From 316a79f4320bbdfd7fd1eead13ea45f71bc66d5b Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Wed, 17 Sep 2025 10:54:02 +0000 Subject: [PATCH 0001/1061] Stabilize 29 RISC-V target features (`riscv_ratified_v2`) This commit stabilizes RISC-V target features with following constraints: * Describes a ratified extension. * Implemented on Rust 1.88.0 or before. Waiting for four+ version cycles seems sufficient. * Does not disrupt current rustc's target feature + ABI handling. It excludes "E" and all floating point-arithmetic extensions. "Zfinx" family does not involve floating point registers but not stabilizing for now to avoid possible confusion between the "F" extension family. * Not vector-related (floating point and integer). While integer vector subsets should not cause any ABI issues (as they don't use ABI-dependent floating point registers), we need to discuss before stabilizing them. * Supported by the lowest LLVM version supported by rustc (LLVM 20). List of target features to be stabilized: 1. "b" 2. "za64rs" (no-RT) 3. "za128rs" (no-RT) 4. "zaamo" 5. "zabha" 6. "zacas" 7. "zalrsc" 8. "zama16b" (no-RT) 9. "zawrs" 10. "zca" 11. "zcb" 12. "zcmop" 13. "zic64b" (no-RT) 14. "zicbom" 15. "zicbop" (no-RT) 16. "zicboz" 17. "ziccamoa" (no-RT) 18. "ziccif" (no-RT) 19. "zicclsm" (no-RT) 20. "ziccrse" (no-RT) 21. "zicntr" 22. "zicond" 23. "zicsr" 24. "zifencei" 25. "zihintntl" 26. "zihintpause" 27. "zihpm" 28. "zimop" 29. "ztso" Of which, 20 of them (29 minus 9 "no-RT" target features) support runtime detection through `std::arch::is_riscv_feature_detected!()`. --- .../rustc_codegen_ssa/src/back/metadata.rs | 6 +- compiler/rustc_target/src/target_features.rs | 58 +++++++++---------- library/std_detect/src/detect/arch/riscv.rs | 40 ++++++------- 3 files changed, 51 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 10aaadd5688a..41b692c466c9 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -330,14 +330,12 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 { let mut e_flags: u32 = 0x0; // Check if compression is enabled - // `unstable_target_features` is used here because "zca" is gated behind riscv_target_feature. - if sess.unstable_target_features.contains(&sym::zca) { + if sess.target_features.contains(&sym::zca) { e_flags |= elf::EF_RISCV_RVC; } // Check if RVTSO is enabled - // `unstable_target_features` is used here because "ztso" is gated behind riscv_target_feature. - if sess.unstable_target_features.contains(&sym::ztso) { + if sess.target_features.contains(&sym::ztso) { e_flags |= elf::EF_RISCV_TSO; } diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index dc70089c385f..f2f0802f12b2 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -589,7 +589,7 @@ const NVPTX_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start ("a", Stable, &["zaamo", "zalrsc"]), - ("b", Unstable(sym::riscv_target_feature), &["zba", "zbb", "zbs"]), + ("b", Stable, &["zba", "zbb", "zbs"]), ("c", Stable, &["zca"]), ("d", Unstable(sym::riscv_target_feature), &["f"]), ("e", Unstable(sym::riscv_target_feature), &[]), @@ -647,14 +647,14 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("unaligned-scalar-mem", Unstable(sym::riscv_target_feature), &[]), ("unaligned-vector-mem", Unstable(sym::riscv_target_feature), &[]), ("v", Unstable(sym::riscv_target_feature), &["zvl128b", "zve64d"]), - ("za64rs", Unstable(sym::riscv_target_feature), &["za128rs"]), // Za64rs ⊃ Za128rs - ("za128rs", Unstable(sym::riscv_target_feature), &[]), - ("zaamo", Unstable(sym::riscv_target_feature), &[]), - ("zabha", Unstable(sym::riscv_target_feature), &["zaamo"]), - ("zacas", Unstable(sym::riscv_target_feature), &["zaamo"]), - ("zalrsc", Unstable(sym::riscv_target_feature), &[]), - ("zama16b", Unstable(sym::riscv_target_feature), &[]), - ("zawrs", Unstable(sym::riscv_target_feature), &[]), + ("za64rs", Stable, &["za128rs"]), // Za64rs ⊃ Za128rs + ("za128rs", Stable, &[]), + ("zaamo", Stable, &[]), + ("zabha", Stable, &["zaamo"]), + ("zacas", Stable, &["zaamo"]), + ("zalrsc", Stable, &[]), + ("zama16b", Stable, &[]), + ("zawrs", Stable, &[]), ("zba", Stable, &[]), ("zbb", Stable, &[]), ("zbc", Stable, &["zbkc"]), // Zbc ⊃ Zbkc @@ -662,9 +662,9 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("zbkc", Stable, &[]), ("zbkx", Stable, &[]), ("zbs", Stable, &[]), - ("zca", Unstable(sym::riscv_target_feature), &[]), - ("zcb", Unstable(sym::riscv_target_feature), &["zca"]), - ("zcmop", Unstable(sym::riscv_target_feature), &["zca"]), + ("zca", Stable, &[]), + ("zcb", Stable, &["zca"]), + ("zcmop", Stable, &["zca"]), ("zdinx", Unstable(sym::riscv_target_feature), &["zfinx"]), ("zfa", Unstable(sym::riscv_target_feature), &["f"]), ("zfbfmin", Unstable(sym::riscv_target_feature), &["f"]), // and a subset of Zfhmin @@ -673,22 +673,22 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("zfinx", Unstable(sym::riscv_target_feature), &["zicsr"]), ("zhinx", Unstable(sym::riscv_target_feature), &["zhinxmin"]), ("zhinxmin", Unstable(sym::riscv_target_feature), &["zfinx"]), - ("zic64b", Unstable(sym::riscv_target_feature), &[]), - ("zicbom", Unstable(sym::riscv_target_feature), &[]), - ("zicbop", Unstable(sym::riscv_target_feature), &[]), - ("zicboz", Unstable(sym::riscv_target_feature), &[]), - ("ziccamoa", Unstable(sym::riscv_target_feature), &[]), - ("ziccif", Unstable(sym::riscv_target_feature), &[]), - ("zicclsm", Unstable(sym::riscv_target_feature), &[]), - ("ziccrse", Unstable(sym::riscv_target_feature), &[]), - ("zicntr", Unstable(sym::riscv_target_feature), &["zicsr"]), - ("zicond", Unstable(sym::riscv_target_feature), &[]), - ("zicsr", Unstable(sym::riscv_target_feature), &[]), - ("zifencei", Unstable(sym::riscv_target_feature), &[]), - ("zihintntl", Unstable(sym::riscv_target_feature), &[]), - ("zihintpause", Unstable(sym::riscv_target_feature), &[]), - ("zihpm", Unstable(sym::riscv_target_feature), &["zicsr"]), - ("zimop", Unstable(sym::riscv_target_feature), &[]), + ("zic64b", Stable, &[]), + ("zicbom", Stable, &[]), + ("zicbop", Stable, &[]), + ("zicboz", Stable, &[]), + ("ziccamoa", Stable, &[]), + ("ziccif", Stable, &[]), + ("zicclsm", Stable, &[]), + ("ziccrse", Stable, &[]), + ("zicntr", Stable, &["zicsr"]), + ("zicond", Stable, &[]), + ("zicsr", Stable, &[]), + ("zifencei", Stable, &[]), + ("zihintntl", Stable, &[]), + ("zihintpause", Stable, &[]), + ("zihpm", Stable, &["zicsr"]), + ("zimop", Stable, &[]), ("zk", Stable, &["zkn", "zkr", "zkt"]), ("zkn", Stable, &["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"]), ("zknd", Stable, &[]), @@ -699,7 +699,7 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("zksed", Stable, &[]), ("zksh", Stable, &[]), ("zkt", Stable, &[]), - ("ztso", Unstable(sym::riscv_target_feature), &[]), + ("ztso", Stable, &[]), ("zvbb", Unstable(sym::riscv_target_feature), &["zvkb"]), // Zvbb ⊃ Zvkb ("zvbc", Unstable(sym::riscv_target_feature), &["zve64x"]), ("zve32f", Unstable(sym::riscv_target_feature), &["zve32x", "f"]), diff --git a/library/std_detect/src/detect/arch/riscv.rs b/library/std_detect/src/detect/arch/riscv.rs index 1e57d09edb14..f6d708dd2ee0 100644 --- a/library/std_detect/src/detect/arch/riscv.rs +++ b/library/std_detect/src/detect/arch/riscv.rs @@ -194,26 +194,26 @@ features! { @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] unaligned_vector_mem: "unaligned-vector-mem"; /// Has reasonably performant unaligned vector - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zicsr: "zicsr"; + @FEATURE: #[stable(feature = "riscv_ratified_v2", since = "CURRENT_RUSTC_VERSION")] zicsr: "zicsr"; /// "Zicsr" Extension for Control and Status Register (CSR) Instructions - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zicntr: "zicntr"; + @FEATURE: #[stable(feature = "riscv_ratified_v2", since = "CURRENT_RUSTC_VERSION")] zicntr: "zicntr"; /// "Zicntr" Extension for Base Counters and Timers - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zihpm: "zihpm"; + @FEATURE: #[stable(feature = "riscv_ratified_v2", since = "CURRENT_RUSTC_VERSION")] zihpm: "zihpm"; /// "Zihpm" Extension for Hardware Performance Counters - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zifencei: "zifencei"; + @FEATURE: #[stable(feature = "riscv_ratified_v2", since = "CURRENT_RUSTC_VERSION")] zifencei: "zifencei"; /// "Zifencei" Extension for Instruction-Fetch Fence - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zihintntl: "zihintntl"; + @FEATURE: #[stable(feature = "riscv_ratified_v2", since = "CURRENT_RUSTC_VERSION")] zihintntl: "zihintntl"; /// "Zihintntl" Extension for Non-Temporal Locality Hints - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zihintpause: "zihintpause"; + @FEATURE: #[stable(feature = "riscv_ratified_v2", since = "CURRENT_RUSTC_VERSION")] zihintpause: "zihintpause"; /// "Zihintpause" Extension for Pause Hint - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zimop: "zimop"; + @FEATURE: #[stable(feature = "riscv_ratified_v2", since = "CURRENT_RUSTC_VERSION")] zimop: "zimop"; /// "Zimop" Extension for May-Be-Operations - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zicbom: "zicbom"; + @FEATURE: #[stable(feature = "riscv_ratified_v2", since = "CURRENT_RUSTC_VERSION")] zicbom: "zicbom"; /// "Zicbom" Extension for Cache-Block Management Instructions - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zicboz: "zicboz"; + @FEATURE: #[stable(feature = "riscv_ratified_v2", since = "CURRENT_RUSTC_VERSION")] zicboz: "zicboz"; /// "Zicboz" Extension for Cache-Block Zero Instruction - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zicond: "zicond"; + @FEATURE: #[stable(feature = "riscv_ratified_v2", since = "CURRENT_RUSTC_VERSION")] zicond: "zicond"; /// "Zicond" Extension for Integer Conditional Operations @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] m: "m"; @@ -221,20 +221,20 @@ features! { @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] a: "a"; /// "A" Extension for Atomic Instructions - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zalrsc: "zalrsc"; + @FEATURE: #[stable(feature = "riscv_ratified_v2", since = "CURRENT_RUSTC_VERSION")] zalrsc: "zalrsc"; /// "Zalrsc" Extension for Load-Reserved/Store-Conditional Instructions - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zaamo: "zaamo"; + @FEATURE: #[stable(feature = "riscv_ratified_v2", since = "CURRENT_RUSTC_VERSION")] zaamo: "zaamo"; /// "Zaamo" Extension for Atomic Memory Operations - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zawrs: "zawrs"; + @FEATURE: #[stable(feature = "riscv_ratified_v2", since = "CURRENT_RUSTC_VERSION")] zawrs: "zawrs"; /// "Zawrs" Extension for Wait-on-Reservation-Set Instructions - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zabha: "zabha"; + @FEATURE: #[stable(feature = "riscv_ratified_v2", since = "CURRENT_RUSTC_VERSION")] zabha: "zabha"; /// "Zabha" Extension for Byte and Halfword Atomic Memory Operations - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zacas: "zacas"; + @FEATURE: #[stable(feature = "riscv_ratified_v2", since = "CURRENT_RUSTC_VERSION")] zacas: "zacas"; /// "Zacas" Extension for Atomic Compare-and-Swap (CAS) Instructions @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zam: "zam"; without cfg check: true; /// "Zam" Extension for Misaligned Atomics - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] ztso: "ztso"; + @FEATURE: #[stable(feature = "riscv_ratified_v2", since = "CURRENT_RUSTC_VERSION")] ztso: "ztso"; /// "Ztso" Extension for Total Store Ordering @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] f: "f"; @@ -264,7 +264,7 @@ features! { @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] c: "c"; /// "C" Extension for Compressed Instructions - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zca: "zca"; + @FEATURE: #[stable(feature = "riscv_ratified_v2", since = "CURRENT_RUSTC_VERSION")] zca: "zca"; /// "Zca" Compressed Instructions excluding Floating-Point Loads/Stores @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zcf: "zcf"; without cfg check: true; @@ -272,12 +272,12 @@ features! { @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zcd: "zcd"; without cfg check: true; /// "Zcd" Compressed Instructions for Double-Precision Floating-Point Loads/Stores - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zcb: "zcb"; + @FEATURE: #[stable(feature = "riscv_ratified_v2", since = "CURRENT_RUSTC_VERSION")] zcb: "zcb"; /// "Zcb" Simple Code-size Saving Compressed Instructions - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zcmop: "zcmop"; + @FEATURE: #[stable(feature = "riscv_ratified_v2", since = "CURRENT_RUSTC_VERSION")] zcmop: "zcmop"; /// "Zcmop" Extension for Compressed May-Be-Operations - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] b: "b"; + @FEATURE: #[stable(feature = "riscv_ratified_v2", since = "CURRENT_RUSTC_VERSION")] b: "b"; /// "B" Extension for Bit Manipulation @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] zba: "zba"; /// "Zba" Extension for Address Generation From 1566879798185efdcfba62d2944a2e60dc10d814 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Mon, 13 Oct 2025 19:53:57 +0200 Subject: [PATCH 0002/1061] clean-up - update file name to match lint name - use `Symbol`s instead of `&str`s - get rid of needless lifetimes --- ...alls.rs => collapsible_span_lint_calls.rs} | 47 +++++++++---------- clippy_lints_internal/src/lib.rs | 6 +-- clippy_utils/src/sym.rs | 4 ++ 3 files changed, 29 insertions(+), 28 deletions(-) rename clippy_lints_internal/src/{collapsible_calls.rs => collapsible_span_lint_calls.rs} (88%) diff --git a/clippy_lints_internal/src/collapsible_calls.rs b/clippy_lints_internal/src/collapsible_span_lint_calls.rs similarity index 88% rename from clippy_lints_internal/src/collapsible_calls.rs rename to clippy_lints_internal/src/collapsible_span_lint_calls.rs index 7c9e7286925e..e83508f6ff4a 100644 --- a/clippy_lints_internal/src/collapsible_calls.rs +++ b/clippy_lints_internal/src/collapsible_span_lint_calls.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::{SpanlessEq, is_lint_allowed, peel_blocks_with_stmt}; +use clippy_utils::{SpanlessEq, is_lint_allowed, peel_blocks_with_stmt, sym}; use rustc_errors::Applicability; use rustc_hir::{Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -91,8 +91,8 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls { let and_then_snippets = get_and_then_snippets(cx, call_cx.span, call_lint.span, call_sp.span, call_msg.span); let mut sle = SpanlessEq::new(cx).deny_side_effects(); - match ps.ident.as_str() { - "span_suggestion" if sle.eq_expr(call_sp, &span_call_args[0]) => { + match ps.ident.name { + sym::span_suggestion if sle.eq_expr(call_sp, &span_call_args[0]) => { suggest_suggestion( cx, expr, @@ -100,19 +100,19 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls { &span_suggestion_snippets(cx, span_call_args), ); }, - "span_help" if sle.eq_expr(call_sp, &span_call_args[0]) => { + sym::span_help if sle.eq_expr(call_sp, &span_call_args[0]) => { let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#); suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), true); }, - "span_note" if sle.eq_expr(call_sp, &span_call_args[0]) => { + sym::span_note if sle.eq_expr(call_sp, &span_call_args[0]) => { let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#); suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), true); }, - "help" => { + sym::help => { let help_snippet = snippet(cx, span_call_args[0].span, r#""...""#); suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), false); }, - "note" => { + sym::note => { let note_snippet = snippet(cx, span_call_args[0].span, r#""...""#); suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), false); }, @@ -122,11 +122,11 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls { } } -struct AndThenSnippets<'a> { - cx: Cow<'a, str>, - lint: Cow<'a, str>, - span: Cow<'a, str>, - msg: Cow<'a, str>, +struct AndThenSnippets { + cx: Cow<'static, str>, + lint: Cow<'static, str>, + span: Cow<'static, str>, + msg: Cow<'static, str>, } fn get_and_then_snippets( @@ -135,7 +135,7 @@ fn get_and_then_snippets( lint_span: Span, span_span: Span, msg_span: Span, -) -> AndThenSnippets<'static> { +) -> AndThenSnippets { let cx_snippet = snippet(cx, cx_span, "cx"); let lint_snippet = snippet(cx, lint_span, ".."); let span_snippet = snippet(cx, span_span, "span"); @@ -149,16 +149,13 @@ fn get_and_then_snippets( } } -struct SpanSuggestionSnippets<'a> { - help: Cow<'a, str>, - sugg: Cow<'a, str>, - applicability: Cow<'a, str>, +struct SpanSuggestionSnippets { + help: Cow<'static, str>, + sugg: Cow<'static, str>, + applicability: Cow<'static, str>, } -fn span_suggestion_snippets<'a, 'hir>( - cx: &LateContext<'_>, - span_call_args: &'hir [Expr<'hir>], -) -> SpanSuggestionSnippets<'a> { +fn span_suggestion_snippets<'hir>(cx: &LateContext<'_>, span_call_args: &'hir [Expr<'hir>]) -> SpanSuggestionSnippets { let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#); let sugg_snippet = snippet(cx, span_call_args[2].span, ".."); let applicability_snippet = snippet(cx, span_call_args[3].span, "Applicability::MachineApplicable"); @@ -173,8 +170,8 @@ fn span_suggestion_snippets<'a, 'hir>( fn suggest_suggestion( cx: &LateContext<'_>, expr: &Expr<'_>, - and_then_snippets: &AndThenSnippets<'_>, - span_suggestion_snippets: &SpanSuggestionSnippets<'_>, + and_then_snippets: &AndThenSnippets, + span_suggestion_snippets: &SpanSuggestionSnippets, ) { span_lint_and_sugg( cx, @@ -199,7 +196,7 @@ fn suggest_suggestion( fn suggest_help( cx: &LateContext<'_>, expr: &Expr<'_>, - and_then_snippets: &AndThenSnippets<'_>, + and_then_snippets: &AndThenSnippets, help: &str, with_span: bool, ) { @@ -226,7 +223,7 @@ fn suggest_help( fn suggest_note( cx: &LateContext<'_>, expr: &Expr<'_>, - and_then_snippets: &AndThenSnippets<'_>, + and_then_snippets: &AndThenSnippets, note: &str, with_span: bool, ) { diff --git a/clippy_lints_internal/src/lib.rs b/clippy_lints_internal/src/lib.rs index 43cde86504f5..2fc172f64725 100644 --- a/clippy_lints_internal/src/lib.rs +++ b/clippy_lints_internal/src/lib.rs @@ -31,7 +31,7 @@ extern crate rustc_session; extern crate rustc_span; mod almost_standard_lint_formulation; -mod collapsible_calls; +mod collapsible_span_lint_calls; mod derive_deserialize_allowing_unknown; mod internal_paths; mod lint_without_lint_pass; @@ -46,7 +46,7 @@ use rustc_lint::{Lint, LintStore}; static LINTS: &[&Lint] = &[ almost_standard_lint_formulation::ALMOST_STANDARD_LINT_FORMULATION, - collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS, + collapsible_span_lint_calls::COLLAPSIBLE_SPAN_LINT_CALLS, derive_deserialize_allowing_unknown::DERIVE_DESERIALIZE_ALLOWING_UNKNOWN, lint_without_lint_pass::DEFAULT_LINT, lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE, @@ -66,7 +66,7 @@ pub fn register_lints(store: &mut LintStore) { store.register_early_pass(|| Box::new(unsorted_clippy_utils_paths::UnsortedClippyUtilsPaths)); store.register_early_pass(|| Box::new(produce_ice::ProduceIce)); - store.register_late_pass(|_| Box::new(collapsible_calls::CollapsibleCalls)); + store.register_late_pass(|_| Box::new(collapsible_span_lint_calls::CollapsibleCalls)); store.register_late_pass(|_| Box::new(derive_deserialize_allowing_unknown::DeriveDeserializeAllowingUnknown)); store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::::default()); diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index 2b22f344e8c0..e3d733cada71 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -173,6 +173,7 @@ generate! { get_unchecked, get_unchecked_mut, has_significant_drop, + help, hidden_glob_reexports, hygiene, insert, @@ -310,7 +311,10 @@ generate! { sort, sort_by, sort_unstable_by, + span_help, span_lint_and_then, + span_note, + span_suggestion, split, split_at, split_at_checked, From 4d795229058b568570cf68a1320cd5bd95eab377 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Mon, 13 Oct 2025 19:32:34 +0200 Subject: [PATCH 0003/1061] fix: use `snippet_with_context` for spans that are likely to contain macro expns --- .../src/collapsible_span_lint_calls.rs | 69 ++++++++++++------- .../collapsible_span_lint_calls.fixed | 9 +++ .../collapsible_span_lint_calls.rs | 29 ++++++++ .../collapsible_span_lint_calls.stderr | 50 +++++++++++++- 4 files changed, 131 insertions(+), 26 deletions(-) diff --git a/clippy_lints_internal/src/collapsible_span_lint_calls.rs b/clippy_lints_internal/src/collapsible_span_lint_calls.rs index e83508f6ff4a..f7adb782929c 100644 --- a/clippy_lints_internal/src/collapsible_span_lint_calls.rs +++ b/clippy_lints_internal/src/collapsible_span_lint_calls.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet; +use clippy_utils::source::{snippet, snippet_with_context}; use clippy_utils::{SpanlessEq, is_lint_allowed, peel_blocks_with_stmt, sym}; use rustc_errors::Applicability; use rustc_hir::{Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::Span; +use rustc_span::{Span, SyntaxContext}; use std::borrow::{Borrow, Cow}; @@ -88,33 +88,42 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls { && let ExprKind::MethodCall(ps, recv, span_call_args, _) = &only_expr.kind && let ExprKind::Path(..) = recv.kind { - let and_then_snippets = - get_and_then_snippets(cx, call_cx.span, call_lint.span, call_sp.span, call_msg.span); + let mut app = Applicability::MachineApplicable; + let expr_ctxt = expr.span.ctxt(); + let and_then_snippets = get_and_then_snippets( + cx, + expr_ctxt, + call_cx.span, + call_lint.span, + call_sp.span, + call_msg.span, + &mut app, + ); let mut sle = SpanlessEq::new(cx).deny_side_effects(); match ps.ident.name { sym::span_suggestion if sle.eq_expr(call_sp, &span_call_args[0]) => { - suggest_suggestion( - cx, - expr, - &and_then_snippets, - &span_suggestion_snippets(cx, span_call_args), - ); + let snippets = span_suggestion_snippets(cx, expr_ctxt, span_call_args, &mut app); + suggest_suggestion(cx, expr, &and_then_snippets, &snippets, app); }, sym::span_help if sle.eq_expr(call_sp, &span_call_args[0]) => { - let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#); - suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), true); + let help_snippet = + snippet_with_context(cx, span_call_args[1].span, expr_ctxt, r#""...""#, &mut app).0; + suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), true, app); }, sym::span_note if sle.eq_expr(call_sp, &span_call_args[0]) => { - let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#); - suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), true); + let note_snippet = + snippet_with_context(cx, span_call_args[1].span, expr_ctxt, r#""...""#, &mut app).0; + suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), true, app); }, sym::help => { - let help_snippet = snippet(cx, span_call_args[0].span, r#""...""#); - suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), false); + let help_snippet = + snippet_with_context(cx, span_call_args[0].span, expr_ctxt, r#""...""#, &mut app).0; + suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), false, app); }, sym::note => { - let note_snippet = snippet(cx, span_call_args[0].span, r#""...""#); - suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), false); + let note_snippet = + snippet_with_context(cx, span_call_args[0].span, expr_ctxt, r#""...""#, &mut app).0; + suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), false, app); }, _ => (), } @@ -131,15 +140,17 @@ struct AndThenSnippets { fn get_and_then_snippets( cx: &LateContext<'_>, + expr_ctxt: SyntaxContext, cx_span: Span, lint_span: Span, span_span: Span, msg_span: Span, + app: &mut Applicability, ) -> AndThenSnippets { let cx_snippet = snippet(cx, cx_span, "cx"); let lint_snippet = snippet(cx, lint_span, ".."); let span_snippet = snippet(cx, span_span, "span"); - let msg_snippet = snippet(cx, msg_span, r#""...""#); + let msg_snippet = snippet_with_context(cx, msg_span, expr_ctxt, r#""...""#, app).0; AndThenSnippets { cx: cx_snippet, @@ -155,9 +166,14 @@ struct SpanSuggestionSnippets { applicability: Cow<'static, str>, } -fn span_suggestion_snippets<'hir>(cx: &LateContext<'_>, span_call_args: &'hir [Expr<'hir>]) -> SpanSuggestionSnippets { - let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#); - let sugg_snippet = snippet(cx, span_call_args[2].span, ".."); +fn span_suggestion_snippets<'hir>( + cx: &LateContext<'_>, + expr_ctxt: SyntaxContext, + span_call_args: &'hir [Expr<'hir>], + app: &mut Applicability, +) -> SpanSuggestionSnippets { + let help_snippet = snippet_with_context(cx, span_call_args[1].span, expr_ctxt, r#""...""#, app).0; + let sugg_snippet = snippet_with_context(cx, span_call_args[2].span, expr_ctxt, "..", app).0; let applicability_snippet = snippet(cx, span_call_args[3].span, "Applicability::MachineApplicable"); SpanSuggestionSnippets { @@ -172,6 +188,7 @@ fn suggest_suggestion( expr: &Expr<'_>, and_then_snippets: &AndThenSnippets, span_suggestion_snippets: &SpanSuggestionSnippets, + app: Applicability, ) { span_lint_and_sugg( cx, @@ -189,7 +206,7 @@ fn suggest_suggestion( span_suggestion_snippets.sugg, span_suggestion_snippets.applicability ), - Applicability::MachineApplicable, + app, ); } @@ -199,6 +216,7 @@ fn suggest_help( and_then_snippets: &AndThenSnippets, help: &str, with_span: bool, + app: Applicability, ) { let option_span = if with_span { format!("Some({})", and_then_snippets.span) @@ -216,7 +234,7 @@ fn suggest_help( "span_lint_and_help({}, {}, {}, {}, {}, {help})", and_then_snippets.cx, and_then_snippets.lint, and_then_snippets.span, and_then_snippets.msg, &option_span, ), - Applicability::MachineApplicable, + app, ); } @@ -226,6 +244,7 @@ fn suggest_note( and_then_snippets: &AndThenSnippets, note: &str, with_span: bool, + app: Applicability, ) { let note_span = if with_span { format!("Some({})", and_then_snippets.span) @@ -243,6 +262,6 @@ fn suggest_note( "span_lint_and_note({}, {}, {}, {}, {note_span}, {note})", and_then_snippets.cx, and_then_snippets.lint, and_then_snippets.span, and_then_snippets.msg, ), - Applicability::MachineApplicable, + app, ); } diff --git a/tests/ui-internal/collapsible_span_lint_calls.fixed b/tests/ui-internal/collapsible_span_lint_calls.fixed index 76f68686ee2a..2b646a38b534 100644 --- a/tests/ui-internal/collapsible_span_lint_calls.fixed +++ b/tests/ui-internal/collapsible_span_lint_calls.fixed @@ -50,6 +50,15 @@ impl EarlyLintPass for Pass { span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { db.help(help_msg).help(help_msg); }); + + // Issue #15880 + #[expect(clippy::disallowed_names)] + let foo = "foo"; + span_lint_and_sugg(cx, TEST_LINT, expr.span, lint_msg, format!("try using {foo}"), format!("{foo}.use"), Applicability::MachineApplicable); + span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), format!("try using {foo}")); + span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, None, format!("try using {foo}")); + span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), format!("required because of {foo}")); + span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, None, format!("required because of {foo}")); } } diff --git a/tests/ui-internal/collapsible_span_lint_calls.rs b/tests/ui-internal/collapsible_span_lint_calls.rs index 214c8783a669..500552370053 100644 --- a/tests/ui-internal/collapsible_span_lint_calls.rs +++ b/tests/ui-internal/collapsible_span_lint_calls.rs @@ -65,6 +65,35 @@ impl EarlyLintPass for Pass { span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { db.help(help_msg).help(help_msg); }); + + // Issue #15880 + #[expect(clippy::disallowed_names)] + let foo = "foo"; + span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { + //~^ collapsible_span_lint_calls + db.span_suggestion( + expr.span, + format!("try using {foo}"), + format!("{foo}.use"), + Applicability::MachineApplicable, + ); + }); + span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { + //~^ collapsible_span_lint_calls + db.span_help(expr.span, format!("try using {foo}")); + }); + span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { + //~^ collapsible_span_lint_calls + db.help(format!("try using {foo}")); + }); + span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { + //~^ collapsible_span_lint_calls + db.span_note(expr.span, format!("required because of {foo}")); + }); + span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { + //~^ collapsible_span_lint_calls + db.note(format!("required because of {foo}")); + }); } } diff --git a/tests/ui-internal/collapsible_span_lint_calls.stderr b/tests/ui-internal/collapsible_span_lint_calls.stderr index 9c83538947ca..76b453019270 100644 --- a/tests/ui-internal/collapsible_span_lint_calls.stderr +++ b/tests/ui-internal/collapsible_span_lint_calls.stderr @@ -49,5 +49,53 @@ LL | | db.note(note_msg); LL | | }); | |__________^ help: collapse into: `span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, None, note_msg)` -error: aborting due to 5 previous errors +error: this call is collapsible + --> tests/ui-internal/collapsible_span_lint_calls.rs:72:9 + | +LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { +LL | | +LL | | db.span_suggestion( +LL | | expr.span, +... | +LL | | ); +LL | | }); + | |__________^ help: collapse into: `span_lint_and_sugg(cx, TEST_LINT, expr.span, lint_msg, format!("try using {foo}"), format!("{foo}.use"), Applicability::MachineApplicable)` + +error: this call is collapsible + --> tests/ui-internal/collapsible_span_lint_calls.rs:81:9 + | +LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { +LL | | +LL | | db.span_help(expr.span, format!("try using {foo}")); +LL | | }); + | |__________^ help: collapse into: `span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), format!("try using {foo}"))` + +error: this call is collapsible + --> tests/ui-internal/collapsible_span_lint_calls.rs:85:9 + | +LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { +LL | | +LL | | db.help(format!("try using {foo}")); +LL | | }); + | |__________^ help: collapse into: `span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, None, format!("try using {foo}"))` + +error: this call is collapsible + --> tests/ui-internal/collapsible_span_lint_calls.rs:89:9 + | +LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { +LL | | +LL | | db.span_note(expr.span, format!("required because of {foo}")); +LL | | }); + | |__________^ help: collapse into: `span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), format!("required because of {foo}"))` + +error: this call is collapsible + --> tests/ui-internal/collapsible_span_lint_calls.rs:93:9 + | +LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { +LL | | +LL | | db.note(format!("required because of {foo}")); +LL | | }); + | |__________^ help: collapse into: `span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, None, format!("required because of {foo}"))` + +error: aborting due to 10 previous errors From b270954300ec06f3478e3758d0c8d3e9f38efebf Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Mon, 13 Oct 2025 19:50:47 +0200 Subject: [PATCH 0004/1061] s/snippet/snippet_with_applicability while we're at it --- .../src/collapsible_span_lint_calls.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/clippy_lints_internal/src/collapsible_span_lint_calls.rs b/clippy_lints_internal/src/collapsible_span_lint_calls.rs index f7adb782929c..b048a1004b0d 100644 --- a/clippy_lints_internal/src/collapsible_span_lint_calls.rs +++ b/clippy_lints_internal/src/collapsible_span_lint_calls.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{snippet, snippet_with_context}; +use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::{SpanlessEq, is_lint_allowed, peel_blocks_with_stmt, sym}; use rustc_errors::Applicability; use rustc_hir::{Closure, Expr, ExprKind}; @@ -147,9 +147,9 @@ fn get_and_then_snippets( msg_span: Span, app: &mut Applicability, ) -> AndThenSnippets { - let cx_snippet = snippet(cx, cx_span, "cx"); - let lint_snippet = snippet(cx, lint_span, ".."); - let span_snippet = snippet(cx, span_span, "span"); + let cx_snippet = snippet_with_applicability(cx, cx_span, "cx", app); + let lint_snippet = snippet_with_applicability(cx, lint_span, "..", app); + let span_snippet = snippet_with_applicability(cx, span_span, "span", app); let msg_snippet = snippet_with_context(cx, msg_span, expr_ctxt, r#""...""#, app).0; AndThenSnippets { @@ -174,7 +174,8 @@ fn span_suggestion_snippets<'hir>( ) -> SpanSuggestionSnippets { let help_snippet = snippet_with_context(cx, span_call_args[1].span, expr_ctxt, r#""...""#, app).0; let sugg_snippet = snippet_with_context(cx, span_call_args[2].span, expr_ctxt, "..", app).0; - let applicability_snippet = snippet(cx, span_call_args[3].span, "Applicability::MachineApplicable"); + let applicability_snippet = + snippet_with_applicability(cx, span_call_args[3].span, "Applicability::MachineApplicable", app); SpanSuggestionSnippets { help: help_snippet, From d056f59704cdd283733fa8a896e45f1731725cbb Mon Sep 17 00:00:00 2001 From: matwatson Date: Sun, 21 Sep 2025 14:14:29 -0700 Subject: [PATCH 0005/1061] corrected Cell module level doc replaced `&mut T` with `&T` to finally state "a &T to the inner value can never be obtained" --- library/core/src/cell.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 9b53b75ebee8..1b3126700ff3 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -27,10 +27,9 @@ //! //! ## `Cell` //! -//! [`Cell`] implements interior mutability by moving values in and out of the cell. That is, an -//! `&mut T` to the inner value can never be obtained, and the value itself cannot be directly -//! obtained without replacing it with something else. Both of these rules ensure that there is -//! never more than one reference pointing to the inner value. This type provides the following +//! [`Cell`] implements interior mutability by moving values in and out of the cell. That is, a +//! `&T` to the inner value can never be obtained, and the value itself cannot be directly +//! obtained without replacing it with something else. This type provides the following //! methods: //! //! - For types that implement [`Copy`], the [`get`](Cell::get) method retrieves the current From d160cb7313fb07d85ad57b99a98106211684c270 Mon Sep 17 00:00:00 2001 From: "Ian D. Bollinger" Date: Tue, 4 Nov 2025 13:00:02 -0500 Subject: [PATCH 0006/1061] `double_comparison`: add missing cases Add checks for expressions such as `x != y && x >= y` and `x != y && x <= y`. --- .../src/operators/double_comparison.rs | 12 +++++++++ tests/ui/double_comparison.fixed | 16 ++++++++++++ tests/ui/double_comparison.rs | 16 ++++++++++++ tests/ui/double_comparison.stderr | 26 ++++++++++++++++++- 4 files changed, 69 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/operators/double_comparison.rs b/clippy_lints/src/operators/double_comparison.rs index 71982023779e..a40a724d2da5 100644 --- a/clippy_lints/src/operators/double_comparison.rs +++ b/clippy_lints/src/operators/double_comparison.rs @@ -39,6 +39,18 @@ pub(super) fn check(cx: &LateContext<'_>, op: BinOpKind, lhs: &Expr<'_>, rhs: &E | (BinOpKind::And, BinOpKind::Ge, BinOpKind::Le) => { "==" }, + // x != y && x >= y => x > y + (BinOpKind::And, BinOpKind::Ne, BinOpKind::Ge) + // x >= y && x != y => x > y + | (BinOpKind::And, BinOpKind::Ge, BinOpKind::Ne) => { + ">" + }, + // x != y && x <= y => x < y + (BinOpKind::And, BinOpKind::Ne, BinOpKind::Le) + // x <= y && x != y => x < y + | (BinOpKind::And, BinOpKind::Le, BinOpKind::Ne) => { + "<" + }, _ => return, }; diff --git a/tests/ui/double_comparison.fixed b/tests/ui/double_comparison.fixed index 0680eb35ef97..29047b8a31cb 100644 --- a/tests/ui/double_comparison.fixed +++ b/tests/ui/double_comparison.fixed @@ -35,4 +35,20 @@ fn main() { //~^ double_comparisons // do something } + if x < y { + //~^ double_comparisons + // do something + } + if x < y { + //~^ double_comparisons + // do something + } + if x > y { + //~^ double_comparisons + // do something + } + if x > y { + //~^ double_comparisons + // do something + } } diff --git a/tests/ui/double_comparison.rs b/tests/ui/double_comparison.rs index 18ab7d2c4254..13edb2a996a1 100644 --- a/tests/ui/double_comparison.rs +++ b/tests/ui/double_comparison.rs @@ -35,4 +35,20 @@ fn main() { //~^ double_comparisons // do something } + if x != y && x <= y { + //~^ double_comparisons + // do something + } + if x <= y && x != y { + //~^ double_comparisons + // do something + } + if x != y && x >= y { + //~^ double_comparisons + // do something + } + if x >= y && x != y { + //~^ double_comparisons + // do something + } } diff --git a/tests/ui/double_comparison.stderr b/tests/ui/double_comparison.stderr index 984614c203eb..be7eba611cb0 100644 --- a/tests/ui/double_comparison.stderr +++ b/tests/ui/double_comparison.stderr @@ -49,5 +49,29 @@ error: this binary expression can be simplified LL | if x >= y && x <= y { | ^^^^^^^^^^^^^^^^ help: try: `x == y` -error: aborting due to 8 previous errors +error: this binary expression can be simplified + --> tests/ui/double_comparison.rs:38:8 + | +LL | if x != y && x <= y { + | ^^^^^^^^^^^^^^^^ help: try: `x < y` + +error: this binary expression can be simplified + --> tests/ui/double_comparison.rs:42:8 + | +LL | if x <= y && x != y { + | ^^^^^^^^^^^^^^^^ help: try: `x < y` + +error: this binary expression can be simplified + --> tests/ui/double_comparison.rs:46:8 + | +LL | if x != y && x >= y { + | ^^^^^^^^^^^^^^^^ help: try: `x > y` + +error: this binary expression can be simplified + --> tests/ui/double_comparison.rs:50:8 + | +LL | if x >= y && x != y { + | ^^^^^^^^^^^^^^^^ help: try: `x > y` + +error: aborting due to 12 previous errors From 12f41b519435e3952f2bf8e2c829e19c982ace04 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 17 Oct 2025 12:52:31 +0000 Subject: [PATCH 0007/1061] More explicit handling of the allocator shim around LTO --- compiler/rustc_codegen_ssa/src/back/write.rs | 56 +++++++++----------- compiler/rustc_codegen_ssa/src/base.rs | 11 +--- 2 files changed, 27 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 3e36bd8552b1..885af95b1f2c 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -334,7 +334,6 @@ pub struct CodegenContext { pub output_filenames: Arc, pub invocation_temp: Option, pub module_config: Arc, - pub allocator_config: Arc, pub tm_factory: TargetMachineFactoryFn, pub msvc_imps_needed: bool, pub is_pe_coff: bool, @@ -799,19 +798,12 @@ pub(crate) fn compute_per_cgu_lto_type( sess_lto: &Lto, opts: &config::Options, sess_crate_types: &[CrateType], - module_kind: ModuleKind, ) -> ComputedLtoType { // If the linker does LTO, we don't have to do it. Note that we // keep doing full LTO, if it is requested, as not to break the // assumption that the output will be a single module. let linker_does_lto = opts.cg.linker_plugin_lto.enabled(); - // When we're automatically doing ThinLTO for multi-codegen-unit - // builds we don't actually want to LTO the allocator module if - // it shows up. This is due to various linker shenanigans that - // we'll encounter later. - let is_allocator = module_kind == ModuleKind::Allocator; - // We ignore a request for full crate graph LTO if the crate type // is only an rlib, as there is no full crate graph to process, // that'll happen later. @@ -823,7 +815,7 @@ pub(crate) fn compute_per_cgu_lto_type( let is_rlib = matches!(sess_crate_types, [CrateType::Rlib]); match sess_lto { - Lto::ThinLocal if !linker_does_lto && !is_allocator => ComputedLtoType::Thin, + Lto::ThinLocal if !linker_does_lto => ComputedLtoType::Thin, Lto::Thin if !linker_does_lto && !is_rlib => ComputedLtoType::Thin, Lto::Fat if !is_rlib => ComputedLtoType::Fat, _ => ComputedLtoType::No, @@ -839,23 +831,18 @@ fn execute_optimize_work_item( let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); - let module_config = match module.kind { - ModuleKind::Regular => &cgcx.module_config, - ModuleKind::Allocator => &cgcx.allocator_config, - }; - - B::optimize(cgcx, dcx, &mut module, module_config); + B::optimize(cgcx, dcx, &mut module, &cgcx.module_config); // After we've done the initial round of optimizations we need to // decide whether to synchronously codegen this module or ship it // back to the coordinator thread for further LTO processing (which // has to wait for all the initial modules to be optimized). - let lto_type = compute_per_cgu_lto_type(&cgcx.lto, &cgcx.opts, &cgcx.crate_types, module.kind); + let lto_type = compute_per_cgu_lto_type(&cgcx.lto, &cgcx.opts, &cgcx.crate_types); // If we're doing some form of incremental LTO then we need to be sure to // save our module to disk first. - let bitcode = if module_config.emit_pre_lto_bc { + let bitcode = if cgcx.module_config.emit_pre_lto_bc { let filename = pre_lto_bitcode_filename(&module.name); cgcx.incr_comp_session_dir.as_ref().map(|path| path.join(&filename)) } else { @@ -864,7 +851,7 @@ fn execute_optimize_work_item( match lto_type { ComputedLtoType::No => { - let module = B::codegen(cgcx, module, module_config); + let module = B::codegen(cgcx, module, &cgcx.module_config); WorkItemResult::Finished(module) } ComputedLtoType::Thin => { @@ -1245,7 +1232,7 @@ fn start_executing_work( coordinator_receive: Receiver>, regular_config: Arc, allocator_config: Arc, - allocator_module: Option>, + mut allocator_module: Option>, coordinator_send: Sender>, ) -> thread::JoinHandle> { let sess = tcx.sess; @@ -1303,7 +1290,6 @@ fn start_executing_work( diag_emitter: shared_emitter.clone(), output_filenames: Arc::clone(tcx.output_filenames(())), module_config: regular_config, - allocator_config, tm_factory: backend.target_machine_factory(tcx.sess, ol, backend_features), msvc_imps_needed: msvc_imps_needed(tcx), is_pe_coff: tcx.sess.target.is_like_windows, @@ -1497,16 +1483,12 @@ fn start_executing_work( let mut llvm_start_time: Option> = None; - let compiled_allocator_module = allocator_module.and_then(|allocator_module| { - match execute_optimize_work_item(&cgcx, allocator_module) { - WorkItemResult::Finished(compiled_module) => return Some(compiled_module), - WorkItemResult::NeedsFatLto(fat_lto_input) => needs_fat_lto.push(fat_lto_input), - WorkItemResult::NeedsThinLto(name, thin_buffer) => { - needs_thin_lto.push((name, thin_buffer)) - } - } - None - }); + if let Some(allocator_module) = &mut allocator_module { + let dcx = cgcx.create_dcx(); + let dcx = dcx.handle(); + + B::optimize(&cgcx, dcx, allocator_module, &allocator_config); + } // Run the message loop while there's still anything that needs message // processing. Note that as soon as codegen is aborted we simply want to @@ -1733,6 +1715,10 @@ fn start_executing_work( assert!(compiled_modules.is_empty()); assert!(needs_thin_lto.is_empty()); + if let Some(allocator_module) = allocator_module.take() { + needs_fat_lto.push(FatLtoInput::InMemory(allocator_module)); + } + // This uses the implicit token let module = do_fat_lto( &cgcx, @@ -1746,6 +1732,13 @@ fn start_executing_work( assert!(compiled_modules.is_empty()); assert!(needs_fat_lto.is_empty()); + if cgcx.lto != Lto::ThinLocal { + if let Some(allocator_module) = allocator_module.take() { + let (name, thin_buffer) = B::prepare_thin(allocator_module); + needs_thin_lto.push((name, thin_buffer)); + } + } + compiled_modules.extend(do_thin_lto( &cgcx, exported_symbols_for_lto, @@ -1762,7 +1755,8 @@ fn start_executing_work( Ok(CompiledModules { modules: compiled_modules, - allocator_module: compiled_allocator_module, + allocator_module: allocator_module + .map(|allocator_module| B::codegen(&cgcx, allocator_module, &allocator_config)), }) }) .expect("failed to spawn coordinator thread"); diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 414e9ce1c821..815a3ee706f8 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -49,9 +49,7 @@ use crate::meth::load_vtable; use crate::mir::operand::OperandValue; use crate::mir::place::PlaceRef; use crate::traits::*; -use crate::{ - CachedModuleCodegen, CodegenLintLevels, CrateInfo, ModuleCodegen, ModuleKind, errors, meth, mir, -}; +use crate::{CachedModuleCodegen, CodegenLintLevels, CrateInfo, ModuleCodegen, errors, meth, mir}; pub(crate) fn bin_op_to_icmp_predicate(op: BinOp, signed: bool) -> IntPredicate { match (op, signed) { @@ -1132,12 +1130,7 @@ pub fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> // We can re-use either the pre- or the post-thinlto state. If no LTO is // being performed then we can use post-LTO artifacts, otherwise we must // reuse pre-LTO artifacts - match compute_per_cgu_lto_type( - &tcx.sess.lto(), - &tcx.sess.opts, - tcx.crate_types(), - ModuleKind::Regular, - ) { + match compute_per_cgu_lto_type(&tcx.sess.lto(), &tcx.sess.opts, tcx.crate_types()) { ComputedLtoType::No => CguReuse::PostLto, _ => CguReuse::PreLto, } From b93b4b003eb1b1dea681d65a5ac9c222b854046d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 23 Oct 2025 09:39:13 +0000 Subject: [PATCH 0008/1061] Remove opts field from CodegenContext --- compiler/rustc_codegen_gcc/src/back/lto.rs | 2 +- compiler/rustc_codegen_llvm/src/back/lto.rs | 2 +- compiler/rustc_codegen_llvm/src/back/write.rs | 6 +++--- compiler/rustc_codegen_ssa/src/back/lto.rs | 6 +++--- compiler/rustc_codegen_ssa/src/back/write.rs | 14 +++++++++----- compiler/rustc_codegen_ssa/src/base.rs | 6 +++++- 6 files changed, 22 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/back/lto.rs b/compiler/rustc_codegen_gcc/src/back/lto.rs index 404064fb7a06..08c36d2b7318 100644 --- a/compiler/rustc_codegen_gcc/src/back/lto.rs +++ b/compiler/rustc_codegen_gcc/src/back/lto.rs @@ -290,7 +290,7 @@ pub(crate) fn run_thin( let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); let lto_data = prepare_lto(cgcx, each_linked_rlib_for_lto, dcx); - if cgcx.opts.cg.linker_plugin_lto.enabled() { + if cgcx.use_linker_plugin_lto { unreachable!( "We should never reach this case if the LTO step \ is deferred to the linker" diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index b820b992105f..3137ed288fa8 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -179,7 +179,7 @@ pub(crate) fn run_thin( prepare_lto(cgcx, exported_symbols_for_lto, each_linked_rlib_for_lto, dcx); let symbols_below_threshold = symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::>(); - if cgcx.opts.cg.linker_plugin_lto.enabled() { + if cgcx.use_linker_plugin_lto { unreachable!( "We should never reach this case if the LTO step \ is deferred to the linker" diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 95539059653b..a49d4c010d67 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -398,7 +398,7 @@ impl<'a> DiagnosticHandlers<'a> { }) .and_then(|dir| dir.to_str().and_then(|p| CString::new(p).ok())); - let pgo_available = cgcx.opts.cg.profile_use.is_some(); + let pgo_available = cgcx.module_config.pgo_use.is_some(); let data = Box::into_raw(Box::new((cgcx, dcx))); unsafe { let old_handler = llvm::LLVMRustContextGetDiagnosticHandler(llcx); @@ -738,7 +738,7 @@ pub(crate) unsafe fn llvm_optimize( &*module.module_llvm.tm.raw(), to_pass_builder_opt_level(opt_level), opt_stage, - cgcx.opts.cg.linker_plugin_lto.enabled(), + cgcx.use_linker_plugin_lto, config.no_prepopulate_passes, config.verify_llvm_ir, config.lint_llvm_ir, @@ -801,7 +801,7 @@ pub(crate) fn optimize( let opt_stage = match cgcx.lto { Lto::Fat => llvm::OptStage::PreLinkFatLTO, Lto::Thin | Lto::ThinLocal => llvm::OptStage::PreLinkThinLTO, - _ if cgcx.opts.cg.linker_plugin_lto.enabled() => llvm::OptStage::PreLinkThinLTO, + _ if cgcx.use_linker_plugin_lto => llvm::OptStage::PreLinkThinLTO, _ => llvm::OptStage::PreLinkNoLTO, }; diff --git a/compiler/rustc_codegen_ssa/src/back/lto.rs b/compiler/rustc_codegen_ssa/src/back/lto.rs index e6df6a2469f3..e3dc985bf782 100644 --- a/compiler/rustc_codegen_ssa/src/back/lto.rs +++ b/compiler/rustc_codegen_ssa/src/back/lto.rs @@ -137,15 +137,15 @@ pub(super) fn check_lto_allowed(cgcx: &CodegenContext if !crate_type_allows_lto(*crate_type) { dcx.handle().emit_fatal(LtoDisallowed); } else if *crate_type == CrateType::Dylib { - if !cgcx.opts.unstable_opts.dylib_lto { + if !cgcx.dylib_lto { dcx.handle().emit_fatal(LtoDylib); } - } else if *crate_type == CrateType::ProcMacro && !cgcx.opts.unstable_opts.dylib_lto { + } else if *crate_type == CrateType::ProcMacro && !cgcx.dylib_lto { dcx.handle().emit_fatal(LtoProcMacro); } } - if cgcx.opts.cg.prefer_dynamic && !cgcx.opts.unstable_opts.dylib_lto { + if cgcx.prefer_dynamic && !cgcx.dylib_lto { dcx.handle().emit_fatal(DynamicLinkingWithLTO); } } diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 885af95b1f2c..bc7c32931613 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -326,10 +326,12 @@ pub struct CodegenContext { // Resources needed when running LTO pub prof: SelfProfilerRef, pub lto: Lto, + pub use_linker_plugin_lto: bool, + pub dylib_lto: bool, + pub prefer_dynamic: bool, pub save_temps: bool, pub fewer_names: bool, pub time_trace: bool, - pub opts: Arc, pub crate_types: Vec, pub output_filenames: Arc, pub invocation_temp: Option, @@ -796,13 +798,12 @@ pub(crate) enum ComputedLtoType { pub(crate) fn compute_per_cgu_lto_type( sess_lto: &Lto, - opts: &config::Options, + linker_does_lto: bool, sess_crate_types: &[CrateType], ) -> ComputedLtoType { // If the linker does LTO, we don't have to do it. Note that we // keep doing full LTO, if it is requested, as not to break the // assumption that the output will be a single module. - let linker_does_lto = opts.cg.linker_plugin_lto.enabled(); // We ignore a request for full crate graph LTO if the crate type // is only an rlib, as there is no full crate graph to process, @@ -838,7 +839,8 @@ fn execute_optimize_work_item( // back to the coordinator thread for further LTO processing (which // has to wait for all the initial modules to be optimized). - let lto_type = compute_per_cgu_lto_type(&cgcx.lto, &cgcx.opts, &cgcx.crate_types); + let lto_type = + compute_per_cgu_lto_type(&cgcx.lto, cgcx.use_linker_plugin_lto, &cgcx.crate_types); // If we're doing some form of incremental LTO then we need to be sure to // save our module to disk first. @@ -1279,10 +1281,12 @@ fn start_executing_work( let cgcx = CodegenContext:: { crate_types: tcx.crate_types().to_vec(), lto: sess.lto(), + use_linker_plugin_lto: sess.opts.cg.linker_plugin_lto.enabled(), + dylib_lto: sess.opts.unstable_opts.dylib_lto, + prefer_dynamic: sess.opts.cg.prefer_dynamic, fewer_names: sess.fewer_names(), save_temps: sess.opts.cg.save_temps, time_trace: sess.opts.unstable_opts.llvm_time_trace, - opts: Arc::new(sess.opts.clone()), prof: sess.prof.clone(), remark: sess.opts.cg.remark.clone(), remark_dir, diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 815a3ee706f8..2943df8f02aa 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -1130,7 +1130,11 @@ pub fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> // We can re-use either the pre- or the post-thinlto state. If no LTO is // being performed then we can use post-LTO artifacts, otherwise we must // reuse pre-LTO artifacts - match compute_per_cgu_lto_type(&tcx.sess.lto(), &tcx.sess.opts, tcx.crate_types()) { + match compute_per_cgu_lto_type( + &tcx.sess.lto(), + tcx.sess.opts.cg.linker_plugin_lto.enabled(), + tcx.crate_types(), + ) { ComputedLtoType::No => CguReuse::PostLto, _ => CguReuse::PreLto, } From 2d7c571391e558a55767dc9aaeca6989a63c77c4 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 21 Nov 2025 15:08:09 +0000 Subject: [PATCH 0009/1061] Remove SharedEmitter from CodegenContext --- compiler/rustc_codegen_gcc/src/back/lto.rs | 12 +- compiler/rustc_codegen_gcc/src/back/write.rs | 8 +- compiler/rustc_codegen_gcc/src/lib.rs | 14 ++- compiler/rustc_codegen_llvm/src/back/lto.rs | 27 +++-- compiler/rustc_codegen_llvm/src/back/write.rs | 43 ++++--- compiler/rustc_codegen_llvm/src/lib.rs | 29 +++-- compiler/rustc_codegen_ssa/src/back/lto.rs | 8 +- compiler/rustc_codegen_ssa/src/back/write.rs | 112 +++++++++++------- .../rustc_codegen_ssa/src/traits/write.rs | 8 +- 9 files changed, 165 insertions(+), 96 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/back/lto.rs b/compiler/rustc_codegen_gcc/src/back/lto.rs index 08c36d2b7318..24be3ee4c34d 100644 --- a/compiler/rustc_codegen_gcc/src/back/lto.rs +++ b/compiler/rustc_codegen_gcc/src/back/lto.rs @@ -26,11 +26,11 @@ use std::sync::atomic::Ordering; use gccjit::{Context, OutputKind}; use object::read::archive::ArchiveFile; use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule, ThinShared}; -use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput}; +use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput, SharedEmitter}; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{ModuleCodegen, ModuleKind, looks_like_rust_object_file}; use rustc_data_structures::memmap::Mmap; -use rustc_errors::DiagCtxtHandle; +use rustc_errors::{DiagCtxt, DiagCtxtHandle}; use rustc_log::tracing::info; use rustc_middle::bug; use rustc_middle::dep_graph::WorkProduct; @@ -112,10 +112,11 @@ fn save_as_file(obj: &[u8], path: &Path) -> Result<(), LtoBitcodeFromRlib> { /// for further optimization. pub(crate) fn run_fat( cgcx: &CodegenContext, + shared_emitter: &SharedEmitter, each_linked_rlib_for_lto: &[PathBuf], modules: Vec>, ) -> ModuleCodegen { - let dcx = cgcx.create_dcx(); + let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); let dcx = dcx.handle(); let lto_data = prepare_lto(cgcx, each_linked_rlib_for_lto, dcx); /*let symbols_below_threshold = @@ -283,12 +284,11 @@ impl ModuleBufferMethods for ModuleBuffer { /// can simply be copied over from the incr. comp. cache. pub(crate) fn run_thin( cgcx: &CodegenContext, + dcx: DiagCtxtHandle<'_>, each_linked_rlib_for_lto: &[PathBuf], modules: Vec<(String, ThinBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, ) -> (Vec>, Vec) { - let dcx = cgcx.create_dcx(); - let dcx = dcx.handle(); let lto_data = prepare_lto(cgcx, each_linked_rlib_for_lto, dcx); if cgcx.use_linker_plugin_lto { unreachable!( @@ -522,8 +522,6 @@ pub fn optimize_thin_module( thin_module: ThinModule, _cgcx: &CodegenContext, ) -> ModuleCodegen { - //let dcx = cgcx.create_dcx(); - //let module_name = &thin_module.shared.module_names[thin_module.idx]; /*let tm_factory_config = TargetMachineFactoryConfig::new(cgcx, module_name.to_str().unwrap()); let tm = (cgcx.tm_factory)(tm_factory_config).map_err(|e| write::llvm_err(&dcx, e))?;*/ diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs index eae0f2aa00f6..b6223c5be370 100644 --- a/compiler/rustc_codegen_gcc/src/back/write.rs +++ b/compiler/rustc_codegen_gcc/src/back/write.rs @@ -2,8 +2,11 @@ use std::{env, fs}; use gccjit::{Context, OutputKind}; use rustc_codegen_ssa::back::link::ensure_removed; -use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, ModuleConfig}; +use rustc_codegen_ssa::back::write::{ + BitcodeSection, CodegenContext, EmitObj, ModuleConfig, SharedEmitter, +}; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; +use rustc_errors::DiagCtxt; use rustc_fs_util::link_or_copy; use rustc_log::tracing::debug; use rustc_session::config::OutputType; @@ -15,10 +18,11 @@ use crate::{GccCodegenBackend, GccContext, LtoMode}; pub(crate) fn codegen( cgcx: &CodegenContext, + shared_emitter: &SharedEmitter, module: ModuleCodegen, config: &ModuleConfig, ) -> CompiledModule { - let dcx = cgcx.create_dcx(); + let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); let dcx = dcx.handle(); let _timer = cgcx.prof.generic_activity_with_arg("GCC_module_codegen", &*module.name); diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 409b7886740a..5a2ec0a2fc68 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -82,7 +82,7 @@ use gccjit::{TargetInfo, Version}; use rustc_ast::expand::allocator::AllocatorMethod; use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule}; use rustc_codegen_ssa::back::write::{ - CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn, + CodegenContext, FatLtoInput, ModuleConfig, SharedEmitter, TargetMachineFactoryFn, }; use rustc_codegen_ssa::base::codegen_crate; use rustc_codegen_ssa::target_features::cfg_target_feature; @@ -371,23 +371,25 @@ impl WriteBackendMethods for GccCodegenBackend { fn run_and_optimize_fat_lto( cgcx: &CodegenContext, + shared_emitter: &SharedEmitter, // FIXME(bjorn3): Limit LTO exports to these symbols _exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], modules: Vec>, ) -> ModuleCodegen { - back::lto::run_fat(cgcx, each_linked_rlib_for_lto, modules) + back::lto::run_fat(cgcx, shared_emitter, each_linked_rlib_for_lto, modules) } fn run_thin_lto( cgcx: &CodegenContext, + dcx: DiagCtxtHandle<'_>, // FIXME(bjorn3): Limit LTO exports to these symbols _exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], modules: Vec<(String, Self::ThinBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, ) -> (Vec>, Vec) { - back::lto::run_thin(cgcx, each_linked_rlib_for_lto, modules, cached_modules) + back::lto::run_thin(cgcx, dcx, each_linked_rlib_for_lto, modules, cached_modules) } fn print_pass_timings(&self) { @@ -400,7 +402,7 @@ impl WriteBackendMethods for GccCodegenBackend { fn optimize( _cgcx: &CodegenContext, - _dcx: DiagCtxtHandle<'_>, + _shared_emitter: &SharedEmitter, module: &mut ModuleCodegen, config: &ModuleConfig, ) { @@ -409,6 +411,7 @@ impl WriteBackendMethods for GccCodegenBackend { fn optimize_thin( cgcx: &CodegenContext, + _shared_emitter: &SharedEmitter, thin: ThinModule, ) -> ModuleCodegen { back::lto::optimize_thin_module(thin, cgcx) @@ -416,10 +419,11 @@ impl WriteBackendMethods for GccCodegenBackend { fn codegen( cgcx: &CodegenContext, + shared_emitter: &SharedEmitter, module: ModuleCodegen, config: &ModuleConfig, ) -> CompiledModule { - back::write::codegen(cgcx, module, config) + back::write::codegen(cgcx, shared_emitter, module, config) } fn prepare_thin(module: ModuleCodegen) -> (String, Self::ThinBuffer) { diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 3137ed288fa8..3210afc063a9 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -9,12 +9,12 @@ use std::{io, iter, slice}; use object::read::archive::ArchiveFile; use object::{Object, ObjectSection}; use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule, ThinShared}; -use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput}; +use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput, SharedEmitter}; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{ModuleCodegen, ModuleKind, looks_like_rust_object_file}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::memmap::Mmap; -use rustc_errors::DiagCtxtHandle; +use rustc_errors::{DiagCtxt, DiagCtxtHandle}; use rustc_hir::attrs::SanitizerSet; use rustc_middle::bug; use rustc_middle::dep_graph::WorkProduct; @@ -150,17 +150,18 @@ fn get_bitcode_slice_from_object_data<'a>( /// for further optimization. pub(crate) fn run_fat( cgcx: &CodegenContext, + shared_emitter: &SharedEmitter, exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], modules: Vec>, ) -> ModuleCodegen { - let dcx = cgcx.create_dcx(); + let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); let dcx = dcx.handle(); let (symbols_below_threshold, upstream_modules) = prepare_lto(cgcx, exported_symbols_for_lto, each_linked_rlib_for_lto, dcx); let symbols_below_threshold = symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::>(); - fat_lto(cgcx, dcx, modules, upstream_modules, &symbols_below_threshold) + fat_lto(cgcx, dcx, shared_emitter, modules, upstream_modules, &symbols_below_threshold) } /// Performs thin LTO by performing necessary global analysis and returning two @@ -168,13 +169,12 @@ pub(crate) fn run_fat( /// can simply be copied over from the incr. comp. cache. pub(crate) fn run_thin( cgcx: &CodegenContext, + dcx: DiagCtxtHandle<'_>, exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], modules: Vec<(String, ThinBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, ) -> (Vec>, Vec) { - let dcx = cgcx.create_dcx(); - let dcx = dcx.handle(); let (symbols_below_threshold, upstream_modules) = prepare_lto(cgcx, exported_symbols_for_lto, each_linked_rlib_for_lto, dcx); let symbols_below_threshold = @@ -197,6 +197,7 @@ pub(crate) fn prepare_thin(module: ModuleCodegen) -> (String, ThinBu fn fat_lto( cgcx: &CodegenContext, dcx: DiagCtxtHandle<'_>, + shared_emitter: &SharedEmitter, modules: Vec>, mut serialized_modules: Vec<(SerializedModule, CString)>, symbols_below_threshold: &[*const libc::c_char], @@ -265,8 +266,13 @@ fn fat_lto( // The linking steps below may produce errors and diagnostics within LLVM // which we'd like to handle and print, so set up our diagnostic handlers // (which get unregistered when they go out of scope below). - let _handler = - DiagnosticHandlers::new(cgcx, dcx, llcx, &module, CodegenDiagnosticsStage::LTO); + let _handler = DiagnosticHandlers::new( + cgcx, + shared_emitter, + llcx, + &module, + CodegenDiagnosticsStage::LTO, + ); // For all other modules we codegened we'll need to link them into our own // bitcode. All modules were codegened in their own LLVM context, however, @@ -730,10 +736,11 @@ impl Drop for ThinBuffer { } pub(crate) fn optimize_thin_module( - thin_module: ThinModule, cgcx: &CodegenContext, + shared_emitter: &SharedEmitter, + thin_module: ThinModule, ) -> ModuleCodegen { - let dcx = cgcx.create_dcx(); + let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); let dcx = dcx.handle(); let module_name = &thin_module.shared.module_names[thin_module.idx]; diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index a49d4c010d67..a5b6ea08a66d 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -9,7 +9,7 @@ use libc::{c_char, c_int, c_void, size_t}; use rustc_codegen_ssa::back::link::ensure_removed; use rustc_codegen_ssa::back::versioned_llvm_target; use rustc_codegen_ssa::back::write::{ - BitcodeSection, CodegenContext, EmitObj, InlineAsmError, ModuleConfig, + BitcodeSection, CodegenContext, EmitObj, InlineAsmError, ModuleConfig, SharedEmitter, TargetMachineFactoryConfig, TargetMachineFactoryFn, }; use rustc_codegen_ssa::base::wants_wasm_eh; @@ -17,7 +17,7 @@ use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen, ModuleKind}; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::small_c_str::SmallCStr; -use rustc_errors::{DiagCtxtHandle, Level}; +use rustc_errors::{DiagCtxt, DiagCtxtHandle, Level}; use rustc_fs_util::{link_or_copy, path_to_c_string}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; @@ -356,7 +356,7 @@ pub(crate) enum CodegenDiagnosticsStage { } pub(crate) struct DiagnosticHandlers<'a> { - data: *mut (&'a CodegenContext, DiagCtxtHandle<'a>), + data: *mut (&'a CodegenContext, &'a SharedEmitter), llcx: &'a llvm::Context, old_handler: Option<&'a llvm::DiagnosticHandler>, } @@ -364,7 +364,7 @@ pub(crate) struct DiagnosticHandlers<'a> { impl<'a> DiagnosticHandlers<'a> { pub(crate) fn new( cgcx: &'a CodegenContext, - dcx: DiagCtxtHandle<'a>, + shared_emitter: &'a SharedEmitter, llcx: &'a llvm::Context, module: &ModuleCodegen, stage: CodegenDiagnosticsStage, @@ -399,7 +399,7 @@ impl<'a> DiagnosticHandlers<'a> { .and_then(|dir| dir.to_str().and_then(|p| CString::new(p).ok())); let pgo_available = cgcx.module_config.pgo_use.is_some(); - let data = Box::into_raw(Box::new((cgcx, dcx))); + let data = Box::into_raw(Box::new((cgcx, shared_emitter))); unsafe { let old_handler = llvm::LLVMRustContextGetDiagnosticHandler(llcx); llvm::LLVMRustContextConfigureDiagnosticHandler( @@ -461,12 +461,16 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void if user.is_null() { return; } - let (cgcx, dcx) = - unsafe { *(user as *const (&CodegenContext, DiagCtxtHandle<'_>)) }; + let (cgcx, shared_emitter) = + unsafe { *(user as *const (&CodegenContext, &SharedEmitter)) }; + + let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); + let dcx = dcx.handle(); match unsafe { llvm::diagnostic::Diagnostic::unpack(info) } { llvm::diagnostic::InlineAsm(inline) => { - cgcx.diag_emitter.inline_asm_error(report_inline_asm( + // FIXME use dcx + shared_emitter.inline_asm_error(report_inline_asm( cgcx, inline.message, inline.level, @@ -777,14 +781,18 @@ pub(crate) unsafe fn llvm_optimize( // Unsafe due to LLVM calls. pub(crate) fn optimize( cgcx: &CodegenContext, - dcx: DiagCtxtHandle<'_>, + shared_emitter: &SharedEmitter, module: &mut ModuleCodegen, config: &ModuleConfig, ) { let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_optimize", &*module.name); + let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); + let dcx = dcx.handle(); + let llcx = &*module.module_llvm.llcx; - let _handlers = DiagnosticHandlers::new(cgcx, dcx, llcx, module, CodegenDiagnosticsStage::Opt); + let _handlers = + DiagnosticHandlers::new(cgcx, shared_emitter, llcx, module, CodegenDiagnosticsStage::Opt); if config.emit_no_opt_bc { let out = cgcx.output_filenames.temp_path_ext_for_cgu( @@ -865,19 +873,26 @@ pub(crate) fn optimize( pub(crate) fn codegen( cgcx: &CodegenContext, + shared_emitter: &SharedEmitter, module: ModuleCodegen, config: &ModuleConfig, ) -> CompiledModule { - let dcx = cgcx.create_dcx(); + let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_codegen", &*module.name); + + let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); let dcx = dcx.handle(); - let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_codegen", &*module.name); { let llmod = module.module_llvm.llmod(); let llcx = &*module.module_llvm.llcx; let tm = &*module.module_llvm.tm; - let _handlers = - DiagnosticHandlers::new(cgcx, dcx, llcx, &module, CodegenDiagnosticsStage::Codegen); + let _handlers = DiagnosticHandlers::new( + cgcx, + shared_emitter, + llcx, + &module, + CodegenDiagnosticsStage::Codegen, + ); if cgcx.msvc_imps_needed { create_msvc_imps(cgcx, llcx, llmod); diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 1b65a133d58c..3901662442e9 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -30,12 +30,13 @@ use llvm_util::target_config; use rustc_ast::expand::allocator::AllocatorMethod; use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule}; use rustc_codegen_ssa::back::write::{ - CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn, + CodegenContext, FatLtoInput, ModuleConfig, SharedEmitter, TargetMachineFactoryConfig, + TargetMachineFactoryFn, }; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen, TargetConfig}; use rustc_data_structures::fx::FxIndexMap; -use rustc_errors::DiagCtxtHandle; +use rustc_errors::{DiagCtxt, DiagCtxtHandle}; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; @@ -166,14 +167,20 @@ impl WriteBackendMethods for LlvmCodegenBackend { } fn run_and_optimize_fat_lto( cgcx: &CodegenContext, + shared_emitter: &SharedEmitter, exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], modules: Vec>, ) -> ModuleCodegen { - let mut module = - back::lto::run_fat(cgcx, exported_symbols_for_lto, each_linked_rlib_for_lto, modules); + let mut module = back::lto::run_fat( + cgcx, + shared_emitter, + exported_symbols_for_lto, + each_linked_rlib_for_lto, + modules, + ); - let dcx = cgcx.create_dcx(); + let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); let dcx = dcx.handle(); back::lto::run_pass_manager(cgcx, dcx, &mut module, false); @@ -181,6 +188,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { } fn run_thin_lto( cgcx: &CodegenContext, + dcx: DiagCtxtHandle<'_>, exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], modules: Vec<(String, Self::ThinBuffer)>, @@ -188,6 +196,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { ) -> (Vec>, Vec) { back::lto::run_thin( cgcx, + dcx, exported_symbols_for_lto, each_linked_rlib_for_lto, modules, @@ -196,24 +205,26 @@ impl WriteBackendMethods for LlvmCodegenBackend { } fn optimize( cgcx: &CodegenContext, - dcx: DiagCtxtHandle<'_>, + shared_emitter: &SharedEmitter, module: &mut ModuleCodegen, config: &ModuleConfig, ) { - back::write::optimize(cgcx, dcx, module, config) + back::write::optimize(cgcx, shared_emitter, module, config) } fn optimize_thin( cgcx: &CodegenContext, + shared_emitter: &SharedEmitter, thin: ThinModule, ) -> ModuleCodegen { - back::lto::optimize_thin_module(thin, cgcx) + back::lto::optimize_thin_module(cgcx, shared_emitter, thin) } fn codegen( cgcx: &CodegenContext, + shared_emitter: &SharedEmitter, module: ModuleCodegen, config: &ModuleConfig, ) -> CompiledModule { - back::write::codegen(cgcx, module, config) + back::write::codegen(cgcx, shared_emitter, module, config) } fn prepare_thin(module: ModuleCodegen) -> (String, Self::ThinBuffer) { back::lto::prepare_thin(module) diff --git a/compiler/rustc_codegen_ssa/src/back/lto.rs b/compiler/rustc_codegen_ssa/src/back/lto.rs index e3dc985bf782..ef4c193c4c2a 100644 --- a/compiler/rustc_codegen_ssa/src/back/lto.rs +++ b/compiler/rustc_codegen_ssa/src/back/lto.rs @@ -2,6 +2,7 @@ use std::ffi::CString; use std::sync::Arc; use rustc_data_structures::memmap::Mmap; +use rustc_errors::DiagCtxtHandle; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportLevel}; use rustc_middle::ty::TyCtxt; @@ -124,14 +125,15 @@ pub(super) fn exported_symbols_for_lto( symbols_below_threshold } -pub(super) fn check_lto_allowed(cgcx: &CodegenContext) { +pub(super) fn check_lto_allowed( + cgcx: &CodegenContext, + dcx: DiagCtxtHandle<'_>, +) { if cgcx.lto == Lto::ThinLocal { // Crate local LTO is always allowed return; } - let dcx = cgcx.create_dcx(); - // Make sure we actually can run LTO for crate_type in cgcx.crate_types.iter() { if !crate_type_allows_lto(*crate_type) { diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index bc7c32931613..76f76c84dbdc 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -15,8 +15,8 @@ use rustc_data_structures::profiling::{SelfProfilerRef, VerboseTimingGuard}; use rustc_errors::emitter::Emitter; use rustc_errors::translation::Translator; use rustc_errors::{ - Diag, DiagArgMap, DiagCtxt, DiagMessage, ErrCode, FatalError, FatalErrorMarker, Level, - MultiSpan, Style, Suggestions, + Diag, DiagArgMap, DiagCtxt, DiagCtxtHandle, DiagMessage, ErrCode, FatalError, FatalErrorMarker, + Level, MultiSpan, Style, Suggestions, }; use rustc_fs_util::link_or_copy; use rustc_incremental::{ @@ -348,8 +348,6 @@ pub struct CodegenContext { pub split_dwarf_kind: rustc_session::config::SplitDwarfKind, pub pointer_size: Size, - /// Emitter to use for diagnostics produced during codegen. - pub diag_emitter: SharedEmitter, /// LLVM optimizations for which we want to print remarks. pub remark: Passes, /// Directory into which should the LLVM optimization remarks be written. @@ -364,14 +362,9 @@ pub struct CodegenContext { pub parallel: bool, } -impl CodegenContext { - pub fn create_dcx(&self) -> DiagCtxt { - DiagCtxt::new(Box::new(self.diag_emitter.clone())) - } -} - fn generate_thin_lto_work( cgcx: &CodegenContext, + dcx: DiagCtxtHandle<'_>, exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], needs_thin_lto: Vec<(String, B::ThinBuffer)>, @@ -381,6 +374,7 @@ fn generate_thin_lto_work( let (lto_modules, copy_jobs) = B::run_thin_lto( cgcx, + dcx, exported_symbols_for_lto, each_linked_rlib_for_lto, needs_thin_lto, @@ -825,14 +819,12 @@ pub(crate) fn compute_per_cgu_lto_type( fn execute_optimize_work_item( cgcx: &CodegenContext, + shared_emitter: SharedEmitter, mut module: ModuleCodegen, ) -> WorkItemResult { let _timer = cgcx.prof.generic_activity_with_arg("codegen_module_optimize", &*module.name); - let dcx = cgcx.create_dcx(); - let dcx = dcx.handle(); - - B::optimize(cgcx, dcx, &mut module, &cgcx.module_config); + B::optimize(cgcx, &shared_emitter, &mut module, &cgcx.module_config); // After we've done the initial round of optimizations we need to // decide whether to synchronously codegen this module or ship it @@ -853,7 +845,7 @@ fn execute_optimize_work_item( match lto_type { ComputedLtoType::No => { - let module = B::codegen(cgcx, module, &cgcx.module_config); + let module = B::codegen(cgcx, &shared_emitter, module, &cgcx.module_config); WorkItemResult::Finished(module) } ComputedLtoType::Thin => { @@ -883,12 +875,16 @@ fn execute_optimize_work_item( fn execute_copy_from_cache_work_item( cgcx: &CodegenContext, + shared_emitter: SharedEmitter, module: CachedModuleCodegen, ) -> CompiledModule { let _timer = cgcx .prof .generic_activity_with_arg("codegen_copy_artifacts_from_incr_cache", &*module.name); + let dcx = DiagCtxt::new(Box::new(shared_emitter)); + let dcx = dcx.handle(); + let incr_comp_session_dir = cgcx.incr_comp_session_dir.as_ref().unwrap(); let mut links_from_incr_cache = Vec::new(); @@ -907,11 +903,7 @@ fn execute_copy_from_cache_work_item( Some(output_path) } Err(error) => { - cgcx.create_dcx().handle().emit_err(errors::CopyPathBuf { - source_file, - output_path, - error, - }); + dcx.emit_err(errors::CopyPathBuf { source_file, output_path, error }); None } } @@ -954,7 +946,7 @@ fn execute_copy_from_cache_work_item( let bytecode = load_from_incr_cache(module_config.emit_bc, OutputType::Bitcode); let object = load_from_incr_cache(should_emit_obj, OutputType::Object); if should_emit_obj && object.is_none() { - cgcx.create_dcx().handle().emit_fatal(errors::NoSavedObjectFile { cgu_name: &module.name }) + dcx.emit_fatal(errors::NoSavedObjectFile { cgu_name: &module.name }) } CompiledModule { @@ -971,6 +963,7 @@ fn execute_copy_from_cache_work_item( fn do_fat_lto( cgcx: &CodegenContext, + shared_emitter: SharedEmitter, exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], mut needs_fat_lto: Vec>, @@ -978,7 +971,10 @@ fn do_fat_lto( ) -> CompiledModule { let _timer = cgcx.prof.verbose_generic_activity("LLVM_fatlto"); - check_lto_allowed(&cgcx); + let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); + let dcx = dcx.handle(); + + check_lto_allowed(&cgcx, dcx); for (module, wp) in import_only_modules { needs_fat_lto.push(FatLtoInput::Serialized { name: wp.cgu_name, buffer: module }) @@ -986,15 +982,17 @@ fn do_fat_lto( let module = B::run_and_optimize_fat_lto( cgcx, + &shared_emitter, exported_symbols_for_lto, each_linked_rlib_for_lto, needs_fat_lto, ); - B::codegen(cgcx, module, &cgcx.module_config) + B::codegen(cgcx, &shared_emitter, module, &cgcx.module_config) } fn do_thin_lto<'a, B: ExtraBackendMethods>( cgcx: &'a CodegenContext, + shared_emitter: SharedEmitter, exported_symbols_for_lto: Arc>, each_linked_rlib_for_lto: Vec, needs_thin_lto: Vec<(String, ::ThinBuffer)>, @@ -1005,7 +1003,10 @@ fn do_thin_lto<'a, B: ExtraBackendMethods>( ) -> Vec { let _timer = cgcx.prof.verbose_generic_activity("LLVM_thinlto"); - check_lto_allowed(&cgcx); + let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); + let dcx = dcx.handle(); + + check_lto_allowed(&cgcx, dcx); let (coordinator_send, coordinator_receive) = channel(); @@ -1030,6 +1031,7 @@ fn do_thin_lto<'a, B: ExtraBackendMethods>( // we don't worry about tokens. for (work, cost) in generate_thin_lto_work( cgcx, + dcx, &exported_symbols_for_lto, &each_linked_rlib_for_lto, needs_thin_lto, @@ -1071,7 +1073,7 @@ fn do_thin_lto<'a, B: ExtraBackendMethods>( while used_token_count < tokens.len() + 1 && let Some((item, _)) = work_items.pop() { - spawn_thin_lto_work(&cgcx, coordinator_send.clone(), item); + spawn_thin_lto_work(&cgcx, shared_emitter.clone(), coordinator_send.clone(), item); used_token_count += 1; } } else { @@ -1095,7 +1097,7 @@ fn do_thin_lto<'a, B: ExtraBackendMethods>( } Err(e) => { let msg = &format!("failed to acquire jobserver token: {e}"); - cgcx.diag_emitter.fatal(msg); + shared_emitter.fatal(msg); codegen_aborted = Some(FatalError); } }, @@ -1133,12 +1135,13 @@ fn do_thin_lto<'a, B: ExtraBackendMethods>( fn execute_thin_lto_work_item( cgcx: &CodegenContext, + shared_emitter: SharedEmitter, module: lto::ThinModule, ) -> CompiledModule { let _timer = cgcx.prof.generic_activity_with_arg("codegen_module_perform_lto", module.name()); - let module = B::optimize_thin(cgcx, module); - B::codegen(cgcx, module, &cgcx.module_config) + let module = B::optimize_thin(cgcx, &shared_emitter, module); + B::codegen(cgcx, &shared_emitter, module, &cgcx.module_config) } /// Messages sent to the coordinator. @@ -1291,7 +1294,6 @@ fn start_executing_work( remark: sess.opts.cg.remark.clone(), remark_dir, incr_comp_session_dir: sess.incr_comp_session_dir_opt().map(|r| r.clone()), - diag_emitter: shared_emitter.clone(), output_filenames: Arc::clone(tcx.output_filenames(())), module_config: regular_config, tm_factory: backend.target_machine_factory(tcx.sess, ol, backend_features), @@ -1488,10 +1490,7 @@ fn start_executing_work( let mut llvm_start_time: Option> = None; if let Some(allocator_module) = &mut allocator_module { - let dcx = cgcx.create_dcx(); - let dcx = dcx.handle(); - - B::optimize(&cgcx, dcx, allocator_module, &allocator_config); + B::optimize(&cgcx, &shared_emitter, allocator_module, &allocator_config); } // Run the message loop while there's still anything that needs message @@ -1529,7 +1528,13 @@ fn start_executing_work( let (item, _) = work_items.pop().expect("queue empty - queue_full_enough() broken?"); main_thread_state = MainThreadState::Lending; - spawn_work(&cgcx, coordinator_send.clone(), &mut llvm_start_time, item); + spawn_work( + &cgcx, + shared_emitter.clone(), + coordinator_send.clone(), + &mut llvm_start_time, + item, + ); } } } else if codegen_state == Completed { @@ -1547,7 +1552,13 @@ fn start_executing_work( MainThreadState::Idle => { if let Some((item, _)) = work_items.pop() { main_thread_state = MainThreadState::Lending; - spawn_work(&cgcx, coordinator_send.clone(), &mut llvm_start_time, item); + spawn_work( + &cgcx, + shared_emitter.clone(), + coordinator_send.clone(), + &mut llvm_start_time, + item, + ); } else { // There is no unstarted work, so let the main thread // take over for a running worker. Otherwise the @@ -1583,7 +1594,13 @@ fn start_executing_work( while running_with_own_token < tokens.len() && let Some((item, _)) = work_items.pop() { - spawn_work(&cgcx, coordinator_send.clone(), &mut llvm_start_time, item); + spawn_work( + &cgcx, + shared_emitter.clone(), + coordinator_send.clone(), + &mut llvm_start_time, + item, + ); running_with_own_token += 1; } } @@ -1726,6 +1743,7 @@ fn start_executing_work( // This uses the implicit token let module = do_fat_lto( &cgcx, + shared_emitter.clone(), &exported_symbols_for_lto, &each_linked_rlib_file_for_lto, needs_fat_lto, @@ -1745,6 +1763,7 @@ fn start_executing_work( compiled_modules.extend(do_thin_lto( &cgcx, + shared_emitter.clone(), exported_symbols_for_lto, each_linked_rlib_file_for_lto, needs_thin_lto, @@ -1759,8 +1778,9 @@ fn start_executing_work( Ok(CompiledModules { modules: compiled_modules, - allocator_module: allocator_module - .map(|allocator_module| B::codegen(&cgcx, allocator_module, &allocator_config)), + allocator_module: allocator_module.map(|allocator_module| { + B::codegen(&cgcx, &shared_emitter, allocator_module, &allocator_config) + }), }) }) .expect("failed to spawn coordinator thread"); @@ -1829,6 +1849,7 @@ pub(crate) struct WorkerFatalError; fn spawn_work<'a, B: ExtraBackendMethods>( cgcx: &'a CodegenContext, + shared_emitter: SharedEmitter, coordinator_send: Sender>, llvm_start_time: &mut Option>, work: WorkItem, @@ -1841,10 +1862,10 @@ fn spawn_work<'a, B: ExtraBackendMethods>( B::spawn_named_thread(cgcx.time_trace, work.short_description(), move || { let result = std::panic::catch_unwind(AssertUnwindSafe(|| match work { - WorkItem::Optimize(m) => execute_optimize_work_item(&cgcx, m), - WorkItem::CopyPostLtoArtifacts(m) => { - WorkItemResult::Finished(execute_copy_from_cache_work_item(&cgcx, m)) - } + WorkItem::Optimize(m) => execute_optimize_work_item(&cgcx, shared_emitter, m), + WorkItem::CopyPostLtoArtifacts(m) => WorkItemResult::Finished( + execute_copy_from_cache_work_item(&cgcx, shared_emitter, m), + ), })); let msg = match result { @@ -1866,6 +1887,7 @@ fn spawn_work<'a, B: ExtraBackendMethods>( fn spawn_thin_lto_work<'a, B: ExtraBackendMethods>( cgcx: &'a CodegenContext, + shared_emitter: SharedEmitter, coordinator_send: Sender, work: ThinLtoWorkItem, ) { @@ -1873,8 +1895,10 @@ fn spawn_thin_lto_work<'a, B: ExtraBackendMethods>( B::spawn_named_thread(cgcx.time_trace, work.short_description(), move || { let result = std::panic::catch_unwind(AssertUnwindSafe(|| match work { - ThinLtoWorkItem::CopyPostLtoArtifacts(m) => execute_copy_from_cache_work_item(&cgcx, m), - ThinLtoWorkItem::ThinLto(m) => execute_thin_lto_work_item(&cgcx, m), + ThinLtoWorkItem::CopyPostLtoArtifacts(m) => { + execute_copy_from_cache_work_item(&cgcx, shared_emitter, m) + } + ThinLtoWorkItem::ThinLto(m) => execute_thin_lto_work_item(&cgcx, shared_emitter, m), })); let msg = match result { diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index 1ac1d7ef2e2e..e1d23841118c 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -4,7 +4,7 @@ use rustc_errors::DiagCtxtHandle; use rustc_middle::dep_graph::WorkProduct; use crate::back::lto::{SerializedModule, ThinModule}; -use crate::back::write::{CodegenContext, FatLtoInput, ModuleConfig}; +use crate::back::write::{CodegenContext, FatLtoInput, ModuleConfig, SharedEmitter}; use crate::{CompiledModule, ModuleCodegen}; pub trait WriteBackendMethods: Clone + 'static { @@ -19,6 +19,7 @@ pub trait WriteBackendMethods: Clone + 'static { /// if necessary and running any further optimizations fn run_and_optimize_fat_lto( cgcx: &CodegenContext, + shared_emitter: &SharedEmitter, exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], modules: Vec>, @@ -28,6 +29,7 @@ pub trait WriteBackendMethods: Clone + 'static { /// can simply be copied over from the incr. comp. cache. fn run_thin_lto( cgcx: &CodegenContext, + dcx: DiagCtxtHandle<'_>, exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], modules: Vec<(String, Self::ThinBuffer)>, @@ -37,16 +39,18 @@ pub trait WriteBackendMethods: Clone + 'static { fn print_statistics(&self); fn optimize( cgcx: &CodegenContext, - dcx: DiagCtxtHandle<'_>, + shared_emitter: &SharedEmitter, module: &mut ModuleCodegen, config: &ModuleConfig, ); fn optimize_thin( cgcx: &CodegenContext, + shared_emitter: &SharedEmitter, thin: ThinModule, ) -> ModuleCodegen; fn codegen( cgcx: &CodegenContext, + shared_emitter: &SharedEmitter, module: ModuleCodegen, config: &ModuleConfig, ) -> CompiledModule; From b13bb4b2da208c2c26d000354816400243df1b4a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 21 Nov 2025 15:26:47 +0000 Subject: [PATCH 0010/1061] Move LTO to OngoingCodegen::join --- compiler/rustc_codegen_ssa/src/back/write.rs | 140 +++++++++++++++---- compiler/rustc_driver_impl/src/lib.rs | 20 +-- compiler/rustc_errors/src/lib.rs | 2 +- compiler/rustc_span/src/fatal_error.rs | 17 +++ 4 files changed, 131 insertions(+), 48 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 76f76c84dbdc..ddcd8decf303 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -16,7 +16,7 @@ use rustc_errors::emitter::Emitter; use rustc_errors::translation::Translator; use rustc_errors::{ Diag, DiagArgMap, DiagCtxt, DiagCtxtHandle, DiagMessage, ErrCode, FatalError, FatalErrorMarker, - Level, MultiSpan, Style, Suggestions, + Level, MultiSpan, Style, Suggestions, catch_fatal_errors, }; use rustc_fs_util::link_or_copy; use rustc_incremental::{ @@ -403,6 +403,29 @@ struct CompiledModules { allocator_module: Option, } +enum MaybeLtoModules { + NoLto { + modules: Vec, + allocator_module: Option, + }, + FatLto { + cgcx: CodegenContext, + exported_symbols_for_lto: Arc>, + each_linked_rlib_file_for_lto: Vec, + needs_fat_lto: Vec>, + lto_import_only_modules: + Vec<(SerializedModule<::ModuleBuffer>, WorkProduct)>, + }, + ThinLto { + cgcx: CodegenContext, + exported_symbols_for_lto: Arc>, + each_linked_rlib_file_for_lto: Vec, + needs_thin_lto: Vec<(String, ::ThinBuffer)>, + lto_import_only_modules: + Vec<(SerializedModule<::ModuleBuffer>, WorkProduct)>, + }, +} + fn need_bitcode_in_object(tcx: TyCtxt<'_>) -> bool { let sess = tcx.sess; sess.opts.cg.embed_bitcode @@ -1239,7 +1262,7 @@ fn start_executing_work( allocator_config: Arc, mut allocator_module: Option>, coordinator_send: Sender>, -) -> thread::JoinHandle> { +) -> thread::JoinHandle, ()>> { let sess = tcx.sess; let mut each_linked_rlib_for_lto = Vec::new(); @@ -1740,43 +1763,43 @@ fn start_executing_work( needs_fat_lto.push(FatLtoInput::InMemory(allocator_module)); } - // This uses the implicit token - let module = do_fat_lto( - &cgcx, - shared_emitter.clone(), - &exported_symbols_for_lto, - &each_linked_rlib_file_for_lto, + return Ok(MaybeLtoModules::FatLto { + cgcx, + exported_symbols_for_lto, + each_linked_rlib_file_for_lto, needs_fat_lto, lto_import_only_modules, - ); - compiled_modules.push(module); + }); } else if !needs_thin_lto.is_empty() || !lto_import_only_modules.is_empty() { assert!(compiled_modules.is_empty()); assert!(needs_fat_lto.is_empty()); - if cgcx.lto != Lto::ThinLocal { + if cgcx.lto == Lto::ThinLocal { + compiled_modules.extend(do_thin_lto( + &cgcx, + shared_emitter.clone(), + exported_symbols_for_lto, + each_linked_rlib_file_for_lto, + needs_thin_lto, + lto_import_only_modules, + )); + } else { if let Some(allocator_module) = allocator_module.take() { let (name, thin_buffer) = B::prepare_thin(allocator_module); needs_thin_lto.push((name, thin_buffer)); } - } - compiled_modules.extend(do_thin_lto( - &cgcx, - shared_emitter.clone(), - exported_symbols_for_lto, - each_linked_rlib_file_for_lto, - needs_thin_lto, - lto_import_only_modules, - )); + return Ok(MaybeLtoModules::ThinLto { + cgcx, + exported_symbols_for_lto, + each_linked_rlib_file_for_lto, + needs_thin_lto, + lto_import_only_modules, + }); + } } - // Regardless of what order these modules completed in, report them to - // the backend in the same order every time to ensure that we're handing - // out deterministic results. - compiled_modules.sort_by(|a, b| a.name.cmp(&b.name)); - - Ok(CompiledModules { + Ok(MaybeLtoModules::NoLto { modules: compiled_modules, allocator_module: allocator_module.map(|allocator_module| { B::codegen(&cgcx, &shared_emitter, allocator_module, &allocator_config) @@ -2074,13 +2097,13 @@ impl SharedEmitterMain { pub struct Coordinator { sender: Sender>, - future: Option>>, + future: Option, ()>>>, // Only used for the Message type. phantom: PhantomData, } impl Coordinator { - fn join(mut self) -> std::thread::Result> { + fn join(mut self) -> std::thread::Result, ()>> { self.future.take().unwrap().join() } } @@ -2111,8 +2134,9 @@ pub struct OngoingCodegen { impl OngoingCodegen { pub fn join(self, sess: &Session) -> (CodegenResults, FxIndexMap) { self.shared_emitter_main.check(sess, true); - let compiled_modules = sess.time("join_worker_thread", || match self.coordinator.join() { - Ok(Ok(compiled_modules)) => compiled_modules, + + let maybe_lto_modules = sess.time("join_worker_thread", || match self.coordinator.join() { + Ok(Ok(maybe_lto_modules)) => maybe_lto_modules, Ok(Err(())) => { sess.dcx().abort_if_errors(); panic!("expected abort due to worker thread errors") @@ -2124,6 +2148,62 @@ impl OngoingCodegen { sess.dcx().abort_if_errors(); + let (shared_emitter, shared_emitter_main) = SharedEmitter::new(); + + // Catch fatal errors to ensure shared_emitter_main.check() can emit the actual diagnostics + let compiled_modules = catch_fatal_errors(|| match maybe_lto_modules { + MaybeLtoModules::NoLto { modules, allocator_module } => { + drop(shared_emitter); + CompiledModules { modules, allocator_module } + } + MaybeLtoModules::FatLto { + cgcx, + exported_symbols_for_lto, + each_linked_rlib_file_for_lto, + needs_fat_lto, + lto_import_only_modules, + } => CompiledModules { + modules: vec![do_fat_lto( + &cgcx, + shared_emitter, + &exported_symbols_for_lto, + &each_linked_rlib_file_for_lto, + needs_fat_lto, + lto_import_only_modules, + )], + allocator_module: None, + }, + MaybeLtoModules::ThinLto { + cgcx, + exported_symbols_for_lto, + each_linked_rlib_file_for_lto, + needs_thin_lto, + lto_import_only_modules, + } => CompiledModules { + modules: do_thin_lto( + &cgcx, + shared_emitter, + exported_symbols_for_lto, + each_linked_rlib_file_for_lto, + needs_thin_lto, + lto_import_only_modules, + ), + allocator_module: None, + }, + }); + + shared_emitter_main.check(sess, true); + + sess.dcx().abort_if_errors(); + + let mut compiled_modules = + compiled_modules.expect("fatal error emitted but not sent to SharedEmitter"); + + // Regardless of what order these modules completed in, report them to + // the backend in the same order every time to ensure that we're handing + // out deterministic results. + compiled_modules.modules.sort_by(|a, b| a.name.cmp(&b.name)); + let work_products = copy_all_cgu_workproducts_to_incr_comp_cache_dir(sess, &compiled_modules); produce_final_output_artifacts(sess, &compiled_modules, &self.output_filenames); diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 9a3d7cc506cf..cf5a5fdd234c 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -19,7 +19,7 @@ use std::ffi::OsString; use std::fmt::Write as _; use std::fs::{self, File}; use std::io::{self, IsTerminal, Read, Write}; -use std::panic::{self, PanicHookInfo, catch_unwind}; +use std::panic::{self, PanicHookInfo}; use std::path::{Path, PathBuf}; use std::process::{self, Command, Stdio}; use std::sync::OnceLock; @@ -33,10 +33,11 @@ use rustc_codegen_ssa::{CodegenErrors, CodegenResults}; use rustc_data_structures::profiling::{ TimePassesFormat, get_resident_set_size, print_time_passes_entry, }; +pub use rustc_errors::catch_fatal_errors; use rustc_errors::emitter::stderr_destination; use rustc_errors::registry::Registry; use rustc_errors::translation::Translator; -use rustc_errors::{ColorConfig, DiagCtxt, ErrCode, FatalError, PResult, markdown}; +use rustc_errors::{ColorConfig, DiagCtxt, ErrCode, PResult, markdown}; use rustc_feature::find_gated_cfg; // This avoids a false positive with `-Wunused_crate_dependencies`. // `rust_index` isn't used in this crate's code, but it must be named in the @@ -1306,21 +1307,6 @@ fn parse_crate_attrs<'a>(sess: &'a Session) -> PResult<'a, ast::AttrVec> { parser.parse_inner_attributes() } -/// Runs a closure and catches unwinds triggered by fatal errors. -/// -/// The compiler currently unwinds with a special sentinel value to abort -/// compilation on fatal errors. This function catches that sentinel and turns -/// the panic into a `Result` instead. -pub fn catch_fatal_errors R, R>(f: F) -> Result { - catch_unwind(panic::AssertUnwindSafe(f)).map_err(|value| { - if value.is::() { - FatalError - } else { - panic::resume_unwind(value); - } - }) -} - /// Variant of `catch_fatal_errors` for the `interface::Result` return type /// that also computes the exit code. pub fn catch_with_exit_code(f: impl FnOnce()) -> i32 { diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index bbdda155496f..ada32bf0c283 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -68,7 +68,7 @@ pub use rustc_lint_defs::{Applicability, listify, pluralize}; use rustc_lint_defs::{Lint, LintExpectationId}; use rustc_macros::{Decodable, Encodable}; pub use rustc_span::ErrorGuaranteed; -pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker}; +pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker, catch_fatal_errors}; use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, DUMMY_SP, Loc, Span}; pub use snippet::Style; diff --git a/compiler/rustc_span/src/fatal_error.rs b/compiler/rustc_span/src/fatal_error.rs index 26c5711099c6..5e2d82681a11 100644 --- a/compiler/rustc_span/src/fatal_error.rs +++ b/compiler/rustc_span/src/fatal_error.rs @@ -3,6 +3,8 @@ #[must_use] pub struct FatalError; +use std::panic; + pub use rustc_data_structures::FatalErrorMarker; // Don't implement Send on FatalError. This makes it impossible to `panic_any!(FatalError)`. @@ -22,3 +24,18 @@ impl std::fmt::Display for FatalError { } impl std::error::Error for FatalError {} + +/// Runs a closure and catches unwinds triggered by fatal errors. +/// +/// The compiler currently unwinds with a special sentinel value to abort +/// compilation on fatal errors. This function catches that sentinel and turns +/// the panic into a `Result` instead. +pub fn catch_fatal_errors R, R>(f: F) -> Result { + panic::catch_unwind(panic::AssertUnwindSafe(f)).map_err(|value| { + if value.is::() { + FatalError + } else { + panic::resume_unwind(value); + } + }) +} From 845da883816d60b6a3c8b161ecf5d3c306867afa Mon Sep 17 00:00:00 2001 From: Aatif Syed Date: Fri, 28 Nov 2025 00:52:38 +0000 Subject: [PATCH 0011/1061] refactor: remove Ord bound from BinaryHeap::new etc --- library/alloc/src/collections/binary_heap/mod.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index 63828b482b9a..a221c66d31d5 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -466,7 +466,7 @@ impl Clone for BinaryHeap { } #[stable(feature = "rust1", since = "1.0.0")] -impl Default for BinaryHeap { +impl Default for BinaryHeap { /// Creates an empty `BinaryHeap`. #[inline] fn default() -> BinaryHeap { @@ -496,7 +496,7 @@ impl Drop for RebuildOnDrop<'_, T, A> { } } -impl BinaryHeap { +impl BinaryHeap { /// Creates an empty `BinaryHeap` as a max-heap. /// /// # Examples @@ -537,7 +537,7 @@ impl BinaryHeap { } } -impl BinaryHeap { +impl BinaryHeap { /// Creates an empty `BinaryHeap` as a max-heap, using `A` as allocator. /// /// # Examples @@ -615,7 +615,9 @@ impl BinaryHeap { pub fn peek_mut(&mut self) -> Option> { if self.is_empty() { None } else { Some(PeekMut { heap: self, original_len: None }) } } +} +impl BinaryHeap { /// Removes the greatest item from the binary heap and returns it, or `None` if it /// is empty. /// From fcf24266b4feb4f788ad1d51d8f056cce039cf00 Mon Sep 17 00:00:00 2001 From: Aatif Syed Date: Fri, 28 Nov 2025 01:19:07 +0000 Subject: [PATCH 0012/1061] fix: BinaryHeap::peek_mut --- library/alloc/src/collections/binary_heap/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index a221c66d31d5..5710b2a3a91d 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -581,7 +581,9 @@ impl BinaryHeap { pub fn with_capacity_in(capacity: usize, alloc: A) -> BinaryHeap { BinaryHeap { data: Vec::with_capacity_in(capacity, alloc) } } +} +impl BinaryHeap { /// Returns a mutable reference to the greatest item in the binary heap, or /// `None` if it is empty. /// @@ -615,9 +617,7 @@ impl BinaryHeap { pub fn peek_mut(&mut self) -> Option> { if self.is_empty() { None } else { Some(PeekMut { heap: self, original_len: None }) } } -} -impl BinaryHeap { /// Removes the greatest item from the binary heap and returns it, or `None` if it /// is empty. /// From ae310e230a14205b26f2c2796d80e9d90a6b5333 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Wed, 12 Nov 2025 19:26:31 +0000 Subject: [PATCH 0013/1061] fix: `redundant_pattern_matching` misses `)` in suggestion span --- .../src/matches/redundant_pattern_match.rs | 14 ++++---------- tests/ui/redundant_pattern_matching_option.fixed | 13 +++++++++++++ tests/ui/redundant_pattern_matching_option.rs | 13 +++++++++++++ tests/ui/redundant_pattern_matching_option.stderr | 14 +++++++++++++- 4 files changed, 43 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index bc3783750e5c..897e7da5a967 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -1,7 +1,6 @@ use super::REDUNDANT_PATTERN_MATCHING; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; -use clippy_utils::source::walk_span_to_context; use clippy_utils::sugg::{Sugg, make_unop}; use clippy_utils::ty::needs_ordered_drop; use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr_without_closures}; @@ -25,7 +24,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { .. }) = higher::WhileLet::hir(expr) { - find_method_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false); + find_method_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false, let_span); find_if_let_true(cx, let_pat, let_expr, let_span); } } @@ -39,7 +38,7 @@ pub(super) fn check_if_let<'tcx>( let_span: Span, ) { find_if_let_true(cx, pat, scrutinee, let_span); - find_method_sugg_for_if_let(cx, expr, pat, scrutinee, "if", has_else); + find_method_sugg_for_if_let(cx, expr, pat, scrutinee, "if", has_else, let_span); } /// Looks for: @@ -182,6 +181,7 @@ fn find_method_sugg_for_if_let<'tcx>( let_expr: &'tcx Expr<'_>, keyword: &'static str, has_else: bool, + let_span: Span, ) { // also look inside refs // if we have &None for example, peel it so we can detect "if let None = x" @@ -239,15 +239,9 @@ fn find_method_sugg_for_if_let<'tcx>( let expr_span = expr.span; let ctxt = expr.span.ctxt(); - // if/while let ... = ... { ... } - // ^^^ - let Some(res_span) = walk_span_to_context(result_expr.span.source_callsite(), ctxt) else { - return; - }; - // if/while let ... = ... { ... } // ^^^^^^^^^^^^^^^^^^^^^^ - let span = expr_span.until(res_span.shrink_to_hi()); + let span = expr_span.until(let_span.shrink_to_hi()); let mut app = if needs_drop { Applicability::MaybeIncorrect diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed index 08903ef7fdda..b44009446640 100644 --- a/tests/ui/redundant_pattern_matching_option.fixed +++ b/tests/ui/redundant_pattern_matching_option.fixed @@ -195,3 +195,16 @@ fn issue16045() { } } } + +fn issue14989() { + macro_rules! x { + () => { + None:: + }; + } + + if x! {}.is_some() {}; + //~^ redundant_pattern_matching + while x! {}.is_some() {} + //~^ redundant_pattern_matching +} diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs index 95eff3f9ebf9..c13cf993e786 100644 --- a/tests/ui/redundant_pattern_matching_option.rs +++ b/tests/ui/redundant_pattern_matching_option.rs @@ -231,3 +231,16 @@ fn issue16045() { } } } + +fn issue14989() { + macro_rules! x { + () => { + None:: + }; + } + + if let Some(_) = (x! {}) {}; + //~^ redundant_pattern_matching + while let Some(_) = (x! {}) {} + //~^ redundant_pattern_matching +} diff --git a/tests/ui/redundant_pattern_matching_option.stderr b/tests/ui/redundant_pattern_matching_option.stderr index 6fd0c5a6f859..5c9edfd4c50a 100644 --- a/tests/ui/redundant_pattern_matching_option.stderr +++ b/tests/ui/redundant_pattern_matching_option.stderr @@ -236,5 +236,17 @@ error: redundant pattern matching, consider using `is_some()` LL | if let Some(_) = x.await { | -------^^^^^^^---------- help: try: `if x.await.is_some()` -error: aborting due to 33 previous errors +error: redundant pattern matching, consider using `is_some()` + --> tests/ui/redundant_pattern_matching_option.rs:242:12 + | +LL | if let Some(_) = (x! {}) {}; + | -------^^^^^^^---------- help: try: `if x! {}.is_some()` + +error: redundant pattern matching, consider using `is_some()` + --> tests/ui/redundant_pattern_matching_option.rs:244:15 + | +LL | while let Some(_) = (x! {}) {} + | ----------^^^^^^^---------- help: try: `while x! {}.is_some()` + +error: aborting due to 35 previous errors From 7553f464308db4d5508e81dd4d4ad92252186a68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Thu, 4 Dec 2025 10:41:13 +0000 Subject: [PATCH 0014/1061] inline constant typeck constraint --- .../src/polonius/typeck_constraints.rs | 32 +++++++------------ 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs b/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs index e4e52962bf7f..7d406837f5ae 100644 --- a/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs +++ b/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs @@ -45,7 +45,6 @@ pub(super) fn convert_typeck_constraints<'tcx>( { localize_statement_constraint( tcx, - body, stmt, &outlives_constraint, point, @@ -74,7 +73,6 @@ pub(super) fn convert_typeck_constraints<'tcx>( /// needed CFG `from`-`to` intra-block nodes. fn localize_statement_constraint<'tcx>( tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, stmt: &Statement<'tcx>, outlives_constraint: &OutlivesConstraint<'tcx>, current_point: PointIndex, @@ -114,28 +112,22 @@ fn localize_statement_constraint<'tcx>( }, "there should be no common regions between the LHS and RHS of an assignment" ); - - let lhs_ty = body.local_decls[lhs.local].ty; - let successor_point = current_point; - compute_constraint_direction( - tcx, - outlives_constraint, - &lhs_ty, - current_point, - successor_point, - universal_regions, - ) } _ => { - // For the other cases, we localize an outlives constraint to where it arises. - LocalizedOutlivesConstraint { - source: outlives_constraint.sup, - from: current_point, - target: outlives_constraint.sub, - to: current_point, - } + // Assignments should be the only statement that can both generate constraints that + // apply on entry (specific to the RHS place) *and* others that only apply on exit (the + // subset of RHS regions that actually flow into the LHS): i.e., where midpoints would + // be used to ensure the former happen before the latter, within the same MIR Location. } } + + // We generally localize an outlives constraint to where it arises. + LocalizedOutlivesConstraint { + source: outlives_constraint.sup, + from: current_point, + target: outlives_constraint.sub, + to: current_point, + } } /// For a given outlives constraint arising from a MIR terminator, localize the constraint with the From 38f795dd028fd02b28278c43a828907e34f82cbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Thu, 4 Dec 2025 11:18:06 +0000 Subject: [PATCH 0015/1061] update comments --- .../rustc_borrowck/src/polonius/typeck_constraints.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs b/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs index 7d406837f5ae..cfe9376fb502 100644 --- a/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs +++ b/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs @@ -142,14 +142,12 @@ fn localize_terminator_constraint<'tcx>( universal_regions: &UniversalRegions<'tcx>, ) -> LocalizedOutlivesConstraint { // FIXME: check if other terminators need the same handling as `Call`s, in particular - // Assert/Yield/Drop. A handful of tests are failing with Drop related issues, as well as some - // coroutine tests, and that may be why. + // Assert/Yield/Drop. match &terminator.kind { // FIXME: also handle diverging calls. TerminatorKind::Call { destination, target: Some(target), .. } => { - // Calls are similar to assignments, and thus follow the same pattern. If there is a - // target for the call we also relate what flows into the destination here to entry to - // that successor. + // If there is a target for the call we also relate what flows into the destination here + // to entry to that successor. let destination_ty = destination.ty(&body.local_decls, tcx); let successor_location = Location { block: *target, statement_index: 0 }; let successor_point = liveness.point_from_location(successor_location); From c17b4a2ec78e9d726e471feba169572ec33ea230 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Fischer?= Date: Thu, 18 Sep 2025 23:10:59 -0300 Subject: [PATCH 0016/1061] Clarify `strlen_on_c_strings` documentation --- clippy_lints/src/strlen_on_c_strings.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/strlen_on_c_strings.rs b/clippy_lints/src/strlen_on_c_strings.rs index 33856c750d7e..2e7affb8d07f 100644 --- a/clippy_lints/src/strlen_on_c_strings.rs +++ b/clippy_lints/src/strlen_on_c_strings.rs @@ -14,8 +14,8 @@ declare_clippy_lint! { /// and suggest calling `as_bytes().len()` or `to_bytes().len()` respectively instead. /// /// ### Why is this bad? - /// This avoids calling an unsafe `libc` function. - /// Currently, it also avoids calculating the length. + /// libc::strlen is an unsafe function, which we don't need to call + /// if all we want to know is the length of the c-string. /// /// ### Example /// ```rust, ignore From c1472c573ae83c45a11bb61b10f205c65322485f Mon Sep 17 00:00:00 2001 From: Evgenii Zheltonozhskii Date: Fri, 12 Dec 2025 06:31:00 +0200 Subject: [PATCH 0017/1061] Add const cloning of slices and tests --- library/core/src/slice/mod.rs | 30 +++++++++----- library/coretests/tests/clone.rs | 71 ++++++++++++++++++++++++++++++++ library/coretests/tests/lib.rs | 3 ++ 3 files changed, 94 insertions(+), 10 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index dc34d2a21ee9..3202a330b7a4 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -9,6 +9,7 @@ use crate::clone::TrivialClone; use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::intrinsics::{exact_div, unchecked_sub}; +use crate::marker::Destruct; use crate::mem::{self, MaybeUninit, SizedTypeProperties}; use crate::num::NonZero; use crate::ops::{OneSidedRange, OneSidedRangeBound, Range, RangeBounds, RangeInclusive}; @@ -3823,9 +3824,10 @@ impl [T] { /// [`split_at_mut`]: slice::split_at_mut #[stable(feature = "clone_from_slice", since = "1.7.0")] #[track_caller] - pub fn clone_from_slice(&mut self, src: &[T]) + #[rustc_const_unstable(feature = "const_clone", issue = "142757")] + pub const fn clone_from_slice(&mut self, src: &[T]) where - T: Clone, + T: [const] Clone + [const] Destruct, { self.spec_clone_from(src); } @@ -5136,13 +5138,17 @@ const unsafe fn copy_from_slice_impl(dest: &mut [T], src: &[T]) { } } -trait CloneFromSpec { - fn spec_clone_from(&mut self, src: &[T]); +#[rustc_const_unstable(feature = "const_clone", issue = "142757")] +const trait CloneFromSpec { + fn spec_clone_from(&mut self, src: &[T]) + where + T: [const] Destruct; } -impl CloneFromSpec for [T] +#[rustc_const_unstable(feature = "const_clone", issue = "142757")] +impl const CloneFromSpec for [T] where - T: Clone, + T: [const] Clone + [const] Destruct, { #[track_caller] default fn spec_clone_from(&mut self, src: &[T]) { @@ -5152,15 +5158,19 @@ where // But since it can't be relied on we also have an explicit specialization for T: Copy. let len = self.len(); let src = &src[..len]; - for i in 0..len { - self[i].clone_from(&src[i]); + // FIXME(const_hack): make this a `for idx in 0..self.len()` loop. + let mut idx = 0; + while idx < self.len() { + self[idx].clone_from(&src[idx]); + idx += 1; } } } -impl CloneFromSpec for [T] +#[rustc_const_unstable(feature = "const_clone", issue = "142757")] +impl const CloneFromSpec for [T] where - T: TrivialClone, + T: [const] TrivialClone + [const] Destruct, { #[track_caller] fn spec_clone_from(&mut self, src: &[T]) { diff --git a/library/coretests/tests/clone.rs b/library/coretests/tests/clone.rs index 054b1d3d4986..68871dbccf07 100644 --- a/library/coretests/tests/clone.rs +++ b/library/coretests/tests/clone.rs @@ -121,3 +121,74 @@ fn cstr_metadata_is_length_with_nul() { let bytes: *const [u8] = p as *const [u8]; assert_eq!(s.to_bytes_with_nul().len(), bytes.len()); } + +#[test] +fn test_const_clone() { + const { + let bool: bool = Default::default(); + let char: char = Default::default(); + let ascii_char: std::ascii::Char = Default::default(); + let usize: usize = Default::default(); + let u8: u8 = Default::default(); + let u16: u16 = Default::default(); + let u32: u32 = Default::default(); + let u64: u64 = Default::default(); + let u128: u128 = Default::default(); + let i8: i8 = Default::default(); + let i16: i16 = Default::default(); + let i32: i32 = Default::default(); + let i64: i64 = Default::default(); + let i128: i128 = Default::default(); + let f16: f16 = Default::default(); + let f32: f32 = Default::default(); + let f64: f64 = Default::default(); + let f128: f128 = Default::default(); + + let bool_clone: bool = bool.clone(); + let char_clone: char = char.clone(); + let ascii_char_clone: std::ascii::Char = ascii_char.clone(); + + let usize_clone: usize = usize.clone(); + let u8_clone: u8 = u8.clone(); + let u16_clone: u16 = u16.clone(); + let u32_clone: u32 = u32.clone(); + let u64_clone: u64 = u64.clone(); + let u128_clone: u128 = u128.clone(); + let i8_clone: i8 = i8.clone(); + let i16_clone: i16 = i16.clone(); + let i32_clone: i32 = i32.clone(); + let i64_clone: i64 = i64.clone(); + let i128_clone: i128 = i128.clone(); + let f16_clone: f16 = f16.clone(); + let f32_clone: f32 = f32.clone(); + let f64_clone: f64 = f64.clone(); + let f128_clone: f128 = f128.clone(); + + assert!(bool == bool_clone); + assert!(char == char_clone); + assert!(ascii_char == ascii_char_clone); + assert!(usize == usize_clone); + assert!(u8 == u8_clone); + assert!(u16 == u16_clone); + assert!(u32 == u32_clone); + assert!(u64 == u64_clone); + assert!(u128 == u128_clone); + assert!(i8 == i8_clone); + assert!(i16 == i16_clone); + assert!(i32 == i32_clone); + assert!(i64 == i64_clone); + assert!(i128 == i128_clone); + assert!(f16 == f16_clone); + assert!(f32 == f32_clone); + assert!(f64 == f64_clone); + assert!(f128 == f128_clone); + + let src: [i32; 4] = [1, 2, 3, 4]; + let mut dst: [i32; 2] = [0, 0]; + + dst.clone_from_slice(&src[2..]); + + assert!(src == [1, 2, 3, 4]); + assert!(dst == [3, 4]); + } +} diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 0387b442562d..a8421f333155 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -19,11 +19,14 @@ #![feature(clone_to_uninit)] #![feature(const_array)] #![feature(const_cell_traits)] +#![feature(const_clone)] #![feature(const_cmp)] #![feature(const_convert)] +#![feature(const_default)] #![feature(const_destruct)] #![feature(const_drop_in_place)] #![feature(const_eval_select)] +#![feature(const_index)] #![feature(const_ops)] #![feature(const_option_ops)] #![feature(const_ref_cell)] From d0d8258886dfb8c09d337b094ca1e6f26f85cd8b Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 12 Oct 2025 17:19:17 +0200 Subject: [PATCH 0018/1061] Stabilize `-Zremap-path-scope` as `--remap-path-scope` In the process also document that new `--remap-path-scope` scopes may be added in the future, and that the `all` scope always represent all the scopes. Co-authored-by: David Wood --- compiler/rustc_session/src/config.rs | 48 ++++++++++++++++--- compiler/rustc_session/src/options.rs | 28 +---------- src/doc/rustc/src/command-line-arguments.md | 8 ++++ src/doc/rustc/src/remap-source-paths.md | 27 ++++++++++- .../src/compiler-flags/remap-path-scope.md | 23 --------- tests/coverage/remap-path-prefix.rs | 6 +-- ...emap-path-prefix.with_macro_scope.coverage | 6 +-- .../remap-path-prefix-consts/rmake.rs | 4 +- .../run-make/remap-path-prefix-dwarf/rmake.rs | 8 ++-- tests/run-make/remap-path-prefix/rmake.rs | 6 +-- tests/run-make/rustc-help/help-v.diff | 5 +- tests/run-make/rustc-help/help-v.stdout | 3 ++ tests/run-make/split-debuginfo/rmake.rs | 13 +++-- tests/ui/errors/auxiliary/file-debuginfo.rs | 2 +- tests/ui/errors/auxiliary/file-diag.rs | 2 +- tests/ui/errors/auxiliary/file-macro.rs | 2 +- tests/ui/errors/auxiliary/trait-debuginfo.rs | 2 +- tests/ui/errors/auxiliary/trait-diag.rs | 2 +- tests/ui/errors/auxiliary/trait-macro.rs | 2 +- .../errors/remap-path-prefix-diagnostics.rs | 10 ++-- tests/ui/errors/remap-path-prefix-macro.rs | 10 ++-- tests/ui/errors/remap-path-prefix.rs | 4 +- 22 files changed, 124 insertions(+), 97 deletions(-) delete mode 100644 src/doc/unstable-book/src/compiler-flags/remap-path-scope.md diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index be4b36e3b926..4d2ca8987df4 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -24,7 +24,9 @@ use rustc_hashes::Hash64; use rustc_macros::{BlobDecodable, Decodable, Encodable, HashStable_Generic}; use rustc_span::edition::{DEFAULT_EDITION, EDITION_NAME_LIST, Edition, LATEST_STABLE_EDITION}; use rustc_span::source_map::FilePathMapping; -use rustc_span::{FileName, RealFileName, SourceFileHashAlgorithm, Symbol, sym}; +use rustc_span::{ + FileName, RealFileName, RemapPathScopeComponents, SourceFileHashAlgorithm, Symbol, sym, +}; use rustc_target::spec::{ FramePointer, LinkSelfContainedComponents, LinkerFeatures, PanicStrategy, SplitDebuginfo, Target, TargetTuple, @@ -1315,6 +1317,29 @@ impl OutputFilenames { } } +pub(crate) fn parse_remap_path_scope( + early_dcx: &EarlyDiagCtxt, + matches: &getopts::Matches, +) -> RemapPathScopeComponents { + if let Some(v) = matches.opt_str("remap-path-scope") { + let mut slot = RemapPathScopeComponents::empty(); + for s in v.split(',') { + slot |= match s { + "macro" => RemapPathScopeComponents::MACRO, + "diagnostics" => RemapPathScopeComponents::DIAGNOSTICS, + "debuginfo" => RemapPathScopeComponents::DEBUGINFO, + "coverage" => RemapPathScopeComponents::COVERAGE, + "object" => RemapPathScopeComponents::OBJECT, + "all" => RemapPathScopeComponents::all(), + _ => early_dcx.early_fatal("argument for `--remap-path-scope` must be a comma separated list of scopes: `macro`, `diagnostics`, `debuginfo`, `coverage`, `object`, `all`"), + } + } + slot + } else { + RemapPathScopeComponents::all() + } +} + #[derive(Clone, Debug)] pub struct Sysroot { pub explicit: Option, @@ -1351,9 +1376,9 @@ pub fn host_tuple() -> &'static str { fn file_path_mapping( remap_path_prefix: Vec<(PathBuf, PathBuf)>, - unstable_opts: &UnstableOptions, + remap_path_scope: RemapPathScopeComponents, ) -> FilePathMapping { - FilePathMapping::new(remap_path_prefix.clone(), unstable_opts.remap_path_scope) + FilePathMapping::new(remap_path_prefix.clone(), remap_path_scope) } impl Default for Options { @@ -1365,7 +1390,7 @@ impl Default for Options { // to create a default working directory. let working_dir = { let working_dir = std::env::current_dir().unwrap(); - let file_mapping = file_path_mapping(Vec::new(), &unstable_opts); + let file_mapping = file_path_mapping(Vec::new(), RemapPathScopeComponents::empty()); file_mapping.to_real_filename(&RealFileName::empty(), &working_dir) }; @@ -1401,6 +1426,7 @@ impl Default for Options { cli_forced_codegen_units: None, cli_forced_local_thinlto_off: false, remap_path_prefix: Vec::new(), + remap_path_scope: RemapPathScopeComponents::all(), real_rust_source_base_dir: None, real_rustc_dev_source_base_dir: None, edition: DEFAULT_EDITION, @@ -1427,7 +1453,7 @@ impl Options { } pub fn file_path_mapping(&self) -> FilePathMapping { - file_path_mapping(self.remap_path_prefix.clone(), &self.unstable_opts) + file_path_mapping(self.remap_path_prefix.clone(), self.remap_path_scope) } /// Returns `true` if there will be an output file generated. @@ -1864,6 +1890,14 @@ pub fn rustc_optgroups() -> Vec { "Remap source names in all output (compiler messages and output files)", "=", ), + opt( + Stable, + Opt, + "", + "remap-path-scope", + "Defines which scopes of paths should be remapped by `--remap-path-prefix`", + "", + ), opt(Unstable, Multi, "", "env-set", "Inject an environment variable", "="), ]; options.extend(verbose_only.into_iter().map(|mut opt| { @@ -2704,6 +2738,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M let externs = parse_externs(early_dcx, matches, &unstable_opts); let remap_path_prefix = parse_remap_path_prefix(early_dcx, matches, &unstable_opts); + let remap_path_scope = parse_remap_path_scope(early_dcx, matches); let pretty = parse_pretty(early_dcx, &unstable_opts); @@ -2770,7 +2805,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M early_dcx.early_fatal(format!("Current directory is invalid: {e}")); }); - let file_mapping = file_path_mapping(remap_path_prefix.clone(), &unstable_opts); + let file_mapping = file_path_mapping(remap_path_prefix.clone(), remap_path_scope); file_mapping.to_real_filename(&RealFileName::empty(), &working_dir) }; @@ -2808,6 +2843,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M cli_forced_codegen_units: codegen_units, cli_forced_local_thinlto_off: disable_local_thinlto, remap_path_prefix, + remap_path_scope, real_rust_source_base_dir, real_rustc_dev_source_base_dir, edition, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index aea0b73ee927..42d62a7f8437 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -454,6 +454,8 @@ top_level_options!( /// Remap source path prefixes in all output (messages, object files, debug, etc.). remap_path_prefix: Vec<(PathBuf, PathBuf)> [TRACKED_NO_CRATE_HASH], + /// Defines which scopes of paths should be remapped by `--remap-path-prefix`. + remap_path_scope: RemapPathScopeComponents [TRACKED_NO_CRATE_HASH], /// Base directory containing the `library/` directory for the Rust standard library. /// Right now it's always `$sysroot/lib/rustlib/src/rust` @@ -872,7 +874,6 @@ mod desc { pub(crate) const parse_branch_protection: &str = "a `,` separated combination of `bti`, `gcs`, `pac-ret`, (optionally with `pc`, `b-key`, `leaf` if `pac-ret` is set)"; pub(crate) const parse_proc_macro_execution_strategy: &str = "one of supported execution strategies (`same-thread`, or `cross-thread`)"; - pub(crate) const parse_remap_path_scope: &str = "comma separated list of scopes: `macro`, `diagnostics`, `debuginfo`, `coverage`, `object`, `all`"; pub(crate) const parse_inlining_threshold: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a non-negative number"; pub(crate) const parse_llvm_module_flag: &str = ":::. Type must currently be `u32`. Behavior should be one of (`error`, `warning`, `require`, `override`, `append`, `appendunique`, `max`, `min`)"; @@ -1711,29 +1712,6 @@ pub mod parse { true } - pub(crate) fn parse_remap_path_scope( - slot: &mut RemapPathScopeComponents, - v: Option<&str>, - ) -> bool { - if let Some(v) = v { - *slot = RemapPathScopeComponents::empty(); - for s in v.split(',') { - *slot |= match s { - "macro" => RemapPathScopeComponents::MACRO, - "diagnostics" => RemapPathScopeComponents::DIAGNOSTICS, - "debuginfo" => RemapPathScopeComponents::DEBUGINFO, - "coverage" => RemapPathScopeComponents::COVERAGE, - "object" => RemapPathScopeComponents::OBJECT, - "all" => RemapPathScopeComponents::all(), - _ => return false, - } - } - true - } else { - false - } - } - pub(crate) fn parse_relocation_model(slot: &mut Option, v: Option<&str>) -> bool { match v.and_then(|s| RelocModel::from_str(s).ok()) { Some(relocation_model) => *slot = Some(relocation_model), @@ -2584,8 +2562,6 @@ options! { "whether ELF relocations can be relaxed"), remap_cwd_prefix: Option = (None, parse_opt_pathbuf, [TRACKED], "remap paths under the current working directory to this path prefix"), - remap_path_scope: RemapPathScopeComponents = (RemapPathScopeComponents::all(), parse_remap_path_scope, [TRACKED], - "remap path scope (default: all)"), remark_dir: Option = (None, parse_opt_pathbuf, [UNTRACKED], "directory into which to write optimization remarks (if not specified, they will be \ written to standard error output)"), diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index 0b15fbc24dfc..1309ecd73679 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -428,6 +428,14 @@ specified multiple times. Refer to the [Remap source paths](remap-source-paths.md) section of this book for further details and explanation. + +## `--remap-path-scope`: remap source paths in output + +Defines which scopes of paths should be remapped by `--remap-path-prefix`. + +Refer to the [Remap source paths](remap-source-paths.md) section of this book for +further details and explanation. + ## `--json`: configure json messages printed by the compiler diff --git a/src/doc/rustc/src/remap-source-paths.md b/src/doc/rustc/src/remap-source-paths.md index 03f5d98091cc..d27359fb550f 100644 --- a/src/doc/rustc/src/remap-source-paths.md +++ b/src/doc/rustc/src/remap-source-paths.md @@ -6,7 +6,7 @@ output, including compiler diagnostics, debugging information, macro expansions, This is useful for normalizing build products, for example by removing the current directory out of the paths emitted into object files. -The remapping is done via the `--remap-path-prefix` option. +The remapping is done via the `--remap-path-prefix` flag and can be customized via the `--remap-path-scope` flag. ## `--remap-path-prefix` @@ -25,6 +25,31 @@ rustc --remap-path-prefix "/home/user/project=/redacted" This example replaces all occurrences of `/home/user/project` in emitted paths with `/redacted`. +## `--remap-path-scope` + +Defines which scopes of paths should be remapped by `--remap-path-prefix`. + +This flag accepts a comma-separated list of values and may be specified multiple times, in which case the scopes are aggregated together. + +The valid scopes are: + +- `macro` - apply remappings to the expansion of `std::file!()` macro. This is where paths in embedded panic messages come from +- `diagnostics` - apply remappings to printed compiler diagnostics +- `debuginfo` - apply remappings to debug information +- `coverage` - apply remappings to coverage information +- `object` - apply remappings to all paths in compiled executables or libraries, but not elsewhere. Currently an alias for `macro,coverage,debuginfo`. +- `all` (default) - an alias for all of the above, also equivalent to supplying only `--remap-path-prefix` without `--remap-path-scope`. + +The scopes accepted by `--remap-path-scope` are not exhaustive - new scopes may be added in future releases for eventual stabilisation. +This implies that the `all` scope can correspond to different scopes between releases. + +### Example + +```sh +# With `object` scope only the build outputs will be remapped, the diagnostics won't be remapped. +rustc --remap-path-prefix=$(PWD)=/remapped --remap-path-scope=object main.rs +``` + ## Caveats and Limitations ### Linkers generated paths diff --git a/src/doc/unstable-book/src/compiler-flags/remap-path-scope.md b/src/doc/unstable-book/src/compiler-flags/remap-path-scope.md deleted file mode 100644 index fb1c7d7a6878..000000000000 --- a/src/doc/unstable-book/src/compiler-flags/remap-path-scope.md +++ /dev/null @@ -1,23 +0,0 @@ -# `remap-path-scope` - -The tracking issue for this feature is: [#111540](https://github.com/rust-lang/rust/issues/111540). - ------------------------- - -When the `--remap-path-prefix` option is passed to rustc, source path prefixes in all output will be affected by default. -The `--remap-path-scope` argument can be used in conjunction with `--remap-path-prefix` to determine paths in which output context should be affected. -This flag accepts a comma-separated list of values and may be specified multiple times, in which case the scopes are aggregated together. The valid scopes are: - -- `macro` - apply remappings to the expansion of `std::file!()` macro. This is where paths in embedded panic messages come from -- `diagnostics` - apply remappings to printed compiler diagnostics -- `debuginfo` - apply remappings to debug information -- `coverage` - apply remappings to coverage information -- `object` - apply remappings to all paths in compiled executables or libraries, but not elsewhere. Currently an alias for `macro,debuginfo`. -- `all` - an alias for all of the above, also equivalent to supplying only `--remap-path-prefix` without `--remap-path-scope`. - -## Example -```sh -# This would produce an absolute path to main.rs in build outputs of -# "./main.rs". -rustc --remap-path-prefix=$(PWD)=/remapped -Zremap-path-scope=object main.rs -``` diff --git a/tests/coverage/remap-path-prefix.rs b/tests/coverage/remap-path-prefix.rs index 29c5826989c4..031b87b8f771 100644 --- a/tests/coverage/remap-path-prefix.rs +++ b/tests/coverage/remap-path-prefix.rs @@ -10,8 +10,8 @@ //@ revisions: with_remap with_coverage_scope with_object_scope with_macro_scope //@ compile-flags: --remap-path-prefix={{src-base}}=remapped // -//@[with_coverage_scope] compile-flags: -Zremap-path-scope=coverage -//@[with_object_scope] compile-flags: -Zremap-path-scope=object -//@[with_macro_scope] compile-flags: -Zremap-path-scope=macro +//@[with_coverage_scope] compile-flags: --remap-path-scope=coverage +//@[with_object_scope] compile-flags: --remap-path-scope=object +//@[with_macro_scope] compile-flags: --remap-path-scope=macro fn main() {} diff --git a/tests/coverage/remap-path-prefix.with_macro_scope.coverage b/tests/coverage/remap-path-prefix.with_macro_scope.coverage index 63979d8fe15a..9e8317672f90 100644 --- a/tests/coverage/remap-path-prefix.with_macro_scope.coverage +++ b/tests/coverage/remap-path-prefix.with_macro_scope.coverage @@ -10,9 +10,9 @@ LL| |//@ revisions: with_remap with_coverage_scope with_object_scope with_macro_scope LL| |//@ compile-flags: --remap-path-prefix={{src-base}}=remapped LL| |// - LL| |//@[with_coverage_scope] compile-flags: -Zremap-path-scope=coverage - LL| |//@[with_object_scope] compile-flags: -Zremap-path-scope=object - LL| |//@[with_macro_scope] compile-flags: -Zremap-path-scope=macro + LL| |//@[with_coverage_scope] compile-flags: --remap-path-scope=coverage + LL| |//@[with_object_scope] compile-flags: --remap-path-scope=object + LL| |//@[with_macro_scope] compile-flags: --remap-path-scope=macro LL| | LL| 1|fn main() {} diff --git a/tests/run-make/remap-path-prefix-consts/rmake.rs b/tests/run-make/remap-path-prefix-consts/rmake.rs index d07a5e00768a..07b5e2f97414 100644 --- a/tests/run-make/remap-path-prefix-consts/rmake.rs +++ b/tests/run-make/remap-path-prefix-consts/rmake.rs @@ -97,7 +97,7 @@ fn main() { location_caller .crate_type("lib") .remap_path_prefix(cwd(), "/remapped") - .arg("-Zremap-path-scope=object") + .arg("--remap-path-scope=object") .input(cwd().join("location-caller.rs")); location_caller.run(); @@ -105,7 +105,7 @@ fn main() { runner .crate_type("bin") .remap_path_prefix(cwd(), "/remapped") - .arg("-Zremap-path-scope=diagnostics") + .arg("--remap-path-scope=diagnostics") .input(cwd().join("runner.rs")) .output(&runner_bin); runner.run(); diff --git a/tests/run-make/remap-path-prefix-dwarf/rmake.rs b/tests/run-make/remap-path-prefix-dwarf/rmake.rs index 3b88fca0bb7f..ab6c1fb70d68 100644 --- a/tests/run-make/remap-path-prefix-dwarf/rmake.rs +++ b/tests/run-make/remap-path-prefix-dwarf/rmake.rs @@ -105,7 +105,7 @@ fn check_dwarf_deps(scope: &str, dwarf_test: DwarfDump) { let mut rustc_sm = rustc(); rustc_sm.input(cwd().join("src/some_value.rs")); rustc_sm.arg("-Cdebuginfo=2"); - rustc_sm.arg(format!("-Zremap-path-scope={}", scope)); + rustc_sm.arg(format!("--remap-path-scope={}", scope)); rustc_sm.arg("--remap-path-prefix"); rustc_sm.arg(format!("{}=/REMAPPED", cwd().display())); rustc_sm.arg("-Csplit-debuginfo=off"); @@ -117,7 +117,7 @@ fn check_dwarf_deps(scope: &str, dwarf_test: DwarfDump) { rustc_pv.input(cwd().join("src/print_value.rs")); rustc_pv.output(&print_value_rlib); rustc_pv.arg("-Cdebuginfo=2"); - rustc_pv.arg(format!("-Zremap-path-scope={}", scope)); + rustc_pv.arg(format!("--remap-path-scope={}", scope)); rustc_pv.arg("--remap-path-prefix"); rustc_pv.arg(format!("{}=/REMAPPED", cwd().display())); rustc_pv.arg("-Csplit-debuginfo=off"); @@ -158,8 +158,8 @@ fn check_dwarf(test: DwarfTest) { rustc.arg("-Cdebuginfo=2"); if let Some(scope) = test.scope { match scope { - ScopeType::Object => rustc.arg("-Zremap-path-scope=object"), - ScopeType::Diagnostics => rustc.arg("-Zremap-path-scope=diagnostics"), + ScopeType::Object => rustc.arg("--remap-path-scope=object"), + ScopeType::Diagnostics => rustc.arg("--remap-path-scope=diagnostics"), }; if is_darwin() { rustc.arg("-Csplit-debuginfo=off"); diff --git a/tests/run-make/remap-path-prefix/rmake.rs b/tests/run-make/remap-path-prefix/rmake.rs index b75ca9e796ac..22ffd4f1f0d1 100644 --- a/tests/run-make/remap-path-prefix/rmake.rs +++ b/tests/run-make/remap-path-prefix/rmake.rs @@ -38,9 +38,9 @@ fn main() { rmeta_contains("/the/aux/lib.rs"); rmeta_not_contains("auxiliary"); - out_object.arg("-Zremap-path-scope=object"); - out_macro.arg("-Zremap-path-scope=macro"); - out_diagobj.arg("-Zremap-path-scope=diagnostics,object"); + out_object.arg("--remap-path-scope=object"); + out_macro.arg("--remap-path-scope=macro"); + out_diagobj.arg("--remap-path-scope=diagnostics,object"); if is_darwin() { out_object.arg("-Csplit-debuginfo=off"); out_macro.arg("-Csplit-debuginfo=off"); diff --git a/tests/run-make/rustc-help/help-v.diff b/tests/run-make/rustc-help/help-v.diff index 60a9dfbe201d..94ed6a0ed027 100644 --- a/tests/run-make/rustc-help/help-v.diff +++ b/tests/run-make/rustc-help/help-v.diff @@ -1,4 +1,4 @@ -@@ -65,10 +65,28 @@ +@@ -65,10 +65,31 @@ Set a codegen option -V, --version Print version info and exit -v, --verbose Use verbose output @@ -20,6 +20,9 @@ + --remap-path-prefix = + Remap source names in all output (compiler messages + and output files) ++ --remap-path-scope ++ Defines which scopes of paths should be remapped by ++ `--remap-path-prefix` + @path Read newline separated options from `path` Additional help: diff --git a/tests/run-make/rustc-help/help-v.stdout b/tests/run-make/rustc-help/help-v.stdout index c41cb5e3bde8..fb08d114ad1a 100644 --- a/tests/run-make/rustc-help/help-v.stdout +++ b/tests/run-make/rustc-help/help-v.stdout @@ -83,6 +83,9 @@ Options: --remap-path-prefix = Remap source names in all output (compiler messages and output files) + --remap-path-scope + Defines which scopes of paths should be remapped by + `--remap-path-prefix` @path Read newline separated options from `path` Additional help: diff --git a/tests/run-make/split-debuginfo/rmake.rs b/tests/run-make/split-debuginfo/rmake.rs index e53b71010781..0d311607a11a 100644 --- a/tests/run-make/split-debuginfo/rmake.rs +++ b/tests/run-make/split-debuginfo/rmake.rs @@ -171,8 +171,7 @@ enum RemapPathPrefix { Unspecified, } -/// `-Zremap-path-scope`. See -/// . +/// `--remap-path-scope` #[derive(Debug, Clone)] enum RemapPathScope { /// Comma-separated list of remap scopes: `macro`, `diagnostics`, `debuginfo`, `object`, `all`. @@ -921,7 +920,7 @@ mod shared_linux_other_tests { .debuginfo(level.cli_value()) .arg(format!("-Zsplit-dwarf-kind={}", split_dwarf_kind.cli_value())) .remap_path_prefix(cwd(), remapped_prefix) - .arg(format!("-Zremap-path-scope={scope}")) + .arg(format!("--remap-path-scope={scope}")) .run(); let found_files = cwd_filenames(); FileAssertions { expected_files: BTreeSet::from(["foo", "foo.dwp"]) } @@ -950,7 +949,7 @@ mod shared_linux_other_tests { .debuginfo(level.cli_value()) .arg(format!("-Zsplit-dwarf-kind={}", split_dwarf_kind.cli_value())) .remap_path_prefix(cwd(), remapped_prefix) - .arg(format!("-Zremap-path-scope={scope}")) + .arg(format!("--remap-path-scope={scope}")) .run(); let found_files = cwd_filenames(); FileAssertions { expected_files: BTreeSet::from(["foo", "foo.dwp"]) } @@ -1202,7 +1201,7 @@ mod shared_linux_other_tests { .debuginfo(level.cli_value()) .arg(format!("-Zsplit-dwarf-kind={}", split_dwarf_kind.cli_value())) .remap_path_prefix(cwd(), remapped_prefix) - .arg(format!("-Zremap-path-scope={scope}")) + .arg(format!("--remap-path-scope={scope}")) .run(); let found_files = cwd_filenames(); @@ -1242,7 +1241,7 @@ mod shared_linux_other_tests { .debuginfo(level.cli_value()) .arg(format!("-Zsplit-dwarf-kind={}", split_dwarf_kind.cli_value())) .remap_path_prefix(cwd(), remapped_prefix) - .arg(format!("-Zremap-path-scope={scope}")) + .arg(format!("--remap-path-scope={scope}")) .run(); let found_files = cwd_filenames(); @@ -1356,7 +1355,7 @@ fn main() { // NOTE: these combinations are not exhaustive, because while porting to rmake.rs initially I // tried to preserve the existing test behavior closely. Notably, no attempt was made to // exhaustively cover all cases in the 6-fold Cartesian product of `{,-Csplit=debuginfo=...}` x - // `{,-Cdebuginfo=...}` x `{,--remap-path-prefix}` x `{,-Zremap-path-scope=...}` x + // `{,-Cdebuginfo=...}` x `{,--remap-path-prefix}` x `{,--remap-path-scope=...}` x // `{,-Zsplit-dwarf-kind=...}` x `{,-Clinker-plugin-lto}`. If you really want to, you can // identify which combination isn't exercised with a 6-layers nested for loop iterating through // each of the cli flag enum variants. diff --git a/tests/ui/errors/auxiliary/file-debuginfo.rs b/tests/ui/errors/auxiliary/file-debuginfo.rs index 08113ec26bfd..3c95512d8cc2 100644 --- a/tests/ui/errors/auxiliary/file-debuginfo.rs +++ b/tests/ui/errors/auxiliary/file-debuginfo.rs @@ -1,5 +1,5 @@ //@ compile-flags: --remap-path-prefix={{src-base}}=remapped -//@ compile-flags: -Zremap-path-scope=debuginfo +//@ compile-flags: --remap-path-scope=debuginfo #[macro_export] macro_rules! my_file { diff --git a/tests/ui/errors/auxiliary/file-diag.rs b/tests/ui/errors/auxiliary/file-diag.rs index f29c349f703b..61fc9d2b4829 100644 --- a/tests/ui/errors/auxiliary/file-diag.rs +++ b/tests/ui/errors/auxiliary/file-diag.rs @@ -1,5 +1,5 @@ //@ compile-flags: --remap-path-prefix={{src-base}}=remapped -//@ compile-flags: -Zremap-path-scope=diagnostics +//@ compile-flags: --remap-path-scope=diagnostics #[macro_export] macro_rules! my_file { diff --git a/tests/ui/errors/auxiliary/file-macro.rs b/tests/ui/errors/auxiliary/file-macro.rs index 11abc0549a7b..11e5de1e3274 100644 --- a/tests/ui/errors/auxiliary/file-macro.rs +++ b/tests/ui/errors/auxiliary/file-macro.rs @@ -1,5 +1,5 @@ //@ compile-flags: --remap-path-prefix={{src-base}}=remapped -//@ compile-flags: -Zremap-path-scope=macro +//@ compile-flags: --remap-path-scope=macro #[macro_export] macro_rules! my_file { diff --git a/tests/ui/errors/auxiliary/trait-debuginfo.rs b/tests/ui/errors/auxiliary/trait-debuginfo.rs index d5a0825fe6d1..dbe3d09d317d 100644 --- a/tests/ui/errors/auxiliary/trait-debuginfo.rs +++ b/tests/ui/errors/auxiliary/trait-debuginfo.rs @@ -1,4 +1,4 @@ //@ compile-flags: --remap-path-prefix={{src-base}}=remapped -//@ compile-flags: -Zremap-path-scope=debuginfo +//@ compile-flags: --remap-path-scope=debuginfo pub trait Trait: std::fmt::Display {} diff --git a/tests/ui/errors/auxiliary/trait-diag.rs b/tests/ui/errors/auxiliary/trait-diag.rs index e07961a276a9..3a30366683c4 100644 --- a/tests/ui/errors/auxiliary/trait-diag.rs +++ b/tests/ui/errors/auxiliary/trait-diag.rs @@ -1,4 +1,4 @@ //@ compile-flags: --remap-path-prefix={{src-base}}=remapped -//@ compile-flags: -Zremap-path-scope=diagnostics +//@ compile-flags: --remap-path-scope=diagnostics pub trait Trait: std::fmt::Display {} diff --git a/tests/ui/errors/auxiliary/trait-macro.rs b/tests/ui/errors/auxiliary/trait-macro.rs index 48673d04ee16..334b1c9bba2f 100644 --- a/tests/ui/errors/auxiliary/trait-macro.rs +++ b/tests/ui/errors/auxiliary/trait-macro.rs @@ -1,4 +1,4 @@ //@ compile-flags: --remap-path-prefix={{src-base}}=remapped -//@ compile-flags: -Zremap-path-scope=macro +//@ compile-flags: --remap-path-scope=macro pub trait Trait: std::fmt::Display {} diff --git a/tests/ui/errors/remap-path-prefix-diagnostics.rs b/tests/ui/errors/remap-path-prefix-diagnostics.rs index fac7e937cb0b..54dbcfd64711 100644 --- a/tests/ui/errors/remap-path-prefix-diagnostics.rs +++ b/tests/ui/errors/remap-path-prefix-diagnostics.rs @@ -1,4 +1,4 @@ -// This test exercises `-Zremap-path-scope`, diagnostics printing paths and dependency. +// This test exercises `--remap-path-scope`, diagnostics printing paths and dependency. // // We test different combinations with/without remap in deps, with/without remap in this // crate but always in deps and always here but never in deps. @@ -12,10 +12,10 @@ //@[with-debuginfo-in-deps] compile-flags: --remap-path-prefix={{src-base}}=remapped //@[not-diag-in-deps] compile-flags: --remap-path-prefix={{src-base}}=remapped -//@[with-diag-in-deps] compile-flags: -Zremap-path-scope=diagnostics -//@[with-macro-in-deps] compile-flags: -Zremap-path-scope=macro -//@[with-debuginfo-in-deps] compile-flags: -Zremap-path-scope=debuginfo -//@[not-diag-in-deps] compile-flags: -Zremap-path-scope=diagnostics +//@[with-diag-in-deps] compile-flags: --remap-path-scope=diagnostics +//@[with-macro-in-deps] compile-flags: --remap-path-scope=macro +//@[with-debuginfo-in-deps] compile-flags: --remap-path-scope=debuginfo +//@[not-diag-in-deps] compile-flags: --remap-path-scope=diagnostics //@[with-diag-in-deps] aux-build:trait-diag.rs //@[with-macro-in-deps] aux-build:trait-macro.rs diff --git a/tests/ui/errors/remap-path-prefix-macro.rs b/tests/ui/errors/remap-path-prefix-macro.rs index 3e93843f9164..1f895aeeb6b4 100644 --- a/tests/ui/errors/remap-path-prefix-macro.rs +++ b/tests/ui/errors/remap-path-prefix-macro.rs @@ -1,4 +1,4 @@ -// This test exercises `-Zremap-path-scope`, macros (like file!()) and dependency. +// This test exercises `--remap-path-scope`, macros (like file!()) and dependency. // // We test different combinations with/without remap in deps, with/without remap in // this crate but always in deps and always here but never in deps. @@ -15,10 +15,10 @@ //@[with-debuginfo-in-deps] compile-flags: --remap-path-prefix={{src-base}}=remapped //@[not-macro-in-deps] compile-flags: --remap-path-prefix={{src-base}}=remapped -//@[with-diag-in-deps] compile-flags: -Zremap-path-scope=diagnostics -//@[with-macro-in-deps] compile-flags: -Zremap-path-scope=macro -//@[with-debuginfo-in-deps] compile-flags: -Zremap-path-scope=debuginfo -//@[not-macro-in-deps] compile-flags: -Zremap-path-scope=macro +//@[with-diag-in-deps] compile-flags: --remap-path-scope=diagnostics +//@[with-macro-in-deps] compile-flags: --remap-path-scope=macro +//@[with-debuginfo-in-deps] compile-flags: --remap-path-scope=debuginfo +//@[not-macro-in-deps] compile-flags: --remap-path-scope=macro //@[with-diag-in-deps] aux-build:file-diag.rs //@[with-macro-in-deps] aux-build:file-macro.rs diff --git a/tests/ui/errors/remap-path-prefix.rs b/tests/ui/errors/remap-path-prefix.rs index de18aa8cc204..b49514711355 100644 --- a/tests/ui/errors/remap-path-prefix.rs +++ b/tests/ui/errors/remap-path-prefix.rs @@ -1,7 +1,7 @@ //@ revisions: normal with-diagnostic-scope without-diagnostic-scope //@ compile-flags: --remap-path-prefix={{src-base}}=remapped -//@ [with-diagnostic-scope]compile-flags: -Zremap-path-scope=diagnostics -//@ [without-diagnostic-scope]compile-flags: -Zremap-path-scope=object +//@ [with-diagnostic-scope]compile-flags: --remap-path-scope=diagnostics +//@ [without-diagnostic-scope]compile-flags: --remap-path-scope=object // Manually remap, so the remapped path remains in .stderr file. // The remapped paths are not normalized by compiletest. From 624135bd79ccfc6602b013225de4a33d5701035f Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Sat, 13 Dec 2025 20:16:12 +0100 Subject: [PATCH 0019/1061] Promote powerpc64-unknown-linux-musl to tier 2 with host tools Signed-off-by: Jens Reidel --- .../targets/powerpc64_unknown_linux_musl.rs | 4 +- src/bootstrap/src/core/build_steps/llvm.rs | 1 + src/bootstrap/src/core/download.rs | 1 + .../Dockerfile | 2 +- .../powerpc64-linux-gnu.defconfig | 0 .../dist-powerpc64-linux-musl/Dockerfile | 39 +++++++++++++++++++ .../powerpc64-unknown-linux-musl.defconfig | 15 +++++++ src/ci/github-actions/jobs.yml | 5 ++- src/doc/rustc/src/platform-support.md | 2 +- .../powerpc64-unknown-linux-musl.md | 10 +++-- 10 files changed, 70 insertions(+), 9 deletions(-) rename src/ci/docker/host-x86_64/{dist-powerpc64-linux => dist-powerpc64-linux-gnu}/Dockerfile (89%) rename src/ci/docker/host-x86_64/{dist-powerpc64-linux => dist-powerpc64-linux-gnu}/powerpc64-linux-gnu.defconfig (100%) create mode 100644 src/ci/docker/host-x86_64/dist-powerpc64-linux-musl/Dockerfile create mode 100644 src/ci/docker/host-x86_64/dist-powerpc64-linux-musl/powerpc64-unknown-linux-musl.defconfig diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs index b663ddf962ea..130bcacfc8cc 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs @@ -17,8 +17,8 @@ pub(crate) fn target() -> Target { llvm_target: "powerpc64-unknown-linux-musl".into(), metadata: TargetMetadata { description: Some("64-bit PowerPC Linux with musl 1.2.5".into()), - tier: Some(3), - host_tools: Some(false), + tier: Some(2), + host_tools: Some(true), std: Some(true), }, pointer_width: 64, diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index db2a76c4a2df..8acc92451519 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -223,6 +223,7 @@ pub(crate) fn is_ci_llvm_available_for_target( ("loongarch64-unknown-linux-musl", false), ("powerpc-unknown-linux-gnu", false), ("powerpc64-unknown-linux-gnu", false), + ("powerpc64-unknown-linux-musl", false), ("powerpc64le-unknown-linux-gnu", false), ("powerpc64le-unknown-linux-musl", false), ("riscv64gc-unknown-linux-gnu", false), diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index d950dc1a1c58..274bd56aff7e 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -460,6 +460,7 @@ pub(crate) fn is_download_ci_available(target_triple: &str, llvm_assertions: boo "loongarch64-unknown-linux-gnu", "powerpc-unknown-linux-gnu", "powerpc64-unknown-linux-gnu", + "powerpc64-unknown-linux-musl", "powerpc64le-unknown-linux-gnu", "powerpc64le-unknown-linux-musl", "riscv64gc-unknown-linux-gnu", diff --git a/src/ci/docker/host-x86_64/dist-powerpc64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-powerpc64-linux-gnu/Dockerfile similarity index 89% rename from src/ci/docker/host-x86_64/dist-powerpc64-linux/Dockerfile rename to src/ci/docker/host-x86_64/dist-powerpc64-linux-gnu/Dockerfile index 298282a76463..046406224c34 100644 --- a/src/ci/docker/host-x86_64/dist-powerpc64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-powerpc64-linux-gnu/Dockerfile @@ -11,7 +11,7 @@ RUN sh /scripts/rustbuild-setup.sh WORKDIR /tmp COPY scripts/crosstool-ng-build.sh /scripts/ -COPY host-x86_64/dist-powerpc64-linux/powerpc64-linux-gnu.defconfig /tmp/crosstool.defconfig +COPY host-x86_64/dist-powerpc64-linux-gnu/powerpc64-linux-gnu.defconfig /tmp/crosstool.defconfig RUN /scripts/crosstool-ng-build.sh COPY scripts/sccache.sh /scripts/ diff --git a/src/ci/docker/host-x86_64/dist-powerpc64-linux/powerpc64-linux-gnu.defconfig b/src/ci/docker/host-x86_64/dist-powerpc64-linux-gnu/powerpc64-linux-gnu.defconfig similarity index 100% rename from src/ci/docker/host-x86_64/dist-powerpc64-linux/powerpc64-linux-gnu.defconfig rename to src/ci/docker/host-x86_64/dist-powerpc64-linux-gnu/powerpc64-linux-gnu.defconfig diff --git a/src/ci/docker/host-x86_64/dist-powerpc64-linux-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-powerpc64-linux-musl/Dockerfile new file mode 100644 index 000000000000..7c8a1e657ac2 --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-powerpc64-linux-musl/Dockerfile @@ -0,0 +1,39 @@ +FROM ubuntu:22.04 + +COPY scripts/cross-apt-packages.sh /scripts/ +RUN sh /scripts/cross-apt-packages.sh + +COPY scripts/crosstool-ng.sh /scripts/ +RUN sh /scripts/crosstool-ng.sh + +COPY scripts/rustbuild-setup.sh /scripts/ +RUN sh /scripts/rustbuild-setup.sh + +WORKDIR /tmp + +COPY scripts/crosstool-ng-build.sh /scripts/ +COPY host-x86_64/dist-powerpc64-linux-musl/powerpc64-unknown-linux-musl.defconfig /tmp/crosstool.defconfig +RUN /scripts/crosstool-ng-build.sh + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +ENV PATH=$PATH:/x-tools/powerpc64-unknown-linux-musl/bin + +ENV \ + AR_powerpc64_unknown_linux_musl=powerpc64-unknown-linux-musl-ar \ + CC_powerpc64_unknown_linux_musl=powerpc64-unknown-linux-musl-gcc \ + CXX_powerpc64_unknown_linux_musl=powerpc64-unknown-linux-musl-g++ + +ENV HOSTS=powerpc64-unknown-linux-musl + +ENV RUST_CONFIGURE_ARGS \ + --enable-extended \ + --enable-full-tools \ + --enable-profiler \ + --enable-sanitizers \ + --disable-docs \ + --set target.powerpc64-unknown-linux-musl.crt-static=false \ + --musl-root-powerpc64=/x-tools/powerpc64-unknown-linux-musl/powerpc64-unknown-linux-musl/sysroot/usr + +ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/host-x86_64/dist-powerpc64-linux-musl/powerpc64-unknown-linux-musl.defconfig b/src/ci/docker/host-x86_64/dist-powerpc64-linux-musl/powerpc64-unknown-linux-musl.defconfig new file mode 100644 index 000000000000..08132d3ab8ba --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-powerpc64-linux-musl/powerpc64-unknown-linux-musl.defconfig @@ -0,0 +1,15 @@ +CT_CONFIG_VERSION="4" +CT_EXPERIMENTAL=y +CT_PREFIX_DIR="/x-tools/${CT_TARGET}" +CT_USE_MIRROR=y +CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc" +CT_ARCH_POWERPC=y +CT_ARCH_64=y +CT_ARCH_ABI="elfv2" +# CT_DEMULTILIB is not set +CT_KERNEL_LINUX=y +CT_LINUX_V_4_19=y +CT_LIBC_MUSL=y +CT_MUSL_V_1_2_5=y +CT_CC_LANG_CXX=y +CT_GETTEXT_NEEDED=y diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 9acad5c06b21..38c30f8b8e29 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -232,7 +232,10 @@ auto: - name: dist-powerpc-linux <<: *job-linux-4c - - name: dist-powerpc64-linux + - name: dist-powerpc64-linux-gnu + <<: *job-linux-4c + + - name: dist-powerpc64-linux-musl <<: *job-linux-4c - name: dist-powerpc64le-linux-gnu diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index d772702df76e..c2b26e56ef49 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -100,6 +100,7 @@ target | notes [`i686-pc-windows-gnu`](platform-support/windows-gnu.md) | 32-bit MinGW (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment] `powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2+, glibc 2.17) `powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2+, glibc 2.17) +[`powerpc64-unknown-linux-musl`](platform-support/powerpc64-unknown-linux-musl.md) | PPC64 Linux (kernel 4.19+, musl 1.2.5) [`powerpc64le-unknown-linux-gnu`](platform-support/powerpc64le-unknown-linux-gnu.md) | PPC64LE Linux (kernel 3.10+, glibc 2.17) [`powerpc64le-unknown-linux-musl`](platform-support/powerpc64le-unknown-linux-musl.md) | PPC64LE Linux (kernel 4.19+, musl 1.2.5) [`riscv64gc-unknown-linux-gnu`](platform-support/riscv64gc-unknown-linux-gnu.md) | RISC-V Linux (kernel 4.20+, glibc 2.29) @@ -369,7 +370,6 @@ target | std | host | notes [`powerpc-wrs-vxworks-spe`](platform-support/vxworks.md) | ✓ | | [`powerpc64-ibm-aix`](platform-support/aix.md) | ? | | 64-bit AIX (7.2 and newer) [`powerpc64-unknown-freebsd`](platform-support/freebsd.md) | ✓ | ✓ | PPC64 FreeBSD (ELFv2) -[`powerpc64-unknown-linux-musl`](platform-support/powerpc64-unknown-linux-musl.md) | ✓ | ✓ | PPC64 Linux (kernel 4.19, musl 1.2.5) [`powerpc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/powerpc64 [`powerpc64-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | [`powerpc64le-unknown-freebsd`](platform-support/freebsd.md) | ✓ | ✓ | PPC64LE FreeBSD diff --git a/src/doc/rustc/src/platform-support/powerpc64-unknown-linux-musl.md b/src/doc/rustc/src/platform-support/powerpc64-unknown-linux-musl.md index 7213e54d5a1a..23cb31af6a26 100644 --- a/src/doc/rustc/src/platform-support/powerpc64-unknown-linux-musl.md +++ b/src/doc/rustc/src/platform-support/powerpc64-unknown-linux-musl.md @@ -1,10 +1,13 @@ # powerpc64-unknown-linux-musl -**Tier: 3** +**Tier: 2** Target for 64-bit big endian PowerPC Linux programs using musl libc. This target uses the ELF v2 ABI. +The baseline CPU required is a PowerPC 970, which means AltiVec is required and +the oldest IBM server CPU supported is therefore POWER6. + ## Target maintainers [@Gelbpunkt](https://github.com/Gelbpunkt) @@ -38,9 +41,8 @@ linker = "powerpc64-linux-musl-gcc" ## Building Rust programs -Rust does not yet ship pre-compiled artifacts for this target. To compile for -this target, you will first need to build Rust with the target enabled (see -"Building the target" above). +This target is distributed through `rustup`, and otherwise requires no +special configuration. ## Cross-compilation From 4081c149b890c7536d0fa03c4c379a7c58074c2a Mon Sep 17 00:00:00 2001 From: Mahdi Ali-Raihan Date: Sat, 13 Dec 2025 19:18:17 -0500 Subject: [PATCH 0020/1061] create_dir_all() operates iteratively instead of recursively --- library/std/src/fs.rs | 50 ++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index b548eb4939d4..90e619ffbc15 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -3333,26 +3333,42 @@ impl DirBuilder { return Ok(()); } - match self.inner.mkdir(path) { - Ok(()) => return Ok(()), - Err(ref e) if e.kind() == io::ErrorKind::NotFound => {} - Err(_) if path.is_dir() => return Ok(()), - Err(e) => return Err(e), - } - match path.parent() { - Some(p) => self.create_dir_all(p)?, - None => { - return Err(io::const_error!( - io::ErrorKind::Uncategorized, - "failed to create whole tree", - )); + let ancestors = path.ancestors(); + let mut uncreated_dirs = 0; + + for ancestor in ancestors { + // for relative paths like "foo/bar", the parent of + // "foo" will be "" which there's no need to invoke + // a mkdir syscall on + if ancestor == Path::new("") { + break; + } + + match self.inner.mkdir(ancestor) { + Ok(()) => break, + Err(e) if e.kind() == io::ErrorKind::NotFound => uncreated_dirs += 1, + // we check if the err is AlreadyExists for two reasons + // - in case the path exists as a *file* + // - and to avoid calls to .is_dir() in case of other errs + // (i.e. PermissionDenied) + Err(e) if e.kind() == io::ErrorKind::AlreadyExists && ancestor.is_dir() => break, + Err(e) => return Err(e), } } - match self.inner.mkdir(path) { - Ok(()) => Ok(()), - Err(_) if path.is_dir() => Ok(()), - Err(e) => Err(e), + + // collect only the uncreated directories w/o letting the vec resize + let mut uncreated_dirs_vec = Vec::with_capacity(uncreated_dirs); + uncreated_dirs_vec.extend(ancestors.take(uncreated_dirs)); + + for uncreated_dir in uncreated_dirs_vec.iter().rev() { + if let Err(e) = self.inner.mkdir(uncreated_dir) { + if e.kind() != io::ErrorKind::AlreadyExists || !uncreated_dir.is_dir() { + return Err(e); + } + } } + + Ok(()) } } From cd39f5a5fe0dededd4d53823fe395f98f0747cc2 Mon Sep 17 00:00:00 2001 From: tison Date: Sun, 14 Dec 2025 14:35:07 +0800 Subject: [PATCH 0021/1061] Add waker_fn and local_waker_fn to std::task Signed-off-by: tison --- library/alloc/src/task.rs | 76 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs index b4116f4988b6..73b732241974 100644 --- a/library/alloc/src/task.rs +++ b/library/alloc/src/task.rs @@ -127,6 +127,44 @@ impl From> for RawWaker { } } +/// Converts a closure into a [`Waker`]. +/// +/// The closure gets called every time the waker is woken. +/// +/// # Examples +/// +/// ``` +/// #![feature(waker_fn)] +/// use std::task::waker_fn; +/// +/// let waker = waker_fn(|| println!("woken")); +/// +/// waker.wake_by_ref(); // Prints "woken". +/// waker.wake(); // Prints "woken". +/// ``` +#[cfg(target_has_atomic = "ptr")] +#[unstable(feature = "waker_fn", issue = "149580")] +pub fn waker_fn(f: F) -> Waker { + struct WakeFn { + f: F, + } + + impl Wake for WakeFn + where + F: Fn(), + { + fn wake(self: Arc) { + (self.f)() + } + + fn wake_by_ref(self: &Arc) { + (self.f)() + } + } + + Waker::from(Arc::new(WakeFn { f })) +} + // NB: This private function for constructing a RawWaker is used, rather than // inlining this into the `From> for RawWaker` impl, to ensure that // the safety of `From> for Waker` does not depend on the correct @@ -306,6 +344,44 @@ impl From> for RawWaker { } } +/// Converts a closure into a [`LocalWaker`]. +/// +/// The closure gets called every time the local waker is woken. +/// +/// # Examples +/// +/// ``` +/// #![feature(local_waker)] +/// #![feature(waker_fn)] +/// use std::task::local_waker_fn; +/// +/// let waker = local_waker_fn(|| println!("woken")); +/// +/// waker.wake_by_ref(); // Prints "woken". +/// waker.wake(); // Prints "woken". +/// ``` +#[unstable(feature = "waker_fn", issue = "149580")] +pub fn local_waker_fn(f: F) -> LocalWaker { + struct LocalWakeFn { + f: F, + } + + impl LocalWake for LocalWakeFn + where + F: Fn(), + { + fn wake(self: Rc) { + (self.f)() + } + + fn wake_by_ref(self: &Rc) { + (self.f)() + } + } + + LocalWaker::from(Rc::new(LocalWakeFn { f })) +} + // NB: This private function for constructing a RawWaker is used, rather than // inlining this into the `From> for RawWaker` impl, to ensure that // the safety of `From> for Waker` does not depend on the correct From 167ad11c229a5804b8373b500d5a8cc5f67731f4 Mon Sep 17 00:00:00 2001 From: Mahdi Ali-Raihan Date: Sun, 14 Dec 2025 15:57:23 -0500 Subject: [PATCH 0022/1061] check if current path is root through seeing if its parent is None --- library/std/src/fs.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 90e619ffbc15..feb17877d96f 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -3329,7 +3329,9 @@ impl DirBuilder { } fn create_dir_all(&self, path: &Path) -> io::Result<()> { - if path == Path::new("") { + // if path's parent is None, it is "/" path, which should + // return Ok immediately + if path == Path::new("") || path.parent() == None { return Ok(()); } @@ -3340,7 +3342,7 @@ impl DirBuilder { // for relative paths like "foo/bar", the parent of // "foo" will be "" which there's no need to invoke // a mkdir syscall on - if ancestor == Path::new("") { + if ancestor == Path::new("") || ancestor.parent() == None { break; } From 96c165b1110db7519e60f076a111b8a796180305 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Tue, 16 Dec 2025 22:38:34 +0100 Subject: [PATCH 0023/1061] Make `asm_experimental_arch` work in `allow_internal_unstable` macros --- compiler/rustc_ast_lowering/src/asm.rs | 10 +++++++++- .../ui/internal/auxiliary/internal_unstable.rs | 7 +++++++ .../internal-unstable-asm-experimental-arch.rs | 18 ++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 tests/ui/internal/internal-unstable-asm-experimental-arch.rs diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index d44faad017ee..04e5f0523101 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -52,7 +52,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { | asm::InlineAsmArch::LoongArch64 | asm::InlineAsmArch::S390x ); - if !is_stable && !self.tcx.features().asm_experimental_arch() { + if !is_stable + && !self.tcx.features().asm_experimental_arch() + && sp + .ctxt() + .outer_expn_data() + .allow_internal_unstable + .filter(|features| features.contains(&sym::asm_experimental_arch)) + .is_none() + { feature_err( &self.tcx.sess, sym::asm_experimental_arch, diff --git a/tests/ui/internal/auxiliary/internal_unstable.rs b/tests/ui/internal/auxiliary/internal_unstable.rs index eb4d6cb380ef..bea153227a77 100644 --- a/tests/ui/internal/auxiliary/internal_unstable.rs +++ b/tests/ui/internal/auxiliary/internal_unstable.rs @@ -99,3 +99,10 @@ macro_rules! access_field_noallow { macro_rules! pass_through_noallow { ($e: expr) => { $e } } + +#[stable(feature = "stable", since = "1.0.0")] +#[allow_internal_unstable(asm_experimental_arch)] +#[macro_export] +macro_rules! asm_redirect { + ($($t:tt)*) => { core::arch::global_asm!($($t)*); } +} diff --git a/tests/ui/internal/internal-unstable-asm-experimental-arch.rs b/tests/ui/internal/internal-unstable-asm-experimental-arch.rs new file mode 100644 index 000000000000..6d97779ff911 --- /dev/null +++ b/tests/ui/internal/internal-unstable-asm-experimental-arch.rs @@ -0,0 +1,18 @@ +//@ only-wasm32-wasip1 +//@ compile-flags: --crate-type=lib +//@ build-pass +//@ aux-build:internal_unstable.rs + +#[macro_use] +extern crate internal_unstable; + +asm_redirect!( + "test:", + ".globl test", + ".functype test (i32) -> (i32)", + "local.get 0", + "i32.const 1", + "i32.add", + "end_function", + ".export_name test, test", +); From dc3786eb3c0b373665939763ddeac1d630f07ac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 14 Nov 2025 10:10:06 +0100 Subject: [PATCH 0024/1061] stabilize map_next_if --- library/core/src/iter/adapters/peekable.rs | 7 ++----- library/coretests/tests/lib.rs | 1 - 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/library/core/src/iter/adapters/peekable.rs b/library/core/src/iter/adapters/peekable.rs index ee40d2b74c64..b9bdb827209b 100644 --- a/library/core/src/iter/adapters/peekable.rs +++ b/library/core/src/iter/adapters/peekable.rs @@ -337,7 +337,6 @@ impl Peekable { /// /// Parse the leading decimal number from an iterator of characters. /// ``` - /// #![feature(peekable_next_if_map)] /// let mut iter = "125 GOTO 10".chars().peekable(); /// let mut line_num = 0_u32; /// while let Some(digit) = iter.next_if_map(|c| c.to_digit(10).ok_or(c)) { @@ -349,7 +348,6 @@ impl Peekable { /// /// Matching custom types. /// ``` - /// #![feature(peekable_next_if_map)] /// /// #[derive(Debug, PartialEq, Eq)] /// enum Node { @@ -408,7 +406,7 @@ impl Peekable { ///# ], ///# ) /// ``` - #[unstable(feature = "peekable_next_if_map", issue = "143702")] + #[stable(feature = "peekable_next_if_map", since = "CURRENT_RUSTC_VERSION")] pub fn next_if_map(&mut self, f: impl FnOnce(I::Item) -> Result) -> Option { let unpeek = if let Some(item) = self.next() { match f(item) { @@ -437,7 +435,6 @@ impl Peekable { /// /// Parse the leading decimal number from an iterator of characters. /// ``` - /// #![feature(peekable_next_if_map)] /// let mut iter = "125 GOTO 10".chars().peekable(); /// let mut line_num = 0_u32; /// while let Some(digit) = iter.next_if_map_mut(|c| c.to_digit(10)) { @@ -446,7 +443,7 @@ impl Peekable { /// assert_eq!(line_num, 125); /// assert_eq!(iter.collect::(), " GOTO 10"); /// ``` - #[unstable(feature = "peekable_next_if_map", issue = "143702")] + #[stable(feature = "peekable_next_if_map", since = "CURRENT_RUSTC_VERSION")] pub fn next_if_map_mut(&mut self, f: impl FnOnce(&mut I::Item) -> Option) -> Option { let unpeek = if let Some(mut item) = self.next() { match f(&mut item) { diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 0387b442562d..222e5dd32c86 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -91,7 +91,6 @@ #![feature(one_sided_range)] #![feature(option_reduce)] #![feature(pattern)] -#![feature(peekable_next_if_map)] #![feature(pointer_is_aligned_to)] #![feature(portable_simd)] #![feature(ptr_metadata)] From d5061a86172e73a33b43f50edc5b144ffa7cc556 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 17 Dec 2025 21:03:53 +0200 Subject: [PATCH 0025/1061] make date-check entries clickable --- src/doc/rustc-dev-guide/ci/date-check/src/main.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/ci/date-check/src/main.rs b/src/doc/rustc-dev-guide/ci/date-check/src/main.rs index 0a32f4e9b7b6..bdf727b09ebe 100644 --- a/src/doc/rustc-dev-guide/ci/date-check/src/main.rs +++ b/src/doc/rustc-dev-guide/ci/date-check/src/main.rs @@ -153,9 +153,13 @@ fn main() { println!(); for (path, dates) in dates_by_file { - println!("- {}", path.strip_prefix(&root_dir_path).unwrap_or(&path).display(),); + let path = path.strip_prefix(&root_dir_path).unwrap_or(&path).display(); + println!("- {path}"); for (line, date) in dates { - println!(" - [ ] line {}: {}", line, date); + let url = format!( + "https://github.com/rust-lang/rustc-dev-guide/blob/main/{path}?plain=1#L{line}" + ); + println!(" - [ ] [{date}]({url})"); } } println!(); From fd1a753d2b555ff91cbd7a0f552466a9137745b6 Mon Sep 17 00:00:00 2001 From: hulxv Date: Wed, 17 Dec 2025 22:54:51 +0200 Subject: [PATCH 0026/1061] Refactor CPU affinity tests to use errno_check for error handling --- .../miri/tests/pass-dep/libc/libc-affinity.rs | 54 ++++++++----------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs b/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs index 400e3ca3d7db..87ef0510af4f 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs @@ -7,6 +7,10 @@ use std::mem::{size_of, size_of_val}; use libc::{cpu_set_t, sched_getaffinity, sched_setaffinity}; +#[path = "../../utils/libc.rs"] +mod libc_utils; +use libc_utils::errno_check; + // If pid is zero, then the calling thread is used. const PID: i32 = 0; @@ -41,8 +45,7 @@ fn configure_unavailable_cpu() { // Safety: valid value for this type let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; - let err = unsafe { sched_getaffinity(PID, size_of::(), &mut cpuset) }; - assert_eq!(err, 0); + errno_check(unsafe { sched_getaffinity(PID, size_of::(), &mut cpuset) }); // by default, only available CPUs are configured for i in 0..cpu_count { @@ -53,11 +56,9 @@ fn configure_unavailable_cpu() { // configure CPU that we don't have unsafe { libc::CPU_SET(cpu_count, &mut cpuset) }; - let err = unsafe { sched_setaffinity(PID, size_of::(), &cpuset) }; - assert_eq!(err, 0); + errno_check(unsafe { sched_setaffinity(PID, size_of::(), &cpuset) }); - let err = unsafe { sched_getaffinity(PID, size_of::(), &mut cpuset) }; - assert_eq!(err, 0); + errno_check(unsafe { sched_getaffinity(PID, size_of::(), &mut cpuset) }); // the CPU is not set because it is not available assert!(!unsafe { libc::CPU_ISSET(cpu_count, &cpuset) }); @@ -70,11 +71,11 @@ fn large_set() { // i.e. this has 2048 bits, twice the standard number let mut cpuset = [u64::MAX; 32]; - let err = unsafe { sched_setaffinity(PID, size_of_val(&cpuset), cpuset.as_ptr().cast()) }; - assert_eq!(err, 0); + errno_check(unsafe { sched_setaffinity(PID, size_of_val(&cpuset), cpuset.as_ptr().cast()) }); - let err = unsafe { sched_getaffinity(PID, size_of_val(&cpuset), cpuset.as_mut_ptr().cast()) }; - assert_eq!(err, 0); + errno_check(unsafe { + sched_getaffinity(PID, size_of_val(&cpuset), cpuset.as_mut_ptr().cast()) + }); } fn get_small_cpu_mask() { @@ -91,8 +92,7 @@ fn get_small_cpu_mask() { assert_eq!(std::io::Error::last_os_error().kind(), std::io::ErrorKind::InvalidInput); } else { // other whole multiples of the size of c_ulong works - let err = unsafe { sched_getaffinity(PID, i, &mut cpuset) }; - assert_eq!(err, 0, "fail for {i}"); + errno_check(unsafe { sched_getaffinity(PID, i, &mut cpuset) }); } // anything else returns an error @@ -107,8 +107,7 @@ fn get_small_cpu_mask() { fn set_small_cpu_mask() { let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; - let err = unsafe { sched_getaffinity(PID, size_of::(), &mut cpuset) }; - assert_eq!(err, 0); + errno_check(unsafe { sched_getaffinity(PID, size_of::(), &mut cpuset) }); // setting a mask of size 0 is invalid let err = unsafe { sched_setaffinity(PID, 0, &cpuset) }; @@ -122,8 +121,7 @@ fn set_small_cpu_mask() { if cfg!(target_endian = "little") { 1 } else { core::mem::size_of::() }; for i in cpu_zero_included_length..24 { - let err = unsafe { sched_setaffinity(PID, i, &cpuset) }; - assert_eq!(err, 0, "fail for {i}"); + errno_check(unsafe { sched_setaffinity(PID, i, &cpuset) }); } } @@ -135,8 +133,7 @@ fn set_custom_cpu_mask() { let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; // at the start, thread 1 should be set - let err = unsafe { sched_getaffinity(PID, size_of::(), &mut cpuset) }; - assert_eq!(err, 0); + errno_check(unsafe { sched_getaffinity(PID, size_of::(), &mut cpuset) }); assert!(unsafe { libc::CPU_ISSET(1, &cpuset) }); // make a valid mask @@ -144,12 +141,10 @@ fn set_custom_cpu_mask() { unsafe { libc::CPU_SET(0, &mut cpuset) }; // giving a smaller mask is fine - let err = unsafe { sched_setaffinity(PID, 8, &cpuset) }; - assert_eq!(err, 0); + errno_check(unsafe { sched_setaffinity(PID, 8, &cpuset) }); // and actually disables other threads - let err = unsafe { sched_getaffinity(PID, size_of::(), &mut cpuset) }; - assert_eq!(err, 0); + errno_check(unsafe { sched_getaffinity(PID, size_of::(), &mut cpuset) }); assert!(unsafe { !libc::CPU_ISSET(1, &cpuset) }); // it is important that we reset the cpu mask now for future tests @@ -157,8 +152,7 @@ fn set_custom_cpu_mask() { unsafe { libc::CPU_SET(i, &mut cpuset) }; } - let err = unsafe { sched_setaffinity(PID, size_of::(), &cpuset) }; - assert_eq!(err, 0); + errno_check(unsafe { sched_setaffinity(PID, size_of::(), &cpuset) }); } fn parent_child() { @@ -170,15 +164,13 @@ fn parent_child() { let mut parent_cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; unsafe { libc::CPU_SET(0, &mut parent_cpuset) }; - let err = unsafe { sched_setaffinity(PID, size_of::(), &parent_cpuset) }; - assert_eq!(err, 0); + errno_check(unsafe { sched_setaffinity(PID, size_of::(), &parent_cpuset) }); std::thread::scope(|spawner| { spawner.spawn(|| { let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; - let err = unsafe { sched_getaffinity(PID, size_of::(), &mut cpuset) }; - assert_eq!(err, 0); + errno_check(unsafe { sched_getaffinity(PID, size_of::(), &mut cpuset) }); // the child inherits its parent's set assert!(unsafe { libc::CPU_ISSET(0, &cpuset) }); @@ -189,8 +181,7 @@ fn parent_child() { }); }); - let err = unsafe { sched_getaffinity(PID, size_of::(), &mut parent_cpuset) }; - assert_eq!(err, 0); + errno_check(unsafe { sched_getaffinity(PID, size_of::(), &mut parent_cpuset) }); // the parent's set should be unaffected assert!(unsafe { !libc::CPU_ISSET(1, &parent_cpuset) }); @@ -201,8 +192,7 @@ fn parent_child() { unsafe { libc::CPU_SET(i, &mut cpuset) }; } - let err = unsafe { sched_setaffinity(PID, size_of::(), &cpuset) }; - assert_eq!(err, 0); + errno_check(unsafe { sched_setaffinity(PID, size_of::(), &cpuset) }); } fn main() { From d5d605acd46dd767c2aef0ff80c00328daf35b9f Mon Sep 17 00:00:00 2001 From: hulxv Date: Wed, 17 Dec 2025 23:05:04 +0200 Subject: [PATCH 0027/1061] Refactor libc time tests to use errno_check for error handling --- .../miri/tests/pass-dep/libc/libc-time.rs | 53 ++++++++----------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/src/tools/miri/tests/pass-dep/libc/libc-time.rs b/src/tools/miri/tests/pass-dep/libc/libc-time.rs index 9e9fadfca9e7..b80fb0025530 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-time.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-time.rs @@ -1,8 +1,13 @@ //@ignore-target: windows # no libc time APIs on Windows //@compile-flags: -Zmiri-disable-isolation + +#[path = "../../utils/libc.rs"] +mod libc_utils; use std::time::{Duration, Instant}; use std::{env, mem, ptr}; +use libc_utils::errno_check; + fn main() { test_clocks(); test_posix_gettimeofday(); @@ -39,30 +44,23 @@ fn main() { /// Tests whether clock support exists at all fn test_clocks() { let mut tp = mem::MaybeUninit::::uninit(); - let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, tp.as_mut_ptr()) }; - assert_eq!(is_error, 0); - let is_error = unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC, tp.as_mut_ptr()) }; - assert_eq!(is_error, 0); + errno_check(unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, tp.as_mut_ptr()) }); + errno_check(unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC, tp.as_mut_ptr()) }); #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "android"))] { - let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME_COARSE, tp.as_mut_ptr()) }; - assert_eq!(is_error, 0); - let is_error = - unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC_COARSE, tp.as_mut_ptr()) }; - assert_eq!(is_error, 0); + errno_check(unsafe { libc::clock_gettime(libc::CLOCK_REALTIME_COARSE, tp.as_mut_ptr()) }); + errno_check(unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC_COARSE, tp.as_mut_ptr()) }); } #[cfg(target_os = "macos")] { - let is_error = unsafe { libc::clock_gettime(libc::CLOCK_UPTIME_RAW, tp.as_mut_ptr()) }; - assert_eq!(is_error, 0); + errno_check(unsafe { libc::clock_gettime(libc::CLOCK_UPTIME_RAW, tp.as_mut_ptr()) }); } } fn test_posix_gettimeofday() { let mut tp = mem::MaybeUninit::::uninit(); let tz = ptr::null_mut::(); - let is_error = unsafe { libc::gettimeofday(tp.as_mut_ptr(), tz.cast()) }; - assert_eq!(is_error, 0); + errno_check(unsafe { libc::gettimeofday(tp.as_mut_ptr(), tz.cast()) }); let tv = unsafe { tp.assume_init() }; assert!(tv.tv_sec > 0); assert!(tv.tv_usec >= 0); // Theoretically this could be 0. @@ -334,15 +332,13 @@ fn test_nanosleep() { let start_test_sleep = Instant::now(); let duration_zero = libc::timespec { tv_sec: 0, tv_nsec: 0 }; let remainder = ptr::null_mut::(); - let is_error = unsafe { libc::nanosleep(&duration_zero, remainder) }; - assert_eq!(is_error, 0); + errno_check(unsafe { libc::nanosleep(&duration_zero, remainder) }); assert!(start_test_sleep.elapsed() < Duration::from_millis(100)); let start_test_sleep = Instant::now(); let duration_100_millis = libc::timespec { tv_sec: 0, tv_nsec: 1_000_000_000 / 10 }; let remainder = ptr::null_mut::(); - let is_error = unsafe { libc::nanosleep(&duration_100_millis, remainder) }; - assert_eq!(is_error, 0); + errno_check(unsafe { libc::nanosleep(&duration_100_millis, remainder) }); assert!(start_test_sleep.elapsed() > Duration::from_millis(100)); } @@ -371,8 +367,7 @@ mod test_clock_nanosleep { /// Helper function to get the current time for testing relative sleeps fn timespec_now(clock: libc::clockid_t) -> libc::timespec { let mut timespec = mem::MaybeUninit::::uninit(); - let is_error = unsafe { libc::clock_gettime(clock, timespec.as_mut_ptr()) }; - assert_eq!(is_error, 0); + errno_check(unsafe { libc::clock_gettime(clock, timespec.as_mut_ptr()) }); unsafe { timespec.assume_init() } } @@ -380,7 +375,7 @@ mod test_clock_nanosleep { let start_test_sleep = Instant::now(); let before_start = libc::timespec { tv_sec: 0, tv_nsec: 0 }; let remainder = ptr::null_mut::(); - let error = unsafe { + errno_check(unsafe { // this will not sleep since unix time zero is in the past libc::clock_nanosleep( libc::CLOCK_MONOTONIC, @@ -388,22 +383,20 @@ mod test_clock_nanosleep { &before_start, remainder, ) - }; - assert_eq!(error, 0); + }); assert!(start_test_sleep.elapsed() < Duration::from_millis(100)); let start_test_sleep = Instant::now(); let hunderd_millis_after_start = add_100_millis(timespec_now(libc::CLOCK_MONOTONIC)); let remainder = ptr::null_mut::(); - let error = unsafe { + errno_check(unsafe { libc::clock_nanosleep( libc::CLOCK_MONOTONIC, libc::TIMER_ABSTIME, &hunderd_millis_after_start, remainder, ) - }; - assert_eq!(error, 0); + }); assert!(start_test_sleep.elapsed() > Duration::from_millis(100)); } @@ -413,19 +406,17 @@ mod test_clock_nanosleep { let start_test_sleep = Instant::now(); let duration_zero = libc::timespec { tv_sec: 0, tv_nsec: 0 }; let remainder = ptr::null_mut::(); - let error = unsafe { + errno_check(unsafe { libc::clock_nanosleep(libc::CLOCK_MONOTONIC, NO_FLAGS, &duration_zero, remainder) - }; - assert_eq!(error, 0); + }); assert!(start_test_sleep.elapsed() < Duration::from_millis(100)); let start_test_sleep = Instant::now(); let duration_100_millis = libc::timespec { tv_sec: 0, tv_nsec: 1_000_000_000 / 10 }; let remainder = ptr::null_mut::(); - let error = unsafe { + errno_check(unsafe { libc::clock_nanosleep(libc::CLOCK_MONOTONIC, NO_FLAGS, &duration_100_millis, remainder) - }; - assert_eq!(error, 0); + }); assert!(start_test_sleep.elapsed() > Duration::from_millis(100)); } } From 3566b6775c45169ffc9c5ede434ad0500ba0476e Mon Sep 17 00:00:00 2001 From: delta17920 Date: Mon, 15 Dec 2025 15:28:57 +0000 Subject: [PATCH 0028/1061] Fix macro_metavar_expr_concat behavior with nested repetitions --- compiler/rustc_expand/src/mbe/transcribe.rs | 29 +++++++-------- tests/ui/macros/concat-nested-repetition.rs | 35 +++++++++++++++++++ .../in-repetition.rs | 2 +- .../in-repetition.stderr | 6 ++-- .../metavar-expressions/concat-repetitions.rs | 7 ++-- .../concat-repetitions.stderr | 18 +++++----- 6 files changed, 63 insertions(+), 34 deletions(-) create mode 100644 tests/ui/macros/concat-nested-repetition.rs diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index dddd62a4945a..d53d180a4ab9 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -558,25 +558,20 @@ fn metavar_expr_concat<'tx>( MetaVarExprConcatElem::Ident(elem) => elem.name, MetaVarExprConcatElem::Literal(elem) => *elem, MetaVarExprConcatElem::Var(ident) => { - match matched_from_ident(dcx, *ident, tscx.interp)? { - NamedMatch::MatchedSeq(named_matches) => { - let Some((curr_idx, _)) = tscx.repeats.last() else { - return Err(dcx.struct_span_err(dspan.entire(), "invalid syntax")); - }; - match &named_matches[*curr_idx] { - // FIXME(c410-f3r) Nested repetitions are unimplemented - MatchedSeq(_) => { - return Err(dcx.struct_span_err( - ident.span, - "nested repetitions with `${concat(...)}` metavariable expressions are not yet supported", - )); - } - MatchedSingle(pnr) => extract_symbol_from_pnr(dcx, pnr, ident.span)?, - } - } - NamedMatch::MatchedSingle(pnr) => { + let key = MacroRulesNormalizedIdent::new(*ident); + match lookup_cur_matched(key, tscx.interp, &tscx.repeats) { + Some(NamedMatch::MatchedSingle(pnr)) => { extract_symbol_from_pnr(dcx, pnr, ident.span)? } + Some(NamedMatch::MatchedSeq(..)) => { + return Err(dcx.struct_span_err( + ident.span, + "`${concat(...)}` variable is still repeating at this depth", + )); + } + None => { + return Err(dcx.create_err(MveUnrecognizedVar { span: ident.span, key })); + } } } }; diff --git a/tests/ui/macros/concat-nested-repetition.rs b/tests/ui/macros/concat-nested-repetition.rs new file mode 100644 index 000000000000..ac5394ef8dcc --- /dev/null +++ b/tests/ui/macros/concat-nested-repetition.rs @@ -0,0 +1,35 @@ +//@ check-pass +#![feature(macro_metavar_expr_concat)] + +struct A; +struct B; +const AA: A = A; +const BB: B = B; + +macro_rules! define_ioctl_data { + (struct $s:ident { + $($field:ident: $ty:ident $([$opt:ident])?,)* + }) => { + pub struct $s { + $($field: $ty,)* + } + + impl $s { + $($( + fn ${concat(get_, $field)}(&self) -> $ty { + let _ = $opt; + todo!() + } + )?)* + } + }; +} + +define_ioctl_data! { + struct Foo { + a: A [AA], + b: B [BB], + } +} + +fn main() {} diff --git a/tests/ui/macros/macro-metavar-expr-concat/in-repetition.rs b/tests/ui/macros/macro-metavar-expr-concat/in-repetition.rs index d2bd31b06d60..3ee11d373e05 100644 --- a/tests/ui/macros/macro-metavar-expr-concat/in-repetition.rs +++ b/tests/ui/macros/macro-metavar-expr-concat/in-repetition.rs @@ -11,7 +11,7 @@ macro_rules! InRepetition { ) => { $( $( - ${concat(_, $arg)} //~ ERROR nested repetitions with `${concat(...)}` metavariable expressions are not yet supported + ${concat(_, $arg)} //~ ERROR macro expansion ends with an incomplete expression: expected one of `!` or `::` )* )* }; diff --git a/tests/ui/macros/macro-metavar-expr-concat/in-repetition.stderr b/tests/ui/macros/macro-metavar-expr-concat/in-repetition.stderr index ec39ca799e19..b84d98874931 100644 --- a/tests/ui/macros/macro-metavar-expr-concat/in-repetition.stderr +++ b/tests/ui/macros/macro-metavar-expr-concat/in-repetition.stderr @@ -1,8 +1,8 @@ -error: nested repetitions with `${concat(...)}` metavariable expressions are not yet supported - --> $DIR/in-repetition.rs:14:30 +error: macro expansion ends with an incomplete expression: expected one of `!` or `::` + --> $DIR/in-repetition.rs:14:35 | LL | ${concat(_, $arg)} - | ^^^ + | ^ expected one of `!` or `::` error: aborting due to 1 previous error diff --git a/tests/ui/macros/metavar-expressions/concat-repetitions.rs b/tests/ui/macros/metavar-expressions/concat-repetitions.rs index 52a7d5cd8a7e..133a969b1248 100644 --- a/tests/ui/macros/metavar-expressions/concat-repetitions.rs +++ b/tests/ui/macros/metavar-expressions/concat-repetitions.rs @@ -11,8 +11,7 @@ macro_rules! one_rep { macro_rules! issue_128346 { ( $($a:ident)* ) => { A( - const ${concat($a, Z)}: i32 = 3; - //~^ ERROR invalid syntax + const ${concat($a, Z)}: i32 = 3; //~ ERROR `${concat(...)}` variable is still repeating at this depth )* }; } @@ -20,8 +19,8 @@ macro_rules! issue_128346 { macro_rules! issue_131393 { ($t:ident $($en:ident)?) => { read::<${concat($t, $en)}>() - //~^ ERROR invalid syntax - //~| ERROR invalid syntax + //~^ ERROR `${concat(...)}` variable is still repeating at this depth + //~| ERROR `${concat(...)}` variable is still repeating at this depth } } diff --git a/tests/ui/macros/metavar-expressions/concat-repetitions.stderr b/tests/ui/macros/metavar-expressions/concat-repetitions.stderr index 18b0a90c1c8a..0ef20c65a284 100644 --- a/tests/ui/macros/metavar-expressions/concat-repetitions.stderr +++ b/tests/ui/macros/metavar-expressions/concat-repetitions.stderr @@ -1,20 +1,20 @@ -error: invalid syntax - --> $DIR/concat-repetitions.rs:14:20 +error: `${concat(...)}` variable is still repeating at this depth + --> $DIR/concat-repetitions.rs:14:29 | LL | const ${concat($a, Z)}: i32 = 3; - | ^^^^^^^^^^^^^^^ + | ^ -error: invalid syntax - --> $DIR/concat-repetitions.rs:22:17 +error: `${concat(...)}` variable is still repeating at this depth + --> $DIR/concat-repetitions.rs:21:30 | LL | read::<${concat($t, $en)}>() - | ^^^^^^^^^^^^^^^^^ + | ^^ -error: invalid syntax - --> $DIR/concat-repetitions.rs:22:17 +error: `${concat(...)}` variable is still repeating at this depth + --> $DIR/concat-repetitions.rs:21:30 | LL | read::<${concat($t, $en)}>() - | ^^^^^^^^^^^^^^^^^ + | ^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` From 558ff51722a7944e37c60ea73525bb9090955f90 Mon Sep 17 00:00:00 2001 From: Coca Date: Thu, 18 Dec 2025 17:13:55 +0000 Subject: [PATCH 0029/1061] `transmuting_null`: Check single expression const blocks and blocks changelog: [`transmuting_null`]: now checks single expression const blocks and blocks --- .../src/transmute/transmuting_null.rs | 20 ++++++++++++++++++- tests/ui/transmuting_null.rs | 11 ++++++++++ tests/ui/transmuting_null.stderr | 14 ++++++++++++- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/transmute/transmuting_null.rs b/clippy_lints/src/transmute/transmuting_null.rs index 31e770f421e1..3f435f255d91 100644 --- a/clippy_lints/src/transmute/transmuting_null.rs +++ b/clippy_lints/src/transmute/transmuting_null.rs @@ -2,7 +2,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_integer_const; use clippy_utils::res::{MaybeDef, MaybeResPath}; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{ConstBlock, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::Ty; use rustc_span::symbol::sym; @@ -42,5 +42,23 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t return true; } + // Catching: + // `std::mem::transmute({ 0 as *const u64 })` and similar const blocks + if let ExprKind::Block(block, _) = arg.kind + && block.stmts.is_empty() + && let Some(inner) = block.expr + { + // Run again with the inner expression + return check(cx, expr, inner, to_ty); + } + + // Catching: + // `std::mem::transmute(const { u64::MIN as *const u64 });` + if let ExprKind::ConstBlock(ConstBlock { body, .. }) = arg.kind { + // Strip out the const and run again + let block = cx.tcx.hir_body(body).value; + return check(cx, expr, block, to_ty); + } + false } diff --git a/tests/ui/transmuting_null.rs b/tests/ui/transmuting_null.rs index 0d3b26673452..00aa35dff803 100644 --- a/tests/ui/transmuting_null.rs +++ b/tests/ui/transmuting_null.rs @@ -37,8 +37,19 @@ fn transmute_const_int() { } } +fn transumute_single_expr_blocks() { + unsafe { + let _: &u64 = std::mem::transmute({ 0 as *const u64 }); + //~^ transmuting_null + + let _: &u64 = std::mem::transmute(const { u64::MIN as *const u64 }); + //~^ transmuting_null + } +} + fn main() { one_liners(); transmute_const(); transmute_const_int(); + transumute_single_expr_blocks(); } diff --git a/tests/ui/transmuting_null.stderr b/tests/ui/transmuting_null.stderr index ed7c3396a243..e1de391813bd 100644 --- a/tests/ui/transmuting_null.stderr +++ b/tests/ui/transmuting_null.stderr @@ -25,5 +25,17 @@ error: transmuting a known null pointer into a reference LL | let _: &u64 = std::mem::transmute(u64::MIN as *const u64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: transmuting a known null pointer into a reference + --> tests/ui/transmuting_null.rs:42:23 + | +LL | let _: &u64 = std::mem::transmute({ 0 as *const u64 }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: transmuting a known null pointer into a reference + --> tests/ui/transmuting_null.rs:45:23 + | +LL | let _: &u64 = std::mem::transmute(const { u64::MIN as *const u64 }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors From f2283e2ef54539e51d47335fc3ab0435f6efd495 Mon Sep 17 00:00:00 2001 From: yanglsh Date: Fri, 19 Sep 2025 23:51:46 +0800 Subject: [PATCH 0030/1061] fix: `map_unwrap_or` fail to cover `Result::unwrap_or` --- clippy_lints/src/methods/map_unwrap_or.rs | 208 ++++++++++++++---- .../src/methods/map_unwrap_or_else.rs | 71 ++++++ clippy_lints/src/methods/mod.rs | 6 +- .../src/methods/option_map_unwrap_or.rs | 180 --------------- clippy_utils/src/msrvs.rs | 2 +- lintcheck/src/input.rs | 3 +- tests/ui/map_unwrap_or_fixable.fixed | 16 ++ tests/ui/map_unwrap_or_fixable.rs | 16 ++ tests/ui/map_unwrap_or_fixable.stderr | 50 ++++- 9 files changed, 325 insertions(+), 227 deletions(-) create mode 100644 clippy_lints/src/methods/map_unwrap_or_else.rs delete mode 100644 clippy_lints/src/methods/option_map_unwrap_or.rs diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index 8eb26fb50747..b29be88fb520 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -1,71 +1,199 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeDef; -use clippy_utils::source::snippet; -use clippy_utils::usage::mutated_variables; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::is_copy; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; -use rustc_hir as hir; +use rustc_hir::def::Res; +use rustc_hir::intravisit::{Visitor, walk_path}; +use rustc_hir::{ExprKind, HirId, Node, PatKind, Path, QPath}; use rustc_lint::LateContext; -use rustc_span::symbol::sym; +use rustc_middle::hir::nested_filter; +use rustc_span::{Span, sym}; +use std::ops::ControlFlow; use super::MAP_UNWRAP_OR; -/// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s -/// -/// Returns true if the lint was emitted +/// lint use of `map().unwrap_or()` for `Option`s and `Result`s +#[expect(clippy::too_many_arguments)] pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'_>, - recv: &'tcx hir::Expr<'_>, - map_arg: &'tcx hir::Expr<'_>, - unwrap_arg: &'tcx hir::Expr<'_>, + expr: &rustc_hir::Expr<'_>, + recv: &rustc_hir::Expr<'_>, + map_arg: &'tcx rustc_hir::Expr<'_>, + unwrap_recv: &rustc_hir::Expr<'_>, + unwrap_arg: &'tcx rustc_hir::Expr<'_>, + map_span: Span, msrv: Msrv, ) -> bool { // lint if the caller of `map()` is an `Option` or a `Result`. let is_option = cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Option); let is_result = cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Result); - if is_result && !msrv.meets(cx, msrvs::RESULT_MAP_OR_ELSE) { + if is_result && !msrv.meets(cx, msrvs::RESULT_MAP_OR) { return false; } + // lint if the caller of `map()` is an `Option` if is_option || is_result { - // Don't make a suggestion that may fail to compile due to mutably borrowing - // the same variable twice. - let map_mutated_vars = mutated_variables(recv, cx); - let unwrap_mutated_vars = mutated_variables(unwrap_arg, cx); - if let (Some(map_mutated_vars), Some(unwrap_mutated_vars)) = (map_mutated_vars, unwrap_mutated_vars) { - if map_mutated_vars.intersection(&unwrap_mutated_vars).next().is_some() { + if !is_copy(cx, cx.typeck_results().expr_ty(unwrap_arg)) { + // Replacing `.map().unwrap_or()` with `.map_or(, )` can sometimes lead to + // borrowck errors, see #10579 for one such instance. + // In particular, if `a` causes a move and `f` references that moved binding, then we cannot lint: + // ``` + // let x = vec![1, 2]; + // x.get(0..1).map(|s| s.to_vec()).unwrap_or(x); + // ``` + // This compiles, but changing it to `map_or` will produce a compile error: + // ``` + // let x = vec![1, 2]; + // x.get(0..1).map_or(x, |s| s.to_vec()) + // ^ moving `x` here + // ^^^^^^^^^^^ while it is borrowed here (and later used in the closure) + // ``` + // So, we have to check that `a` is not referenced anywhere (even outside of the `.map` closure!) + // before the call to `unwrap_or`. + + let mut unwrap_visitor = UnwrapVisitor { + cx, + identifiers: FxHashSet::default(), + }; + unwrap_visitor.visit_expr(unwrap_arg); + + let mut reference_visitor = ReferenceVisitor { + cx, + identifiers: unwrap_visitor.identifiers, + unwrap_or_span: unwrap_arg.span, + }; + + let body = cx.tcx.hir_body_owned_by(cx.tcx.hir_enclosing_body_owner(expr.hir_id)); + + // Visit the body, and return if we've found a reference + if reference_visitor.visit_body(body).is_break() { return false; } - } else { + } + + if !unwrap_arg.span.eq_ctxt(map_span) { return false; } + // is_some_and is stabilised && `unwrap_or` argument is false; suggest `is_some_and` instead + let suggest_is_some_and = matches!(&unwrap_arg.kind, ExprKind::Lit(lit) + if matches!(lit.node, rustc_ast::LitKind::Bool(false))) + && msrv.meets(cx, msrvs::OPTION_RESULT_IS_VARIANT_AND); + + let mut applicability = Applicability::MachineApplicable; + // get snippet for unwrap_or() + let unwrap_snippet = snippet_with_applicability(cx, unwrap_arg.span, "..", &mut applicability); // lint message - let msg = if is_option { - "called `map().unwrap_or_else()` on an `Option` value" + // comparing the snippet from source to raw text ("None") below is safe + // because we already have checked the type. + let unwrap_snippet_none = is_option && unwrap_snippet == "None"; + let arg = if unwrap_snippet_none { + "None" + } else if suggest_is_some_and { + "false" } else { - "called `map().unwrap_or_else()` on a `Result` value" + "" }; - // get snippets for args to map() and unwrap_or_else() - let map_snippet = snippet(cx, map_arg.span, ".."); - let unwrap_snippet = snippet(cx, unwrap_arg.span, ".."); - // lint, with note if both map() and unwrap_or_else() have the same span - if map_arg.span.eq_ctxt(unwrap_arg.span) { - let var_snippet = snippet(cx, recv.span, ".."); - span_lint_and_sugg( - cx, - MAP_UNWRAP_OR, - expr.span, - msg, - "try", - format!("{var_snippet}.map_or_else({unwrap_snippet}, {map_snippet})"), - Applicability::MachineApplicable, - ); - return true; - } + let suggest = if unwrap_snippet_none { + "and_then()" + } else if suggest_is_some_and { + if is_result { + "is_ok_and()" + } else { + "is_some_and()" + } + } else { + "map_or(, )" + }; + let msg = format!( + "called `map().unwrap_or({arg})` on an `{}` value", + if is_option { "Option" } else { "Result" } + ); + + span_lint_and_then(cx, MAP_UNWRAP_OR, expr.span, msg, |diag| { + let map_arg_span = map_arg.span; + + let mut suggestion = vec![ + ( + map_span, + String::from(if unwrap_snippet_none { + "and_then" + } else if suggest_is_some_and { + if is_result { "is_ok_and" } else { "is_some_and" } + } else { + "map_or" + }), + ), + (expr.span.with_lo(unwrap_recv.span.hi()), String::new()), + ]; + + if !unwrap_snippet_none && !suggest_is_some_and { + suggestion.push((map_arg_span.with_hi(map_arg_span.lo()), format!("{unwrap_snippet}, "))); + } + + diag.multipart_suggestion(format!("use `{suggest}` instead"), suggestion, applicability); + }); + + return true; } false } + +struct UnwrapVisitor<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + identifiers: FxHashSet, +} + +impl<'tcx> Visitor<'tcx> for UnwrapVisitor<'_, 'tcx> { + type NestedFilter = nested_filter::All; + + fn visit_path(&mut self, path: &Path<'tcx>, _: HirId) { + if let Res::Local(local_id) = path.res + && let Node::Pat(pat) = self.cx.tcx.hir_node(local_id) + && let PatKind::Binding(_, local_id, ..) = pat.kind + { + self.identifiers.insert(local_id); + } + walk_path(self, path); + } + + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.cx.tcx + } +} + +struct ReferenceVisitor<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + identifiers: FxHashSet, + unwrap_or_span: Span, +} + +impl<'tcx> Visitor<'tcx> for ReferenceVisitor<'_, 'tcx> { + type NestedFilter = nested_filter::All; + type Result = ControlFlow<()>; + fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'_>) -> ControlFlow<()> { + // If we haven't found a reference yet, check if this references + // one of the locals that was moved in the `unwrap_or` argument. + // We are only interested in exprs that appear before the `unwrap_or` call. + if expr.span < self.unwrap_or_span + && let ExprKind::Path(ref path) = expr.kind + && let QPath::Resolved(_, path) = path + && let Res::Local(local_id) = path.res + && let Node::Pat(pat) = self.cx.tcx.hir_node(local_id) + && let PatKind::Binding(_, local_id, ..) = pat.kind + && self.identifiers.contains(&local_id) + { + return ControlFlow::Break(()); + } + rustc_hir::intravisit::walk_expr(self, expr) + } + + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.cx.tcx + } +} diff --git a/clippy_lints/src/methods/map_unwrap_or_else.rs b/clippy_lints/src/methods/map_unwrap_or_else.rs new file mode 100644 index 000000000000..8eb26fb50747 --- /dev/null +++ b/clippy_lints/src/methods/map_unwrap_or_else.rs @@ -0,0 +1,71 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::res::MaybeDef; +use clippy_utils::source::snippet; +use clippy_utils::usage::mutated_variables; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; + +use super::MAP_UNWRAP_OR; + +/// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s +/// +/// Returns true if the lint was emitted +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + recv: &'tcx hir::Expr<'_>, + map_arg: &'tcx hir::Expr<'_>, + unwrap_arg: &'tcx hir::Expr<'_>, + msrv: Msrv, +) -> bool { + // lint if the caller of `map()` is an `Option` or a `Result`. + let is_option = cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Option); + let is_result = cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Result); + + if is_result && !msrv.meets(cx, msrvs::RESULT_MAP_OR_ELSE) { + return false; + } + + if is_option || is_result { + // Don't make a suggestion that may fail to compile due to mutably borrowing + // the same variable twice. + let map_mutated_vars = mutated_variables(recv, cx); + let unwrap_mutated_vars = mutated_variables(unwrap_arg, cx); + if let (Some(map_mutated_vars), Some(unwrap_mutated_vars)) = (map_mutated_vars, unwrap_mutated_vars) { + if map_mutated_vars.intersection(&unwrap_mutated_vars).next().is_some() { + return false; + } + } else { + return false; + } + + // lint message + let msg = if is_option { + "called `map().unwrap_or_else()` on an `Option` value" + } else { + "called `map().unwrap_or_else()` on a `Result` value" + }; + // get snippets for args to map() and unwrap_or_else() + let map_snippet = snippet(cx, map_arg.span, ".."); + let unwrap_snippet = snippet(cx, unwrap_arg.span, ".."); + // lint, with note if both map() and unwrap_or_else() have the same span + if map_arg.span.eq_ctxt(unwrap_arg.span) { + let var_snippet = snippet(cx, recv.span, ".."); + span_lint_and_sugg( + cx, + MAP_UNWRAP_OR, + expr.span, + msg, + "try", + format!("{var_snippet}.map_or_else({unwrap_snippet}, {map_snippet})"), + Applicability::MachineApplicable, + ); + return true; + } + } + + false +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 48842c8739c0..163205ea87be 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -74,6 +74,7 @@ mod map_err_ignore; mod map_flatten; mod map_identity; mod map_unwrap_or; +mod map_unwrap_or_else; mod map_with_unused_argument_over_ranges; mod mut_mutex_lock; mod needless_as_bytes; @@ -89,7 +90,6 @@ mod open_options; mod option_as_ref_cloned; mod option_as_ref_deref; mod option_map_or_none; -mod option_map_unwrap_or; mod or_fun_call; mod or_then_unwrap; mod path_buf_push_overwrite; @@ -5607,7 +5607,7 @@ impl Methods { manual_saturating_arithmetic::check_unwrap_or(cx, expr, lhs, rhs, u_arg, arith); }, Some((sym::map, m_recv, [m_arg], span, _)) => { - option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span, self.msrv); + map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span, self.msrv); }, Some((then_method @ (sym::then | sym::then_some), t_recv, [t_arg], _, _)) => { obfuscated_if_else::check( @@ -5648,7 +5648,7 @@ impl Methods { (sym::unwrap_or_else, [u_arg]) => { match method_call(recv) { Some((sym::map, recv, [map_arg], _, _)) - if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {}, + if map_unwrap_or_else::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {}, Some((then_method @ (sym::then | sym::then_some), t_recv, [t_arg], _, _)) => { obfuscated_if_else::check( cx, diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs deleted file mode 100644 index 32a9b4fe7c58..000000000000 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ /dev/null @@ -1,180 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::res::MaybeDef; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::is_copy; -use rustc_data_structures::fx::FxHashSet; -use rustc_errors::Applicability; -use rustc_hir::def::Res; -use rustc_hir::intravisit::{Visitor, walk_path}; -use rustc_hir::{ExprKind, HirId, Node, PatKind, Path, QPath}; -use rustc_lint::LateContext; -use rustc_middle::hir::nested_filter; -use rustc_span::{Span, sym}; -use std::ops::ControlFlow; - -use super::MAP_UNWRAP_OR; - -/// lint use of `map().unwrap_or()` for `Option`s -#[expect(clippy::too_many_arguments)] -pub(super) fn check<'tcx>( - cx: &LateContext<'tcx>, - expr: &rustc_hir::Expr<'_>, - recv: &rustc_hir::Expr<'_>, - map_arg: &'tcx rustc_hir::Expr<'_>, - unwrap_recv: &rustc_hir::Expr<'_>, - unwrap_arg: &'tcx rustc_hir::Expr<'_>, - map_span: Span, - msrv: Msrv, -) { - // lint if the caller of `map()` is an `Option` - if cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Option) { - if !is_copy(cx, cx.typeck_results().expr_ty(unwrap_arg)) { - // Replacing `.map().unwrap_or()` with `.map_or(, )` can sometimes lead to - // borrowck errors, see #10579 for one such instance. - // In particular, if `a` causes a move and `f` references that moved binding, then we cannot lint: - // ``` - // let x = vec![1, 2]; - // x.get(0..1).map(|s| s.to_vec()).unwrap_or(x); - // ``` - // This compiles, but changing it to `map_or` will produce a compile error: - // ``` - // let x = vec![1, 2]; - // x.get(0..1).map_or(x, |s| s.to_vec()) - // ^ moving `x` here - // ^^^^^^^^^^^ while it is borrowed here (and later used in the closure) - // ``` - // So, we have to check that `a` is not referenced anywhere (even outside of the `.map` closure!) - // before the call to `unwrap_or`. - - let mut unwrap_visitor = UnwrapVisitor { - cx, - identifiers: FxHashSet::default(), - }; - unwrap_visitor.visit_expr(unwrap_arg); - - let mut reference_visitor = ReferenceVisitor { - cx, - identifiers: unwrap_visitor.identifiers, - unwrap_or_span: unwrap_arg.span, - }; - - let body = cx.tcx.hir_body_owned_by(cx.tcx.hir_enclosing_body_owner(expr.hir_id)); - - // Visit the body, and return if we've found a reference - if reference_visitor.visit_body(body).is_break() { - return; - } - } - - if !unwrap_arg.span.eq_ctxt(map_span) { - return; - } - - // is_some_and is stabilised && `unwrap_or` argument is false; suggest `is_some_and` instead - let suggest_is_some_and = matches!(&unwrap_arg.kind, ExprKind::Lit(lit) - if matches!(lit.node, rustc_ast::LitKind::Bool(false))) - && msrv.meets(cx, msrvs::OPTION_RESULT_IS_VARIANT_AND); - - let mut applicability = Applicability::MachineApplicable; - // get snippet for unwrap_or() - let unwrap_snippet = snippet_with_applicability(cx, unwrap_arg.span, "..", &mut applicability); - // lint message - // comparing the snippet from source to raw text ("None") below is safe - // because we already have checked the type. - let arg = if unwrap_snippet == "None" { - "None" - } else if suggest_is_some_and { - "false" - } else { - "" - }; - let unwrap_snippet_none = unwrap_snippet == "None"; - let suggest = if unwrap_snippet_none { - "and_then()" - } else if suggest_is_some_and { - "is_some_and()" - } else { - "map_or(, )" - }; - let msg = format!("called `map().unwrap_or({arg})` on an `Option` value"); - - span_lint_and_then(cx, MAP_UNWRAP_OR, expr.span, msg, |diag| { - let map_arg_span = map_arg.span; - - let mut suggestion = vec![ - ( - map_span, - String::from(if unwrap_snippet_none { - "and_then" - } else if suggest_is_some_and { - "is_some_and" - } else { - "map_or" - }), - ), - (expr.span.with_lo(unwrap_recv.span.hi()), String::new()), - ]; - - if !unwrap_snippet_none && !suggest_is_some_and { - suggestion.push((map_arg_span.with_hi(map_arg_span.lo()), format!("{unwrap_snippet}, "))); - } - - diag.multipart_suggestion(format!("use `{suggest}` instead"), suggestion, applicability); - }); - } -} - -struct UnwrapVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - identifiers: FxHashSet, -} - -impl<'tcx> Visitor<'tcx> for UnwrapVisitor<'_, 'tcx> { - type NestedFilter = nested_filter::All; - - fn visit_path(&mut self, path: &Path<'tcx>, _: HirId) { - if let Res::Local(local_id) = path.res - && let Node::Pat(pat) = self.cx.tcx.hir_node(local_id) - && let PatKind::Binding(_, local_id, ..) = pat.kind - { - self.identifiers.insert(local_id); - } - walk_path(self, path); - } - - fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { - self.cx.tcx - } -} - -struct ReferenceVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - identifiers: FxHashSet, - unwrap_or_span: Span, -} - -impl<'tcx> Visitor<'tcx> for ReferenceVisitor<'_, 'tcx> { - type NestedFilter = nested_filter::All; - type Result = ControlFlow<()>; - fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'_>) -> ControlFlow<()> { - // If we haven't found a reference yet, check if this references - // one of the locals that was moved in the `unwrap_or` argument. - // We are only interested in exprs that appear before the `unwrap_or` call. - if expr.span < self.unwrap_or_span - && let ExprKind::Path(ref path) = expr.kind - && let QPath::Resolved(_, path) = path - && let Res::Local(local_id) = path.res - && let Node::Pat(pat) = self.cx.tcx.hir_node(local_id) - && let PatKind::Binding(_, local_id, ..) = pat.kind - && self.identifiers.contains(&local_id) - { - return ControlFlow::Break(()); - } - rustc_hir::intravisit::walk_expr(self, expr) - } - - fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { - self.cx.tcx - } -} diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 4a7fa3472cae..144ed3dec7d0 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -61,7 +61,7 @@ msrv_aliases! { 1,45,0 { STR_STRIP_PREFIX } 1,43,0 { LOG2_10, LOG10_2, NUMERIC_ASSOCIATED_CONSTANTS } 1,42,0 { MATCHES_MACRO, SLICE_PATTERNS, PTR_SLICE_RAW_PARTS } - 1,41,0 { RE_REBALANCING_COHERENCE, RESULT_MAP_OR_ELSE } + 1,41,0 { RE_REBALANCING_COHERENCE, RESULT_MAP_OR, RESULT_MAP_OR_ELSE } 1,40,0 { MEM_TAKE, NON_EXHAUSTIVE, OPTION_AS_DEREF } 1,38,0 { POINTER_CAST, REM_EUCLID } 1,37,0 { TYPE_ALIAS_ENUM_VARIANTS } diff --git a/lintcheck/src/input.rs b/lintcheck/src/input.rs index 7dda2b7b25f8..ee3fcaa0a84a 100644 --- a/lintcheck/src/input.rs +++ b/lintcheck/src/input.rs @@ -281,8 +281,7 @@ impl CrateWithSource { CrateSource::Path { path } => { fn is_cache_dir(entry: &DirEntry) -> bool { fs::read(entry.path().join("CACHEDIR.TAG")) - .map(|x| x.starts_with(b"Signature: 8a477f597d28d172789f06886806bc55")) - .unwrap_or(false) + .is_ok_and(|x| x.starts_with(b"Signature: 8a477f597d28d172789f06886806bc55")) } // copy path into the dest_crate_root but skip directories that contain a CACHEDIR.TAG file. diff --git a/tests/ui/map_unwrap_or_fixable.fixed b/tests/ui/map_unwrap_or_fixable.fixed index 90f3cf8bab04..a7a2f0693210 100644 --- a/tests/ui/map_unwrap_or_fixable.fixed +++ b/tests/ui/map_unwrap_or_fixable.fixed @@ -51,3 +51,19 @@ fn main() { option_methods(); result_methods(); } + +fn issue15714() { + let o: Option = Some(3); + let r: Result = Ok(3); + println!("{}", o.map_or(3, |y| y + 1)); + //~^ map_unwrap_or + println!("{}", o.map_or_else(|| 3, |y| y + 1)); + //~^ map_unwrap_or + println!("{}", r.map_or(3, |y| y + 1)); + //~^ map_unwrap_or + println!("{}", r.map_or_else(|()| 3, |y| y + 1)); + //~^ map_unwrap_or + + println!("{}", r.is_ok_and(|y| y == 1)); + //~^ map_unwrap_or +} diff --git a/tests/ui/map_unwrap_or_fixable.rs b/tests/ui/map_unwrap_or_fixable.rs index 1078c7a3cf34..f12f058c1c4b 100644 --- a/tests/ui/map_unwrap_or_fixable.rs +++ b/tests/ui/map_unwrap_or_fixable.rs @@ -57,3 +57,19 @@ fn main() { option_methods(); result_methods(); } + +fn issue15714() { + let o: Option = Some(3); + let r: Result = Ok(3); + println!("{}", o.map(|y| y + 1).unwrap_or(3)); + //~^ map_unwrap_or + println!("{}", o.map(|y| y + 1).unwrap_or_else(|| 3)); + //~^ map_unwrap_or + println!("{}", r.map(|y| y + 1).unwrap_or(3)); + //~^ map_unwrap_or + println!("{}", r.map(|y| y + 1).unwrap_or_else(|()| 3)); + //~^ map_unwrap_or + + println!("{}", r.map(|y| y == 1).unwrap_or(false)); + //~^ map_unwrap_or +} diff --git a/tests/ui/map_unwrap_or_fixable.stderr b/tests/ui/map_unwrap_or_fixable.stderr index 99e660f8dbd1..083a2510bdf2 100644 --- a/tests/ui/map_unwrap_or_fixable.stderr +++ b/tests/ui/map_unwrap_or_fixable.stderr @@ -19,5 +19,53 @@ LL | let _ = res.map(|x| x + 1) LL | | .unwrap_or_else(|_e| 0); | |_______________________________^ help: try: `res.map_or_else(|_e| 0, |x| x + 1)` -error: aborting due to 2 previous errors +error: called `map().unwrap_or()` on an `Option` value + --> tests/ui/map_unwrap_or_fixable.rs:64:20 + | +LL | println!("{}", o.map(|y| y + 1).unwrap_or(3)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `map_or(, )` instead + | +LL - println!("{}", o.map(|y| y + 1).unwrap_or(3)); +LL + println!("{}", o.map_or(3, |y| y + 1)); + | + +error: called `map().unwrap_or_else()` on an `Option` value + --> tests/ui/map_unwrap_or_fixable.rs:66:20 + | +LL | println!("{}", o.map(|y| y + 1).unwrap_or_else(|| 3)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `o.map_or_else(|| 3, |y| y + 1)` + +error: called `map().unwrap_or()` on an `Result` value + --> tests/ui/map_unwrap_or_fixable.rs:68:20 + | +LL | println!("{}", r.map(|y| y + 1).unwrap_or(3)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `map_or(, )` instead + | +LL - println!("{}", r.map(|y| y + 1).unwrap_or(3)); +LL + println!("{}", r.map_or(3, |y| y + 1)); + | + +error: called `map().unwrap_or_else()` on a `Result` value + --> tests/ui/map_unwrap_or_fixable.rs:70:20 + | +LL | println!("{}", r.map(|y| y + 1).unwrap_or_else(|()| 3)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `r.map_or_else(|()| 3, |y| y + 1)` + +error: called `map().unwrap_or(false)` on an `Result` value + --> tests/ui/map_unwrap_or_fixable.rs:73:20 + | +LL | println!("{}", r.map(|y| y == 1).unwrap_or(false)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `is_ok_and()` instead + | +LL - println!("{}", r.map(|y| y == 1).unwrap_or(false)); +LL + println!("{}", r.is_ok_and(|y| y == 1)); + | + +error: aborting due to 7 previous errors From 9565b28598976f62305ea3fb9a877b2628bb1c14 Mon Sep 17 00:00:00 2001 From: yanglsh Date: Wed, 24 Sep 2025 00:04:49 +0800 Subject: [PATCH 0031/1061] fix: `map_unwrap_or` FN on references --- clippy_lints/src/methods/map_unwrap_or.rs | 18 +++---- .../src/methods/map_unwrap_or_else.rs | 6 +-- tests/ui/map_unwrap_or_fixable.fixed | 19 +++++++ tests/ui/map_unwrap_or_fixable.rs | 19 +++++++ tests/ui/map_unwrap_or_fixable.stderr | 52 ++++++++++++++++--- 5 files changed, 92 insertions(+), 22 deletions(-) diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index b29be88fb520..f2e3cc5c0091 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -26,13 +26,13 @@ pub(super) fn check<'tcx>( unwrap_arg: &'tcx rustc_hir::Expr<'_>, map_span: Span, msrv: Msrv, -) -> bool { - // lint if the caller of `map()` is an `Option` or a `Result`. - let is_option = cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Option); - let is_result = cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Result); +) { + let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs(); + let is_option = recv_ty.is_diag_item(cx, sym::Option); + let is_result = recv_ty.is_diag_item(cx, sym::Result); if is_result && !msrv.meets(cx, msrvs::RESULT_MAP_OR) { - return false; + return; } // lint if the caller of `map()` is an `Option` @@ -71,12 +71,12 @@ pub(super) fn check<'tcx>( // Visit the body, and return if we've found a reference if reference_visitor.visit_body(body).is_break() { - return false; + return; } } if !unwrap_arg.span.eq_ctxt(map_span) { - return false; + return; } // is_some_and is stabilised && `unwrap_or` argument is false; suggest `is_some_and` instead @@ -137,11 +137,7 @@ pub(super) fn check<'tcx>( diag.multipart_suggestion(format!("use `{suggest}` instead"), suggestion, applicability); }); - - return true; } - - false } struct UnwrapVisitor<'a, 'tcx> { diff --git a/clippy_lints/src/methods/map_unwrap_or_else.rs b/clippy_lints/src/methods/map_unwrap_or_else.rs index 8eb26fb50747..a2f157c0cb8a 100644 --- a/clippy_lints/src/methods/map_unwrap_or_else.rs +++ b/clippy_lints/src/methods/map_unwrap_or_else.rs @@ -21,9 +21,9 @@ pub(super) fn check<'tcx>( unwrap_arg: &'tcx hir::Expr<'_>, msrv: Msrv, ) -> bool { - // lint if the caller of `map()` is an `Option` or a `Result`. - let is_option = cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Option); - let is_result = cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Result); + let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs(); + let is_option = recv_ty.is_diag_item(cx, sym::Option); + let is_result = recv_ty.is_diag_item(cx, sym::Result); if is_result && !msrv.meets(cx, msrvs::RESULT_MAP_OR_ELSE) { return false; diff --git a/tests/ui/map_unwrap_or_fixable.fixed b/tests/ui/map_unwrap_or_fixable.fixed index a7a2f0693210..1789c7f4d487 100644 --- a/tests/ui/map_unwrap_or_fixable.fixed +++ b/tests/ui/map_unwrap_or_fixable.fixed @@ -1,6 +1,7 @@ //@aux-build:option_helpers.rs #![warn(clippy::map_unwrap_or)] +#![allow(clippy::unnecessary_lazy_evaluations)] #[macro_use] extern crate option_helpers; @@ -67,3 +68,21 @@ fn issue15714() { println!("{}", r.is_ok_and(|y| y == 1)); //~^ map_unwrap_or } + +fn issue15713() { + let x = &Some(3); + println!("{}", x.map_or(3, |y| y + 1)); + //~^ map_unwrap_or + + let x: &Result = &Ok(3); + println!("{}", x.map_or(3, |y| y + 1)); + //~^ map_unwrap_or + + let x = &Some(3); + println!("{}", x.map_or_else(|| 3, |y| y + 1)); + //~^ map_unwrap_or + + let x: &Result = &Ok(3); + println!("{}", x.map_or_else(|_| 3, |y| y + 1)); + //~^ map_unwrap_or +} diff --git a/tests/ui/map_unwrap_or_fixable.rs b/tests/ui/map_unwrap_or_fixable.rs index f12f058c1c4b..309067edce4d 100644 --- a/tests/ui/map_unwrap_or_fixable.rs +++ b/tests/ui/map_unwrap_or_fixable.rs @@ -1,6 +1,7 @@ //@aux-build:option_helpers.rs #![warn(clippy::map_unwrap_or)] +#![allow(clippy::unnecessary_lazy_evaluations)] #[macro_use] extern crate option_helpers; @@ -73,3 +74,21 @@ fn issue15714() { println!("{}", r.map(|y| y == 1).unwrap_or(false)); //~^ map_unwrap_or } + +fn issue15713() { + let x = &Some(3); + println!("{}", x.map(|y| y + 1).unwrap_or(3)); + //~^ map_unwrap_or + + let x: &Result = &Ok(3); + println!("{}", x.map(|y| y + 1).unwrap_or(3)); + //~^ map_unwrap_or + + let x = &Some(3); + println!("{}", x.map(|y| y + 1).unwrap_or_else(|| 3)); + //~^ map_unwrap_or + + let x: &Result = &Ok(3); + println!("{}", x.map(|y| y + 1).unwrap_or_else(|_| 3)); + //~^ map_unwrap_or +} diff --git a/tests/ui/map_unwrap_or_fixable.stderr b/tests/ui/map_unwrap_or_fixable.stderr index 083a2510bdf2..696f516ee055 100644 --- a/tests/ui/map_unwrap_or_fixable.stderr +++ b/tests/ui/map_unwrap_or_fixable.stderr @@ -1,5 +1,5 @@ error: called `map().unwrap_or_else()` on an `Option` value - --> tests/ui/map_unwrap_or_fixable.rs:16:13 + --> tests/ui/map_unwrap_or_fixable.rs:17:13 | LL | let _ = opt.map(|x| x + 1) | _____________^ @@ -11,7 +11,7 @@ LL | | .unwrap_or_else(|| 0); = help: to override `-D warnings` add `#[allow(clippy::map_unwrap_or)]` error: called `map().unwrap_or_else()` on a `Result` value - --> tests/ui/map_unwrap_or_fixable.rs:47:13 + --> tests/ui/map_unwrap_or_fixable.rs:48:13 | LL | let _ = res.map(|x| x + 1) | _____________^ @@ -20,7 +20,7 @@ LL | | .unwrap_or_else(|_e| 0); | |_______________________________^ help: try: `res.map_or_else(|_e| 0, |x| x + 1)` error: called `map().unwrap_or()` on an `Option` value - --> tests/ui/map_unwrap_or_fixable.rs:64:20 + --> tests/ui/map_unwrap_or_fixable.rs:65:20 | LL | println!("{}", o.map(|y| y + 1).unwrap_or(3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,13 +32,13 @@ LL + println!("{}", o.map_or(3, |y| y + 1)); | error: called `map().unwrap_or_else()` on an `Option` value - --> tests/ui/map_unwrap_or_fixable.rs:66:20 + --> tests/ui/map_unwrap_or_fixable.rs:67:20 | LL | println!("{}", o.map(|y| y + 1).unwrap_or_else(|| 3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `o.map_or_else(|| 3, |y| y + 1)` error: called `map().unwrap_or()` on an `Result` value - --> tests/ui/map_unwrap_or_fixable.rs:68:20 + --> tests/ui/map_unwrap_or_fixable.rs:69:20 | LL | println!("{}", r.map(|y| y + 1).unwrap_or(3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -50,13 +50,13 @@ LL + println!("{}", r.map_or(3, |y| y + 1)); | error: called `map().unwrap_or_else()` on a `Result` value - --> tests/ui/map_unwrap_or_fixable.rs:70:20 + --> tests/ui/map_unwrap_or_fixable.rs:71:20 | LL | println!("{}", r.map(|y| y + 1).unwrap_or_else(|()| 3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `r.map_or_else(|()| 3, |y| y + 1)` error: called `map().unwrap_or(false)` on an `Result` value - --> tests/ui/map_unwrap_or_fixable.rs:73:20 + --> tests/ui/map_unwrap_or_fixable.rs:74:20 | LL | println!("{}", r.map(|y| y == 1).unwrap_or(false)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -67,5 +67,41 @@ LL - println!("{}", r.map(|y| y == 1).unwrap_or(false)); LL + println!("{}", r.is_ok_and(|y| y == 1)); | -error: aborting due to 7 previous errors +error: called `map().unwrap_or()` on an `Option` value + --> tests/ui/map_unwrap_or_fixable.rs:80:20 + | +LL | println!("{}", x.map(|y| y + 1).unwrap_or(3)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `map_or(, )` instead + | +LL - println!("{}", x.map(|y| y + 1).unwrap_or(3)); +LL + println!("{}", x.map_or(3, |y| y + 1)); + | + +error: called `map().unwrap_or()` on an `Result` value + --> tests/ui/map_unwrap_or_fixable.rs:84:20 + | +LL | println!("{}", x.map(|y| y + 1).unwrap_or(3)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `map_or(, )` instead + | +LL - println!("{}", x.map(|y| y + 1).unwrap_or(3)); +LL + println!("{}", x.map_or(3, |y| y + 1)); + | + +error: called `map().unwrap_or_else()` on an `Option` value + --> tests/ui/map_unwrap_or_fixable.rs:88:20 + | +LL | println!("{}", x.map(|y| y + 1).unwrap_or_else(|| 3)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.map_or_else(|| 3, |y| y + 1)` + +error: called `map().unwrap_or_else()` on a `Result` value + --> tests/ui/map_unwrap_or_fixable.rs:92:20 + | +LL | println!("{}", x.map(|y| y + 1).unwrap_or_else(|_| 3)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.map_or_else(|_| 3, |y| y + 1)` + +error: aborting due to 11 previous errors From b00739765c89f9182a8284c1718de7c858217869 Mon Sep 17 00:00:00 2001 From: Jane Losare-Lusby Date: Tue, 16 Dec 2025 13:25:27 -0800 Subject: [PATCH 0032/1061] Update provider API docs --- library/core/src/error.rs | 50 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/library/core/src/error.rs b/library/core/src/error.rs index 9ca91ee009ee..011d6ac4a1c7 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -205,6 +205,56 @@ pub trait Error: Debug + Display { /// assert!(request_ref::(dyn_error).is_none()); /// } /// ``` + /// + /// # Delegating Impls + /// + ///
+ /// + /// **Warning**: We recommend implementors avoid delegating implementations of `provide` to + /// source error implementations. + /// + ///
+ /// + /// This method should expose context from the current piece of the source chain only, not from + /// sources that are exposed in the chain of sources. Delegating `provide` implementations cause + /// the same context to be provided by multiple errors in the chain of sources which can cause + /// unintended duplication of information in error reports or require heuristics to deduplicate. + /// + /// In other words, the following implementation pattern for `provide` is discouraged and should + /// not be used for [`Error`] types exposed in public APIs to third parties. + /// + /// ```rust + /// # #![feature(error_generic_member_access)] + /// # use core::fmt; + /// # use core::error::Request; + /// # #[derive(Debug)] + /// struct MyError { + /// source: Error, + /// } + /// # #[derive(Debug)] + /// # struct Error; + /// # impl fmt::Display for Error { + /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// # write!(f, "Example Source Error") + /// # } + /// # } + /// # impl fmt::Display for MyError { + /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// # write!(f, "Example Error") + /// # } + /// # } + /// # impl std::error::Error for Error { } + /// + /// impl std::error::Error for MyError { + /// fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + /// Some(&self.source) + /// } + /// + /// fn provide<'a>(&'a self, request: &mut Request<'a>) { + /// self.source.provide(request) // <--- Discouraged + /// } + /// } + /// ``` #[unstable(feature = "error_generic_member_access", issue = "99301")] #[allow(unused_variables)] fn provide<'a>(&'a self, request: &mut Request<'a>) {} From bd0341471abbf02331061d76ca54fe801f95fb52 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Fri, 19 Dec 2025 11:20:38 +0100 Subject: [PATCH 0033/1061] Post `needless_continue` diagnostic on the right node --- clippy_lints/src/needless_continue.rs | 31 +++++++++++------------- tests/ui/needless_continue.rs | 35 +++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 55208ae708b9..d1d0d31ed91a 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -1,9 +1,9 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::higher; use clippy_utils::source::{indent_of, snippet_block, snippet_with_context}; use rustc_ast::Label; use rustc_errors::Applicability; -use rustc_hir::{Block, Expr, ExprKind, LoopSource, StmtKind}; +use rustc_hir::{Block, Expr, ExprKind, HirId, LoopSource, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::declare_lint_pass; use rustc_span::{ExpnKind, Span}; @@ -336,14 +336,9 @@ fn emit_warning(cx: &LateContext<'_>, data: &LintData<'_>, header: &str, typ: Li data.if_expr, ), }; - span_lint_and_help( - cx, - NEEDLESS_CONTINUE, - expr.span, - message, - None, - format!("{header}\n{snip}"), - ); + span_lint_hir_and_then(cx, NEEDLESS_CONTINUE, expr.hir_id, expr.span, message, |diag| { + diag.help(format!("{header}\n{snip}")); + }); } fn suggestion_snippet_for_continue_inside_if(cx: &LateContext<'_>, data: &LintData<'_>) -> String { @@ -424,11 +419,11 @@ fn suggestion_snippet_for_continue_inside_else(cx: &LateContext<'_>, data: &Lint fn check_last_stmt_in_expr(cx: &LateContext<'_>, inner_expr: &Expr<'_>, func: &F) where - F: Fn(Option<&Label>, Span), + F: Fn(HirId, Option<&Label>, Span), { match inner_expr.kind { ExprKind::Continue(continue_label) => { - func(continue_label.label.as_ref(), inner_expr.span); + func(inner_expr.hir_id, continue_label.label.as_ref(), inner_expr.span); }, ExprKind::If(_, then_block, else_block) if let ExprKind::Block(then_block, _) = then_block.kind => { check_last_stmt_in_block(cx, then_block, func); @@ -454,7 +449,7 @@ where fn check_last_stmt_in_block(cx: &LateContext<'_>, b: &Block<'_>, func: &F) where - F: Fn(Option<&Label>, Span), + F: Fn(HirId, Option<&Label>, Span), { if let Some(expr) = b.expr { check_last_stmt_in_expr(cx, expr, func); @@ -470,15 +465,17 @@ where fn check_and_warn(cx: &LateContext<'_>, expr: &Expr<'_>) { with_loop_block(expr, |loop_block, label| { - let p = |continue_label: Option<&Label>, span: Span| { + let p = |continue_hir_id, continue_label: Option<&Label>, span: Span| { if compare_labels(label, continue_label) { - span_lint_and_help( + span_lint_hir_and_then( cx, NEEDLESS_CONTINUE, + continue_hir_id, span, MSG_REDUNDANT_CONTINUE_EXPRESSION, - None, - DROP_CONTINUE_EXPRESSION_MSG, + |diag| { + diag.help(DROP_CONTINUE_EXPRESSION_MSG); + }, ); } }; diff --git a/tests/ui/needless_continue.rs b/tests/ui/needless_continue.rs index 88b7905e7fa8..3275dddf1a0f 100644 --- a/tests/ui/needless_continue.rs +++ b/tests/ui/needless_continue.rs @@ -342,3 +342,38 @@ fn issue15548() { } } } + +fn issue16256() { + fn some_condition() -> bool { + true + } + fn another_condition() -> bool { + true + } + + for _ in 0..5 { + if some_condition() { + // ... + continue; + } + + if another_condition() { + // ... + // "this `continue` expression is redundant" is posted on + // the `continue` node. + #[expect(clippy::needless_continue)] + continue; + } + } + + for _ in 0..5 { + // "This `else` block is redundant" is posted on the + // `else` node. + #[expect(clippy::needless_continue)] + if some_condition() { + // ... + } else { + continue; + } + } +} From 6c4c4384e8f66476214d56b82313c39472c8215e Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 19 Dec 2025 11:37:22 +0000 Subject: [PATCH 0034/1061] destabilise target-spec-json --- compiler/rustc_driver_impl/src/lib.rs | 3 ++- compiler/rustc_interface/src/interface.rs | 1 + compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_session/src/config.rs | 3 ++- compiler/rustc_session/src/session.rs | 7 +++++-- compiler/rustc_target/src/spec/mod.rs | 15 ++++++++++++--- tests/run-make/target-specs/rmake.rs | 16 +++++++++++++++- 7 files changed, 38 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 63fc9c96f450..5a30e7869f86 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -1124,9 +1124,10 @@ fn get_backend_from_raw_matches( let backend_name = debug_flags .iter() .find_map(|x| x.strip_prefix("codegen-backend=").or(x.strip_prefix("codegen_backend="))); + let unstable_options = debug_flags.iter().find(|x| *x == "unstable-options").is_some(); let target = parse_target_triple(early_dcx, matches); let sysroot = Sysroot::new(matches.opt_str("sysroot").map(PathBuf::from)); - let target = config::build_target_config(early_dcx, &target, sysroot.path()); + let target = config::build_target_config(early_dcx, &target, sysroot.path(), unstable_options); get_codegen_backend(early_dcx, &sysroot, backend_name, &target) } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index c0f8f33692e8..863c56f1a54f 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -427,6 +427,7 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se &early_dcx, &config.opts.target_triple, config.opts.sysroot.path(), + config.opts.unstable_opts.unstable_options, ); let file_loader = config.file_loader.unwrap_or_else(|| Box::new(RealFileLoader)); let path_mapping = config.opts.file_path_mapping(); diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 8dab3a7f37f5..0ea7232cb7a9 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -46,6 +46,7 @@ where &early_dcx, &sessopts.target_triple, sessopts.sysroot.path(), + sessopts.unstable_opts.unstable_options, ); let hash_kind = sessopts.unstable_opts.src_hash_algorithm(&target); let checksum_hash_kind = sessopts.unstable_opts.checksum_hash_algorithm(); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index a3a97dfec61d..74826d053101 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1586,8 +1586,9 @@ pub fn build_target_config( early_dcx: &EarlyDiagCtxt, target: &TargetTuple, sysroot: &Path, + unstable_options: bool, ) -> Target { - match Target::search(target, sysroot) { + match Target::search(target, sysroot, unstable_options) { Ok((target, warnings)) => { for warning in warnings.warning_messages() { early_dcx.early_warn(warning) diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 1a0ec600af47..1d5b36fc61b8 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1002,8 +1002,11 @@ pub fn build_session( } let host_triple = TargetTuple::from_tuple(config::host_tuple()); - let (host, target_warnings) = Target::search(&host_triple, sopts.sysroot.path()) - .unwrap_or_else(|e| dcx.handle().fatal(format!("Error loading host specification: {e}"))); + let (host, target_warnings) = + Target::search(&host_triple, sopts.sysroot.path(), sopts.unstable_opts.unstable_options) + .unwrap_or_else(|e| { + dcx.handle().fatal(format!("Error loading host specification: {e}")) + }); for warning in target_warnings.warning_messages() { dcx.handle().warn(warning) } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 3d500694c978..d6d607fb18d6 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -3299,10 +3299,19 @@ impl Target { pub fn search( target_tuple: &TargetTuple, sysroot: &Path, + unstable_options: bool, ) -> Result<(Target, TargetWarnings), String> { use std::{env, fs}; - fn load_file(path: &Path) -> Result<(Target, TargetWarnings), String> { + fn load_file( + path: &Path, + unstable_options: bool, + ) -> Result<(Target, TargetWarnings), String> { + if !unstable_options { + return Err( + "custom targets are unstable and require `-Zunstable-options`".to_string() + ); + } let contents = fs::read_to_string(path).map_err(|e| e.to_string())?; Target::from_json(&contents) } @@ -3326,7 +3335,7 @@ impl Target { for dir in env::split_paths(&target_path) { let p = dir.join(&path); if p.is_file() { - return load_file(&p); + return load_file(&p, unstable_options); } } @@ -3339,7 +3348,7 @@ impl Target { Path::new("target.json"), ]); if p.is_file() { - return load_file(&p); + return load_file(&p, unstable_options); } Err(format!("could not find specification for target {target_tuple:?}")) diff --git a/tests/run-make/target-specs/rmake.rs b/tests/run-make/target-specs/rmake.rs index 7c30a5b21b33..69292af5fd69 100644 --- a/tests/run-make/target-specs/rmake.rs +++ b/tests/run-make/target-specs/rmake.rs @@ -15,11 +15,20 @@ fn main() { .run_fail() .assert_stderr_contains("error loading target specification"); rustc() + .arg("-Zunstable-options") .input("foo.rs") .target("my-incomplete-platform.json") .run_fail() .assert_stderr_contains("missing field `llvm-target`"); + let test_platform = rustc() + .input("foo.rs") + .target("my-x86_64-unknown-linux-gnu-platform") + .crate_type("lib") + .emit("asm") + .run_fail() + .assert_stderr_contains("custom targets are unstable and require `-Zunstable-options`"); rustc() + .arg("-Zunstable-options") .env("RUST_TARGET_PATH", ".") .input("foo.rs") .target("my-awesome-platform") @@ -27,6 +36,7 @@ fn main() { .emit("asm") .run(); rustc() + .arg("-Zunstable-options") .env("RUST_TARGET_PATH", ".") .input("foo.rs") .target("my-x86_64-unknown-linux-gnu-platform") @@ -52,27 +62,31 @@ fn main() { .actual_text("test-platform-2", test_platform_2) .run(); rustc() + .arg("-Zunstable-options") .input("foo.rs") .target("endianness-mismatch") .run_fail() .assert_stderr_contains(r#""data-layout" claims architecture is little-endian"#); rustc() + .arg("-Zunstable-options") .input("foo.rs") .target("mismatching-data-layout") .crate_type("lib") .run_fail() .assert_stderr_contains("data-layout for target"); rustc() + .arg("-Zunstable-options") .input("foo.rs") .target("require-explicit-cpu") .crate_type("lib") .run_fail() .assert_stderr_contains("target requires explicitly specifying a cpu"); rustc() + .arg("-Zunstable-options") .input("foo.rs") .target("require-explicit-cpu") .crate_type("lib") .arg("-Ctarget-cpu=generic") .run(); - rustc().target("require-explicit-cpu").arg("--print=target-cpus").run(); + rustc().arg("-Zunstable-options").target("require-explicit-cpu").print("target-cpus").run(); } From 9bfc9a4778d41831157e2af5063e38542960ece0 Mon Sep 17 00:00:00 2001 From: WaterWhisperer Date: Thu, 18 Dec 2025 23:29:54 +0800 Subject: [PATCH 0035/1061] fix: `main_recursion` enable lint in no_std crates and fix broken tests --- tests/ui/crate_level_checks/entrypoint_recursion.rs | 7 +++---- .../crate_level_checks/entrypoint_recursion.stderr | 12 ++++++++++++ .../ui/crate_level_checks/no_std_main_recursion.rs | 13 +++++++++++++ 3 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 tests/ui/crate_level_checks/entrypoint_recursion.stderr create mode 100644 tests/ui/crate_level_checks/no_std_main_recursion.rs diff --git a/tests/ui/crate_level_checks/entrypoint_recursion.rs b/tests/ui/crate_level_checks/entrypoint_recursion.rs index 3ded902e36b1..84147d8e9c16 100644 --- a/tests/ui/crate_level_checks/entrypoint_recursion.rs +++ b/tests/ui/crate_level_checks/entrypoint_recursion.rs @@ -1,12 +1,11 @@ -//@check-pass //@ignore-target: apple - #![feature(rustc_attrs)] - #[warn(clippy::main_recursion)] #[allow(unconditional_recursion)] #[rustc_main] fn a() { - println!("Hello, World!"); a(); + //~^ main_recursion } + +fn main() {} diff --git a/tests/ui/crate_level_checks/entrypoint_recursion.stderr b/tests/ui/crate_level_checks/entrypoint_recursion.stderr new file mode 100644 index 000000000000..d9f50d2dfc4b --- /dev/null +++ b/tests/ui/crate_level_checks/entrypoint_recursion.stderr @@ -0,0 +1,12 @@ +error: recursing into entrypoint `a` + --> tests/ui/crate_level_checks/entrypoint_recursion.rs:7:5 + | +LL | a(); + | ^ + | + = help: consider using another function for this recursion + = note: `-D clippy::main-recursion` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::main_recursion)]` + +error: aborting due to 1 previous error + diff --git a/tests/ui/crate_level_checks/no_std_main_recursion.rs b/tests/ui/crate_level_checks/no_std_main_recursion.rs new file mode 100644 index 000000000000..74763d67dd78 --- /dev/null +++ b/tests/ui/crate_level_checks/no_std_main_recursion.rs @@ -0,0 +1,13 @@ +//@check-pass +//@compile-flags: -Cpanic=abort +#![no_std] +#[warn(clippy::main_recursion)] +#[allow(unconditional_recursion)] +fn main() { + main(); +} + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} From 5610d84ab12502922459ae5da17ac8e0774a8e44 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 19 Dec 2025 07:55:00 -0800 Subject: [PATCH 0036/1061] rustc: Fix `-Zexport-executable-symbols` on wasm This commit reorders some cases in `export_symbols` in the linker implementation for wasm to ensure that the `is_like_wasm` case is handled before the catch-all `CrateType::Executable` case. --- compiler/rustc_codegen_ssa/src/back/linker.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index c73e950bed40..b47652092ed5 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -839,6 +839,11 @@ impl<'a> Linker for GccLinker<'a> { self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error }); } self.link_arg(path); + } else if self.sess.target.is_like_wasm { + self.link_arg("--no-export-dynamic"); + for (sym, _) in symbols { + self.link_arg("--export").link_arg(sym); + } } else if crate_type == CrateType::Executable && !self.sess.target.is_like_solaris { let res: io::Result<()> = try { let mut f = File::create_buffered(&path)?; @@ -853,11 +858,6 @@ impl<'a> Linker for GccLinker<'a> { self.sess.dcx().emit_fatal(errors::VersionScriptWriteFailure { error }); } self.link_arg("--dynamic-list").link_arg(path); - } else if self.sess.target.is_like_wasm { - self.link_arg("--no-export-dynamic"); - for (sym, _) in symbols { - self.link_arg("--export").link_arg(sym); - } } else { // Write an LD version script let res: io::Result<()> = try { From ca91076898c59730efe3c615916fa0a589d4fe8a Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Wed, 13 Aug 2025 10:13:48 +0530 Subject: [PATCH 0037/1061] std: sys: net: uefi: tcp: Initial TcpListener support Add support for binding and accepting TCP4 connections. While testing, the following network options were used with QEMU + OVMF: -nic user,hostfwd=tcp::12345-:12345 The default localhost address on qemu seems to be 10.0.2.15. UEFI spec does not seem to state that the TCP Handle returned by the Accept method has a ServiceBinding Protocol. So have made the ServiceBinding Protocol optional. Signed-off-by: Ayush Singh --- .../std/src/sys/net/connection/uefi/mod.rs | 35 +++++---- .../std/src/sys/net/connection/uefi/tcp.rs | 19 ++++- .../std/src/sys/net/connection/uefi/tcp4.rs | 78 +++++++++++++++---- library/std/src/sys/pal/uefi/helpers.rs | 48 ++++++------ 4 files changed, 128 insertions(+), 52 deletions(-) diff --git a/library/std/src/sys/net/connection/uefi/mod.rs b/library/std/src/sys/net/connection/uefi/mod.rs index db2d18646d02..107a3e23733d 100644 --- a/library/std/src/sys/net/connection/uefi/mod.rs +++ b/library/std/src/sys/net/connection/uefi/mod.rs @@ -16,26 +16,26 @@ pub struct TcpStream { } impl TcpStream { + fn new(inner: tcp::Tcp) -> Self { + Self { + inner, + read_timeout: Arc::new(Mutex::new(None)), + write_timeout: Arc::new(Mutex::new(None)), + } + } + pub fn connect(addr: A) -> io::Result { return each_addr(addr, inner); fn inner(addr: &SocketAddr) -> io::Result { let inner = tcp::Tcp::connect(addr, None)?; - Ok(TcpStream { - inner, - read_timeout: Arc::new(Mutex::new(None)), - write_timeout: Arc::new(Mutex::new(None)), - }) + Ok(TcpStream::new(inner)) } } pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result { let inner = tcp::Tcp::connect(addr, Some(timeout))?; - Ok(Self { - inner, - read_timeout: Arc::new(Mutex::new(None)), - write_timeout: Arc::new(Mutex::new(None)), - }) + Ok(Self::new(inner)) } pub fn set_read_timeout(&self, t: Option) -> io::Result<()> { @@ -148,16 +148,23 @@ pub struct TcpListener { } impl TcpListener { - pub fn bind(_: A) -> io::Result { - unsupported() + pub fn bind(addr: A) -> io::Result { + return each_addr(addr, inner); + + fn inner(addr: &SocketAddr) -> io::Result { + let inner = tcp::Tcp::bind(addr)?; + Ok(TcpListener { inner }) + } } pub fn socket_addr(&self) -> io::Result { - unsupported() + self.inner.socket_addr() } pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { - unsupported() + let tcp = self.inner.accept()?; + let addr = tcp.peer_addr()?; + Ok((TcpStream::new(tcp), addr)) } pub fn duplicate(&self) -> io::Result { diff --git a/library/std/src/sys/net/connection/uefi/tcp.rs b/library/std/src/sys/net/connection/uefi/tcp.rs index 1e7e829c85f3..dc6765b125ea 100644 --- a/library/std/src/sys/net/connection/uefi/tcp.rs +++ b/library/std/src/sys/net/connection/uefi/tcp.rs @@ -18,7 +18,24 @@ impl Tcp { temp.connect(timeout)?; Ok(Tcp::V4(temp)) } - SocketAddr::V6(_) => todo!(), + SocketAddr::V6(_) => unsupported(), + } + } + + pub(crate) fn bind(addr: &SocketAddr) -> io::Result { + match addr { + SocketAddr::V4(x) => { + let temp = tcp4::Tcp4::new()?; + temp.configure(false, None, Some(x))?; + Ok(Tcp::V4(temp)) + } + SocketAddr::V6(_) => unsupported(), + } + } + + pub(crate) fn accept(&self) -> io::Result { + match self { + Self::V4(client) => client.accept().map(Tcp::V4), } } diff --git a/library/std/src/sys/net/connection/uefi/tcp4.rs b/library/std/src/sys/net/connection/uefi/tcp4.rs index 0409997f0272..00c93384e5f6 100644 --- a/library/std/src/sys/net/connection/uefi/tcp4.rs +++ b/library/std/src/sys/net/connection/uefi/tcp4.rs @@ -3,7 +3,7 @@ use r_efi::protocols::tcp4; use crate::io::{self, IoSlice, IoSliceMut}; use crate::net::SocketAddrV4; -use crate::ptr::NonNull; +use crate::ptr::{self, NonNull}; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sys::pal::helpers; use crate::time::{Duration, Instant}; @@ -12,9 +12,9 @@ const TYPE_OF_SERVICE: u8 = 8; const TIME_TO_LIVE: u8 = 255; pub(crate) struct Tcp4 { + handle: NonNull, protocol: NonNull, flag: AtomicBool, - #[expect(dead_code)] service_binding: helpers::ServiceProtocol, } @@ -22,10 +22,11 @@ const DEFAULT_ADDR: efi::Ipv4Address = efi::Ipv4Address { addr: [0u8; 4] }; impl Tcp4 { pub(crate) fn new() -> io::Result { - let service_binding = helpers::ServiceProtocol::open(tcp4::SERVICE_BINDING_PROTOCOL_GUID)?; - let protocol = helpers::open_protocol(service_binding.child_handle(), tcp4::PROTOCOL_GUID)?; + let (service_binding, handle) = + helpers::ServiceProtocol::open(tcp4::SERVICE_BINDING_PROTOCOL_GUID)?; + let protocol = helpers::open_protocol(handle, tcp4::PROTOCOL_GUID)?; - Ok(Self { service_binding, protocol, flag: AtomicBool::new(false) }) + Ok(Self { service_binding, handle, protocol, flag: AtomicBool::new(false) }) } pub(crate) fn configure( @@ -42,11 +43,14 @@ impl Tcp4 { (DEFAULT_ADDR, 0) }; - // FIXME: Remove when passive connections with proper subnet handling are added - assert!(station_address.is_none()); - let use_default_address = efi::Boolean::TRUE; - let (station_address, station_port) = (DEFAULT_ADDR, 0); - let subnet_mask = helpers::ipv4_to_r_efi(crate::net::Ipv4Addr::new(0, 0, 0, 0)); + let use_default_address: r_efi::efi::Boolean = + station_address.is_none_or(|addr| addr.ip().is_unspecified()).into(); + let (station_address, station_port) = if let Some(x) = station_address { + (helpers::ipv4_to_r_efi(*x.ip()), x.port()) + } else { + (DEFAULT_ADDR, 0) + }; + let subnet_mask = helpers::ipv4_to_r_efi(crate::net::Ipv4Addr::new(255, 255, 255, 0)); let mut config_data = tcp4::ConfigData { type_of_service: TYPE_OF_SERVICE, @@ -60,7 +64,7 @@ impl Tcp4 { station_port, subnet_mask, }, - control_option: crate::ptr::null_mut(), + control_option: ptr::null_mut(), }; let r = unsafe { ((*protocol).configure)(protocol, &mut config_data) }; @@ -74,17 +78,55 @@ impl Tcp4 { let r = unsafe { ((*protocol).get_mode_data)( protocol, - crate::ptr::null_mut(), + ptr::null_mut(), &mut config_data, - crate::ptr::null_mut(), - crate::ptr::null_mut(), - crate::ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), ) }; if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(config_data) } } + pub(crate) fn accept(&self) -> io::Result { + let evt = unsafe { self.create_evt() }?; + let completion_token = + tcp4::CompletionToken { event: evt.as_ptr(), status: Status::SUCCESS }; + let mut listen_token = + tcp4::ListenToken { completion_token, new_child_handle: ptr::null_mut() }; + + let protocol = self.protocol.as_ptr(); + let r = unsafe { ((*protocol).accept)(protocol, &mut listen_token) }; + if r.is_error() { + return Err(io::Error::from_raw_os_error(r.as_usize())); + } + + unsafe { self.wait_or_cancel(None, &mut listen_token.completion_token) }?; + + if completion_token.status.is_error() { + Err(io::Error::from_raw_os_error(completion_token.status.as_usize())) + } else { + // EDK2 internals seem to assume a single ServiceBinding Protocol for TCP4 and TCP6, and + // thus does not use any service binding protocol data in destroying child sockets. It + // does seem to suggest that we need to cleanup even the protocols created by accept. To + // be on the safe side with other implementations, we will be using the same service + // binding protocol as the parent TCP4 handle. + // + // https://github.com/tianocore/edk2/blob/f80580f56b267c96f16f985dbf707b2f96947da4/NetworkPkg/TcpDxe/TcpDriver.c#L938 + + let handle = NonNull::new(listen_token.new_child_handle).unwrap(); + let protocol = helpers::open_protocol(handle, tcp4::PROTOCOL_GUID)?; + + Ok(Self { + handle, + service_binding: self.service_binding, + protocol, + flag: AtomicBool::new(false), + }) + } + } + pub(crate) fn connect(&self, timeout: Option) -> io::Result<()> { let evt = unsafe { self.create_evt() }?; let completion_token = @@ -352,6 +394,12 @@ impl Tcp4 { } } +impl Drop for Tcp4 { + fn drop(&mut self) { + let _ = unsafe { self.service_binding.destroy_child(self.handle) }; + } +} + extern "efiapi" fn toggle_atomic_flag(_: r_efi::efi::Event, ctx: *mut crate::ffi::c_void) { let flag = unsafe { AtomicBool::from_ptr(ctx.cast()) }; flag.store(true, Ordering::Relaxed); diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs index d059be010e98..8a3ed6c00c15 100644 --- a/library/std/src/sys/pal/uefi/helpers.rs +++ b/library/std/src/sys/pal/uefi/helpers.rs @@ -651,34 +651,38 @@ pub(crate) fn get_device_path_from_map(map: &Path) -> io::Result, - child_handle: NonNull, } impl ServiceProtocol { - pub(crate) fn open(service_guid: r_efi::efi::Guid) -> io::Result { + /// Open a child handle on a service_binding protocol. + pub(crate) fn open( + service_guid: r_efi::efi::Guid, + ) -> io::Result<(Self, NonNull)> { let handles = locate_handles(service_guid)?; for handle in handles { if let Ok(protocol) = open_protocol::(handle, service_guid) { - let Ok(child_handle) = Self::create_child(protocol) else { - continue; - }; - - return Ok(Self { service_guid, handle, child_handle }); + if let Ok(child_handle) = unsafe { Self::create_child(protocol) } { + return Ok((Self { service_guid, handle }, child_handle)); + } } } Err(io::const_error!(io::ErrorKind::NotFound, "no service binding protocol found")) } - pub(crate) fn child_handle(&self) -> NonNull { - self.child_handle - } - - fn create_child( + // SAFETY: sbp must be a valid service binding protocol pointer + unsafe fn create_child( sbp: NonNull, ) -> io::Result> { let mut child_handle: r_efi::efi::Handle = crate::ptr::null_mut(); @@ -692,17 +696,17 @@ impl ServiceProtocol { .ok_or(const_error!(io::ErrorKind::Other, "null child handle")) } } -} -impl Drop for ServiceProtocol { - fn drop(&mut self) { - if let Ok(sbp) = open_protocol::(self.handle, self.service_guid) - { - // SAFETY: Child handle must be allocated by the current service binding protocol. - let _ = unsafe { - ((*sbp.as_ptr()).destroy_child)(sbp.as_ptr(), self.child_handle.as_ptr()) - }; - } + // SAFETY: Child handle must be allocated by the current service binding protocol and must be + // valid. + pub(crate) unsafe fn destroy_child( + &self, + handle: NonNull, + ) -> io::Result<()> { + let sbp = open_protocol::(self.handle, self.service_guid)?; + + let r = unsafe { ((*sbp.as_ptr()).destroy_child)(sbp.as_ptr(), handle.as_ptr()) }; + if r.is_error() { Err(crate::io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } } } From 7b7ee8463f0b21e7cf2c6dc57ea8c026bc2f5829 Mon Sep 17 00:00:00 2001 From: Redddy Date: Sun, 21 Dec 2025 00:26:51 +0900 Subject: [PATCH 0038/1061] Add title field to ICE issue template --- .github/ISSUE_TEMPLATE/ice.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ISSUE_TEMPLATE/ice.md b/.github/ISSUE_TEMPLATE/ice.md index 2afcd210a6eb..1ab1ddf46016 100644 --- a/.github/ISSUE_TEMPLATE/ice.md +++ b/.github/ISSUE_TEMPLATE/ice.md @@ -2,6 +2,7 @@ name: Internal Compiler Error about: Create a report for an internal compiler error in rustc. labels: C-bug, I-ICE, T-compiler +title: "[ICE]: " --- tests/ui/new_without_default.rs:340:9 + | +LL | / pub fn new() -> Self +LL | | +LL | | where +LL | | T: Clone, +LL | | { +LL | | Self { marker: PhantomData } +LL | | } + | |_________^ + | +help: try adding this + | +LL ~ impl Default for Foo +LL + where +LL + T: Display, +LL + T: Clone, +LL + { +LL + fn default() -> Self { +LL + Self::new() +LL + } +LL + } +LL + +LL ~ impl Foo + | + +error: you should consider adding a `Default` implementation for `Bar` + --> tests/ui/new_without_default.rs:354:9 + | +LL | / pub fn new() -> Self +LL | | +LL | | where +LL | | T: Clone, +LL | | { +LL | | Self { marker: PhantomData } +LL | | } + | |_________^ + | +help: try adding this + | +LL ~ impl Default for Bar +LL + where +LL + T: Clone, +LL + { +LL + fn default() -> Self { +LL + Self::new() +LL + } +LL + } +LL + +LL ~ impl Bar { + | + +error: aborting due to 15 previous errors From 4c4b2a1dbe8692196df6f4f117c2f074b410fa81 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Sat, 20 Dec 2025 18:53:58 +0000 Subject: [PATCH 0040/1061] fix: `str_to_string` wrongly unmangled macros --- clippy_lints/src/strings.rs | 5 +++-- tests/ui/str_to_string.fixed | 14 ++++++++++++++ tests/ui/str_to_string.rs | 14 ++++++++++++++ tests/ui/str_to_string.stderr | 8 +++++++- 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 1d0efa46a14c..609504ffc233 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::res::{MaybeDef, MaybeQPath}; -use clippy_utils::source::{snippet, snippet_with_applicability}; +use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context}; use clippy_utils::{ SpanlessEq, get_expr_use_or_unification_node, get_parent_expr, is_lint_allowed, method_calls, peel_blocks, sym, }; @@ -404,7 +404,8 @@ impl<'tcx> LateLintPass<'tcx> for StrToString { "`to_string()` called on a `&str`", |diag| { let mut applicability = Applicability::MachineApplicable; - let snippet = snippet_with_applicability(cx, self_arg.span, "..", &mut applicability); + let (snippet, _) = + snippet_with_context(cx, self_arg.span, expr.span.ctxt(), "..", &mut applicability); diag.span_suggestion(expr.span, "try", format!("{snippet}.to_owned()"), applicability); }, ); diff --git a/tests/ui/str_to_string.fixed b/tests/ui/str_to_string.fixed index 2941c4dbd33d..8713c4f9bc86 100644 --- a/tests/ui/str_to_string.fixed +++ b/tests/ui/str_to_string.fixed @@ -8,3 +8,17 @@ fn main() { msg.to_owned(); //~^ str_to_string } + +fn issue16271(key: &[u8]) { + macro_rules! t { + ($e:expr) => { + match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + } + }; + } + + let _value = t!(str::from_utf8(key)).to_owned(); + //~^ str_to_string +} diff --git a/tests/ui/str_to_string.rs b/tests/ui/str_to_string.rs index 4c4d2bb18062..b81759e1037b 100644 --- a/tests/ui/str_to_string.rs +++ b/tests/ui/str_to_string.rs @@ -8,3 +8,17 @@ fn main() { msg.to_string(); //~^ str_to_string } + +fn issue16271(key: &[u8]) { + macro_rules! t { + ($e:expr) => { + match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + } + }; + } + + let _value = t!(str::from_utf8(key)).to_string(); + //~^ str_to_string +} diff --git a/tests/ui/str_to_string.stderr b/tests/ui/str_to_string.stderr index cb7b6b48843a..c0a38c8ebe46 100644 --- a/tests/ui/str_to_string.stderr +++ b/tests/ui/str_to_string.stderr @@ -13,5 +13,11 @@ error: `to_string()` called on a `&str` LL | msg.to_string(); | ^^^^^^^^^^^^^^^ help: try: `msg.to_owned()` -error: aborting due to 2 previous errors +error: `to_string()` called on a `&str` + --> tests/ui/str_to_string.rs:22:18 + | +LL | let _value = t!(str::from_utf8(key)).to_string(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t!(str::from_utf8(key)).to_owned()` + +error: aborting due to 3 previous errors From 1377de0f0e7e25ee4c4869853456694fc8639363 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Sun, 21 Dec 2025 21:20:42 +0000 Subject: [PATCH 0041/1061] fix: `bool_assert_comparison` suggests wrongly for macros --- clippy_lints/src/bool_assert_comparison.rs | 33 ++++++++++++---------- tests/ui/bool_assert_comparison.fixed | 13 +++++++++ tests/ui/bool_assert_comparison.rs | 13 +++++++++ tests/ui/bool_assert_comparison.stderr | 26 ++++++++++++++++- 4 files changed, 69 insertions(+), 16 deletions(-) diff --git a/clippy_lints/src/bool_assert_comparison.rs b/clippy_lints/src/bool_assert_comparison.rs index f31b67f470f9..165941a859f7 100644 --- a/clippy_lints/src/bool_assert_comparison.rs +++ b/clippy_lints/src/bool_assert_comparison.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node}; +use clippy_utils::source::walk_span_to_context; use clippy_utils::sugg::Sugg; use clippy_utils::sym; use clippy_utils::ty::{implements_trait, is_copy}; @@ -130,22 +131,24 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison { let mut suggestions = vec![(name_span, non_eq_mac.to_string()), (lit_span, String::new())]; - if let Some(sugg) = Sugg::hir_opt(cx, non_lit_expr) { - let sugg = if bool_value ^ eq_macro { - !sugg.maybe_paren() - } else if ty::Bool == *non_lit_ty.kind() { - sugg - } else { - !!sugg.maybe_paren() - }; - suggestions.push((non_lit_expr.span, sugg.to_string())); + let mut applicability = Applicability::MachineApplicable; + let sugg = Sugg::hir_with_context(cx, non_lit_expr, macro_call.span.ctxt(), "..", &mut applicability); + let sugg = if bool_value ^ eq_macro { + !sugg.maybe_paren() + } else if ty::Bool == *non_lit_ty.kind() { + sugg + } else { + !!sugg.maybe_paren() + }; + let non_lit_expr_span = + walk_span_to_context(non_lit_expr.span, macro_call.span.ctxt()).unwrap_or(non_lit_expr.span); + suggestions.push((non_lit_expr_span, sugg.to_string())); - diag.multipart_suggestion( - format!("replace it with `{non_eq_mac}!(..)`"), - suggestions, - Applicability::MachineApplicable, - ); - } + diag.multipart_suggestion( + format!("replace it with `{non_eq_mac}!(..)`"), + suggestions, + applicability, + ); }, ); } diff --git a/tests/ui/bool_assert_comparison.fixed b/tests/ui/bool_assert_comparison.fixed index ec76abbef05a..cd390ce0db9d 100644 --- a/tests/ui/bool_assert_comparison.fixed +++ b/tests/ui/bool_assert_comparison.fixed @@ -216,3 +216,16 @@ fn main() { assert!(!(b + b)); //~^ bool_assert_comparison } + +fn issue16279() { + macro_rules! is_empty { + ($x:expr) => { + $x.is_empty() + }; + } + + assert!(!is_empty!("a")); + //~^ bool_assert_comparison + assert!(is_empty!("")); + //~^ bool_assert_comparison +} diff --git a/tests/ui/bool_assert_comparison.rs b/tests/ui/bool_assert_comparison.rs index 40824a23c82e..b2ea5b6ea540 100644 --- a/tests/ui/bool_assert_comparison.rs +++ b/tests/ui/bool_assert_comparison.rs @@ -216,3 +216,16 @@ fn main() { assert_eq!(b + b, false); //~^ bool_assert_comparison } + +fn issue16279() { + macro_rules! is_empty { + ($x:expr) => { + $x.is_empty() + }; + } + + assert_eq!(is_empty!("a"), false); + //~^ bool_assert_comparison + assert_eq!(is_empty!(""), true); + //~^ bool_assert_comparison +} diff --git a/tests/ui/bool_assert_comparison.stderr b/tests/ui/bool_assert_comparison.stderr index 72aa6303a202..b4e8fcf09bb6 100644 --- a/tests/ui/bool_assert_comparison.stderr +++ b/tests/ui/bool_assert_comparison.stderr @@ -444,5 +444,29 @@ LL - assert_eq!(b + b, false); LL + assert!(!(b + b)); | -error: aborting due to 37 previous errors +error: used `assert_eq!` with a literal bool + --> tests/ui/bool_assert_comparison.rs:227:5 + | +LL | assert_eq!(is_empty!("a"), false); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert!(..)` + | +LL - assert_eq!(is_empty!("a"), false); +LL + assert!(!is_empty!("a")); + | + +error: used `assert_eq!` with a literal bool + --> tests/ui/bool_assert_comparison.rs:229:5 + | +LL | assert_eq!(is_empty!(""), true); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert!(..)` + | +LL - assert_eq!(is_empty!(""), true); +LL + assert!(is_empty!("")); + | + +error: aborting due to 39 previous errors From a8e5693797b42df429929d372179567035d5e1a0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Dec 2025 13:29:11 +0100 Subject: [PATCH 0042/1061] split up tracking issue for target feature feature gates --- compiler/rustc_feature/src/unstable.rs | 81 +++++++++++---------- library/std_detect/src/detect/arch/s390x.rs | 24 +++--- tests/ui/target-feature/gate.stderr | 2 +- 3 files changed, 57 insertions(+), 50 deletions(-) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 692cba8035c4..072543871e31 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -319,47 +319,14 @@ declare_features! ( // feature-group-end: internal feature gates // ------------------------------------------------------------------------- - // ------------------------------------------------------------------------- - // feature-group-start: actual feature gates (target features) - // ------------------------------------------------------------------------- - - // FIXME: Document these and merge with the list below. - - // Unstable `#[target_feature]` directives. - (unstable, aarch64_unstable_target_feature, "1.82.0", Some(44839)), - (unstable, aarch64_ver_target_feature, "1.27.0", Some(44839)), - (unstable, apx_target_feature, "1.88.0", Some(139284)), - (unstable, arm_target_feature, "1.27.0", Some(44839)), - (unstable, bpf_target_feature, "1.54.0", Some(44839)), - (unstable, csky_target_feature, "1.73.0", Some(44839)), - (unstable, ermsb_target_feature, "1.49.0", Some(44839)), - (unstable, hexagon_target_feature, "1.27.0", Some(44839)), - (unstable, lahfsahf_target_feature, "1.78.0", Some(44839)), - (unstable, loongarch_target_feature, "1.73.0", Some(44839)), - (unstable, m68k_target_feature, "1.85.0", Some(134328)), - (unstable, mips_target_feature, "1.27.0", Some(44839)), - (unstable, movrs_target_feature, "1.88.0", Some(137976)), - (unstable, nvptx_target_feature, "1.91.0", Some(44839)), - (unstable, powerpc_target_feature, "1.27.0", Some(44839)), - (unstable, prfchw_target_feature, "1.78.0", Some(44839)), - (unstable, riscv_target_feature, "1.45.0", Some(44839)), - (unstable, rtm_target_feature, "1.35.0", Some(44839)), - (unstable, s390x_target_feature, "1.82.0", Some(44839)), - (unstable, sparc_target_feature, "1.84.0", Some(132783)), - (unstable, wasm_target_feature, "1.30.0", Some(44839)), - (unstable, x87_target_feature, "1.85.0", Some(44839)), - // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! - // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way. - // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! - - // ------------------------------------------------------------------------- - // feature-group-end: actual feature gates (target features) - // ------------------------------------------------------------------------- - // ------------------------------------------------------------------------- // feature-group-start: actual feature gates // ------------------------------------------------------------------------- + /// The remaining unstable target features on aarch64. + (unstable, aarch64_unstable_target_feature, "1.82.0", Some(150244)), + /// Instruction set "version" target features on aarch64. + (unstable, aarch64_ver_target_feature, "1.27.0", Some(150245)), /// Allows `extern "avr-interrupt" fn()` and `extern "avr-non-blocking-interrupt" fn()`. (unstable, abi_avr_interrupt, "1.45.0", Some(69664)), /// Allows `extern "cmse-nonsecure-call" fn()`. @@ -380,10 +347,14 @@ declare_features! ( (unstable, adt_const_params, "1.56.0", Some(95174)), /// Allows defining an `#[alloc_error_handler]`. (unstable, alloc_error_handler, "1.29.0", Some(51540)), + /// The `apxf` target feature on x86 + (unstable, apx_target_feature, "1.88.0", Some(139284)), /// Allows inherent and trait methods with arbitrary self types. (unstable, arbitrary_self_types, "1.23.0", Some(44874)), /// Allows inherent and trait methods with arbitrary self types that are raw pointers. (unstable, arbitrary_self_types_pointers, "1.83.0", Some(44874)), + /// Target features on arm. + (unstable, arm_target_feature, "1.27.0", Some(150246)), /// Enables experimental inline assembly support for additional architectures. (unstable, asm_experimental_arch, "1.58.0", Some(93335)), /// Enables experimental register support in inline assembly. @@ -408,6 +379,8 @@ declare_features! ( (unstable, async_trait_bounds, "1.85.0", Some(62290)), /// Allows using Intel AVX10 target features and intrinsics (unstable, avx10_target_feature, "1.88.0", Some(138843)), + /// Target features on bpf. + (unstable, bpf_target_feature, "1.54.0", Some(150247)), /// Allows using C-variadics. (unstable, c_variadic, "1.34.0", Some(44930)), /// Allows defining c-variadic naked functions with any extern ABI that is allowed @@ -468,6 +441,8 @@ declare_features! ( /// Allows function attribute `#[coverage(on/off)]`, to control coverage /// instrumentation of that function. (unstable, coverage_attribute, "1.74.0", Some(84605)), + /// Target features on csky. + (unstable, csky_target_feature, "1.73.0", Some(150248)), /// Allows non-builtin attributes in inner attribute position. (unstable, custom_inner_attributes, "1.30.0", Some(54726)), /// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`. @@ -495,6 +470,8 @@ declare_features! ( (incomplete, effective_target_features, "1.91.0", Some(143352)), /// Allows the .use postfix syntax `x.use` and use closures `use |x| { ... }` (incomplete, ergonomic_clones, "1.87.0", Some(132290)), + /// ermsb target feature on x86. + (unstable, ermsb_target_feature, "1.49.0", Some(150249)), /// Allows exhaustive pattern matching on types that contain uninhabited types. (unstable, exhaustive_patterns, "1.13.0", Some(51085)), /// Disallows `extern` without an explicit ABI. @@ -541,6 +518,8 @@ declare_features! ( (incomplete, guard_patterns, "1.85.0", Some(129967)), /// Allows using `..=X` as a patterns in slices. (unstable, half_open_range_patterns_in_slices, "1.66.0", Some(67264)), + /// Target features on hexagon. + (unstable, hexagon_target_feature, "1.27.0", Some(150250)), /// Allows `if let` guard in match arms. (unstable, if_let_guard, "1.47.0", Some(51114)), /// Allows `impl Trait` to be used inside associated types (RFC 2515). @@ -555,6 +534,8 @@ declare_features! ( (incomplete, inherent_associated_types, "1.52.0", Some(8995)), /// Allows using `pointer` and `reference` in intra-doc links (unstable, intra_doc_pointers, "1.51.0", Some(80896)), + /// lahfsahf target feature on x86. + (unstable, lahfsahf_target_feature, "1.78.0", Some(150251)), /// Allows setting the threshold for the `large_assignments` lint. (unstable, large_assignments, "1.52.0", Some(83518)), /// Allow to have type alias types for inter-crate use. @@ -562,8 +543,12 @@ declare_features! ( /// Allows using `#[link(kind = "link-arg", name = "...")]` /// to pass custom arguments to the linker. (unstable, link_arg_attribute, "1.76.0", Some(99427)), + /// Target features on loongarch. + (unstable, loongarch_target_feature, "1.73.0", Some(150252)), /// Allows fused `loop`/`match` for direct intraprocedural jumps. (incomplete, loop_match, "1.90.0", Some(132306)), + /// Target features on m68k. + (unstable, m68k_target_feature, "1.85.0", Some(134328)), /// Allow `macro_rules!` attribute rules (unstable, macro_attr, "1.91.0", Some(143547)), /// Allow `macro_rules!` derive rules @@ -580,8 +565,12 @@ declare_features! ( /// standard library until the soundness issues with specialization /// are fixed. (unstable, min_specialization, "1.7.0", Some(31844)), + /// Target features on mips. + (unstable, mips_target_feature, "1.27.0", Some(150253)), /// Allows qualified paths in struct expressions, struct patterns and tuple struct patterns. (unstable, more_qualified_paths, "1.54.0", Some(86935)), + /// The `movrs` target feature on x86. + (unstable, movrs_target_feature, "1.88.0", Some(137976)), /// Allows the `#[must_not_suspend]` attribute. (unstable, must_not_suspend, "1.57.0", Some(83310)), /// Allows `mut ref` and `mut ref mut` identifier patterns. @@ -606,6 +595,8 @@ declare_features! ( (unstable, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554)), /// Allows `for` binders in where-clauses (incomplete, non_lifetime_binders, "1.69.0", Some(108185)), + /// Target feaures on nvptx. + (unstable, nvptx_target_feature, "1.91.0", Some(150254)), /// Allows using enums in offset_of! (unstable, offset_of_enum, "1.75.0", Some(120141)), /// Allows using fields with slice type in offset_of! @@ -618,6 +609,10 @@ declare_features! ( (incomplete, pin_ergonomics, "1.83.0", Some(130494)), /// Allows postfix match `expr.match { ... }` (unstable, postfix_match, "1.79.0", Some(121618)), + /// Target features on powerpc. + (unstable, powerpc_target_feature, "1.27.0", Some(150255)), + /// The prfchw target feature on x86. + (unstable, prfchw_target_feature, "1.78.0", Some(150256)), /// Allows macro attributes on expressions, statements and non-inline modules. (unstable, proc_macro_hygiene, "1.30.0", Some(54727)), /// Allows the use of raw-dylibs on ELF platforms @@ -633,12 +628,20 @@ declare_features! ( (unstable, repr_simd, "1.4.0", Some(27731)), /// Allows bounding the return type of AFIT/RPITIT. (unstable, return_type_notation, "1.70.0", Some(109417)), + /// Target features on riscv. + (unstable, riscv_target_feature, "1.45.0", Some(150257)), + /// The rtm target feature on x86. + (unstable, rtm_target_feature, "1.35.0", Some(150258)), /// Allows `extern "rust-cold"`. (unstable, rust_cold_cc, "1.63.0", Some(97544)), + /// Target features on s390x. + (unstable, s390x_target_feature, "1.82.0", Some(150259)), /// Allows the use of the `sanitize` attribute. (unstable, sanitize, "1.91.0", Some(39699)), /// Allows the use of SIMD types in functions declared in `extern` blocks. (unstable, simd_ffi, "1.0.0", Some(27731)), + /// Target features on sparc. + (unstable, sparc_target_feature, "1.84.0", Some(132783)), /// Allows specialization of implementations (RFC 1210). (incomplete, specialization, "1.7.0", Some(31844)), /// Allows using `#[rustc_align_static(...)]` on static items. @@ -685,10 +688,14 @@ declare_features! ( (internal, unsized_fn_params, "1.49.0", Some(48055)), /// Allows using the `#[used(linker)]` (or `#[used(compiler)]`) attribute. (unstable, used_with_arg, "1.60.0", Some(93798)), + /// Target features on wasm. + (unstable, wasm_target_feature, "1.30.0", Some(150260)), /// Allows use of attributes in `where` clauses. (unstable, where_clause_attrs, "1.87.0", Some(115590)), /// Allows use of x86 `AMX` target-feature attributes and intrinsics (unstable, x86_amx_intrinsics, "1.81.0", Some(126622)), + /// The x87 target feature on x86. + (unstable, x87_target_feature, "1.85.0", Some(150261)), /// Allows use of the `xop` target-feature (unstable, xop_target_feature, "1.81.0", Some(127208)), /// Allows `do yeet` expressions diff --git a/library/std_detect/src/detect/arch/s390x.rs b/library/std_detect/src/detect/arch/s390x.rs index a04283f90a02..63f7390d5ae3 100644 --- a/library/std_detect/src/detect/arch/s390x.rs +++ b/library/std_detect/src/detect/arch/s390x.rs @@ -10,27 +10,27 @@ features! { /// When the feature is known to be enabled at compile time (e.g. via `-Ctarget-feature`) /// the macro expands to `true`. #[stable(feature = "stdarch_s390x_feature_detection", since = "1.93.0")] - @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "44839")] concurrent_functions: "concurrent-functions"; + @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "150259")] concurrent_functions: "concurrent-functions"; /// s390x concurrent-functions facility - @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "44839")] deflate_conversion: "deflate-conversion"; + @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "150259")] deflate_conversion: "deflate-conversion"; /// s390x deflate-conversion facility - @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "44839")] enhanced_sort: "enhanced-sort"; + @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "150259")] enhanced_sort: "enhanced-sort"; /// s390x enhanced-sort facility - @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "44839")] guarded_storage: "guarded-storage"; + @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "150259")] guarded_storage: "guarded-storage"; /// s390x guarded-storage facility - @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "44839")] high_word: "high-word"; + @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "150259")] high_word: "high-word"; /// s390x high-word facility - @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "44839")] message_security_assist_extension3: "message-security-assist-extension3"; + @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "150259")] message_security_assist_extension3: "message-security-assist-extension3"; /// s390x message-security-assist-extension3 facility - @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "44839")] message_security_assist_extension4: "message-security-assist-extension4"; + @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "150259")] message_security_assist_extension4: "message-security-assist-extension4"; /// s390x message-security-assist-extension4 facility - @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "44839")] message_security_assist_extension5: "message-security-assist-extension5"; + @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "150259")] message_security_assist_extension5: "message-security-assist-extension5"; /// s390x message-security-assist-extension5 facility - @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "44839")] message_security_assist_extension8: "message-security-assist-extension8"; + @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "150259")] message_security_assist_extension8: "message-security-assist-extension8"; /// s390x message-security-assist-extension8 facility - @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "44839")] message_security_assist_extension9: "message-security-assist-extension9"; + @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "150259")] message_security_assist_extension9: "message-security-assist-extension9"; /// s390x message-security-assist-extension9 facility - @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "44839")] message_security_assist_extension12: "message-security-assist-extension12"; + @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "150259")] message_security_assist_extension12: "message-security-assist-extension12"; /// s390x message-security-assist-extension12 facility @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "1.93.0")] miscellaneous_extensions_2: "miscellaneous-extensions-2"; /// s390x miscellaneous-extensions-2 facility @@ -40,7 +40,7 @@ features! { /// s390x miscellaneous-extensions-4 facility @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "1.93.0")] nnp_assist: "nnp-assist"; /// s390x nnp-assist facility - @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "44839")] transactional_execution: "transactional-execution"; + @FEATURE: #[unstable(feature = "s390x_target_feature", issue = "150259")] transactional_execution: "transactional-execution"; /// s390x transactional-execution facility @FEATURE: #[stable(feature = "s390x_target_feature_vector", since = "1.93.0")] vector: "vector"; /// s390x vector facility diff --git a/tests/ui/target-feature/gate.stderr b/tests/ui/target-feature/gate.stderr index 345dc2006d0b..67df09fd369e 100644 --- a/tests/ui/target-feature/gate.stderr +++ b/tests/ui/target-feature/gate.stderr @@ -4,7 +4,7 @@ error[E0658]: the target feature `x87` is currently unstable LL | #[target_feature(enable = "x87")] | ^^^^^^^^^^^^^^ | - = note: see issue #44839 for more information + = note: see issue #150261 for more information = help: add `#![feature(x87_target_feature)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date From 22996d69599b39f5bbad9f1b85aaa7e9d1f3990f Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Mon, 22 Dec 2025 14:55:44 +0100 Subject: [PATCH 0043/1061] Remove inactive nvptx maintainer --- src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md b/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md index 36598982481b..56caf531a92e 100644 --- a/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md +++ b/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md @@ -7,7 +7,6 @@ platform. ## Target maintainers -[@RDambrosio016](https://github.com/RDambrosio016) [@kjetilkjeka](https://github.com/kjetilkjeka) ## Requirements From 27be5c2f682567a8825d6b50a04feda8f74ccf39 Mon Sep 17 00:00:00 2001 From: Soroush Mirzaei Date: Mon, 22 Dec 2025 10:14:57 -0500 Subject: [PATCH 0044/1061] docs(core): update `find()` and `rfind()` examples `find()` has a missing example. In the docs there was a mention of an example with double reference but it didn't exist. `rfind()` is also very similar to `find()`, however it had the double reference example and no owned value example like `find()` did. This commit adds the missing examples and making them look consistent. --- library/core/src/iter/traits/double_ended.rs | 12 +++++++++++- library/core/src/iter/traits/iterator.rs | 11 +++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index 7dabaece9556..da0b05063657 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -334,8 +334,18 @@ pub trait DoubleEndedIterator: Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// assert_eq!(a.iter().rfind(|&&x| x == 2), Some(&2)); + /// assert_eq!(a.into_iter().rfind(|&x| x == 2), Some(2)); + /// assert_eq!(a.into_iter().rfind(|&x| x == 5), None); + /// ``` /// + /// Iterating over references: + /// + /// ``` + /// let a = [1, 2, 3]; + /// + /// // `iter()` yields references i.e. `&i32` and `rfind()` takes a + /// // reference to each element. + /// assert_eq!(a.iter().rfind(|&&x| x == 2), Some(&2)); /// assert_eq!(a.iter().rfind(|&&x| x == 5), None); /// ``` /// diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 29230b166538..d99afbc6036d 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -2858,6 +2858,17 @@ pub trait Iterator { /// assert_eq!(a.into_iter().find(|&x| x == 5), None); /// ``` /// + /// Iterating over references: + /// + /// ``` + /// let a = [1, 2, 3]; + /// + /// // `iter()` yields references i.e. `&i32` and `find()` takes a + /// // reference to each element. + /// assert_eq!(a.iter().find(|&&x| x == 2), Some(&2)); + /// assert_eq!(a.iter().find(|&&x| x == 5), None); + /// ``` + /// /// Stopping at the first `true`: /// /// ``` From 7afba2977d0d8a2a2148cbdc244a86258bb5d328 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Tue, 9 Dec 2025 09:49:50 +0100 Subject: [PATCH 0045/1061] Make attr path symbols rather than idents --- compiler/rustc_ast/src/attr/mod.rs | 42 +++++++++---------- compiler/rustc_ast_passes/src/feature_gate.rs | 2 +- .../rustc_attr_parsing/src/attributes/cfg.rs | 8 +--- .../src/attributes/cfg_select.rs | 7 +--- .../rustc_attr_parsing/src/attributes/util.rs | 3 +- compiler/rustc_attr_parsing/src/parser.rs | 2 +- compiler/rustc_attr_parsing/src/safety.rs | 2 +- .../rustc_attr_parsing/src/target_checking.rs | 2 +- .../rustc_attr_parsing/src/validate_attr.rs | 2 +- compiler/rustc_builtin_macros/src/cfg.rs | 4 +- compiler/rustc_builtin_macros/src/cfg_eval.rs | 5 +-- .../rustc_codegen_ssa/src/codegen_attrs.rs | 4 +- compiler/rustc_expand/src/expand.rs | 4 +- compiler/rustc_hir/src/hir.rs | 33 ++++++++------- compiler/rustc_hir_pretty/src/lib.rs | 8 +++- .../rustc_parse/src/parser/attr_wrapper.rs | 12 +++--- compiler/rustc_passes/src/check_attr.rs | 4 +- .../src/ich/impls_syntax.rs | 2 +- src/librustdoc/clean/cfg.rs | 4 +- src/librustdoc/clean/mod.rs | 4 +- src/librustdoc/passes/propagate_doc_cfg.rs | 4 +- .../src/attrs/allow_attributes.rs | 7 ++-- .../clippy/clippy_lints/src/attrs/mod.rs | 12 +++--- .../src/attrs/useless_attribute.rs | 2 +- .../clippy_lints/src/incompatible_msrv.rs | 2 +- .../clippy/clippy_lints/src/missing_doc.rs | 4 +- src/tools/clippy/clippy_utils/src/attrs.rs | 17 ++++---- .../clippy_utils/src/check_proc_macro.rs | 4 +- .../tests/ui/renamed_builtin_attr.stderr | 4 +- .../clippy/tests/ui/unknown_attribute.stderr | 4 +- src/tools/rustfmt/src/attr.rs | 4 +- 31 files changed, 103 insertions(+), 115 deletions(-) diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index c53188a22aed..c0ed6e24e222 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -96,11 +96,11 @@ impl AttributeExt for Attribute { } /// For a single-segment attribute, returns its name; otherwise, returns `None`. - fn ident(&self) -> Option { + fn name(&self) -> Option { match &self.kind { AttrKind::Normal(normal) => { if let [ident] = &*normal.item.path.segments { - Some(ident.ident) + Some(ident.ident.name) } else { None } @@ -109,9 +109,18 @@ impl AttributeExt for Attribute { } } - fn ident_path(&self) -> Option> { + fn symbol_path(&self) -> Option> { match &self.kind { - AttrKind::Normal(p) => Some(p.item.path.segments.iter().map(|i| i.ident).collect()), + AttrKind::Normal(p) => { + Some(p.item.path.segments.iter().map(|i| i.ident.name).collect()) + } + AttrKind::DocComment(_, _) => None, + } + } + + fn path_span(&self) -> Option { + match &self.kind { + AttrKind::Normal(attr) => Some(attr.item.path.span), AttrKind::DocComment(_, _) => None, } } @@ -794,9 +803,7 @@ pub trait AttributeExt: Debug { /// For a single-segment attribute (i.e., `#[attr]` and not `#[path::atrr]`), /// return the name of the attribute; otherwise, returns `None`. - fn name(&self) -> Option { - self.ident().map(|ident| ident.name) - } + fn name(&self) -> Option; /// Get the meta item list, `#[attr(meta item list)]` fn meta_item_list(&self) -> Option>; @@ -807,9 +814,6 @@ pub trait AttributeExt: Debug { /// Gets the span of the value literal, as string, when using `#[attr = value]` fn value_span(&self) -> Option; - /// For a single-segment attribute, returns its ident; otherwise, returns `None`. - fn ident(&self) -> Option; - /// Checks whether the path of this attribute matches the name. /// /// Matches one segment of the path to each element in `name` @@ -822,7 +826,7 @@ pub trait AttributeExt: Debug { #[inline] fn has_name(&self, name: Symbol) -> bool { - self.ident().map(|x| x.name == name).unwrap_or(false) + self.name().map(|x| x == name).unwrap_or(false) } #[inline] @@ -836,13 +840,13 @@ pub trait AttributeExt: Debug { fn is_word(&self) -> bool; fn path(&self) -> SmallVec<[Symbol; 1]> { - self.ident_path() - .map(|i| i.into_iter().map(|i| i.name).collect()) - .unwrap_or(smallvec![sym::doc]) + self.symbol_path().unwrap_or(smallvec![sym::doc]) } + fn path_span(&self) -> Option; + /// Returns None for doc comments - fn ident_path(&self) -> Option>; + fn symbol_path(&self) -> Option>; /// Returns the documentation if this is a doc comment or a sugared doc comment. /// * `///doc` returns `Some("doc")`. @@ -903,10 +907,6 @@ impl Attribute { AttributeExt::value_span(self) } - pub fn ident(&self) -> Option { - AttributeExt::ident(self) - } - pub fn path_matches(&self, name: &[Symbol]) -> bool { AttributeExt::path_matches(self, name) } @@ -938,10 +938,6 @@ impl Attribute { AttributeExt::path(self) } - pub fn ident_path(&self) -> Option> { - AttributeExt::ident_path(self) - } - pub fn doc_str(&self) -> Option { AttributeExt::doc_str(self) } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index dbbd3906b525..26eb8051df37 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -160,7 +160,7 @@ impl<'a> PostExpansionVisitor<'a> { impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_attribute(&mut self, attr: &ast::Attribute) { - let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); + let attr_info = attr.name().and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name)); // Check feature gates for built-in attributes. if let Some(BuiltinAttribute { gate: AttributeGate::Gated { feature, message, check, notes, .. }, diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 798cc1076541..66f0f8d391f6 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -371,13 +371,7 @@ fn parse_cfg_attr_internal<'a>( attribute.span, attribute.get_normal_item().span(), attribute.style, - AttrPath { - segments: attribute - .ident_path() - .expect("cfg_attr is not a doc comment") - .into_boxed_slice(), - span: attribute.span, - }, + AttrPath { segments: attribute.path().into_boxed_slice(), span: attribute.span }, Some(attribute.get_normal_item().unsafety), ParsedDescription::Attribute, pred_span, diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs index 00a2d12106e7..24b989e22a2b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs @@ -7,7 +7,7 @@ use rustc_hir::attrs::CfgEntry; use rustc_parse::exp; use rustc_parse::parser::Parser; use rustc_session::Session; -use rustc_span::{ErrorGuaranteed, Ident, Span}; +use rustc_span::{ErrorGuaranteed, Span, sym}; use crate::parser::MetaItemOrLitParser; use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry}; @@ -86,10 +86,7 @@ pub fn parse_cfg_select( cfg_span, cfg_span, AttrStyle::Inner, - AttrPath { - segments: vec![Ident::from_str("cfg_select")].into_boxed_slice(), - span: cfg_span, - }, + AttrPath { segments: vec![sym::cfg_select].into_boxed_slice(), span: cfg_span }, None, ParsedDescription::Macro, cfg_span, diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs index 431ba539b2ba..ebec8e8443fc 100644 --- a/compiler/rustc_attr_parsing/src/attributes/util.rs +++ b/compiler/rustc_attr_parsing/src/attributes/util.rs @@ -28,8 +28,7 @@ pub fn parse_version(s: Symbol) -> Option { } pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool { - attr.is_doc_comment().is_some() - || attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name)) + attr.is_doc_comment().is_some() || attr.name().is_some_and(|name| is_builtin_attr_name(name)) } /// Parse a single integer. diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 9551744d5ec5..9c0fbe92d71b 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -34,7 +34,7 @@ pub type RefPathParser<'p> = PathParser<&'p Path>; impl> PathParser

{ pub fn get_attribute_path(&self) -> hir::AttrPath { AttrPath { - segments: self.segments().copied().collect::>().into_boxed_slice(), + segments: self.segments().map(|s| s.name).collect::>().into_boxed_slice(), span: self.span(), } } diff --git a/compiler/rustc_attr_parsing/src/safety.rs b/compiler/rustc_attr_parsing/src/safety.rs index 817785108a1e..68aeca2bbda9 100644 --- a/compiler/rustc_attr_parsing/src/safety.rs +++ b/compiler/rustc_attr_parsing/src/safety.rs @@ -22,7 +22,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { return; } - let name = (attr_path.segments.len() == 1).then_some(attr_path.segments[0].name); + let name = (attr_path.segments.len() == 1).then_some(attr_path.segments[0]); if let Some(name) = name && [sym::cfg_trace, sym::cfg_attr_trace].contains(&name) { diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index 88efb910c160..e86ecb451fc2 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -104,7 +104,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { let (applied, only) = allowed_targets_applied(allowed_targets, target, cx.features); let name = cx.attr_path.clone(); - let lint = if name.segments[0].name == sym::deprecated + let lint = if name.segments[0] == sym::deprecated && ![ Target::Closure, Target::Expression, diff --git a/compiler/rustc_attr_parsing/src/validate_attr.rs b/compiler/rustc_attr_parsing/src/validate_attr.rs index e69ed0eea6b0..4879646a1107 100644 --- a/compiler/rustc_attr_parsing/src/validate_attr.rs +++ b/compiler/rustc_attr_parsing/src/validate_attr.rs @@ -27,7 +27,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) { return; } - let builtin_attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); + let builtin_attr_info = attr.name().and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name)); // Check input tokens for built-in and key-value attributes. match builtin_attr_info { diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 7bc9080ba022..557daa94b98e 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -13,7 +13,7 @@ use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpa use rustc_hir::AttrPath; use rustc_hir::attrs::CfgEntry; use rustc_parse::exp; -use rustc_span::{ErrorGuaranteed, Ident, Span}; +use rustc_span::{ErrorGuaranteed, Span, sym}; use crate::errors; @@ -47,7 +47,7 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result bool { impl<'ast> visit::Visitor<'ast> for CfgFinder { type Result = ControlFlow<()>; fn visit_attribute(&mut self, attr: &'ast Attribute) -> ControlFlow<()> { - if attr - .ident() - .is_some_and(|ident| ident.name == sym::cfg || ident.name == sym::cfg_attr) - { + if attr.name().is_some_and(|name| name == sym::cfg || name == sym::cfg_attr) { ControlFlow::Break(()) } else { ControlFlow::Continue(()) diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 8135fd43dd93..93043c69579a 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -18,7 +18,7 @@ use rustc_middle::span_bug; use rustc_middle::ty::{self as ty, Instance, TyCtxt}; use rustc_session::lint; use rustc_session::parse::feature_err; -use rustc_span::{Ident, Span, Symbol, sym}; +use rustc_span::{Span, Symbol, sym}; use rustc_target::spec::Os; use crate::errors; @@ -357,7 +357,7 @@ fn process_builtin_attrs( } } - let Some(Ident { name, .. }) = attr.ident() else { + let Some(name) = attr.name() else { continue; }; diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 6422779e13c9..52b7339e0140 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -2110,7 +2110,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { let mut attr_pos = None; for (pos, attr) in item.attrs().iter().enumerate() { if !attr.is_doc_comment() && !self.cx.expanded_inert_attrs.is_marked(attr) { - let name = attr.ident().map(|ident| ident.name); + let name = attr.name(); if name == Some(sym::cfg) || name == Some(sym::cfg_attr) { cfg_pos = Some(pos); // a cfg attr found, no need to search anymore break; @@ -2187,7 +2187,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } else if rustc_attr_parsing::is_builtin_attr(attr) && !AttributeParser::::is_parsed_attribute(&attr.path()) { - let attr_name = attr.ident().unwrap().name; + let attr_name = attr.name().unwrap(); // `#[cfg]` and `#[cfg_attr]` are special - they are // eagerly evaluated. if attr_name != sym::cfg_trace && attr_name != sym::cfg_attr_trace { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index c60471848c89..483e864f69d4 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1182,7 +1182,7 @@ pub enum AttrArgs { #[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)] pub struct AttrPath { - pub segments: Box<[Ident]>, + pub segments: Box<[Symbol]>, pub span: Span, } @@ -1198,7 +1198,7 @@ impl AttrPath { segments: path .segments .iter() - .map(|i| Ident { name: i.ident.name, span: lower_span(i.ident.span) }) + .map(|i| i.ident.name) .collect::>() .into_boxed_slice(), span: lower_span(path.span), @@ -1208,7 +1208,11 @@ impl AttrPath { impl fmt::Display for AttrPath { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", join_path_idents(&self.segments)) + write!( + f, + "{}", + join_path_idents(self.segments.iter().map(|i| Ident { name: *i, span: DUMMY_SP })) + ) } } @@ -1313,7 +1317,7 @@ impl AttributeExt for Attribute { /// For a single-segment attribute, returns its name; otherwise, returns `None`. #[inline] - fn ident(&self) -> Option { + fn name(&self) -> Option { match &self { Attribute::Unparsed(n) => { if let [ident] = n.path.segments.as_ref() { @@ -1329,7 +1333,7 @@ impl AttributeExt for Attribute { #[inline] fn path_matches(&self, name: &[Symbol]) -> bool { match &self { - Attribute::Unparsed(n) => n.path.segments.iter().map(|ident| &ident.name).eq(name), + Attribute::Unparsed(n) => n.path.segments.iter().eq(name), _ => false, } } @@ -1365,13 +1369,20 @@ impl AttributeExt for Attribute { } #[inline] - fn ident_path(&self) -> Option> { + fn symbol_path(&self) -> Option> { match &self { Attribute::Unparsed(n) => Some(n.path.segments.iter().copied().collect()), _ => None, } } + fn path_span(&self) -> Option { + match &self { + Attribute::Unparsed(attr) => Some(attr.path.span), + Attribute::Parsed(_) => None, + } + } + #[inline] fn doc_str(&self) -> Option { match &self { @@ -1451,11 +1462,6 @@ impl Attribute { AttributeExt::value_span(self) } - #[inline] - pub fn ident(&self) -> Option { - AttributeExt::ident(self) - } - #[inline] pub fn path_matches(&self, name: &[Symbol]) -> bool { AttributeExt::path_matches(self, name) @@ -1491,11 +1497,6 @@ impl Attribute { AttributeExt::path(self) } - #[inline] - pub fn ident_path(&self) -> Option> { - AttributeExt::ident_path(self) - } - #[inline] pub fn doc_str(&self) -> Option { AttributeExt::doc_str(self) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index b3b416955230..80e8bcb9a93a 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -22,7 +22,7 @@ use rustc_hir::{ TyPatKind, }; use rustc_span::source_map::SourceMap; -use rustc_span::{FileName, Ident, Span, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, FileName, Ident, Span, Symbol, kw, sym}; use {rustc_ast as ast, rustc_hir as hir}; pub fn id_to_string(cx: &dyn rustc_hir::intravisit::HirTyCtxt<'_>, hir_id: HirId) -> String { @@ -136,7 +136,11 @@ impl<'a> State<'a> { .path .segments .iter() - .map(|i| ast::PathSegment { ident: *i, args: None, id: DUMMY_NODE_ID }) + .map(|i| ast::PathSegment { + ident: Ident { name: *i, span: DUMMY_SP }, + args: None, + id: DUMMY_NODE_ID, + }) .collect(), tokens: None, }; diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 44fdf146f9c7..e04178645fdd 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -86,9 +86,9 @@ fn has_cfg_or_cfg_attr(attrs: &[Attribute]) -> bool { // NOTE: Builtin attributes like `cfg` and `cfg_attr` cannot be renamed via imports. // Therefore, the absence of a literal `cfg` or `cfg_attr` guarantees that // we don't need to do any eager expansion. - attrs.iter().any(|attr| { - attr.ident().is_some_and(|ident| ident.name == sym::cfg || ident.name == sym::cfg_attr) - }) + attrs + .iter() + .any(|attr| attr.name().is_some_and(|ident| ident == sym::cfg || ident == sym::cfg_attr)) } impl<'a> Parser<'a> { @@ -398,10 +398,8 @@ impl<'a> Parser<'a> { /// - any single-segment, non-builtin attributes are present, e.g. `derive`, /// `test`, `global_allocator`. fn needs_tokens(attrs: &[ast::Attribute]) -> bool { - attrs.iter().any(|attr| match attr.ident() { + attrs.iter().any(|attr| match attr.name() { None => !attr.is_doc_comment(), - Some(ident) => { - ident.name == sym::cfg_attr || !rustc_feature::is_builtin_attr_name(ident.name) - } + Some(name) => name == sym::cfg_attr || !rustc_feature::is_builtin_attr_name(name), }) } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 7822614a05cb..eb551201b083 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -388,7 +388,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { attr.path .segments .first() - .and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)) + .and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name)) { match attr.style { ast::AttrStyle::Outer => { @@ -425,7 +425,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if let Attribute::Unparsed(unparsed_attr) = attr && let Some(BuiltinAttribute { duplicates, .. }) = - attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)) + attr.name().and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name)) { check_duplicates( self.tcx, diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs index 118229ffc990..fe6fb3d65194 100644 --- a/compiler/rustc_query_system/src/ich/impls_syntax.rs +++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs @@ -24,7 +24,7 @@ impl<'a> HashStable> for [hir::Attribute] { .filter(|attr| { attr.is_doc_comment().is_none() // FIXME(jdonszelmann) have a better way to handle ignored attrs - && !attr.ident().is_some_and(|ident| hcx.is_ignored_attr(ident.name)) + && !attr.name().is_some_and(|ident| hcx.is_ignored_attr(ident)) }) .collect(); diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 7ab2a72d75b5..61ebc73182c0 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -859,8 +859,8 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator } continue; } else if !cfg_info.parent_is_doc_cfg - && let Some(ident) = attr.ident() - && matches!(ident.name, sym::cfg | sym::cfg_trace) + && let Some(name) = attr.name() + && matches!(name, sym::cfg | sym::cfg_trace) && let Some(attr) = single(attr.meta_item_list()?) && let Ok(new_cfg) = Cfg::parse(&attr) { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 764b3a0acdb6..72996cc4f21e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2673,8 +2673,8 @@ fn add_without_unwanted_attributes<'hir>( import_parent, )); } - hir::Attribute::Unparsed(normal) if let [ident] = &*normal.path.segments => { - if is_inline || ident.name != sym::cfg_trace { + hir::Attribute::Unparsed(normal) if let [name] = &*normal.path.segments => { + if is_inline || *name != sym::cfg_trace { // If it's not a `cfg()` attribute, we keep it. attrs.push((Cow::Borrowed(attr), import_parent)); } diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index 95f5537f394c..d4bf74c29514 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -40,8 +40,8 @@ fn add_only_cfg_attributes(attrs: &mut Vec, new_attrs: &[Attribute]) new_attr.cfg = d.cfg.clone(); attrs.push(Attribute::Parsed(AttributeKind::Doc(Box::new(new_attr)))); } else if let Attribute::Unparsed(normal) = attr - && let [ident] = &*normal.path.segments - && ident.name == sym::cfg_trace + && let [name] = &*normal.path.segments + && *name == sym::cfg_trace { // If it's a `cfg()` attribute, we keep it. attrs.push(attr.clone()); diff --git a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs index 53d9725703c3..84b65d3185e3 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs @@ -4,18 +4,19 @@ use clippy_utils::is_from_proc_macro; use rustc_ast::{AttrStyle, Attribute}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, LintContext}; +use rustc_ast::attr::AttributeExt; // Separate each crate's features. pub fn check<'cx>(cx: &EarlyContext<'cx>, attr: &'cx Attribute) { if !attr.span.in_external_macro(cx.sess().source_map()) && let AttrStyle::Outer = attr.style - && let Some(ident) = attr.ident() + && let Some(path_span) = attr.path_span() && !is_from_proc_macro(cx, attr) { #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] - span_lint_and_then(cx, ALLOW_ATTRIBUTES, ident.span, "#[allow] attribute found", |diag| { + span_lint_and_then(cx, ALLOW_ATTRIBUTES, path_span, "#[allow] attribute found", |diag| { diag.span_suggestion( - ident.span, + path_span, "replace it with", "expect", Applicability::MachineApplicable, diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs index 91c2dc7f3dc6..679ccfb8de3a 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs @@ -574,16 +574,16 @@ impl EarlyLintPass for PostExpansionEarlyAttributes { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { if let Some(items) = &attr.meta_item_list() - && let Some(ident) = attr.ident() + && let Some(name) = attr.name() { - if matches!(ident.name, sym::allow) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) { + if matches!(name, sym::allow) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) { allow_attributes::check(cx, attr); } - if matches!(ident.name, sym::allow | sym::expect) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) { - allow_attributes_without_reason::check(cx, ident.name, items, attr); + if matches!(name, sym::allow | sym::expect) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) { + allow_attributes_without_reason::check(cx, name, items, attr); } - if is_lint_level(ident.name, attr.id) { - blanket_clippy_restriction_lints::check(cx, ident.name, items); + if is_lint_level(name, attr.id) { + blanket_clippy_restriction_lints::check(cx, name, items); } if items.is_empty() || !attr.has_name(sym::deprecated) { return; diff --git a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs index 1cebc18edc90..aa9a6654bee3 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs @@ -15,7 +15,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) { return; } if let Some(lint_list) = &attr.meta_item_list() - && attr.ident().is_some_and(|ident| is_lint_level(ident.name, attr.id)) + && attr.name().is_some_and(|name| is_lint_level(name, attr.id)) { for lint in lint_list { match item.kind { diff --git a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs index c3bc9048c23a..28ea2e4fa1f0 100644 --- a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs +++ b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs @@ -270,7 +270,7 @@ fn is_under_cfg_attribute(cx: &LateContext<'_>, hir_id: HirId) -> bool { cx.tcx.hir_parent_id_iter(hir_id).any(|id| { cx.tcx.hir_attrs(id).iter().any(|attr| { matches!( - attr.ident().map(|ident| ident.name), + attr.name(), Some(sym::cfg_trace | sym::cfg_attr_trace) ) }) diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs index ac221743cfd6..375b275cd113 100644 --- a/src/tools/clippy/clippy_lints/src/missing_doc.rs +++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs @@ -287,8 +287,8 @@ fn is_doc_attr(attr: &Attribute) -> bool { match attr { Attribute::Parsed(AttributeKind::DocComment { .. }) => true, Attribute::Unparsed(attr) - if let [ident] = &*attr.path.segments - && ident.name == sym::doc => + if let [name] = &*attr.path.segments + && *name == sym::doc => { matches!(attr.args, AttrArgs::Eq { .. }) }, diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs index 2fd773b06781..94e4ede14048 100644 --- a/src/tools/clippy/clippy_utils/src/attrs.rs +++ b/src/tools/clippy/clippy_utils/src/attrs.rs @@ -20,10 +20,11 @@ pub fn get_builtin_attr<'a, A: AttributeExt + 'a>( name: Symbol, ) -> impl Iterator { attrs.iter().filter(move |attr| { - if let Some([clippy, segment2]) = attr.ident_path().as_deref() - && clippy.name == sym::clippy + if let [clippy, segment2] = &*attr.path() + && *clippy == sym::clippy { - let new_name = match segment2.name { + let path_span = attr.path_span().expect("Clippy attributes are unparsed and have a span"); + let new_name = match *segment2 { sym::cyclomatic_complexity => Some("cognitive_complexity"), sym::author | sym::version @@ -35,7 +36,7 @@ pub fn get_builtin_attr<'a, A: AttributeExt + 'a>( | sym::has_significant_drop | sym::format_args => None, _ => { - sess.dcx().span_err(segment2.span, "usage of unknown attribute"); + sess.dcx().span_err(path_span, "usage of unknown attribute"); return false; }, }; @@ -43,17 +44,17 @@ pub fn get_builtin_attr<'a, A: AttributeExt + 'a>( match new_name { Some(new_name) => { sess.dcx() - .struct_span_err(segment2.span, "usage of deprecated attribute") + .struct_span_err(path_span, "usage of deprecated attribute") .with_span_suggestion( - segment2.span, + path_span, "consider using", - new_name, + format!("clippy::{}", new_name), Applicability::MachineApplicable, ) .emit(); false }, - None => segment2.name == name, + None => *segment2 == name, } } else { false diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index d9254fca9453..7fb8616072a5 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -348,9 +348,9 @@ fn fn_kind_pat(tcx: TyCtxt<'_>, kind: &FnKind<'_>, body: &Body<'_>, hir_id: HirI fn attr_search_pat(attr: &Attribute) -> (Pat, Pat) { match attr.kind { AttrKind::Normal(..) => { - if let Some(ident) = attr.ident() { + if let Some(name) = attr.name() { // NOTE: This will likely have false positives, like `allow = 1` - let ident_string = ident.to_string(); + let ident_string = name.to_string(); if attr.style == AttrStyle::Outer { ( Pat::OwnedMultiStr(vec!["#[".to_owned() + &ident_string, ident_string]), diff --git a/src/tools/clippy/tests/ui/renamed_builtin_attr.stderr b/src/tools/clippy/tests/ui/renamed_builtin_attr.stderr index fb51313dab69..0ebc43739d6b 100644 --- a/src/tools/clippy/tests/ui/renamed_builtin_attr.stderr +++ b/src/tools/clippy/tests/ui/renamed_builtin_attr.stderr @@ -1,8 +1,8 @@ error: usage of deprecated attribute - --> tests/ui/renamed_builtin_attr.rs:3:11 + --> tests/ui/renamed_builtin_attr.rs:3:3 | LL | #[clippy::cyclomatic_complexity = "1"] - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `cognitive_complexity` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `clippy::cognitive_complexity` error: aborting due to 1 previous error diff --git a/src/tools/clippy/tests/ui/unknown_attribute.stderr b/src/tools/clippy/tests/ui/unknown_attribute.stderr index b306abe0a9d1..1d4d50ffc02a 100644 --- a/src/tools/clippy/tests/ui/unknown_attribute.stderr +++ b/src/tools/clippy/tests/ui/unknown_attribute.stderr @@ -1,8 +1,8 @@ error: usage of unknown attribute - --> tests/ui/unknown_attribute.rs:3:11 + --> tests/ui/unknown_attribute.rs:3:3 | LL | #[clippy::unknown] - | ^^^^^^^ + | ^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/src/tools/rustfmt/src/attr.rs b/src/tools/rustfmt/src/attr.rs index 381c938ae806..d03d33514046 100644 --- a/src/tools/rustfmt/src/attr.rs +++ b/src/tools/rustfmt/src/attr.rs @@ -336,8 +336,8 @@ impl Rewrite for ast::Attribute { rewrite_doc_comment(snippet, shape.comment(context.config), context.config) } else { let should_skip = self - .ident() - .map(|s| context.skip_context.attributes.skip(s.name.as_str())) + .name() + .map(|s| context.skip_context.attributes.skip(s.as_str())) .unwrap_or(false); let prefix = attr_prefix(self); From 4d0dbee8362a6b2f46526a8050ca8b6e658bfc38 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Tue, 9 Dec 2025 09:49:50 +0100 Subject: [PATCH 0046/1061] Make attr path symbols rather than idents --- clippy_lints/src/attrs/allow_attributes.rs | 7 ++++--- clippy_lints/src/attrs/mod.rs | 12 ++++++------ clippy_lints/src/attrs/useless_attribute.rs | 2 +- clippy_lints/src/incompatible_msrv.rs | 2 +- clippy_lints/src/missing_doc.rs | 4 ++-- clippy_utils/src/attrs.rs | 17 +++++++++-------- clippy_utils/src/check_proc_macro.rs | 4 ++-- tests/ui/renamed_builtin_attr.stderr | 4 ++-- tests/ui/unknown_attribute.stderr | 4 ++-- 9 files changed, 29 insertions(+), 27 deletions(-) diff --git a/clippy_lints/src/attrs/allow_attributes.rs b/clippy_lints/src/attrs/allow_attributes.rs index 53d9725703c3..84b65d3185e3 100644 --- a/clippy_lints/src/attrs/allow_attributes.rs +++ b/clippy_lints/src/attrs/allow_attributes.rs @@ -4,18 +4,19 @@ use clippy_utils::is_from_proc_macro; use rustc_ast::{AttrStyle, Attribute}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, LintContext}; +use rustc_ast::attr::AttributeExt; // Separate each crate's features. pub fn check<'cx>(cx: &EarlyContext<'cx>, attr: &'cx Attribute) { if !attr.span.in_external_macro(cx.sess().source_map()) && let AttrStyle::Outer = attr.style - && let Some(ident) = attr.ident() + && let Some(path_span) = attr.path_span() && !is_from_proc_macro(cx, attr) { #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] - span_lint_and_then(cx, ALLOW_ATTRIBUTES, ident.span, "#[allow] attribute found", |diag| { + span_lint_and_then(cx, ALLOW_ATTRIBUTES, path_span, "#[allow] attribute found", |diag| { diag.span_suggestion( - ident.span, + path_span, "replace it with", "expect", Applicability::MachineApplicable, diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index 91c2dc7f3dc6..679ccfb8de3a 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -574,16 +574,16 @@ impl EarlyLintPass for PostExpansionEarlyAttributes { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { if let Some(items) = &attr.meta_item_list() - && let Some(ident) = attr.ident() + && let Some(name) = attr.name() { - if matches!(ident.name, sym::allow) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) { + if matches!(name, sym::allow) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) { allow_attributes::check(cx, attr); } - if matches!(ident.name, sym::allow | sym::expect) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) { - allow_attributes_without_reason::check(cx, ident.name, items, attr); + if matches!(name, sym::allow | sym::expect) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) { + allow_attributes_without_reason::check(cx, name, items, attr); } - if is_lint_level(ident.name, attr.id) { - blanket_clippy_restriction_lints::check(cx, ident.name, items); + if is_lint_level(name, attr.id) { + blanket_clippy_restriction_lints::check(cx, name, items); } if items.is_empty() || !attr.has_name(sym::deprecated) { return; diff --git a/clippy_lints/src/attrs/useless_attribute.rs b/clippy_lints/src/attrs/useless_attribute.rs index 1cebc18edc90..aa9a6654bee3 100644 --- a/clippy_lints/src/attrs/useless_attribute.rs +++ b/clippy_lints/src/attrs/useless_attribute.rs @@ -15,7 +15,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) { return; } if let Some(lint_list) = &attr.meta_item_list() - && attr.ident().is_some_and(|ident| is_lint_level(ident.name, attr.id)) + && attr.name().is_some_and(|name| is_lint_level(name, attr.id)) { for lint in lint_list { match item.kind { diff --git a/clippy_lints/src/incompatible_msrv.rs b/clippy_lints/src/incompatible_msrv.rs index c3bc9048c23a..28ea2e4fa1f0 100644 --- a/clippy_lints/src/incompatible_msrv.rs +++ b/clippy_lints/src/incompatible_msrv.rs @@ -270,7 +270,7 @@ fn is_under_cfg_attribute(cx: &LateContext<'_>, hir_id: HirId) -> bool { cx.tcx.hir_parent_id_iter(hir_id).any(|id| { cx.tcx.hir_attrs(id).iter().any(|attr| { matches!( - attr.ident().map(|ident| ident.name), + attr.name(), Some(sym::cfg_trace | sym::cfg_attr_trace) ) }) diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index ac221743cfd6..375b275cd113 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -287,8 +287,8 @@ fn is_doc_attr(attr: &Attribute) -> bool { match attr { Attribute::Parsed(AttributeKind::DocComment { .. }) => true, Attribute::Unparsed(attr) - if let [ident] = &*attr.path.segments - && ident.name == sym::doc => + if let [name] = &*attr.path.segments + && *name == sym::doc => { matches!(attr.args, AttrArgs::Eq { .. }) }, diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 2fd773b06781..94e4ede14048 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -20,10 +20,11 @@ pub fn get_builtin_attr<'a, A: AttributeExt + 'a>( name: Symbol, ) -> impl Iterator { attrs.iter().filter(move |attr| { - if let Some([clippy, segment2]) = attr.ident_path().as_deref() - && clippy.name == sym::clippy + if let [clippy, segment2] = &*attr.path() + && *clippy == sym::clippy { - let new_name = match segment2.name { + let path_span = attr.path_span().expect("Clippy attributes are unparsed and have a span"); + let new_name = match *segment2 { sym::cyclomatic_complexity => Some("cognitive_complexity"), sym::author | sym::version @@ -35,7 +36,7 @@ pub fn get_builtin_attr<'a, A: AttributeExt + 'a>( | sym::has_significant_drop | sym::format_args => None, _ => { - sess.dcx().span_err(segment2.span, "usage of unknown attribute"); + sess.dcx().span_err(path_span, "usage of unknown attribute"); return false; }, }; @@ -43,17 +44,17 @@ pub fn get_builtin_attr<'a, A: AttributeExt + 'a>( match new_name { Some(new_name) => { sess.dcx() - .struct_span_err(segment2.span, "usage of deprecated attribute") + .struct_span_err(path_span, "usage of deprecated attribute") .with_span_suggestion( - segment2.span, + path_span, "consider using", - new_name, + format!("clippy::{}", new_name), Applicability::MachineApplicable, ) .emit(); false }, - None => segment2.name == name, + None => *segment2 == name, } } else { false diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index d9254fca9453..7fb8616072a5 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -348,9 +348,9 @@ fn fn_kind_pat(tcx: TyCtxt<'_>, kind: &FnKind<'_>, body: &Body<'_>, hir_id: HirI fn attr_search_pat(attr: &Attribute) -> (Pat, Pat) { match attr.kind { AttrKind::Normal(..) => { - if let Some(ident) = attr.ident() { + if let Some(name) = attr.name() { // NOTE: This will likely have false positives, like `allow = 1` - let ident_string = ident.to_string(); + let ident_string = name.to_string(); if attr.style == AttrStyle::Outer { ( Pat::OwnedMultiStr(vec!["#[".to_owned() + &ident_string, ident_string]), diff --git a/tests/ui/renamed_builtin_attr.stderr b/tests/ui/renamed_builtin_attr.stderr index fb51313dab69..0ebc43739d6b 100644 --- a/tests/ui/renamed_builtin_attr.stderr +++ b/tests/ui/renamed_builtin_attr.stderr @@ -1,8 +1,8 @@ error: usage of deprecated attribute - --> tests/ui/renamed_builtin_attr.rs:3:11 + --> tests/ui/renamed_builtin_attr.rs:3:3 | LL | #[clippy::cyclomatic_complexity = "1"] - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `cognitive_complexity` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `clippy::cognitive_complexity` error: aborting due to 1 previous error diff --git a/tests/ui/unknown_attribute.stderr b/tests/ui/unknown_attribute.stderr index b306abe0a9d1..1d4d50ffc02a 100644 --- a/tests/ui/unknown_attribute.stderr +++ b/tests/ui/unknown_attribute.stderr @@ -1,8 +1,8 @@ error: usage of unknown attribute - --> tests/ui/unknown_attribute.rs:3:11 + --> tests/ui/unknown_attribute.rs:3:3 | LL | #[clippy::unknown] - | ^^^^^^^ + | ^^^^^^^^^^^^^^^ error: aborting due to 1 previous error From f186dadb0dee2a1065743e76bf0be99dd4046926 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sat, 20 Dec 2025 11:22:16 +0100 Subject: [PATCH 0047/1061] compiletest: Use `DirectiveLine` also for debuginfo (read: debugger) tests This not only reduces code duplication already, it also gives us revision parsing for free which we need in an upcoming commit. --- src/tools/compiletest/src/directives.rs | 3 +- src/tools/compiletest/src/runtest/debugger.rs | 28 +++++++------------ 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index d1e0c5d95001..5865954558d8 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -15,7 +15,7 @@ use crate::directives::directive_names::{ }; pub(crate) use crate::directives::file::FileDirectives; use crate::directives::handlers::DIRECTIVE_HANDLERS_MAP; -use crate::directives::line::{DirectiveLine, line_directive}; +use crate::directives::line::DirectiveLine; use crate::directives::needs::CachedNeedsConditions; use crate::edition::{Edition, parse_edition}; use crate::errors::ErrorKind; @@ -29,6 +29,7 @@ mod directive_names; mod file; mod handlers; mod line; +pub(crate) use line::line_directive; mod line_number; pub(crate) use line_number::LineNumber; mod needs; diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs index c83e00c1006e..64b969f11059 100644 --- a/src/tools/compiletest/src/runtest/debugger.rs +++ b/src/tools/compiletest/src/runtest/debugger.rs @@ -4,7 +4,7 @@ use std::io::{BufRead, BufReader}; use camino::{Utf8Path, Utf8PathBuf}; -use crate::directives::LineNumber; +use crate::directives::{LineNumber, line_directive}; use crate::runtest::ProcRes; /// Representation of information to invoke a debugger and check its output @@ -37,15 +37,19 @@ impl DebuggerCommands { continue; } - let Some(line) = line.trim_start().strip_prefix("//@").map(str::trim_start) else { + let Some(directive) = line_directive(file, line_number, &line) else { continue; }; - if let Some(command) = parse_name_value(&line, &command_directive) { - commands.push(command); + if directive.name == command_directive + && let Some(command) = directive.value_after_colon() + { + commands.push(command.to_string()); } - if let Some(pattern) = parse_name_value(&line, &check_directive) { - check_lines.push((line_number, pattern)); + if directive.name == check_directive + && let Some(pattern) = directive.value_after_colon() + { + check_lines.push((line_number, pattern.to_string())); } } @@ -103,18 +107,6 @@ impl DebuggerCommands { } } -/// Split off from the main `parse_name_value_directive`, so that improvements -/// to directive handling aren't held back by debuginfo test commands. -fn parse_name_value(line: &str, name: &str) -> Option { - if let Some(after_name) = line.strip_prefix(name) - && let Some(value) = after_name.strip_prefix(':') - { - Some(value.to_owned()) - } else { - None - } -} - /// Check that the pattern in `check_line` applies to `line`. Returns `true` if they do match. fn check_single_line(line: &str, check_line: &str) -> bool { // Allow check lines to leave parts unspecified (e.g., uninitialized From 4516daccb36711f2d4536561762ed49281c2a0e8 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sat, 20 Dec 2025 11:41:05 +0100 Subject: [PATCH 0048/1061] compiletest: Support revisions in debuginfo (read: debugger) tests --- src/tools/compiletest/src/runtest/debugger.rs | 26 ++++++++++++++++--- .../compiletest/src/runtest/debuginfo.rs | 6 ++--- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs index 64b969f11059..70996004a336 100644 --- a/src/tools/compiletest/src/runtest/debugger.rs +++ b/src/tools/compiletest/src/runtest/debugger.rs @@ -17,10 +17,16 @@ pub(super) struct DebuggerCommands { check_lines: Vec<(LineNumber, String)>, /// Source file name file: Utf8PathBuf, + /// The revision being tested, if any + revision: Option, } impl DebuggerCommands { - pub fn parse_from(file: &Utf8Path, debugger_prefix: &str) -> Result { + pub fn parse_from( + file: &Utf8Path, + debugger_prefix: &str, + test_revision: Option<&str>, + ) -> Result { let command_directive = format!("{debugger_prefix}-command"); let check_directive = format!("{debugger_prefix}-check"); @@ -41,6 +47,10 @@ impl DebuggerCommands { continue; }; + if !directive.applies_to_test_revision(test_revision) { + continue; + } + if directive.name == command_directive && let Some(command) = directive.value_after_colon() { @@ -53,7 +63,13 @@ impl DebuggerCommands { } } - Ok(Self { commands, breakpoint_lines, check_lines, file: file.to_path_buf() }) + Ok(Self { + commands, + breakpoint_lines, + check_lines, + file: file.to_path_buf(), + revision: test_revision.map(str::to_owned), + }) } /// Given debugger output and lines to check, ensure that every line is @@ -85,9 +101,11 @@ impl DebuggerCommands { Ok(()) } else { let fname = self.file.file_name().unwrap(); + let revision_suffix = + self.revision.as_ref().map_or(String::new(), |r| format!("#{}", r)); let mut msg = format!( - "check directive(s) from `{}` not found in debugger output. errors:", - self.file + "check directive(s) from `{}{}` not found in debugger output. errors:", + self.file, revision_suffix ); for (src_lineno, err_line) in missing { diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs index 83b61b9be57d..9d6edaddc1b7 100644 --- a/src/tools/compiletest/src/runtest/debuginfo.rs +++ b/src/tools/compiletest/src/runtest/debuginfo.rs @@ -46,7 +46,7 @@ impl TestCx<'_> { } // Parse debugger commands etc from test files - let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "cdb") + let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "cdb", self.revision) .unwrap_or_else(|e| self.fatal(&e)); // https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands @@ -105,7 +105,7 @@ impl TestCx<'_> { } fn run_debuginfo_gdb_test(&self) { - let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "gdb") + let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "gdb", self.revision) .unwrap_or_else(|e| self.fatal(&e)); let mut cmds = dbg_cmds.commands.join("\n"); @@ -366,7 +366,7 @@ impl TestCx<'_> { } // Parse debugger commands etc from test files - let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "lldb") + let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "lldb", self.revision) .unwrap_or_else(|e| self.fatal(&e)); // Write debugger script: From 423a8dc4090a47589a61e30a139731eb500892db Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sat, 20 Dec 2025 11:49:04 +0100 Subject: [PATCH 0049/1061] tests/debuginfo/macro-stepping.rs: Add revisions `default-mir-passes`, `no-SingleUseConsts-mir-pass` To prevent the test from regressing both with and without `SingleUseConsts` MIR pass. --- tests/debuginfo/macro-stepping.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/debuginfo/macro-stepping.rs b/tests/debuginfo/macro-stepping.rs index 0dff383be825..ba3a4452041a 100644 --- a/tests/debuginfo/macro-stepping.rs +++ b/tests/debuginfo/macro-stepping.rs @@ -14,8 +14,10 @@ #[macro_use] extern crate macro_stepping; // exports new_scope!() -//@ compile-flags:-g -Zmir-enable-passes=-SingleUseConsts -// SingleUseConsts shouldn't need to be disabled, see #128945 +//@ compile-flags: -g +// FIXME(#128945): SingleUseConsts shouldn't need to be disabled. +//@ revisions: default-mir-passes no-SingleUseConsts-mir-pass +//@ [no-SingleUseConsts-mir-pass] compile-flags: -Zmir-enable-passes=-SingleUseConsts // === GDB TESTS =================================================================================== @@ -48,7 +50,7 @@ extern crate macro_stepping; // exports new_scope!() //@ gdb-check:[...]#inc-loc2[...] //@ gdb-command:next //@ gdb-command:frame -//@ gdb-check:[...]#inc-loc3[...] +//@ [no-SingleUseConsts-mir-pass] gdb-check:[...]#inc-loc3[...] // === LLDB TESTS ================================================================================== From bc943aa8ea5aad5690eef4594ad50da949c181fb Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Tue, 23 Dec 2025 22:55:19 +0000 Subject: [PATCH 0050/1061] fix: `checked_conversions` wrongly unmangled macros --- clippy_lints/src/checked_conversions.rs | 5 +-- tests/ui/checked_conversions.fixed | 16 ++++++++++ tests/ui/checked_conversions.rs | 16 ++++++++++ tests/ui/checked_conversions.stderr | 42 ++++++++++++++----------- 4 files changed, 59 insertions(+), 20 deletions(-) diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 9b3822f9d8f0..8303897d1294 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal, sym}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, TyKind}; @@ -80,7 +80,8 @@ impl LateLintPass<'_> for CheckedConversions { && self.msrv.meets(cx, msrvs::TRY_FROM) { let mut applicability = Applicability::MachineApplicable; - let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut applicability); + let (snippet, _) = + snippet_with_context(cx, cv.expr_to_cast.span, item.span.ctxt(), "_", &mut applicability); span_lint_and_sugg( cx, CHECKED_CONVERSIONS, diff --git a/tests/ui/checked_conversions.fixed b/tests/ui/checked_conversions.fixed index 6175275ef047..2309a053146f 100644 --- a/tests/ui/checked_conversions.fixed +++ b/tests/ui/checked_conversions.fixed @@ -1,6 +1,7 @@ #![allow( clippy::cast_lossless, clippy::legacy_numeric_constants, + clippy::no_effect, unused, // Int::max_value will be deprecated in the future deprecated, @@ -105,4 +106,19 @@ fn msrv_1_34() { //~^ checked_conversions } +fn issue16293() { + struct Outer { + inner: u32, + } + let outer = Outer { inner: 42 }; + macro_rules! dot_inner { + ($obj:expr) => { + $obj.inner + }; + } + + i32::try_from(dot_inner!(outer)).is_ok(); + //~^ checked_conversions +} + fn main() {} diff --git a/tests/ui/checked_conversions.rs b/tests/ui/checked_conversions.rs index 9ed0e8f660d0..dabb552eba27 100644 --- a/tests/ui/checked_conversions.rs +++ b/tests/ui/checked_conversions.rs @@ -1,6 +1,7 @@ #![allow( clippy::cast_lossless, clippy::legacy_numeric_constants, + clippy::no_effect, unused, // Int::max_value will be deprecated in the future deprecated, @@ -105,4 +106,19 @@ fn msrv_1_34() { //~^ checked_conversions } +fn issue16293() { + struct Outer { + inner: u32, + } + let outer = Outer { inner: 42 }; + macro_rules! dot_inner { + ($obj:expr) => { + $obj.inner + }; + } + + dot_inner!(outer) <= i32::MAX as u32; + //~^ checked_conversions +} + fn main() {} diff --git a/tests/ui/checked_conversions.stderr b/tests/ui/checked_conversions.stderr index 624876dacb26..6018dacace39 100644 --- a/tests/ui/checked_conversions.stderr +++ b/tests/ui/checked_conversions.stderr @@ -1,5 +1,5 @@ error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:15:13 + --> tests/ui/checked_conversions.rs:16:13 | LL | let _ = value <= (u32::max_value() as i64) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()` @@ -8,100 +8,106 @@ LL | let _ = value <= (u32::max_value() as i64) && value >= 0; = help: to override `-D warnings` add `#[allow(clippy::checked_conversions)]` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:17:13 + --> tests/ui/checked_conversions.rs:18:13 | LL | let _ = value <= (u32::MAX as i64) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:22:13 + --> tests/ui/checked_conversions.rs:23:13 | LL | let _ = value <= i64::from(u16::max_value()) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:24:13 + --> tests/ui/checked_conversions.rs:25:13 | LL | let _ = value <= i64::from(u16::MAX) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:29:13 + --> tests/ui/checked_conversions.rs:30:13 | LL | let _ = value <= (u8::max_value() as isize) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:31:13 + --> tests/ui/checked_conversions.rs:32:13 | LL | let _ = value <= (u8::MAX as isize) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:38:13 + --> tests/ui/checked_conversions.rs:39:13 | LL | let _ = value <= (i32::max_value() as i64) && value >= (i32::min_value() as i64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:40:13 + --> tests/ui/checked_conversions.rs:41:13 | LL | let _ = value <= (i32::MAX as i64) && value >= (i32::MIN as i64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:45:13 + --> tests/ui/checked_conversions.rs:46:13 | LL | let _ = value <= i64::from(i16::max_value()) && value >= i64::from(i16::min_value()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:47:13 + --> tests/ui/checked_conversions.rs:48:13 | LL | let _ = value <= i64::from(i16::MAX) && value >= i64::from(i16::MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:54:13 + --> tests/ui/checked_conversions.rs:55:13 | LL | let _ = value <= i32::max_value() as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:56:13 + --> tests/ui/checked_conversions.rs:57:13 | LL | let _ = value <= i32::MAX as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:61:13 + --> tests/ui/checked_conversions.rs:62:13 | LL | let _ = value <= isize::max_value() as usize && value as i32 == 5; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:63:13 + --> tests/ui/checked_conversions.rs:64:13 | LL | let _ = value <= isize::MAX as usize && value as i32 == 5; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:68:13 + --> tests/ui/checked_conversions.rs:69:13 | LL | let _ = value <= u16::max_value() as u32 && value as i32 == 5; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:70:13 + --> tests/ui/checked_conversions.rs:71:13 | LL | let _ = value <= u16::MAX as u32 && value as i32 == 5; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:104:13 + --> tests/ui/checked_conversions.rs:105:13 | LL | let _ = value <= (u32::max_value() as i64) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()` -error: aborting due to 17 previous errors +error: checked cast can be simplified + --> tests/ui/checked_conversions.rs:120:5 + | +LL | dot_inner!(outer) <= i32::MAX as u32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(dot_inner!(outer)).is_ok()` + +error: aborting due to 18 previous errors From ffbdb578b0e6e9d4657abbd3d6454bde4bed1869 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Tue, 23 Dec 2025 23:08:32 +0000 Subject: [PATCH 0051/1061] fix: `manual_ignore_case_cmp` wrongly unmangled macros --- clippy_lints/src/manual_ignore_case_cmp.rs | 10 ++++----- tests/ui/manual_ignore_case_cmp.fixed | 20 +++++++++++++++++ tests/ui/manual_ignore_case_cmp.rs | 20 +++++++++++++++++ tests/ui/manual_ignore_case_cmp.stderr | 26 +++++++++++++++++++++- 4 files changed, 69 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/manual_ignore_case_cmp.rs b/clippy_lints/src/manual_ignore_case_cmp.rs index 25057b4aeaa2..1c20a8f81efb 100644 --- a/clippy_lints/src/manual_ignore_case_cmp.rs +++ b/clippy_lints/src/manual_ignore_case_cmp.rs @@ -1,7 +1,7 @@ use crate::manual_ignore_case_cmp::MatchType::{Literal, ToAscii}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeDef; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::sym; use rustc_ast::LitKind; use rustc_errors::Applicability; @@ -111,14 +111,12 @@ impl LateLintPass<'_> for ManualIgnoreCaseCmp { "manual case-insensitive ASCII comparison", |diag| { let mut app = Applicability::MachineApplicable; + let (left_snip, _) = snippet_with_context(cx, left_span, expr.span.ctxt(), "..", &mut app); + let (right_snip, _) = snippet_with_context(cx, right_span, expr.span.ctxt(), "..", &mut app); diag.span_suggestion_verbose( expr.span, "consider using `.eq_ignore_ascii_case()` instead", - format!( - "{neg}{}.eq_ignore_ascii_case({deref}{})", - snippet_with_applicability(cx, left_span, "_", &mut app), - snippet_with_applicability(cx, right_span, "_", &mut app) - ), + format!("{neg}{left_snip}.eq_ignore_ascii_case({deref}{right_snip})"), app, ); }, diff --git a/tests/ui/manual_ignore_case_cmp.fixed b/tests/ui/manual_ignore_case_cmp.fixed index cd7adc20b127..f0e413aaec0d 100644 --- a/tests/ui/manual_ignore_case_cmp.fixed +++ b/tests/ui/manual_ignore_case_cmp.fixed @@ -160,3 +160,23 @@ fn ref_osstring(a: OsString, b: &OsString) { b.eq_ignore_ascii_case(a); //~^ manual_ignore_case_cmp } + +fn wrongly_unmangled_macros(a: &str, b: &str) -> bool { + struct S<'a> { + inner: &'a str, + } + + let a = S { inner: a }; + let b = S { inner: b }; + + macro_rules! dot_inner { + ($s:expr) => { + $s.inner + }; + } + + dot_inner!(a).eq_ignore_ascii_case(dot_inner!(b)) + //~^ manual_ignore_case_cmp + || dot_inner!(a).eq_ignore_ascii_case("abc") + //~^ manual_ignore_case_cmp +} diff --git a/tests/ui/manual_ignore_case_cmp.rs b/tests/ui/manual_ignore_case_cmp.rs index 85f6719827c9..9802e87cd233 100644 --- a/tests/ui/manual_ignore_case_cmp.rs +++ b/tests/ui/manual_ignore_case_cmp.rs @@ -160,3 +160,23 @@ fn ref_osstring(a: OsString, b: &OsString) { b.to_ascii_lowercase() == a.to_ascii_lowercase(); //~^ manual_ignore_case_cmp } + +fn wrongly_unmangled_macros(a: &str, b: &str) -> bool { + struct S<'a> { + inner: &'a str, + } + + let a = S { inner: a }; + let b = S { inner: b }; + + macro_rules! dot_inner { + ($s:expr) => { + $s.inner + }; + } + + dot_inner!(a).to_ascii_lowercase() == dot_inner!(b).to_ascii_lowercase() + //~^ manual_ignore_case_cmp + || dot_inner!(a).to_ascii_lowercase() == "abc" + //~^ manual_ignore_case_cmp +} diff --git a/tests/ui/manual_ignore_case_cmp.stderr b/tests/ui/manual_ignore_case_cmp.stderr index fa7fadd91076..2f698e076ed3 100644 --- a/tests/ui/manual_ignore_case_cmp.stderr +++ b/tests/ui/manual_ignore_case_cmp.stderr @@ -588,5 +588,29 @@ LL - b.to_ascii_lowercase() == a.to_ascii_lowercase(); LL + b.eq_ignore_ascii_case(a); | -error: aborting due to 49 previous errors +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:178:5 + | +LL | dot_inner!(a).to_ascii_lowercase() == dot_inner!(b).to_ascii_lowercase() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL - dot_inner!(a).to_ascii_lowercase() == dot_inner!(b).to_ascii_lowercase() +LL + dot_inner!(a).eq_ignore_ascii_case(dot_inner!(b)) + | + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:180:12 + | +LL | || dot_inner!(a).to_ascii_lowercase() == "abc" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL - || dot_inner!(a).to_ascii_lowercase() == "abc" +LL + || dot_inner!(a).eq_ignore_ascii_case("abc") + | + +error: aborting due to 51 previous errors From d30647b7f2085dd073f756aca40cf965b060921a Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Tue, 23 Dec 2025 23:13:13 +0000 Subject: [PATCH 0052/1061] fix: `manual_ilog2` wrongly unmangled macros --- clippy_lints/src/manual_ilog2.rs | 4 ++-- tests/ui/manual_ilog2.fixed | 17 +++++++++++++++++ tests/ui/manual_ilog2.rs | 17 +++++++++++++++++ tests/ui/manual_ilog2.stderr | 14 +++++++++++++- 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/manual_ilog2.rs b/clippy_lints/src/manual_ilog2.rs index 1c61db530606..4b411a60f3bf 100644 --- a/clippy_lints/src/manual_ilog2.rs +++ b/clippy_lints/src/manual_ilog2.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::{is_from_proc_macro, sym}; use rustc_ast::LitKind; use rustc_data_structures::packed::Pu128; @@ -102,7 +102,7 @@ impl LateLintPass<'_> for ManualIlog2 { fn emit(cx: &LateContext<'_>, recv: &Expr<'_>, full_expr: &Expr<'_>) { let mut app = Applicability::MachineApplicable; - let recv = snippet_with_applicability(cx, recv.span, "_", &mut app); + let (recv, _) = snippet_with_context(cx, recv.span, full_expr.span.ctxt(), "_", &mut app); span_lint_and_sugg( cx, MANUAL_ILOG2, diff --git a/tests/ui/manual_ilog2.fixed b/tests/ui/manual_ilog2.fixed index a0f6d9392c30..ea86fc927c7c 100644 --- a/tests/ui/manual_ilog2.fixed +++ b/tests/ui/manual_ilog2.fixed @@ -30,3 +30,20 @@ fn foo(a: u32, b: u64) { external!($a.ilog(2)); with_span!(span; a.ilog(2)); } + +fn wrongly_unmangled_macros() { + struct S { + inner: u32, + } + + let x = S { inner: 42 }; + macro_rules! access { + ($s:expr) => { + $s.inner + }; + } + let log = access!(x).ilog2(); + //~^ manual_ilog2 + let log = access!(x).ilog2(); + //~^ manual_ilog2 +} diff --git a/tests/ui/manual_ilog2.rs b/tests/ui/manual_ilog2.rs index bd4b5d9d3c0d..8cb0e12d7361 100644 --- a/tests/ui/manual_ilog2.rs +++ b/tests/ui/manual_ilog2.rs @@ -30,3 +30,20 @@ fn foo(a: u32, b: u64) { external!($a.ilog(2)); with_span!(span; a.ilog(2)); } + +fn wrongly_unmangled_macros() { + struct S { + inner: u32, + } + + let x = S { inner: 42 }; + macro_rules! access { + ($s:expr) => { + $s.inner + }; + } + let log = 31 - access!(x).leading_zeros(); + //~^ manual_ilog2 + let log = access!(x).ilog(2); + //~^ manual_ilog2 +} diff --git a/tests/ui/manual_ilog2.stderr b/tests/ui/manual_ilog2.stderr index 7c9694f35330..d0ef8378081a 100644 --- a/tests/ui/manual_ilog2.stderr +++ b/tests/ui/manual_ilog2.stderr @@ -19,5 +19,17 @@ error: manually reimplementing `ilog2` LL | 63 - b.leading_zeros(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `b.ilog2()` -error: aborting due to 3 previous errors +error: manually reimplementing `ilog2` + --> tests/ui/manual_ilog2.rs:45:15 + | +LL | let log = 31 - access!(x).leading_zeros(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `access!(x).ilog2()` + +error: manually reimplementing `ilog2` + --> tests/ui/manual_ilog2.rs:47:15 + | +LL | let log = access!(x).ilog(2); + | ^^^^^^^^^^^^^^^^^^ help: try: `access!(x).ilog2()` + +error: aborting due to 5 previous errors From 01b39655df52597ddf31c0e243d3bfbdbf3a0be0 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Tue, 23 Dec 2025 23:53:17 +0000 Subject: [PATCH 0053/1061] fix: `needless_bool_assign` wrongly unmangled macros --- clippy_lints/src/needless_bool.rs | 6 +++--- tests/ui/needless_bool_assign.fixed | 19 +++++++++++++++++++ tests/ui/needless_bool_assign.rs | 23 +++++++++++++++++++++++ tests/ui/needless_bool_assign.stderr | 12 +++++++++++- 4 files changed, 56 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 854e927aa2f7..6b5db9dcf3e2 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::Sugg; use clippy_utils::{ SpanlessEq, get_parent_expr, higher, is_block_like, is_else_clause, is_parent_stmt, is_receiver_of_method_call, @@ -171,8 +171,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool { && SpanlessEq::new(cx).eq_expr(lhs_a, lhs_b) { let mut applicability = Applicability::MachineApplicable; - let cond = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability); - let lhs = snippet_with_applicability(cx, lhs_a.span, "..", &mut applicability); + let cond = Sugg::hir_with_context(cx, cond, e.span.ctxt(), "..", &mut applicability); + let (lhs, _) = snippet_with_context(cx, lhs_a.span, e.span.ctxt(), "..", &mut applicability); let mut sugg = if a == b { format!("{cond}; {lhs} = {a:?};") } else { diff --git a/tests/ui/needless_bool_assign.fixed b/tests/ui/needless_bool_assign.fixed index d6fab4c51b53..8fd572038140 100644 --- a/tests/ui/needless_bool_assign.fixed +++ b/tests/ui/needless_bool_assign.fixed @@ -42,3 +42,22 @@ fn issue15063(x: bool, y: bool) { } else { z = x || y; } //~^^^^^ needless_bool_assign } + +fn wrongly_unmangled_macros(must_keep: fn(usize, usize) -> bool, x: usize, y: usize) { + struct Wrapper(T); + let mut skip = Wrapper(false); + + macro_rules! invoke { + ($func:expr, $a:expr, $b:expr) => { + $func($a, $b) + }; + } + macro_rules! dot_0 { + ($w:expr) => { + $w.0 + }; + } + + dot_0!(skip) = !invoke!(must_keep, x, y); + //~^^^^^ needless_bool_assign +} diff --git a/tests/ui/needless_bool_assign.rs b/tests/ui/needless_bool_assign.rs index c504f61f4dd1..4721ab433b32 100644 --- a/tests/ui/needless_bool_assign.rs +++ b/tests/ui/needless_bool_assign.rs @@ -58,3 +58,26 @@ fn issue15063(x: bool, y: bool) { } //~^^^^^ needless_bool_assign } + +fn wrongly_unmangled_macros(must_keep: fn(usize, usize) -> bool, x: usize, y: usize) { + struct Wrapper(T); + let mut skip = Wrapper(false); + + macro_rules! invoke { + ($func:expr, $a:expr, $b:expr) => { + $func($a, $b) + }; + } + macro_rules! dot_0 { + ($w:expr) => { + $w.0 + }; + } + + if invoke!(must_keep, x, y) { + dot_0!(skip) = false; + } else { + dot_0!(skip) = true; + } + //~^^^^^ needless_bool_assign +} diff --git a/tests/ui/needless_bool_assign.stderr b/tests/ui/needless_bool_assign.stderr index 1d09b8b25a09..34ff782f34a3 100644 --- a/tests/ui/needless_bool_assign.stderr +++ b/tests/ui/needless_bool_assign.stderr @@ -62,5 +62,15 @@ LL | | z = false; LL | | } | |_____^ help: you can reduce it to: `{ z = x || y; }` -error: aborting due to 5 previous errors +error: this if-then-else expression assigns a bool literal + --> tests/ui/needless_bool_assign.rs:77:5 + | +LL | / if invoke!(must_keep, x, y) { +LL | | dot_0!(skip) = false; +LL | | } else { +LL | | dot_0!(skip) = true; +LL | | } + | |_____^ help: you can reduce it to: `dot_0!(skip) = !invoke!(must_keep, x, y);` + +error: aborting due to 6 previous errors From 21eaa04df821f0c716a9cbca2e502aef50e4d2e3 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Wed, 24 Dec 2025 00:09:43 +0000 Subject: [PATCH 0054/1061] fix: `needless_for_each` FN when `for_each` is in the expr of a block --- clippy_lints/src/needless_for_each.rs | 125 ++++++++++++---------- tests/ui/needless_for_each_fixable.fixed | 8 ++ tests/ui/needless_for_each_fixable.rs | 8 ++ tests/ui/needless_for_each_fixable.stderr | 19 +++- 4 files changed, 105 insertions(+), 55 deletions(-) diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index d03188f1d39b..55a5a16c0099 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -56,8 +56,20 @@ declare_lint_pass!(NeedlessForEach => [NEEDLESS_FOR_EACH]); impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { - if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind - && let ExprKind::MethodCall(method_name, for_each_recv, [for_each_arg], _) = expr.kind + if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind { + check_expr(cx, expr, stmt.span); + } + } + + fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) { + if let Some(expr) = block.expr { + check_expr(cx, expr, expr.span); + } + } +} + +fn check_expr(cx: &LateContext<'_>, expr: &Expr<'_>, outer_span: Span) { + if let ExprKind::MethodCall(method_name, for_each_recv, [for_each_arg], _) = expr.kind && let ExprKind::MethodCall(_, iter_recv, [], _) = for_each_recv.kind // Skip the lint if the call chain is too long. e.g. `v.field.iter().for_each()` or // `v.foo().iter().for_each()` must be skipped. @@ -76,69 +88,74 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { // Skip the lint if the body is not safe, so as not to suggest `for … in … unsafe {}` // and suggesting `for … in … { unsafe { } }` is a little ugly. && !matches!(body.value.kind, ExprKind::Block(Block { rules: BlockCheckMode::UnsafeBlock(_), .. }, ..)) + { + let mut applicability = Applicability::MachineApplicable; + + // If any closure parameter has an explicit type specified, applying the lint would necessarily + // remove that specification, possibly breaking type inference + if fn_decl + .inputs + .iter() + .any(|input| matches!(input.kind, TyKind::Infer(..))) { - let mut applicability = Applicability::MachineApplicable; + applicability = Applicability::MaybeIncorrect; + } - // If any closure parameter has an explicit type specified, applying the lint would necessarily - // remove that specification, possibly breaking type inference - if fn_decl - .inputs - .iter() - .any(|input| matches!(input.kind, TyKind::Infer(..))) - { - applicability = Applicability::MaybeIncorrect; - } + let mut ret_collector = RetCollector::default(); + ret_collector.visit_expr(body.value); - let mut ret_collector = RetCollector::default(); - ret_collector.visit_expr(body.value); + // Skip the lint if `return` is used in `Loop` in order not to suggest using `'label`. + if ret_collector.ret_in_loop { + return; + } - // Skip the lint if `return` is used in `Loop` in order not to suggest using `'label`. - if ret_collector.ret_in_loop { - return; - } + let ret_suggs = if ret_collector.spans.is_empty() { + None + } else { + applicability = Applicability::MaybeIncorrect; + Some( + ret_collector + .spans + .into_iter() + .map(|span| (span, "continue".to_string())) + .collect(), + ) + }; - let ret_suggs = if ret_collector.spans.is_empty() { - None + let body_param_sugg = snippet_with_applicability(cx, body.params[0].pat.span, "..", &mut applicability); + let for_each_rev_sugg = snippet_with_applicability(cx, for_each_recv.span, "..", &mut applicability); + let (body_value_sugg, is_macro_call) = + snippet_with_context(cx, body.value.span, for_each_recv.span.ctxt(), "..", &mut applicability); + + let sugg = format!( + "for {} in {} {}", + body_param_sugg, + for_each_rev_sugg, + if is_macro_call { + format!("{{ {body_value_sugg}; }}") } else { - applicability = Applicability::MaybeIncorrect; - Some( - ret_collector - .spans - .into_iter() - .map(|span| (span, "continue".to_string())) - .collect(), - ) - }; - - let body_param_sugg = snippet_with_applicability(cx, body.params[0].pat.span, "..", &mut applicability); - let for_each_rev_sugg = snippet_with_applicability(cx, for_each_recv.span, "..", &mut applicability); - let (body_value_sugg, is_macro_call) = - snippet_with_context(cx, body.value.span, for_each_recv.span.ctxt(), "..", &mut applicability); - - let sugg = format!( - "for {} in {} {}", - body_param_sugg, - for_each_rev_sugg, - if is_macro_call { - format!("{{ {body_value_sugg}; }}") - } else { - match body.value.kind { - ExprKind::Block(block, _) if is_let_desugar(block) => { - format!("{{ {body_value_sugg} }}") - }, - ExprKind::Block(_, _) => body_value_sugg.to_string(), - _ => format!("{{ {body_value_sugg}; }}"), - } + match body.value.kind { + ExprKind::Block(block, _) if is_let_desugar(block) => { + format!("{{ {body_value_sugg} }}") + }, + ExprKind::Block(_, _) => body_value_sugg.to_string(), + _ => format!("{{ {body_value_sugg}; }}"), } - ); + } + ); - span_lint_and_then(cx, NEEDLESS_FOR_EACH, stmt.span, "needless use of `for_each`", |diag| { - diag.span_suggestion(stmt.span, "try", sugg, applicability); + span_lint_and_then( + cx, + NEEDLESS_FOR_EACH, + outer_span, + "needless use of `for_each`", + |diag| { + diag.span_suggestion(outer_span, "try", sugg, applicability); if let Some(ret_suggs) = ret_suggs { diag.multipart_suggestion("...and replace `return` with `continue`", ret_suggs, applicability); } - }); - } + }, + ); } } diff --git a/tests/ui/needless_for_each_fixable.fixed b/tests/ui/needless_for_each_fixable.fixed index a6d64d9afc1a..19b34f42af24 100644 --- a/tests/ui/needless_for_each_fixable.fixed +++ b/tests/ui/needless_for_each_fixable.fixed @@ -149,3 +149,11 @@ fn issue15256() { for v in vec.iter() { println!("{v}"); } //~^ needless_for_each } + +fn issue16294() { + let vec: Vec = Vec::new(); + for elem in vec.iter() { + //~^ needless_for_each + println!("{elem}"); + } +} diff --git a/tests/ui/needless_for_each_fixable.rs b/tests/ui/needless_for_each_fixable.rs index 7e74d2b428fd..f04e2555a370 100644 --- a/tests/ui/needless_for_each_fixable.rs +++ b/tests/ui/needless_for_each_fixable.rs @@ -149,3 +149,11 @@ fn issue15256() { vec.iter().for_each(|v| println!("{v}")); //~^ needless_for_each } + +fn issue16294() { + let vec: Vec = Vec::new(); + vec.iter().for_each(|elem| { + //~^ needless_for_each + println!("{elem}"); + }) +} diff --git a/tests/ui/needless_for_each_fixable.stderr b/tests/ui/needless_for_each_fixable.stderr index 204cfa36b022..121669d15072 100644 --- a/tests/ui/needless_for_each_fixable.stderr +++ b/tests/ui/needless_for_each_fixable.stderr @@ -154,5 +154,22 @@ error: needless use of `for_each` LL | vec.iter().for_each(|v| println!("{v}")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for v in vec.iter() { println!("{v}"); }` -error: aborting due to 11 previous errors +error: needless use of `for_each` + --> tests/ui/needless_for_each_fixable.rs:155:5 + | +LL | / vec.iter().for_each(|elem| { +LL | | +LL | | println!("{elem}"); +LL | | }) + | |______^ + | +help: try + | +LL ~ for elem in vec.iter() { +LL + +LL + println!("{elem}"); +LL + } + | + +error: aborting due to 12 previous errors From 6bc65090756d6d81d3414fdc50f856ea45a24046 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Wed, 24 Dec 2025 00:21:23 +0000 Subject: [PATCH 0055/1061] fix: `manual_is_multiple_of` wrongly unmangled macros --- .../src/operators/manual_is_multiple_of.rs | 4 ++-- tests/ui/manual_is_multiple_of.fixed | 16 ++++++++++++++++ tests/ui/manual_is_multiple_of.rs | 16 ++++++++++++++++ tests/ui/manual_is_multiple_of.stderr | 8 +++++++- 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/operators/manual_is_multiple_of.rs b/clippy_lints/src/operators/manual_is_multiple_of.rs index 0b9bd4fb6d32..291d81097b51 100644 --- a/clippy_lints/src/operators/manual_is_multiple_of.rs +++ b/clippy_lints/src/operators/manual_is_multiple_of.rs @@ -35,7 +35,7 @@ pub(super) fn check<'tcx>( { let mut app = Applicability::MachineApplicable; let divisor = deref_sugg( - Sugg::hir_with_applicability(cx, operand_right, "_", &mut app), + Sugg::hir_with_context(cx, operand_right, expr.span.ctxt(), "_", &mut app), cx.typeck_results().expr_ty_adjusted(operand_right), ); span_lint_and_sugg( @@ -47,7 +47,7 @@ pub(super) fn check<'tcx>( format!( "{}{}.is_multiple_of({divisor})", if op == BinOpKind::Eq { "" } else { "!" }, - Sugg::hir_with_applicability(cx, operand_left, "_", &mut app).maybe_paren() + Sugg::hir_with_context(cx, operand_left, expr.span.ctxt(), "_", &mut app).maybe_paren() ), app, ); diff --git a/tests/ui/manual_is_multiple_of.fixed b/tests/ui/manual_is_multiple_of.fixed index 03f75e725ed5..82e0684e5e57 100644 --- a/tests/ui/manual_is_multiple_of.fixed +++ b/tests/ui/manual_is_multiple_of.fixed @@ -101,3 +101,19 @@ mod issue15103 { (1..1_000).filter(|&i| i == d(d(i)) && i != d(i)).sum() } } + +fn wrongly_unmangled_macros(a: u32, b: u32) { + struct Wrapper(u32); + let a = Wrapper(a); + let b = Wrapper(b); + macro_rules! dot_0 { + ($x:expr) => { + $x.0 + }; + } + + if dot_0!(a).is_multiple_of(dot_0!(b)) { + //~^ manual_is_multiple_of + todo!() + } +} diff --git a/tests/ui/manual_is_multiple_of.rs b/tests/ui/manual_is_multiple_of.rs index 7b6fa64c843d..82a492e24092 100644 --- a/tests/ui/manual_is_multiple_of.rs +++ b/tests/ui/manual_is_multiple_of.rs @@ -101,3 +101,19 @@ mod issue15103 { (1..1_000).filter(|&i| i == d(d(i)) && i != d(i)).sum() } } + +fn wrongly_unmangled_macros(a: u32, b: u32) { + struct Wrapper(u32); + let a = Wrapper(a); + let b = Wrapper(b); + macro_rules! dot_0 { + ($x:expr) => { + $x.0 + }; + } + + if dot_0!(a) % dot_0!(b) == 0 { + //~^ manual_is_multiple_of + todo!() + } +} diff --git a/tests/ui/manual_is_multiple_of.stderr b/tests/ui/manual_is_multiple_of.stderr index 8523599ec402..3aba869c9111 100644 --- a/tests/ui/manual_is_multiple_of.stderr +++ b/tests/ui/manual_is_multiple_of.stderr @@ -67,5 +67,11 @@ error: manual implementation of `.is_multiple_of()` LL | let d = |n: u32| -> u32 { (1..=n / 2).filter(|i| n % i == 0).sum() }; | ^^^^^^^^^^ help: replace with: `n.is_multiple_of(*i)` -error: aborting due to 11 previous errors +error: manual implementation of `.is_multiple_of()` + --> tests/ui/manual_is_multiple_of.rs:115:8 + | +LL | if dot_0!(a) % dot_0!(b) == 0 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `dot_0!(a).is_multiple_of(dot_0!(b))` + +error: aborting due to 12 previous errors From 5fbb39c036c8620d2d8efa54b6e1bfc5bd664008 Mon Sep 17 00:00:00 2001 From: Redddy Date: Tue, 23 Dec 2025 15:22:59 +0900 Subject: [PATCH 0056/1061] Fix function formatting in src/overview.md --- src/doc/rustc-dev-guide/src/overview.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/overview.md b/src/doc/rustc-dev-guide/src/overview.md index 23cc94d41846..1200a854f8ed 100644 --- a/src/doc/rustc-dev-guide/src/overview.md +++ b/src/doc/rustc-dev-guide/src/overview.md @@ -50,10 +50,10 @@ preserves full fidelity information for both IDEs and procedural macros The *parser* [translates the token stream from the `lexer` into an Abstract Syntax Tree (AST)][parser]. It uses a recursive descent (top-down) approach to syntax analysis. The crate entry points for the `parser` are the -[`Parser::parse_crate_mod()`][parse_crate_mod] and [`Parser::parse_mod()`][parse_mod] +[`Parser::parse_crate_mod`][parse_crate_mod] and [`Parser::parse_mod`][parse_mod] methods found in [`rustc_parse::parser::Parser`]. The external module parsing entry point is [`rustc_expand::module::parse_external_mod`][parse_external_mod]. -And the macro-`parser` entry point is [`Parser::parse_nonterminal()`][parse_nonterminal]. +And the macro-`parser` entry point is [`Parser::parse_nonterminal`][parse_nonterminal]. Parsing is performed with a set of [`parser`] utility methods including [`bump`], [`check`], [`eat`], [`expect`], [`look_ahead`]. From 611becee8ca44af529774b34fd6c7dac537ed553 Mon Sep 17 00:00:00 2001 From: Redddy Date: Wed, 24 Dec 2025 21:58:59 +0900 Subject: [PATCH 0057/1061] Update 'Working groups' to 'Working areas' in docs --- src/doc/rustc-dev-guide/src/getting-started.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/getting-started.md b/src/doc/rustc-dev-guide/src/getting-started.md index 36d19e6c570e..6ccc5a75497a 100644 --- a/src/doc/rustc-dev-guide/src/getting-started.md +++ b/src/doc/rustc-dev-guide/src/getting-started.md @@ -179,7 +179,7 @@ The following tasks are doable without much background knowledge but are incredi to read a part of the code and write doc comments for it. This will help you to learn some part of the compiler while also producing a useful artifact! - [Triaging issues][triage]: categorizing, replicating, and minimizing issues is very helpful to the Rust maintainers. -- [Working groups][wg]: there are a bunch of working groups on a wide variety +- [Working areas][wa]: there are a bunch of working areas on a wide variety of rust-related things. - Answer questions on [users.rust-lang.org][users], or on [Stack Overflow][so]. - Participate in the [RFC process](https://github.com/rust-lang/rfcs). @@ -191,7 +191,7 @@ The following tasks are doable without much background knowledge but are incredi [so]: http://stackoverflow.com/questions/tagged/rust [community-library]: https://github.com/rust-lang/rfcs/labels/A-community-library [wd]: ./contributing.md#writing-documentation -[wg]: https://rust-lang.github.io/compiler-team/working-groups/ +[wa]: https://forge.rust-lang.org/compiler/working-areas.html [triage]: ./contributing.md#issue-triage ## Cloning and Building From 9f7dc2e474081a2a79c756abddf4dc367cc1d8cf Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Sun, 21 Dec 2025 20:49:36 +0000 Subject: [PATCH 0058/1061] Extract version check from ensure_version_or_cargo_install Define a new function ensure_version which is extracted (and modified) from ensure_version_or_cargo_install. --- src/tools/tidy/src/lib.rs | 47 ++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 756f9790e04a..1bbea81ff0fb 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -158,6 +158,27 @@ pub fn files_modified(ci_info: &CiInfo, pred: impl Fn(&str) -> bool) -> bool { !v.is_empty() } +/// Check if the given executable is installed and the version is expected. +pub fn ensure_version(build_dir: &Path, bin_name: &str, version: &str) -> io::Result { + let bin_path = build_dir.join("misc-tools").join("bin").join(bin_name); + + match Command::new(&bin_path).arg("--version").output() { + Ok(output) => { + let Some(v) = str::from_utf8(&output.stdout).unwrap().trim().split_whitespace().last() else { + return Err(io::Error::other("version check failed")); + }; + + if v != version { + eprintln!( + "warning: the tool `{bin_name}` is detected, but version {v} doesn't match with the expected version {version}" + ); + } + Ok(bin_path) + } + Err(e) => Err(e), + } +} + /// If the given executable is installed with the given version, use that, /// otherwise install via cargo. pub fn ensure_version_or_cargo_install( @@ -167,30 +188,16 @@ pub fn ensure_version_or_cargo_install( bin_name: &str, version: &str, ) -> io::Result { + if let Ok(bin_path) = ensure_version(build_dir, bin_name, version) { + return Ok(bin_path); + } + + eprintln!("building external tool {bin_name} from package {pkg_name}@{version}"); + let tool_root_dir = build_dir.join("misc-tools"); let tool_bin_dir = tool_root_dir.join("bin"); let bin_path = tool_bin_dir.join(bin_name).with_extension(env::consts::EXE_EXTENSION); - // ignore the process exit code here and instead just let the version number check fail. - // we also importantly don't return if the program wasn't installed, - // instead we want to continue to the fallback. - 'ck: { - // FIXME: rewrite as if-let chain once this crate is 2024 edition. - let Ok(output) = Command::new(&bin_path).arg("--version").output() else { - break 'ck; - }; - let Ok(s) = str::from_utf8(&output.stdout) else { - break 'ck; - }; - let Some(v) = s.trim().split_whitespace().last() else { - break 'ck; - }; - if v == version { - return Ok(bin_path); - } - } - - eprintln!("building external tool {bin_name} from package {pkg_name}@{version}"); // use --force to ensure that if the required version is bumped, we update it. // use --target-dir to ensure we have a build cache so repeated invocations aren't slow. // modify PATH so that cargo doesn't print a warning telling the user to modify the path. From b305a98349e2d661bc6169b33cdc1699557de8df Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Sun, 21 Dec 2025 20:49:41 +0000 Subject: [PATCH 0059/1061] implpement if_installed for spellcheck for other extra checks, it is WIP. --- src/tools/tidy/src/extra_checks/mod.rs | 65 ++++++++++++++++++++++---- src/tools/tidy/src/lib.rs | 3 +- 2 files changed, 57 insertions(+), 11 deletions(-) diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index a45af7fcf158..1304de16874d 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -23,8 +23,8 @@ use std::process::Command; use std::str::FromStr; use std::{fmt, fs, io}; -use crate::CiInfo; use crate::diagnostics::TidyCtx; +use crate::{CiInfo, ensure_version}; mod rustdoc_js; @@ -43,6 +43,7 @@ const RUFF_CACHE_PATH: &[&str] = &["cache", "ruff_cache"]; const PIP_REQ_PATH: &[&str] = &["src", "tools", "tidy", "config", "requirements.txt"]; const SPELLCHECK_DIRS: &[&str] = &["compiler", "library", "src/bootstrap", "src/librustdoc"]; +const SPELLCHECK_VER: &str = "1.38.1"; pub fn check( root_path: &Path, @@ -120,6 +121,9 @@ fn check_impl( ck.is_non_auto_or_matches(path) }); } + if lint_args.iter().any(|ck| ck.if_installed) { + lint_args.retain(|ck| ck.is_non_if_installed_or_matches(outdir)); + } macro_rules! extra_check { ($lang:ident, $kind:ident) => { @@ -620,8 +624,13 @@ fn spellcheck_runner( cargo: &Path, args: &[&str], ) -> Result<(), Error> { - let bin_path = - crate::ensure_version_or_cargo_install(outdir, cargo, "typos-cli", "typos", "1.38.1")?; + let bin_path = crate::ensure_version_or_cargo_install( + outdir, + cargo, + "typos-cli", + "typos", + SPELLCHECK_VER, + )?; match Command::new(bin_path).current_dir(src_root).args(args).status() { Ok(status) => { if status.success() { @@ -736,10 +745,14 @@ enum ExtraCheckParseError { Empty, /// `auto` specified without lang part. AutoRequiresLang, + /// `if-installed` specified without lang part. + IfInsatlledRequiresLang, } struct ExtraCheckArg { auto: bool, + /// Only run the check if the requisite software is already installed. + if_installed: bool, lang: ExtraCheckLang, /// None = run all extra checks for the given lang kind: Option, @@ -750,6 +763,19 @@ impl ExtraCheckArg { self.lang == lang && self.kind.map(|k| k == kind).unwrap_or(true) } + fn is_non_if_installed_or_matches(&self, build_dir: &Path) -> bool { + if !self.if_installed { + return true; + } + + match self.lang { + ExtraCheckLang::Spellcheck => { + ensure_version(build_dir, "typos", SPELLCHECK_VER).is_ok() + } + _ => todo!("implement other checks"), + } + } + /// Returns `false` if this is an auto arg and the passed filename does not trigger the auto rule fn is_non_auto_or_matches(&self, filepath: &str) -> bool { if !self.auto { @@ -792,22 +818,41 @@ impl FromStr for ExtraCheckArg { fn from_str(s: &str) -> Result { let mut auto = false; + let mut if_installed = false; let mut parts = s.split(':'); let Some(mut first) = parts.next() else { return Err(ExtraCheckParseError::Empty); }; - if first == "auto" { - let Some(part) = parts.next() else { - return Err(ExtraCheckParseError::AutoRequiresLang); - }; - auto = true; - first = part; + loop { + if !auto && first == "auto" { + let Some(part) = parts.next() else { + return Err(ExtraCheckParseError::AutoRequiresLang); + }; + auto = true; + first = part; + continue; + } + + if !if_installed && first == "if-installed" { + let Some(part) = parts.next() else { + return Err(ExtraCheckParseError::IfInsatlledRequiresLang); + }; + if_installed = true; + first = part; + continue; + } + break; } let second = parts.next(); if parts.next().is_some() { return Err(ExtraCheckParseError::TooManyParts); } - let arg = Self { auto, lang: first.parse()?, kind: second.map(|s| s.parse()).transpose()? }; + let arg = Self { + auto, + if_installed, + lang: first.parse()?, + kind: second.map(|s| s.parse()).transpose()?, + }; if !arg.has_supported_kind() { return Err(ExtraCheckParseError::UnsupportedKindForLang); } diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 1bbea81ff0fb..62da0191da9e 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -164,7 +164,8 @@ pub fn ensure_version(build_dir: &Path, bin_name: &str, version: &str) -> io::Re match Command::new(&bin_path).arg("--version").output() { Ok(output) => { - let Some(v) = str::from_utf8(&output.stdout).unwrap().trim().split_whitespace().last() else { + let Some(v) = str::from_utf8(&output.stdout).unwrap().trim().split_whitespace().last() + else { return Err(io::Error::other("version check failed")); }; From 40be1f8bc53e7815b7a229e8b3a2945353de3207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 25 Dec 2025 20:56:03 +0000 Subject: [PATCH 0060/1061] Tweak wording of diff marker diagnostic --- .../rustc_parse/src/parser/diagnostics.rs | 35 ++++++++++--------- tests/ui/parser/diff-markers/enum-2.stderr | 11 +++--- tests/ui/parser/diff-markers/enum.stderr | 11 +++--- tests/ui/parser/diff-markers/fn-arg.stderr | 11 +++--- .../parser/diff-markers/item-with-attr.stderr | 11 +++--- tests/ui/parser/diff-markers/item.stderr | 11 +++--- tests/ui/parser/diff-markers/statement.stderr | 11 +++--- .../ui/parser/diff-markers/struct-expr.stderr | 11 +++--- tests/ui/parser/diff-markers/struct.stderr | 11 +++--- .../ui/parser/diff-markers/trait-item.stderr | 11 +++--- .../parser/diff-markers/tuple-struct.stderr | 11 +++--- .../parser/diff-markers/use-statement.stderr | 11 +++--- 12 files changed, 62 insertions(+), 94 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index d7d343ac16b4..70ec80a50812 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -3084,22 +3084,24 @@ impl<'a> Parser<'a> { } let mut err = self.dcx().struct_span_fatal(spans, "encountered diff marker"); - match middlediff3 { + let middle_marker = match middlediff3 { // We're using diff3 Some(middlediff3) => { err.span_label( - start, - "between this marker and `|||||||` is the code that we're merging into", - ); - err.span_label(middlediff3, "between this marker and `=======` is the base code (what the two refs diverged from)"); - } - None => { - err.span_label( - start, - "between this marker and `=======` is the code that we're merging into", + middlediff3, + "between this marker and `=======` is the base code (what the two refs \ + diverged from)", ); + "|||||||" } + None => "=======", }; + err.span_label( + start, + format!( + "between this marker and `{middle_marker}` is the code that you are merging into", + ), + ); if let Some(middle) = middle { err.span_label(middle, "between this marker and `>>>>>>>` is the incoming code"); @@ -3114,16 +3116,15 @@ impl<'a> Parser<'a> { containing conflict markers", ); err.help( - "if you're having merge conflicts after pulling new code:\n\ - the top section is the code you already had and the bottom section is the remote code\n\ - if you're in the middle of a rebase:\n\ - the top section is the code being rebased onto and the bottom section is the code \ - coming from the current commit being rebased", + "if you are in a merge, the top section is the code you already had checked out and \ + the bottom section is the new code\n\ + if you are in a rebase, the top section is the code being rebased onto and the bottom \ + section is the code you had checked out which is being rebased", ); err.note( - "for an explanation on these markers from the `git` documentation:\n\ - visit ", + "for an explanation on these markers from the `git` documentation, visit \ + ", ); err.emit(); diff --git a/tests/ui/parser/diff-markers/enum-2.stderr b/tests/ui/parser/diff-markers/enum-2.stderr index b76cf5d5a01e..8f20e70922f9 100644 --- a/tests/ui/parser/diff-markers/enum-2.stderr +++ b/tests/ui/parser/diff-markers/enum-2.stderr @@ -2,7 +2,7 @@ error: encountered diff marker --> $DIR/enum-2.rs:3:1 | LL | <<<<<<< HEAD - | ^^^^^^^ between this marker and `|||||||` is the code that we're merging into + | ^^^^^^^ between this marker and `|||||||` is the code that you are merging into LL | x: u8, LL | ||||||| | ------- between this marker and `=======` is the base code (what the two refs diverged from) @@ -15,12 +15,9 @@ LL | >>>>>>> branch | = note: conflict markers indicate that a merge was started but could not be completed due to merge conflicts to resolve a conflict, keep only the code you want and then delete the lines containing conflict markers - = help: if you're having merge conflicts after pulling new code: - the top section is the code you already had and the bottom section is the remote code - if you're in the middle of a rebase: - the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased - = note: for an explanation on these markers from the `git` documentation: - visit + = help: if you are in a merge, the top section is the code you already had checked out and the bottom section is the new code + if you are in a rebase, the top section is the code being rebased onto and the bottom section is the code you had checked out which is being rebased + = note: for an explanation on these markers from the `git` documentation, visit error: aborting due to 1 previous error diff --git a/tests/ui/parser/diff-markers/enum.stderr b/tests/ui/parser/diff-markers/enum.stderr index 0ce473bc7023..67f7561fd77b 100644 --- a/tests/ui/parser/diff-markers/enum.stderr +++ b/tests/ui/parser/diff-markers/enum.stderr @@ -2,7 +2,7 @@ error: encountered diff marker --> $DIR/enum.rs:2:1 | LL | <<<<<<< HEAD - | ^^^^^^^ between this marker and `=======` is the code that we're merging into + | ^^^^^^^ between this marker and `=======` is the code that you are merging into LL | Foo(u8), LL | ======= | ------- between this marker and `>>>>>>>` is the incoming code @@ -12,12 +12,9 @@ LL | >>>>>>> branch | = note: conflict markers indicate that a merge was started but could not be completed due to merge conflicts to resolve a conflict, keep only the code you want and then delete the lines containing conflict markers - = help: if you're having merge conflicts after pulling new code: - the top section is the code you already had and the bottom section is the remote code - if you're in the middle of a rebase: - the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased - = note: for an explanation on these markers from the `git` documentation: - visit + = help: if you are in a merge, the top section is the code you already had checked out and the bottom section is the new code + if you are in a rebase, the top section is the code being rebased onto and the bottom section is the code you had checked out which is being rebased + = note: for an explanation on these markers from the `git` documentation, visit error: aborting due to 1 previous error diff --git a/tests/ui/parser/diff-markers/fn-arg.stderr b/tests/ui/parser/diff-markers/fn-arg.stderr index 24521ffa6262..e63592ecf426 100644 --- a/tests/ui/parser/diff-markers/fn-arg.stderr +++ b/tests/ui/parser/diff-markers/fn-arg.stderr @@ -2,7 +2,7 @@ error: encountered diff marker --> $DIR/fn-arg.rs:3:1 | LL | <<<<<<< HEAD - | ^^^^^^^ between this marker and `=======` is the code that we're merging into + | ^^^^^^^ between this marker and `=======` is the code that you are merging into LL | x: u8, LL | ======= | ------- between this marker and `>>>>>>>` is the incoming code @@ -12,12 +12,9 @@ LL | >>>>>>> branch | = note: conflict markers indicate that a merge was started but could not be completed due to merge conflicts to resolve a conflict, keep only the code you want and then delete the lines containing conflict markers - = help: if you're having merge conflicts after pulling new code: - the top section is the code you already had and the bottom section is the remote code - if you're in the middle of a rebase: - the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased - = note: for an explanation on these markers from the `git` documentation: - visit + = help: if you are in a merge, the top section is the code you already had checked out and the bottom section is the new code + if you are in a rebase, the top section is the code being rebased onto and the bottom section is the code you had checked out which is being rebased + = note: for an explanation on these markers from the `git` documentation, visit error: aborting due to 1 previous error diff --git a/tests/ui/parser/diff-markers/item-with-attr.stderr b/tests/ui/parser/diff-markers/item-with-attr.stderr index 432673cd5518..29dbfab16fda 100644 --- a/tests/ui/parser/diff-markers/item-with-attr.stderr +++ b/tests/ui/parser/diff-markers/item-with-attr.stderr @@ -2,7 +2,7 @@ error: encountered diff marker --> $DIR/item-with-attr.rs:2:1 | LL | <<<<<<< HEAD - | ^^^^^^^ between this marker and `=======` is the code that we're merging into + | ^^^^^^^ between this marker and `=======` is the code that you are merging into LL | fn foo() {} LL | ======= | ------- between this marker and `>>>>>>>` is the incoming code @@ -12,12 +12,9 @@ LL | >>>>>>> branch | = note: conflict markers indicate that a merge was started but could not be completed due to merge conflicts to resolve a conflict, keep only the code you want and then delete the lines containing conflict markers - = help: if you're having merge conflicts after pulling new code: - the top section is the code you already had and the bottom section is the remote code - if you're in the middle of a rebase: - the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased - = note: for an explanation on these markers from the `git` documentation: - visit + = help: if you are in a merge, the top section is the code you already had checked out and the bottom section is the new code + if you are in a rebase, the top section is the code being rebased onto and the bottom section is the code you had checked out which is being rebased + = note: for an explanation on these markers from the `git` documentation, visit error: aborting due to 1 previous error diff --git a/tests/ui/parser/diff-markers/item.stderr b/tests/ui/parser/diff-markers/item.stderr index 180c74e5d696..8de41123c9e9 100644 --- a/tests/ui/parser/diff-markers/item.stderr +++ b/tests/ui/parser/diff-markers/item.stderr @@ -2,7 +2,7 @@ error: encountered diff marker --> $DIR/item.rs:1:1 | LL | <<<<<<< HEAD - | ^^^^^^^ between this marker and `=======` is the code that we're merging into + | ^^^^^^^ between this marker and `=======` is the code that you are merging into LL | fn foo() {} LL | ======= | ------- between this marker and `>>>>>>>` is the incoming code @@ -12,12 +12,9 @@ LL | >>>>>>> branch | = note: conflict markers indicate that a merge was started but could not be completed due to merge conflicts to resolve a conflict, keep only the code you want and then delete the lines containing conflict markers - = help: if you're having merge conflicts after pulling new code: - the top section is the code you already had and the bottom section is the remote code - if you're in the middle of a rebase: - the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased - = note: for an explanation on these markers from the `git` documentation: - visit + = help: if you are in a merge, the top section is the code you already had checked out and the bottom section is the new code + if you are in a rebase, the top section is the code being rebased onto and the bottom section is the code you had checked out which is being rebased + = note: for an explanation on these markers from the `git` documentation, visit error: aborting due to 1 previous error diff --git a/tests/ui/parser/diff-markers/statement.stderr b/tests/ui/parser/diff-markers/statement.stderr index 6dccce4a48ee..5b5da0ede615 100644 --- a/tests/ui/parser/diff-markers/statement.stderr +++ b/tests/ui/parser/diff-markers/statement.stderr @@ -2,7 +2,7 @@ error: encountered diff marker --> $DIR/statement.rs:10:1 | LL | <<<<<<< HEAD - | ^^^^^^^ between this marker and `=======` is the code that we're merging into + | ^^^^^^^ between this marker and `=======` is the code that you are merging into LL | S::foo(); LL | ======= | ------- between this marker and `>>>>>>>` is the incoming code @@ -12,12 +12,9 @@ LL | >>>>>>> branch | = note: conflict markers indicate that a merge was started but could not be completed due to merge conflicts to resolve a conflict, keep only the code you want and then delete the lines containing conflict markers - = help: if you're having merge conflicts after pulling new code: - the top section is the code you already had and the bottom section is the remote code - if you're in the middle of a rebase: - the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased - = note: for an explanation on these markers from the `git` documentation: - visit + = help: if you are in a merge, the top section is the code you already had checked out and the bottom section is the new code + if you are in a rebase, the top section is the code being rebased onto and the bottom section is the code you had checked out which is being rebased + = note: for an explanation on these markers from the `git` documentation, visit error: aborting due to 1 previous error diff --git a/tests/ui/parser/diff-markers/struct-expr.stderr b/tests/ui/parser/diff-markers/struct-expr.stderr index 3733cdd34964..d094cbcc9e8c 100644 --- a/tests/ui/parser/diff-markers/struct-expr.stderr +++ b/tests/ui/parser/diff-markers/struct-expr.stderr @@ -2,7 +2,7 @@ error: encountered diff marker --> $DIR/struct-expr.rs:6:1 | LL | <<<<<<< HEAD - | ^^^^^^^ between this marker and `=======` is the code that we're merging into + | ^^^^^^^ between this marker and `=======` is the code that you are merging into LL | x: 42, LL | ======= | ------- between this marker and `>>>>>>>` is the incoming code @@ -12,12 +12,9 @@ LL | >>>>>>> branch | = note: conflict markers indicate that a merge was started but could not be completed due to merge conflicts to resolve a conflict, keep only the code you want and then delete the lines containing conflict markers - = help: if you're having merge conflicts after pulling new code: - the top section is the code you already had and the bottom section is the remote code - if you're in the middle of a rebase: - the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased - = note: for an explanation on these markers from the `git` documentation: - visit + = help: if you are in a merge, the top section is the code you already had checked out and the bottom section is the new code + if you are in a rebase, the top section is the code being rebased onto and the bottom section is the code you had checked out which is being rebased + = note: for an explanation on these markers from the `git` documentation, visit error: aborting due to 1 previous error diff --git a/tests/ui/parser/diff-markers/struct.stderr b/tests/ui/parser/diff-markers/struct.stderr index 44f8346613e6..33999ff92b93 100644 --- a/tests/ui/parser/diff-markers/struct.stderr +++ b/tests/ui/parser/diff-markers/struct.stderr @@ -2,7 +2,7 @@ error: encountered diff marker --> $DIR/struct.rs:2:1 | LL | <<<<<<< HEAD - | ^^^^^^^ between this marker and `=======` is the code that we're merging into + | ^^^^^^^ between this marker and `=======` is the code that you are merging into LL | x: u8, LL | ======= | ------- between this marker and `>>>>>>>` is the incoming code @@ -12,12 +12,9 @@ LL | >>>>>>> branch | = note: conflict markers indicate that a merge was started but could not be completed due to merge conflicts to resolve a conflict, keep only the code you want and then delete the lines containing conflict markers - = help: if you're having merge conflicts after pulling new code: - the top section is the code you already had and the bottom section is the remote code - if you're in the middle of a rebase: - the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased - = note: for an explanation on these markers from the `git` documentation: - visit + = help: if you are in a merge, the top section is the code you already had checked out and the bottom section is the new code + if you are in a rebase, the top section is the code being rebased onto and the bottom section is the code you had checked out which is being rebased + = note: for an explanation on these markers from the `git` documentation, visit error: aborting due to 1 previous error diff --git a/tests/ui/parser/diff-markers/trait-item.stderr b/tests/ui/parser/diff-markers/trait-item.stderr index 4361542c7743..6b89b800790c 100644 --- a/tests/ui/parser/diff-markers/trait-item.stderr +++ b/tests/ui/parser/diff-markers/trait-item.stderr @@ -2,7 +2,7 @@ error: encountered diff marker --> $DIR/trait-item.rs:2:1 | LL | <<<<<<< HEAD - | ^^^^^^^ between this marker and `=======` is the code that we're merging into + | ^^^^^^^ between this marker and `=======` is the code that you are merging into LL | fn foo() {} LL | ======= | ------- between this marker and `>>>>>>>` is the incoming code @@ -12,12 +12,9 @@ LL | >>>>>>> branch | = note: conflict markers indicate that a merge was started but could not be completed due to merge conflicts to resolve a conflict, keep only the code you want and then delete the lines containing conflict markers - = help: if you're having merge conflicts after pulling new code: - the top section is the code you already had and the bottom section is the remote code - if you're in the middle of a rebase: - the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased - = note: for an explanation on these markers from the `git` documentation: - visit + = help: if you are in a merge, the top section is the code you already had checked out and the bottom section is the new code + if you are in a rebase, the top section is the code being rebased onto and the bottom section is the code you had checked out which is being rebased + = note: for an explanation on these markers from the `git` documentation, visit error: aborting due to 1 previous error diff --git a/tests/ui/parser/diff-markers/tuple-struct.stderr b/tests/ui/parser/diff-markers/tuple-struct.stderr index 7fda24ba4853..a0c8b7f3700a 100644 --- a/tests/ui/parser/diff-markers/tuple-struct.stderr +++ b/tests/ui/parser/diff-markers/tuple-struct.stderr @@ -2,7 +2,7 @@ error: encountered diff marker --> $DIR/tuple-struct.rs:2:1 | LL | <<<<<<< HEAD - | ^^^^^^^ between this marker and `=======` is the code that we're merging into + | ^^^^^^^ between this marker and `=======` is the code that you are merging into LL | u8, LL | ======= | ------- between this marker and `>>>>>>>` is the incoming code @@ -12,12 +12,9 @@ LL | >>>>>>> branch | = note: conflict markers indicate that a merge was started but could not be completed due to merge conflicts to resolve a conflict, keep only the code you want and then delete the lines containing conflict markers - = help: if you're having merge conflicts after pulling new code: - the top section is the code you already had and the bottom section is the remote code - if you're in the middle of a rebase: - the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased - = note: for an explanation on these markers from the `git` documentation: - visit + = help: if you are in a merge, the top section is the code you already had checked out and the bottom section is the new code + if you are in a rebase, the top section is the code being rebased onto and the bottom section is the code you had checked out which is being rebased + = note: for an explanation on these markers from the `git` documentation, visit error: aborting due to 1 previous error diff --git a/tests/ui/parser/diff-markers/use-statement.stderr b/tests/ui/parser/diff-markers/use-statement.stderr index 3eac7bebb5af..640f88f98057 100644 --- a/tests/ui/parser/diff-markers/use-statement.stderr +++ b/tests/ui/parser/diff-markers/use-statement.stderr @@ -2,7 +2,7 @@ error: encountered diff marker --> $DIR/use-statement.rs:2:1 | LL | <<<<<<< HEAD - | ^^^^^^^ between this marker and `=======` is the code that we're merging into + | ^^^^^^^ between this marker and `=======` is the code that you are merging into LL | bar, LL | ======= | ------- between this marker and `>>>>>>>` is the incoming code @@ -12,12 +12,9 @@ LL | >>>>>>> branch | = note: conflict markers indicate that a merge was started but could not be completed due to merge conflicts to resolve a conflict, keep only the code you want and then delete the lines containing conflict markers - = help: if you're having merge conflicts after pulling new code: - the top section is the code you already had and the bottom section is the remote code - if you're in the middle of a rebase: - the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased - = note: for an explanation on these markers from the `git` documentation: - visit + = help: if you are in a merge, the top section is the code you already had checked out and the bottom section is the new code + if you are in a rebase, the top section is the code being rebased onto and the bottom section is the code you had checked out which is being rebased + = note: for an explanation on these markers from the `git` documentation, visit error: aborting due to 1 previous error From 54e9e8cd3872be7ccf9e3b04559ea61441f258a8 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 25 Dec 2025 23:24:43 +0100 Subject: [PATCH 0061/1061] Merge commit '99edcadfd5f6f6e8da34b1ba62774b53f5ca3863' into clippy-subtree-update --- .github/workflows/clippy_dev.yml | 2 +- .github/workflows/clippy_pr.yml | 2 +- .github/workflows/remark.yml | 4 +- CHANGELOG.md | 1 + clippy_dev/Cargo.toml | 1 + clippy_dev/src/lib.rs | 1 - clippy_lints/src/assertions_on_constants.rs | 2 + clippy_lints/src/booleans.rs | 2 +- clippy_lints/src/casts/cast_precision_loss.rs | 22 +- clippy_lints/src/casts/mod.rs | 2 +- clippy_lints/src/casts/needless_type_cast.rs | 66 ++- clippy_lints/src/casts/ref_as_ptr.rs | 16 +- clippy_lints/src/collapsible_if.rs | 18 +- clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/disallowed_methods.rs | 3 + clippy_lints/src/empty_with_brackets.rs | 202 ++++--- clippy_lints/src/entry.rs | 8 +- clippy_lints/src/fallible_impl_from.rs | 2 +- clippy_lints/src/format_push_string.rs | 209 +++++-- clippy_lints/src/functions/mod.rs | 4 + clippy_lints/src/functions/result.rs | 43 +- clippy_lints/src/if_not_else.rs | 37 +- clippy_lints/src/if_then_some_else_none.rs | 32 +- clippy_lints/src/ifs/branches_sharing_code.rs | 75 ++- clippy_lints/src/implicit_hasher.rs | 23 +- clippy_lints/src/lib.rs | 7 +- clippy_lints/src/loops/for_kv_map.rs | 2 +- clippy_lints/src/loops/mod.rs | 46 +- clippy_lints/src/loops/never_loop.rs | 33 +- .../src/loops/unused_enumerate_index.rs | 12 +- clippy_lints/src/manual_let_else.rs | 2 +- .../src/matches/match_like_matches.rs | 18 +- clippy_lints/src/matches/match_wild_enum.rs | 2 +- clippy_lints/src/methods/expect_fun_call.rs | 10 +- clippy_lints/src/methods/iter_count.rs | 31 +- clippy_lints/src/methods/iter_kv_map.rs | 2 +- .../src/methods/join_absolute_paths.rs | 2 +- clippy_lints/src/methods/map_clone.rs | 2 +- clippy_lints/src/methods/map_unwrap_or.rs | 12 +- clippy_lints/src/methods/needless_collect.rs | 4 +- .../src/methods/obfuscated_if_else.rs | 16 +- clippy_lints/src/methods/or_then_unwrap.rs | 38 +- clippy_lints/src/methods/unnecessary_fold.rs | 179 +++--- .../src/methods/unnecessary_get_then_check.rs | 4 +- .../src/methods/unwrap_expect_used.rs | 24 +- clippy_lints/src/missing_fields_in_debug.rs | 12 +- .../src/multiple_unsafe_ops_per_block.rs | 70 ++- clippy_lints/src/needless_pass_by_ref_mut.rs | 21 +- clippy_lints/src/ptr/cmp_null.rs | 7 +- clippy_lints/src/ptr/mod.rs | 4 +- clippy_lints/src/same_length_and_capacity.rs | 105 ++++ clippy_lints/src/set_contains_or_insert.rs | 21 +- clippy_lints/src/time_subtraction.rs | 65 +- .../src/transmute/transmuting_null.rs | 9 +- clippy_lints/src/use_self.rs | 36 +- clippy_lints/src/write/empty_string.rs | 42 +- clippy_lints/src/zero_sized_map_values.rs | 2 +- .../src/almost_standard_lint_formulation.rs | 35 +- clippy_lints_internal/src/internal_paths.rs | 1 + clippy_lints_internal/src/lib.rs | 2 + .../src/repeated_is_diagnostic_item.rs | 561 ++++++++++++++++++ clippy_utils/README.md | 2 +- clippy_utils/src/attrs.rs | 2 +- clippy_utils/src/consts.rs | 14 +- clippy_utils/src/hir_utils.rs | 233 +++++++- clippy_utils/src/lib.rs | 3 +- clippy_utils/src/source.rs | 4 +- clippy_utils/src/sym.rs | 7 + rust-toolchain.toml | 2 +- .../repeated_is_diagnostic_item.fixed | 77 +++ .../repeated_is_diagnostic_item.rs | 77 +++ .../repeated_is_diagnostic_item.stderr | 82 +++ .../repeated_is_diagnostic_item_unfixable.rs | 213 +++++++ ...peated_is_diagnostic_item_unfixable.stderr | 374 ++++++++++++ .../collapsible_if/collapsible_else_if.fixed | 2 +- .../collapsible_if/collapsible_else_if.rs | 2 +- .../needless_pass_by_ref_mut.fixed | 2 +- .../needless_pass_by_ref_mut.rs | 2 +- .../needless_pass_by_ref_mut.stderr | 6 +- .../toml_disallowed_methods/clippy.toml | 2 + .../conf_disallowed_methods.rs | 16 + .../conf_disallowed_methods.stderr | 8 +- tests/ui/assertions_on_constants.rs | 5 + .../branches_sharing_code/shared_at_bottom.rs | 62 ++ .../shared_at_bottom.stderr | 70 ++- tests/ui/cast.stderr | 12 +- tests/ui/cast_size.r32bit.stderr | 12 +- tests/ui/cast_size.r64bit.stderr | 12 +- tests/ui/cmp_null.fixed | 20 + tests/ui/cmp_null.rs | 20 + tests/ui/cmp_null.stderr | 8 +- tests/ui/collapsible_else_if.fixed | 48 +- tests/ui/collapsible_else_if.rs | 50 +- tests/ui/collapsible_else_if.stderr | 24 +- tests/ui/crashes/ice-10148.stderr | 2 +- tests/ui/crashes/ice-7410.rs | 2 +- tests/ui/def_id_nocore.rs | 2 - tests/ui/def_id_nocore.stderr | 2 +- .../empty_enum_variants_with_brackets.fixed | 59 ++ tests/ui/empty_enum_variants_with_brackets.rs | 59 ++ .../empty_enum_variants_with_brackets.stderr | 67 ++- tests/ui/empty_loop_no_std.rs | 2 - tests/ui/empty_loop_no_std.stderr | 2 +- tests/ui/entry.fixed | 10 + tests/ui/entry.rs | 10 + tests/ui/entry.stderr | 23 +- tests/ui/format_push_string.fixed | 132 +++++ tests/ui/format_push_string.rs | 140 ++++- tests/ui/format_push_string.stderr | 205 +++++-- tests/ui/format_push_string_no_core.rs | 15 + tests/ui/format_push_string_no_std.fixed | 15 + tests/ui/format_push_string_no_std.rs | 15 + tests/ui/format_push_string_no_std.stderr | 17 + .../ui/format_push_string_no_std_unfixable.rs | 13 + ...format_push_string_no_std_unfixable.stderr | 17 + tests/ui/format_push_string_unfixable.rs | 144 +++++ tests/ui/format_push_string_unfixable.stderr | 233 ++++++++ tests/ui/if_not_else.fixed | 17 + tests/ui/if_not_else.rs | 17 + tests/ui/if_not_else.stderr | 44 +- tests/ui/if_then_some_else_none.fixed | 52 +- tests/ui/if_then_some_else_none.rs | 23 + tests/ui/if_then_some_else_none.stderr | 78 ++- tests/ui/manual_instant_elapsed.fixed | 16 + tests/ui/manual_instant_elapsed.rs | 16 + tests/ui/manual_instant_elapsed.stderr | 14 +- tests/ui/map_unwrap_or.stderr | 29 + tests/ui/match_like_matches_macro.fixed | 22 + tests/ui/match_like_matches_macro.rs | 25 + tests/ui/match_like_matches_macro.stderr | 62 +- tests/ui/multiple_unsafe_ops_per_block.rs | 133 +++++ tests/ui/multiple_unsafe_ops_per_block.stderr | 257 ++++++-- tests/ui/needless_collect.fixed | 5 + tests/ui/needless_collect.rs | 5 + tests/ui/needless_pass_by_ref_mut.stderr | 204 ++++--- tests/ui/needless_pass_by_ref_mut2.fixed | 6 + tests/ui/needless_pass_by_ref_mut2.rs | 6 + tests/ui/needless_pass_by_ref_mut2.stderr | 22 +- tests/ui/needless_type_cast.fixed | 87 +++ tests/ui/needless_type_cast.rs | 87 +++ tests/ui/needless_type_cast.stderr | 114 +++- tests/ui/needless_type_cast_unfixable.rs | 20 + tests/ui/needless_type_cast_unfixable.stderr | 17 + tests/ui/never_loop_iterator_reduction.rs | 17 + tests/ui/never_loop_iterator_reduction.stderr | 27 + tests/ui/obfuscated_if_else.fixed | 6 + tests/ui/obfuscated_if_else.rs | 6 + tests/ui/obfuscated_if_else.stderr | 8 +- tests/ui/println_empty_string.fixed | 20 + tests/ui/println_empty_string.rs | 24 + tests/ui/println_empty_string.stderr | 39 +- tests/ui/println_empty_string_unfixable.rs | 30 + .../ui/println_empty_string_unfixable.stderr | 85 +++ tests/ui/ref_as_ptr.fixed | 10 + tests/ui/ref_as_ptr.rs | 10 + tests/ui/ref_as_ptr.stderr | 60 +- tests/ui/result_large_err.rs | 9 + tests/ui/result_large_err.stderr | 18 +- tests/ui/same_length_and_capacity.rs | 27 + tests/ui/same_length_and_capacity.stderr | 20 + tests/ui/set_contains_or_insert.rs | 21 + tests/ui/set_contains_or_insert.stderr | 11 +- tests/ui/track-diagnostics.rs | 1 + tests/ui/transmuting_null.rs | 8 + tests/ui/transmuting_null.stderr | 8 +- tests/ui/unchecked_time_subtraction.fixed | 25 + tests/ui/unchecked_time_subtraction.rs | 25 + tests/ui/unchecked_time_subtraction.stderr | 26 +- tests/ui/unnecessary_fold.fixed | 85 +++ tests/ui/unnecessary_fold.rs | 85 +++ tests/ui/unnecessary_fold.stderr | 130 +++- tests/ui/use_self.fixed | 25 + tests/ui/use_self.rs | 25 + tests/ui/use_self.stderr | 84 +-- tests/ui/writeln_empty_string_unfixable.rs | 26 + .../ui/writeln_empty_string_unfixable.stderr | 47 ++ triagebot.toml | 1 + 177 files changed, 6336 insertions(+), 967 deletions(-) create mode 100644 clippy_lints/src/same_length_and_capacity.rs create mode 100644 clippy_lints_internal/src/repeated_is_diagnostic_item.rs create mode 100644 tests/ui-internal/repeated_is_diagnostic_item.fixed create mode 100644 tests/ui-internal/repeated_is_diagnostic_item.rs create mode 100644 tests/ui-internal/repeated_is_diagnostic_item.stderr create mode 100644 tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs create mode 100644 tests/ui-internal/repeated_is_diagnostic_item_unfixable.stderr create mode 100644 tests/ui/format_push_string.fixed create mode 100644 tests/ui/format_push_string_no_core.rs create mode 100644 tests/ui/format_push_string_no_std.fixed create mode 100644 tests/ui/format_push_string_no_std.rs create mode 100644 tests/ui/format_push_string_no_std.stderr create mode 100644 tests/ui/format_push_string_no_std_unfixable.rs create mode 100644 tests/ui/format_push_string_no_std_unfixable.stderr create mode 100644 tests/ui/format_push_string_unfixable.rs create mode 100644 tests/ui/format_push_string_unfixable.stderr create mode 100644 tests/ui/needless_type_cast_unfixable.rs create mode 100644 tests/ui/needless_type_cast_unfixable.stderr create mode 100644 tests/ui/never_loop_iterator_reduction.rs create mode 100644 tests/ui/never_loop_iterator_reduction.stderr create mode 100644 tests/ui/println_empty_string_unfixable.rs create mode 100644 tests/ui/println_empty_string_unfixable.stderr create mode 100644 tests/ui/same_length_and_capacity.rs create mode 100644 tests/ui/same_length_and_capacity.stderr create mode 100644 tests/ui/writeln_empty_string_unfixable.rs create mode 100644 tests/ui/writeln_empty_string_unfixable.stderr diff --git a/.github/workflows/clippy_dev.yml b/.github/workflows/clippy_dev.yml index d530eb6c73a3..3a99d65233d3 100644 --- a/.github/workflows/clippy_dev.yml +++ b/.github/workflows/clippy_dev.yml @@ -16,7 +16,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false diff --git a/.github/workflows/clippy_pr.yml b/.github/workflows/clippy_pr.yml index d91c638a8fb5..f9e882d9757c 100644 --- a/.github/workflows/clippy_pr.yml +++ b/.github/workflows/clippy_pr.yml @@ -24,7 +24,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false diff --git a/.github/workflows/remark.yml b/.github/workflows/remark.yml index 03641a9aa62f..d4dc80efe79d 100644 --- a/.github/workflows/remark.yml +++ b/.github/workflows/remark.yml @@ -20,9 +20,9 @@ jobs: persist-credentials: false - name: Setup Node.js - uses: actions/setup-node@v5 + uses: actions/setup-node@v6 with: - node-version: '20.x' + node-version: '24.x' - name: Install remark run: npm install remark-cli remark-lint remark-lint-maximum-line-length@^3.1.3 remark-preset-lint-recommended remark-gfm diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f666caf306f..91d793489be2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6916,6 +6916,7 @@ Released 2018-09-13 [`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges [`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition [`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push +[`same_length_and_capacity`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_length_and_capacity [`same_name_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_name_method [`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some [`seek_from_current`]: https://rust-lang.github.io/rust-clippy/master/index.html#seek_from_current diff --git a/clippy_dev/Cargo.toml b/clippy_dev/Cargo.toml index 10c08dba50b9..c2abbac37535 100644 --- a/clippy_dev/Cargo.toml +++ b/clippy_dev/Cargo.toml @@ -10,6 +10,7 @@ clap = { version = "4.4", features = ["derive"] } indoc = "1.0" itertools = "0.12" opener = "0.7" +rustc-literal-escaper = "0.0.5" walkdir = "2.3" [package.metadata.rust-analyzer] diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index dcca08aee7e6..cd103908be03 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -22,7 +22,6 @@ extern crate rustc_arena; #[expect(unused_extern_crates, reason = "required to link to rustc crates")] extern crate rustc_driver; extern crate rustc_lexer; -extern crate rustc_literal_escaper; pub mod deprecate_lint; pub mod dogfood; diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index 2586c89bc868..4aa55e53445c 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -3,6 +3,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::macros::{find_assert_args, root_macro_call_first_node}; use clippy_utils::msrvs::Msrv; +use clippy_utils::visitors::is_const_evaluatable; use clippy_utils::{is_inside_always_const_context, msrvs}; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; @@ -50,6 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { _ => return, } && let Some((condition, _)) = find_assert_args(cx, e, macro_call.expn) + && is_const_evaluatable(cx, condition) && let Some((Constant::Bool(assert_val), const_src)) = ConstEvalCtxt::new(cx).eval_with_source(condition, macro_call.span.ctxt()) && let in_const_context = is_inside_always_const_context(cx.tcx, e.hir_id) diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 902ba70577b9..a04a56d72bc0 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -433,7 +433,7 @@ fn simplify_not(cx: &LateContext<'_>, curr_msrv: Msrv, expr: &Expr<'_>) -> Optio }, ExprKind::MethodCall(path, receiver, args, _) => { let type_of_receiver = cx.typeck_results().expr_ty(receiver); - if !type_of_receiver.is_diag_item(cx, sym::Option) && !type_of_receiver.is_diag_item(cx, sym::Result) { + if !matches!(type_of_receiver.opt_diag_name(cx), Some(sym::Option | sym::Result)) { return None; } METHODS_WITH_NEGATION diff --git a/clippy_lints/src/casts/cast_precision_loss.rs b/clippy_lints/src/casts/cast_precision_loss.rs index 712e38db499f..748ab3163496 100644 --- a/clippy_lints/src/casts/cast_precision_loss.rs +++ b/clippy_lints/src/casts/cast_precision_loss.rs @@ -23,15 +23,11 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca let cast_to_f64 = to_nbits == 64; let mantissa_nbits = if cast_to_f64 { 52 } else { 23 }; - let arch_dependent = is_isize_or_usize(cast_from) && cast_to_f64; - let arch_dependent_str = "on targets with 64-bit wide pointers "; - let from_nbits_str = if arch_dependent { - "64".to_owned() - } else if is_isize_or_usize(cast_from) { - // FIXME: handle 16 bits `usize` type - "32 or 64".to_owned() + + let has_width = if is_isize_or_usize(cast_from) { + "can be up to 64 bits wide depending on the target architecture".to_owned() } else { - from_nbits.to_string() + format!("is {from_nbits} bits wide") }; span_lint( @@ -39,13 +35,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca CAST_PRECISION_LOSS, expr.span, format!( - "casting `{0}` to `{1}` causes a loss of precision {2}(`{0}` is {3} bits wide, \ - but `{1}`'s mantissa is only {4} bits wide)", - cast_from, - if cast_to_f64 { "f64" } else { "f32" }, - if arch_dependent { arch_dependent_str } else { "" }, - from_nbits_str, - mantissa_nbits + "casting `{cast_from}` to `{cast_to}` may cause a loss of precision \ + (`{cast_from}` {has_width}, \ + but `{cast_to}`'s mantissa is only {mantissa_nbits} bits wide)", ), ); } diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 494d6180d3cb..7220a8a80066 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -836,7 +836,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.93.0"] pub NEEDLESS_TYPE_CAST, - pedantic, + nursery, "binding defined with one type but always cast to another" } diff --git a/clippy_lints/src/casts/needless_type_cast.rs b/clippy_lints/src/casts/needless_type_cast.rs index ca6aa0f87bbf..1d899a21c229 100644 --- a/clippy_lints/src/casts/needless_type_cast.rs +++ b/clippy_lints/src/casts/needless_type_cast.rs @@ -1,6 +1,8 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg::Sugg; use clippy_utils::visitors::{Descend, for_each_expr, for_each_expr_without_closures}; use core::ops::ControlFlow; +use rustc_ast::ast::{LitFloatType, LitIntType, LitKind}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -14,6 +16,7 @@ use super::NEEDLESS_TYPE_CAST; struct BindingInfo<'a> { source_ty: Ty<'a>, ty_span: Span, + init: Option<&'a Expr<'a>>, } struct UsageInfo<'a> { @@ -73,6 +76,7 @@ fn collect_binding_from_let<'a>( BindingInfo { source_ty: ty, ty_span: ty_hir.span, + init: Some(let_expr.init), }, ); } @@ -103,6 +107,7 @@ fn collect_binding_from_local<'a>( BindingInfo { source_ty: ty, ty_span: ty_hir.span, + init: let_stmt.init, }, ); } @@ -182,12 +187,7 @@ fn is_generic_res(cx: &LateContext<'_>, res: Res) -> bool { .iter() .any(|p| p.kind.is_ty_or_const()) }; - match res { - Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) => has_type_params(def_id), - // Ctor → Variant → ADT: constructor's parent is variant, variant's parent is the ADT - Res::Def(DefKind::Ctor(..), def_id) => has_type_params(cx.tcx.parent(cx.tcx.parent(def_id))), - _ => false, - } + cx.tcx.res_generics_def_id(res).is_some_and(has_type_params) } fn is_cast_in_generic_context<'a>(cx: &LateContext<'a>, cast_expr: &Expr<'a>) -> bool { @@ -234,6 +234,18 @@ fn is_cast_in_generic_context<'a>(cx: &LateContext<'a>, cast_expr: &Expr<'a>) -> } } +fn can_coerce_to_target_type(expr: &Expr<'_>) -> bool { + match expr.kind { + ExprKind::Lit(lit) => matches!( + lit.node, + LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed) + ), + ExprKind::Unary(rustc_hir::UnOp::Neg, inner) => can_coerce_to_target_type(inner), + ExprKind::Binary(_, lhs, rhs) => can_coerce_to_target_type(lhs) && can_coerce_to_target_type(rhs), + _ => false, + } +} + fn check_binding_usages<'a>(cx: &LateContext<'a>, body: &Body<'a>, hir_id: HirId, binding_info: &BindingInfo<'a>) { let mut usages = Vec::new(); @@ -274,7 +286,19 @@ fn check_binding_usages<'a>(cx: &LateContext<'a>, body: &Body<'a>, hir_id: HirId return; }; - span_lint_and_sugg( + // Don't lint if there's exactly one use and the initializer cannot be coerced to the + // target type (i.e., would require an explicit cast). In such cases, the fix would add + // a cast to the initializer rather than eliminating one - the cast isn't truly "needless." + // See: https://github.com/rust-lang/rust-clippy/issues/16240 + if usages.len() == 1 + && binding_info + .init + .is_some_and(|init| !can_coerce_to_target_type(init) && !init.span.from_expansion()) + { + return; + } + + span_lint_and_then( cx, NEEDLESS_TYPE_CAST, binding_info.ty_span, @@ -282,8 +306,28 @@ fn check_binding_usages<'a>(cx: &LateContext<'a>, body: &Body<'a>, hir_id: HirId "this binding is defined as `{}` but is always cast to `{}`", binding_info.source_ty, first_target ), - "consider defining it as", - first_target.to_string(), - Applicability::MaybeIncorrect, + |diag| { + if let Some(init) = binding_info + .init + .filter(|i| !can_coerce_to_target_type(i) && !i.span.from_expansion()) + { + let sugg = Sugg::hir(cx, init, "..").as_ty(first_target); + diag.multipart_suggestion( + format!("consider defining it as `{first_target}` and casting the initializer"), + vec![ + (binding_info.ty_span, first_target.to_string()), + (init.span, sugg.to_string()), + ], + Applicability::MachineApplicable, + ); + } else { + diag.span_suggestion( + binding_info.ty_span, + "consider defining it as", + first_target.to_string(), + Applicability::MachineApplicable, + ); + } + }, ); } diff --git a/clippy_lints/src/casts/ref_as_ptr.rs b/clippy_lints/src/casts/ref_as_ptr.rs index 592c820a25e1..b3805c678174 100644 --- a/clippy_lints/src/casts/ref_as_ptr.rs +++ b/clippy_lints/src/casts/ref_as_ptr.rs @@ -1,9 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; -use clippy_utils::{ExprUseNode, expr_use_ctxt, std_or_core}; +use clippy_utils::{ExprUseNode, expr_use_ctxt, is_expr_temporary_value, std_or_core}; use rustc_errors::Applicability; -use rustc_hir::{Expr, Mutability, Ty, TyKind}; +use rustc_hir::{Expr, ExprKind, Mutability, Ty, TyKind}; use rustc_lint::LateContext; use rustc_middle::ty; @@ -23,10 +23,18 @@ pub(super) fn check<'tcx>( if matches!(cast_from.kind(), ty::Ref(..)) && let ty::RawPtr(_, to_mutbl) = cast_to.kind() && let use_cx = expr_use_ctxt(cx, expr) - // TODO: only block the lint if `cast_expr` is a temporary - && !matches!(use_cx.use_node(cx), ExprUseNode::LetStmt(_) | ExprUseNode::ConstStatic(_)) && let Some(std_or_core) = std_or_core(cx) { + if let ExprKind::AddrOf(_, _, addr_inner) = cast_expr.kind + && is_expr_temporary_value(cx, addr_inner) + && matches!( + use_cx.use_node(cx), + ExprUseNode::LetStmt(_) | ExprUseNode::ConstStatic(_) + ) + { + return; + } + let fn_name = match to_mutbl { Mutability::Not => "from_ref", Mutability::Mut => "from_mut", diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index b13e307a3f9c..be07ce1272bd 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -76,7 +76,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.51.0"] pub COLLAPSIBLE_ELSE_IF, - style, + pedantic, "nested `else`-`if` expressions that can be collapsed (e.g., `else { if x { ... } }`)" } @@ -267,6 +267,9 @@ impl LateLintPass<'_> for CollapsibleIf { && !expr.span.from_expansion() { if let Some(else_) = else_ + // Short circuit if both `if` branches contain only a single `if {..} else {}`, as + // collapsing such blocks can lead to less readable code (#4971) + && !(single_inner_if_else(then) && single_inner_if_else(else_)) && let ExprKind::Block(else_, None) = else_.kind { self.check_collapsible_else_if(cx, then.span, else_); @@ -280,6 +283,19 @@ impl LateLintPass<'_> for CollapsibleIf { } } +/// Returns true if `expr` is a block that contains only one `if {..} else {}` statement +fn single_inner_if_else(expr: &Expr<'_>) -> bool { + if let ExprKind::Block(block, None) = expr.kind + && let Some(inner_expr) = expr_block(block) + && let ExprKind::If(_, _, else_) = inner_expr.kind + && else_.is_some() + { + true + } else { + false + } +} + /// If `block` is a block with either one expression or a statement containing an expression, /// return the expression. We don't peel blocks recursively, as extra blocks might be intentional. fn expr_block<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> { diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 87d75234ebc0..6b68940c6423 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -667,6 +667,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::returns::LET_AND_RETURN_INFO, crate::returns::NEEDLESS_RETURN_INFO, crate::returns::NEEDLESS_RETURN_WITH_QUESTION_MARK_INFO, + crate::same_length_and_capacity::SAME_LENGTH_AND_CAPACITY_INFO, crate::same_name_method::SAME_NAME_METHOD_INFO, crate::self_named_constructors::SELF_NAMED_CONSTRUCTORS_INFO, crate::semicolon_block::SEMICOLON_INSIDE_BLOCK_INFO, diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs index 8c067432cb4e..58403ad19235 100644 --- a/clippy_lints/src/disallowed_methods.rs +++ b/clippy_lints/src/disallowed_methods.rs @@ -88,6 +88,9 @@ impl_lint_pass!(DisallowedMethods => [DISALLOWED_METHODS]); impl<'tcx> LateLintPass<'tcx> for DisallowedMethods { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if expr.span.desugaring_kind().is_some() { + return; + } let (id, span) = match &expr.kind { ExprKind::Path(path) if let Res::Def(_, id) = cx.qpath_res(path, expr.hir_id) => (id, expr.span), ExprKind::MethodCall(name, ..) if let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) => { diff --git a/clippy_lints/src/empty_with_brackets.rs b/clippy_lints/src/empty_with_brackets.rs index e7230ebf8cba..7e335d5c9809 100644 --- a/clippy_lints/src/empty_with_brackets.rs +++ b/clippy_lints/src/empty_with_brackets.rs @@ -1,16 +1,18 @@ use clippy_utils::attrs::span_contains_cfg; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; -use rustc_data_structures::fx::FxIndexMap; +use clippy_utils::source::SpanRangeExt; +use clippy_utils::span_contains_non_whitespace; +use rustc_data_structures::fx::{FxIndexMap, IndexEntry}; use rustc_errors::Applicability; -use rustc_hir::def::CtorOf; use rustc_hir::def::DefKind::Ctor; use rustc_hir::def::Res::Def; +use rustc_hir::def::{CtorOf, DefKind}; use rustc_hir::def_id::LocalDefId; -use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node, Path, QPath, Variant, VariantData}; +use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node, Pat, PatKind, Path, QPath, Variant, VariantData}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{self, TyCtxt}; use rustc_session::impl_lint_pass; -use rustc_span::Span; +use rustc_span::{BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -118,7 +120,6 @@ impl LateLintPass<'_> for EmptyWithBrackets { } fn check_variant(&mut self, cx: &LateContext<'_>, variant: &Variant<'_>) { - // FIXME: handle `$name {}` if !variant.span.from_expansion() && !variant.ident.span.from_expansion() && let span_after_ident = variant.span.with_lo(variant.ident.span.hi()) @@ -126,44 +127,14 @@ impl LateLintPass<'_> for EmptyWithBrackets { { match variant.data { VariantData::Struct { .. } => { - // Empty struct variants can be linted immediately - span_lint_and_then( - cx, - EMPTY_ENUM_VARIANTS_WITH_BRACKETS, - span_after_ident, - "enum variant has empty brackets", - |diagnostic| { - diagnostic.span_suggestion_hidden( - span_after_ident, - "remove the brackets", - "", - Applicability::MaybeIncorrect, - ); - }, - ); + self.add_enum_variant(variant.def_id); }, VariantData::Tuple(.., local_def_id) => { // Don't lint reachable tuple enums if cx.effective_visibilities.is_reachable(variant.def_id) { return; } - if let Some(entry) = self.empty_tuple_enum_variants.get_mut(&local_def_id) { - // empty_tuple_enum_variants contains Usage::NoDefinition if the variant was called before the - // definition was encountered. Now that there's a definition, convert it - // to Usage::Unused. - if let Usage::NoDefinition { redundant_use_sites } = entry { - *entry = Usage::Unused { - redundant_use_sites: redundant_use_sites.clone(), - }; - } - } else { - self.empty_tuple_enum_variants.insert( - local_def_id, - Usage::Unused { - redundant_use_sites: vec![], - }, - ); - } + self.add_enum_variant(local_def_id); }, VariantData::Unit(..) => {}, } @@ -171,56 +142,58 @@ impl LateLintPass<'_> for EmptyWithBrackets { } fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if let Some(def_id) = check_expr_for_enum_as_function(expr) { - if let Some(parentheses_span) = call_parentheses_span(cx.tcx, expr) { + if let Some((def_id, mut span)) = check_expr_for_enum_as_function(cx, expr) { + if span.is_empty() + && let Some(parentheses_span) = call_parentheses_span(cx.tcx, expr) + { + span = parentheses_span; + } + + if span.is_empty() { + // The parentheses are not redundant. + self.empty_tuple_enum_variants.insert(def_id, Usage::Used); + } else { // Do not count expressions from macro expansion as a redundant use site. if expr.span.from_expansion() { return; } - match self.empty_tuple_enum_variants.get_mut(&def_id) { - Some( - &mut (Usage::Unused { - ref mut redundant_use_sites, - } - | Usage::NoDefinition { - ref mut redundant_use_sites, - }), - ) => { - redundant_use_sites.push(parentheses_span); - }, - None => { - // The variant isn't in the IndexMap which means its definition wasn't encountered yet. - self.empty_tuple_enum_variants.insert( - def_id, - Usage::NoDefinition { - redundant_use_sites: vec![parentheses_span], - }, - ); - }, - _ => {}, - } - } else { - // The parentheses are not redundant. - self.empty_tuple_enum_variants.insert(def_id, Usage::Used); + self.update_enum_variant_usage(def_id, span); } } } + fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) { + if !pat.span.from_expansion() + && let Some((def_id, span)) = check_pat_for_enum_as_function(cx, pat) + { + self.update_enum_variant_usage(def_id, span); + } + } + fn check_crate_post(&mut self, cx: &LateContext<'_>) { - for (local_def_id, usage) in &self.empty_tuple_enum_variants { + for (&local_def_id, usage) in &self.empty_tuple_enum_variants { // Ignore all variants with Usage::Used or Usage::NoDefinition let Usage::Unused { redundant_use_sites } = usage else { continue; }; + // Attempt to fetch the Variant from LocalDefId. - let Node::Variant(variant) = cx.tcx.hir_node( - cx.tcx - .local_def_id_to_hir_id(cx.tcx.parent(local_def_id.to_def_id()).expect_local()), - ) else { + let variant = if let Node::Variant(variant) = cx.tcx.hir_node_by_def_id(local_def_id) { + variant + } else if let Node::Variant(variant) = cx.tcx.hir_node_by_def_id(cx.tcx.local_parent(local_def_id)) { + variant + } else { continue; }; + // Span of the parentheses in variant definition let span = variant.span.with_lo(variant.ident.span.hi()); + let span_inner = span + .with_lo(SpanRangeExt::trim_start(span, cx).start + BytePos(1)) + .with_hi(span.hi() - BytePos(1)); + if span_contains_non_whitespace(cx, span_inner, false) { + continue; + } span_lint_hir_and_then( cx, EMPTY_ENUM_VARIANTS_WITH_BRACKETS, @@ -252,6 +225,43 @@ impl LateLintPass<'_> for EmptyWithBrackets { } } +impl EmptyWithBrackets { + fn add_enum_variant(&mut self, local_def_id: LocalDefId) { + self.empty_tuple_enum_variants + .entry(local_def_id) + .and_modify(|entry| { + // empty_tuple_enum_variants contains Usage::NoDefinition if the variant was called before + // the definition was encountered. Now that there's a + // definition, convert it to Usage::Unused. + if let Usage::NoDefinition { redundant_use_sites } = entry { + *entry = Usage::Unused { + redundant_use_sites: redundant_use_sites.clone(), + }; + } + }) + .or_insert_with(|| Usage::Unused { + redundant_use_sites: vec![], + }); + } + + fn update_enum_variant_usage(&mut self, def_id: LocalDefId, parentheses_span: Span) { + match self.empty_tuple_enum_variants.entry(def_id) { + IndexEntry::Occupied(mut e) => { + if let Usage::Unused { redundant_use_sites } | Usage::NoDefinition { redundant_use_sites } = e.get_mut() + { + redundant_use_sites.push(parentheses_span); + } + }, + IndexEntry::Vacant(e) => { + // The variant isn't in the IndexMap which means its definition wasn't encountered yet. + e.insert(Usage::NoDefinition { + redundant_use_sites: vec![parentheses_span], + }); + }, + } + } +} + fn has_brackets(var_data: &VariantData<'_>) -> bool { !matches!(var_data, VariantData::Unit(..)) } @@ -277,17 +287,47 @@ fn call_parentheses_span(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> Option { } // Returns the LocalDefId of the variant being called as a function if it exists. -fn check_expr_for_enum_as_function(expr: &Expr<'_>) -> Option { - if let ExprKind::Path(QPath::Resolved( - _, - Path { - res: Def(Ctor(CtorOf::Variant, _), def_id), - .. +fn check_expr_for_enum_as_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<(LocalDefId, Span)> { + match expr.kind { + ExprKind::Path(QPath::Resolved( + _, + Path { + res: Def(Ctor(CtorOf::Variant, _), def_id), + span, + .. + }, + )) => def_id.as_local().map(|id| (id, span.with_lo(expr.span.hi()))), + ExprKind::Struct(qpath, ..) + if let Def(DefKind::Variant, mut def_id) = cx.typeck_results().qpath_res(qpath, expr.hir_id) => + { + let ty = cx.tcx.type_of(def_id).instantiate_identity(); + if let ty::FnDef(ctor_def_id, _) = ty.kind() { + def_id = *ctor_def_id; + } + + def_id.as_local().map(|id| (id, qpath.span().with_lo(expr.span.hi()))) }, - )) = expr.kind - { - def_id.as_local() - } else { - None + _ => None, + } +} + +fn check_pat_for_enum_as_function(cx: &LateContext<'_>, pat: &Pat<'_>) -> Option<(LocalDefId, Span)> { + match pat.kind { + PatKind::TupleStruct(qpath, ..) + if let Def(Ctor(CtorOf::Variant, _), def_id) = cx.typeck_results().qpath_res(&qpath, pat.hir_id) => + { + def_id.as_local().map(|id| (id, qpath.span().with_lo(pat.span.hi()))) + }, + PatKind::Struct(qpath, ..) + if let Def(DefKind::Variant, mut def_id) = cx.typeck_results().qpath_res(&qpath, pat.hir_id) => + { + let ty = cx.tcx.type_of(def_id).instantiate_identity(); + if let ty::FnDef(ctor_def_id, _) = ty.kind() { + def_id = *ctor_def_id; + } + + def_id.as_local().map(|id| (id, qpath.span().with_lo(pat.span.hi()))) + }, + _ => None, } } diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index bdfe2e49e66e..75ab890a8a7f 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -4,7 +4,7 @@ use clippy_utils::ty::is_copy; use clippy_utils::visitors::for_each_expr; use clippy_utils::{ SpanlessEq, can_move_expr_to_closure_no_visit, desugar_await, higher, is_expr_final_block_expr, - is_expr_used_or_unified, paths, peel_hir_expr_while, + is_expr_used_or_unified, paths, peel_hir_expr_while, span_contains_non_whitespace, }; use core::fmt::{self, Write}; use rustc_errors::Applicability; @@ -167,7 +167,11 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass { "if let {}::{entry_kind} = {map_str}.entry({key_str}) {body_str}", map_ty.entry_path(), )) - } else if let Some(insertion) = then_search.as_single_insertion() { + } else if let Some(insertion) = then_search.as_single_insertion() + && let span_in_between = then_expr.span.shrink_to_lo().between(insertion.call.span) + && let span_in_between = span_in_between.split_at(1).1 + && !span_contains_non_whitespace(cx, span_in_between, true) + { let value_str = snippet_with_context(cx, insertion.value.span, then_expr.span.ctxt(), "..", &mut app).0; if contains_expr.negated { if insertion.value.can_have_side_effects() { diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index c42998ffc3f5..bd2bd6628464 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -82,7 +82,7 @@ fn lint_impl_body(cx: &LateContext<'_>, item_def_id: hir::OwnerId, impl_span: Sp // check for `unwrap` if let Some(arglists) = method_chain_args(expr, &[sym::unwrap]) { let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs(); - if receiver_ty.is_diag_item(self.lcx, sym::Option) || receiver_ty.is_diag_item(self.lcx, sym::Result) { + if matches!(receiver_ty.opt_diag_name(self.lcx), Some(sym::Option | sym::Result)) { self.result.push(expr.span); } } diff --git a/clippy_lints/src/format_push_string.rs b/clippy_lints/src/format_push_string.rs index a23ba9ab837a..fea55f91bce7 100644 --- a/clippy_lints/src/format_push_string.rs +++ b/clippy_lints/src/format_push_string.rs @@ -1,10 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::higher; +use clippy_utils::macros::{FormatArgsStorage, format_args_inputs_span, root_macro_call_first_node}; use clippy_utils::res::MaybeDef; +use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; +use clippy_utils::std_or_core; +use rustc_errors::Applicability; use rustc_hir::{AssignOpKind, Expr, ExprKind, LangItem, MatchSource}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; -use rustc_span::sym; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_session::impl_lint_pass; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does @@ -38,7 +41,152 @@ declare_clippy_lint! { pedantic, "`format!(..)` appended to existing `String`" } -declare_lint_pass!(FormatPushString => [FORMAT_PUSH_STRING]); +impl_lint_pass!(FormatPushString => [FORMAT_PUSH_STRING]); + +pub(crate) struct FormatPushString { + format_args: FormatArgsStorage, +} + +enum FormatSearchResults { + /// The expression is itself a `format!()` invocation -- we can make a suggestion to replace it + Direct(Span), + /// The expression contains zero or more `format!()`s, e.g.: + /// ```ignore + /// if true { + /// format!("hello") + /// } else { + /// format!("world") + /// } + /// ``` + /// or + /// ```ignore + /// match true { + /// true => format!("hello"), + /// false => format!("world"), + /// } + Nested(Vec), +} + +impl FormatPushString { + pub(crate) fn new(format_args: FormatArgsStorage) -> Self { + Self { format_args } + } + + fn find_formats<'tcx>(&self, cx: &LateContext<'_>, e: &'tcx Expr<'tcx>) -> FormatSearchResults { + let expr_as_format = |e| { + if let Some(macro_call) = root_macro_call_first_node(cx, e) + && cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) + && let Some(format_args) = self.format_args.get(cx, e, macro_call.expn) + { + Some(format_args_inputs_span(format_args)) + } else { + None + } + }; + + let e = e.peel_blocks().peel_borrows(); + if let Some(fmt) = expr_as_format(e) { + FormatSearchResults::Direct(fmt) + } else { + fn inner<'tcx>( + e: &'tcx Expr<'tcx>, + expr_as_format: &impl Fn(&'tcx Expr<'tcx>) -> Option, + out: &mut Vec, + ) { + let e = e.peel_blocks().peel_borrows(); + + match e.kind { + _ if expr_as_format(e).is_some() => out.push(e.span), + ExprKind::Match(_, arms, MatchSource::Normal) => { + for arm in arms { + inner(arm.body, expr_as_format, out); + } + }, + ExprKind::If(_, then, els) => { + inner(then, expr_as_format, out); + if let Some(els) = els { + inner(els, expr_as_format, out); + } + }, + _ => {}, + } + } + let mut spans = vec![]; + inner(e, &expr_as_format, &mut spans); + FormatSearchResults::Nested(spans) + } + } +} + +impl<'tcx> LateLintPass<'tcx> for FormatPushString { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + let (recv, arg) = match expr.kind { + ExprKind::MethodCall(_, recv, [arg], _) => { + if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && cx.tcx.is_diagnostic_item(sym::string_push_str, fn_def_id) + { + (recv, arg) + } else { + return; + } + }, + ExprKind::AssignOp(op, recv, arg) if op.node == AssignOpKind::AddAssign && is_string(cx, recv) => { + (recv, arg) + }, + _ => return, + }; + let Some(std_or_core) = std_or_core(cx) else { + // not even `core` is available, so can't suggest `write!` + return; + }; + match self.find_formats(cx, arg) { + FormatSearchResults::Direct(format_args) => { + span_lint_and_then( + cx, + FORMAT_PUSH_STRING, + expr.span, + "`format!(..)` appended to existing `String`", + |diag| { + let mut app = Applicability::MaybeIncorrect; + let msg = "consider using `write!` to avoid the extra allocation"; + + let sugg = format!( + "let _ = write!({recv}, {format_args})", + recv = snippet_with_context(cx.sess(), recv.span, expr.span.ctxt(), "_", &mut app).0, + format_args = snippet_with_applicability(cx.sess(), format_args, "..", &mut app), + ); + diag.span_suggestion_verbose(expr.span, msg, sugg, app); + + // TODO: omit the note if the `Write` trait is imported at point + // Tip: `TyCtxt::in_scope_traits` isn't it -- it returns a non-empty list only when called on + // the `HirId` of a `ExprKind::MethodCall` that is a call of a _trait_ method. + diag.note(format!("you may need to import the `{std_or_core}::fmt::Write` trait")); + }, + ); + }, + FormatSearchResults::Nested(spans) => { + if !spans.is_empty() { + span_lint_and_then( + cx, + FORMAT_PUSH_STRING, + expr.span, + "`format!(..)` appended to existing `String`", + |diag| { + diag.help("consider using `write!` to avoid the extra allocation"); + diag.span_labels(spans, "`format!` used here"); + + // TODO: omit the note if the `Write` trait is imported at point + // Tip: `TyCtxt::in_scope_traits` isn't it -- it returns a non-empty list only when called + // on the `HirId` of a `ExprKind::MethodCall` that is a call of + // a _trait_ method. + diag.note(format!("you may need to import the `{std_or_core}::fmt::Write` trait")); + }, + ); + } + }, + } + } +} fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { cx.typeck_results() @@ -46,54 +194,3 @@ fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { .peel_refs() .is_lang_item(cx, LangItem::String) } -fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { - let e = e.peel_blocks().peel_borrows(); - - if e.span.from_expansion() - && let Some(macro_def_id) = e.span.ctxt().outer_expn_data().macro_def_id - { - cx.tcx.get_diagnostic_name(macro_def_id) == Some(sym::format_macro) - } else if let Some(higher::If { then, r#else, .. }) = higher::If::hir(e) { - is_format(cx, then) || r#else.is_some_and(|e| is_format(cx, e)) - } else { - match higher::IfLetOrMatch::parse(cx, e) { - Some(higher::IfLetOrMatch::Match(_, arms, MatchSource::Normal)) => { - arms.iter().any(|arm| is_format(cx, arm.body)) - }, - Some(higher::IfLetOrMatch::IfLet(_, _, then, r#else, _)) => { - is_format(cx, then) || r#else.is_some_and(|e| is_format(cx, e)) - }, - _ => false, - } - } -} - -impl<'tcx> LateLintPass<'tcx> for FormatPushString { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let arg = match expr.kind { - ExprKind::MethodCall(_, _, [arg], _) => { - if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) - && cx.tcx.is_diagnostic_item(sym::string_push_str, fn_def_id) - { - arg - } else { - return; - } - }, - ExprKind::AssignOp(op, left, arg) if op.node == AssignOpKind::AddAssign && is_string(cx, left) => arg, - _ => return, - }; - if is_format(cx, arg) { - #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] - span_lint_and_then( - cx, - FORMAT_PUSH_STRING, - expr.span, - "`format!(..)` appended to existing `String`", - |diag| { - diag.help("consider using `write!` to avoid the extra allocation"); - }, - ); - } - } -} diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index bdc366f6878a..9a7427ea1447 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -596,4 +596,8 @@ impl<'tcx> LateLintPass<'tcx> for Functions { impl_trait_in_params::check_trait_item(cx, item, self.avoid_breaking_exported_api); ref_option::check_trait_item(cx, item, self.avoid_breaking_exported_api); } + + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { + result::check_expr(cx, expr, self.large_error_threshold, &self.large_error_ignored); + } } diff --git a/clippy_lints/src/functions/result.rs b/clippy_lints/src/functions/result.rs index 04e15a1d8a0e..77fec9371425 100644 --- a/clippy_lints/src/functions/result.rs +++ b/clippy_lints/src/functions/result.rs @@ -50,7 +50,7 @@ pub(super) fn check_item<'tcx>( let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); check_result_unit_err(cx, err_ty, fn_header_span, msrv); } - check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold, large_err_ignored); + check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold, large_err_ignored, false); } } @@ -70,7 +70,7 @@ pub(super) fn check_impl_item<'tcx>( let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); check_result_unit_err(cx, err_ty, fn_header_span, msrv); } - check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold, large_err_ignored); + check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold, large_err_ignored, false); } } @@ -87,7 +87,7 @@ pub(super) fn check_trait_item<'tcx>( if cx.effective_visibilities.is_exported(item.owner_id.def_id) { check_result_unit_err(cx, err_ty, fn_header_span, msrv); } - check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold, large_err_ignored); + check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold, large_err_ignored, false); } } } @@ -111,12 +111,15 @@ fn check_result_large_err<'tcx>( hir_ty_span: Span, large_err_threshold: u64, large_err_ignored: &DefIdSet, + is_closure: bool, ) { if let ty::Adt(adt, _) = err_ty.kind() && large_err_ignored.contains(&adt.did()) { return; } + + let subject = if is_closure { "closure" } else { "function" }; if let ty::Adt(adt, subst) = err_ty.kind() && let Some(local_def_id) = adt.did().as_local() && let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id(local_def_id) @@ -130,7 +133,7 @@ fn check_result_large_err<'tcx>( cx, RESULT_LARGE_ERR, hir_ty_span, - "the `Err`-variant returned from this function is very large", + format!("the `Err`-variant returned from this {subject} is very large"), |diag| { diag.span_label( def.variants[first_variant.ind].span, @@ -161,7 +164,7 @@ fn check_result_large_err<'tcx>( cx, RESULT_LARGE_ERR, hir_ty_span, - "the `Err`-variant returned from this function is very large", + format!("the `Err`-variant returned from this {subject} is very large"), |diag: &mut Diag<'_, ()>| { diag.span_label(hir_ty_span, format!("the `Err`-variant is at least {ty_size} bytes")); diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`")); @@ -170,3 +173,33 @@ fn check_result_large_err<'tcx>( } } } + +pub(super) fn check_expr<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + large_err_threshold: u64, + large_err_ignored: &DefIdSet, +) { + if let hir::ExprKind::Closure(closure) = expr.kind + && let ty::Closure(_, args) = cx.typeck_results().expr_ty(expr).kind() + && let closure_sig = args.as_closure().sig() + && let Ok(err_binder) = closure_sig.output().try_map_bound(|output_ty| { + if let ty::Adt(adt, args) = output_ty.kind() + && let [_, err_arg] = args.as_slice() + && let Some(err_ty) = err_arg.as_type() + && adt.is_diag_item(cx, sym::Result) + { + return Ok(err_ty); + } + + Err(()) + }) + { + let err_ty = cx.tcx.instantiate_bound_regions_with_erased(err_binder); + let hir_ty_span = match closure.fn_decl.output { + hir::FnRetTy::Return(hir_ty) => hir_ty.span, + hir::FnRetTy::DefaultReturn(_) => expr.span, + }; + check_result_large_err(cx, err_ty, hir_ty_span, large_err_threshold, large_err_ignored, true); + } +} diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index 54e9538fcb99..ff22ba4fcd0d 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -1,7 +1,7 @@ use clippy_utils::consts::is_zero_integer_const; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::is_else_clause; -use clippy_utils::source::{HasSession, indent_of, reindent_multiline, snippet}; +use clippy_utils::source::{HasSession, indent_of, reindent_multiline, snippet_with_context}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; @@ -78,6 +78,7 @@ impl LateLintPass<'_> for IfNotElse { // } // ``` if !e.span.from_expansion() && !is_else_clause(cx.tcx, e) { + let mut applicability = Applicability::MachineApplicable; match cond.kind { ExprKind::Unary(UnOp::Not, _) | ExprKind::Binary(_, _, _) => span_lint_and_sugg( cx, @@ -85,8 +86,16 @@ impl LateLintPass<'_> for IfNotElse { e.span, msg, "try", - make_sugg(cx, &cond.kind, cond_inner.span, els.span, "..", Some(e.span)), - Applicability::MachineApplicable, + make_sugg( + cx, + e.span, + &cond.kind, + cond_inner.span, + els.span, + "..", + &mut applicability, + ), + applicability, ), _ => span_lint_and_help(cx, IF_NOT_ELSE, e.span, msg, None, help), } @@ -97,28 +106,26 @@ impl LateLintPass<'_> for IfNotElse { fn make_sugg<'a>( sess: &impl HasSession, + expr_span: Span, cond_kind: &'a ExprKind<'a>, cond_inner: Span, els_span: Span, default: &'a str, - indent_relative_to: Option, + applicability: &mut Applicability, ) -> String { - let cond_inner_snip = snippet(sess, cond_inner, default); - let els_snip = snippet(sess, els_span, default); - let indent = indent_relative_to.and_then(|s| indent_of(sess, s)); + let (cond_inner_snip, _) = snippet_with_context(sess, cond_inner, expr_span.ctxt(), default, applicability); + let (els_snip, _) = snippet_with_context(sess, els_span, expr_span.ctxt(), default, applicability); + let indent = indent_of(sess, expr_span); let suggestion = match cond_kind { ExprKind::Unary(UnOp::Not, cond_rest) => { - format!( - "if {} {} else {}", - snippet(sess, cond_rest.span, default), - els_snip, - cond_inner_snip - ) + let (cond_rest_snip, _) = + snippet_with_context(sess, cond_rest.span, expr_span.ctxt(), default, applicability); + format!("if {cond_rest_snip} {els_snip} else {cond_inner_snip}") }, ExprKind::Binary(_, lhs, rhs) => { - let lhs_snip = snippet(sess, lhs.span, default); - let rhs_snip = snippet(sess, rhs.span, default); + let (lhs_snip, _) = snippet_with_context(sess, lhs.span, expr_span.ctxt(), default, applicability); + let (rhs_snip, _) = snippet_with_context(sess, rhs.span, expr_span.ctxt(), default, applicability); format!("if {lhs_snip} == {rhs_snip} {els_snip} else {cond_inner_snip}") }, diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index 7f3ef58c93d1..9e5e4fa58d2f 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -4,10 +4,12 @@ use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{snippet_with_applicability, snippet_with_context, walk_span_to_context}; use clippy_utils::sugg::Sugg; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{ - as_some_expr, contains_return, expr_adjustment_requires_coercion, higher, is_else_clause, is_in_const_context, - is_none_expr, peel_blocks, sym, + as_some_expr, expr_adjustment_requires_coercion, higher, is_else_clause, is_in_const_context, is_none_expr, + peel_blocks, sym, }; +use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -76,8 +78,14 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { && !is_else_clause(cx.tcx, expr) && !is_in_const_context(cx) && self.msrv.meets(cx, msrvs::BOOL_THEN) - && !contains_return(then_block.stmts) - && then_block.expr.is_none_or(|expr| !contains_return(expr)) + && for_each_expr_without_closures(then_block, |e| { + if matches!(e.kind, ExprKind::Ret(..) | ExprKind::Yield(..)) { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + }) + .is_none() { let method_name = if switch_to_eager_eval(cx, expr) && self.msrv.meets(cx, msrvs::BOOL_THEN_SOME) { sym::then_some @@ -101,13 +109,19 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { .maybe_paren() .to_string(); let arg_snip = snippet_with_context(cx, then_arg.span, ctxt, "[body]", &mut app).0; - let method_body = if let Some(first_stmt) = then_block.stmts.first() - && let Some(first_stmt_span) = walk_span_to_context(first_stmt.span, ctxt) + let method_body = if let Some(_) = then_block.stmts.first() + && let Some(then_span) = walk_span_to_context(then.span, ctxt) { - let block_snippet = - snippet_with_applicability(cx, first_stmt_span.until(then_expr.span), "..", &mut app); + let block_before_snippet = + snippet_with_applicability(cx, then_span.until(then_expr.span), "..", &mut app); + let block_after_snippet = snippet_with_applicability( + cx, + then_expr.span.shrink_to_hi().until(then_span.shrink_to_hi()), + "..", + &mut app, + ); let closure = if method_name == sym::then { "|| " } else { "" }; - format!("{closure} {{ {} {arg_snip} }}", block_snippet.trim_end()) + format!("{closure}{block_before_snippet}{arg_snip}{block_after_snippet}") } else if method_name == sym::then { (std::borrow::Cow::Borrowed("|| ") + arg_snip).into_owned() } else { diff --git a/clippy_lints/src/ifs/branches_sharing_code.rs b/clippy_lints/src/ifs/branches_sharing_code.rs index b3f597cc8736..b6e8d047c5cd 100644 --- a/clippy_lints/src/ifs/branches_sharing_code.rs +++ b/clippy_lints/src/ifs/branches_sharing_code.rs @@ -9,7 +9,7 @@ use clippy_utils::{ use core::iter; use core::ops::ControlFlow; use rustc_errors::Applicability; -use rustc_hir::{Block, Expr, ExprKind, HirId, HirIdSet, LetStmt, Node, Stmt, StmtKind, intravisit}; +use rustc_hir::{Block, Expr, ExprKind, HirId, HirIdSet, ItemKind, LetStmt, Node, Stmt, StmtKind, UseKind, intravisit}; use rustc_lint::LateContext; use rustc_span::hygiene::walk_chain; use rustc_span::source_map::SourceMap; @@ -108,6 +108,7 @@ struct BlockEq { /// The name and id of every local which can be moved at the beginning and the end. moved_locals: Vec<(HirId, Symbol)>, } + impl BlockEq { fn start_span(&self, b: &Block<'_>, sm: &SourceMap) -> Option { match &b.stmts[..self.start_end_eq] { @@ -129,20 +130,33 @@ impl BlockEq { } /// If the statement is a local, checks if the bound names match the expected list of names. -fn eq_binding_names(s: &Stmt<'_>, names: &[(HirId, Symbol)]) -> bool { - if let StmtKind::Let(l) = s.kind { - let mut i = 0usize; - let mut res = true; - l.pat.each_binding_or_first(&mut |_, _, _, name| { - if names.get(i).is_some_and(|&(_, n)| n == name.name) { - i += 1; - } else { - res = false; - } - }); - res && i == names.len() - } else { - false +fn eq_binding_names(cx: &LateContext<'_>, s: &Stmt<'_>, names: &[(HirId, Symbol)]) -> bool { + match s.kind { + StmtKind::Let(l) => { + let mut i = 0usize; + let mut res = true; + l.pat.each_binding_or_first(&mut |_, _, _, name| { + if names.get(i).is_some_and(|&(_, n)| n == name.name) { + i += 1; + } else { + res = false; + } + }); + res && i == names.len() + }, + StmtKind::Item(item_id) + if let [(_, name)] = names + && let item = cx.tcx.hir_item(item_id) + && let ItemKind::Static(_, ident, ..) + | ItemKind::Const(ident, ..) + | ItemKind::Fn { ident, .. } + | ItemKind::TyAlias(ident, ..) + | ItemKind::Use(_, UseKind::Single(ident)) + | ItemKind::Mod(ident, _) = item.kind => + { + *name == ident.name + }, + _ => false, } } @@ -164,6 +178,7 @@ fn modifies_any_local<'tcx>(cx: &LateContext<'tcx>, s: &'tcx Stmt<'_>, locals: & /// Checks if the given statement should be considered equal to the statement in the same /// position for each block. fn eq_stmts( + cx: &LateContext<'_>, stmt: &Stmt<'_>, blocks: &[&Block<'_>], get_stmt: impl for<'a> Fn(&'a Block<'a>) -> Option<&'a Stmt<'a>>, @@ -178,7 +193,7 @@ fn eq_stmts( let new_bindings = &moved_bindings[old_count..]; blocks .iter() - .all(|b| get_stmt(b).is_some_and(|s| eq_binding_names(s, new_bindings))) + .all(|b| get_stmt(b).is_some_and(|s| eq_binding_names(cx, s, new_bindings))) } else { true }) && blocks.iter().all(|b| get_stmt(b).is_some_and(|s| eq.eq_stmt(s, stmt))) @@ -218,7 +233,7 @@ fn scan_block_for_eq<'tcx>( return true; } modifies_any_local(cx, stmt, &cond_locals) - || !eq_stmts(stmt, blocks, |b| b.stmts.get(i), &mut eq, &mut moved_locals) + || !eq_stmts(cx, stmt, blocks, |b| b.stmts.get(i), &mut eq, &mut moved_locals) }) .map_or(block.stmts.len(), |(i, stmt)| { adjust_by_closest_callsite(i, stmt, block.stmts[..i].iter().enumerate().rev()) @@ -279,6 +294,7 @@ fn scan_block_for_eq<'tcx>( })) .fold(end_search_start, |init, (stmt, offset)| { if eq_stmts( + cx, stmt, blocks, |b| b.stmts.get(b.stmts.len() - offset), @@ -290,11 +306,26 @@ fn scan_block_for_eq<'tcx>( // Clear out all locals seen at the end so far. None of them can be moved. let stmts = &blocks[0].stmts; for stmt in &stmts[stmts.len() - init..=stmts.len() - offset] { - if let StmtKind::Let(l) = stmt.kind { - l.pat.each_binding_or_first(&mut |_, id, _, _| { - // FIXME(rust/#120456) - is `swap_remove` correct? - eq.locals.swap_remove(&id); - }); + match stmt.kind { + StmtKind::Let(l) => { + l.pat.each_binding_or_first(&mut |_, id, _, _| { + // FIXME(rust/#120456) - is `swap_remove` correct? + eq.locals.swap_remove(&id); + }); + }, + StmtKind::Item(item_id) => { + let item = cx.tcx.hir_item(item_id); + if let ItemKind::Static(..) + | ItemKind::Const(..) + | ItemKind::Fn { .. } + | ItemKind::TyAlias(..) + | ItemKind::Use(..) + | ItemKind::Mod(..) = item.kind + { + eq.local_items.swap_remove(&item.owner_id.to_def_id()); + } + }, + _ => {}, } } moved_locals.truncate(moved_locals_at_start); diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index 638a08b096db..9dc74a157cbf 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -223,25 +223,20 @@ impl<'tcx> ImplicitHasherType<'tcx> { _ => None, }) .collect(); - let params_len = params.len(); let ty = lower_ty(cx.tcx, hir_ty); - if ty.is_diag_item(cx, sym::HashMap) && params_len == 2 { - Some(ImplicitHasherType::HashMap( + match (ty.opt_diag_name(cx), ¶ms[..]) { + (Some(sym::HashMap), [k, v]) => Some(ImplicitHasherType::HashMap( hir_ty.span, ty, - snippet(cx, params[0].span, "K"), - snippet(cx, params[1].span, "V"), - )) - } else if ty.is_diag_item(cx, sym::HashSet) && params_len == 1 { - Some(ImplicitHasherType::HashSet( - hir_ty.span, - ty, - snippet(cx, params[0].span, "T"), - )) - } else { - None + snippet(cx, k.span, "K"), + snippet(cx, v.span, "V"), + )), + (Some(sym::HashSet), [t]) => { + Some(ImplicitHasherType::HashSet(hir_ty.span, ty, snippet(cx, t.span, "T"))) + }, + _ => None, } } else { None diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 40487fe48f22..a957afdb1910 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -318,6 +318,7 @@ mod replace_box; mod reserve_after_initialization; mod return_self_not_must_use; mod returns; +mod same_length_and_capacity; mod same_name_method; mod self_named_constructors; mod semicolon_block; @@ -739,7 +740,10 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co Box::new(move |_| Box::new(cargo::Cargo::new(conf))), Box::new(|_| Box::new(empty_with_brackets::EmptyWithBrackets::default())), Box::new(|_| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings)), - Box::new(|_| Box::new(format_push_string::FormatPushString)), + { + let format_args = format_args_storage.clone(); + Box::new(move |_| Box::new(format_push_string::FormatPushString::new(format_args.clone()))) + }, Box::new(move |_| Box::new(large_include_file::LargeIncludeFile::new(conf))), Box::new(|_| Box::new(strings::TrimSplitWhitespace)), Box::new(|_| Box::new(rc_clone_in_vec_init::RcCloneInVecInit)), @@ -852,6 +856,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co Box::new(|_| Box::new(volatile_composites::VolatileComposites)), Box::new(|_| Box::::default()), Box::new(move |_| Box::new(manual_ilog2::ManualIlog2::new(conf))), + Box::new(|_| Box::new(same_length_and_capacity::SameLengthAndCapacity)), // add late passes here, used by `cargo dev new_lint` ]; store.late_passes.extend(late_lints); diff --git a/clippy_lints/src/loops/for_kv_map.rs b/clippy_lints/src/loops/for_kv_map.rs index c6b650a1a88b..39b2391c98ec 100644 --- a/clippy_lints/src/loops/for_kv_map.rs +++ b/clippy_lints/src/loops/for_kv_map.rs @@ -34,7 +34,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx _ => arg, }; - if ty.is_diag_item(cx, sym::HashMap) || ty.is_diag_item(cx, sym::BTreeMap) { + if matches!(ty.opt_diag_name(cx), Some(sym::HashMap | sym::BTreeMap)) { span_lint_and_then( cx, FOR_KV_MAP, diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 21198c3c8bc2..ddc783069385 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -26,6 +26,7 @@ mod while_let_on_iterator; use clippy_config::Conf; use clippy_utils::msrvs::Msrv; +use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; use clippy_utils::{higher, sym}; use rustc_ast::Label; use rustc_hir::{Expr, ExprKind, LoopSource, Pat}; @@ -881,13 +882,44 @@ impl<'tcx> LateLintPass<'tcx> for Loops { manual_while_let_some::check(cx, condition, body, span); } - if let ExprKind::MethodCall(path, recv, [arg], _) = expr.kind - && matches!( - path.ident.name, - sym::all | sym::any | sym::filter_map | sym::find_map | sym::flat_map | sym::for_each | sym::map - ) - { - unused_enumerate_index::check_method(cx, expr, recv, arg); + if let ExprKind::MethodCall(path, recv, args, _) = expr.kind { + let name = path.ident.name; + + let is_iterator_method = || { + cx.ty_based_def(expr) + .assoc_fn_parent(cx) + .is_diag_item(cx, sym::Iterator) + }; + + // is_iterator_method is a bit expensive, so we call it last in each match arm + match (name, args) { + (sym::for_each | sym::all | sym::any, [arg]) => { + if let ExprKind::Closure(closure) = arg.kind + && is_iterator_method() + { + unused_enumerate_index::check_method(cx, recv, arg, closure); + never_loop::check_iterator_reduction(cx, expr, recv, closure); + } + }, + + (sym::filter_map | sym::find_map | sym::flat_map | sym::map, [arg]) => { + if let ExprKind::Closure(closure) = arg.kind + && is_iterator_method() + { + unused_enumerate_index::check_method(cx, recv, arg, closure); + } + }, + + (sym::try_for_each | sym::reduce, [arg]) | (sym::fold | sym::try_fold, [_, arg]) => { + if let ExprKind::Closure(closure) = arg.kind + && is_iterator_method() + { + never_loop::check_iterator_reduction(cx, expr, recv, closure); + } + }, + + _ => {}, + } } } } diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index 0d37be17689a..a037af3433c3 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -3,14 +3,16 @@ use super::utils::make_iterator_snippet; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::ForLoop; use clippy_utils::macros::root_macro_call_first_node; -use clippy_utils::source::snippet; +use clippy_utils::source::{snippet, snippet_with_context}; +use clippy_utils::sym; use clippy_utils::visitors::{Descend, for_each_expr_without_closures}; use rustc_errors::Applicability; use rustc_hir::{ - Block, Destination, Expr, ExprKind, HirId, InlineAsm, InlineAsmOperand, Node, Pat, Stmt, StmtKind, StructTailExpr, + Block, Closure, Destination, Expr, ExprKind, HirId, InlineAsm, InlineAsmOperand, Node, Pat, Stmt, StmtKind, + StructTailExpr, }; use rustc_lint::LateContext; -use rustc_span::{BytePos, Span, sym}; +use rustc_span::{BytePos, Span}; use std::iter::once; use std::ops::ControlFlow; @@ -72,6 +74,31 @@ pub(super) fn check<'tcx>( } } +pub(super) fn check_iterator_reduction<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + recv: &'tcx Expr<'tcx>, + closure: &'tcx Closure<'tcx>, +) { + let closure_body = cx.tcx.hir_body(closure.body).value; + let body_ty = cx.typeck_results().expr_ty(closure_body); + if body_ty.is_never() { + span_lint_and_then( + cx, + NEVER_LOOP, + expr.span, + "this iterator reduction never loops (closure always diverges)", + |diag| { + let mut app = Applicability::HasPlaceholders; + let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "", &mut app).0; + diag.note("if you only need one element, `if let Some(x) = iter.next()` is clearer"); + let sugg = format!("if let Some(x) = {recv_snip}.next() {{ ... }}"); + diag.span_suggestion_verbose(expr.span, "consider this pattern", sugg, app); + }, + ); + } +} + fn contains_any_break_or_continue(block: &Block<'_>) -> bool { for_each_expr_without_closures(block, |e| match e.kind { ExprKind::Break(..) | ExprKind::Continue(..) => ControlFlow::Break(()), diff --git a/clippy_lints/src/loops/unused_enumerate_index.rs b/clippy_lints/src/loops/unused_enumerate_index.rs index 82ded453616d..816273c7ba8b 100644 --- a/clippy_lints/src/loops/unused_enumerate_index.rs +++ b/clippy_lints/src/loops/unused_enumerate_index.rs @@ -1,10 +1,10 @@ use super::UNUSED_ENUMERATE_INDEX; use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; +use clippy_utils::res::MaybeDef; use clippy_utils::source::{SpanRangeExt, walk_span_to_context}; use clippy_utils::{expr_or_init, pat_is_wild}; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, Pat, PatKind, TyKind}; +use rustc_hir::{Closure, Expr, ExprKind, Pat, PatKind, TyKind}; use rustc_lint::LateContext; use rustc_span::{Span, SyntaxContext, sym}; @@ -60,14 +60,12 @@ pub(super) fn check<'tcx>( pub(super) fn check_method<'tcx>( cx: &LateContext<'tcx>, - e: &'tcx Expr<'tcx>, recv: &'tcx Expr<'tcx>, arg: &'tcx Expr<'tcx>, + closure: &'tcx Closure<'tcx>, ) { - if let ExprKind::Closure(closure) = arg.kind - && let body = cx.tcx.hir_body(closure.body) - && let [param] = body.params - && cx.ty_based_def(e).opt_parent(cx).is_diag_item(cx, sym::Iterator) + let body = cx.tcx.hir_body(closure.body); + if let [param] = body.params && let [input] = closure.fn_decl.inputs && !arg.span.from_expansion() && !input.span.from_expansion() diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs index 0f3d8b336675..38ee4ce104a5 100644 --- a/clippy_lints/src/manual_let_else.rs +++ b/clippy_lints/src/manual_let_else.rs @@ -374,7 +374,7 @@ fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>, check_types: boo } let ty = typeck_results.pat_ty(pat); // Option and Result are allowed, everything else isn't. - if !(ty.is_diag_item(cx, sym::Option) || ty.is_diag_item(cx, sym::Result)) { + if !matches!(ty.opt_diag_name(cx), Some(sym::Option | sym::Result)) { has_disallowed = true; } }); diff --git a/clippy_lints/src/matches/match_like_matches.rs b/clippy_lints/src/matches/match_like_matches.rs index 89411115f730..c26b2dbde7fc 100644 --- a/clippy_lints/src/matches/match_like_matches.rs +++ b/clippy_lints/src/matches/match_like_matches.rs @@ -3,7 +3,7 @@ use super::REDUNDANT_PATTERN_MATCHING; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::has_let_expr; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::{is_lint_allowed, is_wild, span_contains_comment}; use rustc_ast::LitKind; use rustc_errors::Applicability; @@ -44,6 +44,8 @@ pub(crate) fn check_if_let<'tcx>( { ex_new = ex_inner; } + + let (snippet, _) = snippet_with_context(cx, ex_new.span, expr.span.ctxt(), "..", &mut applicability); span_lint_and_then( cx, MATCH_LIKE_MATCHES_MACRO, @@ -53,11 +55,7 @@ pub(crate) fn check_if_let<'tcx>( diag.span_suggestion_verbose( expr.span, "use `matches!` directly", - format!( - "{}matches!({}, {pat})", - if b0 { "" } else { "!" }, - snippet_with_applicability(cx, ex_new.span, "..", &mut applicability), - ), + format!("{}matches!({snippet}, {pat})", if b0 { "" } else { "!" }), applicability, ); }, @@ -178,6 +176,8 @@ pub(super) fn check_match<'tcx>( { ex_new = ex_inner; } + + let (snippet, _) = snippet_with_context(cx, ex_new.span, e.span.ctxt(), "..", &mut applicability); span_lint_and_then( cx, MATCH_LIKE_MATCHES_MACRO, @@ -187,11 +187,7 @@ pub(super) fn check_match<'tcx>( diag.span_suggestion_verbose( e.span, "use `matches!` directly", - format!( - "{}matches!({}, {pat_and_guard})", - if b0 { "" } else { "!" }, - snippet_with_applicability(cx, ex_new.span, "..", &mut applicability), - ), + format!("{}matches!({snippet}, {pat_and_guard})", if b0 { "" } else { "!" },), applicability, ); }, diff --git a/clippy_lints/src/matches/match_wild_enum.rs b/clippy_lints/src/matches/match_wild_enum.rs index fa44a56af182..00bd1c2ca698 100644 --- a/clippy_lints/src/matches/match_wild_enum.rs +++ b/clippy_lints/src/matches/match_wild_enum.rs @@ -16,7 +16,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { let ty = cx.typeck_results().expr_ty(ex).peel_refs(); let adt_def = match ty.kind() { ty::Adt(adt_def, _) - if adt_def.is_enum() && !(ty.is_diag_item(cx, sym::Option) || ty.is_diag_item(cx, sym::Result)) => + if adt_def.is_enum() && !matches!(ty.opt_diag_name(cx), Some(sym::Option | sym::Result)) => { adt_def }, diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index 288f966991ac..e891b2ac6d64 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -26,12 +26,10 @@ pub(super) fn check<'tcx>( let arg_root = get_arg_root(cx, arg); if contains_call(cx, arg_root) && !contains_return(arg_root) { let receiver_type = cx.typeck_results().expr_ty_adjusted(receiver); - let closure_args = if receiver_type.is_diag_item(cx, sym::Option) { - "||" - } else if receiver_type.is_diag_item(cx, sym::Result) { - "|_|" - } else { - return; + let closure_args = match receiver_type.opt_diag_name(cx) { + Some(sym::Option) => "||", + Some(sym::Result) => "|_|", + _ => return, }; let span_replace_word = method_span.with_hi(expr.span.hi()); diff --git a/clippy_lints/src/methods/iter_count.rs b/clippy_lints/src/methods/iter_count.rs index ea2508cd7f38..8b303c0ca5b2 100644 --- a/clippy_lints/src/methods/iter_count.rs +++ b/clippy_lints/src/methods/iter_count.rs @@ -11,26 +11,17 @@ use super::ITER_COUNT; pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx Expr<'tcx>, iter_method: Symbol) { let ty = cx.typeck_results().expr_ty(recv); - let caller_type = if derefs_to_slice(cx, recv, ty).is_some() { - "slice" - } else if ty.is_diag_item(cx, sym::Vec) { - "Vec" - } else if ty.is_diag_item(cx, sym::VecDeque) { - "VecDeque" - } else if ty.is_diag_item(cx, sym::HashSet) { - "HashSet" - } else if ty.is_diag_item(cx, sym::HashMap) { - "HashMap" - } else if ty.is_diag_item(cx, sym::BTreeMap) { - "BTreeMap" - } else if ty.is_diag_item(cx, sym::BTreeSet) { - "BTreeSet" - } else if ty.is_diag_item(cx, sym::LinkedList) { - "LinkedList" - } else if ty.is_diag_item(cx, sym::BinaryHeap) { - "BinaryHeap" - } else { - return; + let caller_type = match ty.opt_diag_name(cx) { + _ if derefs_to_slice(cx, recv, ty).is_some() => "slice", + Some(sym::Vec) => "Vec", + Some(sym::VecDeque) => "VecDeque", + Some(sym::HashSet) => "HashSet", + Some(sym::HashMap) => "HashMap", + Some(sym::BTreeMap) => "BTreeMap", + Some(sym::BTreeSet) => "BTreeSet", + Some(sym::LinkedList) => "LinkedList", + Some(sym::BinaryHeap) => "BinaryHeap", + _ => return, }; let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index 2d6bc36dc535..16db8663941e 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -38,7 +38,7 @@ pub(super) fn check<'tcx>( _ => return, } && let ty = cx.typeck_results().expr_ty_adjusted(recv).peel_refs() - && (ty.is_diag_item(cx, sym::HashMap) || ty.is_diag_item(cx, sym::BTreeMap)) + && matches!(ty.opt_diag_name(cx), Some(sym::HashMap | sym::BTreeMap)) { let mut applicability = rustc_errors::Applicability::MachineApplicable; let recv_snippet = snippet_with_applicability(cx, recv.span, "map", &mut applicability); diff --git a/clippy_lints/src/methods/join_absolute_paths.rs b/clippy_lints/src/methods/join_absolute_paths.rs index e84b7452c758..905a58afa795 100644 --- a/clippy_lints/src/methods/join_absolute_paths.rs +++ b/clippy_lints/src/methods/join_absolute_paths.rs @@ -13,7 +13,7 @@ use super::JOIN_ABSOLUTE_PATHS; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx Expr<'tcx>, join_arg: &'tcx Expr<'tcx>, expr_span: Span) { let ty = cx.typeck_results().expr_ty(recv).peel_refs(); - if (ty.is_diag_item(cx, sym::Path) || ty.is_diag_item(cx, sym::PathBuf)) + if matches!(ty.opt_diag_name(cx), Some(sym::Path | sym::PathBuf)) && let ExprKind::Lit(spanned) = expr_or_init(cx, join_arg).kind && let LitKind::Str(symbol, _) = spanned.node && let sym_str = symbol.as_str() diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs index a1aac96ccf86..8a1cc664ac60 100644 --- a/clippy_lints/src/methods/map_clone.rs +++ b/clippy_lints/src/methods/map_clone.rs @@ -25,7 +25,7 @@ fn should_run_lint(cx: &LateContext<'_>, e: &hir::Expr<'_>, method_parent_id: De } // We check if it's an `Option` or a `Result`. if let Some(ty) = method_parent_id.opt_impl_ty(cx) { - if !ty.is_diag_item(cx, sym::Option) && !ty.is_diag_item(cx, sym::Result) { + if !matches!(ty.opt_diag_name(cx), Some(sym::Option | sym::Result)) { return false; } } else { diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index 62bdc4a3e411..8eb26fb50747 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeDef; use clippy_utils::source::snippet; @@ -51,11 +51,8 @@ pub(super) fn check<'tcx>( // get snippets for args to map() and unwrap_or_else() let map_snippet = snippet(cx, map_arg.span, ".."); let unwrap_snippet = snippet(cx, unwrap_arg.span, ".."); - // lint, with note if neither arg is > 1 line and both map() and - // unwrap_or_else() have the same span - let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1; - let same_span = map_arg.span.eq_ctxt(unwrap_arg.span); - if same_span && !multiline { + // lint, with note if both map() and unwrap_or_else() have the same span + if map_arg.span.eq_ctxt(unwrap_arg.span) { let var_snippet = snippet(cx, recv.span, ".."); span_lint_and_sugg( cx, @@ -67,9 +64,6 @@ pub(super) fn check<'tcx>( Applicability::MachineApplicable, ); return true; - } else if same_span && multiline { - span_lint(cx, MAP_UNWRAP_OR, expr.span, msg); - return true; } } diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index 055fdcabdd21..0e2012319147 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -81,7 +81,9 @@ pub(super) fn check<'tcx>( }, _ => return, }; - } else if let ExprKind::Index(_, index, _) = parent.kind { + } else if let ExprKind::Index(_, index, _) = parent.kind + && cx.typeck_results().expr_ty(index).is_usize() + { app = Applicability::MaybeIncorrect; let snip = snippet_with_applicability(cx, index.span, "_", &mut app); sugg = format!("nth({snip}).unwrap()"); diff --git a/clippy_lints/src/methods/obfuscated_if_else.rs b/clippy_lints/src/methods/obfuscated_if_else.rs index b2466bbd982d..69d851e81600 100644 --- a/clippy_lints/src/methods/obfuscated_if_else.rs +++ b/clippy_lints/src/methods/obfuscated_if_else.rs @@ -1,7 +1,7 @@ use super::OBFUSCATED_IF_ELSE; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::eager_or_lazy::switch_to_eager_eval; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::Sugg; use clippy_utils::{get_parent_expr, sym}; use rustc_errors::Applicability; @@ -33,20 +33,22 @@ pub(super) fn check<'tcx>( let if_then = match then_method_name { sym::then if let ExprKind::Closure(closure) = then_arg.kind => { let body = cx.tcx.hir_body(closure.body); - snippet_with_applicability(cx, body.value.span, "..", &mut applicability) + snippet_with_context(cx, body.value.span, expr.span.ctxt(), "..", &mut applicability).0 }, - sym::then_some => snippet_with_applicability(cx, then_arg.span, "..", &mut applicability), + sym::then_some => snippet_with_context(cx, then_arg.span, expr.span.ctxt(), "..", &mut applicability).0, _ => return, }; let els = match unwrap { - Unwrap::Or(arg) => snippet_with_applicability(cx, arg.span, "..", &mut applicability), + Unwrap::Or(arg) => snippet_with_context(cx, arg.span, expr.span.ctxt(), "..", &mut applicability).0, Unwrap::OrElse(arg) => match arg.kind { ExprKind::Closure(closure) => { let body = cx.tcx.hir_body(closure.body); - snippet_with_applicability(cx, body.value.span, "..", &mut applicability) + snippet_with_context(cx, body.value.span, expr.span.ctxt(), "..", &mut applicability).0 + }, + ExprKind::Path(_) => { + snippet_with_context(cx, arg.span, expr.span.ctxt(), "_", &mut applicability).0 + "()" }, - ExprKind::Path(_) => snippet_with_applicability(cx, arg.span, "_", &mut applicability) + "()", _ => return, }, Unwrap::OrDefault => "Default::default()".into(), @@ -54,7 +56,7 @@ pub(super) fn check<'tcx>( let sugg = format!( "if {} {{ {} }} else {{ {} }}", - Sugg::hir_with_applicability(cx, then_recv, "..", &mut applicability), + Sugg::hir_with_context(cx, then_recv, expr.span.ctxt(), "..", &mut applicability), if_then, els ); diff --git a/clippy_lints/src/methods/or_then_unwrap.rs b/clippy_lints/src/methods/or_then_unwrap.rs index 07199b84f39e..448ab621a7ce 100644 --- a/clippy_lints/src/methods/or_then_unwrap.rs +++ b/clippy_lints/src/methods/or_then_unwrap.rs @@ -20,24 +20,28 @@ pub(super) fn check<'tcx>( let title; let or_arg_content: Span; - if ty.is_diag_item(cx, sym::Option) { - title = "found `.or(Some(…)).unwrap()`"; - if let Some(content) = get_content_if_ctor_matches(cx, or_arg, LangItem::OptionSome) { - or_arg_content = content; - } else { + match ty.opt_diag_name(cx) { + Some(sym::Option) => { + title = "found `.or(Some(…)).unwrap()`"; + if let Some(content) = get_content_if_ctor_matches(cx, or_arg, LangItem::OptionSome) { + or_arg_content = content; + } else { + return; + } + }, + Some(sym::Result) => { + title = "found `.or(Ok(…)).unwrap()`"; + if let Some(content) = get_content_if_ctor_matches(cx, or_arg, LangItem::ResultOk) { + or_arg_content = content; + } else { + return; + } + }, + _ => { + // Someone has implemented a struct with .or(...).unwrap() chaining, + // but it's not an Option or a Result, so bail return; - } - } else if ty.is_diag_item(cx, sym::Result) { - title = "found `.or(Ok(…)).unwrap()`"; - if let Some(content) = get_content_if_ctor_matches(cx, or_arg, LangItem::ResultOk) { - or_arg_content = content; - } else { - return; - } - } else { - // Someone has implemented a struct with .or(...).unwrap() chaining, - // but it's not an Option or a Result, so bail - return; + }, } let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index bd471e0b18e3..9dae6fbb48dd 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -1,44 +1,52 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::res::{MaybeDef, MaybeResPath, MaybeTypeckRes}; +use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath, MaybeTypeckRes}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{peel_blocks, strip_pat_refs}; +use clippy_utils::{DefinedTy, ExprUseNode, expr_use_ctxt, peel_blocks, strip_pat_refs}; use rustc_ast::ast; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::PatKind; +use rustc_hir::def::{DefKind, Res}; use rustc_lint::LateContext; -use rustc_middle::ty; -use rustc_span::{Span, sym}; +use rustc_middle::ty::{self, Ty}; +use rustc_span::{Span, Symbol, sym}; use super::UNNECESSARY_FOLD; /// Do we need to suggest turbofish when suggesting a replacement method? /// Changing `fold` to `sum` needs it sometimes when the return type can't be /// inferred. This checks for some common cases where it can be safely omitted -fn needs_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { - let parent = cx.tcx.parent_hir_node(expr.hir_id); - - // some common cases where turbofish isn't needed: - // - assigned to a local variable with a type annotation - if let hir::Node::LetStmt(local) = parent - && local.ty.is_some() +fn needs_turbofish<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) -> bool { + let use_cx = expr_use_ctxt(cx, expr); + if use_cx.same_ctxt + && let use_node = use_cx.use_node(cx) + && let Some(ty) = use_node.defined_ty(cx) { - return false; - } + // some common cases where turbofish isn't needed: + match (use_node, ty) { + // - assigned to a local variable with a type annotation + (ExprUseNode::LetStmt(_), _) => return false, - // - part of a function call argument, can be inferred from the function signature (provided that - // the parameter is not a generic type parameter) - if let hir::Node::Expr(parent_expr) = parent - && let hir::ExprKind::Call(recv, args) = parent_expr.kind - && let hir::ExprKind::Path(ref qpath) = recv.kind - && let Some(fn_def_id) = cx.qpath_res(qpath, recv.hir_id).opt_def_id() - && let fn_sig = cx.tcx.fn_sig(fn_def_id).skip_binder().skip_binder() - && let Some(arg_pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id) - && let Some(ty) = fn_sig.inputs().get(arg_pos) - && !matches!(ty.kind(), ty::Param(_)) - { - return false; + // - part of a function call argument, can be inferred from the function signature (provided that the + // parameter is not a generic type parameter) + (ExprUseNode::FnArg(..), DefinedTy::Mir { ty: arg_ty, .. }) + if !matches!(arg_ty.skip_binder().kind(), ty::Param(_)) => + { + return false; + }, + + // - the final expression in the body of a function with a simple return type + (ExprUseNode::Return(_), DefinedTy::Mir { ty: fn_return_ty, .. }) + if !fn_return_ty + .skip_binder() + .walk() + .any(|generic| generic.as_type().is_some_and(Ty::is_impl_trait)) => + { + return false; + }, + _ => {}, + } } // if it's neither of those, stay on the safe side and suggest turbofish, @@ -60,7 +68,7 @@ fn check_fold_with_op( fold_span: Span, op: hir::BinOpKind, replacement: Replacement, -) { +) -> bool { if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = acc.kind // Extract the body of the closure passed to fold && let closure_body = cx.tcx.hir_body(body) @@ -93,7 +101,7 @@ fn check_fold_with_op( r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability), ) } else { - format!("{method}{turbofish}()", method = replacement.method_name,) + format!("{method}{turbofish}()", method = replacement.method_name) }; span_lint_and_sugg( @@ -105,12 +113,47 @@ fn check_fold_with_op( sugg, applicability, ); + return true; + } + false +} + +fn check_fold_with_method( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + acc: &hir::Expr<'_>, + fold_span: Span, + method: Symbol, + replacement: Replacement, +) { + // Extract the name of the function passed to `fold` + if let Res::Def(DefKind::AssocFn, fn_did) = acc.res_if_named(cx, method) + // Check if the function belongs to the operator + && cx.tcx.is_diagnostic_item(method, fn_did) + { + let applicability = Applicability::MachineApplicable; + + let turbofish = if replacement.has_generic_return { + format!("::<{}>", cx.typeck_results().expr_ty(expr)) + } else { + String::new() + }; + + span_lint_and_sugg( + cx, + UNNECESSARY_FOLD, + fold_span.with_hi(expr.span.hi()), + "this `.fold` can be written more succinctly using another method", + "try", + format!("{method}{turbofish}()", method = replacement.method_name), + applicability, + ); } } -pub(super) fn check( - cx: &LateContext<'_>, - expr: &hir::Expr<'_>, +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &hir::Expr<'tcx>, init: &hir::Expr<'_>, acc: &hir::Expr<'_>, fold_span: Span, @@ -124,60 +167,40 @@ pub(super) fn check( if let hir::ExprKind::Lit(lit) = init.kind { match lit.node { ast::LitKind::Bool(false) => { - check_fold_with_op( - cx, - expr, - acc, - fold_span, - hir::BinOpKind::Or, - Replacement { - method_name: "any", - has_args: true, - has_generic_return: false, - }, - ); + let replacement = Replacement { + method_name: "any", + has_args: true, + has_generic_return: false, + }; + check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, replacement); }, ast::LitKind::Bool(true) => { - check_fold_with_op( - cx, - expr, - acc, - fold_span, - hir::BinOpKind::And, - Replacement { - method_name: "all", - has_args: true, - has_generic_return: false, - }, - ); + let replacement = Replacement { + method_name: "all", + has_args: true, + has_generic_return: false, + }; + check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, replacement); }, ast::LitKind::Int(Pu128(0), _) => { - check_fold_with_op( - cx, - expr, - acc, - fold_span, - hir::BinOpKind::Add, - Replacement { - method_name: "sum", - has_args: false, - has_generic_return: needs_turbofish(cx, expr), - }, - ); + let replacement = Replacement { + method_name: "sum", + has_args: false, + has_generic_return: needs_turbofish(cx, expr), + }; + if !check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, replacement) { + check_fold_with_method(cx, expr, acc, fold_span, sym::add, replacement); + } }, ast::LitKind::Int(Pu128(1), _) => { - check_fold_with_op( - cx, - expr, - acc, - fold_span, - hir::BinOpKind::Mul, - Replacement { - method_name: "product", - has_args: false, - has_generic_return: needs_turbofish(cx, expr), - }, - ); + let replacement = Replacement { + method_name: "product", + has_args: false, + has_generic_return: needs_turbofish(cx, expr), + }; + if !check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, replacement) { + check_fold_with_method(cx, expr, acc, fold_span, sym::mul, replacement); + } }, _ => (), } diff --git a/clippy_lints/src/methods/unnecessary_get_then_check.rs b/clippy_lints/src/methods/unnecessary_get_then_check.rs index 10ea0c0c3e23..3207c4207fc0 100644 --- a/clippy_lints/src/methods/unnecessary_get_then_check.rs +++ b/clippy_lints/src/methods/unnecessary_get_then_check.rs @@ -11,11 +11,11 @@ use rustc_span::{Span, sym}; use super::UNNECESSARY_GET_THEN_CHECK; fn is_a_std_set_type(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { - ty.is_diag_item(cx, sym::HashSet) || ty.is_diag_item(cx, sym::BTreeSet) + matches!(ty.opt_diag_name(cx), Some(sym::HashSet | sym::BTreeSet)) } fn is_a_std_map_type(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { - ty.is_diag_item(cx, sym::HashMap) || ty.is_diag_item(cx, sym::BTreeMap) + matches!(ty.opt_diag_name(cx), Some(sym::HashMap | sym::BTreeMap)) } pub(super) fn check( diff --git a/clippy_lints/src/methods/unwrap_expect_used.rs b/clippy_lints/src/methods/unwrap_expect_used.rs index 73a407be4f21..30db2a75df57 100644 --- a/clippy_lints/src/methods/unwrap_expect_used.rs +++ b/clippy_lints/src/methods/unwrap_expect_used.rs @@ -46,19 +46,19 @@ pub(super) fn check( ) { let ty = cx.typeck_results().expr_ty(recv).peel_refs(); - let (kind, none_value, none_prefix) = if ty.is_diag_item(cx, sym::Option) && !is_err { - ("an `Option`", "None", "") - } else if ty.is_diag_item(cx, sym::Result) - && let ty::Adt(_, substs) = ty.kind() - && let Some(t_or_e_ty) = substs[usize::from(!is_err)].as_type() - { - if is_never_like(t_or_e_ty) { - return; - } + let (kind, none_value, none_prefix) = match ty.opt_diag_name(cx) { + Some(sym::Option) if !is_err => ("an `Option`", "None", ""), + Some(sym::Result) + if let ty::Adt(_, substs) = ty.kind() + && let Some(t_or_e_ty) = substs[usize::from(!is_err)].as_type() => + { + if is_never_like(t_or_e_ty) { + return; + } - ("a `Result`", if is_err { "Ok" } else { "Err" }, "an ") - } else { - return; + ("a `Result`", if is_err { "Ok" } else { "Err" }, "an ") + }, + _ => return, }; let method_suffix = if is_err { "_err" } else { "" }; diff --git a/clippy_lints/src/missing_fields_in_debug.rs b/clippy_lints/src/missing_fields_in_debug.rs index 15b773c2c64f..a26f24d15247 100644 --- a/clippy_lints/src/missing_fields_in_debug.rs +++ b/clippy_lints/src/missing_fields_in_debug.rs @@ -112,10 +112,14 @@ fn should_lint<'tcx>( if let ExprKind::MethodCall(path, recv, ..) = &expr.kind { let recv_ty = typeck_results.expr_ty(recv).peel_refs(); - if path.ident.name == sym::debug_struct && recv_ty.is_diag_item(cx, sym::Formatter) { - has_debug_struct = true; - } else if path.ident.name == sym::finish_non_exhaustive && recv_ty.is_diag_item(cx, sym::DebugStruct) { - has_finish_non_exhaustive = true; + match (path.ident.name, recv_ty.opt_diag_name(cx)) { + (sym::debug_struct, Some(sym::Formatter)) => { + has_debug_struct = true; + }, + (sym::finish_non_exhaustive, Some(sym::DebugStruct)) => { + has_finish_non_exhaustive = true; + }, + _ => {}, } } ControlFlow::::Continue(()) diff --git a/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/clippy_lints/src/multiple_unsafe_ops_per_block.rs index 80cf081992cc..42dc9f2f1fa8 100644 --- a/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -3,13 +3,14 @@ use clippy_utils::diagnostics::span_lint_and_then; use hir::def::{DefKind, Res}; use hir::{BlockCheckMode, ExprKind, QPath, UnOp}; use rustc_ast::{BorrowKind, Mutability}; +use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::intravisit::{Visitor, walk_body, walk_expr}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, TyCtxt, TypeckResults}; use rustc_session::declare_lint_pass; -use rustc_span::{DesugaringKind, Span}; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -56,12 +57,16 @@ declare_clippy_lint! { /// } /// ``` /// - /// ### Note + /// ### Notes /// - /// Taking a raw pointer to a union field is always safe and will - /// not be considered unsafe by this lint, even when linting code written - /// with a specified Rust version of 1.91 or earlier (which required - /// using an `unsafe` block). + /// - Unsafe operations only count towards the total for the innermost + /// enclosing `unsafe` block. + /// - Each call to a macro expanding to unsafe operations count for one + /// unsafe operation. + /// - Taking a raw pointer to a union field is always safe and will + /// not be considered unsafe by this lint, even when linting code written + /// with a specified Rust version of 1.91 or earlier (which required + /// using an `unsafe` block). #[clippy::version = "1.69.0"] pub MULTIPLE_UNSAFE_OPS_PER_BLOCK, restriction, @@ -71,10 +76,7 @@ declare_lint_pass!(MultipleUnsafeOpsPerBlock => [MULTIPLE_UNSAFE_OPS_PER_BLOCK]) impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) { - if !matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) - || block.span.in_external_macro(cx.tcx.sess.source_map()) - || block.span.is_desugaring(DesugaringKind::Await) - { + if !matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) || block.span.from_expansion() { return; } let unsafe_ops = UnsafeExprCollector::collect_unsafe_exprs(cx, block); @@ -100,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock { struct UnsafeExprCollector<'tcx> { tcx: TyCtxt<'tcx>, typeck_results: &'tcx TypeckResults<'tcx>, - unsafe_ops: Vec<(&'static str, Span)>, + unsafe_ops: FxHashMap, } impl<'tcx> UnsafeExprCollector<'tcx> { @@ -108,10 +110,33 @@ impl<'tcx> UnsafeExprCollector<'tcx> { let mut collector = Self { tcx: cx.tcx, typeck_results: cx.typeck_results(), - unsafe_ops: vec![], + unsafe_ops: FxHashMap::default(), }; collector.visit_block(block); - collector.unsafe_ops + #[allow( + rustc::potential_query_instability, + reason = "span ordering only needed inside the one expression being walked" + )] + let mut unsafe_ops = collector + .unsafe_ops + .into_iter() + .map(|(span, msg)| (msg, span)) + .collect::>(); + unsafe_ops.sort_unstable(); + unsafe_ops + } +} + +impl UnsafeExprCollector<'_> { + fn insert_span(&mut self, span: Span, message: &'static str) { + if span.from_expansion() { + self.unsafe_ops.insert( + span.source_callsite(), + "this macro call expands into one or more unsafe operations", + ); + } else { + self.unsafe_ops.insert(span, message); + } } } @@ -126,7 +151,10 @@ impl<'tcx> Visitor<'tcx> for UnsafeExprCollector<'tcx> { return self.visit_expr(e); }, - ExprKind::InlineAsm(_) => self.unsafe_ops.push(("inline assembly used here", expr.span)), + // Do not recurse inside an inner `unsafe` block, it will be checked on its own + ExprKind::Block(block, _) if matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) => return, + + ExprKind::InlineAsm(_) => self.insert_span(expr.span, "inline assembly used here"), ExprKind::AddrOf(BorrowKind::Raw, _, mut inner) => { while let ExprKind::Field(prefix, _) = inner.kind @@ -139,7 +167,7 @@ impl<'tcx> Visitor<'tcx> for UnsafeExprCollector<'tcx> { ExprKind::Field(e, _) => { if self.typeck_results.expr_ty(e).is_union() { - self.unsafe_ops.push(("union field access occurs here", expr.span)); + self.insert_span(expr.span, "union field access occurs here"); } }, @@ -157,12 +185,11 @@ impl<'tcx> Visitor<'tcx> for UnsafeExprCollector<'tcx> { .. }, )) => { - self.unsafe_ops - .push(("access of a mutable static occurs here", expr.span)); + self.insert_span(expr.span, "access of a mutable static occurs here"); }, ExprKind::Unary(UnOp::Deref, e) if self.typeck_results.expr_ty(e).is_raw_ptr() => { - self.unsafe_ops.push(("raw pointer dereference occurs here", expr.span)); + self.insert_span(expr.span, "raw pointer dereference occurs here"); }, ExprKind::Call(path_expr, _) => { @@ -172,7 +199,7 @@ impl<'tcx> Visitor<'tcx> for UnsafeExprCollector<'tcx> { _ => None, }; if opt_sig.is_some_and(|sig| sig.safety().is_unsafe()) { - self.unsafe_ops.push(("unsafe function call occurs here", expr.span)); + self.insert_span(expr.span, "unsafe function call occurs here"); } }, @@ -182,7 +209,7 @@ impl<'tcx> Visitor<'tcx> for UnsafeExprCollector<'tcx> { .type_dependent_def_id(expr.hir_id) .map(|def_id| self.tcx.fn_sig(def_id)); if opt_sig.is_some_and(|sig| sig.skip_binder().safety().is_unsafe()) { - self.unsafe_ops.push(("unsafe method call occurs here", expr.span)); + self.insert_span(expr.span, "unsafe method call occurs here"); } }, @@ -203,8 +230,7 @@ impl<'tcx> Visitor<'tcx> for UnsafeExprCollector<'tcx> { } )) ) { - self.unsafe_ops - .push(("modification of a mutable static occurs here", expr.span)); + self.insert_span(expr.span, "modification of a mutable static occurs here"); return self.visit_expr(rhs); } }, diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index 3d2285efbe18..f3e42b1c58f8 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -1,7 +1,7 @@ use super::needless_pass_by_value::requires_exact_signature; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::source::snippet; +use clippy_utils::source::HasSession as _; use clippy_utils::visitors::for_each_expr; use clippy_utils::{inherits_cfg, is_from_proc_macro, is_self}; use core::ops::ControlFlow; @@ -18,9 +18,9 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TyCtxt, UpvarId, UpvarPath}; use rustc_session::impl_lint_pass; -use rustc_span::Span; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; +use rustc_span::{BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -269,18 +269,27 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { // If the argument is never used mutably, we emit the warning. let sp = input.span; if let rustc_hir::TyKind::Ref(_, inner_ty) = input.kind { + let Some(after_mut_span) = cx.sess().source_map().span_extend_to_prev_str( + inner_ty.ty.span.shrink_to_lo(), + "mut", + true, + true, + ) else { + return; + }; + let mut_span = after_mut_span.with_lo(after_mut_span.lo() - BytePos(3)); let is_cfged = is_cfged.get_or_insert_with(|| inherits_cfg(cx.tcx, *fn_def_id)); span_lint_hir_and_then( cx, NEEDLESS_PASS_BY_REF_MUT, cx.tcx.local_def_id_to_hir_id(*fn_def_id), sp, - "this argument is a mutable reference, but not used mutably", + "this parameter is a mutable reference but is not used mutably", |diag| { diag.span_suggestion( - sp, - "consider changing to".to_string(), - format!("&{}", snippet(cx, cx.tcx.hir_span(inner_ty.ty.hir_id), "_"),), + mut_span, + "consider removing this `mut`", + "", Applicability::Unspecified, ); if cx.effective_visibilities.is_exported(*fn_def_id) { diff --git a/clippy_lints/src/ptr/cmp_null.rs b/clippy_lints/src/ptr/cmp_null.rs index 905b48e6d1d4..f2d1c855eddd 100644 --- a/clippy_lints/src/ptr/cmp_null.rs +++ b/clippy_lints/src/ptr/cmp_null.rs @@ -14,13 +14,14 @@ pub(super) fn check<'tcx>( l: &Expr<'_>, r: &Expr<'_>, ) -> bool { + let mut applicability = Applicability::MachineApplicable; let non_null_path_snippet = match ( is_lint_allowed(cx, CMP_NULL, expr.hir_id), is_null_path(cx, l), is_null_path(cx, r), ) { - (false, true, false) if let Some(sugg) = Sugg::hir_opt(cx, r) => sugg.maybe_paren(), - (false, false, true) if let Some(sugg) = Sugg::hir_opt(cx, l) => sugg.maybe_paren(), + (false, true, false) => Sugg::hir_with_context(cx, r, expr.span.ctxt(), "..", &mut applicability).maybe_paren(), + (false, false, true) => Sugg::hir_with_context(cx, l, expr.span.ctxt(), "..", &mut applicability).maybe_paren(), _ => return false, }; let invert = if op == BinOpKind::Eq { "" } else { "!" }; @@ -32,7 +33,7 @@ pub(super) fn check<'tcx>( "comparing with null is better expressed by the `.is_null()` method", "try", format!("{invert}{non_null_path_snippet}.is_null()",), - Applicability::MachineApplicable, + applicability, ); true } diff --git a/clippy_lints/src/ptr/mod.rs b/clippy_lints/src/ptr/mod.rs index 6b2647e7b0a2..c4f40a7ffcaa 100644 --- a/clippy_lints/src/ptr/mod.rs +++ b/clippy_lints/src/ptr/mod.rs @@ -45,7 +45,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// This lint checks for equality comparisons with `ptr::null` + /// This lint checks for equality comparisons with `ptr::null` or `ptr::null_mut` /// /// ### Why is this bad? /// It's easier and more readable to use the inherent @@ -56,7 +56,7 @@ declare_clippy_lint! { /// ```rust,ignore /// use std::ptr; /// - /// if x == ptr::null { + /// if x == ptr::null() { /// // .. /// } /// ``` diff --git a/clippy_lints/src/same_length_and_capacity.rs b/clippy_lints/src/same_length_and_capacity.rs new file mode 100644 index 000000000000..042dec35f7c9 --- /dev/null +++ b/clippy_lints/src/same_length_and_capacity.rs @@ -0,0 +1,105 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::res::MaybeDef; +use clippy_utils::{eq_expr_value, sym}; +use rustc_hir::{Expr, ExprKind, LangItem, QPath}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_lint_pass; +use rustc_span::symbol::sym as rustc_sym; + +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for usages of `Vec::from_raw_parts` and `String::from_raw_parts` + /// where the same expression is used for the length and the capacity. + /// + /// ### Why is this bad? + /// + /// If the same expression is being passed for the length and + /// capacity, it is most likely a semantic error. In the case of a + /// Vec, for example, the only way to end up with one that has + /// the same length and capacity is by going through a boxed slice, + /// e.g. `Box::from(some_vec)`, which shrinks the capacity to match + /// the length. + /// + /// ### Example + /// + /// ```no_run + /// #![feature(vec_into_raw_parts)] + /// let mut original: Vec:: = Vec::with_capacity(20); + /// original.extend([1, 2, 3, 4, 5]); + /// + /// let (ptr, mut len, cap) = original.into_raw_parts(); + /// + /// // I will add three more integers: + /// unsafe { + /// let ptr = ptr as *mut i32; + /// + /// for i in 6..9 { + /// *ptr.add(i - 1) = i as i32; + /// len += 1; + /// } + /// } + /// + /// // But I forgot the capacity was separate from the length: + /// let reconstructed = unsafe { Vec::from_raw_parts(ptr, len, len) }; + /// ``` + /// + /// Use instead: + /// ```no_run + /// #![feature(vec_into_raw_parts)] + /// let mut original: Vec:: = Vec::with_capacity(20); + /// original.extend([1, 2, 3, 4, 5]); + /// + /// let (ptr, mut len, cap) = original.into_raw_parts(); + /// + /// // I will add three more integers: + /// unsafe { + /// let ptr = ptr as *mut i32; + /// + /// for i in 6..9 { + /// *ptr.add(i - 1) = i as i32; + /// len += 1; + /// } + /// } + /// + /// // This time, leverage the previously saved capacity: + /// let reconstructed = unsafe { Vec::from_raw_parts(ptr, len, cap) }; + /// ``` + #[clippy::version = "1.93.0"] + pub SAME_LENGTH_AND_CAPACITY, + pedantic, + "`from_raw_parts` with same length and capacity" +} +declare_lint_pass!(SameLengthAndCapacity => [SAME_LENGTH_AND_CAPACITY]); + +impl<'tcx> LateLintPass<'tcx> for SameLengthAndCapacity { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if let ExprKind::Call(path_expr, args) = expr.kind + && let ExprKind::Path(QPath::TypeRelative(ty, fn_path)) = path_expr.kind + && fn_path.ident.name == sym::from_raw_parts + && args.len() >= 3 + && eq_expr_value(cx, &args[1], &args[2]) + { + let middle_ty = cx.typeck_results().node_type(ty.hir_id); + if middle_ty.is_diag_item(cx, rustc_sym::Vec) { + span_lint_and_help( + cx, + SAME_LENGTH_AND_CAPACITY, + expr.span, + "usage of `Vec::from_raw_parts` with the same expression for length and capacity", + None, + "try `Box::from(slice::from_raw_parts(...)).into::>()`", + ); + } else if middle_ty.is_lang_item(cx, LangItem::String) { + span_lint_and_help( + cx, + SAME_LENGTH_AND_CAPACITY, + expr.span, + "usage of `String::from_raw_parts` with the same expression for length and capacity", + None, + "try `String::from(str::from_utf8_unchecked(slice::from_raw_parts(...)))`", + ); + } + } + } +} diff --git a/clippy_lints/src/set_contains_or_insert.rs b/clippy_lints/src/set_contains_or_insert.rs index 688da33a1777..7482bac4c7b4 100644 --- a/clippy_lints/src/set_contains_or_insert.rs +++ b/clippy_lints/src/set_contains_or_insert.rs @@ -112,6 +112,16 @@ fn try_parse_op_call<'tcx>( None } +fn is_set_mutated<'tcx>(cx: &LateContext<'tcx>, contains_expr: &OpExpr<'tcx>, expr: &'tcx Expr<'_>) -> bool { + // Guard on type to avoid useless potentially expansive `SpanlessEq` checks + cx.typeck_results().expr_ty_adjusted(expr).is_mutable_ptr() + && matches!( + cx.typeck_results().expr_ty(expr).peel_refs().opt_diag_name(cx), + Some(sym::HashSet | sym::BTreeSet) + ) + && SpanlessEq::new(cx).eq_expr(contains_expr.receiver, expr.peel_borrows()) +} + fn find_insert_calls<'tcx>( cx: &LateContext<'tcx>, contains_expr: &OpExpr<'tcx>, @@ -122,9 +132,14 @@ fn find_insert_calls<'tcx>( && SpanlessEq::new(cx).eq_expr(contains_expr.receiver, insert_expr.receiver) && SpanlessEq::new(cx).eq_expr(contains_expr.value, insert_expr.value) { - ControlFlow::Break(insert_expr) - } else { - ControlFlow::Continue(()) + return ControlFlow::Break(Some(insert_expr)); } + + if is_set_mutated(cx, contains_expr, e) { + return ControlFlow::Break(None); + } + + ControlFlow::Continue(()) }) + .flatten() } diff --git a/clippy_lints/src/time_subtraction.rs b/clippy_lints/src/time_subtraction.rs index e0fdca97dbee..3ba59aefea06 100644 --- a/clippy_lints/src/time_subtraction.rs +++ b/clippy_lints/src/time_subtraction.rs @@ -8,7 +8,6 @@ use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; use rustc_session::impl_lint_pass; -use rustc_span::source_map::Spanned; use rustc_span::sym; declare_clippy_lint! { @@ -84,43 +83,38 @@ impl_lint_pass!(UncheckedTimeSubtraction => [MANUAL_INSTANT_ELAPSED, UNCHECKED_T impl LateLintPass<'_> for UncheckedTimeSubtraction { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { - if let ExprKind::Binary( - Spanned { - node: BinOpKind::Sub, .. + let (lhs, rhs) = match expr.kind { + ExprKind::Binary(op, lhs, rhs) if matches!(op.node, BinOpKind::Sub,) => (lhs, rhs), + ExprKind::MethodCall(fn_name, lhs, [rhs], _) if cx.ty_based_def(expr).is_diag_item(cx, sym::sub) => { + (lhs, rhs) }, - lhs, - rhs, - ) = expr.kind - { - let typeck = cx.typeck_results(); - let lhs_ty = typeck.expr_ty(lhs); - let rhs_ty = typeck.expr_ty(rhs); + _ => return, + }; + let typeck = cx.typeck_results(); + let lhs_name = typeck.expr_ty(lhs).opt_diag_name(cx); + let rhs_name = typeck.expr_ty(rhs).opt_diag_name(cx); - if lhs_ty.is_diag_item(cx, sym::Instant) { - // Instant::now() - instant - if is_instant_now_call(cx, lhs) - && rhs_ty.is_diag_item(cx, sym::Instant) - && let Some(sugg) = Sugg::hir_opt(cx, rhs) - { - print_manual_instant_elapsed_sugg(cx, expr, sugg); - } - // instant - duration - else if rhs_ty.is_diag_item(cx, sym::Duration) - && !expr.span.from_expansion() - && self.msrv.meets(cx, msrvs::TRY_FROM) - { - print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr); - } + if lhs_name == Some(sym::Instant) { + // Instant::now() - instant + if is_instant_now_call(cx, lhs) && rhs_name == Some(sym::Instant) { + print_manual_instant_elapsed_sugg(cx, expr, rhs); } - // duration - duration - else if lhs_ty.is_diag_item(cx, sym::Duration) - && rhs_ty.is_diag_item(cx, sym::Duration) + // instant - duration + else if rhs_name == Some(sym::Duration) && !expr.span.from_expansion() && self.msrv.meets(cx, msrvs::TRY_FROM) { print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr); } } + // duration - duration + else if lhs_name == Some(sym::Duration) + && rhs_name == Some(sym::Duration) + && !expr.span.from_expansion() + && self.msrv.meets(cx, msrvs::TRY_FROM) + { + print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr); + } } } @@ -150,10 +144,12 @@ fn is_chained_time_subtraction(cx: &LateContext<'_>, lhs: &Expr<'_>) -> bool { /// Returns true if the type is Duration or Instant fn is_time_type(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { - ty.is_diag_item(cx, sym::Duration) || ty.is_diag_item(cx, sym::Instant) + matches!(ty.opt_diag_name(cx), Some(sym::Duration | sym::Instant)) } -fn print_manual_instant_elapsed_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, sugg: Sugg<'_>) { +fn print_manual_instant_elapsed_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, rhs: &Expr<'_>) { + let mut applicability = Applicability::MachineApplicable; + let sugg = Sugg::hir_with_context(cx, rhs, expr.span.ctxt(), "", &mut applicability); span_lint_and_sugg( cx, MANUAL_INSTANT_ELAPSED, @@ -161,7 +157,7 @@ fn print_manual_instant_elapsed_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, sugg "manual implementation of `Instant::elapsed`", "try", format!("{}.elapsed()", sugg.maybe_paren()), - Applicability::MachineApplicable, + applicability, ); } @@ -181,8 +177,9 @@ fn print_unchecked_duration_subtraction_sugg( // avoid suggestions if !is_chained_time_subtraction(cx, left_expr) { let mut applicability = Applicability::MachineApplicable; - let left_sugg = Sugg::hir_with_applicability(cx, left_expr, "", &mut applicability); - let right_sugg = Sugg::hir_with_applicability(cx, right_expr, "", &mut applicability); + let left_sugg = Sugg::hir_with_context(cx, left_expr, expr.span.ctxt(), "", &mut applicability); + let right_sugg = + Sugg::hir_with_context(cx, right_expr, expr.span.ctxt(), "", &mut applicability); diag.span_suggestion( expr.span, diff --git a/clippy_lints/src/transmute/transmuting_null.rs b/clippy_lints/src/transmute/transmuting_null.rs index 1a6262f2ff76..31e770f421e1 100644 --- a/clippy_lints/src/transmute/transmuting_null.rs +++ b/clippy_lints/src/transmute/transmuting_null.rs @@ -1,6 +1,6 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_integer_literal; +use clippy_utils::is_integer_const; use clippy_utils::res::{MaybeDef, MaybeResPath}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; @@ -27,7 +27,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t // Catching: // `std::mem::transmute(0 as *const i32)` if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind - && is_integer_literal(inner_expr, 0) + && is_integer_const(cx, inner_expr, 0) { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); return true; @@ -42,10 +42,5 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t return true; } - // FIXME: - // Also catch transmutations of variables which are known nulls. - // To do this, MIR const propagation seems to be the better tool. - // Whenever MIR const prop routines are more developed, this will - // become available. As of this writing (25/03/19) it is not yet. false } diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index eba60501ae21..38ce9dc3f916 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -10,13 +10,14 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_ty}; use rustc_hir::{ self as hir, AmbigArg, Expr, ExprKind, FnRetTy, FnSig, GenericArgsParentheses, GenericParamKind, HirId, Impl, - ImplItemImplKind, ImplItemKind, Item, ItemKind, Pat, PatExpr, PatExprKind, PatKind, Path, QPath, Ty, TyKind, + ImplItemImplKind, ImplItemKind, Item, ItemKind, Node, Pat, PatExpr, PatExprKind, PatKind, Path, QPath, Ty, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty as MiddleTy; use rustc_session::impl_lint_pass; use rustc_span::Span; use std::iter; +use std::ops::ControlFlow; declare_clippy_lint! { /// ### What it does @@ -213,6 +214,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { path.res, Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _) ) + && !ty_is_in_generic_args(cx, hir_ty) && !types_to_skip.contains(&hir_ty.hir_id) && let ty = ty_from_hir_ty(cx, hir_ty.as_unambig_ty()) && let impl_ty = cx.tcx.type_of(impl_id).instantiate_identity() @@ -312,6 +314,38 @@ fn lint_path_to_variant(cx: &LateContext<'_>, path: &Path<'_>) { } } +fn ty_is_in_generic_args<'tcx>(cx: &LateContext<'tcx>, hir_ty: &Ty<'tcx, AmbigArg>) -> bool { + cx.tcx.hir_parent_iter(hir_ty.hir_id).any(|(_, parent)| { + matches!(parent, Node::ImplItem(impl_item) if impl_item.generics.params.iter().any(|param| { + let GenericParamKind::Const { ty: const_ty, .. } = ¶m.kind else { + return false; + }; + ty_contains_ty(const_ty, hir_ty) + })) + }) +} + +fn ty_contains_ty<'tcx>(outer: &Ty<'tcx>, inner: &Ty<'tcx, AmbigArg>) -> bool { + struct ContainsVisitor<'tcx> { + inner: &'tcx Ty<'tcx, AmbigArg>, + } + + impl<'tcx> Visitor<'tcx> for ContainsVisitor<'tcx> { + type Result = ControlFlow<()>; + + fn visit_ty(&mut self, t: &'tcx Ty<'tcx, AmbigArg>) -> Self::Result { + if t.hir_id == self.inner.hir_id { + return ControlFlow::Break(()); + } + + walk_ty(self, t) + } + } + + let mut visitor = ContainsVisitor { inner }; + visitor.visit_ty_unambig(outer).is_break() +} + /// Checks whether types `a` and `b` have the same lifetime parameters. /// /// This function does not check that types `a` and `b` are the same types. diff --git a/clippy_lints/src/write/empty_string.rs b/clippy_lints/src/write/empty_string.rs index e7eb99eb34ec..1291f2489a21 100644 --- a/clippy_lints/src/write/empty_string.rs +++ b/clippy_lints/src/write/empty_string.rs @@ -1,37 +1,43 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::MacroCall; use clippy_utils::source::expand_past_previous_comma; -use clippy_utils::sym; +use clippy_utils::{span_extract_comments, sym}; use rustc_ast::{FormatArgs, FormatArgsPiece}; use rustc_errors::Applicability; -use rustc_lint::LateContext; +use rustc_lint::{LateContext, LintContext}; use super::{PRINTLN_EMPTY_STRING, WRITELN_EMPTY_STRING}; pub(super) fn check(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &MacroCall, name: &str) { if let [FormatArgsPiece::Literal(sym::LF)] = &format_args.template[..] { - let mut span = format_args.span; - - let lint = if name == "writeln" { - span = expand_past_previous_comma(cx, span); - - WRITELN_EMPTY_STRING - } else { - PRINTLN_EMPTY_STRING - }; + let is_writeln = name == "writeln"; span_lint_and_then( cx, - lint, + if is_writeln { + WRITELN_EMPTY_STRING + } else { + PRINTLN_EMPTY_STRING + }, macro_call.span, format!("empty string literal in `{name}!`"), |diag| { - diag.span_suggestion( - span, - "remove the empty string", - String::new(), - Applicability::MachineApplicable, - ); + if span_extract_comments(cx.sess().source_map(), macro_call.span).is_empty() { + let closing_paren = cx.sess().source_map().span_extend_to_prev_char_before( + macro_call.span.shrink_to_hi(), + ')', + false, + ); + let mut span = format_args.span.with_hi(closing_paren.lo()); + if is_writeln { + span = expand_past_previous_comma(cx, span); + } + + diag.span_suggestion(span, "remove the empty string", "", Applicability::MachineApplicable); + } else { + // If there is a comment in the span of macro call, we don't provide an auto-fix suggestion. + diag.span_note(format_args.span, "remove the empty string"); + } }, ); } diff --git a/clippy_lints/src/zero_sized_map_values.rs b/clippy_lints/src/zero_sized_map_values.rs index bf133d26ed9d..94c2fb20d5f5 100644 --- a/clippy_lints/src/zero_sized_map_values.rs +++ b/clippy_lints/src/zero_sized_map_values.rs @@ -49,7 +49,7 @@ impl LateLintPass<'_> for ZeroSizedMapValues { && !in_trait_impl(cx, hir_ty.hir_id) // We don't care about infer vars && let ty = ty_from_hir_ty(cx, hir_ty.as_unambig_ty()) - && (ty.is_diag_item(cx, sym::HashMap) || ty.is_diag_item(cx, sym::BTreeMap)) + && matches!(ty.opt_diag_name(cx), Some(sym::HashMap | sym::BTreeMap)) && let ty::Adt(_, args) = ty.kind() && let ty = args.type_at(1) // Ensure that no type information is missing, to avoid a delayed bug in the compiler if this is not the case. diff --git a/clippy_lints_internal/src/almost_standard_lint_formulation.rs b/clippy_lints_internal/src/almost_standard_lint_formulation.rs index 7eeec84720f7..b5a12606fb3e 100644 --- a/clippy_lints_internal/src/almost_standard_lint_formulation.rs +++ b/clippy_lints_internal/src/almost_standard_lint_formulation.rs @@ -1,9 +1,11 @@ use crate::lint_without_lint_pass::is_lint_ref_type; use clippy_utils::diagnostics::span_lint_and_help; use regex::Regex; +use rustc_ast::token::DocFragmentKind; use rustc_hir::{Attribute, Item, ItemKind, Mutability}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::{Span, Symbol}; declare_tool_lint! { /// ### What it does @@ -46,28 +48,22 @@ impl<'tcx> LateLintPass<'tcx> for AlmostStandardFormulation { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { let mut check_next = false; if let ItemKind::Static(Mutability::Not, _, ty, _) = item.kind { - let lines = cx - .tcx - .hir_attrs(item.hir_id()) - .iter() - .filter_map(|attr| Attribute::doc_str(attr).map(|sym| (sym, attr))); + let lines = cx.tcx.hir_attrs(item.hir_id()).iter().filter_map(doc_attr); if is_lint_ref_type(cx, ty) { - for (line, attr) in lines { + for (line, span) in lines { let cur_line = line.as_str().trim(); if check_next && !cur_line.is_empty() { for formulation in &self.standard_formulations { let starts_with_correct_formulation = cur_line.starts_with(formulation.correction); if !starts_with_correct_formulation && formulation.wrong_pattern.is_match(cur_line) { - if let Some(ident) = attr.ident() { - span_lint_and_help( - cx, - ALMOST_STANDARD_LINT_FORMULATION, - ident.span, - "non-standard lint formulation", - None, - format!("consider using `{}`", formulation.correction), - ); - } + span_lint_and_help( + cx, + ALMOST_STANDARD_LINT_FORMULATION, + span, + "non-standard lint formulation", + None, + format!("consider using `{}`", formulation.correction), + ); return; } } @@ -84,3 +80,10 @@ impl<'tcx> LateLintPass<'tcx> for AlmostStandardFormulation { } } } + +fn doc_attr(attr: &Attribute) -> Option<(Symbol, Span)> { + match Attribute::doc_str_and_fragment_kind(attr) { + Some((symbol, DocFragmentKind::Raw(span))) => Some((symbol, span)), + _ => None, + } +} diff --git a/clippy_lints_internal/src/internal_paths.rs b/clippy_lints_internal/src/internal_paths.rs index 95bdf27b019c..14d4139a0065 100644 --- a/clippy_lints_internal/src/internal_paths.rs +++ b/clippy_lints_internal/src/internal_paths.rs @@ -17,6 +17,7 @@ pub static TY_CTXT: PathLookup = type_path!(rustc_middle::ty::TyCtxt); // Paths in clippy itself pub static CLIPPY_SYM_MODULE: PathLookup = type_path!(clippy_utils::sym); +pub static MAYBE_DEF: PathLookup = type_path!(clippy_utils::res::MaybeDef); pub static MSRV_STACK: PathLookup = type_path!(clippy_utils::msrvs::MsrvStack); pub static PATH_LOOKUP_NEW: PathLookup = value_path!(clippy_utils::paths::PathLookup::new); pub static SPAN_LINT_AND_THEN: PathLookup = value_path!(clippy_utils::diagnostics::span_lint_and_then); diff --git a/clippy_lints_internal/src/lib.rs b/clippy_lints_internal/src/lib.rs index d686ba73387c..cca5608fa6be 100644 --- a/clippy_lints_internal/src/lib.rs +++ b/clippy_lints_internal/src/lib.rs @@ -38,6 +38,7 @@ mod lint_without_lint_pass; mod msrv_attr_impl; mod outer_expn_data_pass; mod produce_ice; +mod repeated_is_diagnostic_item; mod symbols; mod unnecessary_def_path; mod unsorted_clippy_utils_paths; @@ -77,4 +78,5 @@ pub fn register_lints(store: &mut LintStore) { store.register_late_pass(|_| Box::new(msrv_attr_impl::MsrvAttrImpl)); store.register_late_pass(|_| Box::new(almost_standard_lint_formulation::AlmostStandardFormulation::new())); store.register_late_pass(|_| Box::new(unusual_names::UnusualNames)); + store.register_late_pass(|_| Box::new(repeated_is_diagnostic_item::RepeatedIsDiagnosticItem)); } diff --git a/clippy_lints_internal/src/repeated_is_diagnostic_item.rs b/clippy_lints_internal/src/repeated_is_diagnostic_item.rs new file mode 100644 index 000000000000..55fb78b1e296 --- /dev/null +++ b/clippy_lints_internal/src/repeated_is_diagnostic_item.rs @@ -0,0 +1,561 @@ +use std::iter; +use std::ops::ControlFlow; + +use crate::internal_paths::MAYBE_DEF; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; +use clippy_utils::source::{snippet_indent, snippet_with_applicability}; +use clippy_utils::visitors::for_each_expr; +use clippy_utils::{eq_expr_value, if_sequence, sym}; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Node, StmtKind, UnOp}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::print::with_forced_trimmed_paths; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::Span; + +declare_tool_lint! { + /// ### What it does + /// Checks for repeated use of `MaybeDef::is_diag_item`/`TyCtxt::is_diagnostic_item`; + /// suggests to first call `MaybDef::opt_diag_name`/`TyCtxt::get_diagnostic_name` and then + /// compare the output with all the `Symbol`s. + /// + /// ### Why is this bad? + /// Each of such calls ultimately invokes the `diagnostic_items` query. + /// While the query is cached, it's still better to avoid calling it multiple times if possible. + /// + /// ### Example + /// ```no_run + /// ty.is_diag_item(cx, sym::Option) || ty.is_diag_item(cx, sym::Result) + /// cx.tcx.is_diagnostic_item(sym::Option, did) || cx.tcx.is_diagnostic_item(sym::Result, did) + /// + /// if ty.is_diag_item(cx, sym::Option) { + /// .. + /// } else if ty.is_diag_item(cx, sym::Result) { + /// .. + /// } else { + /// .. + /// } + /// + /// if cx.tcx.is_diagnostic_item(sym::Option, did) { + /// .. + /// } else if cx.tcx.is_diagnostic_item(sym::Result, did) { + /// .. + /// } else { + /// .. + /// } + /// + /// { + /// if ty.is_diag_item(cx, sym::Option) { + /// .. + /// } + /// if ty.is_diag_item(cx, sym::Result) { + /// .. + /// } + /// } + /// + /// { + /// if cx.tcx.is_diagnostic_item(sym::Option, did) { + /// .. + /// } + /// if cx.tcx.is_diagnostic_item(sym::Result, did) { + /// .. + /// } + /// } + /// ``` + /// Use instead: + /// ```no_run + /// matches!(ty.opt_diag_name(cx), Some(sym::Option | sym::Result)) + /// matches!(cx.tcx.get_diagnostic_name(did), Some(sym::Option | sym::Result)) + /// + /// match ty.opt_diag_name(cx) { + /// Some(sym::Option) => { + /// .. + /// } + /// Some(sym::Result) => { + /// .. + /// } + /// _ => { + /// .. + /// } + /// } + /// + /// match cx.tcx.get_diagnostic_name(did) { + /// Some(sym::Option) => { + /// .. + /// } + /// Some(sym::Result) => { + /// .. + /// } + /// _ => { + /// .. + /// } + /// } + /// + /// { + /// let name = ty.opt_diag_name(cx); + /// if name == Some(sym::Option) { + /// .. + /// } + /// if name == Some(sym::Result) { + /// .. + /// } + /// } + /// + /// { + /// let name = cx.tcx.get_diagnostic_name(did); + /// if name == Some(sym::Option) { + /// .. + /// } + /// if name == Some(sym::Result) { + /// .. + /// } + /// } + /// ``` + pub clippy::REPEATED_IS_DIAGNOSTIC_ITEM, + Warn, + "repeated use of `MaybeDef::is_diag_item`/`TyCtxt::is_diagnostic_item`" +} +declare_lint_pass!(RepeatedIsDiagnosticItem => [REPEATED_IS_DIAGNOSTIC_ITEM]); + +const NOTE: &str = "each call performs the same compiler query -- it's faster to query once, and reuse the results"; + +impl<'tcx> LateLintPass<'tcx> for RepeatedIsDiagnosticItem { + #[expect(clippy::too_many_lines)] + fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) { + for [(cond1, stmt1_span), (cond2, stmt2_span)] in block + .stmts + .windows(2) + .filter_map(|pair| { + if let [if1, if2] = pair + && let StmtKind::Expr(e1) | StmtKind::Semi(e1) = if1.kind + && let ExprKind::If(cond1, ..) = e1.kind + && let StmtKind::Expr(e2) | StmtKind::Semi(e2) = if2.kind + && let ExprKind::If(cond2, ..) = e2.kind + { + Some([(cond1, if1.span), (cond2, if2.span)]) + } else { + None + } + }) + .chain( + if let Some(if1) = block.stmts.last() + && let StmtKind::Expr(e1) | StmtKind::Semi(e1) = if1.kind + && let ExprKind::If(cond1, ..) = e1.kind + && let Some(e2) = block.expr + && let ExprKind::If(cond2, ..) = e2.kind + { + Some([(cond1, if1.span), (cond2, e2.span)]) + } else { + None + }, + ) + { + let lint_span = stmt1_span.to(stmt2_span); + + // if recv1.is_diag_item(cx, sym1) && .. { + // .. + // } + // if recv2.is_diag_item(cx, sym2) && .. { + // .. + // } + if let Some(first @ (span1, (cx1, recv1, _))) = extract_nested_is_diag_item(cx, cond1) + && let Some(second @ (span2, (cx2, recv2, _))) = extract_nested_is_diag_item(cx, cond2) + && eq_expr_value(cx, cx1, cx2) + && eq_expr_value(cx, recv1, recv2) + { + let recv_ty = + with_forced_trimmed_paths!(format!("{}", cx.typeck_results().expr_ty_adjusted(recv1).peel_refs())); + let recv_ty = recv_ty.trim_end_matches("<'_>"); + span_lint_and_then( + cx, + REPEATED_IS_DIAGNOSTIC_ITEM, + lint_span, + format!("repeated calls to `{recv_ty}::is_diag_item`"), + |diag| { + diag.span_labels([span1, span2], "called here"); + diag.note(NOTE); + + let mut app = Applicability::HasPlaceholders; + let cx_str = snippet_with_applicability(cx, cx1.span, "_", &mut app); + let recv = snippet_with_applicability(cx, recv1.span, "_", &mut app); + let indent = snippet_indent(cx, stmt1_span).unwrap_or_default(); + let sugg: Vec<_> = iter::once(( + stmt1_span.shrink_to_lo(), + format!("let /* name */ = {recv}.opt_diag_name({cx_str});\n{indent}"), + )) // call `opt_diag_name` once + .chain([first, second].into_iter().map(|(expr_span, (_, _, sym))| { + let sym = snippet_with_applicability(cx, sym.span, "_", &mut app); + (expr_span, format!("/* name */ == Some({sym})")) + })) + .collect(); + + diag.multipart_suggestion_verbose( + format!("call `{recv_ty}::opt_diag_name`, and reuse the results"), + sugg, + app, + ); + }, + ); + return; + } + + // if cx.tcx.is_diagnostic_item(sym1, did) && .. { + // .. + // } + // if cx.tcx.is_diagnostic_item(sym2, did) && .. { + // .. + // } + if let Some(first @ (span1, (tcx1, did1, _))) = extract_nested_is_diagnostic_item(cx, cond1) + && let Some(second @ (span2, (tcx2, did2, _))) = extract_nested_is_diagnostic_item(cx, cond2) + && eq_expr_value(cx, tcx1, tcx2) + && eq_expr_value(cx, did1, did2) + { + span_lint_and_then( + cx, + REPEATED_IS_DIAGNOSTIC_ITEM, + lint_span, + "repeated calls to `TyCtxt::is_diagnostic_item`", + |diag| { + diag.span_labels([span1, span2], "called here"); + diag.note(NOTE); + + let mut app = Applicability::HasPlaceholders; + let tcx = snippet_with_applicability(cx, tcx1.span, "_", &mut app); + let did = snippet_with_applicability(cx, did1.span, "_", &mut app); + let indent = snippet_indent(cx, stmt1_span).unwrap_or_default(); + let sugg: Vec<_> = iter::once(( + stmt1_span.shrink_to_lo(), + format!("let /* name */ = {tcx}.get_diagnostic_name({did});\n{indent}"), + )) // call `get_diagnostic_name` once + .chain([first, second].into_iter().map(|(expr_span, (_, _, sym))| { + let sym = snippet_with_applicability(cx, sym.span, "_", &mut app); + (expr_span, format!("/* name */ == Some({sym})")) + })) + .collect(); + + diag.multipart_suggestion_verbose( + "call `TyCtxt::get_diagnostic_name`, and reuse the results", + sugg, + app, + ); + }, + ); + } + } + } + + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if let ExprKind::Binary(op, left, right) = expr.kind { + if op.node == BinOpKind::Or { + check_ors(cx, expr.span, left, right); + } else if op.node == BinOpKind::And + && let ExprKind::Unary(UnOp::Not, left) = left.kind + && let ExprKind::Unary(UnOp::Not, right) = right.kind + { + check_ands(cx, expr.span, left, right); + } + } else if let (conds, _) = if_sequence(expr) + && !conds.is_empty() + { + check_if_chains(cx, expr, conds); + } + } +} + +fn check_ors(cx: &LateContext<'_>, span: Span, left: &Expr<'_>, right: &Expr<'_>) { + // recv1.is_diag_item(cx, sym1) || recv2.is_diag_item(cx, sym2) + if let Some((cx1, recv1, sym1)) = extract_is_diag_item(cx, left) + && let Some((cx2, recv2, sym2)) = extract_is_diag_item(cx, right) + && eq_expr_value(cx, cx1, cx2) + && eq_expr_value(cx, recv1, recv2) + { + let recv_ty = + with_forced_trimmed_paths!(format!("{}", cx.typeck_results().expr_ty_adjusted(recv1).peel_refs())); + let recv_ty = recv_ty.trim_end_matches("<'_>"); + span_lint_and_then( + cx, + REPEATED_IS_DIAGNOSTIC_ITEM, + span, + format!("repeated calls to `{recv_ty}::is_diag_item`"), + |diag| { + diag.note(NOTE); + + let mut app = Applicability::MachineApplicable; + let cx_str = snippet_with_applicability(cx, cx1.span, "_", &mut app); + let recv = snippet_with_applicability(cx, recv1.span, "_", &mut app); + let sym1 = snippet_with_applicability(cx, sym1.span, "_", &mut app); + let sym2 = snippet_with_applicability(cx, sym2.span, "_", &mut app); + diag.span_suggestion_verbose( + span, + format!("call `{recv_ty}::opt_diag_name`, and reuse the results"), + format!("matches!({recv}.opt_diag_name({cx_str}), Some({sym1} | {sym2}))"), + app, + ); + }, + ); + return; + } + + // cx.tcx.is_diagnostic_item(sym1, did) || cx.tcx.is_diagnostic_item(sym2, did) + if let Some((tcx1, did1, sym1)) = extract_is_diagnostic_item(cx, left) + && let Some((tcx2, did2, sym2)) = extract_is_diagnostic_item(cx, right) + && eq_expr_value(cx, tcx1, tcx2) + && eq_expr_value(cx, did1, did2) + { + span_lint_and_then( + cx, + REPEATED_IS_DIAGNOSTIC_ITEM, + span, + "repeated calls to `TyCtxt::is_diagnostic_item`", + |diag| { + diag.note(NOTE); + + let mut app = Applicability::MachineApplicable; + let tcx = snippet_with_applicability(cx, tcx1.span, "_", &mut app); + let did = snippet_with_applicability(cx, did1.span, "_", &mut app); + let sym1 = snippet_with_applicability(cx, sym1.span, "_", &mut app); + let sym2 = snippet_with_applicability(cx, sym2.span, "_", &mut app); + diag.span_suggestion_verbose( + span, + "call `TyCtxt::get_diagnostic_name`, and reuse the results", + format!("matches!({tcx}.get_diagnostic_name({did}), Some({sym1} | {sym2}))"), + app, + ); + }, + ); + } +} + +fn check_ands(cx: &LateContext<'_>, span: Span, left: &Expr<'_>, right: &Expr<'_>) { + // !recv1.is_diag_item(cx, sym1) && !recv2.is_diag_item(cx, sym2) + if let Some((cx1, recv1, sym1)) = extract_is_diag_item(cx, left) + && let Some((cx2, recv2, sym2)) = extract_is_diag_item(cx, right) + && eq_expr_value(cx, cx1, cx2) + && eq_expr_value(cx, recv1, recv2) + { + let recv_ty = + with_forced_trimmed_paths!(format!("{}", cx.typeck_results().expr_ty_adjusted(recv1).peel_refs())); + let recv_ty = recv_ty.trim_end_matches("<'_>"); + span_lint_and_then( + cx, + REPEATED_IS_DIAGNOSTIC_ITEM, + span, + format!("repeated calls to `{recv_ty}::is_diag_item`"), + |diag| { + diag.note(NOTE); + + let mut app = Applicability::MachineApplicable; + let cx_str = snippet_with_applicability(cx, cx1.span, "_", &mut app); + let recv = snippet_with_applicability(cx, recv1.span, "_", &mut app); + let sym1 = snippet_with_applicability(cx, sym1.span, "_", &mut app); + let sym2 = snippet_with_applicability(cx, sym2.span, "_", &mut app); + diag.span_suggestion_verbose( + span, + format!("call `{recv_ty}::opt_diag_name`, and reuse the results"), + format!("!matches!({recv}.opt_diag_name({cx_str}), Some({sym1} | {sym2}))"), + app, + ); + }, + ); + return; + } + + // !cx.tcx.is_diagnostic_item(sym1, did) && !cx.tcx.is_diagnostic_item(sym2, did) + if let Some((tcx1, did1, sym1)) = extract_is_diagnostic_item(cx, left) + && let Some((tcx2, did2, sym2)) = extract_is_diagnostic_item(cx, right) + && eq_expr_value(cx, tcx1, tcx2) + && eq_expr_value(cx, did1, did2) + { + span_lint_and_then( + cx, + REPEATED_IS_DIAGNOSTIC_ITEM, + span, + "repeated calls to `TyCtxt::is_diagnostic_item`", + |diag| { + diag.note(NOTE); + + let mut app = Applicability::MachineApplicable; + let tcx = snippet_with_applicability(cx, tcx1.span, "_", &mut app); + let did = snippet_with_applicability(cx, did1.span, "_", &mut app); + let sym1 = snippet_with_applicability(cx, sym1.span, "_", &mut app); + let sym2 = snippet_with_applicability(cx, sym2.span, "_", &mut app); + diag.span_suggestion_verbose( + span, + "call `TyCtxt::get_diagnostic_name`, and reuse the results", + format!("!matches!({tcx}.get_diagnostic_name({did}), Some({sym1} | {sym2}))"), + app, + ); + }, + ); + } +} + +fn check_if_chains<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, conds: Vec<&'tcx Expr<'_>>) { + // if ty.is_diag_item(cx, sym1) { + // .. + // } else if ty.is_diag_item(cx, sym2) { + // .. + // } else { + // .. + // } + let mut found = conds.iter().filter_map(|cond| extract_nested_is_diag_item(cx, cond)); + if let Some(first @ (_, (cx_1, recv1, _))) = found.next() + && let other = + found.filter(|(_, (cx_, recv, _))| eq_expr_value(cx, cx_, cx_1) && eq_expr_value(cx, recv, recv1)) + && let results = iter::once(first).chain(other).collect::>() + && results.len() > 1 + { + let recv_ty = + with_forced_trimmed_paths!(format!("{}", cx.typeck_results().expr_ty_adjusted(recv1).peel_refs())); + let recv_ty = recv_ty.trim_end_matches("<'_>"); + span_lint_and_then( + cx, + REPEATED_IS_DIAGNOSTIC_ITEM, + expr.span, + format!("repeated calls to `{recv_ty}::is_diag_item`"), + |diag| { + diag.span_labels(results.iter().map(|(span, _)| *span), "called here"); + diag.note(NOTE); + + let mut app = Applicability::HasPlaceholders; + let cx_str = snippet_with_applicability(cx, cx_1.span, "_", &mut app); + let recv = snippet_with_applicability(cx, recv1.span, "_", &mut app); + let span_before = if let Node::LetStmt(let_stmt) = cx.tcx.parent_hir_node(expr.hir_id) { + let_stmt.span + } else { + expr.span + }; + let indent = snippet_indent(cx, span_before).unwrap_or_default(); + let sugg: Vec<_> = iter::once(( + span_before.shrink_to_lo(), + format!("let /* name */ = {recv}.opt_diag_name({cx_str});\n{indent}"), + )) // call `opt_diag_name` once + .chain(results.into_iter().map(|(expr_span, (_, _, sym))| { + let sym = snippet_with_applicability(cx, sym.span, "_", &mut app); + (expr_span, format!("/* name */ == Some({sym})")) + })) + .collect(); + + diag.multipart_suggestion_verbose( + format!("call `{recv_ty}::opt_diag_name`, and reuse the results"), + sugg, + app, + ); + }, + ); + } + + // if cx.tcx.is_diagnostic_item(sym1, did) { + // .. + // } else if cx.tcx.is_diagnostic_item(sym2, did) { + // .. + // } else { + // .. + // } + let mut found = conds + .into_iter() + .filter_map(|cond| extract_nested_is_diagnostic_item(cx, cond)); + if let Some(first @ (_, (tcx1, did1, _))) = found.next() + && let other = found.filter(|(_, (tcx, did, _))| eq_expr_value(cx, tcx, tcx1) && eq_expr_value(cx, did, did1)) + && let results = iter::once(first).chain(other).collect::>() + && results.len() > 1 + { + span_lint_and_then( + cx, + REPEATED_IS_DIAGNOSTIC_ITEM, + expr.span, + "repeated calls to `TyCtxt::is_diagnostic_item`", + |diag| { + diag.span_labels(results.iter().map(|(span, _)| *span), "called here"); + diag.note(NOTE); + + let mut app = Applicability::HasPlaceholders; + let tcx = snippet_with_applicability(cx, tcx1.span, "_", &mut app); + let recv = snippet_with_applicability(cx, did1.span, "_", &mut app); + let span_before = if let Node::LetStmt(let_stmt) = cx.tcx.parent_hir_node(expr.hir_id) { + let_stmt.span + } else { + expr.span + }; + let indent = snippet_indent(cx, span_before).unwrap_or_default(); + let sugg: Vec<_> = iter::once(( + span_before.shrink_to_lo(), + format!("let /* name */ = {tcx}.get_diagnostic_name({recv});\n{indent}"), + )) // call `get_diagnostic_name` once + .chain(results.into_iter().map(|(expr_span, (_, _, sym))| { + let sym = snippet_with_applicability(cx, sym.span, "_", &mut app); + (expr_span, format!("/* name */ == Some({sym})")) + })) + .collect(); + + diag.multipart_suggestion_verbose( + "call `TyCtxt::get_diagnostic_name`, and reuse the results", + sugg, + app, + ); + }, + ); + } +} + +fn extract_is_diag_item<'tcx>( + cx: &LateContext<'_>, + expr: &'tcx Expr<'tcx>, +) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> { + if let ExprKind::MethodCall(is_diag_item, recv, [cx_, sym], _) = expr.kind + && is_diag_item.ident.name == sym::is_diag_item + // Whether this a method from the `MaybeDef` trait + && let Some(did) = cx.ty_based_def(expr).opt_parent(cx).opt_def_id() + && MAYBE_DEF.matches(cx, did) + { + Some((cx_, recv, sym)) + } else { + None + } +} + +fn extract_is_diagnostic_item<'tcx>( + cx: &LateContext<'_>, + expr: &'tcx Expr<'tcx>, +) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> { + if let ExprKind::MethodCall(is_diag_item, tcx, [sym, did], _) = expr.kind + && is_diag_item.ident.name == sym::is_diagnostic_item + // Whether this is an inherent method on `TyCtxt` + && cx + .ty_based_def(expr) + .opt_parent(cx) + .opt_impl_ty(cx) + .is_diag_item(cx, sym::TyCtxt) + { + Some((tcx, did, sym)) + } else { + None + } +} + +fn extract_nested_is_diag_item<'tcx>( + cx: &LateContext<'tcx>, + cond: &'tcx Expr<'_>, +) -> Option<(Span, (&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>))> { + for_each_expr(cx, cond, |cond_part| { + if let Some(res) = extract_is_diag_item(cx, cond_part) { + ControlFlow::Break((cond_part.span, res)) + } else { + ControlFlow::Continue(()) + } + }) +} + +fn extract_nested_is_diagnostic_item<'tcx>( + cx: &LateContext<'tcx>, + cond: &'tcx Expr<'_>, +) -> Option<(Span, (&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>))> { + for_each_expr(cx, cond, |cond_part| { + if let Some(res) = extract_is_diagnostic_item(cx, cond_part) { + ControlFlow::Break((cond_part.span, res)) + } else { + ControlFlow::Continue(()) + } + }) +} diff --git a/clippy_utils/README.md b/clippy_utils/README.md index dc8695fef9f5..01257c1a3059 100644 --- a/clippy_utils/README.md +++ b/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: ``` -nightly-2025-12-11 +nightly-2025-12-25 ``` diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 2fd773b06781..8820801853e0 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -86,7 +86,7 @@ pub fn is_proc_macro(attrs: &[impl AttributeExt]) -> bool { /// Checks whether `attrs` contain `#[doc(hidden)]` pub fn is_doc_hidden(attrs: &[impl AttributeExt]) -> bool { - attrs.iter().any(|attr| attr.is_doc_hidden()) + attrs.iter().any(AttributeExt::is_doc_hidden) } /// Checks whether the given ADT, or any of its fields/variants, are marked as `#[non_exhaustive]` diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index e43b0b95d9f7..9574e6fa40b0 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -809,10 +809,12 @@ impl<'tcx> ConstEvalCtxt<'tcx> { | sym::i128_legacy_const_max ) ) || self.tcx.opt_parent(did).is_some_and(|parent| { - parent.is_diag_item(&self.tcx, sym::f16_consts_mod) - || parent.is_diag_item(&self.tcx, sym::f32_consts_mod) - || parent.is_diag_item(&self.tcx, sym::f64_consts_mod) - || parent.is_diag_item(&self.tcx, sym::f128_consts_mod) + matches!( + parent.opt_diag_name(&self.tcx), + Some( + sym::f16_consts_mod | sym::f32_consts_mod | sym::f64_consts_mod | sym::f128_consts_mod + ) + ) })) => { did @@ -1139,7 +1141,9 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx ConstItemRhs::Body(body_id) => Some(tcx.hir_body(body_id).value), ConstItemRhs::TypeConst(const_arg) => match const_arg.kind { ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value), - ConstArgKind::Struct(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => None, + ConstArgKind::Struct(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => { + None + }, }, } } diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 5cadf5fbb869..055f6d03eff0 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -4,14 +4,17 @@ use crate::source::{SpanRange, SpanRangeExt, walk_span_to_context}; use crate::tokenize_with_text; use rustc_ast::ast; use rustc_ast::ast::InlineAsmTemplatePiece; -use rustc_data_structures::fx::FxHasher; +use rustc_data_structures::fx::{FxHasher, FxIndexMap}; use rustc_hir::MatchSource::TryDesugar; use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def_id::DefId; use rustc_hir::{ - AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, ByRef, Closure, ConstArg, ConstArgKind, Expr, - ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, - LifetimeKind, Node, Pat, PatExpr, PatExprKind, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, - StructTailExpr, TraitBoundModifiers, Ty, TyKind, TyPat, TyPatKind, + AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, ByRef, Closure, ConstArg, ConstArgKind, ConstItemRhs, + Expr, ExprField, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericArgs, GenericBound, GenericBounds, + GenericParam, GenericParamKind, GenericParamSource, Generics, HirId, HirIdMap, InlineAsmOperand, ItemId, ItemKind, + LetExpr, Lifetime, LifetimeKind, LifetimeParamKind, Node, ParamName, Pat, PatExpr, PatExprKind, PatField, PatKind, + Path, PathSegment, PreciseCapturingArgKind, PrimTy, QPath, Stmt, StmtKind, StructTailExpr, TraitBoundModifiers, Ty, + TyKind, TyPat, TyPatKind, UseKind, WherePredicate, WherePredicateKind, }; use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize}; use rustc_lint::LateContext; @@ -106,6 +109,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { left_ctxt: SyntaxContext::root(), right_ctxt: SyntaxContext::root(), locals: HirIdMap::default(), + local_items: FxIndexMap::default(), } } @@ -144,6 +148,7 @@ pub struct HirEqInterExpr<'a, 'b, 'tcx> { // right. For example, when comparing `{ let x = 1; x + 2 }` and `{ let y = 1; y + 2 }`, // these blocks are considered equal since `x` is mapped to `y`. pub locals: HirIdMap, + pub local_items: FxIndexMap, } impl HirEqInterExpr<'_, '_, '_> { @@ -168,6 +173,189 @@ impl HirEqInterExpr<'_, '_, '_> { && self.eq_pat(l.pat, r.pat) }, (StmtKind::Expr(l), StmtKind::Expr(r)) | (StmtKind::Semi(l), StmtKind::Semi(r)) => self.eq_expr(l, r), + (StmtKind::Item(l), StmtKind::Item(r)) => self.eq_item(*l, *r), + _ => false, + } + } + + pub fn eq_item(&mut self, l: ItemId, r: ItemId) -> bool { + let left = self.inner.cx.tcx.hir_item(l); + let right = self.inner.cx.tcx.hir_item(r); + let eq = match (left.kind, right.kind) { + ( + ItemKind::Const(l_ident, l_generics, l_ty, ConstItemRhs::Body(l_body)), + ItemKind::Const(r_ident, r_generics, r_ty, ConstItemRhs::Body(r_body)), + ) => { + l_ident.name == r_ident.name + && self.eq_generics(l_generics, r_generics) + && self.eq_ty(l_ty, r_ty) + && self.eq_body(l_body, r_body) + }, + (ItemKind::Static(l_mut, l_ident, l_ty, l_body), ItemKind::Static(r_mut, r_ident, r_ty, r_body)) => { + l_mut == r_mut && l_ident.name == r_ident.name && self.eq_ty(l_ty, r_ty) && self.eq_body(l_body, r_body) + }, + ( + ItemKind::Fn { + sig: l_sig, + ident: l_ident, + generics: l_generics, + body: l_body, + has_body: l_has_body, + }, + ItemKind::Fn { + sig: r_sig, + ident: r_ident, + generics: r_generics, + body: r_body, + has_body: r_has_body, + }, + ) => { + l_ident.name == r_ident.name + && (l_has_body == r_has_body) + && self.eq_fn_sig(&l_sig, &r_sig) + && self.eq_generics(l_generics, r_generics) + && self.eq_body(l_body, r_body) + }, + (ItemKind::TyAlias(l_ident, l_generics, l_ty), ItemKind::TyAlias(r_ident, r_generics, r_ty)) => { + l_ident.name == r_ident.name && self.eq_generics(l_generics, r_generics) && self.eq_ty(l_ty, r_ty) + }, + (ItemKind::Use(l_path, l_kind), ItemKind::Use(r_path, r_kind)) => { + self.eq_path_segments(l_path.segments, r_path.segments) + && match (l_kind, r_kind) { + (UseKind::Single(l_ident), UseKind::Single(r_ident)) => l_ident.name == r_ident.name, + (UseKind::Glob, UseKind::Glob) | (UseKind::ListStem, UseKind::ListStem) => true, + _ => false, + } + }, + (ItemKind::Mod(l_ident, l_mod), ItemKind::Mod(r_ident, r_mod)) => { + l_ident.name == r_ident.name && over(l_mod.item_ids, r_mod.item_ids, |l, r| self.eq_item(*l, *r)) + }, + _ => false, + }; + if eq { + self.local_items.insert(l.owner_id.to_def_id(), r.owner_id.to_def_id()); + } + eq + } + + fn eq_fn_sig(&mut self, left: &FnSig<'_>, right: &FnSig<'_>) -> bool { + left.header.safety == right.header.safety + && left.header.constness == right.header.constness + && left.header.asyncness == right.header.asyncness + && left.header.abi == right.header.abi + && self.eq_fn_decl(left.decl, right.decl) + } + + fn eq_fn_decl(&mut self, left: &FnDecl<'_>, right: &FnDecl<'_>) -> bool { + over(left.inputs, right.inputs, |l, r| self.eq_ty(l, r)) + && (match (left.output, right.output) { + (FnRetTy::DefaultReturn(_), FnRetTy::DefaultReturn(_)) => true, + (FnRetTy::Return(l_ty), FnRetTy::Return(r_ty)) => self.eq_ty(l_ty, r_ty), + _ => false, + }) + && left.c_variadic == right.c_variadic + && left.implicit_self == right.implicit_self + && left.lifetime_elision_allowed == right.lifetime_elision_allowed + } + + fn eq_generics(&mut self, left: &Generics<'_>, right: &Generics<'_>) -> bool { + self.eq_generics_param(left.params, right.params) + && self.eq_generics_predicate(left.predicates, right.predicates) + } + + fn eq_generics_predicate(&mut self, left: &[WherePredicate<'_>], right: &[WherePredicate<'_>]) -> bool { + over(left, right, |l, r| match (l.kind, r.kind) { + (WherePredicateKind::BoundPredicate(l_bound), WherePredicateKind::BoundPredicate(r_bound)) => { + l_bound.origin == r_bound.origin + && self.eq_ty(l_bound.bounded_ty, r_bound.bounded_ty) + && self.eq_generics_param(l_bound.bound_generic_params, r_bound.bound_generic_params) + && self.eq_generics_bound(l_bound.bounds, r_bound.bounds) + }, + (WherePredicateKind::RegionPredicate(l_region), WherePredicateKind::RegionPredicate(r_region)) => { + Self::eq_lifetime(l_region.lifetime, r_region.lifetime) + && self.eq_generics_bound(l_region.bounds, r_region.bounds) + }, + (WherePredicateKind::EqPredicate(l_eq), WherePredicateKind::EqPredicate(r_eq)) => { + self.eq_ty(l_eq.lhs_ty, r_eq.lhs_ty) + }, + _ => false, + }) + } + + fn eq_generics_bound(&mut self, left: GenericBounds<'_>, right: GenericBounds<'_>) -> bool { + over(left, right, |l, r| match (l, r) { + (GenericBound::Trait(l_trait), GenericBound::Trait(r_trait)) => { + l_trait.modifiers == r_trait.modifiers + && self.eq_path(l_trait.trait_ref.path, r_trait.trait_ref.path) + && self.eq_generics_param(l_trait.bound_generic_params, r_trait.bound_generic_params) + }, + (GenericBound::Outlives(l_lifetime), GenericBound::Outlives(r_lifetime)) => { + Self::eq_lifetime(l_lifetime, r_lifetime) + }, + (GenericBound::Use(l_capture, _), GenericBound::Use(r_capture, _)) => { + over(l_capture, r_capture, |l, r| match (l, r) { + (PreciseCapturingArgKind::Lifetime(l_lifetime), PreciseCapturingArgKind::Lifetime(r_lifetime)) => { + Self::eq_lifetime(l_lifetime, r_lifetime) + }, + (PreciseCapturingArgKind::Param(l_param), PreciseCapturingArgKind::Param(r_param)) => { + l_param.ident == r_param.ident && l_param.res == r_param.res + }, + _ => false, + }) + }, + _ => false, + }) + } + + fn eq_generics_param(&mut self, left: &[GenericParam<'_>], right: &[GenericParam<'_>]) -> bool { + over(left, right, |l, r| { + (match (l.name, r.name) { + (ParamName::Plain(l_ident), ParamName::Plain(r_ident)) + | (ParamName::Error(l_ident), ParamName::Error(r_ident)) => l_ident.name == r_ident.name, + (ParamName::Fresh, ParamName::Fresh) => true, + _ => false, + }) && l.pure_wrt_drop == r.pure_wrt_drop + && self.eq_generics_param_kind(&l.kind, &r.kind) + && (matches!( + (l.source, r.source), + (GenericParamSource::Generics, GenericParamSource::Generics) + | (GenericParamSource::Binder, GenericParamSource::Binder) + )) + }) + } + + fn eq_generics_param_kind(&mut self, left: &GenericParamKind<'_>, right: &GenericParamKind<'_>) -> bool { + match (left, right) { + (GenericParamKind::Lifetime { kind: l_kind }, GenericParamKind::Lifetime { kind: r_kind }) => { + match (l_kind, r_kind) { + (LifetimeParamKind::Explicit, LifetimeParamKind::Explicit) + | (LifetimeParamKind::Error, LifetimeParamKind::Error) => true, + (LifetimeParamKind::Elided(l_lifetime_kind), LifetimeParamKind::Elided(r_lifetime_kind)) => { + l_lifetime_kind == r_lifetime_kind + }, + _ => false, + } + }, + ( + GenericParamKind::Type { + default: l_default, + synthetic: l_synthetic, + }, + GenericParamKind::Type { + default: r_default, + synthetic: r_synthetic, + }, + ) => both(*l_default, *r_default, |l, r| self.eq_ty(l, r)) && l_synthetic == r_synthetic, + ( + GenericParamKind::Const { + ty: l_ty, + default: l_default, + }, + GenericParamKind::Const { + ty: r_ty, + default: r_default, + }, + ) => self.eq_ty(l_ty, r_ty) && both(*l_default, *r_default, |l, r| self.eq_const_arg(l, r)), _ => false, } } @@ -479,16 +667,20 @@ impl HirEqInterExpr<'_, '_, '_> { (ConstArgKind::Infer(..), ConstArgKind::Infer(..)) => true, (ConstArgKind::Struct(path_a, inits_a), ConstArgKind::Struct(path_b, inits_b)) => { self.eq_qpath(path_a, path_b) - && inits_a.iter().zip(*inits_b).all(|(init_a, init_b)| { - self.eq_const_arg(init_a.expr, init_b.expr) - }) - } + && inits_a + .iter() + .zip(*inits_b) + .all(|(init_a, init_b)| self.eq_const_arg(init_a.expr, init_b.expr)) + }, // Use explicit match for now since ConstArg is undergoing flux. - (ConstArgKind::Path(..), _) - | (ConstArgKind::Anon(..), _) - | (ConstArgKind::Infer(..), _) - | (ConstArgKind::Struct(..), _) - | (ConstArgKind::Error(..), _) => false, + ( + ConstArgKind::Path(..) + | ConstArgKind::Anon(..) + | ConstArgKind::Infer(..) + | ConstArgKind::Struct(..) + | ConstArgKind::Error(..), + _, + ) => false, } } @@ -570,6 +762,17 @@ impl HirEqInterExpr<'_, '_, '_> { match (left.res, right.res) { (Res::Local(l), Res::Local(r)) => l == r || self.locals.get(&l) == Some(&r), (Res::Local(_), _) | (_, Res::Local(_)) => false, + (Res::Def(l_kind, l), Res::Def(r_kind, r)) + if l_kind == r_kind + && let DefKind::Const + | DefKind::Static { .. } + | DefKind::Fn + | DefKind::TyAlias + | DefKind::Use + | DefKind::Mod = l_kind => + { + (l == r || self.local_items.get(&l) == Some(&r)) && self.eq_path_segments(left.segments, right.segments) + }, _ => self.eq_path_segments(left.segments, right.segments), } } @@ -1344,7 +1547,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { for init in *inits { self.hash_const_arg(init.expr); } - } + }, ConstArgKind::Infer(..) | ConstArgKind::Error(..) => {}, } } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 409f13013489..954c32687af6 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2490,7 +2490,7 @@ pub enum DefinedTy<'tcx> { /// in the context of its definition site. We also track the `def_id` of its /// definition site. /// - /// WARNING: As the `ty` in in the scope of the definition, not of the function + /// WARNING: As the `ty` is in the scope of the definition, not of the function /// using it, you must be very careful with how you use it. Using it in the wrong /// scope easily results in ICEs. Mir { @@ -2719,7 +2719,6 @@ pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'tcx>) -> ExprUseCtx moved_before_use, same_ctxt, }, - Some(ControlFlow::Break(_)) => unreachable!("type of node is ControlFlow"), None => ExprUseCtxt { node: Node::Crate(cx.tcx.hir_root_module()), child_id: HirId::INVALID, diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index b48d17863aa3..f30f26f3a70b 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -13,8 +13,8 @@ use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::source_map::{SourceMap, original_sp}; use rustc_span::{ - BytePos, DUMMY_SP, DesugaringKind, Pos, RelativeBytePos, SourceFile, SourceFileAndLine, - Span, SpanData, SyntaxContext, hygiene, + BytePos, DUMMY_SP, DesugaringKind, Pos, RelativeBytePos, SourceFile, SourceFileAndLine, Span, SpanData, + SyntaxContext, hygiene, }; use std::borrow::Cow; use std::fmt; diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index 00f4a9c7e586..a0d2e8673fe6 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -58,6 +58,7 @@ generate! { LowerHex, MAX, MIN, + MaybeDef, MsrvStack, Octal, OpenOptions, @@ -167,6 +168,7 @@ generate! { from_ne_bytes, from_ptr, from_raw, + from_raw_parts, from_str_radix, fs, fuse, @@ -192,6 +194,8 @@ generate! { io, is_ascii, is_char_boundary, + is_diag_item, + is_diagnostic_item, is_digit, is_empty, is_err, @@ -275,6 +279,7 @@ generate! { read_to_string, read_unaligned, read_volatile, + reduce, redundant_imports, redundant_pub_crate, regex, @@ -282,6 +287,7 @@ generate! { repeat, replace, replacen, + res, reserve, resize, restriction, @@ -364,6 +370,7 @@ generate! { trim_start, trim_start_matches, truncate, + try_fold, try_for_each, unreachable_pub, unsafe_removed_from_name, diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 1384f4078ebe..dbec79e111fb 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2025-12-11" +channel = "nightly-2025-12-25" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" diff --git a/tests/ui-internal/repeated_is_diagnostic_item.fixed b/tests/ui-internal/repeated_is_diagnostic_item.fixed new file mode 100644 index 000000000000..fcacf504804c --- /dev/null +++ b/tests/ui-internal/repeated_is_diagnostic_item.fixed @@ -0,0 +1,77 @@ +#![feature(rustc_private)] + +extern crate rustc_hir; +extern crate rustc_lint; +extern crate rustc_middle; +extern crate rustc_span; + +use clippy_utils::res::MaybeDef; +use clippy_utils::sym; +use rustc_hir::def_id::DefId; +use rustc_lint::LateContext; +use rustc_middle::ty::{AdtDef, Ty, TyCtxt}; +use rustc_span::Symbol; + +fn binops(cx: &LateContext<'_>, ty: Ty<'_>, adt_def: &AdtDef<'_>) { + let did = ty.opt_def_id().unwrap(); + + let _ = matches!(ty.opt_diag_name(cx), Some(sym::Option | sym::Result)); + //~^ repeated_is_diagnostic_item + let _ = !matches!(ty.opt_diag_name(cx), Some(sym::Option | sym::Result)); + //~^ repeated_is_diagnostic_item + let _ = matches!(adt_def.opt_diag_name(cx), Some(sym::Option | sym::Result)); + //~^ repeated_is_diagnostic_item + let _ = !matches!(adt_def.opt_diag_name(cx), Some(sym::Option | sym::Result)); + //~^ repeated_is_diagnostic_item + let _ = matches!(cx.tcx.get_diagnostic_name(did), Some(sym::Option | sym::Result)); + //~^ repeated_is_diagnostic_item + let _ = !matches!(cx.tcx.get_diagnostic_name(did), Some(sym::Option | sym::Result)); + //~^ repeated_is_diagnostic_item + + // Don't lint: `is_diagnostic_item` is called not on `TyCtxt` + struct FakeTyCtxt; + impl FakeTyCtxt { + fn is_diagnostic_item(&self, sym: Symbol, did: DefId) -> bool { + unimplemented!() + } + } + let f = FakeTyCtxt; + let _ = f.is_diagnostic_item(sym::Option, did) || f.is_diagnostic_item(sym::Result, did); + + // Don't lint: `is_diagnostic_item` on `TyCtxt` comes from a(n unrelated) trait + trait IsDiagnosticItem { + fn is_diagnostic_item(&self, sym: Symbol, did: DefId) -> bool; + } + impl IsDiagnosticItem for TyCtxt<'_> { + fn is_diagnostic_item(&self, sym: Symbol, did: DefId) -> bool { + unimplemented!() + } + } + let _ = IsDiagnosticItem::is_diagnostic_item(&cx.tcx, sym::Option, did) + || IsDiagnosticItem::is_diagnostic_item(&cx.tcx, sym::Result, did); + + // Don't lint: `is_diag_item` is an inherent method + struct DoesntImplMaybeDef; + impl DoesntImplMaybeDef { + fn is_diag_item(&self, cx: &LateContext, sym: Symbol) -> bool { + unimplemented!() + } + } + let d = DoesntImplMaybeDef; + let _ = d.is_diag_item(cx, sym::Option) || d.is_diag_item(cx, sym::Result); + + // Don't lint: `is_diag_item` comes from a trait other than `MaybeDef` + trait FakeMaybeDef { + fn is_diag_item(&self, cx: &LateContext, sym: Symbol) -> bool; + } + struct Bar; + impl FakeMaybeDef for Bar { + fn is_diag_item(&self, cx: &LateContext, sym: Symbol) -> bool { + unimplemented!() + } + } + let b = Bar; + let _ = b.is_diag_item(cx, sym::Option) || b.is_diag_item(cx, sym::Result); +} + +fn main() {} diff --git a/tests/ui-internal/repeated_is_diagnostic_item.rs b/tests/ui-internal/repeated_is_diagnostic_item.rs new file mode 100644 index 000000000000..7ccbbfd94029 --- /dev/null +++ b/tests/ui-internal/repeated_is_diagnostic_item.rs @@ -0,0 +1,77 @@ +#![feature(rustc_private)] + +extern crate rustc_hir; +extern crate rustc_lint; +extern crate rustc_middle; +extern crate rustc_span; + +use clippy_utils::res::MaybeDef; +use clippy_utils::sym; +use rustc_hir::def_id::DefId; +use rustc_lint::LateContext; +use rustc_middle::ty::{AdtDef, Ty, TyCtxt}; +use rustc_span::Symbol; + +fn binops(cx: &LateContext<'_>, ty: Ty<'_>, adt_def: &AdtDef<'_>) { + let did = ty.opt_def_id().unwrap(); + + let _ = ty.is_diag_item(cx, sym::Option) || ty.is_diag_item(cx, sym::Result); + //~^ repeated_is_diagnostic_item + let _ = !ty.is_diag_item(cx, sym::Option) && !ty.is_diag_item(cx, sym::Result); + //~^ repeated_is_diagnostic_item + let _ = adt_def.is_diag_item(cx, sym::Option) || adt_def.is_diag_item(cx, sym::Result); + //~^ repeated_is_diagnostic_item + let _ = !adt_def.is_diag_item(cx, sym::Option) && !adt_def.is_diag_item(cx, sym::Result); + //~^ repeated_is_diagnostic_item + let _ = cx.tcx.is_diagnostic_item(sym::Option, did) || cx.tcx.is_diagnostic_item(sym::Result, did); + //~^ repeated_is_diagnostic_item + let _ = !cx.tcx.is_diagnostic_item(sym::Option, did) && !cx.tcx.is_diagnostic_item(sym::Result, did); + //~^ repeated_is_diagnostic_item + + // Don't lint: `is_diagnostic_item` is called not on `TyCtxt` + struct FakeTyCtxt; + impl FakeTyCtxt { + fn is_diagnostic_item(&self, sym: Symbol, did: DefId) -> bool { + unimplemented!() + } + } + let f = FakeTyCtxt; + let _ = f.is_diagnostic_item(sym::Option, did) || f.is_diagnostic_item(sym::Result, did); + + // Don't lint: `is_diagnostic_item` on `TyCtxt` comes from a(n unrelated) trait + trait IsDiagnosticItem { + fn is_diagnostic_item(&self, sym: Symbol, did: DefId) -> bool; + } + impl IsDiagnosticItem for TyCtxt<'_> { + fn is_diagnostic_item(&self, sym: Symbol, did: DefId) -> bool { + unimplemented!() + } + } + let _ = IsDiagnosticItem::is_diagnostic_item(&cx.tcx, sym::Option, did) + || IsDiagnosticItem::is_diagnostic_item(&cx.tcx, sym::Result, did); + + // Don't lint: `is_diag_item` is an inherent method + struct DoesntImplMaybeDef; + impl DoesntImplMaybeDef { + fn is_diag_item(&self, cx: &LateContext, sym: Symbol) -> bool { + unimplemented!() + } + } + let d = DoesntImplMaybeDef; + let _ = d.is_diag_item(cx, sym::Option) || d.is_diag_item(cx, sym::Result); + + // Don't lint: `is_diag_item` comes from a trait other than `MaybeDef` + trait FakeMaybeDef { + fn is_diag_item(&self, cx: &LateContext, sym: Symbol) -> bool; + } + struct Bar; + impl FakeMaybeDef for Bar { + fn is_diag_item(&self, cx: &LateContext, sym: Symbol) -> bool { + unimplemented!() + } + } + let b = Bar; + let _ = b.is_diag_item(cx, sym::Option) || b.is_diag_item(cx, sym::Result); +} + +fn main() {} diff --git a/tests/ui-internal/repeated_is_diagnostic_item.stderr b/tests/ui-internal/repeated_is_diagnostic_item.stderr new file mode 100644 index 000000000000..8c52ba561d79 --- /dev/null +++ b/tests/ui-internal/repeated_is_diagnostic_item.stderr @@ -0,0 +1,82 @@ +error: repeated calls to `Ty::is_diag_item` + --> tests/ui-internal/repeated_is_diagnostic_item.rs:18:13 + | +LL | let _ = ty.is_diag_item(cx, sym::Option) || ty.is_diag_item(cx, sym::Result); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results + = note: `-D clippy::repeated-is-diagnostic-item` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::repeated_is_diagnostic_item)]` +help: call `Ty::opt_diag_name`, and reuse the results + | +LL - let _ = ty.is_diag_item(cx, sym::Option) || ty.is_diag_item(cx, sym::Result); +LL + let _ = matches!(ty.opt_diag_name(cx), Some(sym::Option | sym::Result)); + | + +error: repeated calls to `Ty::is_diag_item` + --> tests/ui-internal/repeated_is_diagnostic_item.rs:20:13 + | +LL | let _ = !ty.is_diag_item(cx, sym::Option) && !ty.is_diag_item(cx, sym::Result); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `Ty::opt_diag_name`, and reuse the results + | +LL - let _ = !ty.is_diag_item(cx, sym::Option) && !ty.is_diag_item(cx, sym::Result); +LL + let _ = !matches!(ty.opt_diag_name(cx), Some(sym::Option | sym::Result)); + | + +error: repeated calls to `AdtDef::is_diag_item` + --> tests/ui-internal/repeated_is_diagnostic_item.rs:22:13 + | +LL | let _ = adt_def.is_diag_item(cx, sym::Option) || adt_def.is_diag_item(cx, sym::Result); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `AdtDef::opt_diag_name`, and reuse the results + | +LL - let _ = adt_def.is_diag_item(cx, sym::Option) || adt_def.is_diag_item(cx, sym::Result); +LL + let _ = matches!(adt_def.opt_diag_name(cx), Some(sym::Option | sym::Result)); + | + +error: repeated calls to `AdtDef::is_diag_item` + --> tests/ui-internal/repeated_is_diagnostic_item.rs:24:13 + | +LL | let _ = !adt_def.is_diag_item(cx, sym::Option) && !adt_def.is_diag_item(cx, sym::Result); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `AdtDef::opt_diag_name`, and reuse the results + | +LL - let _ = !adt_def.is_diag_item(cx, sym::Option) && !adt_def.is_diag_item(cx, sym::Result); +LL + let _ = !matches!(adt_def.opt_diag_name(cx), Some(sym::Option | sym::Result)); + | + +error: repeated calls to `TyCtxt::is_diagnostic_item` + --> tests/ui-internal/repeated_is_diagnostic_item.rs:26:13 + | +LL | let _ = cx.tcx.is_diagnostic_item(sym::Option, did) || cx.tcx.is_diagnostic_item(sym::Result, did); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `TyCtxt::get_diagnostic_name`, and reuse the results + | +LL - let _ = cx.tcx.is_diagnostic_item(sym::Option, did) || cx.tcx.is_diagnostic_item(sym::Result, did); +LL + let _ = matches!(cx.tcx.get_diagnostic_name(did), Some(sym::Option | sym::Result)); + | + +error: repeated calls to `TyCtxt::is_diagnostic_item` + --> tests/ui-internal/repeated_is_diagnostic_item.rs:28:13 + | +LL | let _ = !cx.tcx.is_diagnostic_item(sym::Option, did) && !cx.tcx.is_diagnostic_item(sym::Result, did); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `TyCtxt::get_diagnostic_name`, and reuse the results + | +LL - let _ = !cx.tcx.is_diagnostic_item(sym::Option, did) && !cx.tcx.is_diagnostic_item(sym::Result, did); +LL + let _ = !matches!(cx.tcx.get_diagnostic_name(did), Some(sym::Option | sym::Result)); + | + +error: aborting due to 6 previous errors + diff --git a/tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs b/tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs new file mode 100644 index 000000000000..807da07ce8aa --- /dev/null +++ b/tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs @@ -0,0 +1,213 @@ +//@no-rustfix +#![feature(rustc_private)] + +extern crate rustc_hir; +extern crate rustc_lint; +extern crate rustc_middle; +extern crate rustc_span; + +use clippy_utils::res::MaybeDef; +use clippy_utils::sym; +use rustc_hir::def_id::DefId; +use rustc_lint::LateContext; +use rustc_middle::ty::{AdtDef, Ty, TyCtxt}; +use rustc_span::Symbol; + +fn main() {} + +// if-chains with repeated calls on the same `ty` +fn if_chains(cx: &LateContext<'_>, ty: Ty<'_>, adt_def: &AdtDef<'_>) { + let did = ty.opt_def_id().unwrap(); + + let _ = if ty.is_diag_item(cx, sym::Option) { + //~^ repeated_is_diagnostic_item + "Option" + } else if ty.is_diag_item(cx, sym::Result) { + "Result" + } else { + return; + }; + // should ideally suggest the following: + // let _ = match ty.opt_diag_name() { + // Some(sym::Option) => { + // "Option" + // } + // Some(sym::Result) => { + // "Result" + // } + // _ => { + // return; + // } + // }; + + // same but in a stmt + if ty.is_diag_item(cx, sym::Option) { + //~^ repeated_is_diagnostic_item + eprintln!("Option"); + } else if ty.is_diag_item(cx, sym::Result) { + eprintln!("Result"); + } + // should ideally suggest the following: + // match ty.opt_diag_name() { + // Some(sym::Option) => { + // "Option" + // } + // Some(sym::Result) => { + // "Result" + // } + // _ => {} + // }; + + // nested conditions + let _ = if ty.is_diag_item(cx, sym::Option) && 4 == 5 { + //~^ repeated_is_diagnostic_item + "Option" + } else if ty.is_diag_item(cx, sym::Result) && 4 == 5 { + "Result" + } else { + return; + }; + + let _ = if cx.tcx.is_diagnostic_item(sym::Option, did) { + //~^ repeated_is_diagnostic_item + "Option" + } else if cx.tcx.is_diagnostic_item(sym::Result, did) { + "Result" + } else { + return; + }; + // should ideally suggest the following: + // let _ = match cx.get_diagnostic_name(did) { + // Some(sym::Option) => { + // "Option" + // } + // Some(sym::Result) => { + // "Result" + // } + // _ => { + // return; + // } + // }; + + // same but in a stmt + if cx.tcx.is_diagnostic_item(sym::Option, did) { + //~^ repeated_is_diagnostic_item + eprintln!("Option"); + } else if cx.tcx.is_diagnostic_item(sym::Result, did) { + eprintln!("Result"); + } + // should ideally suggest the following: + // match cx.tcx.get_diagnostic_name(did) { + // Some(sym::Option) => { + // "Option" + // } + // Some(sym::Result) => { + // "Result" + // } + // _ => {} + // }; + + // nested conditions + let _ = if cx.tcx.is_diagnostic_item(sym::Option, did) && 4 == 5 { + //~^ repeated_is_diagnostic_item + "Option" + } else if cx.tcx.is_diagnostic_item(sym::Result, did) && 4 == 5 { + "Result" + } else { + return; + }; +} + +// if-chains with repeated calls on the same `ty` +fn consecutive_ifs(cx: &LateContext<'_>, ty: Ty<'_>, adt_def: &AdtDef<'_>) { + let did = ty.opt_def_id().unwrap(); + + { + if ty.is_diag_item(cx, sym::Option) { + //~^ repeated_is_diagnostic_item + println!("Option"); + } + if ty.is_diag_item(cx, sym::Result) { + println!("Result"); + } + println!("done!") + } + + // nested conditions + { + if ty.is_diag_item(cx, sym::Option) && 4 == 5 { + //~^ repeated_is_diagnostic_item + println!("Option"); + } + if ty.is_diag_item(cx, sym::Result) && 4 == 5 { + println!("Result"); + } + println!("done!") + } + + { + if cx.tcx.is_diagnostic_item(sym::Option, did) { + //~^ repeated_is_diagnostic_item + println!("Option"); + } + if cx.tcx.is_diagnostic_item(sym::Result, did) { + println!("Result"); + } + println!("done!") + } + + // nested conditions + { + if cx.tcx.is_diagnostic_item(sym::Option, did) && 4 == 5 { + //~^ repeated_is_diagnostic_item + println!("Option"); + } + if cx.tcx.is_diagnostic_item(sym::Result, did) && 4 == 5 { + println!("Result"); + } + println!("done!") + } + + // All the same, but the second if is the final expression + { + if ty.is_diag_item(cx, sym::Option) { + //~^ repeated_is_diagnostic_item + println!("Option"); + } + if ty.is_diag_item(cx, sym::Result) { + println!("Result"); + } + } + + // nested conditions + { + if ty.is_diag_item(cx, sym::Option) && 4 == 5 { + //~^ repeated_is_diagnostic_item + println!("Option"); + } + if ty.is_diag_item(cx, sym::Result) && 4 == 5 { + println!("Result"); + } + } + + { + if cx.tcx.is_diagnostic_item(sym::Option, did) { + //~^ repeated_is_diagnostic_item + println!("Option"); + } + if cx.tcx.is_diagnostic_item(sym::Result, did) { + println!("Result"); + } + } + + // nested conditions + { + if cx.tcx.is_diagnostic_item(sym::Option, did) && 4 == 5 { + //~^ repeated_is_diagnostic_item + println!("Option"); + } + if cx.tcx.is_diagnostic_item(sym::Result, did) && 4 == 5 { + println!("Result"); + } + } +} diff --git a/tests/ui-internal/repeated_is_diagnostic_item_unfixable.stderr b/tests/ui-internal/repeated_is_diagnostic_item_unfixable.stderr new file mode 100644 index 000000000000..890817da5235 --- /dev/null +++ b/tests/ui-internal/repeated_is_diagnostic_item_unfixable.stderr @@ -0,0 +1,374 @@ +error: repeated calls to `Ty::is_diag_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:22:13 + | +LL | let _ = if ty.is_diag_item(cx, sym::Option) { + | ^ -------------------------------- called here + | _____________| + | | +LL | | +LL | | "Option" +LL | | } else if ty.is_diag_item(cx, sym::Result) { + | | -------------------------------- called here +... | +LL | | return; +LL | | }; + | |_____^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results + = note: `-D clippy::repeated-is-diagnostic-item` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::repeated_is_diagnostic_item)]` +help: call `Ty::opt_diag_name`, and reuse the results + | +LL ~ let /* name */ = ty.opt_diag_name(cx); +LL ~ let _ = if /* name */ == Some(sym::Option) { +LL | +LL | "Option" +LL ~ } else if /* name */ == Some(sym::Result) { + | + +error: repeated calls to `Ty::is_diag_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:44:5 + | +LL | if ty.is_diag_item(cx, sym::Option) { + | ^ -------------------------------- called here + | _____| + | | +LL | | +LL | | eprintln!("Option"); +LL | | } else if ty.is_diag_item(cx, sym::Result) { + | | -------------------------------- called here +LL | | eprintln!("Result"); +LL | | } + | |_____^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `Ty::opt_diag_name`, and reuse the results + | +LL ~ let /* name */ = ty.opt_diag_name(cx); +LL ~ if /* name */ == Some(sym::Option) { +LL | +LL | eprintln!("Option"); +LL ~ } else if /* name */ == Some(sym::Result) { + | + +error: repeated calls to `Ty::is_diag_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:62:13 + | +LL | let _ = if ty.is_diag_item(cx, sym::Option) && 4 == 5 { + | ^ -------------------------------- called here + | _____________| + | | +LL | | +LL | | "Option" +LL | | } else if ty.is_diag_item(cx, sym::Result) && 4 == 5 { + | | -------------------------------- called here +... | +LL | | return; +LL | | }; + | |_____^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `Ty::opt_diag_name`, and reuse the results + | +LL ~ let /* name */ = ty.opt_diag_name(cx); +LL ~ let _ = if /* name */ == Some(sym::Option) && 4 == 5 { +LL | +LL | "Option" +LL ~ } else if /* name */ == Some(sym::Result) && 4 == 5 { + | + +error: repeated calls to `TyCtxt::is_diagnostic_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:71:13 + | +LL | let _ = if cx.tcx.is_diagnostic_item(sym::Option, did) { + | ^ ------------------------------------------- called here + | _____________| + | | +LL | | +LL | | "Option" +LL | | } else if cx.tcx.is_diagnostic_item(sym::Result, did) { + | | ------------------------------------------- called here +... | +LL | | return; +LL | | }; + | |_____^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `TyCtxt::get_diagnostic_name`, and reuse the results + | +LL ~ let /* name */ = cx.tcx.get_diagnostic_name(did); +LL ~ let _ = if /* name */ == Some(sym::Option) { +LL | +LL | "Option" +LL ~ } else if /* name */ == Some(sym::Result) { + | + +error: repeated calls to `TyCtxt::is_diagnostic_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:93:5 + | +LL | if cx.tcx.is_diagnostic_item(sym::Option, did) { + | ^ ------------------------------------------- called here + | _____| + | | +LL | | +LL | | eprintln!("Option"); +LL | | } else if cx.tcx.is_diagnostic_item(sym::Result, did) { + | | ------------------------------------------- called here +LL | | eprintln!("Result"); +LL | | } + | |_____^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `TyCtxt::get_diagnostic_name`, and reuse the results + | +LL ~ let /* name */ = cx.tcx.get_diagnostic_name(did); +LL ~ if /* name */ == Some(sym::Option) { +LL | +LL | eprintln!("Option"); +LL ~ } else if /* name */ == Some(sym::Result) { + | + +error: repeated calls to `TyCtxt::is_diagnostic_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:111:13 + | +LL | let _ = if cx.tcx.is_diagnostic_item(sym::Option, did) && 4 == 5 { + | ^ ------------------------------------------- called here + | _____________| + | | +LL | | +LL | | "Option" +LL | | } else if cx.tcx.is_diagnostic_item(sym::Result, did) && 4 == 5 { + | | ------------------------------------------- called here +... | +LL | | return; +LL | | }; + | |_____^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `TyCtxt::get_diagnostic_name`, and reuse the results + | +LL ~ let /* name */ = cx.tcx.get_diagnostic_name(did); +LL ~ let _ = if /* name */ == Some(sym::Option) && 4 == 5 { +LL | +LL | "Option" +LL ~ } else if /* name */ == Some(sym::Result) && 4 == 5 { + | + +error: repeated calls to `Ty::is_diag_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:126:9 + | +LL | if ty.is_diag_item(cx, sym::Option) { + | ^ -------------------------------- called here + | _________| + | | +LL | | +LL | | println!("Option"); +LL | | } +LL | | if ty.is_diag_item(cx, sym::Result) { + | | -------------------------------- called here +LL | | println!("Result"); +LL | | } + | |_________^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `Ty::opt_diag_name`, and reuse the results + | +LL ~ let /* name */ = ty.opt_diag_name(cx); +LL ~ if /* name */ == Some(sym::Option) { +LL | +LL | println!("Option"); +LL | } +LL ~ if /* name */ == Some(sym::Result) { + | + +error: repeated calls to `Ty::is_diag_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:138:9 + | +LL | if ty.is_diag_item(cx, sym::Option) && 4 == 5 { + | ^ -------------------------------- called here + | _________| + | | +LL | | +LL | | println!("Option"); +LL | | } +LL | | if ty.is_diag_item(cx, sym::Result) && 4 == 5 { + | | -------------------------------- called here +LL | | println!("Result"); +LL | | } + | |_________^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `Ty::opt_diag_name`, and reuse the results + | +LL ~ let /* name */ = ty.opt_diag_name(cx); +LL ~ if /* name */ == Some(sym::Option) && 4 == 5 { +LL | +LL | println!("Option"); +LL | } +LL ~ if /* name */ == Some(sym::Result) && 4 == 5 { + | + +error: repeated calls to `TyCtxt::is_diagnostic_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:149:9 + | +LL | if cx.tcx.is_diagnostic_item(sym::Option, did) { + | ^ ------------------------------------------- called here + | _________| + | | +LL | | +LL | | println!("Option"); +LL | | } +LL | | if cx.tcx.is_diagnostic_item(sym::Result, did) { + | | ------------------------------------------- called here +LL | | println!("Result"); +LL | | } + | |_________^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `TyCtxt::get_diagnostic_name`, and reuse the results + | +LL ~ let /* name */ = cx.tcx.get_diagnostic_name(did); +LL ~ if /* name */ == Some(sym::Option) { +LL | +LL | println!("Option"); +LL | } +LL ~ if /* name */ == Some(sym::Result) { + | + +error: repeated calls to `TyCtxt::is_diagnostic_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:161:9 + | +LL | if cx.tcx.is_diagnostic_item(sym::Option, did) && 4 == 5 { + | ^ ------------------------------------------- called here + | _________| + | | +LL | | +LL | | println!("Option"); +LL | | } +LL | | if cx.tcx.is_diagnostic_item(sym::Result, did) && 4 == 5 { + | | ------------------------------------------- called here +LL | | println!("Result"); +LL | | } + | |_________^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `TyCtxt::get_diagnostic_name`, and reuse the results + | +LL ~ let /* name */ = cx.tcx.get_diagnostic_name(did); +LL ~ if /* name */ == Some(sym::Option) && 4 == 5 { +LL | +LL | println!("Option"); +LL | } +LL ~ if /* name */ == Some(sym::Result) && 4 == 5 { + | + +error: repeated calls to `Ty::is_diag_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:173:9 + | +LL | if ty.is_diag_item(cx, sym::Option) { + | ^ -------------------------------- called here + | _________| + | | +LL | | +LL | | println!("Option"); +LL | | } +LL | | if ty.is_diag_item(cx, sym::Result) { + | | -------------------------------- called here +LL | | println!("Result"); +LL | | } + | |_________^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `Ty::opt_diag_name`, and reuse the results + | +LL ~ let /* name */ = ty.opt_diag_name(cx); +LL ~ if /* name */ == Some(sym::Option) { +LL | +LL | println!("Option"); +LL | } +LL ~ if /* name */ == Some(sym::Result) { + | + +error: repeated calls to `Ty::is_diag_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:184:9 + | +LL | if ty.is_diag_item(cx, sym::Option) && 4 == 5 { + | ^ -------------------------------- called here + | _________| + | | +LL | | +LL | | println!("Option"); +LL | | } +LL | | if ty.is_diag_item(cx, sym::Result) && 4 == 5 { + | | -------------------------------- called here +LL | | println!("Result"); +LL | | } + | |_________^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `Ty::opt_diag_name`, and reuse the results + | +LL ~ let /* name */ = ty.opt_diag_name(cx); +LL ~ if /* name */ == Some(sym::Option) && 4 == 5 { +LL | +LL | println!("Option"); +LL | } +LL ~ if /* name */ == Some(sym::Result) && 4 == 5 { + | + +error: repeated calls to `TyCtxt::is_diagnostic_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:194:9 + | +LL | if cx.tcx.is_diagnostic_item(sym::Option, did) { + | ^ ------------------------------------------- called here + | _________| + | | +LL | | +LL | | println!("Option"); +LL | | } +LL | | if cx.tcx.is_diagnostic_item(sym::Result, did) { + | | ------------------------------------------- called here +LL | | println!("Result"); +LL | | } + | |_________^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `TyCtxt::get_diagnostic_name`, and reuse the results + | +LL ~ let /* name */ = cx.tcx.get_diagnostic_name(did); +LL ~ if /* name */ == Some(sym::Option) { +LL | +LL | println!("Option"); +LL | } +LL ~ if /* name */ == Some(sym::Result) { + | + +error: repeated calls to `TyCtxt::is_diagnostic_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:205:9 + | +LL | if cx.tcx.is_diagnostic_item(sym::Option, did) && 4 == 5 { + | ^ ------------------------------------------- called here + | _________| + | | +LL | | +LL | | println!("Option"); +LL | | } +LL | | if cx.tcx.is_diagnostic_item(sym::Result, did) && 4 == 5 { + | | ------------------------------------------- called here +LL | | println!("Result"); +LL | | } + | |_________^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `TyCtxt::get_diagnostic_name`, and reuse the results + | +LL ~ let /* name */ = cx.tcx.get_diagnostic_name(did); +LL ~ if /* name */ == Some(sym::Option) && 4 == 5 { +LL | +LL | println!("Option"); +LL | } +LL ~ if /* name */ == Some(sym::Result) && 4 == 5 { + | + +error: aborting due to 14 previous errors + diff --git a/tests/ui-toml/collapsible_if/collapsible_else_if.fixed b/tests/ui-toml/collapsible_if/collapsible_else_if.fixed index ec45dfd2033a..213b56b786b1 100644 --- a/tests/ui-toml/collapsible_if/collapsible_else_if.fixed +++ b/tests/ui-toml/collapsible_if/collapsible_else_if.fixed @@ -1,5 +1,5 @@ #![allow(clippy::eq_op, clippy::nonminimal_bool)] -#![warn(clippy::collapsible_if)] +#![warn(clippy::collapsible_else_if)] #[rustfmt::skip] fn main() { diff --git a/tests/ui-toml/collapsible_if/collapsible_else_if.rs b/tests/ui-toml/collapsible_if/collapsible_else_if.rs index 54315a3c32bf..2d4c2c54031e 100644 --- a/tests/ui-toml/collapsible_if/collapsible_else_if.rs +++ b/tests/ui-toml/collapsible_if/collapsible_else_if.rs @@ -1,5 +1,5 @@ #![allow(clippy::eq_op, clippy::nonminimal_bool)] -#![warn(clippy::collapsible_if)] +#![warn(clippy::collapsible_else_if)] #[rustfmt::skip] fn main() { diff --git a/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed b/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed index 40556ca5410f..962a4e00d86e 100644 --- a/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed +++ b/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed @@ -3,7 +3,7 @@ // Should warn pub fn pub_foo(s: &Vec, b: &u32, x: &mut u32) { - //~^ ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut *x += *b + s.len() as u32; } diff --git a/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs b/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs index bbc63ceb15a3..5f584c6704f2 100644 --- a/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs +++ b/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs @@ -3,7 +3,7 @@ // Should warn pub fn pub_foo(s: &mut Vec, b: &u32, x: &mut u32) { - //~^ ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut *x += *b + s.len() as u32; } diff --git a/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr b/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr index c10607bf4bab..57137ab08d1e 100644 --- a/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr +++ b/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr @@ -1,8 +1,10 @@ -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs:5:19 | LL | pub fn pub_foo(s: &mut Vec, b: &u32, x: &mut u32) { - | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` + | ^----^^^^^^^^ + | | + | help: consider removing this `mut` | = warning: changing this function will impact semver compatibility = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` diff --git a/tests/ui-toml/toml_disallowed_methods/clippy.toml b/tests/ui-toml/toml_disallowed_methods/clippy.toml index c7a326f28295..2c54b73d72d7 100644 --- a/tests/ui-toml/toml_disallowed_methods/clippy.toml +++ b/tests/ui-toml/toml_disallowed_methods/clippy.toml @@ -17,4 +17,6 @@ disallowed-methods = [ # re-exports "conf_disallowed_methods::identity", "conf_disallowed_methods::renamed", + # also used in desugaring + "std::future::Future::poll", ] diff --git a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs index 2dac01649a0f..621317246d6d 100644 --- a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs +++ b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs @@ -80,3 +80,19 @@ fn main() { renamed(1); //~^ disallowed_methods } + +mod issue16185 { + use std::pin::Pin; + use std::task::Context; + + async fn test(f: impl Future) { + // Should not lint even though desugaring uses + // disallowed method `std::future::Future::poll()`. + f.await + } + + fn explicit>(f: Pin<&mut F>, cx: &mut Context<'_>) { + f.poll(cx); + //~^ disallowed_methods + } +} diff --git a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr index 20474ad6e927..8e7e112a93f3 100644 --- a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr +++ b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr @@ -99,5 +99,11 @@ error: use of a disallowed method `conf_disallowed_methods::renamed` LL | renamed(1); | ^^^^^^^ -error: aborting due to 16 previous errors +error: use of a disallowed method `std::future::Future::poll` + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:95:11 + | +LL | f.poll(cx); + | ^^^^ + +error: aborting due to 17 previous errors diff --git a/tests/ui/assertions_on_constants.rs b/tests/ui/assertions_on_constants.rs index f467d4966aef..1c49b6e6b7b1 100644 --- a/tests/ui/assertions_on_constants.rs +++ b/tests/ui/assertions_on_constants.rs @@ -96,3 +96,8 @@ fn _f4() { assert!(C); //~^ assertions_on_constants } + +fn issue_16242(var: bool) { + // should not lint + assert!(cfg!(feature = "hey") && var); +} diff --git a/tests/ui/branches_sharing_code/shared_at_bottom.rs b/tests/ui/branches_sharing_code/shared_at_bottom.rs index fa322dc28a78..a7f950b44caf 100644 --- a/tests/ui/branches_sharing_code/shared_at_bottom.rs +++ b/tests/ui/branches_sharing_code/shared_at_bottom.rs @@ -300,3 +300,65 @@ fn issue15004() { //~^ branches_sharing_code }; } + +pub fn issue15347() -> isize { + if false { + static A: isize = 4; + return A; + } else { + static A: isize = 5; + return A; + } + + if false { + //~^ branches_sharing_code + type ISize = isize; + return ISize::MAX; + } else { + type ISize = isize; + return ISize::MAX; + } + + if false { + //~^ branches_sharing_code + fn foo() -> isize { + 4 + } + return foo(); + } else { + fn foo() -> isize { + 4 + } + return foo(); + } + + if false { + //~^ branches_sharing_code + use std::num::NonZeroIsize; + return NonZeroIsize::new(4).unwrap().get(); + } else { + use std::num::NonZeroIsize; + return NonZeroIsize::new(4).unwrap().get(); + } + + if false { + //~^ branches_sharing_code + const B: isize = 5; + return B; + } else { + const B: isize = 5; + return B; + } + + // Should not lint! + const A: isize = 1; + if false { + const B: isize = A; + return B; + } else { + const C: isize = A; + return C; + } + + todo!() +} diff --git a/tests/ui/branches_sharing_code/shared_at_bottom.stderr b/tests/ui/branches_sharing_code/shared_at_bottom.stderr index 1c470fb0da5e..4ff3990232a5 100644 --- a/tests/ui/branches_sharing_code/shared_at_bottom.stderr +++ b/tests/ui/branches_sharing_code/shared_at_bottom.stderr @@ -202,5 +202,73 @@ LL ~ } LL ~ 1; | -error: aborting due to 12 previous errors +error: all if blocks contain the same code at the start + --> tests/ui/branches_sharing_code/shared_at_bottom.rs:313:5 + | +LL | / if false { +LL | | +LL | | type ISize = isize; +LL | | return ISize::MAX; + | |__________________________^ + | +help: consider moving these statements before the if + | +LL ~ type ISize = isize; +LL + return ISize::MAX; +LL + if false { + | + +error: all if blocks contain the same code at the start + --> tests/ui/branches_sharing_code/shared_at_bottom.rs:322:5 + | +LL | / if false { +LL | | +LL | | fn foo() -> isize { +LL | | 4 +LL | | } +LL | | return foo(); + | |_____________________^ + | +help: consider moving these statements before the if + | +LL ~ fn foo() -> isize { +LL + 4 +LL + } +LL + return foo(); +LL + if false { + | + +error: all if blocks contain the same code at the start + --> tests/ui/branches_sharing_code/shared_at_bottom.rs:335:5 + | +LL | / if false { +LL | | +LL | | use std::num::NonZeroIsize; +LL | | return NonZeroIsize::new(4).unwrap().get(); + | |___________________________________________________^ + | +help: consider moving these statements before the if + | +LL ~ use std::num::NonZeroIsize; +LL + return NonZeroIsize::new(4).unwrap().get(); +LL + if false { + | + +error: all if blocks contain the same code at the start + --> tests/ui/branches_sharing_code/shared_at_bottom.rs:344:5 + | +LL | / if false { +LL | | +LL | | const B: isize = 5; +LL | | return B; + | |_________________^ + | +help: consider moving these statements before the if + | +LL ~ const B: isize = 5; +LL + return B; +LL + if false { + | + +error: aborting due to 16 previous errors diff --git a/tests/ui/cast.stderr b/tests/ui/cast.stderr index 0ff1dc11c3ac..14b84b1ff1ef 100644 --- a/tests/ui/cast.stderr +++ b/tests/ui/cast.stderr @@ -1,4 +1,4 @@ -error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) +error: casting `i32` to `f32` may cause a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) --> tests/ui/cast.rs:23:5 | LL | x0 as f32; @@ -7,31 +7,31 @@ LL | x0 as f32; = note: `-D clippy::cast-precision-loss` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]` -error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) +error: casting `i64` to `f32` may cause a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) --> tests/ui/cast.rs:27:5 | LL | x1 as f32; | ^^^^^^^^^ -error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) +error: casting `i64` to `f64` may cause a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) --> tests/ui/cast.rs:30:5 | LL | x1 as f64; | ^^^^^^^^^ -error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) +error: casting `u32` to `f32` may cause a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) --> tests/ui/cast.rs:34:5 | LL | x2 as f32; | ^^^^^^^^^ -error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) +error: casting `u64` to `f32` may cause a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) --> tests/ui/cast.rs:38:5 | LL | x3 as f32; | ^^^^^^^^^ -error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) +error: casting `u64` to `f64` may cause a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) --> tests/ui/cast.rs:41:5 | LL | x3 as f64; diff --git a/tests/ui/cast_size.r32bit.stderr b/tests/ui/cast_size.r32bit.stderr index 5811cb3607ba..2f7eeda385e5 100644 --- a/tests/ui/cast_size.r32bit.stderr +++ b/tests/ui/cast_size.r32bit.stderr @@ -13,7 +13,7 @@ LL - 1isize as i8; LL + i8::try_from(1isize); | -error: casting `isize` to `f32` causes a loss of precision (`isize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide) +error: casting `isize` to `f32` may cause a loss of precision (`isize` can be up to 64 bits wide depending on the target architecture, but `f32`'s mantissa is only 23 bits wide) --> tests/ui/cast_size.rs:24:5 | LL | x0 as f32; @@ -22,19 +22,19 @@ LL | x0 as f32; = note: `-D clippy::cast-precision-loss` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]` -error: casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide) +error: casting `usize` to `f32` may cause a loss of precision (`usize` can be up to 64 bits wide depending on the target architecture, but `f32`'s mantissa is only 23 bits wide) --> tests/ui/cast_size.rs:26:5 | LL | x1 as f32; | ^^^^^^^^^ -error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) +error: casting `isize` to `f64` may cause a loss of precision (`isize` can be up to 64 bits wide depending on the target architecture, but `f64`'s mantissa is only 52 bits wide) --> tests/ui/cast_size.rs:28:5 | LL | x0 as f64; | ^^^^^^^^^ -error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) +error: casting `usize` to `f64` may cause a loss of precision (`usize` can be up to 64 bits wide depending on the target architecture, but `f64`'s mantissa is only 52 bits wide) --> tests/ui/cast_size.rs:30:5 | LL | x1 as f64; @@ -165,13 +165,13 @@ error: casting `u32` to `isize` may wrap around the value on targets with 32-bit LL | 1u32 as isize; | ^^^^^^^^^^^^^ -error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) +error: casting `i32` to `f32` may cause a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) --> tests/ui/cast_size.rs:61:5 | LL | 999_999_999 as f32; | ^^^^^^^^^^^^^^^^^^ -error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) +error: casting `usize` to `f64` may cause a loss of precision (`usize` can be up to 64 bits wide depending on the target architecture, but `f64`'s mantissa is only 52 bits wide) --> tests/ui/cast_size.rs:63:5 | LL | 9_999_999_999_999_999usize as f64; diff --git a/tests/ui/cast_size.r64bit.stderr b/tests/ui/cast_size.r64bit.stderr index ba1419583aeb..8e5f38137602 100644 --- a/tests/ui/cast_size.r64bit.stderr +++ b/tests/ui/cast_size.r64bit.stderr @@ -13,7 +13,7 @@ LL - 1isize as i8; LL + i8::try_from(1isize); | -error: casting `isize` to `f32` causes a loss of precision (`isize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide) +error: casting `isize` to `f32` may cause a loss of precision (`isize` can be up to 64 bits wide depending on the target architecture, but `f32`'s mantissa is only 23 bits wide) --> tests/ui/cast_size.rs:24:5 | LL | x0 as f32; @@ -22,19 +22,19 @@ LL | x0 as f32; = note: `-D clippy::cast-precision-loss` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]` -error: casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide) +error: casting `usize` to `f32` may cause a loss of precision (`usize` can be up to 64 bits wide depending on the target architecture, but `f32`'s mantissa is only 23 bits wide) --> tests/ui/cast_size.rs:26:5 | LL | x1 as f32; | ^^^^^^^^^ -error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) +error: casting `isize` to `f64` may cause a loss of precision (`isize` can be up to 64 bits wide depending on the target architecture, but `f64`'s mantissa is only 52 bits wide) --> tests/ui/cast_size.rs:28:5 | LL | x0 as f64; | ^^^^^^^^^ -error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) +error: casting `usize` to `f64` may cause a loss of precision (`usize` can be up to 64 bits wide depending on the target architecture, but `f64`'s mantissa is only 52 bits wide) --> tests/ui/cast_size.rs:30:5 | LL | x1 as f64; @@ -165,13 +165,13 @@ error: casting `u32` to `isize` may wrap around the value on targets with 32-bit LL | 1u32 as isize; | ^^^^^^^^^^^^^ -error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) +error: casting `i32` to `f32` may cause a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) --> tests/ui/cast_size.rs:61:5 | LL | 999_999_999 as f32; | ^^^^^^^^^^^^^^^^^^ -error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) +error: casting `usize` to `f64` may cause a loss of precision (`usize` can be up to 64 bits wide depending on the target architecture, but `f64`'s mantissa is only 52 bits wide) --> tests/ui/cast_size.rs:63:5 | LL | 9_999_999_999_999_999usize as f64; diff --git a/tests/ui/cmp_null.fixed b/tests/ui/cmp_null.fixed index c12279cf12e6..4a0ee439e94a 100644 --- a/tests/ui/cmp_null.fixed +++ b/tests/ui/cmp_null.fixed @@ -38,3 +38,23 @@ fn issue15010() { debug_assert!(!f.is_null()); //~^ cmp_null } + +fn issue16281() { + use std::ptr; + + struct Container { + value: *const i32, + } + let x = Container { value: ptr::null() }; + + macro_rules! dot_value { + ($obj:expr) => { + $obj.value + }; + } + + if dot_value!(x).is_null() { + //~^ cmp_null + todo!() + } +} diff --git a/tests/ui/cmp_null.rs b/tests/ui/cmp_null.rs index 2771a16e00c5..26ea8960e5fb 100644 --- a/tests/ui/cmp_null.rs +++ b/tests/ui/cmp_null.rs @@ -38,3 +38,23 @@ fn issue15010() { debug_assert!(f != std::ptr::null_mut()); //~^ cmp_null } + +fn issue16281() { + use std::ptr; + + struct Container { + value: *const i32, + } + let x = Container { value: ptr::null() }; + + macro_rules! dot_value { + ($obj:expr) => { + $obj.value + }; + } + + if dot_value!(x) == ptr::null() { + //~^ cmp_null + todo!() + } +} diff --git a/tests/ui/cmp_null.stderr b/tests/ui/cmp_null.stderr index 381747cb3c65..51b98d2a2320 100644 --- a/tests/ui/cmp_null.stderr +++ b/tests/ui/cmp_null.stderr @@ -37,5 +37,11 @@ error: comparing with null is better expressed by the `.is_null()` method LL | debug_assert!(f != std::ptr::null_mut()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!f.is_null()` -error: aborting due to 6 previous errors +error: comparing with null is better expressed by the `.is_null()` method + --> tests/ui/cmp_null.rs:56:8 + | +LL | if dot_value!(x) == ptr::null() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dot_value!(x).is_null()` + +error: aborting due to 7 previous errors diff --git a/tests/ui/collapsible_else_if.fixed b/tests/ui/collapsible_else_if.fixed index e7439beef186..cd2d9be9f433 100644 --- a/tests/ui/collapsible_else_if.fixed +++ b/tests/ui/collapsible_else_if.fixed @@ -1,5 +1,5 @@ #![allow(clippy::assertions_on_constants, clippy::equatable_if_let, clippy::needless_ifs)] -#![warn(clippy::collapsible_if, clippy::collapsible_else_if)] +#![warn(clippy::collapsible_else_if)] #[rustfmt::skip] fn main() { @@ -70,6 +70,17 @@ fn main() { } //~^^^^^^^^ collapsible_else_if + if x == "hello" { + if y == "world" { + print!("Hello "); + } else { + println!("world"); + } + } else if let Some(42) = Some(42) { + println!("42"); + } + //~^^^^^ collapsible_else_if + if x == "hello" { print!("Hello "); } else { @@ -78,6 +89,21 @@ fn main() { println!("world!") } } + + if x == "hello" { + if y == "world" { + print!("Hello "); + } else { + println!("world"); + } + } else { + if let Some(42) = Some(42) { + println!("42"); + } else { + println!("!"); + } + } + } #[rustfmt::skip] @@ -88,30 +114,12 @@ fn issue_7318() { } fn issue_13365() { - // all the `expect`s that we should fulfill + // ensure we fulfill `#[expect]` if true { } else { #[expect(clippy::collapsible_else_if)] if false {} } - - if true { - } else { - #[expect(clippy::style)] - if false {} - } - - if true { - } else { - #[expect(clippy::all)] - if false {} - } - - if true { - } else { - #[expect(warnings)] - if false {} - } } fn issue14799() { diff --git a/tests/ui/collapsible_else_if.rs b/tests/ui/collapsible_else_if.rs index 434ba3654f98..75f204328538 100644 --- a/tests/ui/collapsible_else_if.rs +++ b/tests/ui/collapsible_else_if.rs @@ -1,5 +1,5 @@ #![allow(clippy::assertions_on_constants, clippy::equatable_if_let, clippy::needless_ifs)] -#![warn(clippy::collapsible_if, clippy::collapsible_else_if)] +#![warn(clippy::collapsible_else_if)] #[rustfmt::skip] fn main() { @@ -84,6 +84,19 @@ fn main() { } //~^^^^^^^^ collapsible_else_if + if x == "hello" { + if y == "world" { + print!("Hello "); + } else { + println!("world"); + } + } else { + if let Some(42) = Some(42) { + println!("42"); + } + } + //~^^^^^ collapsible_else_if + if x == "hello" { print!("Hello "); } else { @@ -92,6 +105,21 @@ fn main() { println!("world!") } } + + if x == "hello" { + if y == "world" { + print!("Hello "); + } else { + println!("world"); + } + } else { + if let Some(42) = Some(42) { + println!("42"); + } else { + println!("!"); + } + } + } #[rustfmt::skip] @@ -104,30 +132,12 @@ fn issue_7318() { } fn issue_13365() { - // all the `expect`s that we should fulfill + // ensure we fulfill `#[expect]` if true { } else { #[expect(clippy::collapsible_else_if)] if false {} } - - if true { - } else { - #[expect(clippy::style)] - if false {} - } - - if true { - } else { - #[expect(clippy::all)] - if false {} - } - - if true { - } else { - #[expect(warnings)] - if false {} - } } fn issue14799() { diff --git a/tests/ui/collapsible_else_if.stderr b/tests/ui/collapsible_else_if.stderr index ce1da593a8e9..ebd78d2b1ffe 100644 --- a/tests/ui/collapsible_else_if.stderr +++ b/tests/ui/collapsible_else_if.stderr @@ -142,7 +142,25 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:100:10 + --> tests/ui/collapsible_else_if.rs:93:12 + | +LL | } else { + | ____________^ +LL | | if let Some(42) = Some(42) { +LL | | println!("42"); +LL | | } +LL | | } + | |_____^ + | +help: collapse nested if block + | +LL ~ } else if let Some(42) = Some(42) { +LL + println!("42"); +LL + } + | + +error: this `else { if .. }` block can be collapsed + --> tests/ui/collapsible_else_if.rs:128:10 | LL | }else{ | __________^ @@ -151,7 +169,7 @@ LL | | } | |_____^ help: collapse nested if block: `if false {}` error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:157:12 + --> tests/ui/collapsible_else_if.rs:167:12 | LL | } else { | ____________^ @@ -159,5 +177,5 @@ LL | | (if y == "world" { println!("world") } else { println!("!") }) LL | | } | |_____^ help: collapse nested if block: `if y == "world" { println!("world") } else { println!("!") }` -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors diff --git a/tests/ui/crashes/ice-10148.stderr b/tests/ui/crashes/ice-10148.stderr index 639cf2dd442b..e91fb3778a31 100644 --- a/tests/ui/crashes/ice-10148.stderr +++ b/tests/ui/crashes/ice-10148.stderr @@ -2,7 +2,7 @@ error: empty string literal in `println!` --> tests/ui/crashes/ice-10148.rs:8:5 | LL | println!(with_span!(""something "")); - | ^^^^^^^^^^^^^^^^^^^^-----------^^^^^ + | ^^^^^^^^^^^^^^^^^^^^---------------^ | | | help: remove the empty string | diff --git a/tests/ui/crashes/ice-7410.rs b/tests/ui/crashes/ice-7410.rs index 71f00fb9aede..7b39f7ffc01a 100644 --- a/tests/ui/crashes/ice-7410.rs +++ b/tests/ui/crashes/ice-7410.rs @@ -1,6 +1,6 @@ //@ check-pass //@compile-flags: -Clink-arg=-nostartfiles -//@ignore-target: apple windows +//@ignore-target: windows #![crate_type = "lib"] #![no_std] diff --git a/tests/ui/def_id_nocore.rs b/tests/ui/def_id_nocore.rs index 5c13d8622767..6aa023a8d450 100644 --- a/tests/ui/def_id_nocore.rs +++ b/tests/ui/def_id_nocore.rs @@ -1,5 +1,3 @@ -//@ignore-target: apple - #![feature(no_core, lang_items)] #![no_core] #![allow(clippy::missing_safety_doc)] diff --git a/tests/ui/def_id_nocore.stderr b/tests/ui/def_id_nocore.stderr index 175dd0754081..bf022fb56a36 100644 --- a/tests/ui/def_id_nocore.stderr +++ b/tests/ui/def_id_nocore.stderr @@ -1,5 +1,5 @@ error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> tests/ui/def_id_nocore.rs:33:19 + --> tests/ui/def_id_nocore.rs:31:19 | LL | pub fn as_ref(self) -> &'static str { | ^^^^ diff --git a/tests/ui/empty_enum_variants_with_brackets.fixed b/tests/ui/empty_enum_variants_with_brackets.fixed index abdf6ca5cb61..caf34eaefab9 100644 --- a/tests/ui/empty_enum_variants_with_brackets.fixed +++ b/tests/ui/empty_enum_variants_with_brackets.fixed @@ -1,5 +1,6 @@ #![warn(clippy::empty_enum_variants_with_brackets)] #![allow(dead_code)] +#![feature(more_qualified_paths)] pub enum PublicTestEnum { NonEmptyBraces { x: i32, y: i32 }, // No error @@ -102,4 +103,62 @@ pub enum PubFoo { Variant3(), } +fn issue16157() { + enum E { + V, + //~^ empty_enum_variants_with_brackets + } + + let E::V = E::V; + + ::V = E::V; + ::V = E::V; +} + +fn variant_with_braces() { + enum E { + V, + //~^ empty_enum_variants_with_brackets + } + E::V = E::V; + E::V = E::V; + ::V = ::V; + + enum F { + U, + //~^ empty_enum_variants_with_brackets + } + F::U = F::U; + ::U = F::U; +} + +fn variant_with_comments_and_cfg() { + enum E { + V( + // This is a comment + ), + } + E::V() = E::V(); + + enum F { + U { + // This is a comment + }, + } + F::U {} = F::U {}; + + enum G { + V(#[cfg(target_os = "cuda")] String), + } + G::V() = G::V(); + + enum H { + U { + #[cfg(target_os = "cuda")] + value: String, + }, + } + H::U {} = H::U {}; +} + fn main() {} diff --git a/tests/ui/empty_enum_variants_with_brackets.rs b/tests/ui/empty_enum_variants_with_brackets.rs index 63a5a8e9143e..f7ab062edd1e 100644 --- a/tests/ui/empty_enum_variants_with_brackets.rs +++ b/tests/ui/empty_enum_variants_with_brackets.rs @@ -1,5 +1,6 @@ #![warn(clippy::empty_enum_variants_with_brackets)] #![allow(dead_code)] +#![feature(more_qualified_paths)] pub enum PublicTestEnum { NonEmptyBraces { x: i32, y: i32 }, // No error @@ -102,4 +103,62 @@ pub enum PubFoo { Variant3(), } +fn issue16157() { + enum E { + V(), + //~^ empty_enum_variants_with_brackets + } + + let E::V() = E::V(); + + ::V() = E::V(); + ::V {} = E::V(); +} + +fn variant_with_braces() { + enum E { + V(), + //~^ empty_enum_variants_with_brackets + } + E::V() = E::V(); + E::V() = E::V {}; + ::V {} = ::V {}; + + enum F { + U {}, + //~^ empty_enum_variants_with_brackets + } + F::U {} = F::U {}; + ::U {} = F::U {}; +} + +fn variant_with_comments_and_cfg() { + enum E { + V( + // This is a comment + ), + } + E::V() = E::V(); + + enum F { + U { + // This is a comment + }, + } + F::U {} = F::U {}; + + enum G { + V(#[cfg(target_os = "cuda")] String), + } + G::V() = G::V(); + + enum H { + U { + #[cfg(target_os = "cuda")] + value: String, + }, + } + H::U {} = H::U {}; +} + fn main() {} diff --git a/tests/ui/empty_enum_variants_with_brackets.stderr b/tests/ui/empty_enum_variants_with_brackets.stderr index 7fe85e829a35..d50b07036a94 100644 --- a/tests/ui/empty_enum_variants_with_brackets.stderr +++ b/tests/ui/empty_enum_variants_with_brackets.stderr @@ -1,5 +1,5 @@ error: enum variant has empty brackets - --> tests/ui/empty_enum_variants_with_brackets.rs:7:16 + --> tests/ui/empty_enum_variants_with_brackets.rs:8:16 | LL | EmptyBraces {}, | ^^^ @@ -9,7 +9,7 @@ LL | EmptyBraces {}, = help: remove the brackets error: enum variant has empty brackets - --> tests/ui/empty_enum_variants_with_brackets.rs:15:16 + --> tests/ui/empty_enum_variants_with_brackets.rs:16:16 | LL | EmptyBraces {}, | ^^^ @@ -17,7 +17,7 @@ LL | EmptyBraces {}, = help: remove the brackets error: enum variant has empty brackets - --> tests/ui/empty_enum_variants_with_brackets.rs:17:21 + --> tests/ui/empty_enum_variants_with_brackets.rs:18:21 | LL | EmptyParentheses(), | ^^ @@ -25,7 +25,7 @@ LL | EmptyParentheses(), = help: remove the brackets error: enum variant has empty brackets - --> tests/ui/empty_enum_variants_with_brackets.rs:28:16 + --> tests/ui/empty_enum_variants_with_brackets.rs:29:16 | LL | Unknown(), | ^^ @@ -33,7 +33,7 @@ LL | Unknown(), = help: remove the brackets error: enum variant has empty brackets - --> tests/ui/empty_enum_variants_with_brackets.rs:47:16 + --> tests/ui/empty_enum_variants_with_brackets.rs:48:16 | LL | Unknown(), | ^^ @@ -41,7 +41,7 @@ LL | Unknown(), = help: remove the brackets error: enum variant has empty brackets - --> tests/ui/empty_enum_variants_with_brackets.rs:53:20 + --> tests/ui/empty_enum_variants_with_brackets.rs:54:20 | LL | Parentheses(), | ^^ @@ -56,7 +56,7 @@ LL ~ RedundantParenthesesFunctionCall::Parentheses; | error: enum variant has empty brackets - --> tests/ui/empty_enum_variants_with_brackets.rs:76:20 + --> tests/ui/empty_enum_variants_with_brackets.rs:77:20 | LL | Parentheses(), | ^^ @@ -71,12 +71,61 @@ LL ~ Parentheses, | error: enum variant has empty brackets - --> tests/ui/empty_enum_variants_with_brackets.rs:95:13 + --> tests/ui/empty_enum_variants_with_brackets.rs:96:13 | LL | Variant3(), | ^^ | = help: remove the brackets -error: aborting due to 8 previous errors +error: enum variant has empty brackets + --> tests/ui/empty_enum_variants_with_brackets.rs:108:10 + | +LL | V(), + | ^^ + | +help: remove the brackets + | +LL ~ V, +LL | +LL | } +LL | +LL ~ let E::V = E::V; +LL | +LL ~ ::V = E::V; +LL ~ ::V = E::V; + | + +error: enum variant has empty brackets + --> tests/ui/empty_enum_variants_with_brackets.rs:120:10 + | +LL | V(), + | ^^ + | +help: remove the brackets + | +LL ~ V, +LL | +LL | } +LL ~ E::V = E::V; +LL ~ E::V = E::V; +LL ~ ::V = ::V; + | + +error: enum variant has empty brackets + --> tests/ui/empty_enum_variants_with_brackets.rs:128:10 + | +LL | U {}, + | ^^^ + | +help: remove the brackets + | +LL ~ U, +LL | +LL | } +LL ~ F::U = F::U; +LL ~ ::U = F::U; + | + +error: aborting due to 11 previous errors diff --git a/tests/ui/empty_loop_no_std.rs b/tests/ui/empty_loop_no_std.rs index 6407bd678f9c..1ea96abbcd8b 100644 --- a/tests/ui/empty_loop_no_std.rs +++ b/tests/ui/empty_loop_no_std.rs @@ -1,6 +1,4 @@ //@compile-flags: -Clink-arg=-nostartfiles -//@ignore-target: apple - #![warn(clippy::empty_loop)] #![crate_type = "lib"] #![no_std] diff --git a/tests/ui/empty_loop_no_std.stderr b/tests/ui/empty_loop_no_std.stderr index f36fb9d9e3f2..e34b50ed1aef 100644 --- a/tests/ui/empty_loop_no_std.stderr +++ b/tests/ui/empty_loop_no_std.stderr @@ -1,5 +1,5 @@ error: empty `loop {}` wastes CPU cycles - --> tests/ui/empty_loop_no_std.rs:10:5 + --> tests/ui/empty_loop_no_std.rs:8:5 | LL | loop {} | ^^^^^^^ diff --git a/tests/ui/entry.fixed b/tests/ui/entry.fixed index 1e36ca4f1f09..75e173b9a84d 100644 --- a/tests/ui/entry.fixed +++ b/tests/ui/entry.fixed @@ -273,3 +273,13 @@ mod issue_16173 { } fn main() {} + +fn issue15781(m: &mut std::collections::HashMap, k: i32, v: i32) { + fn very_important_fn() {} + m.entry(k).or_insert_with(|| { + //~^ map_entry + #[cfg(test)] + very_important_fn(); + v + }); +} diff --git a/tests/ui/entry.rs b/tests/ui/entry.rs index b3da0ef3ffd6..7e3308c87356 100644 --- a/tests/ui/entry.rs +++ b/tests/ui/entry.rs @@ -279,3 +279,13 @@ mod issue_16173 { } fn main() {} + +fn issue15781(m: &mut std::collections::HashMap, k: i32, v: i32) { + fn very_important_fn() {} + if !m.contains_key(&k) { + //~^ map_entry + #[cfg(test)] + very_important_fn(); + m.insert(k, v); + } +} diff --git a/tests/ui/entry.stderr b/tests/ui/entry.stderr index 009b78d29073..4a29b3860e89 100644 --- a/tests/ui/entry.stderr +++ b/tests/ui/entry.stderr @@ -246,5 +246,26 @@ LL + e.insert(42); LL + } | -error: aborting due to 11 previous errors +error: usage of `contains_key` followed by `insert` on a `HashMap` + --> tests/ui/entry.rs:285:5 + | +LL | / if !m.contains_key(&k) { +LL | | +LL | | #[cfg(test)] +LL | | very_important_fn(); +LL | | m.insert(k, v); +LL | | } + | |_____^ + | +help: try + | +LL ~ m.entry(k).or_insert_with(|| { +LL + +LL + #[cfg(test)] +LL + very_important_fn(); +LL + v +LL + }); + | + +error: aborting due to 12 previous errors diff --git a/tests/ui/format_push_string.fixed b/tests/ui/format_push_string.fixed new file mode 100644 index 000000000000..f6396d9982a3 --- /dev/null +++ b/tests/ui/format_push_string.fixed @@ -0,0 +1,132 @@ +#![warn(clippy::format_push_string)] + +fn main() { + use std::fmt::Write; + + let mut string = String::new(); + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string + + let _ = write!(string, "{:?}", 5678); + //~^ format_push_string + + macro_rules! string { + () => { + String::new() + }; + } + let _ = write!(string!(), "{:?}", 5678); + //~^ format_push_string +} + +// TODO: recognize the already imported `fmt::Write`, and don't add a note suggesting to import it +// again +mod import_write { + mod push_str { + mod imported_anonymously { + fn main(string: &mut String) { + use std::fmt::Write as _; + + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string + } + } + + mod imported { + fn main(string: &mut String) { + use std::fmt::Write; + + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string + } + } + + mod imported_anonymously_in_module { + use std::fmt::Write as _; + + fn main(string: &mut String) { + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string + } + } + + mod imported_in_module { + use std::fmt::Write; + + fn main(string: &mut String) { + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string + } + } + + mod imported_and_imported { + fn foo(string: &mut String) { + use std::fmt::Write; + + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string + } + + fn bar(string: &mut String) { + use std::fmt::Write; + + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string + } + } + } + + mod add_assign { + mod imported_anonymously { + fn main(string: &mut String) { + use std::fmt::Write as _; + + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string + } + } + + mod imported { + fn main(string: &mut String) { + use std::fmt::Write; + + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string + } + } + + mod imported_anonymously_in_module { + use std::fmt::Write as _; + + fn main(string: &mut String) { + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string + } + } + + mod imported_in_module { + use std::fmt::Write; + + fn main(string: &mut String) { + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string + } + } + + mod imported_and_imported { + fn foo(string: &mut String) { + use std::fmt::Write; + + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string + } + + fn bar(string: &mut String) { + use std::fmt::Write; + + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string + } + } + } +} diff --git a/tests/ui/format_push_string.rs b/tests/ui/format_push_string.rs index 056ef59ff0e2..1ed0f5b3ac59 100644 --- a/tests/ui/format_push_string.rs +++ b/tests/ui/format_push_string.rs @@ -1,44 +1,132 @@ #![warn(clippy::format_push_string)] fn main() { + use std::fmt::Write; + let mut string = String::new(); string += &format!("{:?}", 1234); //~^ format_push_string string.push_str(&format!("{:?}", 5678)); //~^ format_push_string + + macro_rules! string { + () => { + String::new() + }; + } + string!().push_str(&format!("{:?}", 5678)); + //~^ format_push_string } -mod issue9493 { - pub fn u8vec_to_hex(vector: &Vec, upper: bool) -> String { - let mut hex = String::with_capacity(vector.len() * 2); - for byte in vector { - hex += &(if upper { +// TODO: recognize the already imported `fmt::Write`, and don't add a note suggesting to import it +// again +mod import_write { + mod push_str { + mod imported_anonymously { + fn main(string: &mut String) { + use std::fmt::Write as _; + + string.push_str(&format!("{:?}", 1234)); //~^ format_push_string - - format!("{byte:02X}") - } else { - format!("{byte:02x}") - }); + } + } + + mod imported { + fn main(string: &mut String) { + use std::fmt::Write; + + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + + mod imported_anonymously_in_module { + use std::fmt::Write as _; + + fn main(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + + mod imported_in_module { + use std::fmt::Write; + + fn main(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + + mod imported_and_imported { + fn foo(string: &mut String) { + use std::fmt::Write; + + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + + fn bar(string: &mut String) { + use std::fmt::Write; + + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } } - hex } - pub fn other_cases() { - let mut s = String::new(); - // if let - s += &(if let Some(_a) = Some(1234) { - //~^ format_push_string + mod add_assign { + mod imported_anonymously { + fn main(string: &mut String) { + use std::fmt::Write as _; - format!("{}", 1234) - } else { - format!("{}", 1234) - }); - // match - s += &(match Some(1234) { - //~^ format_push_string - Some(_) => format!("{}", 1234), - None => format!("{}", 1234), - }); + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + + mod imported { + fn main(string: &mut String) { + use std::fmt::Write; + + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + + mod imported_anonymously_in_module { + use std::fmt::Write as _; + + fn main(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + + mod imported_in_module { + use std::fmt::Write; + + fn main(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + + mod imported_and_imported { + fn foo(string: &mut String) { + use std::fmt::Write; + + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + + fn bar(string: &mut String) { + use std::fmt::Write; + + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } } } diff --git a/tests/ui/format_push_string.stderr b/tests/ui/format_push_string.stderr index bba2a8947c43..05e26fcbfc2b 100644 --- a/tests/ui/format_push_string.stderr +++ b/tests/ui/format_push_string.stderr @@ -1,60 +1,199 @@ error: `format!(..)` appended to existing `String` - --> tests/ui/format_push_string.rs:5:5 + --> tests/ui/format_push_string.rs:7:5 | LL | string += &format!("{:?}", 1234); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider using `write!` to avoid the extra allocation + = note: you may need to import the `std::fmt::Write` trait = note: `-D clippy::format-push-string` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::format_push_string)]` +help: consider using `write!` to avoid the extra allocation + | +LL - string += &format!("{:?}", 1234); +LL + let _ = write!(string, "{:?}", 1234); + | error: `format!(..)` appended to existing `String` - --> tests/ui/format_push_string.rs:8:5 + --> tests/ui/format_push_string.rs:10:5 | LL | string.push_str(&format!("{:?}", 5678)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider using `write!` to avoid the extra allocation + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 5678)); +LL + let _ = write!(string, "{:?}", 5678); + | error: `format!(..)` appended to existing `String` - --> tests/ui/format_push_string.rs:16:13 + --> tests/ui/format_push_string.rs:18:5 | -LL | / hex += &(if upper { -LL | | -LL | | -LL | | format!("{byte:02X}") -LL | | } else { -LL | | format!("{byte:02x}") -LL | | }); - | |______________^ +LL | string!().push_str(&format!("{:?}", 5678)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string!().push_str(&format!("{:?}", 5678)); +LL + let _ = write!(string!(), "{:?}", 5678); | - = help: consider using `write!` to avoid the extra allocation error: `format!(..)` appended to existing `String` - --> tests/ui/format_push_string.rs:30:9 + --> tests/ui/format_push_string.rs:30:17 | -LL | / s += &(if let Some(_a) = Some(1234) { -LL | | -LL | | -LL | | format!("{}", 1234) -LL | | } else { -LL | | format!("{}", 1234) -LL | | }); - | |__________^ +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); | - = help: consider using `write!` to avoid the extra allocation error: `format!(..)` appended to existing `String` - --> tests/ui/format_push_string.rs:38:9 + --> tests/ui/format_push_string.rs:39:17 | -LL | / s += &(match Some(1234) { -LL | | -LL | | Some(_) => format!("{}", 1234), -LL | | None => format!("{}", 1234), -LL | | }); - | |__________^ +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); | - = help: consider using `write!` to avoid the extra allocation -error: aborting due to 5 previous errors +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string.rs:48:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string.rs:57:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string.rs:66:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string.rs:73:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string.rs:84:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string.rs:93:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string.rs:102:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string.rs:111:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string.rs:120:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string.rs:127:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: aborting due to 15 previous errors diff --git a/tests/ui/format_push_string_no_core.rs b/tests/ui/format_push_string_no_core.rs new file mode 100644 index 000000000000..4bc45906fa78 --- /dev/null +++ b/tests/ui/format_push_string_no_core.rs @@ -0,0 +1,15 @@ +//@check-pass +#![warn(clippy::format_push_string)] +#![no_std] +#![feature(no_core)] +#![no_core] + +extern crate alloc; + +use alloc::format; +use alloc::string::String; + +fn foo(string: &mut String) { + // can't suggest even `core::fmt::Write` because of `#![no_core]` + string.push_str(&format!("{:?}", 1234)); +} diff --git a/tests/ui/format_push_string_no_std.fixed b/tests/ui/format_push_string_no_std.fixed new file mode 100644 index 000000000000..32d8659dcbd5 --- /dev/null +++ b/tests/ui/format_push_string_no_std.fixed @@ -0,0 +1,15 @@ +#![warn(clippy::format_push_string)] +#![no_std] + +extern crate alloc; + +use alloc::format; +use alloc::string::String; + +fn foo(string: &mut String) { + use core::fmt::Write; + + // TODO: recognize the already imported `fmt::Write`, and don't suggest importing it again + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string +} diff --git a/tests/ui/format_push_string_no_std.rs b/tests/ui/format_push_string_no_std.rs new file mode 100644 index 000000000000..a74189abe528 --- /dev/null +++ b/tests/ui/format_push_string_no_std.rs @@ -0,0 +1,15 @@ +#![warn(clippy::format_push_string)] +#![no_std] + +extern crate alloc; + +use alloc::format; +use alloc::string::String; + +fn foo(string: &mut String) { + use core::fmt::Write; + + // TODO: recognize the already imported `fmt::Write`, and don't suggest importing it again + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string +} diff --git a/tests/ui/format_push_string_no_std.stderr b/tests/ui/format_push_string_no_std.stderr new file mode 100644 index 000000000000..30fd42ac71b2 --- /dev/null +++ b/tests/ui/format_push_string_no_std.stderr @@ -0,0 +1,17 @@ +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_no_std.rs:13:5 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `core::fmt::Write` trait + = note: `-D clippy::format-push-string` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::format_push_string)]` +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/format_push_string_no_std_unfixable.rs b/tests/ui/format_push_string_no_std_unfixable.rs new file mode 100644 index 000000000000..f5ed5e435b5a --- /dev/null +++ b/tests/ui/format_push_string_no_std_unfixable.rs @@ -0,0 +1,13 @@ +//@no-rustfix +#![warn(clippy::format_push_string)] +#![no_std] + +extern crate alloc; + +use alloc::format; +use alloc::string::String; + +fn foo(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string +} diff --git a/tests/ui/format_push_string_no_std_unfixable.stderr b/tests/ui/format_push_string_no_std_unfixable.stderr new file mode 100644 index 000000000000..cc716c84efe2 --- /dev/null +++ b/tests/ui/format_push_string_no_std_unfixable.stderr @@ -0,0 +1,17 @@ +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_no_std_unfixable.rs:11:5 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `core::fmt::Write` trait + = note: `-D clippy::format-push-string` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::format_push_string)]` +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/format_push_string_unfixable.rs b/tests/ui/format_push_string_unfixable.rs new file mode 100644 index 000000000000..ff6c13fe4a49 --- /dev/null +++ b/tests/ui/format_push_string_unfixable.rs @@ -0,0 +1,144 @@ +//@no-rustfix +#![warn(clippy::format_push_string)] + +mod issue9493 { + pub fn u8vec_to_hex(vector: &Vec, upper: bool) -> String { + let mut hex = String::with_capacity(vector.len() * 2); + for byte in vector { + hex += &(if upper { + format!("{byte:02X}") + //~^ format_push_string + } else { + format!("{byte:02x}") + }); + } + hex + } + + pub fn other_cases() { + let mut s = String::new(); + // if let + s += &(if let Some(_a) = Some(1234) { + format!("{}", 1234) + //~^ format_push_string + } else { + format!("{}", 1234) + }); + // match + s += &(match Some(1234) { + Some(_) => format!("{}", 1234), + //~^ format_push_string + None => format!("{}", 1234), + }); + } +} + +mod import_write { + mod push_str { + // TODO: suggest importing `std::fmt::Write`; + mod not_imported { + fn main(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + + // TODO: suggest importing the first time, but not again + mod not_imported_and_not_imported { + fn foo(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + + fn bar(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + + // TODO: suggest importing the first time, but not again + mod not_imported_and_imported { + fn foo(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + + fn bar(string: &mut String) { + use std::fmt::Write; + + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + + // TODO: suggest importing, but only for `bar` + mod imported_and_not_imported { + fn foo(string: &mut String) { + use std::fmt::Write; + + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + + fn bar(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + } + + mod add_assign { + // TODO: suggest importing `std::fmt::Write`; + mod not_imported { + fn main(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + + // TODO: suggest importing the first time, but not again + mod not_imported_and_not_imported { + fn foo(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + + fn bar(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + + // TODO: suggest importing the first time, but not again + mod not_imported_and_imported { + fn foo(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + + fn bar(string: &mut String) { + use std::fmt::Write; + + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + + // TODO: suggest importing, but only for `bar` + mod imported_and_not_imported { + fn foo(string: &mut String) { + use std::fmt::Write; + + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + + fn bar(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + } +} + +fn main() {} diff --git a/tests/ui/format_push_string_unfixable.stderr b/tests/ui/format_push_string_unfixable.stderr new file mode 100644 index 000000000000..145e7fcc440d --- /dev/null +++ b/tests/ui/format_push_string_unfixable.stderr @@ -0,0 +1,233 @@ +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:8:13 + | +LL | / hex += &(if upper { +LL | | format!("{byte:02X}") + | | --------------------- `format!` used here +LL | | +LL | | } else { +LL | | format!("{byte:02x}") + | | --------------------- `format!` used here +LL | | }); + | |______________^ + | + = help: consider using `write!` to avoid the extra allocation + = note: you may need to import the `std::fmt::Write` trait + = note: `-D clippy::format-push-string` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::format_push_string)]` + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:21:9 + | +LL | / s += &(if let Some(_a) = Some(1234) { +LL | | format!("{}", 1234) + | | ------------------- `format!` used here +LL | | +LL | | } else { +LL | | format!("{}", 1234) + | | ------------------- `format!` used here +LL | | }); + | |__________^ + | + = help: consider using `write!` to avoid the extra allocation + = note: you may need to import the `std::fmt::Write` trait + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:28:9 + | +LL | / s += &(match Some(1234) { +LL | | Some(_) => format!("{}", 1234), + | | ------------------- `format!` used here +LL | | +LL | | None => format!("{}", 1234), + | | ------------------- `format!` used here +LL | | }); + | |__________^ + | + = help: consider using `write!` to avoid the extra allocation + = note: you may need to import the `std::fmt::Write` trait + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:41:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:49:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:54:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:62:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:69:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:79:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:84:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:94:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:102:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:107:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:115:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:122:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:132:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:137:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: aborting due to 17 previous errors + diff --git a/tests/ui/if_not_else.fixed b/tests/ui/if_not_else.fixed index 4e6f43e5671e..a29847f0cf97 100644 --- a/tests/ui/if_not_else.fixed +++ b/tests/ui/if_not_else.fixed @@ -76,3 +76,20 @@ fn with_annotations() { println!("foo is false"); } } + +fn issue15924() { + let x = 0; + if matches!(x, 0..10) { + println!(":("); + } else { + //~^ if_not_else + println!(":)"); + } + + if dbg!(x) == 1 { + println!(":("); + } else { + //~^ if_not_else + println!(":)"); + } +} diff --git a/tests/ui/if_not_else.rs b/tests/ui/if_not_else.rs index 6cd2e3bd63fe..4ae11d6ad90e 100644 --- a/tests/ui/if_not_else.rs +++ b/tests/ui/if_not_else.rs @@ -76,3 +76,20 @@ fn with_annotations() { println!("foo"); /* foo */ } } + +fn issue15924() { + let x = 0; + if !matches!(x, 0..10) { + //~^ if_not_else + println!(":)"); + } else { + println!(":("); + } + + if dbg!(x) != 1 { + //~^ if_not_else + println!(":)"); + } else { + println!(":("); + } +} diff --git a/tests/ui/if_not_else.stderr b/tests/ui/if_not_else.stderr index 824837bd52bb..0682bf80da55 100644 --- a/tests/ui/if_not_else.stderr +++ b/tests/ui/if_not_else.stderr @@ -147,5 +147,47 @@ LL + println!("foo is false"); LL + } | -error: aborting due to 6 previous errors +error: unnecessary boolean `not` operation + --> tests/ui/if_not_else.rs:82:5 + | +LL | / if !matches!(x, 0..10) { +LL | | +LL | | println!(":)"); +LL | | } else { +LL | | println!(":("); +LL | | } + | |_____^ + | +help: try + | +LL ~ if matches!(x, 0..10) { +LL + println!(":("); +LL + } else { +LL + +LL + println!(":)"); +LL + } + | + +error: unnecessary `!=` operation + --> tests/ui/if_not_else.rs:89:5 + | +LL | / if dbg!(x) != 1 { +LL | | +LL | | println!(":)"); +LL | | } else { +LL | | println!(":("); +LL | | } + | |_____^ + | +help: try + | +LL ~ if dbg!(x) == 1 { +LL + println!(":("); +LL + } else { +LL + +LL + println!(":)"); +LL + } + | + +error: aborting due to 8 previous errors diff --git a/tests/ui/if_then_some_else_none.fixed b/tests/ui/if_then_some_else_none.fixed index 7da9401a308f..ce122ac69b12 100644 --- a/tests/ui/if_then_some_else_none.fixed +++ b/tests/ui/if_then_some_else_none.fixed @@ -3,10 +3,20 @@ fn main() { // Should issue an error. - let _ = foo().then(|| { println!("true!"); "foo" }); + let _ = foo().then(|| { + //~^ if_then_some_else_none + + println!("true!"); + "foo" + }); // Should issue an error when macros are used. - let _ = matches!(true, true).then(|| { println!("true!"); matches!(true, false) }); + let _ = matches!(true, true).then(|| { + //~^ if_then_some_else_none + + println!("true!"); + matches!(true, false) + }); // Should issue an error. Binary expression `o < 32` should be parenthesized. let x = Some(5); @@ -71,7 +81,12 @@ fn _msrv_1_49() { #[clippy::msrv = "1.50"] fn _msrv_1_50() { - let _ = foo().then(|| { println!("true!"); 150 }); + let _ = foo().then(|| { + //~^ if_then_some_else_none + + println!("true!"); + 150 + }); } fn foo() -> bool { @@ -182,7 +197,10 @@ fn issue15005() { fn next(&mut self) -> Option { //~v if_then_some_else_none - (self.count < 5).then(|| { self.count += 1; self.count }) + (self.count < 5).then(|| { + self.count += 1; + self.count + }) } } } @@ -195,7 +213,10 @@ fn statements_from_macro() { }; } //~v if_then_some_else_none - let _ = true.then(|| { mac!(); 42 }); + let _ = true.then(|| { + mac!(); + 42 + }); } fn dont_lint_inside_macros() { @@ -218,3 +239,24 @@ mod issue15770 { Ok(()) } } + +mod issue16176 { + pub async fn foo() -> u32 { + todo!() + } + + pub async fn bar(cond: bool) -> Option { + if cond { Some(foo().await) } else { None } // OK + } +} + +fn issue16269() -> Option { + use std::cell::UnsafeCell; + + //~v if_then_some_else_none + (1 <= 3).then(|| { + let a = UnsafeCell::new(1); + // SAFETY: `bytes` bytes starting at `new_end` were just reserved. + unsafe { *a.get() } + }) +} diff --git a/tests/ui/if_then_some_else_none.rs b/tests/ui/if_then_some_else_none.rs index 02962f83ce8a..1d6c86d94492 100644 --- a/tests/ui/if_then_some_else_none.rs +++ b/tests/ui/if_then_some_else_none.rs @@ -274,3 +274,26 @@ mod issue15770 { Ok(()) } } + +mod issue16176 { + pub async fn foo() -> u32 { + todo!() + } + + pub async fn bar(cond: bool) -> Option { + if cond { Some(foo().await) } else { None } // OK + } +} + +fn issue16269() -> Option { + use std::cell::UnsafeCell; + + //~v if_then_some_else_none + if 1 <= 3 { + let a = UnsafeCell::new(1); + // SAFETY: `bytes` bytes starting at `new_end` were just reserved. + Some(unsafe { *a.get() }) + } else { + None + } +} diff --git a/tests/ui/if_then_some_else_none.stderr b/tests/ui/if_then_some_else_none.stderr index 58651a055942..eff5f8c82dcb 100644 --- a/tests/ui/if_then_some_else_none.stderr +++ b/tests/ui/if_then_some_else_none.stderr @@ -9,10 +9,19 @@ LL | | println!("true!"); ... | LL | | None LL | | }; - | |_____^ help: try: `foo().then(|| { println!("true!"); "foo" })` + | |_____^ | = note: `-D clippy::if-then-some-else-none` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::if_then_some_else_none)]` +help: try + | +LL ~ let _ = foo().then(|| { +LL + +LL + +LL + println!("true!"); +LL + "foo" +LL ~ }); + | error: this could be simplified with `bool::then` --> tests/ui/if_then_some_else_none.rs:16:13 @@ -25,7 +34,17 @@ LL | | println!("true!"); ... | LL | | None LL | | }; - | |_____^ help: try: `matches!(true, true).then(|| { println!("true!"); matches!(true, false) })` + | |_____^ + | +help: try + | +LL ~ let _ = matches!(true, true).then(|| { +LL + +LL + +LL + println!("true!"); +LL + matches!(true, false) +LL ~ }); + | error: this could be simplified with `bool::then_some` --> tests/ui/if_then_some_else_none.rs:27:28 @@ -50,7 +69,17 @@ LL | | println!("true!"); ... | LL | | None LL | | }; - | |_____^ help: try: `foo().then(|| { println!("true!"); 150 })` + | |_____^ + | +help: try + | +LL ~ let _ = foo().then(|| { +LL + +LL + +LL + println!("true!"); +LL + 150 +LL ~ }); + | error: this could be simplified with `bool::then` --> tests/ui/if_then_some_else_none.rs:138:5 @@ -125,7 +154,15 @@ LL | | Some(self.count) LL | | } else { LL | | None LL | | } - | |_____________^ help: try: `(self.count < 5).then(|| { self.count += 1; self.count })` + | |_____________^ + | +help: try + | +LL ~ (self.count < 5).then(|| { +LL + self.count += 1; +LL + self.count +LL + }) + | error: this could be simplified with `bool::then` --> tests/ui/if_then_some_else_none.rs:249:13 @@ -137,7 +174,36 @@ LL | | Some(42) LL | | } else { LL | | None LL | | }; - | |_____^ help: try: `true.then(|| { mac!(); 42 })` + | |_____^ + | +help: try + | +LL ~ let _ = true.then(|| { +LL + mac!(); +LL + 42 +LL ~ }); + | -error: aborting due to 13 previous errors +error: this could be simplified with `bool::then` + --> tests/ui/if_then_some_else_none.rs:292:5 + | +LL | / if 1 <= 3 { +LL | | let a = UnsafeCell::new(1); +LL | | // SAFETY: `bytes` bytes starting at `new_end` were just reserved. +LL | | Some(unsafe { *a.get() }) +LL | | } else { +LL | | None +LL | | } + | |_____^ + | +help: try + | +LL ~ (1 <= 3).then(|| { +LL + let a = UnsafeCell::new(1); +LL + // SAFETY: `bytes` bytes starting at `new_end` were just reserved. +LL + unsafe { *a.get() } +LL + }) + | + +error: aborting due to 14 previous errors diff --git a/tests/ui/manual_instant_elapsed.fixed b/tests/ui/manual_instant_elapsed.fixed index a04c601e08c1..2fa5702f8a04 100644 --- a/tests/ui/manual_instant_elapsed.fixed +++ b/tests/ui/manual_instant_elapsed.fixed @@ -28,3 +28,19 @@ fn main() { // //~^^ manual_instant_elapsed } + +fn issue16236() { + use std::ops::Sub as _; + macro_rules! deref { + ($e:expr) => { + *$e + }; + } + + let start = &Instant::now(); + let _ = deref!(start).elapsed(); + //~^ manual_instant_elapsed + + deref!(start).elapsed(); + //~^ manual_instant_elapsed +} diff --git a/tests/ui/manual_instant_elapsed.rs b/tests/ui/manual_instant_elapsed.rs index 7c67f6acf85d..e7a0e6499e74 100644 --- a/tests/ui/manual_instant_elapsed.rs +++ b/tests/ui/manual_instant_elapsed.rs @@ -28,3 +28,19 @@ fn main() { // //~^^ manual_instant_elapsed } + +fn issue16236() { + use std::ops::Sub as _; + macro_rules! deref { + ($e:expr) => { + *$e + }; + } + + let start = &Instant::now(); + let _ = Instant::now().sub(deref!(start)); + //~^ manual_instant_elapsed + + Instant::now() - deref!(start); + //~^ manual_instant_elapsed +} diff --git a/tests/ui/manual_instant_elapsed.stderr b/tests/ui/manual_instant_elapsed.stderr index e84f3126f707..e42ac5739a29 100644 --- a/tests/ui/manual_instant_elapsed.stderr +++ b/tests/ui/manual_instant_elapsed.stderr @@ -13,5 +13,17 @@ error: manual implementation of `Instant::elapsed` LL | Instant::now() - *ref_to_instant; // to ensure parens are added correctly | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*ref_to_instant).elapsed()` -error: aborting due to 2 previous errors +error: manual implementation of `Instant::elapsed` + --> tests/ui/manual_instant_elapsed.rs:41:13 + | +LL | let _ = Instant::now().sub(deref!(start)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `deref!(start).elapsed()` + +error: manual implementation of `Instant::elapsed` + --> tests/ui/manual_instant_elapsed.rs:44:5 + | +LL | Instant::now() - deref!(start); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `deref!(start).elapsed()` + +error: aborting due to 4 previous errors diff --git a/tests/ui/map_unwrap_or.stderr b/tests/ui/map_unwrap_or.stderr index b0b02f3f8d6b..df0207c420e6 100644 --- a/tests/ui/map_unwrap_or.stderr +++ b/tests/ui/map_unwrap_or.stderr @@ -127,6 +127,14 @@ LL | | x + 1 LL | | } LL | | ).unwrap_or_else(|| 0); | |__________________________^ + | +help: try + | +LL ~ let _ = opt.map_or_else(|| 0, |x| { +LL + +LL + x + 1 +LL ~ }); + | error: called `map().unwrap_or_else()` on an `Option` value --> tests/ui/map_unwrap_or.rs:63:13 @@ -138,6 +146,12 @@ LL | | .unwrap_or_else(|| LL | | 0 LL | | ); | |_________^ + | +help: try + | +LL ~ let _ = opt.map_or_else(|| +LL ~ 0, |x| x + 1); + | error: called `map().unwrap_or(false)` on an `Option` value --> tests/ui/map_unwrap_or.rs:70:13 @@ -161,6 +175,14 @@ LL | | x + 1 LL | | } LL | | ).unwrap_or_else(|_e| 0); | |____________________________^ + | +help: try + | +LL ~ let _ = res.map_or_else(|_e| 0, |x| { +LL + +LL + x + 1 +LL ~ }); + | error: called `map().unwrap_or_else()` on a `Result` value --> tests/ui/map_unwrap_or.rs:86:13 @@ -172,6 +194,13 @@ LL | | .unwrap_or_else(|_e| { LL | | 0 LL | | }); | |__________^ + | +help: try + | +LL ~ let _ = res.map_or_else(|_e| { +LL + 0 +LL ~ }, |x| x + 1); + | error: called `map().unwrap_or_else()` on a `Result` value --> tests/ui/map_unwrap_or.rs:111:13 diff --git a/tests/ui/match_like_matches_macro.fixed b/tests/ui/match_like_matches_macro.fixed index dad59c1ce6e4..045ee32bd8bb 100644 --- a/tests/ui/match_like_matches_macro.fixed +++ b/tests/ui/match_like_matches_macro.fixed @@ -1,6 +1,7 @@ #![warn(clippy::match_like_matches_macro)] #![allow( unreachable_patterns, + irrefutable_let_patterns, clippy::equatable_if_let, clippy::needless_borrowed_reference, clippy::redundant_guards @@ -230,3 +231,24 @@ fn issue15841(opt: Option>>, value: i32) { let _ = matches!(opt, Some(first) if (if let Some(second) = first { true } else { todo!() })); //~^^^^ match_like_matches_macro } + +fn issue16015() -> bool { + use std::any::{TypeId, type_name}; + pub struct GetTypeId(T); + + impl GetTypeId { + pub const VALUE: TypeId = TypeId::of::(); + } + + macro_rules! typeid { + ($t:ty) => { + GetTypeId::<$t>::VALUE + }; + } + + matches!(typeid!(T), _); + //~^^^^ match_like_matches_macro + + matches!(typeid!(U), _) + //~^ match_like_matches_macro +} diff --git a/tests/ui/match_like_matches_macro.rs b/tests/ui/match_like_matches_macro.rs index 94bc6433e5cb..231e1ae98f86 100644 --- a/tests/ui/match_like_matches_macro.rs +++ b/tests/ui/match_like_matches_macro.rs @@ -1,6 +1,7 @@ #![warn(clippy::match_like_matches_macro)] #![allow( unreachable_patterns, + irrefutable_let_patterns, clippy::equatable_if_let, clippy::needless_borrowed_reference, clippy::redundant_guards @@ -277,3 +278,27 @@ fn issue15841(opt: Option>>, value: i32) { }; //~^^^^ match_like_matches_macro } + +fn issue16015() -> bool { + use std::any::{TypeId, type_name}; + pub struct GetTypeId(T); + + impl GetTypeId { + pub const VALUE: TypeId = TypeId::of::(); + } + + macro_rules! typeid { + ($t:ty) => { + GetTypeId::<$t>::VALUE + }; + } + + match typeid!(T) { + _ => true, + _ => false, + }; + //~^^^^ match_like_matches_macro + + if let _ = typeid!(U) { true } else { false } + //~^ match_like_matches_macro +} diff --git a/tests/ui/match_like_matches_macro.stderr b/tests/ui/match_like_matches_macro.stderr index a8e352461dbb..bc3e3584938e 100644 --- a/tests/ui/match_like_matches_macro.stderr +++ b/tests/ui/match_like_matches_macro.stderr @@ -1,5 +1,5 @@ error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:13:14 + --> tests/ui/match_like_matches_macro.rs:14:14 | LL | let _y = match x { | ______________^ @@ -20,7 +20,7 @@ LL + let _y = matches!(x, Some(0)); | error: redundant pattern matching, consider using `is_some()` - --> tests/ui/match_like_matches_macro.rs:20:14 + --> tests/ui/match_like_matches_macro.rs:21:14 | LL | let _w = match x { | ______________^ @@ -33,7 +33,7 @@ LL | | }; = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/match_like_matches_macro.rs:27:14 + --> tests/ui/match_like_matches_macro.rs:28:14 | LL | let _z = match x { | ______________^ @@ -43,7 +43,7 @@ LL | | }; | |_____^ help: try: `x.is_none()` error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:34:15 + --> tests/ui/match_like_matches_macro.rs:35:15 | LL | let _zz = match x { | _______________^ @@ -62,7 +62,7 @@ LL + let _zz = !matches!(x, Some(r) if r == 0); | error: `if let .. else` expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:41:16 + --> tests/ui/match_like_matches_macro.rs:42:16 | LL | let _zzz = if let Some(5) = x { true } else { false }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -74,7 +74,7 @@ LL + let _zzz = matches!(x, Some(5)); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:66:20 + --> tests/ui/match_like_matches_macro.rs:67:20 | LL | let _ans = match x { | ____________________^ @@ -95,7 +95,7 @@ LL + let _ans = matches!(x, E::A(_) | E::B(_)); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:77:20 + --> tests/ui/match_like_matches_macro.rs:78:20 | LL | let _ans = match x { | ____________________^ @@ -119,7 +119,7 @@ LL + let _ans = matches!(x, E::A(_) | E::B(_)); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:88:20 + --> tests/ui/match_like_matches_macro.rs:89:20 | LL | let _ans = match x { | ____________________^ @@ -140,7 +140,7 @@ LL + let _ans = !matches!(x, E::B(_) | E::C); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:149:18 + --> tests/ui/match_like_matches_macro.rs:150:18 | LL | let _z = match &z { | __________________^ @@ -159,7 +159,7 @@ LL + let _z = matches!(z, Some(3)); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:159:18 + --> tests/ui/match_like_matches_macro.rs:160:18 | LL | let _z = match &z { | __________________^ @@ -178,7 +178,7 @@ LL + let _z = matches!(&z, Some(3)); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:177:21 + --> tests/ui/match_like_matches_macro.rs:178:21 | LL | let _ = match &z { | _____________________^ @@ -197,7 +197,7 @@ LL + let _ = matches!(&z, AnEnum::X); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:192:20 + --> tests/ui/match_like_matches_macro.rs:193:20 | LL | let _res = match &val { | ____________________^ @@ -216,7 +216,7 @@ LL + let _res = matches!(&val, &Some(ref _a)); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:205:20 + --> tests/ui/match_like_matches_macro.rs:206:20 | LL | let _res = match &val { | ____________________^ @@ -235,7 +235,7 @@ LL + let _res = matches!(&val, &Some(ref _a)); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:264:14 + --> tests/ui/match_like_matches_macro.rs:265:14 | LL | let _y = match Some(5) { | ______________^ @@ -254,7 +254,7 @@ LL + let _y = matches!(Some(5), Some(0)); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:274:13 + --> tests/ui/match_like_matches_macro.rs:275:13 | LL | let _ = match opt { | _____________^ @@ -272,5 +272,35 @@ LL - }; LL + let _ = matches!(opt, Some(first) if (if let Some(second) = first { true } else { todo!() })); | -error: aborting due to 15 previous errors +error: match expression looks like `matches!` macro + --> tests/ui/match_like_matches_macro.rs:296:5 + | +LL | / match typeid!(T) { +LL | | _ => true, +LL | | _ => false, +LL | | }; + | |_____^ + | +help: use `matches!` directly + | +LL - match typeid!(T) { +LL - _ => true, +LL - _ => false, +LL - }; +LL + matches!(typeid!(T), _); + | + +error: `if let .. else` expression looks like `matches!` macro + --> tests/ui/match_like_matches_macro.rs:302:5 + | +LL | if let _ = typeid!(U) { true } else { false } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `matches!` directly + | +LL - if let _ = typeid!(U) { true } else { false } +LL + matches!(typeid!(U), _) + | + +error: aborting due to 17 previous errors diff --git a/tests/ui/multiple_unsafe_ops_per_block.rs b/tests/ui/multiple_unsafe_ops_per_block.rs index c1512ba3e269..0ff881472cbb 100644 --- a/tests/ui/multiple_unsafe_ops_per_block.rs +++ b/tests/ui/multiple_unsafe_ops_per_block.rs @@ -312,4 +312,137 @@ fn check_closures() { } } +fn issue16116() { + unsafe fn foo() -> u32 { + 0 + } + + // Do not lint even though `format!` expansion + // contains unsafe calls. + unsafe { + let _ = format!("{}", foo()); + } + + unsafe { + //~^ multiple_unsafe_ops_per_block + let _ = format!("{}", foo()); + let _ = format!("{}", foo()); + } + + // Do not lint: only one `assert!()` argument is unsafe + unsafe { + assert_eq!(foo(), 0, "{}", 1 + 2); + } + + // Each argument of a macro call may count as an unsafe operation. + unsafe { + //~^ multiple_unsafe_ops_per_block + assert_eq!(foo(), 0, "{}", foo()); // One unsafe operation + } + + macro_rules! twice { + ($e:expr) => {{ + $e; + $e; + }}; + } + + // Do not lint, a repeated argument used twice by a macro counts + // as at most one unsafe operation. + unsafe { + twice!(foo()); + } + + unsafe { + //~^ multiple_unsafe_ops_per_block + twice!(foo()); + twice!(foo()); + } + + unsafe { + //~^ multiple_unsafe_ops_per_block + assert_eq!(foo(), 0, "{}", 1 + 2); + assert_eq!(foo(), 0, "{}", 1 + 2); + } + + macro_rules! unsafe_twice { + ($e:expr) => { + unsafe { + $e; + $e; + } + }; + }; + + // A macro whose expansion contains unsafe blocks will not + // check inside the blocks. + unsafe { + unsafe_twice!(foo()); + } + + macro_rules! double_non_arg_unsafe { + () => {{ + _ = str::from_utf8_unchecked(&[]); + _ = str::from_utf8_unchecked(&[]); + }}; + } + + // Do not lint: each unsafe expression contained in the + // macro expansion will count towards the macro call. + unsafe { + double_non_arg_unsafe!(); + } + + unsafe { + //~^ multiple_unsafe_ops_per_block + double_non_arg_unsafe!(); + double_non_arg_unsafe!(); + } + + // Do not lint: the inner macro call counts as one unsafe op. + unsafe { + assert_eq!(double_non_arg_unsafe!(), ()); + } + + unsafe { + //~^ multiple_unsafe_ops_per_block + assert_eq!(double_non_arg_unsafe!(), ()); + assert_eq!(double_non_arg_unsafe!(), ()); + } + + unsafe { + //~^ multiple_unsafe_ops_per_block + assert_eq!((double_non_arg_unsafe!(), double_non_arg_unsafe!()), ((), ())); + } + + macro_rules! unsafe_with_arg { + ($e:expr) => {{ + _ = str::from_utf8_unchecked(&[]); + $e; + }}; + } + + // A confusing situation: the macro call counts towards two unsafe calls, + // one coming from inside the macro itself, and one coming from its argument. + // The error message may seem a bit strange as both the macro call and its + // argument will be marked as counting as unsafe ops, but a short investigation + // in those rare situations should sort it out easily. + unsafe { + //~^ multiple_unsafe_ops_per_block + unsafe_with_arg!(foo()); + } + + macro_rules! ignore { + ($e: expr) => {}; + } + + // Another surprising case is when the macro argument is not + // used in the expansion, but in this case we won't see the + // unsafe operation at all. + unsafe { + ignore!(foo()); + ignore!(foo()); + } +} + fn main() {} diff --git a/tests/ui/multiple_unsafe_ops_per_block.stderr b/tests/ui/multiple_unsafe_ops_per_block.stderr index 63f7742b734b..185225bd28c8 100644 --- a/tests/ui/multiple_unsafe_ops_per_block.stderr +++ b/tests/ui/multiple_unsafe_ops_per_block.stderr @@ -31,16 +31,16 @@ LL | | *raw_ptr(); LL | | } | |_____^ | -note: union field access occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:50:14 - | -LL | drop(u.u); - | ^^^ note: raw pointer dereference occurs here --> tests/ui/multiple_unsafe_ops_per_block.rs:51:9 | LL | *raw_ptr(); | ^^^^^^^^^^ +note: union field access occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:50:14 + | +LL | drop(u.u); + | ^^^ error: this `unsafe` block contains 3 unsafe operations, expected only one --> tests/ui/multiple_unsafe_ops_per_block.rs:56:5 @@ -58,16 +58,16 @@ note: inline assembly used here | LL | asm!("nop"); | ^^^^^^^^^^^ -note: unsafe method call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:59:9 - | -LL | sample.not_very_safe(); - | ^^^^^^^^^^^^^^^^^^^^^^ note: modification of a mutable static occurs here --> tests/ui/multiple_unsafe_ops_per_block.rs:60:9 | LL | STATIC = 0; | ^^^^^^^^^^ +note: unsafe method call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:59:9 + | +LL | sample.not_very_safe(); + | ^^^^^^^^^^^^^^^^^^^^^^ error: this `unsafe` block contains 6 unsafe operations, expected only one --> tests/ui/multiple_unsafe_ops_per_block.rs:66:5 @@ -81,36 +81,36 @@ LL | | asm!("nop"); LL | | } | |_____^ | -note: union field access occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:68:14 - | -LL | drop(u.u); - | ^^^ note: access of a mutable static occurs here --> tests/ui/multiple_unsafe_ops_per_block.rs:69:14 | LL | drop(STATIC); | ^^^^^^ -note: unsafe method call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:70:9 - | -LL | sample.not_very_safe(); - | ^^^^^^^^^^^^^^^^^^^^^^ -note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:71:9 - | -LL | not_very_safe(); - | ^^^^^^^^^^^^^^^ -note: raw pointer dereference occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:72:9 - | -LL | *raw_ptr(); - | ^^^^^^^^^^ note: inline assembly used here --> tests/ui/multiple_unsafe_ops_per_block.rs:73:9 | LL | asm!("nop"); | ^^^^^^^^^^^ +note: raw pointer dereference occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:72:9 + | +LL | *raw_ptr(); + | ^^^^^^^^^^ +note: union field access occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:68:14 + | +LL | drop(u.u); + | ^^^ +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:71:9 + | +LL | not_very_safe(); + | ^^^^^^^^^^^^^^^ +note: unsafe method call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:70:9 + | +LL | sample.not_very_safe(); + | ^^^^^^^^^^^^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one --> tests/ui/multiple_unsafe_ops_per_block.rs:109:5 @@ -139,16 +139,16 @@ error: this `unsafe` block contains 2 unsafe operations, expected only one LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:118:18 - | -LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: raw pointer dereference occurs here --> tests/ui/multiple_unsafe_ops_per_block.rs:118:43 | LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^ +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:118:18 + | +LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one --> tests/ui/multiple_unsafe_ops_per_block.rs:139:9 @@ -224,16 +224,16 @@ LL | | foo().await; LL | | } | |_____^ | -note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:194:9 - | -LL | not_very_safe(); - | ^^^^^^^^^^^^^^^ note: modification of a mutable static occurs here --> tests/ui/multiple_unsafe_ops_per_block.rs:195:9 | LL | STATIC += 1; | ^^^^^^^^^^^ +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:194:9 + | +LL | not_very_safe(); + | ^^^^^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one --> tests/ui/multiple_unsafe_ops_per_block.rs:207:5 @@ -265,16 +265,16 @@ LL | | Some(foo_unchecked()).unwrap_unchecked().await; LL | | } | |_____^ | -note: unsafe method call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:216:9 - | -LL | Some(foo_unchecked()).unwrap_unchecked().await; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: unsafe function call occurs here --> tests/ui/multiple_unsafe_ops_per_block.rs:216:14 | LL | Some(foo_unchecked()).unwrap_unchecked().await; | ^^^^^^^^^^^^^^^ +note: unsafe method call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:216:9 + | +LL | Some(foo_unchecked()).unwrap_unchecked().await; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one --> tests/ui/multiple_unsafe_ops_per_block.rs:236:5 @@ -359,5 +359,170 @@ note: unsafe function call occurs here LL | apply(|| f(0)); | ^^^^ -error: aborting due to 16 previous errors +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:326:5 + | +LL | / unsafe { +LL | | +LL | | let _ = format!("{}", foo()); +LL | | let _ = format!("{}", foo()); +LL | | } + | |_____^ + | +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:328:31 + | +LL | let _ = format!("{}", foo()); + | ^^^^^ +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:329:31 + | +LL | let _ = format!("{}", foo()); + | ^^^^^ + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:338:5 + | +LL | / unsafe { +LL | | +LL | | assert_eq!(foo(), 0, "{}", foo()); // One unsafe operation +LL | | } + | |_____^ + | +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:340:20 + | +LL | assert_eq!(foo(), 0, "{}", foo()); // One unsafe operation + | ^^^^^ +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:340:36 + | +LL | assert_eq!(foo(), 0, "{}", foo()); // One unsafe operation + | ^^^^^ + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:356:5 + | +LL | / unsafe { +LL | | +LL | | twice!(foo()); +LL | | twice!(foo()); +LL | | } + | |_____^ + | +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:358:16 + | +LL | twice!(foo()); + | ^^^^^ +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:359:16 + | +LL | twice!(foo()); + | ^^^^^ + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:362:5 + | +LL | / unsafe { +LL | | +LL | | assert_eq!(foo(), 0, "{}", 1 + 2); +LL | | assert_eq!(foo(), 0, "{}", 1 + 2); +LL | | } + | |_____^ + | +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:364:20 + | +LL | assert_eq!(foo(), 0, "{}", 1 + 2); + | ^^^^^ +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:365:20 + | +LL | assert_eq!(foo(), 0, "{}", 1 + 2); + | ^^^^^ + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:396:5 + | +LL | / unsafe { +LL | | +LL | | double_non_arg_unsafe!(); +LL | | double_non_arg_unsafe!(); +LL | | } + | |_____^ + | +note: this macro call expands into one or more unsafe operations + --> tests/ui/multiple_unsafe_ops_per_block.rs:398:9 + | +LL | double_non_arg_unsafe!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ +note: this macro call expands into one or more unsafe operations + --> tests/ui/multiple_unsafe_ops_per_block.rs:399:9 + | +LL | double_non_arg_unsafe!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:407:5 + | +LL | / unsafe { +LL | | +LL | | assert_eq!(double_non_arg_unsafe!(), ()); +LL | | assert_eq!(double_non_arg_unsafe!(), ()); +LL | | } + | |_____^ + | +note: this macro call expands into one or more unsafe operations + --> tests/ui/multiple_unsafe_ops_per_block.rs:409:20 + | +LL | assert_eq!(double_non_arg_unsafe!(), ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ +note: this macro call expands into one or more unsafe operations + --> tests/ui/multiple_unsafe_ops_per_block.rs:410:20 + | +LL | assert_eq!(double_non_arg_unsafe!(), ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:413:5 + | +LL | / unsafe { +LL | | +LL | | assert_eq!((double_non_arg_unsafe!(), double_non_arg_unsafe!()), ((), ())); +LL | | } + | |_____^ + | +note: this macro call expands into one or more unsafe operations + --> tests/ui/multiple_unsafe_ops_per_block.rs:415:21 + | +LL | assert_eq!((double_non_arg_unsafe!(), double_non_arg_unsafe!()), ((), ())); + | ^^^^^^^^^^^^^^^^^^^^^^^^ +note: this macro call expands into one or more unsafe operations + --> tests/ui/multiple_unsafe_ops_per_block.rs:415:47 + | +LL | assert_eq!((double_non_arg_unsafe!(), double_non_arg_unsafe!()), ((), ())); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:430:5 + | +LL | / unsafe { +LL | | +LL | | unsafe_with_arg!(foo()); +LL | | } + | |_____^ + | +note: this macro call expands into one or more unsafe operations + --> tests/ui/multiple_unsafe_ops_per_block.rs:432:9 + | +LL | unsafe_with_arg!(foo()); + | ^^^^^^^^^^^^^^^^^^^^^^^ +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:432:26 + | +LL | unsafe_with_arg!(foo()); + | ^^^^^ + +error: aborting due to 24 previous errors diff --git a/tests/ui/needless_collect.fixed b/tests/ui/needless_collect.fixed index ba1451bf9704..99027e79b664 100644 --- a/tests/ui/needless_collect.fixed +++ b/tests/ui/needless_collect.fixed @@ -214,3 +214,8 @@ mod issue8055_regression { .len(); } } + +fn issue16270() { + // Do not lint, `..` implements `Index` but is not `usize` + _ = &(1..3).collect::>()[..]; +} diff --git a/tests/ui/needless_collect.rs b/tests/ui/needless_collect.rs index e054cd01e6f5..683cc49c9af3 100644 --- a/tests/ui/needless_collect.rs +++ b/tests/ui/needless_collect.rs @@ -214,3 +214,8 @@ mod issue8055_regression { .len(); } } + +fn issue16270() { + // Do not lint, `..` implements `Index` but is not `usize` + _ = &(1..3).collect::>()[..]; +} diff --git a/tests/ui/needless_pass_by_ref_mut.stderr b/tests/ui/needless_pass_by_ref_mut.stderr index 94d98f0e9b12..c427f4c3e42c 100644 --- a/tests/ui/needless_pass_by_ref_mut.stderr +++ b/tests/ui/needless_pass_by_ref_mut.stderr @@ -1,213 +1,281 @@ -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:12:11 | LL | fn foo(s: &mut Vec, b: &u32, x: &mut u32) { - | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` + | ^----^^^^^^^^ + | | + | help: consider removing this `mut` | = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:38:12 | LL | fn foo6(s: &mut Vec) { - | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` + | ^----^^^^^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:49:12 | LL | fn bar(&mut self) {} - | ^^^^^^^^^ help: consider changing to: `&self` + | ^----^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:52:29 | LL | fn mushroom(&self, vec: &mut Vec) -> usize { - | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` + | ^----^^^^^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:130:16 | LL | async fn a1(x: &mut i32) { - | ^^^^^^^^ help: consider changing to: `&i32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:135:16 | LL | async fn a2(x: &mut i32, y: String) { - | ^^^^^^^^ help: consider changing to: `&i32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:140:16 | LL | async fn a3(x: &mut i32, y: String, z: String) { - | ^^^^^^^^ help: consider changing to: `&i32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:145:16 | LL | async fn a4(x: &mut i32, y: i32) { - | ^^^^^^^^ help: consider changing to: `&i32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:150:24 | LL | async fn a5(x: i32, y: &mut i32) { - | ^^^^^^^^ help: consider changing to: `&i32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:155:24 | LL | async fn a6(x: i32, y: &mut i32) { - | ^^^^^^^^ help: consider changing to: `&i32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:160:32 | LL | async fn a7(x: i32, y: i32, z: &mut i32) { - | ^^^^^^^^ help: consider changing to: `&i32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:165:24 | LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) { - | ^^^^^^^^ help: consider changing to: `&i32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:165:45 | LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) { - | ^^^^^^^^ help: consider changing to: `&i32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:201:16 | LL | fn cfg_warn(s: &mut u32) {} - | ^^^^^^^^ help: consider changing to: `&u32` + | ^----^^^ + | | + | help: consider removing this `mut` | = note: this is cfg-gated and may require further changes -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:206:20 | LL | fn cfg_warn(s: &mut u32) {} - | ^^^^^^^^ help: consider changing to: `&u32` + | ^----^^^ + | | + | help: consider removing this `mut` | = note: this is cfg-gated and may require further changes -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:219:39 | LL | async fn inner_async2(x: &mut i32, y: &mut u32) { - | ^^^^^^^^ help: consider changing to: `&u32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:228:26 | LL | async fn inner_async3(x: &mut i32, y: &mut u32) { - | ^^^^^^^^ help: consider changing to: `&i32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:248:30 | LL | async fn call_in_closure1(n: &mut str) { - | ^^^^^^^^ help: consider changing to: `&str` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:268:16 | LL | fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { - | ^^^^^^^^^^ help: consider changing to: `&usize` + | ^----^^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:280:22 | LL | async fn closure4(n: &mut usize) { - | ^^^^^^^^^^ help: consider changing to: `&usize` + | ^----^^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:335:12 | LL | fn bar(&mut self) {} - | ^^^^^^^^^ help: consider changing to: `&self` + | ^----^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:338:18 | LL | async fn foo(&mut self, u: &mut i32, v: &mut u32) { - | ^^^^^^^^^ help: consider changing to: `&self` + | ^----^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:338:45 | LL | async fn foo(&mut self, u: &mut i32, v: &mut u32) { - | ^^^^^^^^ help: consider changing to: `&u32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:347:46 | LL | async fn foo2(&mut self, u: &mut i32, v: &mut u32) { - | ^^^^^^^^ help: consider changing to: `&u32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:364:18 | LL | fn _empty_tup(x: &mut (())) {} - | ^^^^^^^^^ help: consider changing to: `&()` + | ^^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:366:19 | LL | fn _single_tup(x: &mut ((i32,))) {} - | ^^^^^^^^^^^^^ help: consider changing to: `&(i32,)` + | ^^----^^^^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:368:18 | LL | fn _multi_tup(x: &mut ((i32, u32))) {} - | ^^^^^^^^^^^^^^^^^ help: consider changing to: `&(i32, u32)` + | ^^----^^^^^^^^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:370:11 | LL | fn _fn(x: &mut (fn())) {} - | ^^^^^^^^^^^ help: consider changing to: `&fn()` + | ^^----^^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:373:23 | LL | fn _extern_rust_fn(x: &mut extern "Rust" fn()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "Rust" fn()` + | ^----^^^^^^^^^^^^^^^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:375:20 | LL | fn _extern_c_fn(x: &mut extern "C" fn()) {} - | ^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "C" fn()` + | ^----^^^^^^^^^^^^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:377:18 | LL | fn _unsafe_fn(x: &mut unsafe fn()) {} - | ^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe fn()` + | ^----^^^^^^^^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:379:25 | LL | fn _unsafe_extern_fn(x: &mut unsafe extern "C" fn()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn()` + | ^----^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:381:20 | LL | fn _fn_with_arg(x: &mut unsafe extern "C" fn(i32)) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn(i32)` + | ^----^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:383:20 | LL | fn _fn_with_ret(x: &mut unsafe extern "C" fn() -> (i32)) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn() -> (i32)` + | ^----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: consider removing this `mut` error: aborting due to 34 previous errors diff --git a/tests/ui/needless_pass_by_ref_mut2.fixed b/tests/ui/needless_pass_by_ref_mut2.fixed index 0e2ac0202364..c462f1cc8d87 100644 --- a/tests/ui/needless_pass_by_ref_mut2.fixed +++ b/tests/ui/needless_pass_by_ref_mut2.fixed @@ -24,3 +24,9 @@ async fn inner_async4(u: &mut i32, v: &u32) { } fn main() {} + +//~v needless_pass_by_ref_mut +fn issue16267<'a>(msg: &str, slice: &'a [i32]) -> &'a [i32] { + println!("{msg}"); + &slice[0..5] +} diff --git a/tests/ui/needless_pass_by_ref_mut2.rs b/tests/ui/needless_pass_by_ref_mut2.rs index 9201d9a27298..b00f294c57f0 100644 --- a/tests/ui/needless_pass_by_ref_mut2.rs +++ b/tests/ui/needless_pass_by_ref_mut2.rs @@ -24,3 +24,9 @@ async fn inner_async4(u: &mut i32, v: &mut u32) { } fn main() {} + +//~v needless_pass_by_ref_mut +fn issue16267<'a>(msg: &str, slice: &'a mut [i32]) -> &'a [i32] { + println!("{msg}"); + &slice[0..5] +} diff --git a/tests/ui/needless_pass_by_ref_mut2.stderr b/tests/ui/needless_pass_by_ref_mut2.stderr index 9876a6b50718..aa5c412adb4d 100644 --- a/tests/ui/needless_pass_by_ref_mut2.stderr +++ b/tests/ui/needless_pass_by_ref_mut2.stderr @@ -1,17 +1,29 @@ -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut2.rs:8:26 | LL | async fn inner_async3(x: &mut i32, y: &mut u32) { - | ^^^^^^^^ help: consider changing to: `&i32` + | ^----^^^ + | | + | help: consider removing this `mut` | = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut2.rs:17:39 | LL | async fn inner_async4(u: &mut i32, v: &mut u32) { - | ^^^^^^^^ help: consider changing to: `&u32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: aborting due to 2 previous errors +error: this parameter is a mutable reference but is not used mutably + --> tests/ui/needless_pass_by_ref_mut2.rs:29:37 + | +LL | fn issue16267<'a>(msg: &str, slice: &'a mut [i32]) -> &'a [i32] { + | ^^^^----^^^^^ + | | + | help: consider removing this `mut` + +error: aborting due to 3 previous errors diff --git a/tests/ui/needless_type_cast.fixed b/tests/ui/needless_type_cast.fixed index 32c348d3ca3a..72eed32c4d73 100644 --- a/tests/ui/needless_type_cast.fixed +++ b/tests/ui/needless_type_cast.fixed @@ -9,6 +9,10 @@ fn generic(x: T) -> T { x } +fn returns_u8() -> u8 { + 10 +} + fn main() { let a: i32 = 10; //~^ needless_type_cast @@ -180,3 +184,86 @@ fn test_loop_with_generic() { }; let _ = x as i32; } + +fn test_size_of_cast() { + use std::mem::size_of; + // Should lint: suggest casting the initializer + let size: u64 = size_of::() as u64; + //~^ needless_type_cast + let _ = size as u64; + let _ = size as u64; +} + +fn test_suffixed_literal_cast() { + // Should lint: suggest casting the initializer + let a: i32 = 10u8 as i32; + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_negative_literal() { + // Negative literal - should just change type, not add cast + let a: i32 = -10; + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_suffixed_negative_literal() { + // Suffixed negative - needs cast + let a: i32 = -10i8 as i32; + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_binary_op() { + // Binary op needs parens in cast + let a: i32 = 10 + 5; + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_fn_return_as_init() { + let a: i32 = returns_u8() as i32; + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_method_as_init() { + let a: i32 = 2u8.saturating_add(3) as i32; + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_const_as_init() { + const X: u8 = 10; + let a: i32 = X as i32; + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_single_use_fn_call() { + // Should not lint: only one use, and fixing would just move the cast + // to the initializer rather than eliminating it + let a: u8 = returns_u8(); + let _ = a as i32; +} + +fn test_single_use_suffixed_literal() { + // Should not lint: only one use with a suffixed literal + let a: u8 = 10u8; + let _ = a as i32; +} + +fn test_single_use_binary_op() { + // Should lint: binary op of unsuffixed literals can be coerced + let a: i32 = 10 + 5; + //~^ needless_type_cast + let _ = a as i32; +} diff --git a/tests/ui/needless_type_cast.rs b/tests/ui/needless_type_cast.rs index e28f620e035f..31337575fcc3 100644 --- a/tests/ui/needless_type_cast.rs +++ b/tests/ui/needless_type_cast.rs @@ -9,6 +9,10 @@ fn generic(x: T) -> T { x } +fn returns_u8() -> u8 { + 10 +} + fn main() { let a: u8 = 10; //~^ needless_type_cast @@ -180,3 +184,86 @@ fn test_loop_with_generic() { }; let _ = x as i32; } + +fn test_size_of_cast() { + use std::mem::size_of; + // Should lint: suggest casting the initializer + let size: usize = size_of::(); + //~^ needless_type_cast + let _ = size as u64; + let _ = size as u64; +} + +fn test_suffixed_literal_cast() { + // Should lint: suggest casting the initializer + let a: u8 = 10u8; + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_negative_literal() { + // Negative literal - should just change type, not add cast + let a: i8 = -10; + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_suffixed_negative_literal() { + // Suffixed negative - needs cast + let a: i8 = -10i8; + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_binary_op() { + // Binary op needs parens in cast + let a: u8 = 10 + 5; + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_fn_return_as_init() { + let a: u8 = returns_u8(); + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_method_as_init() { + let a: u8 = 2u8.saturating_add(3); + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_const_as_init() { + const X: u8 = 10; + let a: u8 = X; + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_single_use_fn_call() { + // Should not lint: only one use, and fixing would just move the cast + // to the initializer rather than eliminating it + let a: u8 = returns_u8(); + let _ = a as i32; +} + +fn test_single_use_suffixed_literal() { + // Should not lint: only one use with a suffixed literal + let a: u8 = 10u8; + let _ = a as i32; +} + +fn test_single_use_binary_op() { + // Should lint: binary op of unsuffixed literals can be coerced + let a: u8 = 10 + 5; + //~^ needless_type_cast + let _ = a as i32; +} diff --git a/tests/ui/needless_type_cast.stderr b/tests/ui/needless_type_cast.stderr index 3ee9df1043e7..56d9e978d05c 100644 --- a/tests/ui/needless_type_cast.stderr +++ b/tests/ui/needless_type_cast.stderr @@ -1,5 +1,5 @@ error: this binding is defined as `u8` but is always cast to `i32` - --> tests/ui/needless_type_cast.rs:13:12 + --> tests/ui/needless_type_cast.rs:17:12 | LL | let a: u8 = 10; | ^^ help: consider defining it as: `i32` @@ -8,64 +8,154 @@ LL | let a: u8 = 10; = help: to override `-D warnings` add `#[allow(clippy::needless_type_cast)]` error: this binding is defined as `u8` but is always cast to `usize` - --> tests/ui/needless_type_cast.rs:33:12 + --> tests/ui/needless_type_cast.rs:37:12 | LL | let f: u8 = 1; | ^^ help: consider defining it as: `usize` error: this binding is defined as `u8` but is always cast to `i32` - --> tests/ui/needless_type_cast.rs:39:12 + --> tests/ui/needless_type_cast.rs:43:12 | LL | let a: u8 = 10; | ^^ help: consider defining it as: `i32` error: this binding is defined as `u8` but is always cast to `i32` - --> tests/ui/needless_type_cast.rs:52:12 + --> tests/ui/needless_type_cast.rs:56:12 | LL | let a: u8 = 10; | ^^ help: consider defining it as: `i32` error: this binding is defined as `u8` but is always cast to `i32` - --> tests/ui/needless_type_cast.rs:59:12 + --> tests/ui/needless_type_cast.rs:63:12 | LL | let a: u8 = 10; | ^^ help: consider defining it as: `i32` error: this binding is defined as `u8` but is always cast to `i32` - --> tests/ui/needless_type_cast.rs:66:12 + --> tests/ui/needless_type_cast.rs:70:12 | LL | let a: u8 = 10; | ^^ help: consider defining it as: `i32` error: this binding is defined as `u8` but is always cast to `i32` - --> tests/ui/needless_type_cast.rs:77:12 + --> tests/ui/needless_type_cast.rs:81:12 | LL | let a: u8 = 10; | ^^ help: consider defining it as: `i32` error: this binding is defined as `u8` but is always cast to `i32` - --> tests/ui/needless_type_cast.rs:99:16 + --> tests/ui/needless_type_cast.rs:103:16 | LL | let a: u8 = 10; | ^^ help: consider defining it as: `i32` error: this binding is defined as `u8` but is always cast to `i32` - --> tests/ui/needless_type_cast.rs:107:12 + --> tests/ui/needless_type_cast.rs:111:12 | LL | let a: u8 = 10; | ^^ help: consider defining it as: `i32` error: this binding is defined as `u8` but is always cast to `i32` - --> tests/ui/needless_type_cast.rs:116:12 + --> tests/ui/needless_type_cast.rs:120:12 | LL | let a: u8 = 10; | ^^ help: consider defining it as: `i32` error: this binding is defined as `u8` but is always cast to `i32` - --> tests/ui/needless_type_cast.rs:122:12 + --> tests/ui/needless_type_cast.rs:126:12 | LL | let a: u8 = 10; | ^^ help: consider defining it as: `i32` -error: aborting due to 11 previous errors +error: this binding is defined as `usize` but is always cast to `u64` + --> tests/ui/needless_type_cast.rs:191:15 + | +LL | let size: usize = size_of::(); + | ^^^^^ + | +help: consider defining it as `u64` and casting the initializer + | +LL - let size: usize = size_of::(); +LL + let size: u64 = size_of::() as u64; + | + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:199:12 + | +LL | let a: u8 = 10u8; + | ^^ + | +help: consider defining it as `i32` and casting the initializer + | +LL - let a: u8 = 10u8; +LL + let a: i32 = 10u8 as i32; + | + +error: this binding is defined as `i8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:207:12 + | +LL | let a: i8 = -10; + | ^^ help: consider defining it as: `i32` + +error: this binding is defined as `i8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:215:12 + | +LL | let a: i8 = -10i8; + | ^^ + | +help: consider defining it as `i32` and casting the initializer + | +LL - let a: i8 = -10i8; +LL + let a: i32 = -10i8 as i32; + | + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:223:12 + | +LL | let a: u8 = 10 + 5; + | ^^ help: consider defining it as: `i32` + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:230:12 + | +LL | let a: u8 = returns_u8(); + | ^^ + | +help: consider defining it as `i32` and casting the initializer + | +LL - let a: u8 = returns_u8(); +LL + let a: i32 = returns_u8() as i32; + | + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:237:12 + | +LL | let a: u8 = 2u8.saturating_add(3); + | ^^ + | +help: consider defining it as `i32` and casting the initializer + | +LL - let a: u8 = 2u8.saturating_add(3); +LL + let a: i32 = 2u8.saturating_add(3) as i32; + | + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:245:12 + | +LL | let a: u8 = X; + | ^^ + | +help: consider defining it as `i32` and casting the initializer + | +LL - let a: u8 = X; +LL + let a: i32 = X as i32; + | + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:266:12 + | +LL | let a: u8 = 10 + 5; + | ^^ help: consider defining it as: `i32` + +error: aborting due to 20 previous errors diff --git a/tests/ui/needless_type_cast_unfixable.rs b/tests/ui/needless_type_cast_unfixable.rs new file mode 100644 index 000000000000..bbea9bd24296 --- /dev/null +++ b/tests/ui/needless_type_cast_unfixable.rs @@ -0,0 +1,20 @@ +//@no-rustfix +#![warn(clippy::needless_type_cast)] + +struct Foo(*mut core::ffi::c_void); + +enum Bar { + Variant(*mut core::ffi::c_void), +} + +// Suggestions will not compile directly, as `123` is a literal which +// is not compatible with the suggested `*mut core::ffi::c_void` type +fn issue_16243() { + let underlying: isize = 123; + //~^ needless_type_cast + let handle: Foo = Foo(underlying as _); + + let underlying: isize = 123; + //~^ needless_type_cast + let handle: Bar = Bar::Variant(underlying as _); +} diff --git a/tests/ui/needless_type_cast_unfixable.stderr b/tests/ui/needless_type_cast_unfixable.stderr new file mode 100644 index 000000000000..b71f8a09c40f --- /dev/null +++ b/tests/ui/needless_type_cast_unfixable.stderr @@ -0,0 +1,17 @@ +error: this binding is defined as `isize` but is always cast to `*mut std::ffi::c_void` + --> tests/ui/needless_type_cast_unfixable.rs:13:21 + | +LL | let underlying: isize = 123; + | ^^^^^ help: consider defining it as: `*mut std::ffi::c_void` + | + = note: `-D clippy::needless-type-cast` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_type_cast)]` + +error: this binding is defined as `isize` but is always cast to `*mut std::ffi::c_void` + --> tests/ui/needless_type_cast_unfixable.rs:17:21 + | +LL | let underlying: isize = 123; + | ^^^^^ help: consider defining it as: `*mut std::ffi::c_void` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/never_loop_iterator_reduction.rs b/tests/ui/never_loop_iterator_reduction.rs new file mode 100644 index 000000000000..6b07b91db29a --- /dev/null +++ b/tests/ui/never_loop_iterator_reduction.rs @@ -0,0 +1,17 @@ +//@no-rustfix +#![warn(clippy::never_loop)] + +fn main() { + // diverging closure: should trigger + [0, 1].into_iter().for_each(|x| { + //~^ never_loop + + let _ = x; + panic!("boom"); + }); + + // benign closure: should NOT trigger + [0, 1].into_iter().for_each(|x| { + let _ = x + 1; + }); +} diff --git a/tests/ui/never_loop_iterator_reduction.stderr b/tests/ui/never_loop_iterator_reduction.stderr new file mode 100644 index 000000000000..b76ee283146c --- /dev/null +++ b/tests/ui/never_loop_iterator_reduction.stderr @@ -0,0 +1,27 @@ +error: this iterator reduction never loops (closure always diverges) + --> tests/ui/never_loop_iterator_reduction.rs:6:5 + | +LL | / [0, 1].into_iter().for_each(|x| { +LL | | +LL | | +LL | | let _ = x; +LL | | panic!("boom"); +LL | | }); + | |______^ + | + = note: if you only need one element, `if let Some(x) = iter.next()` is clearer + = note: `-D clippy::never-loop` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::never_loop)]` +help: consider this pattern + | +LL - [0, 1].into_iter().for_each(|x| { +LL - +LL - +LL - let _ = x; +LL - panic!("boom"); +LL - }); +LL + if let Some(x) = [0, 1].into_iter().next() { ... }; + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/obfuscated_if_else.fixed b/tests/ui/obfuscated_if_else.fixed index 70ae090626b9..6bdb170a4aa9 100644 --- a/tests/ui/obfuscated_if_else.fixed +++ b/tests/ui/obfuscated_if_else.fixed @@ -87,3 +87,9 @@ fn issue11141() { let _ = *if true { &42 } else { &17 } as u8; //~^ obfuscated_if_else } + +#[allow(clippy::useless_format)] +fn issue16288() { + if true { format!("this is a test") } else { Default::default() }; + //~^ obfuscated_if_else +} diff --git a/tests/ui/obfuscated_if_else.rs b/tests/ui/obfuscated_if_else.rs index 8e1f57ca2c02..f7b5ea8c0135 100644 --- a/tests/ui/obfuscated_if_else.rs +++ b/tests/ui/obfuscated_if_else.rs @@ -87,3 +87,9 @@ fn issue11141() { let _ = *true.then_some(&42).unwrap_or(&17) as u8; //~^ obfuscated_if_else } + +#[allow(clippy::useless_format)] +fn issue16288() { + true.then(|| format!("this is a test")).unwrap_or_default(); + //~^ obfuscated_if_else +} diff --git a/tests/ui/obfuscated_if_else.stderr b/tests/ui/obfuscated_if_else.stderr index 0de7259d8bb8..865dca56b97a 100644 --- a/tests/ui/obfuscated_if_else.stderr +++ b/tests/ui/obfuscated_if_else.stderr @@ -139,5 +139,11 @@ error: this method chain can be written more clearly with `if .. else ..` LL | let _ = *true.then_some(&42).unwrap_or(&17) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { &42 } else { &17 }` -error: aborting due to 23 previous errors +error: this method chain can be written more clearly with `if .. else ..` + --> tests/ui/obfuscated_if_else.rs:93:5 + | +LL | true.then(|| format!("this is a test")).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { format!("this is a test") } else { Default::default() }` + +error: aborting due to 24 previous errors diff --git a/tests/ui/println_empty_string.fixed b/tests/ui/println_empty_string.fixed index 05e262ec7786..6b1039ee8020 100644 --- a/tests/ui/println_empty_string.fixed +++ b/tests/ui/println_empty_string.fixed @@ -19,3 +19,23 @@ fn main() { //~^ println_empty_string } } + +#[rustfmt::skip] +fn issue_16167() { + //~v println_empty_string + println!( + ); + + match "a" { + _ => println!(), // there is a space between "" and comma + //~^ println_empty_string + } + + eprintln!(); // there is a tab between "" and comma + //~^ println_empty_string + + match "a" { + _ => eprintln!(), // tab and space between "" and comma + //~^ println_empty_string + } +} diff --git a/tests/ui/println_empty_string.rs b/tests/ui/println_empty_string.rs index 028ddb60dbce..db3b8e1a0eac 100644 --- a/tests/ui/println_empty_string.rs +++ b/tests/ui/println_empty_string.rs @@ -19,3 +19,27 @@ fn main() { //~^ println_empty_string } } + +#[rustfmt::skip] +fn issue_16167() { + //~v println_empty_string + println!( + "\ + \ + " + , + ); + + match "a" { + _ => println!("" ,), // there is a space between "" and comma + //~^ println_empty_string + } + + eprintln!("" ,); // there is a tab between "" and comma + //~^ println_empty_string + + match "a" { + _ => eprintln!("" ,), // tab and space between "" and comma + //~^ println_empty_string + } +} diff --git a/tests/ui/println_empty_string.stderr b/tests/ui/println_empty_string.stderr index 8b997aef9069..bdac1bb3b8ef 100644 --- a/tests/ui/println_empty_string.stderr +++ b/tests/ui/println_empty_string.stderr @@ -33,5 +33,42 @@ LL | _ => eprintln!(""), | | | help: remove the empty string -error: aborting due to 4 previous errors +error: empty string literal in `println!` + --> tests/ui/println_empty_string.rs:26:5 + | +LL | / println!( +LL | |/ "\ +LL | || \ +LL | || " +LL | || , +LL | || ); + | ||____-^ + | |____| + | help: remove the empty string + +error: empty string literal in `println!` + --> tests/ui/println_empty_string.rs:34:14 + | +LL | _ => println!("" ,), // there is a space between "" and comma + | ^^^^^^^^^----^ + | | + | help: remove the empty string + +error: empty string literal in `eprintln!` + --> tests/ui/println_empty_string.rs:38:5 + | +LL | eprintln!("" ,); // there is a tab between "" and comma + | ^^^^^^^^^^-------^ + | | + | help: remove the empty string + +error: empty string literal in `eprintln!` + --> tests/ui/println_empty_string.rs:42:14 + | +LL | _ => eprintln!("" ,), // tab and space between "" and comma + | ^^^^^^^^^^--------^ + | | + | help: remove the empty string + +error: aborting due to 8 previous errors diff --git a/tests/ui/println_empty_string_unfixable.rs b/tests/ui/println_empty_string_unfixable.rs new file mode 100644 index 000000000000..d6c30f627a58 --- /dev/null +++ b/tests/ui/println_empty_string_unfixable.rs @@ -0,0 +1,30 @@ +#![allow(clippy::match_single_binding)] + +// If there is a comment in the span of macro call, we don't provide an auto-fix suggestion. +#[rustfmt::skip] +fn issue_16167() { + //~v println_empty_string + println!("" /* comment */); + //~v println_empty_string + eprintln!("" /* comment */); + + //~v println_empty_string + println!( // comment + ""); + //~v println_empty_string + eprintln!( // comment + ""); + + //~v println_empty_string + println!("", /* comment */); + + //~v println_empty_string + println!( + "\ + \ + ", + + // there is a comment in the macro span regardless of its position + + ); +} diff --git a/tests/ui/println_empty_string_unfixable.stderr b/tests/ui/println_empty_string_unfixable.stderr new file mode 100644 index 000000000000..648fd7cdbccd --- /dev/null +++ b/tests/ui/println_empty_string_unfixable.stderr @@ -0,0 +1,85 @@ +error: empty string literal in `println!` + --> tests/ui/println_empty_string_unfixable.rs:7:5 + | +LL | println!("" /* comment */); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: remove the empty string + --> tests/ui/println_empty_string_unfixable.rs:7:14 + | +LL | println!("" /* comment */); + | ^^ + = note: `-D clippy::println-empty-string` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::println_empty_string)]` + +error: empty string literal in `eprintln!` + --> tests/ui/println_empty_string_unfixable.rs:9:5 + | +LL | eprintln!("" /* comment */); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: remove the empty string + --> tests/ui/println_empty_string_unfixable.rs:9:15 + | +LL | eprintln!("" /* comment */); + | ^^ + +error: empty string literal in `println!` + --> tests/ui/println_empty_string_unfixable.rs:12:5 + | +LL | / println!( // comment +LL | | ""); + | |___________________^ + | +note: remove the empty string + --> tests/ui/println_empty_string_unfixable.rs:13:17 + | +LL | ""); + | ^^ + +error: empty string literal in `eprintln!` + --> tests/ui/println_empty_string_unfixable.rs:15:5 + | +LL | / eprintln!( // comment +LL | | ""); + | |___________________^ + | +note: remove the empty string + --> tests/ui/println_empty_string_unfixable.rs:16:17 + | +LL | ""); + | ^^ + +error: empty string literal in `println!` + --> tests/ui/println_empty_string_unfixable.rs:19:5 + | +LL | println!("", /* comment */); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: remove the empty string + --> tests/ui/println_empty_string_unfixable.rs:19:14 + | +LL | println!("", /* comment */); + | ^^ + +error: empty string literal in `println!` + --> tests/ui/println_empty_string_unfixable.rs:22:5 + | +LL | / println!( +LL | | "\ +LL | | \ +LL | | ", +... | +LL | | ); + | |_____^ + | +note: remove the empty string + --> tests/ui/println_empty_string_unfixable.rs:23:9 + | +LL | / "\ +LL | | \ +LL | | ", + | |_____________^ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/ref_as_ptr.fixed b/tests/ui/ref_as_ptr.fixed index ce144508581e..eadbb7c36415 100644 --- a/tests/ui/ref_as_ptr.fixed +++ b/tests/ui/ref_as_ptr.fixed @@ -86,6 +86,16 @@ fn main() { f(std::ptr::from_mut::<[usize; 9]>(&mut std::array::from_fn(|i| i * i))); //~^ ref_as_ptr + let x = (10, 20); + let _ = std::ptr::from_ref(&x); + //~^ ref_as_ptr + let _ = std::ptr::from_ref(&x.0); + //~^ ref_as_ptr + + let x = Box::new(10); + let _ = std::ptr::from_ref(&*x); + //~^ ref_as_ptr + let _ = &String::new() as *const _; let _ = &mut String::new() as *mut _; const FOO: *const String = &String::new() as *const _; diff --git a/tests/ui/ref_as_ptr.rs b/tests/ui/ref_as_ptr.rs index acdff2c2ba29..ef96a3ff5693 100644 --- a/tests/ui/ref_as_ptr.rs +++ b/tests/ui/ref_as_ptr.rs @@ -86,6 +86,16 @@ fn main() { f(&mut std::array::from_fn(|i| i * i) as *mut [usize; 9]); //~^ ref_as_ptr + let x = (10, 20); + let _ = &x as *const _; + //~^ ref_as_ptr + let _ = &x.0 as *const _; + //~^ ref_as_ptr + + let x = Box::new(10); + let _ = &*x as *const _; + //~^ ref_as_ptr + let _ = &String::new() as *const _; let _ = &mut String::new() as *mut _; const FOO: *const String = &String::new() as *const _; diff --git a/tests/ui/ref_as_ptr.stderr b/tests/ui/ref_as_ptr.stderr index 79db29e596bd..587e4fb809cd 100644 --- a/tests/ui/ref_as_ptr.stderr +++ b/tests/ui/ref_as_ptr.stderr @@ -200,61 +200,67 @@ LL | f(&mut std::array::from_fn(|i| i * i) as *mut [usize; 9]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut::<[usize; 9]>(&mut std::array::from_fn(|i| i * i))` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:109:7 + --> tests/ui/ref_as_ptr.rs:90:13 + | +LL | let _ = &x as *const _; + | ^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(&x)` + +error: reference as raw pointer + --> tests/ui/ref_as_ptr.rs:92:13 + | +LL | let _ = &x.0 as *const _; + | ^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(&x.0)` + +error: reference as raw pointer + --> tests/ui/ref_as_ptr.rs:96:13 + | +LL | let _ = &*x as *const _; + | ^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(&*x)` + +error: reference as raw pointer + --> tests/ui/ref_as_ptr.rs:119:7 | LL | f(val as *const i32); | ^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::(val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:111:7 + --> tests/ui/ref_as_ptr.rs:121:7 | LL | f(mut_val as *mut i32); | ^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut::(mut_val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:116:7 + --> tests/ui/ref_as_ptr.rs:126:7 | LL | f(val as *const _); | ^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:118:7 + --> tests/ui/ref_as_ptr.rs:128:7 | LL | f(val as *const [u8]); | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::<[u8]>(val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:123:7 + --> tests/ui/ref_as_ptr.rs:133:7 | LL | f(val as *mut _); | ^^^^^^^^^^^^^ help: try: `std::ptr::from_mut(val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:125:7 + --> tests/ui/ref_as_ptr.rs:135:7 | LL | f(val as *mut str); | ^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut::(val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:133:9 + --> tests/ui/ref_as_ptr.rs:143:9 | LL | self.0 as *const _ as *const _ | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(self.0)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:138:9 - | -LL | self.0 as *const _ as *const _ - | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(self.0)` - -error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:147:9 - | -LL | self.0 as *const _ as *const _ - | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(self.0)` - -error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:152:9 + --> tests/ui/ref_as_ptr.rs:148:9 | LL | self.0 as *const _ as *const _ | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(self.0)` @@ -262,8 +268,20 @@ LL | self.0 as *const _ as *const _ error: reference as raw pointer --> tests/ui/ref_as_ptr.rs:157:9 | +LL | self.0 as *const _ as *const _ + | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(self.0)` + +error: reference as raw pointer + --> tests/ui/ref_as_ptr.rs:162:9 + | +LL | self.0 as *const _ as *const _ + | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(self.0)` + +error: reference as raw pointer + --> tests/ui/ref_as_ptr.rs:167:9 + | LL | self.0 as *mut _ as *mut _ | ^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut(self.0)` -error: aborting due to 44 previous errors +error: aborting due to 47 previous errors diff --git a/tests/ui/result_large_err.rs b/tests/ui/result_large_err.rs index fa57b3f553fc..b4ad050df3b7 100644 --- a/tests/ui/result_large_err.rs +++ b/tests/ui/result_large_err.rs @@ -141,3 +141,12 @@ fn _empty_error() -> Result<(), Empty> { } fn main() {} + +fn issue16249() { + type Large = [u8; 1024]; + + let closure = || -> Result<(), Large> { Ok(()) }; + //~^ result_large_err + let closure = || Ok::<(), Large>(()); + //~^ result_large_err +} diff --git a/tests/ui/result_large_err.stderr b/tests/ui/result_large_err.stderr index 72fbc3f58961..fd39179c61cb 100644 --- a/tests/ui/result_large_err.stderr +++ b/tests/ui/result_large_err.stderr @@ -104,5 +104,21 @@ LL | pub fn array_error() -> Result<(), ArrayError<(i32, T), U>> { | = help: try reducing the size of `ArrayError<(i32, T), U>`, for example by boxing large elements or replacing it with `Box>` -error: aborting due to 12 previous errors +error: the `Err`-variant returned from this closure is very large + --> tests/ui/result_large_err.rs:148:25 + | +LL | let closure = || -> Result<(), Large> { Ok(()) }; + | ^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 1024 bytes + | + = help: try reducing the size of `[u8; 1024]`, for example by boxing large elements or replacing it with `Box<[u8; 1024]>` + +error: the `Err`-variant returned from this closure is very large + --> tests/ui/result_large_err.rs:150:19 + | +LL | let closure = || Ok::<(), Large>(()); + | ^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 1024 bytes + | + = help: try reducing the size of `[u8; 1024]`, for example by boxing large elements or replacing it with `Box<[u8; 1024]>` + +error: aborting due to 14 previous errors diff --git a/tests/ui/same_length_and_capacity.rs b/tests/ui/same_length_and_capacity.rs new file mode 100644 index 000000000000..999fcf89881d --- /dev/null +++ b/tests/ui/same_length_and_capacity.rs @@ -0,0 +1,27 @@ +#![warn(clippy::same_length_and_capacity)] + +fn main() { + let mut my_vec: Vec = Vec::with_capacity(20); + my_vec.extend([1, 2, 3, 4, 5]); + let (ptr, mut len, cap) = my_vec.into_raw_parts(); + len = 8; + + let _reconstructed_vec = unsafe { Vec::from_raw_parts(ptr, len, len) }; + //~^ same_length_and_capacity + + // Don't want to lint different expressions for len and cap + let _properly_reconstructed_vec = unsafe { Vec::from_raw_parts(ptr, len, cap) }; + + // Don't want to lint if len and cap are distinct variables but happen to be equal + let len_from_cap = cap; + let _another_properly_reconstructed_vec = unsafe { Vec::from_raw_parts(ptr, len_from_cap, cap) }; + + let my_string = String::from("hello"); + let (string_ptr, string_len, string_cap) = my_string.into_raw_parts(); + + let _reconstructed_string = unsafe { String::from_raw_parts(string_ptr, string_len, string_len) }; + //~^ same_length_and_capacity + + // Don't want to lint different expressions for len and cap + let _properly_reconstructed_string = unsafe { String::from_raw_parts(string_ptr, string_len, string_cap) }; +} diff --git a/tests/ui/same_length_and_capacity.stderr b/tests/ui/same_length_and_capacity.stderr new file mode 100644 index 000000000000..6fc852831269 --- /dev/null +++ b/tests/ui/same_length_and_capacity.stderr @@ -0,0 +1,20 @@ +error: usage of `Vec::from_raw_parts` with the same expression for length and capacity + --> tests/ui/same_length_and_capacity.rs:9:39 + | +LL | let _reconstructed_vec = unsafe { Vec::from_raw_parts(ptr, len, len) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try `Box::from(slice::from_raw_parts(...)).into::>()` + = note: `-D clippy::same-length-and-capacity` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::same_length_and_capacity)]` + +error: usage of `String::from_raw_parts` with the same expression for length and capacity + --> tests/ui/same_length_and_capacity.rs:22:42 + | +LL | let _reconstructed_string = unsafe { String::from_raw_parts(string_ptr, string_len, string_len) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try `String::from(str::from_utf8_unchecked(slice::from_raw_parts(...)))` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/set_contains_or_insert.rs b/tests/ui/set_contains_or_insert.rs index 575cfda139a4..ac1d74f8afa4 100644 --- a/tests/ui/set_contains_or_insert.rs +++ b/tests/ui/set_contains_or_insert.rs @@ -164,3 +164,24 @@ fn main() { should_not_warn_hashset(); should_not_warn_btreeset(); } + +fn issue15990(s: &mut HashSet, v: usize) { + if !s.contains(&v) { + s.clear(); + s.insert(v); + } + + fn borrow_as_mut(v: usize, s: &mut HashSet) { + s.clear(); + } + if !s.contains(&v) { + borrow_as_mut(v, s); + s.insert(v); + } + + if !s.contains(&v) { + //~^ set_contains_or_insert + let _readonly_access = s.contains(&v); + s.insert(v); + } +} diff --git a/tests/ui/set_contains_or_insert.stderr b/tests/ui/set_contains_or_insert.stderr index 3152b1136458..3b06b63182ab 100644 --- a/tests/ui/set_contains_or_insert.stderr +++ b/tests/ui/set_contains_or_insert.stderr @@ -127,5 +127,14 @@ LL | LL | borrow_set.insert(value); | ^^^^^^^^^^^^^ -error: aborting due to 14 previous errors +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/set_contains_or_insert.rs:182:11 + | +LL | if !s.contains(&v) { + | ^^^^^^^^^^^^ +... +LL | s.insert(v); + | ^^^^^^^^^ + +error: aborting due to 15 previous errors diff --git a/tests/ui/track-diagnostics.rs b/tests/ui/track-diagnostics.rs index 0fbde867390d..1cd37e0570d7 100644 --- a/tests/ui/track-diagnostics.rs +++ b/tests/ui/track-diagnostics.rs @@ -3,6 +3,7 @@ // Normalize the emitted location so this doesn't need // updating everytime someone adds or removes a line. //@normalize-stderr-test: ".rs:\d+:\d+" -> ".rs:LL:CC" +//@normalize-stderr-test: "/rustc-dev/[0-9a-f]+/" -> "" struct A; struct B; diff --git a/tests/ui/transmuting_null.rs b/tests/ui/transmuting_null.rs index f3eb5060cd0d..0d3b26673452 100644 --- a/tests/ui/transmuting_null.rs +++ b/tests/ui/transmuting_null.rs @@ -30,7 +30,15 @@ fn transmute_const() { } } +fn transmute_const_int() { + unsafe { + let _: &u64 = std::mem::transmute(u64::MIN as *const u64); + //~^ transmuting_null + } +} + fn main() { one_liners(); transmute_const(); + transmute_const_int(); } diff --git a/tests/ui/transmuting_null.stderr b/tests/ui/transmuting_null.stderr index c68e4102e405..ed7c3396a243 100644 --- a/tests/ui/transmuting_null.stderr +++ b/tests/ui/transmuting_null.stderr @@ -19,5 +19,11 @@ error: transmuting a known null pointer into a reference LL | let _: &u64 = std::mem::transmute(ZPTR); | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: transmuting a known null pointer into a reference + --> tests/ui/transmuting_null.rs:35:23 + | +LL | let _: &u64 = std::mem::transmute(u64::MIN as *const u64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors diff --git a/tests/ui/unchecked_time_subtraction.fixed b/tests/ui/unchecked_time_subtraction.fixed index 2f923fef4c25..830b737f18e7 100644 --- a/tests/ui/unchecked_time_subtraction.fixed +++ b/tests/ui/unchecked_time_subtraction.fixed @@ -35,3 +35,28 @@ fn main() { let _ = (2 * dur1).checked_sub(dur2).unwrap(); //~^ unchecked_time_subtraction } + +fn issue16230() { + use std::ops::Sub as _; + + Duration::ZERO.checked_sub(Duration::MAX).unwrap(); + //~^ unchecked_time_subtraction + + let _ = Duration::ZERO.checked_sub(Duration::MAX).unwrap(); + //~^ unchecked_time_subtraction +} + +fn issue16234() { + use std::ops::Sub as _; + + macro_rules! duration { + ($secs:expr) => { + Duration::from_secs($secs) + }; + } + + duration!(0).checked_sub(duration!(1)).unwrap(); + //~^ unchecked_time_subtraction + let _ = duration!(0).checked_sub(duration!(1)).unwrap(); + //~^ unchecked_time_subtraction +} diff --git a/tests/ui/unchecked_time_subtraction.rs b/tests/ui/unchecked_time_subtraction.rs index cf727f62aafa..e41860157c41 100644 --- a/tests/ui/unchecked_time_subtraction.rs +++ b/tests/ui/unchecked_time_subtraction.rs @@ -35,3 +35,28 @@ fn main() { let _ = 2 * dur1 - dur2; //~^ unchecked_time_subtraction } + +fn issue16230() { + use std::ops::Sub as _; + + Duration::ZERO.sub(Duration::MAX); + //~^ unchecked_time_subtraction + + let _ = Duration::ZERO - Duration::MAX; + //~^ unchecked_time_subtraction +} + +fn issue16234() { + use std::ops::Sub as _; + + macro_rules! duration { + ($secs:expr) => { + Duration::from_secs($secs) + }; + } + + duration!(0).sub(duration!(1)); + //~^ unchecked_time_subtraction + let _ = duration!(0) - duration!(1); + //~^ unchecked_time_subtraction +} diff --git a/tests/ui/unchecked_time_subtraction.stderr b/tests/ui/unchecked_time_subtraction.stderr index c129497447fc..fa4bd1db81ae 100644 --- a/tests/ui/unchecked_time_subtraction.stderr +++ b/tests/ui/unchecked_time_subtraction.stderr @@ -49,5 +49,29 @@ error: unchecked subtraction of a `Duration` LL | let _ = 2 * dur1 - dur2; | ^^^^^^^^^^^^^^^ help: try: `(2 * dur1).checked_sub(dur2).unwrap()` -error: aborting due to 8 previous errors +error: unchecked subtraction of a `Duration` + --> tests/ui/unchecked_time_subtraction.rs:42:5 + | +LL | Duration::ZERO.sub(Duration::MAX); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Duration::ZERO.checked_sub(Duration::MAX).unwrap()` + +error: unchecked subtraction of a `Duration` + --> tests/ui/unchecked_time_subtraction.rs:45:13 + | +LL | let _ = Duration::ZERO - Duration::MAX; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Duration::ZERO.checked_sub(Duration::MAX).unwrap()` + +error: unchecked subtraction of a `Duration` + --> tests/ui/unchecked_time_subtraction.rs:58:5 + | +LL | duration!(0).sub(duration!(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `duration!(0).checked_sub(duration!(1)).unwrap()` + +error: unchecked subtraction of a `Duration` + --> tests/ui/unchecked_time_subtraction.rs:60:13 + | +LL | let _ = duration!(0) - duration!(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `duration!(0).checked_sub(duration!(1)).unwrap()` + +error: aborting due to 12 previous errors diff --git a/tests/ui/unnecessary_fold.fixed b/tests/ui/unnecessary_fold.fixed index 1c331be75094..c3eeafbc39cd 100644 --- a/tests/ui/unnecessary_fold.fixed +++ b/tests/ui/unnecessary_fold.fixed @@ -6,21 +6,35 @@ fn is_any(acc: bool, x: usize) -> bool { /// Calls which should trigger the `UNNECESSARY_FOLD` lint fn unnecessary_fold() { + use std::ops::{Add, Mul}; + // Can be replaced by .any let _ = (0..3).any(|x| x > 2); //~^ unnecessary_fold + // Can be replaced by .any (checking suggestion) let _ = (0..3).fold(false, is_any); //~^ redundant_closure + // Can be replaced by .all let _ = (0..3).all(|x| x > 2); //~^ unnecessary_fold + // Can be replaced by .sum let _: i32 = (0..3).sum(); //~^ unnecessary_fold + let _: i32 = (0..3).sum(); + //~^ unnecessary_fold + let _: i32 = (0..3).sum(); + //~^ unnecessary_fold + // Can be replaced by .product let _: i32 = (0..3).product(); //~^ unnecessary_fold + let _: i32 = (0..3).product(); + //~^ unnecessary_fold + let _: i32 = (0..3).product(); + //~^ unnecessary_fold } /// Should trigger the `UNNECESSARY_FOLD` lint, with an error span including exactly `.fold(...)` @@ -37,6 +51,43 @@ fn unnecessary_fold_should_ignore() { let _ = (0..3).fold(0, |acc, x| acc * x); let _ = (0..3).fold(0, |acc, x| 1 + acc + x); + struct Adder; + impl Adder { + fn add(lhs: i32, rhs: i32) -> i32 { + unimplemented!() + } + fn mul(lhs: i32, rhs: i32) -> i32 { + unimplemented!() + } + } + // `add`/`mul` are inherent methods + let _: i32 = (0..3).fold(0, Adder::add); + let _: i32 = (0..3).fold(1, Adder::mul); + + trait FakeAdd { + type Output; + fn add(self, other: Rhs) -> Self::Output; + } + impl FakeAdd for i32 { + type Output = Self; + fn add(self, other: i32) -> Self::Output { + self + other + } + } + trait FakeMul { + type Output; + fn mul(self, other: Rhs) -> Self::Output; + } + impl FakeMul for i32 { + type Output = Self; + fn mul(self, other: i32) -> Self::Output { + self * other + } + } + // `add`/`mul` come from an unrelated trait + let _: i32 = (0..3).fold(0, FakeAdd::add); + let _: i32 = (0..3).fold(1, FakeMul::mul); + // We only match against an accumulator on the left // hand side. We could lint for .sum and .product when // it's on the right, but don't for now (and this wouldn't @@ -63,6 +114,7 @@ fn unnecessary_fold_over_multiple_lines() { fn issue10000() { use std::collections::HashMap; use std::hash::BuildHasher; + use std::ops::{Add, Mul}; fn anything(_: T) {} fn num(_: i32) {} @@ -74,23 +126,56 @@ fn issue10000() { // more cases: let _ = map.values().sum::(); //~^ unnecessary_fold + let _ = map.values().sum::(); + //~^ unnecessary_fold let _ = map.values().product::(); //~^ unnecessary_fold + let _ = map.values().product::(); + //~^ unnecessary_fold + let _: i32 = map.values().sum(); + //~^ unnecessary_fold let _: i32 = map.values().sum(); //~^ unnecessary_fold let _: i32 = map.values().product(); //~^ unnecessary_fold + let _: i32 = map.values().product(); + //~^ unnecessary_fold + anything(map.values().sum::()); + //~^ unnecessary_fold anything(map.values().sum::()); //~^ unnecessary_fold anything(map.values().product::()); //~^ unnecessary_fold + anything(map.values().product::()); + //~^ unnecessary_fold num(map.values().sum()); //~^ unnecessary_fold + num(map.values().sum()); + //~^ unnecessary_fold + num(map.values().product()); + //~^ unnecessary_fold num(map.values().product()); //~^ unnecessary_fold } smoketest_map(HashMap::new()); + + fn add_turbofish_not_necessary() -> i32 { + (0..3).sum() + //~^ unnecessary_fold + } + fn mul_turbofish_not_necessary() -> i32 { + (0..3).product() + //~^ unnecessary_fold + } + fn add_turbofish_necessary() -> impl Add { + (0..3).sum::() + //~^ unnecessary_fold + } + fn mul_turbofish_necessary() -> impl Mul { + (0..3).product::() + //~^ unnecessary_fold + } } fn main() {} diff --git a/tests/ui/unnecessary_fold.rs b/tests/ui/unnecessary_fold.rs index e2050e37e3b1..6ab41a942625 100644 --- a/tests/ui/unnecessary_fold.rs +++ b/tests/ui/unnecessary_fold.rs @@ -6,21 +6,35 @@ fn is_any(acc: bool, x: usize) -> bool { /// Calls which should trigger the `UNNECESSARY_FOLD` lint fn unnecessary_fold() { + use std::ops::{Add, Mul}; + // Can be replaced by .any let _ = (0..3).fold(false, |acc, x| acc || x > 2); //~^ unnecessary_fold + // Can be replaced by .any (checking suggestion) let _ = (0..3).fold(false, |acc, x| is_any(acc, x)); //~^ redundant_closure + // Can be replaced by .all let _ = (0..3).fold(true, |acc, x| acc && x > 2); //~^ unnecessary_fold + // Can be replaced by .sum let _: i32 = (0..3).fold(0, |acc, x| acc + x); //~^ unnecessary_fold + let _: i32 = (0..3).fold(0, Add::add); + //~^ unnecessary_fold + let _: i32 = (0..3).fold(0, i32::add); + //~^ unnecessary_fold + // Can be replaced by .product let _: i32 = (0..3).fold(1, |acc, x| acc * x); //~^ unnecessary_fold + let _: i32 = (0..3).fold(1, Mul::mul); + //~^ unnecessary_fold + let _: i32 = (0..3).fold(1, i32::mul); + //~^ unnecessary_fold } /// Should trigger the `UNNECESSARY_FOLD` lint, with an error span including exactly `.fold(...)` @@ -37,6 +51,43 @@ fn unnecessary_fold_should_ignore() { let _ = (0..3).fold(0, |acc, x| acc * x); let _ = (0..3).fold(0, |acc, x| 1 + acc + x); + struct Adder; + impl Adder { + fn add(lhs: i32, rhs: i32) -> i32 { + unimplemented!() + } + fn mul(lhs: i32, rhs: i32) -> i32 { + unimplemented!() + } + } + // `add`/`mul` are inherent methods + let _: i32 = (0..3).fold(0, Adder::add); + let _: i32 = (0..3).fold(1, Adder::mul); + + trait FakeAdd { + type Output; + fn add(self, other: Rhs) -> Self::Output; + } + impl FakeAdd for i32 { + type Output = Self; + fn add(self, other: i32) -> Self::Output { + self + other + } + } + trait FakeMul { + type Output; + fn mul(self, other: Rhs) -> Self::Output; + } + impl FakeMul for i32 { + type Output = Self; + fn mul(self, other: i32) -> Self::Output { + self * other + } + } + // `add`/`mul` come from an unrelated trait + let _: i32 = (0..3).fold(0, FakeAdd::add); + let _: i32 = (0..3).fold(1, FakeMul::mul); + // We only match against an accumulator on the left // hand side. We could lint for .sum and .product when // it's on the right, but don't for now (and this wouldn't @@ -63,6 +114,7 @@ fn unnecessary_fold_over_multiple_lines() { fn issue10000() { use std::collections::HashMap; use std::hash::BuildHasher; + use std::ops::{Add, Mul}; fn anything(_: T) {} fn num(_: i32) {} @@ -74,23 +126,56 @@ fn issue10000() { // more cases: let _ = map.values().fold(0, |x, y| x + y); //~^ unnecessary_fold + let _ = map.values().fold(0, Add::add); + //~^ unnecessary_fold let _ = map.values().fold(1, |x, y| x * y); //~^ unnecessary_fold + let _ = map.values().fold(1, Mul::mul); + //~^ unnecessary_fold let _: i32 = map.values().fold(0, |x, y| x + y); //~^ unnecessary_fold + let _: i32 = map.values().fold(0, Add::add); + //~^ unnecessary_fold let _: i32 = map.values().fold(1, |x, y| x * y); //~^ unnecessary_fold + let _: i32 = map.values().fold(1, Mul::mul); + //~^ unnecessary_fold anything(map.values().fold(0, |x, y| x + y)); //~^ unnecessary_fold + anything(map.values().fold(0, Add::add)); + //~^ unnecessary_fold anything(map.values().fold(1, |x, y| x * y)); //~^ unnecessary_fold + anything(map.values().fold(1, Mul::mul)); + //~^ unnecessary_fold num(map.values().fold(0, |x, y| x + y)); //~^ unnecessary_fold + num(map.values().fold(0, Add::add)); + //~^ unnecessary_fold num(map.values().fold(1, |x, y| x * y)); //~^ unnecessary_fold + num(map.values().fold(1, Mul::mul)); + //~^ unnecessary_fold } smoketest_map(HashMap::new()); + + fn add_turbofish_not_necessary() -> i32 { + (0..3).fold(0, |acc, x| acc + x) + //~^ unnecessary_fold + } + fn mul_turbofish_not_necessary() -> i32 { + (0..3).fold(1, |acc, x| acc * x) + //~^ unnecessary_fold + } + fn add_turbofish_necessary() -> impl Add { + (0..3).fold(0, |acc, x| acc + x) + //~^ unnecessary_fold + } + fn mul_turbofish_necessary() -> impl Mul { + (0..3).fold(1, |acc, x| acc * x) + //~^ unnecessary_fold + } } fn main() {} diff --git a/tests/ui/unnecessary_fold.stderr b/tests/ui/unnecessary_fold.stderr index d82b1f39b48b..bb8aa7e18d34 100644 --- a/tests/ui/unnecessary_fold.stderr +++ b/tests/ui/unnecessary_fold.stderr @@ -1,5 +1,5 @@ error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:10:20 + --> tests/ui/unnecessary_fold.rs:12:20 | LL | let _ = (0..3).fold(false, |acc, x| acc || x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)` @@ -8,7 +8,7 @@ LL | let _ = (0..3).fold(false, |acc, x| acc || x > 2); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_fold)]` error: redundant closure - --> tests/ui/unnecessary_fold.rs:13:32 + --> tests/ui/unnecessary_fold.rs:16:32 | LL | let _ = (0..3).fold(false, |acc, x| is_any(acc, x)); | ^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `is_any` @@ -17,88 +17,184 @@ LL | let _ = (0..3).fold(false, |acc, x| is_any(acc, x)); = help: to override `-D warnings` add `#[allow(clippy::redundant_closure)]` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:16:20 + --> tests/ui/unnecessary_fold.rs:20:20 | LL | let _ = (0..3).fold(true, |acc, x| acc && x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `all(|x| x > 2)` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:19:25 + --> tests/ui/unnecessary_fold.rs:24:25 | LL | let _: i32 = (0..3).fold(0, |acc, x| acc + x); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `sum()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:22:25 + --> tests/ui/unnecessary_fold.rs:26:25 + | +LL | let _: i32 = (0..3).fold(0, Add::add); + | ^^^^^^^^^^^^^^^^^ help: try: `sum()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:28:25 + | +LL | let _: i32 = (0..3).fold(0, i32::add); + | ^^^^^^^^^^^^^^^^^ help: try: `sum()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:32:25 | LL | let _: i32 = (0..3).fold(1, |acc, x| acc * x); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `product()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:28:41 + --> tests/ui/unnecessary_fold.rs:34:25 + | +LL | let _: i32 = (0..3).fold(1, Mul::mul); + | ^^^^^^^^^^^^^^^^^ help: try: `product()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:36:25 + | +LL | let _: i32 = (0..3).fold(1, i32::mul); + | ^^^^^^^^^^^^^^^^^ help: try: `product()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:42:41 | LL | let _: bool = (0..3).map(|x| 2 * x).fold(false, |acc, x| acc || x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:59:10 + --> tests/ui/unnecessary_fold.rs:110:10 | LL | .fold(false, |acc, x| acc || x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:71:33 + --> tests/ui/unnecessary_fold.rs:123:33 | LL | assert_eq!(map.values().fold(0, |x, y| x + y), 0); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:75:30 + --> tests/ui/unnecessary_fold.rs:127:30 | LL | let _ = map.values().fold(0, |x, y| x + y); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:77:30 + --> tests/ui/unnecessary_fold.rs:129:30 + | +LL | let _ = map.values().fold(0, Add::add); + | ^^^^^^^^^^^^^^^^^ help: try: `sum::()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:131:30 | LL | let _ = map.values().fold(1, |x, y| x * y); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `product::()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:79:35 + --> tests/ui/unnecessary_fold.rs:133:30 + | +LL | let _ = map.values().fold(1, Mul::mul); + | ^^^^^^^^^^^^^^^^^ help: try: `product::()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:135:35 | LL | let _: i32 = map.values().fold(0, |x, y| x + y); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:81:35 + --> tests/ui/unnecessary_fold.rs:137:35 + | +LL | let _: i32 = map.values().fold(0, Add::add); + | ^^^^^^^^^^^^^^^^^ help: try: `sum()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:139:35 | LL | let _: i32 = map.values().fold(1, |x, y| x * y); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `product()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:83:31 + --> tests/ui/unnecessary_fold.rs:141:35 + | +LL | let _: i32 = map.values().fold(1, Mul::mul); + | ^^^^^^^^^^^^^^^^^ help: try: `product()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:143:31 | LL | anything(map.values().fold(0, |x, y| x + y)); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:85:31 + --> tests/ui/unnecessary_fold.rs:145:31 + | +LL | anything(map.values().fold(0, Add::add)); + | ^^^^^^^^^^^^^^^^^ help: try: `sum::()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:147:31 | LL | anything(map.values().fold(1, |x, y| x * y)); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `product::()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:87:26 + --> tests/ui/unnecessary_fold.rs:149:31 + | +LL | anything(map.values().fold(1, Mul::mul)); + | ^^^^^^^^^^^^^^^^^ help: try: `product::()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:151:26 | LL | num(map.values().fold(0, |x, y| x + y)); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:89:26 + --> tests/ui/unnecessary_fold.rs:153:26 + | +LL | num(map.values().fold(0, Add::add)); + | ^^^^^^^^^^^^^^^^^ help: try: `sum()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:155:26 | LL | num(map.values().fold(1, |x, y| x * y)); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `product()` -error: aborting due to 16 previous errors +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:157:26 + | +LL | num(map.values().fold(1, Mul::mul)); + | ^^^^^^^^^^^^^^^^^ help: try: `product()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:164:16 + | +LL | (0..3).fold(0, |acc, x| acc + x) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `sum()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:168:16 + | +LL | (0..3).fold(1, |acc, x| acc * x) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `product()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:172:16 + | +LL | (0..3).fold(0, |acc, x| acc + x) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:176:16 + | +LL | (0..3).fold(1, |acc, x| acc * x) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `product::()` + +error: aborting due to 32 previous errors diff --git a/tests/ui/use_self.fixed b/tests/ui/use_self.fixed index 075e31d202b0..37559f9a2367 100644 --- a/tests/ui/use_self.fixed +++ b/tests/ui/use_self.fixed @@ -10,6 +10,9 @@ clippy::needless_lifetimes, clippy::missing_transmute_annotations )] +#![allow(incomplete_features)] +#![feature(adt_const_params)] +#![feature(unsized_const_params)] #[macro_use] extern crate proc_macro_derive; @@ -769,3 +772,25 @@ mod issue_13277 { type Item<'foo> = Option>; } } + +mod issue16164 { + trait Bits { + fn bit(self) -> bool; + } + + impl Bits for u8 { + fn bit(self) -> bool { + todo!() + } + } + + trait T { + fn f(self) -> bool; + } + + impl T for u8 { + fn f(self) -> bool { + todo!() + } + } +} diff --git a/tests/ui/use_self.rs b/tests/ui/use_self.rs index 6fbba0bbc550..74abd2f61bf9 100644 --- a/tests/ui/use_self.rs +++ b/tests/ui/use_self.rs @@ -10,6 +10,9 @@ clippy::needless_lifetimes, clippy::missing_transmute_annotations )] +#![allow(incomplete_features)] +#![feature(adt_const_params)] +#![feature(unsized_const_params)] #[macro_use] extern crate proc_macro_derive; @@ -769,3 +772,25 @@ mod issue_13277 { type Item<'foo> = Option>; } } + +mod issue16164 { + trait Bits { + fn bit(self) -> bool; + } + + impl Bits for u8 { + fn bit(self) -> bool { + todo!() + } + } + + trait T { + fn f(self) -> bool; + } + + impl T for u8 { + fn f(self) -> bool { + todo!() + } + } +} diff --git a/tests/ui/use_self.stderr b/tests/ui/use_self.stderr index 5f65c53ea25c..8ce341d22d4f 100644 --- a/tests/ui/use_self.stderr +++ b/tests/ui/use_self.stderr @@ -1,5 +1,5 @@ error: unnecessary structure name repetition - --> tests/ui/use_self.rs:23:21 + --> tests/ui/use_self.rs:26:21 | LL | fn new() -> Foo { | ^^^ help: use the applicable keyword: `Self` @@ -8,247 +8,247 @@ LL | fn new() -> Foo { = help: to override `-D warnings` add `#[allow(clippy::use_self)]` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:25:13 + --> tests/ui/use_self.rs:28:13 | LL | Foo {} | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:28:22 + --> tests/ui/use_self.rs:31:22 | LL | fn test() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:30:13 + --> tests/ui/use_self.rs:33:13 | LL | Foo::new() | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:36:25 + --> tests/ui/use_self.rs:39:25 | LL | fn default() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:38:13 + --> tests/ui/use_self.rs:41:13 | LL | Foo::new() | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:80:28 + --> tests/ui/use_self.rs:83:28 | LL | fn clone(&self) -> Foo<'a> { | ^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:114:24 + --> tests/ui/use_self.rs:117:24 | LL | fn bad(foos: &[Foo]) -> impl Iterator { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:114:55 + --> tests/ui/use_self.rs:117:55 | LL | fn bad(foos: &[Foo]) -> impl Iterator { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:131:13 + --> tests/ui/use_self.rs:134:13 | LL | TS(0) | ^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:167:29 + --> tests/ui/use_self.rs:170:29 | LL | fn bar() -> Bar { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:169:21 + --> tests/ui/use_self.rs:172:21 | LL | Bar { foo: Foo {} } | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:181:21 + --> tests/ui/use_self.rs:184:21 | LL | fn baz() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:183:13 + --> tests/ui/use_self.rs:186:13 | LL | Foo {} | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:201:21 + --> tests/ui/use_self.rs:204:21 | LL | let _ = Enum::B(42); | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:203:21 + --> tests/ui/use_self.rs:206:21 | LL | let _ = Enum::C { field: true }; | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:205:21 + --> tests/ui/use_self.rs:208:21 | LL | let _ = Enum::A; | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:248:13 + --> tests/ui/use_self.rs:251:13 | LL | nested::A::fun_1(); | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:250:13 + --> tests/ui/use_self.rs:253:13 | LL | nested::A::A; | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:253:13 + --> tests/ui/use_self.rs:256:13 | LL | nested::A {}; | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:273:13 + --> tests/ui/use_self.rs:276:13 | LL | TestStruct::from_something() | ^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:288:25 + --> tests/ui/use_self.rs:291:25 | LL | async fn g() -> S { | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:290:13 + --> tests/ui/use_self.rs:293:13 | LL | S {} | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:295:16 + --> tests/ui/use_self.rs:298:16 | LL | &p[S::A..S::B] | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:295:22 + --> tests/ui/use_self.rs:298:22 | LL | &p[S::A..S::B] | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:320:29 + --> tests/ui/use_self.rs:323:29 | LL | fn foo(value: T) -> Foo { | ^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:322:13 + --> tests/ui/use_self.rs:325:13 | LL | Foo:: { value } | ^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:495:13 + --> tests/ui/use_self.rs:498:13 | LL | A::new::(submod::B {}) | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:571:17 + --> tests/ui/use_self.rs:574:17 | LL | Foo::Bar => unimplemented!(), | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:573:17 + --> tests/ui/use_self.rs:576:17 | LL | Foo::Baz => unimplemented!(), | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:580:20 + --> tests/ui/use_self.rs:583:20 | LL | if let Foo::Bar = self { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:605:17 + --> tests/ui/use_self.rs:608:17 | LL | Something::Num(n) => *n, | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:607:17 + --> tests/ui/use_self.rs:610:17 | LL | Something::TupleNums(n, _m) => *n, | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:609:17 + --> tests/ui/use_self.rs:612:17 | LL | Something::StructNums { one, two: _ } => *one, | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:616:17 + --> tests/ui/use_self.rs:619:17 | LL | crate::issue8845::Something::Num(n) => *n, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:618:17 + --> tests/ui/use_self.rs:621:17 | LL | crate::issue8845::Something::TupleNums(n, _m) => *n, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:620:17 + --> tests/ui/use_self.rs:623:17 | LL | crate::issue8845::Something::StructNums { one, two: _ } => *one, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:637:17 + --> tests/ui/use_self.rs:640:17 | LL | let Foo(x) = self; | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:643:17 + --> tests/ui/use_self.rs:646:17 | LL | let crate::issue8845::Foo(x) = self; | ^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:651:17 + --> tests/ui/use_self.rs:654:17 | LL | let Bar { x, .. } = self; | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:657:17 + --> tests/ui/use_self.rs:660:17 | LL | let crate::issue8845::Bar { x, .. } = self; | ^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:697:17 + --> tests/ui/use_self.rs:700:17 | LL | E::A => {}, | ^ help: use the applicable keyword: `Self` diff --git a/tests/ui/writeln_empty_string_unfixable.rs b/tests/ui/writeln_empty_string_unfixable.rs new file mode 100644 index 000000000000..ca570fd1fc7b --- /dev/null +++ b/tests/ui/writeln_empty_string_unfixable.rs @@ -0,0 +1,26 @@ +#![allow(unused_must_use)] +#![warn(clippy::writeln_empty_string)] + +use std::io::Write; + +// If there is a comment in the span of macro call, we don't provide an auto-fix suggestion. +#[rustfmt::skip] +fn issue_16251() { + let mut v = Vec::new(); + + writeln!(v, /* comment */ ""); + //~^ writeln_empty_string + + writeln!(v, "" /* comment */); + //~^ writeln_empty_string + + //~v writeln_empty_string + writeln!(v, + "\ + \ + " + + // there is a comment in the macro span regardless of its position + + ); +} diff --git a/tests/ui/writeln_empty_string_unfixable.stderr b/tests/ui/writeln_empty_string_unfixable.stderr new file mode 100644 index 000000000000..0ed802ba84ba --- /dev/null +++ b/tests/ui/writeln_empty_string_unfixable.stderr @@ -0,0 +1,47 @@ +error: empty string literal in `writeln!` + --> tests/ui/writeln_empty_string_unfixable.rs:11:5 + | +LL | writeln!(v, /* comment */ ""); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: remove the empty string + --> tests/ui/writeln_empty_string_unfixable.rs:11:31 + | +LL | writeln!(v, /* comment */ ""); + | ^^ + = note: `-D clippy::writeln-empty-string` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::writeln_empty_string)]` + +error: empty string literal in `writeln!` + --> tests/ui/writeln_empty_string_unfixable.rs:14:5 + | +LL | writeln!(v, "" /* comment */); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: remove the empty string + --> tests/ui/writeln_empty_string_unfixable.rs:14:17 + | +LL | writeln!(v, "" /* comment */); + | ^^ + +error: empty string literal in `writeln!` + --> tests/ui/writeln_empty_string_unfixable.rs:18:5 + | +LL | / writeln!(v, +LL | | "\ +LL | | \ +LL | | " +... | +LL | | ); + | |_____^ + | +note: remove the empty string + --> tests/ui/writeln_empty_string_unfixable.rs:19:9 + | +LL | / "\ +LL | | \ +LL | | " + | |_____________^ + +error: aborting due to 3 previous errors + diff --git a/triagebot.toml b/triagebot.toml index 09dec7675e7e..5f637205fa65 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -63,6 +63,7 @@ users_on_vacation = [ "Alexendoo", "y21", "blyxyas", + "samueltardieu", ] [assign.owners] From 70d8c6163b81d354b2ee8fcf1fc54aa11e358085 Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Thu, 25 Dec 2025 13:04:23 +0000 Subject: [PATCH 0062/1061] implement shellcheck --- src/tools/tidy/src/extra_checks/mod.rs | 21 ++++++++++++++++--- src/tools/tidy/src/extra_checks/rustdoc_js.rs | 5 +++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index 1304de16874d..1997adeda6f1 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -595,10 +595,9 @@ fn install_requirements( Ok(()) } -/// Check that shellcheck is installed then run it at the given path -fn shellcheck_runner(args: &[&OsStr]) -> Result<(), Error> { +fn has_shellcheck() -> Result<(), Error> { match Command::new("shellcheck").arg("--version").status() { - Ok(_) => (), + Ok(_) => Ok(()), Err(e) if e.kind() == io::ErrorKind::NotFound => { return Err(Error::MissingReq( "shellcheck", @@ -612,6 +611,13 @@ fn shellcheck_runner(args: &[&OsStr]) -> Result<(), Error> { } Err(e) => return Err(e.into()), } +} + +/// Check that shellcheck is installed then run it at the given path +fn shellcheck_runner(args: &[&OsStr]) -> Result<(), Error> { + if let Err(err) = has_shellcheck() { + return Err(err); + } let status = Command::new("shellcheck").args(args).status()?; if status.success() { Ok(()) } else { Err(Error::FailedCheck("shellcheck")) } @@ -772,6 +778,15 @@ impl ExtraCheckArg { ExtraCheckLang::Spellcheck => { ensure_version(build_dir, "typos", SPELLCHECK_VER).is_ok() } + ExtraCheckLang::Shell => { + has_shellcheck().is_ok() + } + ExtraCheckLang::Js => { + // implement detailed check + rustdoc_js::has_tool(build_dir, "eslint") + && rustdoc_js::has_tool(build_dir, "jslint") + && rustdoc_js::has_tool(build_dir, "tsc") + } _ => todo!("implement other checks"), } } diff --git a/src/tools/tidy/src/extra_checks/rustdoc_js.rs b/src/tools/tidy/src/extra_checks/rustdoc_js.rs index 944d8a44112f..6ad5a6665071 100644 --- a/src/tools/tidy/src/extra_checks/rustdoc_js.rs +++ b/src/tools/tidy/src/extra_checks/rustdoc_js.rs @@ -21,6 +21,11 @@ fn spawn_cmd(cmd: &mut Command) -> Result { }) } +pub(super) fn has_tool(outdir: &Path, name: &str) -> bool { + let bin_path = node_module_bin(outdir, name); + Command::new(bin_path).arg("--version").status().is_ok() +} + /// install all js dependencies from package.json. pub(super) fn npm_install(root_path: &Path, outdir: &Path, npm: &Path) -> Result<(), super::Error> { npm::install(root_path, outdir, npm)?; From 258708fa6d1fc680ff06124cbf4455e3c3d83edd Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Thu, 25 Dec 2025 23:41:37 +0000 Subject: [PATCH 0063/1061] implement js check --- src/tools/tidy/src/extra_checks/mod.rs | 29 +++++++++++++++++++------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index 1997adeda6f1..5c83a12e1e5c 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -322,7 +322,7 @@ fn check_impl( } let res = spellcheck_runner(root_path, &outdir, &cargo, &args); if res.is_err() { - rerun_with_bless("spellcheck", "fix typos"); + rerun_with_bless("spellcheck", "fix typechecktypos"); } res?; } @@ -778,14 +778,27 @@ impl ExtraCheckArg { ExtraCheckLang::Spellcheck => { ensure_version(build_dir, "typos", SPELLCHECK_VER).is_ok() } - ExtraCheckLang::Shell => { - has_shellcheck().is_ok() - } + ExtraCheckLang::Shell => has_shellcheck().is_ok(), ExtraCheckLang::Js => { - // implement detailed check - rustdoc_js::has_tool(build_dir, "eslint") - && rustdoc_js::has_tool(build_dir, "jslint") - && rustdoc_js::has_tool(build_dir, "tsc") + match self.kind { + Some(ExtraCheckKind::Lint) => { + // If Lint is enabled, check both eslint and es-check. + rustdoc_js::has_tool(build_dir, "eslint") + && rustdoc_js::has_tool(build_dir, "es-check") + } + Some(ExtraCheckKind::Typecheck) => { + // If Typecheck is enabled, check tsc. + rustdoc_js::has_tool(build_dir, "tsc") + } + None => { + // No kind means it will check both Lint and Typecheck. + rustdoc_js::has_tool(build_dir, "eslint") + && rustdoc_js::has_tool(build_dir, "es-check") + && rustdoc_js::has_tool(build_dir, "tsc") + } + // Unreachable. + Some(_) => false, + } } _ => todo!("implement other checks"), } From a6b005a0c82c223c1f6c8e6d2d11f1f1a211a703 Mon Sep 17 00:00:00 2001 From: andjsrk Date: Fri, 26 Dec 2025 10:12:18 +0900 Subject: [PATCH 0064/1061] fix `Expr::can_have_side_effects` for repeat and binary expressions --- compiler/rustc_hir/src/hir.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e176c703b33e..0898afef47e5 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2618,6 +2618,12 @@ impl Expr<'_> { // them being used only for its side-effects. base.can_have_side_effects() } + ExprKind::Binary(_, lhs, rhs) => { + // This isn't exactly true for all `Binary`, but we are using this + // method exclusively for diagnostics and there's a *cultural* pressure against + // them being used only for its side-effects. + lhs.can_have_side_effects() || rhs.can_have_side_effects() + } ExprKind::Struct(_, fields, init) => { let init_side_effects = match init { StructTailExpr::Base(init) => init.can_have_side_effects(), @@ -2640,13 +2646,13 @@ impl Expr<'_> { }, args, ) => args.iter().any(|arg| arg.can_have_side_effects()), + ExprKind::Repeat(arg, _) => arg.can_have_side_effects(), ExprKind::If(..) | ExprKind::Match(..) | ExprKind::MethodCall(..) | ExprKind::Call(..) | ExprKind::Closure { .. } | ExprKind::Block(..) - | ExprKind::Repeat(..) | ExprKind::Break(..) | ExprKind::Continue(..) | ExprKind::Ret(..) @@ -2657,7 +2663,6 @@ impl Expr<'_> { | ExprKind::InlineAsm(..) | ExprKind::AssignOp(..) | ExprKind::ConstBlock(..) - | ExprKind::Binary(..) | ExprKind::Yield(..) | ExprKind::DropTemps(..) | ExprKind::Err(_) => true, From ec9174248dbcd6bbce4512b6455c99aa714e3c1c Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Mon, 22 Dec 2025 03:20:08 +0100 Subject: [PATCH 0065/1061] Fix `multiple_inherent_impl` false negatives for generic impl blocks --- clippy_lints/src/inherent_impl.rs | 23 +++++--- tests/ui/impl.rs | 42 +++++++++++++-- tests/ui/impl.stderr | 90 ++++++++++++++++++++++++++++--- 3 files changed, 138 insertions(+), 17 deletions(-) diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index f59c7615d745..14928a1be13b 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -101,7 +101,21 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { InherentImplLintScope::Crate => Criterion::Crate, }; let is_test = is_cfg_test(cx.tcx, hir_id) || is_in_cfg_test(cx.tcx, hir_id); - match type_map.entry((impl_ty, criterion, is_test)) { + let predicates = { + // Gets the predicates (bounds) for the given impl block, + // sorted for consistent comparison to allow distinguishing between impl blocks + // with different generic bounds. + let mut predicates = cx + .tcx + .predicates_of(impl_id) + .predicates + .iter() + .map(|(clause, _)| *clause) + .collect::>(); + predicates.sort_by_key(|c| format!("{c:?}")); + predicates + }; + match type_map.entry((impl_ty, predicates, criterion, is_test)) { Entry::Vacant(e) => { // Store the id for the first impl block of this type. The span is retrieved lazily. e.insert(IdOrSpan::Id(impl_id)); @@ -152,15 +166,12 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { fn get_impl_span(cx: &LateContext<'_>, id: LocalDefId) -> Option { let id = cx.tcx.local_def_id_to_hir_id(id); if let Node::Item(&Item { - kind: ItemKind::Impl(impl_item), + kind: ItemKind::Impl(_), span, .. }) = cx.tcx.hir_node(id) { - (!span.from_expansion() - && impl_item.generics.params.is_empty() - && !fulfill_or_allowed(cx, MULTIPLE_INHERENT_IMPL, [id])) - .then_some(span) + (!span.from_expansion() && !fulfill_or_allowed(cx, MULTIPLE_INHERENT_IMPL, [id])).then_some(span) } else { None } diff --git a/tests/ui/impl.rs b/tests/ui/impl.rs index e6044cc50781..75761a34c86e 100644 --- a/tests/ui/impl.rs +++ b/tests/ui/impl.rs @@ -14,6 +14,7 @@ impl MyStruct { } impl<'a> MyStruct { + //~^ multiple_inherent_impl fn lifetimed() {} } @@ -90,10 +91,12 @@ struct Lifetime<'s> { } impl Lifetime<'_> {} -impl Lifetime<'_> {} // false negative +impl Lifetime<'_> {} +//~^ multiple_inherent_impl impl<'a> Lifetime<'a> {} -impl<'a> Lifetime<'a> {} // false negative +impl<'a> Lifetime<'a> {} +//~^ multiple_inherent_impl impl<'b> Lifetime<'b> {} // false negative? @@ -104,6 +107,39 @@ struct Generic { } impl Generic {} -impl Generic {} // false negative +impl Generic {} +//~^ multiple_inherent_impl + +use std::fmt::Debug; + +#[derive(Debug)] +struct GenericWithBounds(T); + +impl GenericWithBounds { + fn make_one(_one: T) -> Self { + todo!() + } +} + +impl GenericWithBounds { + //~^ multiple_inherent_impl + fn make_two(_two: T) -> Self { + todo!() + } +} + +struct MultipleTraitBounds(T); + +impl MultipleTraitBounds { + fn debug_fn() {} +} + +impl MultipleTraitBounds { + fn clone_fn() {} +} + +impl MultipleTraitBounds { + fn debug_clone_fn() {} +} fn main() {} diff --git a/tests/ui/impl.stderr b/tests/ui/impl.stderr index 93d4b3998f90..9c4aaf183d70 100644 --- a/tests/ui/impl.stderr +++ b/tests/ui/impl.stderr @@ -19,7 +19,24 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::multiple_inherent_impl)]` error: multiple implementations of this structure - --> tests/ui/impl.rs:26:5 + --> tests/ui/impl.rs:16:1 + | +LL | / impl<'a> MyStruct { +LL | | +LL | | fn lifetimed() {} +LL | | } + | |_^ + | +note: first implementation here + --> tests/ui/impl.rs:6:1 + | +LL | / impl MyStruct { +LL | | fn first() {} +LL | | } + | |_^ + +error: multiple implementations of this structure + --> tests/ui/impl.rs:27:5 | LL | / impl super::MyStruct { LL | | @@ -37,7 +54,7 @@ LL | | } | |_^ error: multiple implementations of this structure - --> tests/ui/impl.rs:48:1 + --> tests/ui/impl.rs:49:1 | LL | / impl WithArgs { LL | | @@ -47,7 +64,7 @@ LL | | } | |_^ | note: first implementation here - --> tests/ui/impl.rs:45:1 + --> tests/ui/impl.rs:46:1 | LL | / impl WithArgs { LL | | fn f2() {} @@ -55,28 +72,85 @@ LL | | } | |_^ error: multiple implementations of this structure - --> tests/ui/impl.rs:71:1 + --> tests/ui/impl.rs:72:1 | LL | impl OneAllowedImpl {} | ^^^^^^^^^^^^^^^^^^^^^^ | note: first implementation here - --> tests/ui/impl.rs:68:1 + --> tests/ui/impl.rs:69:1 | LL | impl OneAllowedImpl {} | ^^^^^^^^^^^^^^^^^^^^^^ error: multiple implementations of this structure - --> tests/ui/impl.rs:84:1 + --> tests/ui/impl.rs:85:1 | LL | impl OneExpected {} | ^^^^^^^^^^^^^^^^^^^ | note: first implementation here - --> tests/ui/impl.rs:81:1 + --> tests/ui/impl.rs:82:1 | LL | impl OneExpected {} | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 5 previous errors +error: multiple implementations of this structure + --> tests/ui/impl.rs:94:1 + | +LL | impl Lifetime<'_> {} + | ^^^^^^^^^^^^^^^^^^^^ + | +note: first implementation here + --> tests/ui/impl.rs:93:1 + | +LL | impl Lifetime<'_> {} + | ^^^^^^^^^^^^^^^^^^^^ + +error: multiple implementations of this structure + --> tests/ui/impl.rs:98:1 + | +LL | impl<'a> Lifetime<'a> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first implementation here + --> tests/ui/impl.rs:97:1 + | +LL | impl<'a> Lifetime<'a> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: multiple implementations of this structure + --> tests/ui/impl.rs:110:1 + | +LL | impl Generic {} + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: first implementation here + --> tests/ui/impl.rs:109:1 + | +LL | impl Generic {} + | ^^^^^^^^^^^^^^^^^^^^^ + +error: multiple implementations of this structure + --> tests/ui/impl.rs:124:1 + | +LL | / impl GenericWithBounds { +LL | | +LL | | fn make_two(_two: T) -> Self { +LL | | todo!() +LL | | } +LL | | } + | |_^ + | +note: first implementation here + --> tests/ui/impl.rs:118:1 + | +LL | / impl GenericWithBounds { +LL | | fn make_one(_one: T) -> Self { +LL | | todo!() +LL | | } +LL | | } + | |_^ + +error: aborting due to 10 previous errors From e12e19d98c1206f44dbf1ade6debf53f15f9ad66 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Fri, 26 Dec 2025 03:44:09 +0100 Subject: [PATCH 0066/1061] fix double_parens FP on macro repetition patterns --- clippy_lints/src/double_parens.rs | 2 ++ tests/ui/double_parens.fixed | 16 ++++++++++++++++ tests/ui/double_parens.rs | 16 ++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index 8defbeeaa5f2..351d29d87432 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -114,6 +114,8 @@ fn check_source(cx: &EarlyContext<'_>, inner: &Expr) -> bool { && inner.starts_with('(') && inner.ends_with(')') && outer_after_inner.trim_start().starts_with(')') + // Don't lint macro repetition patterns like `($($result),*)` where parens are necessary + && !inner.trim_start_matches('(').trim_start().starts_with("$(") { true } else { diff --git a/tests/ui/double_parens.fixed b/tests/ui/double_parens.fixed index 024af6840132..ef7838491f8f 100644 --- a/tests/ui/double_parens.fixed +++ b/tests/ui/double_parens.fixed @@ -161,4 +161,20 @@ fn issue15940() { pub struct Person; } +fn issue16224() { + fn test() -> i32 { 42 } + + macro_rules! call { + ($matcher:pat $(=> $result:expr)?) => { + match test() { + $matcher => Result::Ok(($($result),*)), + _ => Result::Err("No match".to_string()), + } + }; + } + + let _: Result<(), String> = call!(_); + let _: Result = call!(_ => 42); +} + fn main() {} diff --git a/tests/ui/double_parens.rs b/tests/ui/double_parens.rs index 8a76f2837f35..07eafdf69575 100644 --- a/tests/ui/double_parens.rs +++ b/tests/ui/double_parens.rs @@ -161,4 +161,20 @@ fn issue15940() { pub struct Person; } +fn issue16224() { + fn test() -> i32 { 42 } + + macro_rules! call { + ($matcher:pat $(=> $result:expr)?) => { + match test() { + $matcher => Result::Ok(($($result),*)), + _ => Result::Err("No match".to_string()), + } + }; + } + + let _: Result<(), String> = call!(_); + let _: Result = call!(_ => 42); +} + fn main() {} From 86405fb507bef835470b0c678de80bc35d7ea514 Mon Sep 17 00:00:00 2001 From: Shinonn Date: Fri, 5 Dec 2025 11:02:17 +0700 Subject: [PATCH 0067/1061] Fix ICE by rejecting const blocks in patterns during AST lowering This fixes the ICE reported by rejecting `const` blocks in pattern position during AST lowering. Previously, `ExprKind::ConstBlock` could reach HIR as `PatExprKind::ConstBlock`, allowing invalid patterns to be type-checked and triggering an ICE. This patch removes the lowering path for const blocks in patterns and emits a proper diagnostic instead. A new UI test is added to ensure the compiler reports a regular error and to prevent regressions. --- clippy_lints/src/utils/author.rs | 1 - clippy_utils/src/consts.rs | 1 - clippy_utils/src/hir_utils.rs | 4 +--- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 03cbb0311c6c..9a5fd125a400 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -723,7 +723,6 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { kind!("Lit {{ ref {lit}, {negated} }}"); self.lit(lit); }, - PatExprKind::ConstBlock(_) => kind!("ConstBlock(_)"), PatExprKind::Path(_) => self.maybe_path(pat), } } diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 7e3fa4f9909b..325fc85baa4e 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -578,7 +578,6 @@ impl<'tcx> ConstEvalCtxt<'tcx> { Some(val) } }, - PatExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.tcx.hir_body(*body).value), PatExprKind::Path(qpath) => self.qpath(qpath, pat_expr.hir_id), } } diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index c6d82c0e63fa..581209c68f18 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -506,9 +506,8 @@ impl HirEqInterExpr<'_, '_, '_> { negated: right_neg, }, ) => left_neg == right_neg && left.node == right.node, - (PatExprKind::ConstBlock(left), PatExprKind::ConstBlock(right)) => self.eq_body(left.body, right.body), (PatExprKind::Path(left), PatExprKind::Path(right)) => self.eq_qpath(left, right), - (PatExprKind::Lit { .. } | PatExprKind::ConstBlock(..) | PatExprKind::Path(..), _) => false, + (PatExprKind::Lit { .. } | PatExprKind::Path(..), _) => false, } } @@ -1102,7 +1101,6 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { lit.node.hash(&mut self.s); negated.hash(&mut self.s); }, - PatExprKind::ConstBlock(c) => self.hash_body(c.body), PatExprKind::Path(qpath) => self.hash_qpath(qpath), } } From 5642a2d322937b2ea85856f0c4e0949d63f41d8c Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Fri, 26 Dec 2025 14:28:05 +0000 Subject: [PATCH 0068/1061] implement py and cpp --- src/tools/tidy/src/extra_checks/mod.rs | 43 ++++++++++++++++---------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index 5c83a12e1e5c..d5b360cbe549 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -122,7 +122,7 @@ fn check_impl( }); } if lint_args.iter().any(|ck| ck.if_installed) { - lint_args.retain(|ck| ck.is_non_if_installed_or_matches(outdir)); + lint_args.retain(|ck| ck.is_non_if_installed_or_matches(root_path, outdir)); } macro_rules! extra_check { @@ -322,7 +322,7 @@ fn check_impl( } let res = spellcheck_runner(root_path, &outdir, &cargo, &args); if res.is_err() { - rerun_with_bless("spellcheck", "fix typechecktypos"); + rerun_with_bless("spellcheck", "fix typos"); } res?; } @@ -425,21 +425,11 @@ fn py_runner( /// Create a virtuaenv at a given path if it doesn't already exist, or validate /// the install if it does. Returns the path to that venv's python executable. fn get_or_create_venv(venv_path: &Path, src_reqs_path: &Path) -> Result { - let mut should_create = true; - let dst_reqs_path = venv_path.join("requirements.txt"); let mut py_path = venv_path.to_owned(); py_path.extend(REL_PY_PATH); - if let Ok(req) = fs::read_to_string(&dst_reqs_path) { - if req == fs::read_to_string(src_reqs_path)? { - // found existing environment - should_create = false; - } else { - eprintln!("requirements.txt file mismatch, recreating environment"); - } - } - - if should_create { + if !has_py_tools(venv_path, src_reqs_path)? { + let dst_reqs_path = venv_path.join("requirements.txt"); eprintln!("removing old virtual environment"); if venv_path.is_dir() { fs::remove_dir_all(venv_path).unwrap_or_else(|_| { @@ -454,6 +444,18 @@ fn get_or_create_venv(venv_path: &Path, src_reqs_path: &Path) -> Result Result { + let dst_reqs_path = venv_path.join("requirements.txt"); + if let Ok(req) = fs::read_to_string(&dst_reqs_path) { + if req == fs::read_to_string(src_reqs_path)? { + return Ok(true); + } + eprintln!("requirements.txt file mismatch"); + } + + Ok(false) +} + /// Attempt to create a virtualenv at this path. Cycles through all expected /// valid python versions to find one that is installed. fn create_venv_at_path(path: &Path) -> Result<(), Error> { @@ -769,7 +771,7 @@ impl ExtraCheckArg { self.lang == lang && self.kind.map(|k| k == kind).unwrap_or(true) } - fn is_non_if_installed_or_matches(&self, build_dir: &Path) -> bool { + fn is_non_if_installed_or_matches(&self, root_path: &Path, build_dir: &Path) -> bool { if !self.if_installed { return true; } @@ -800,7 +802,16 @@ impl ExtraCheckArg { Some(_) => false, } } - _ => todo!("implement other checks"), + ExtraCheckLang::Py | ExtraCheckLang::Cpp => { + let venv_path = build_dir.join("venv"); + let mut reqs_path = root_path.to_owned(); + reqs_path.extend(PIP_REQ_PATH); + let Ok(v) = has_py_tools(&venv_path, &reqs_path) else { + return false; + }; + + v + } } } From 871cc746297de1a0837a7dfbfdb659cd5b1225fb Mon Sep 17 00:00:00 2001 From: cyrgani Date: Fri, 26 Dec 2025 22:08:18 +0000 Subject: [PATCH 0069/1061] move `multiple_bound_locations` to style --- clippy_lints/src/multiple_bound_locations.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/multiple_bound_locations.rs b/clippy_lints/src/multiple_bound_locations.rs index 741f38f97560..5b6b4f112455 100644 --- a/clippy_lints/src/multiple_bound_locations.rs +++ b/clippy_lints/src/multiple_bound_locations.rs @@ -31,7 +31,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.78.0"] pub MULTIPLE_BOUND_LOCATIONS, - suspicious, + style, "defining generic bounds in multiple locations" } From f2b640accb0f4364ef3e189b34af03ebabe8dea7 Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Sat, 27 Dec 2025 09:08:00 +0000 Subject: [PATCH 0070/1061] map error from cmd.spawn in npm::install If the tool (yarn) does not exists, spawn() raise an error, but the error message is just like a `No such file or directory`. So it is hard to understand which application/file/directory has a problem. This commit maps the error to expose the problem is around yarn. --- src/build_helper/src/npm.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/build_helper/src/npm.rs b/src/build_helper/src/npm.rs index f250ced4dc8a..2a558b5618b3 100644 --- a/src/build_helper/src/npm.rs +++ b/src/build_helper/src/npm.rs @@ -22,7 +22,16 @@ pub fn install(src_root_path: &Path, out_dir: &Path, yarn: &Path) -> Result::from(format!( + "unable to run yarn: {}", + err.kind() + ))) + })? + .wait()?; if !exit_status.success() { eprintln!("yarn install did not exit successfully"); return Err(io::Error::other(Box::::from(format!( From 5a4f1c33042903a2fc25c205ae588b47605fc049 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 27 Dec 2025 12:04:28 +0200 Subject: [PATCH 0071/1061] put back line numbers --- src/doc/rustc-dev-guide/ci/date-check/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/ci/date-check/src/main.rs b/src/doc/rustc-dev-guide/ci/date-check/src/main.rs index bdf727b09ebe..c9f349147e79 100644 --- a/src/doc/rustc-dev-guide/ci/date-check/src/main.rs +++ b/src/doc/rustc-dev-guide/ci/date-check/src/main.rs @@ -159,7 +159,7 @@ fn main() { let url = format!( "https://github.com/rust-lang/rustc-dev-guide/blob/main/{path}?plain=1#L{line}" ); - println!(" - [ ] [{date}]({url})"); + println!(" - [ ] {date} [line {line}]({url})"); } } println!(); From 287d4dfde770b50171ddba9f9567967200a6b5b3 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 27 Dec 2025 12:29:12 +0200 Subject: [PATCH 0072/1061] make ci step more simple --- src/doc/rustc-dev-guide/.github/workflows/date-check.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/.github/workflows/date-check.yml b/src/doc/rustc-dev-guide/.github/workflows/date-check.yml index 3bac68d23b74..e26dec6ce25d 100644 --- a/src/doc/rustc-dev-guide/.github/workflows/date-check.yml +++ b/src/doc/rustc-dev-guide/.github/workflows/date-check.yml @@ -22,9 +22,7 @@ jobs: rustup update stable - name: Run `date-check` - working-directory: ci/date-check - run: | - cargo run -- ../../src/ > ../../date-check-output.txt + run: cargo run --manifest-path ci/date-check/Cargo.toml . > date-check-output.txt - name: Open issue uses: actions/github-script@v7 From 8fc2acadae8c72a007707b2e9011b39200ab0bc4 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Sat, 27 Dec 2025 13:44:30 +0000 Subject: [PATCH 0073/1061] test and document that `proc_macro::Ident` is NFC-normalized --- library/proc_macro/src/lib.rs | 4 ++ tests/ui/proc-macro/auxiliary/api/ident.rs | 37 +++++++++++++++++++ .../auxiliary/api/proc_macro_api_tests.rs | 2 + 3 files changed, 43 insertions(+) create mode 100644 tests/ui/proc-macro/auxiliary/api/ident.rs diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 735986683d11..a005f743ddfa 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -1038,6 +1038,8 @@ impl Ident { /// The `string` argument must be a valid identifier permitted by the /// language (including keywords, e.g. `self` or `fn`). Otherwise, the function will panic. /// + /// The constructed identifier will be NFC-normalized. See the [Reference] for more info. + /// /// Note that `span`, currently in rustc, configures the hygiene information /// for this identifier. /// @@ -1052,6 +1054,8 @@ impl Ident { /// /// Due to the current importance of hygiene this constructor, unlike other /// tokens, requires a `Span` to be specified at construction. + /// + /// [Reference]: https://doc.rust-lang.org/nightly/reference/identifiers.html#r-ident.normalization #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn new(string: &str, span: Span) -> Ident { Ident(bridge::Ident { diff --git a/tests/ui/proc-macro/auxiliary/api/ident.rs b/tests/ui/proc-macro/auxiliary/api/ident.rs new file mode 100644 index 000000000000..4451b896b65c --- /dev/null +++ b/tests/ui/proc-macro/auxiliary/api/ident.rs @@ -0,0 +1,37 @@ +use proc_macro::{Ident, Span}; + +// FIXME: `Ident` does not yet implement `PartialEq` directly (#146553) +fn assert_eq(l: Ident, r: Ident) { + assert_eq!(l.to_string(), r.to_string()); +} + +fn assert_ne(l: Ident, r: Ident) { + assert_ne!(l.to_string(), r.to_string()); +} + +fn new(s: &str) -> Ident { + Ident::new(s, Span::call_site()) +} + +fn new_raw(s: &str) -> Ident { + Ident::new_raw(s, Span::call_site()) +} + +const LATIN_CAPITAL_LETTER_K: &str = "K"; +const KELVIN_SIGN: &str = "K"; + +const NORMAL_MIDDLE_DOT: &str = "L·L"; +const GREEK_ANO_TELEIA: &str = "L·L"; + +pub fn test() { + assert_eq(new("foo"), new("foo")); + assert_ne(new("foo"), new_raw("foo")); + + assert_ne!(LATIN_CAPITAL_LETTER_K, KELVIN_SIGN); + assert_eq(new(LATIN_CAPITAL_LETTER_K), new(KELVIN_SIGN)); + assert_eq(new_raw(LATIN_CAPITAL_LETTER_K), new_raw(KELVIN_SIGN)); + + assert_ne!(NORMAL_MIDDLE_DOT, GREEK_ANO_TELEIA); + assert_eq(new(NORMAL_MIDDLE_DOT), new(GREEK_ANO_TELEIA)); + assert_eq(new_raw(NORMAL_MIDDLE_DOT), new_raw(GREEK_ANO_TELEIA)); +} diff --git a/tests/ui/proc-macro/auxiliary/api/proc_macro_api_tests.rs b/tests/ui/proc-macro/auxiliary/api/proc_macro_api_tests.rs index abd667d8ce1d..4083604e1885 100644 --- a/tests/ui/proc-macro/auxiliary/api/proc_macro_api_tests.rs +++ b/tests/ui/proc-macro/auxiliary/api/proc_macro_api_tests.rs @@ -6,6 +6,7 @@ extern crate proc_macro; mod cmp; +mod ident; mod literal; use proc_macro::TokenStream; @@ -15,6 +16,7 @@ pub fn run(input: TokenStream) -> TokenStream { assert!(input.is_empty()); cmp::test(); + ident::test(); literal::test(); TokenStream::new() From bc2853f4c1d2d39efca5898fbe188f25ec778ece Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sat, 27 Dec 2025 14:34:20 -0500 Subject: [PATCH 0074/1061] do not suggest method call removal if it changes receiver type --- .../src/error_reporting/traits/suggestions.rs | 28 +++++++++++++------ .../argument-with-unnecessary-method-call.rs | 8 ++++++ ...gument-with-unnecessary-method-call.stderr | 16 +++++++++-- 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index d14ff2c3b7e2..c5b014293f98 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -4069,15 +4069,25 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { )) && expr.span.hi() != rcvr.span.hi() { - err.span_suggestion_verbose( - expr.span.with_lo(rcvr.span.hi()), - format!( - "consider removing this method call, as the receiver has type `{ty}` and \ - `{pred}` trivially holds", - ), - "", - Applicability::MaybeIncorrect, - ); + match tcx.hir_node(call_hir_id) { + // Do not suggest removing a method call if the argument is the receiver of the parent call: + // `x.a().b()`, suggesting removing `.a()` would change the type and could make `.b()` unavailable. + Node::Expr(hir::Expr { + kind: hir::ExprKind::MethodCall(_, call_receiver, _, _), + .. + }) if call_receiver.hir_id == arg_hir_id => {} + _ => { + err.span_suggestion_verbose( + expr.span.with_lo(rcvr.span.hi()), + format!( + "consider removing this method call, as the receiver has type `{ty}` and \ + `{pred}` trivially holds", + ), + "", + Applicability::MaybeIncorrect, + ); + } + } } if let hir::Expr { kind: hir::ExprKind::Block(block, _), .. } = expr { let inner_expr = expr.peel_blocks(); diff --git a/tests/ui/trait-bounds/argument-with-unnecessary-method-call.rs b/tests/ui/trait-bounds/argument-with-unnecessary-method-call.rs index d8fd1d44a985..37fa01692053 100644 --- a/tests/ui/trait-bounds/argument-with-unnecessary-method-call.rs +++ b/tests/ui/trait-bounds/argument-with-unnecessary-method-call.rs @@ -9,3 +9,11 @@ fn main() { //~| HELP try using a fully qualified path to specify the expected types //~| HELP consider removing this method call, as the receiver has type `Bar` and `Bar: From` trivially holds } + +// regression test for https://github.com/rust-lang/rust/issues/149487. +fn quux() { + let mut tx_heights: std::collections::BTreeMap<(), Option<()>> = <_>::default(); + tx_heights.get(&()).unwrap_or_default(); + //~^ ERROR the trait bound `&Option<()>: Default` is not satisfied + //~| HELP: the trait `Default` is implemented for `Option` +} diff --git a/tests/ui/trait-bounds/argument-with-unnecessary-method-call.stderr b/tests/ui/trait-bounds/argument-with-unnecessary-method-call.stderr index 7d795581ea9d..f0c993125279 100644 --- a/tests/ui/trait-bounds/argument-with-unnecessary-method-call.stderr +++ b/tests/ui/trait-bounds/argument-with-unnecessary-method-call.stderr @@ -23,6 +23,18 @@ LL - qux(Bar.into()); LL + qux(Bar); | -error: aborting due to 1 previous error +error[E0277]: the trait bound `&Option<()>: Default` is not satisfied + --> $DIR/argument-with-unnecessary-method-call.rs:16:25 + | +LL | tx_heights.get(&()).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `&Option<()>` + | +help: the trait `Default` is implemented for `Option` + --> $SRC_DIR/core/src/option.rs:LL:COL +note: required by a bound in `Option::::unwrap_or_default` + --> $SRC_DIR/core/src/option.rs:LL:COL -For more information about this error, try `rustc --explain E0283`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0283. +For more information about an error, try `rustc --explain E0277`. From 1c7d3f0ff627e4e7a4587eb4b4de3eed158f6982 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 27 Dec 2025 19:46:42 +0300 Subject: [PATCH 0075/1061] resolve: Preserve binding scopes in ambiguity errors It allows to get rid of `AmbiguityErrorMisc` and `Flags`. --- Cargo.lock | 1 - compiler/rustc_resolve/Cargo.toml | 1 - compiler/rustc_resolve/src/diagnostics.rs | 76 ++++++++------- compiler/rustc_resolve/src/ident.rs | 113 ++++++++-------------- compiler/rustc_resolve/src/lib.rs | 20 +--- 5 files changed, 85 insertions(+), 126 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9e4b2915feff..a1625311d292 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4574,7 +4574,6 @@ dependencies = [ name = "rustc_resolve" version = "0.0.0" dependencies = [ - "bitflags", "indexmap", "itertools", "pulldown-cmark", diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index eb98a6e85c06..dd15e879c644 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -5,7 +5,6 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags = "2.4.1" indexmap = "2.4.0" itertools = "0.12" pulldown-cmark = { version = "0.11", features = ["html"], default-features = false } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index b0cdfe8ab87d..8f20b5fe5745 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -44,7 +44,7 @@ use crate::errors::{ use crate::imports::{Import, ImportKind}; use crate::late::{DiagMetadata, PatternSource, Rib}; use crate::{ - AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingError, BindingKey, Finalize, + AmbiguityError, AmbiguityKind, BindingError, BindingKey, Finalize, ForwardGenericParamBanReason, HasGenericParams, LexicalScopeBinding, MacroRulesScope, Module, ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, ResolutionError, Resolver, Scope, ScopeSet, Segment, UseError, Used, @@ -1968,23 +1968,24 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { true } - fn binding_description(&self, b: NameBinding<'_>, ident: Ident, from_prelude: bool) -> String { + fn binding_description(&self, b: NameBinding<'_>, ident: Ident, scope: Scope<'_>) -> String { let res = b.res(); if b.span.is_dummy() || !self.tcx.sess.source_map().is_span_accessible(b.span) { - // These already contain the "built-in" prefix or look bad with it. - let add_built_in = - !matches!(b.res(), Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod); - let (built_in, from) = if from_prelude { - ("", " from prelude") - } else if b.is_extern_crate() - && !b.is_import() - && self.tcx.sess.opts.externs.get(ident.as_str()).is_some() - { - ("", " passed with `--extern`") - } else if add_built_in { - (" built-in", "") - } else { - ("", "") + let (built_in, from) = match scope { + Scope::StdLibPrelude | Scope::MacroUsePrelude => ("", " from prelude"), + Scope::ExternPreludeFlags + if self.tcx.sess.opts.externs.get(ident.as_str()).is_some() => + { + ("", " passed with `--extern`") + } + _ => { + if matches!(res, Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod) { + // These already contain the "built-in" prefix or look bad with it. + ("", "") + } else { + (" built-in", "") + } + } }; let a = if built_in.is_empty() { res.article() } else { "a" }; @@ -1996,22 +1997,24 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } fn ambiguity_diagnostic(&self, ambiguity_error: &AmbiguityError<'ra>) -> errors::Ambiguity { - let AmbiguityError { kind, ident, b1, b2, misc1, misc2, .. } = *ambiguity_error; + let AmbiguityError { kind, ident, b1, b2, scope1, scope2, .. } = *ambiguity_error; let extern_prelude_ambiguity = || { - self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)).is_some_and(|entry| { - entry.item_binding.map(|(b, _)| b) == Some(b1) - && entry.flag_binding.as_ref().and_then(|pb| pb.get().0.binding()) == Some(b2) - }) + // Note: b1 may come from a module scope, as an extern crate item in module. + matches!(scope2, Scope::ExternPreludeFlags) + && self + .extern_prelude + .get(&Macros20NormalizedIdent::new(ident)) + .is_some_and(|entry| entry.item_binding.map(|(b, _)| b) == Some(b1)) }; - let (b1, b2, misc1, misc2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() { + let (b1, b2, scope1, scope2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() { // We have to print the span-less alternative first, otherwise formatting looks bad. - (b2, b1, misc2, misc1, true) + (b2, b1, scope2, scope1, true) } else { - (b1, b2, misc1, misc2, false) + (b1, b2, scope1, scope2, false) }; - let could_refer_to = |b: NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| { - let what = self.binding_description(b, ident, misc == AmbiguityErrorMisc::FromPrelude); + let could_refer_to = |b: NameBinding<'_>, scope: Scope<'ra>, also: &str| { + let what = self.binding_description(b, ident, scope); let note_msg = format!("`{ident}` could{also} refer to {what}"); let thing = b.res().descr(); @@ -2029,12 +2032,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { { help_msgs.push(format!("use `::{ident}` to refer to this {thing} unambiguously")) } - match misc { - AmbiguityErrorMisc::SuggestCrate => help_msgs - .push(format!("use `crate::{ident}` to refer to this {thing} unambiguously")), - AmbiguityErrorMisc::SuggestSelf => help_msgs - .push(format!("use `self::{ident}` to refer to this {thing} unambiguously")), - AmbiguityErrorMisc::FromPrelude | AmbiguityErrorMisc::None => {} + + if let Scope::Module(module, _) = scope { + if module == self.graph_root { + help_msgs.push(format!( + "use `crate::{ident}` to refer to this {thing} unambiguously" + )); + } else if module != self.empty_module && module.is_normal() { + help_msgs.push(format!( + "use `self::{ident}` to refer to this {thing} unambiguously" + )); + } } ( @@ -2049,8 +2057,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .collect::>(), ) }; - let (b1_note, b1_help_msgs) = could_refer_to(b1, misc1, ""); - let (b2_note, b2_help_msgs) = could_refer_to(b2, misc2, " also"); + let (b1_note, b1_help_msgs) = could_refer_to(b1, scope1, ""); + let (b2_note, b2_help_msgs) = could_refer_to(b2, scope2, " also"); errors::Ambiguity { ident, diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index f4a594a4731d..13359dc9ab52 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -19,10 +19,10 @@ use crate::late::{ }; use crate::macros::{MacroRulesScope, sub_namespace_match}; use crate::{ - AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingKey, CmResolver, Determinacy, - Finalize, ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot, - NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res, ResolutionError, - Resolver, Scope, ScopeSet, Segment, Stage, Used, errors, + AmbiguityError, AmbiguityKind, BindingKey, CmResolver, Determinacy, Finalize, ImportKind, + LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, + ParentScope, PathResult, PrivacyError, Res, ResolutionError, Resolver, Scope, ScopeSet, + Segment, Stage, Used, errors, }; #[derive(Copy, Clone)] @@ -43,17 +43,6 @@ enum Shadowing { Unrestricted, } -bitflags::bitflags! { - #[derive(Clone, Copy)] - struct Flags: u8 { - const MACRO_RULES = 1 << 0; - const MODULE = 1 << 1; - const MISC_SUGGEST_CRATE = 1 << 2; - const MISC_SUGGEST_SELF = 1 << 3; - const MISC_FROM_PRELUDE = 1 << 4; - } -} - impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// A generic scope visitor. /// Visits scopes in order to resolve some identifier in them or perform other actions. @@ -430,10 +419,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // } // So we have to save the innermost solution and continue searching in outer scopes // to detect potential ambiguities. - let mut innermost_result: Option<(NameBinding<'_>, Flags)> = None; + let mut innermost_result: Option<(NameBinding<'_>, Scope<'_>)> = None; let mut determinacy = Determinacy::Determined; let mut extern_prelude_item_binding = None; - let mut extern_prelude_flag_binding = None; // Go through all the scopes and try to resolve the name. let break_result = self.visit_scopes( @@ -459,11 +447,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ignore_binding, ignore_import, &mut extern_prelude_item_binding, - &mut extern_prelude_flag_binding, )? { - Ok((binding, flags)) - if sub_namespace_match(binding.macro_kinds(), macro_kind) => - { + Ok(binding) if sub_namespace_match(binding.macro_kinds(), macro_kind) => { // Below we report various ambiguity errors. // We do not need to report them if we are either in speculative resolution, // or in late resolution when everything is already imported and expanded @@ -472,24 +457,23 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return ControlFlow::Break(Ok(binding)); } - if let Some((innermost_binding, innermost_flags)) = innermost_result { + if let Some((innermost_binding, innermost_scope)) = innermost_result { // Found another solution, if the first one was "weak", report an error. if this.get_mut().maybe_push_ambiguity( orig_ident, parent_scope, binding, innermost_binding, - flags, - innermost_flags, + scope, + innermost_scope, extern_prelude_item_binding, - extern_prelude_flag_binding, ) { // No need to search for more potential ambiguities, one is enough. return ControlFlow::Break(Ok(innermost_binding)); } } else { // Found the first solution. - innermost_result = Some((binding, flags)); + innermost_result = Some((binding, scope)); } } Ok(_) | Err(Determinacy::Determined) => {} @@ -507,7 +491,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Scope visiting walked all the scopes and maybe found something in one of them. match innermost_result { - Some((binding, _)) => Ok(binding), + Some((binding, ..)) => Ok(binding), None => Err(Determinacy::determined(determinacy == Determinacy::Determined || force)), } } @@ -526,18 +510,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ignore_binding: Option>, ignore_import: Option>, extern_prelude_item_binding: &mut Option>, - extern_prelude_flag_binding: &mut Option>, - ) -> ControlFlow< - Result, Determinacy>, - Result<(NameBinding<'ra>, Flags), Determinacy>, - > { + ) -> ControlFlow, Determinacy>, Result, Determinacy>> + { let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt)); let ret = match scope { Scope::DeriveHelpers(expn_id) => { if let Some(binding) = self.helper_attrs.get(&expn_id).and_then(|attrs| { attrs.iter().rfind(|(i, _)| ident == *i).map(|(_, binding)| *binding) }) { - Ok((binding, Flags::empty())) + Ok(binding) } else { Err(Determinacy::Determined) } @@ -559,7 +540,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { derive.span, LocalExpnId::ROOT, ); - result = Ok((binding, Flags::empty())); + result = Ok(binding); break; } } @@ -573,7 +554,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { MacroRulesScope::Binding(macro_rules_binding) if ident == macro_rules_binding.ident => { - Ok((macro_rules_binding.binding, Flags::MACRO_RULES)) + Ok(macro_rules_binding.binding) } MacroRulesScope::Invocation(_) => Err(Determinacy::Undetermined), _ => Err(Determinacy::Determined), @@ -612,14 +593,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }, ); } - let misc_flags = if module == self.graph_root { - Flags::MISC_SUGGEST_CRATE - } else if module.is_normal() { - Flags::MISC_SUGGEST_SELF - } else { - Flags::empty() - }; - Ok((binding, Flags::MODULE | misc_flags)) + Ok(binding) } Err(ControlFlow::Continue(determinacy)) => Err(determinacy), Err(ControlFlow::Break(Determinacy::Undetermined)) => { @@ -630,20 +604,20 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } Scope::MacroUsePrelude => match self.macro_use_prelude.get(&ident.name).cloned() { - Some(binding) => Ok((binding, Flags::MISC_FROM_PRELUDE)), + Some(binding) => Ok(binding), None => Err(Determinacy::determined( self.graph_root.unexpanded_invocations.borrow().is_empty(), )), }, Scope::BuiltinAttrs => match self.builtin_attrs_bindings.get(&ident.name) { - Some(binding) => Ok((*binding, Flags::empty())), + Some(binding) => Ok(*binding), None => Err(Determinacy::Determined), }, Scope::ExternPreludeItems => { match self.reborrow().extern_prelude_get_item(ident, finalize.is_some()) { Some(binding) => { *extern_prelude_item_binding = Some(binding); - Ok((binding, Flags::empty())) + Ok(binding) } None => Err(Determinacy::determined( self.graph_root.unexpanded_invocations.borrow().is_empty(), @@ -652,15 +626,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } Scope::ExternPreludeFlags => { match self.extern_prelude_get_flag(ident, finalize.is_some()) { - Some(binding) => { - *extern_prelude_flag_binding = Some(binding); - Ok((binding, Flags::empty())) - } + Some(binding) => Ok(binding), None => Err(Determinacy::Determined), } } Scope::ToolPrelude => match self.registered_tool_bindings.get(&ident) { - Some(binding) => Ok((*binding, Flags::empty())), + Some(binding) => Ok(*binding), None => Err(Determinacy::Determined), }, Scope::StdLibPrelude => { @@ -679,7 +650,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && (matches!(use_prelude, UsePrelude::Yes) || self.is_builtin_macro(binding.res())) { - result = Ok((binding, Flags::MISC_FROM_PRELUDE)); + result = Ok(binding) } result @@ -712,7 +683,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) .emit(); } - Ok((*binding, Flags::empty())) + Ok(*binding) } None => Err(Determinacy::Determined), }, @@ -727,16 +698,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, binding: NameBinding<'ra>, innermost_binding: NameBinding<'ra>, - flags: Flags, - innermost_flags: Flags, + scope: Scope<'ra>, + innermost_scope: Scope<'ra>, extern_prelude_item_binding: Option>, - extern_prelude_flag_binding: Option>, ) -> bool { let (res, innermost_res) = (binding.res(), innermost_binding.res()); if res == innermost_res { return false; } + // FIXME: Use `scope` instead of `res` to detect built-in attrs and derive helpers, + // it will exclude imports, make slightly more code legal, and will require lang approval. let is_builtin = |res| matches!(res, Res::NonMacroAttr(NonMacroAttrKind::Builtin(..))); let derive_helper = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper); let derive_helper_compat = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat); @@ -747,12 +719,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Some(AmbiguityKind::DeriveHelper) } else if res == derive_helper_compat && innermost_res != derive_helper { span_bug!(orig_ident.span, "impossible inner resolution kind") - } else if innermost_flags.contains(Flags::MACRO_RULES) - && flags.contains(Flags::MODULE) + } else if matches!(innermost_scope, Scope::MacroRules(_)) + && matches!(scope, Scope::Module(..)) && !self.disambiguate_macro_rules_vs_modularized(innermost_binding, binding) { Some(AmbiguityKind::MacroRulesVsModularized) - } else if flags.contains(Flags::MACRO_RULES) && innermost_flags.contains(Flags::MODULE) { + } else if matches!(scope, Scope::MacroRules(_)) + && matches!(innermost_scope, Scope::Module(..)) + { // should be impossible because of visitation order in // visit_scopes // @@ -774,32 +748,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Skip ambiguity errors for extern flag bindings "overridden" // by extern item bindings. // FIXME: Remove with lang team approval. - let issue_145575_hack = Some(binding) == extern_prelude_flag_binding + let issue_145575_hack = matches!(scope, Scope::ExternPreludeFlags) && extern_prelude_item_binding.is_some() && extern_prelude_item_binding != Some(innermost_binding); if issue_145575_hack { self.issue_145575_hack_applied = true; } else { - let misc = |f: Flags| { - if f.contains(Flags::MISC_SUGGEST_CRATE) { - AmbiguityErrorMisc::SuggestCrate - } else if f.contains(Flags::MISC_SUGGEST_SELF) { - AmbiguityErrorMisc::SuggestSelf - } else if f.contains(Flags::MISC_FROM_PRELUDE) { - AmbiguityErrorMisc::FromPrelude - } else { - AmbiguityErrorMisc::None - } - }; self.ambiguity_errors.push(AmbiguityError { kind, ident: orig_ident, b1: innermost_binding, b2: binding, + scope1: innermost_scope, + scope2: scope, warning: false, - misc1: misc(innermost_flags), - misc2: misc(flags), }); return true; } @@ -1216,9 +1179,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, b1: binding, b2: shadowed_glob, + scope1: Scope::Module(self.empty_module, None), + scope2: Scope::Module(self.empty_module, None), warning: false, - misc1: AmbiguityErrorMisc::None, - misc2: AmbiguityErrorMisc::None, }); } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index ec030ecf8e13..7cbf2088efce 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -903,22 +903,14 @@ impl AmbiguityKind { } } -/// Miscellaneous bits of metadata for better ambiguity error reporting. -#[derive(Clone, Copy, PartialEq)] -enum AmbiguityErrorMisc { - SuggestCrate, - SuggestSelf, - FromPrelude, - None, -} - struct AmbiguityError<'ra> { kind: AmbiguityKind, ident: Ident, b1: NameBinding<'ra>, b2: NameBinding<'ra>, - misc1: AmbiguityErrorMisc, - misc2: AmbiguityErrorMisc, + // `empty_module` in module scope serves as an unknown module here. + scope1: Scope<'ra>, + scope2: Scope<'ra>, warning: bool, } @@ -2045,8 +2037,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && ambiguity_error.ident.span == ambi.ident.span && ambiguity_error.b1.span == ambi.b1.span && ambiguity_error.b2.span == ambi.b2.span - && ambiguity_error.misc1 == ambi.misc1 - && ambiguity_error.misc2 == ambi.misc2 { return true; } @@ -2071,8 +2061,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, b1: used_binding, b2, - misc1: AmbiguityErrorMisc::None, - misc2: AmbiguityErrorMisc::None, + scope1: Scope::Module(self.empty_module, None), + scope2: Scope::Module(self.empty_module, None), warning: warn_ambiguity, }; if !self.matches_previous_ambiguity_error(&ambiguity_error) { From b018f42b7bbbb970ebf0faaa4c5df79fa094aa7d Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 27 Dec 2025 23:32:59 +0300 Subject: [PATCH 0076/1061] resolve: Keep all encountered bindings in `resolve_ident_in_scope_set` --- compiler/rustc_resolve/src/ident.rs | 37 +++++++++++------------------ 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 13359dc9ab52..669f045681b7 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -419,9 +419,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // } // So we have to save the innermost solution and continue searching in outer scopes // to detect potential ambiguities. - let mut innermost_result: Option<(NameBinding<'_>, Scope<'_>)> = None; + let mut innermost_results: Vec<(NameBinding<'_>, Scope<'_>)> = Vec::new(); let mut determinacy = Determinacy::Determined; - let mut extern_prelude_item_binding = None; // Go through all the scopes and try to resolve the name. let break_result = self.visit_scopes( @@ -442,11 +441,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { scope_set, parent_scope, // Shadowed bindings don't need to be marked as used or non-speculatively loaded. - if innermost_result.is_none() { finalize } else { None }, + if innermost_results.is_empty() { finalize } else { None }, force, ignore_binding, ignore_import, - &mut extern_prelude_item_binding, )? { Ok(binding) if sub_namespace_match(binding.macro_kinds(), macro_kind) => { // Below we report various ambiguity errors. @@ -457,24 +455,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return ControlFlow::Break(Ok(binding)); } - if let Some((innermost_binding, innermost_scope)) = innermost_result { + if let Some(&(innermost_binding, _)) = innermost_results.first() { // Found another solution, if the first one was "weak", report an error. if this.get_mut().maybe_push_ambiguity( orig_ident, parent_scope, binding, - innermost_binding, scope, - innermost_scope, - extern_prelude_item_binding, + &innermost_results, ) { // No need to search for more potential ambiguities, one is enough. return ControlFlow::Break(Ok(innermost_binding)); } - } else { - // Found the first solution. - innermost_result = Some((binding, scope)); } + + innermost_results.push((binding, scope)); } Ok(_) | Err(Determinacy::Determined) => {} Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined, @@ -490,8 +485,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // Scope visiting walked all the scopes and maybe found something in one of them. - match innermost_result { - Some((binding, ..)) => Ok(binding), + match innermost_results.first() { + Some(&(binding, ..)) => Ok(binding), None => Err(Determinacy::determined(determinacy == Determinacy::Determined || force)), } } @@ -509,7 +504,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { force: bool, ignore_binding: Option>, ignore_import: Option>, - extern_prelude_item_binding: &mut Option>, ) -> ControlFlow, Determinacy>, Result, Determinacy>> { let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt)); @@ -615,10 +609,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }, Scope::ExternPreludeItems => { match self.reborrow().extern_prelude_get_item(ident, finalize.is_some()) { - Some(binding) => { - *extern_prelude_item_binding = Some(binding); - Ok(binding) - } + Some(binding) => Ok(binding), None => Err(Determinacy::determined( self.graph_root.unexpanded_invocations.borrow().is_empty(), )), @@ -697,11 +688,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { orig_ident: Ident, parent_scope: &ParentScope<'ra>, binding: NameBinding<'ra>, - innermost_binding: NameBinding<'ra>, scope: Scope<'ra>, - innermost_scope: Scope<'ra>, - extern_prelude_item_binding: Option>, + innermost_results: &[(NameBinding<'ra>, Scope<'ra>)], ) -> bool { + let (innermost_binding, innermost_scope) = *innermost_results.first().unwrap(); let (res, innermost_res) = (binding.res(), innermost_binding.res()); if res == innermost_res { return false; @@ -749,8 +739,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // by extern item bindings. // FIXME: Remove with lang team approval. let issue_145575_hack = matches!(scope, Scope::ExternPreludeFlags) - && extern_prelude_item_binding.is_some() - && extern_prelude_item_binding != Some(innermost_binding); + && innermost_results[1..].iter().any(|(b, s)| { + matches!(s, Scope::ExternPreludeItems) && *b != innermost_binding + }); if issue_145575_hack { self.issue_145575_hack_applied = true; From 981fddb4a1f5e4ae62062a87dd8aa250a3a5c705 Mon Sep 17 00:00:00 2001 From: Astralchroma Date: Sat, 27 Dec 2025 22:49:31 +0000 Subject: [PATCH 0077/1061] Fix typoed mention of config value using `_` of `-` --- clippy_lints/src/cargo/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/cargo/mod.rs b/clippy_lints/src/cargo/mod.rs index 60371dcd7715..08d92adbacef 100644 --- a/clippy_lints/src/cargo/mod.rs +++ b/clippy_lints/src/cargo/mod.rs @@ -132,7 +132,7 @@ declare_clippy_lint! { /// Because this can be caused purely by the dependencies /// themselves, it's not always possible to fix this issue. /// In those cases, you can allow that specific crate using - /// the `allowed_duplicate_crates` configuration option. + /// the `allowed-duplicate-crates` configuration option. /// /// ### Example /// ```toml From 6da3605bfa84a1a090558ce00bb43402d6d73419 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Sun, 28 Dec 2025 04:22:01 +0000 Subject: [PATCH 0078/1061] Prepare for merging from rust-lang/rust This updates the rust-version file to 23d01cd2412583491621ab1ca4f1b01e37d11e39. --- library/compiler-builtins/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/rust-version b/library/compiler-builtins/rust-version index 7345c25066a8..6a2835bc2d9e 100644 --- a/library/compiler-builtins/rust-version +++ b/library/compiler-builtins/rust-version @@ -1 +1 @@ -2dc30247c5d8293aaa31e1d7dae2ed2fde908ada +23d01cd2412583491621ab1ca4f1b01e37d11e39 From 380e4d28b2304b33995e54f3fa8295d5f4611c8f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 28 Dec 2025 04:32:23 +0000 Subject: [PATCH 0079/1061] compiler-builtins: Revert "cpuid is safe since the stdarch sync, so remove unsafe from usages" We can't drop the `unsafe` here because it is required at the `libm` MSRV. Instead, we will need to `allow` the lint. This reverts commit 96ac3624abc144db930d94504a9c67aad7b949ed. --- .../libm/src/math/arch/x86/detect.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/arch/x86/detect.rs b/library/compiler-builtins/libm/src/math/arch/x86/detect.rs index 5391a68228ed..e6d9b040bfaf 100644 --- a/library/compiler-builtins/libm/src/math/arch/x86/detect.rs +++ b/library/compiler-builtins/libm/src/math/arch/x86/detect.rs @@ -57,7 +57,7 @@ fn load_x86_features() -> Flags { // (in that order) let mut vendor_id = [0u8; 12]; let max_basic_leaf; - { + unsafe { let CpuidResult { eax, ebx, ecx, edx } = __cpuid(0); max_basic_leaf = eax; vendor_id[0..4].copy_from_slice(&ebx.to_ne_bytes()); @@ -72,7 +72,7 @@ fn load_x86_features() -> Flags { // EAX = 1, ECX = 0: Queries "Processor Info and Feature Bits"; // Contains information about most x86 features. - let CpuidResult { ecx, edx, .. } = __cpuid(0x0000_0001_u32); + let CpuidResult { ecx, edx, .. } = unsafe { __cpuid(0x0000_0001_u32) }; let proc_info_ecx = Flags::from_bits(ecx); let proc_info_edx = Flags::from_bits(edx); @@ -82,23 +82,23 @@ fn load_x86_features() -> Flags { let mut extended_features_edx = Flags::empty(); let mut extended_features_eax_leaf_1 = Flags::empty(); if max_basic_leaf >= 7 { - let CpuidResult { ebx, edx, .. } = __cpuid(0x0000_0007_u32); + let CpuidResult { ebx, edx, .. } = unsafe { __cpuid(0x0000_0007_u32) }; extended_features_ebx = Flags::from_bits(ebx); extended_features_edx = Flags::from_bits(edx); - let CpuidResult { eax, .. } = __cpuid_count(0x0000_0007_u32, 0x0000_0001_u32); + let CpuidResult { eax, .. } = unsafe { __cpuid_count(0x0000_0007_u32, 0x0000_0001_u32) }; extended_features_eax_leaf_1 = Flags::from_bits(eax) } // EAX = 0x8000_0000, ECX = 0: Get Highest Extended Function Supported // - EAX returns the max leaf value for extended information, that is, // `cpuid` calls in range [0x8000_0000; u32::MAX]: - let extended_max_basic_leaf = __cpuid(0x8000_0000_u32).eax; + let extended_max_basic_leaf = unsafe { __cpuid(0x8000_0000_u32) }.eax; // EAX = 0x8000_0001, ECX=0: Queries "Extended Processor Info and Feature Bits" let mut extended_proc_info_ecx = Flags::empty(); if extended_max_basic_leaf >= 1 { - let CpuidResult { ecx, .. } = __cpuid(0x8000_0001_u32); + let CpuidResult { ecx, .. } = unsafe { __cpuid(0x8000_0001_u32) }; extended_proc_info_ecx = Flags::from_bits(ecx); } From 1276564146497ed2e11e0ca4a59aa0ecec56f88d Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sat, 27 Dec 2025 16:34:40 +0900 Subject: [PATCH 0080/1061] Ignore unused_unsafe lint in libm/src/math/arch/x86/detect.rs --- library/compiler-builtins/libm/src/math/arch/x86/detect.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/arch/x86/detect.rs b/library/compiler-builtins/libm/src/math/arch/x86/detect.rs index e6d9b040bfaf..ca785470b806 100644 --- a/library/compiler-builtins/libm/src/math/arch/x86/detect.rs +++ b/library/compiler-builtins/libm/src/math/arch/x86/detect.rs @@ -39,6 +39,8 @@ pub fn get_cpu_features() -> Flags { /// Implementation is taken from [std-detect][std-detect]. /// /// [std-detect]: https://github.com/rust-lang/stdarch/blob/690b3a6334d482874163bd6fcef408e0518febe9/crates/std_detect/src/detect/os/x86.rs#L142 +// FIXME(msrv): Remove unsafe block around __cpuid once https://github.com/rust-lang/stdarch/pull/1935 is available in MSRV. +#[allow(unused_unsafe)] fn load_x86_features() -> Flags { let mut value = Flags::empty(); From 12474ce192941fae1f354d85eadb32e9d1da25da Mon Sep 17 00:00:00 2001 From: Mu001999 Date: Fri, 18 Jul 2025 13:12:27 +0800 Subject: [PATCH 0081/1061] Impls and impl items inherit lint levels of the corresponding traits and trait items --- compiler/rustc_passes/src/dead.rs | 17 +++++++++ .../ui/lint/dead-code/allow-trait-or-impl.rs | 38 +++++++++++++++++++ .../lint/dead-code/allow-trait-or-impl.stderr | 26 +++++++++++++ tests/ui/lint/dead-code/allow-unused-trait.rs | 29 ++++++++++++++ 4 files changed, 110 insertions(+) create mode 100644 tests/ui/lint/dead-code/allow-trait-or-impl.rs create mode 100644 tests/ui/lint/dead-code/allow-trait-or-impl.stderr create mode 100644 tests/ui/lint/dead-code/allow-unused-trait.rs diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 0563e9619419..3294b6802a71 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -778,6 +778,15 @@ fn maybe_record_as_seed<'tcx>( match tcx.def_kind(parent) { DefKind::Impl { of_trait: false } | DefKind::Trait => {} DefKind::Impl { of_trait: true } => { + if let Some(trait_item_def_id) = + tcx.associated_item(owner_id.def_id).trait_item_def_id() + && let Some(trait_item_local_def_id) = trait_item_def_id.as_local() + && let Some(comes_from_allow) = + has_allow_dead_code_or_lang_attr(tcx, trait_item_local_def_id) + { + worklist.push((owner_id.def_id, comes_from_allow)); + } + // We only care about associated items of traits, // because they cannot be visited directly, // so we later mark them as live if their corresponding traits @@ -791,6 +800,14 @@ fn maybe_record_as_seed<'tcx>( } DefKind::Impl { of_trait: true } => { if allow_dead_code.is_none() { + if let Some(trait_def_id) = + tcx.impl_trait_ref(owner_id.def_id).skip_binder().def_id.as_local() + && let Some(comes_from_allow) = + has_allow_dead_code_or_lang_attr(tcx, trait_def_id) + { + worklist.push((owner_id.def_id, comes_from_allow)); + } + unsolved_items.push(owner_id.def_id); } } diff --git a/tests/ui/lint/dead-code/allow-trait-or-impl.rs b/tests/ui/lint/dead-code/allow-trait-or-impl.rs new file mode 100644 index 000000000000..92817549a91e --- /dev/null +++ b/tests/ui/lint/dead-code/allow-trait-or-impl.rs @@ -0,0 +1,38 @@ +#![deny(dead_code)] + +pub mod a { + pub trait Foo { } + impl Foo for u32 { } + + struct PrivateType; //~ ERROR struct `PrivateType` is never constructed + impl Foo for PrivateType { } // <-- warns as dead, even though Foo is public + + struct AnotherPrivateType; //~ ERROR struct `AnotherPrivateType` is never constructed + impl Foo for AnotherPrivateType { } // <-- warns as dead, even though Foo is public +} + +pub mod b { + #[allow(dead_code)] + pub trait Foo { } + impl Foo for u32 { } + + struct PrivateType; + impl Foo for PrivateType { } // <-- no warning, trait is "allowed" + + struct AnotherPrivateType; + impl Foo for AnotherPrivateType { } // <-- no warning, trait is "allowed" +} + +pub mod c { + pub trait Foo { } + impl Foo for u32 { } + + struct PrivateType; + #[allow(dead_code)] + impl Foo for PrivateType { } // <-- no warning, impl is allowed + + struct AnotherPrivateType; //~ ERROR struct `AnotherPrivateType` is never constructed + impl Foo for AnotherPrivateType { } // <-- warns as dead, even though Foo is public +} + +fn main() {} diff --git a/tests/ui/lint/dead-code/allow-trait-or-impl.stderr b/tests/ui/lint/dead-code/allow-trait-or-impl.stderr new file mode 100644 index 000000000000..130116b6c91d --- /dev/null +++ b/tests/ui/lint/dead-code/allow-trait-or-impl.stderr @@ -0,0 +1,26 @@ +error: struct `PrivateType` is never constructed + --> $DIR/allow-trait-or-impl.rs:7:12 + | +LL | struct PrivateType; + | ^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/allow-trait-or-impl.rs:1:9 + | +LL | #![deny(dead_code)] + | ^^^^^^^^^ + +error: struct `AnotherPrivateType` is never constructed + --> $DIR/allow-trait-or-impl.rs:10:12 + | +LL | struct AnotherPrivateType; + | ^^^^^^^^^^^^^^^^^^ + +error: struct `AnotherPrivateType` is never constructed + --> $DIR/allow-trait-or-impl.rs:34:12 + | +LL | struct AnotherPrivateType; + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/lint/dead-code/allow-unused-trait.rs b/tests/ui/lint/dead-code/allow-unused-trait.rs new file mode 100644 index 000000000000..4eb63bd4d27a --- /dev/null +++ b/tests/ui/lint/dead-code/allow-unused-trait.rs @@ -0,0 +1,29 @@ +//@ check-pass + +#![deny(dead_code)] + +#[allow(dead_code)] +trait Foo { + const FOO: u32; + type Baz; + fn foobar(); +} + +const fn bar(x: u32) -> u32 { + x +} + +struct Qux; + +struct FooBar; + +impl Foo for u32 { + const FOO: u32 = bar(0); + type Baz = Qux; + + fn foobar() { + let _ = FooBar; + } +} + +fn main() {} From ee12ffe79f97db4ac5e4e763dd9bd99e94863230 Mon Sep 17 00:00:00 2001 From: Mattias Petersson Date: Sun, 14 Dec 2025 17:23:23 +0100 Subject: [PATCH 0082/1061] Add example for profiling diff locally Added an example for profiling an external crate diff locally. The original issue also mentions that the debuginfo-level = 1 should be highlighted, but that has been solved by a different commit and as such was not included here. --- .../src/profiling/with_rustc_perf.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md b/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md index c47fed24e6e3..19935d3d262f 100644 --- a/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md +++ b/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md @@ -28,6 +28,24 @@ You can use the following options for the `x perf` command, which mirror the cor - `--profiles`: Select profiles (`Check`, `Debug`, `Opt`, `Doc`) which should be profiled/benchmarked. - `--scenarios`: Select scenarios (`Full`, `IncrFull`, `IncrPatched`, `IncrUnchanged`) which should be profiled/benchmarked. +## Example profiling diff for external crates +It can be of interest to generate a local diff for two commits of the compiler for external crates. +To start, in the `rustc-perf` repo, build the collector, which runs the Rust compiler benchmarks as follows. +``` +cargo build --release -p collector +``` +After this the collector can be located in `.\target\release\collector`, can be run locally with `bench_local` and expects the following arguments: +- ``: Profiler selection for how performance should be measured. For this example we will use Cachegrind. +- ``: The Rust compiler revision to benchmark, specified as a commit SHA from `rust-lang/rust`. +Optional arguments allow running profiles and scenarios as described above. `--include` in `x perf` is instead `--exact-match`. More information regarding the mandatory and +optional arguments can be found in the [rustc-perf-readme-profilers]. + +Then, for the case of generating a profile diff for the crate `serve_derive-1.0.136`, for two commits `` and `` in the `rust-lang/rust` repository, run the following +``` +./target/release/collector profile_local cachegrind + --rustc2 + --exact-match serde_derive-1.0.136 --profiles Check --scenarios IncrUnchanged +``` + + [samply]: https://github.com/mstange/samply [cachegrind]: https://www.cs.cmu.edu/afs/cs.cmu.edu/project/cmt-40/Nice/RuleRefinement/bin/valgrind-3.2.0/docs/html/cg-manual.html [rustc-perf]: https://github.com/rust-lang/rustc-perf From 61a8b6b43b2cbb90e87eefd4a4803e34fa755727 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sun, 28 Dec 2025 20:34:44 +0200 Subject: [PATCH 0083/1061] stop checking if PRs are behind --- src/doc/rustc-dev-guide/triagebot.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/triagebot.toml b/src/doc/rustc-dev-guide/triagebot.toml index fbfe74234148..974f4cd3dd96 100644 --- a/src/doc/rustc-dev-guide/triagebot.toml +++ b/src/doc/rustc-dev-guide/triagebot.toml @@ -58,9 +58,6 @@ allow-unauthenticated = [ # Documentation at: https://forge.rust-lang.org/triagebot/issue-links.html [issue-links] -[behind-upstream] -days-threshold = 7 - # Enable triagebot (PR) assignment. # Documentation at: https://forge.rust-lang.org/triagebot/pr-assignment.html [assign] From aede29f9ed0b85b305c0bfe6064f7e9126982145 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Sun, 28 Dec 2025 21:23:33 +0000 Subject: [PATCH 0084/1061] Enhance `needless_collect` to cover vec `push` --- clippy_lints/src/methods/needless_collect.rs | 113 ++++++++++++++++--- clippy_utils/src/sym.rs | 1 + tests/ui/needless_collect.fixed | 45 ++++++++ tests/ui/needless_collect.rs | 45 ++++++++ tests/ui/needless_collect.stderr | 54 ++++++++- 5 files changed, 242 insertions(+), 16 deletions(-) diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index 0e2012319147..312133689900 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -16,8 +16,8 @@ use rustc_hir::{ use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, AssocTag, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty}; -use rustc_span::Span; use rustc_span::symbol::Ident; +use rustc_span::{Span, Symbol}; const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed"; @@ -104,16 +104,19 @@ pub(super) fn check<'tcx>( Node::LetStmt(l) => { if let PatKind::Binding(BindingMode::NONE | BindingMode::MUT, id, _, None) = l.pat.kind && let ty = cx.typeck_results().expr_ty(collect_expr) - && matches!( - ty.opt_diag_name(cx), - Some(sym::Vec | sym::VecDeque | sym::BinaryHeap | sym::LinkedList) - ) + && let Some(extra_spec) = ty.opt_diag_name(cx).and_then(ExtraFunctionSpec::new) && let iter_ty = cx.typeck_results().expr_ty(iter_expr) && let Some(block) = get_enclosing_block(cx, l.hir_id) - && let Some(iter_calls) = detect_iter_and_into_iters(block, id, cx, get_captured_ids(cx, iter_ty)) + && let Some((iter_calls, extra_calls)) = + detect_iter_and_into_iters(block, id, cx, get_captured_ids(cx, iter_ty), extra_spec) && let [iter_call] = &*iter_calls { - let mut used_count_visitor = UsedCountVisitor { cx, id, count: 0 }; + let mut used_count_visitor = UsedCountVisitor { + cx, + id, + extra_spec, + count: 0, + }; walk_block(&mut used_count_visitor, block); if used_count_visitor.count > 1 { return; @@ -135,11 +138,18 @@ pub(super) fn check<'tcx>( span, NEEDLESS_COLLECT_MSG, |diag| { - let iter_replacement = - format!("{}{}", Sugg::hir(cx, iter_expr, ".."), iter_call.get_iter_method(cx)); + let iter_snippet = Sugg::hir(cx, iter_expr, ".."); + let mut iter_replacement = iter_snippet.to_string(); + iter_replacement.extend(extra_calls.iter().map(|extra| extra.get_iter_method(cx))); + iter_replacement.push_str(&iter_call.get_iter_method(cx)); + + let mut remove_suggestions = vec![(l.span, String::new())]; + remove_suggestions.extend(extra_calls.iter().map(|extra| (extra.span, String::new()))); + remove_suggestions.push((iter_call.span, iter_replacement)); + diag.multipart_suggestion( iter_call.get_suggestion_text(), - vec![(l.span, String::new()), (iter_call.span, iter_replacement)], + remove_suggestions, Applicability::MaybeIncorrect, ); }, @@ -272,6 +282,7 @@ struct IterFunction { func: IterFunctionKind, span: Span, } + impl IterFunction { fn get_iter_method(&self, cx: &LateContext<'_>) -> String { match &self.func { @@ -288,6 +299,7 @@ impl IterFunction { }, } } + fn get_suggestion_text(&self) -> &'static str { match &self.func { IterFunctionKind::IntoIter(_) => { @@ -305,6 +317,7 @@ impl IterFunction { } } } + enum IterFunctionKind { IntoIter(HirId), Len, @@ -312,16 +325,59 @@ enum IterFunctionKind { Contains(Span), } +struct ExtraFunction { + kind: ExtraFunctionKind, + span: Span, +} + +impl ExtraFunction { + fn get_iter_method(&self, cx: &LateContext<'_>) -> String { + match &self.kind { + ExtraFunctionKind::Push(span) => { + let s = snippet(cx, *span, ".."); + format!(".chain([{s}])") + }, + } + } +} + +enum ExtraFunctionKind { + Push(Span), +} + +#[derive(Clone, Copy)] +struct ExtraFunctionSpec { + push_symbol: Option, +} + +impl ExtraFunctionSpec { + fn new(target: Symbol) -> Option { + match target { + sym::Vec => Some(ExtraFunctionSpec { + push_symbol: Some(sym::push), + }), + sym::VecDeque | sym::LinkedList => Some(ExtraFunctionSpec { + push_symbol: Some(sym::push_back), + }), + sym::BinaryHeap => Some(ExtraFunctionSpec { push_symbol: None }), + _ => None, + } + } +} + struct IterFunctionVisitor<'a, 'tcx> { illegal_mutable_capture_ids: HirIdSet, current_mutably_captured_ids: HirIdSet, cx: &'a LateContext<'tcx>, uses: Vec>, + extras: Vec, + extra_spec: ExtraFunctionSpec, hir_id_uses_map: FxHashMap, current_statement_hir_id: Option, seen_other: bool, target: HirId, } + impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> { fn visit_block(&mut self, block: &'tcx Block<'tcx>) { for (expr, hir_id) in block.stmts.iter().filter_map(get_expr_and_hir_id_from_stmt) { @@ -384,6 +440,17 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> { func: IterFunctionKind::Contains(args[0].span), span: expr.span, })), + name if Some(name) == self.extra_spec.push_symbol && self.uses.is_empty() => { + let mut span = expr.span; + // Remove the statement span if possible + if let Node::Stmt(stmt) = self.cx.tcx.parent_hir_node(expr.hir_id) { + span = stmt.span; + } + self.extras.push(ExtraFunction { + kind: ExtraFunctionKind::Push(args[0].span), + span, + }); + }, _ => { self.seen_other = true; if let Some(hir_id) = self.current_statement_hir_id { @@ -468,6 +535,7 @@ fn get_expr_and_hir_id_from_stmt<'v>(stmt: &'v Stmt<'v>) -> Option<(&'v Expr<'v> struct UsedCountVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, id: HirId, + extra_spec: ExtraFunctionSpec, count: usize, } @@ -475,11 +543,23 @@ impl<'tcx> Visitor<'tcx> for UsedCountVisitor<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if expr.res_local_id() == Some(self.id) { - self.count += 1; - } else { + if expr.res_local_id() != Some(self.id) { walk_expr(self, expr); + return; } + + let parent = self.cx.tcx.parent_hir_node(expr.hir_id); + if let Node::Expr(expr) = parent + && let ExprKind::MethodCall(method_name, _, _, _) = &expr.kind + && self + .extra_spec + .push_symbol + .is_some_and(|sym| method_name.ident.name == sym) + { + return; + } + + self.count += 1; } fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { @@ -494,12 +574,15 @@ fn detect_iter_and_into_iters<'tcx: 'a, 'a>( id: HirId, cx: &'a LateContext<'tcx>, captured_ids: HirIdSet, -) -> Option> { + extra_spec: ExtraFunctionSpec, +) -> Option<(Vec, Vec)> { let mut visitor = IterFunctionVisitor { illegal_mutable_capture_ids: captured_ids, current_mutably_captured_ids: HirIdSet::default(), cx, uses: Vec::new(), + extras: Vec::new(), + extra_spec, hir_id_uses_map: FxHashMap::default(), current_statement_hir_id: None, seen_other: false, @@ -509,7 +592,7 @@ fn detect_iter_and_into_iters<'tcx: 'a, 'a>( if visitor.seen_other { None } else { - Some(visitor.uses.into_iter().flatten().collect()) + Some((visitor.uses.into_iter().flatten().collect(), visitor.extras)) } } diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index a0d2e8673fe6..a36f4954a06a 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -271,6 +271,7 @@ generate! { powi, product, push, + push_back, push_str, read, read_exact, diff --git a/tests/ui/needless_collect.fixed b/tests/ui/needless_collect.fixed index 99027e79b664..fff383fb1328 100644 --- a/tests/ui/needless_collect.fixed +++ b/tests/ui/needless_collect.fixed @@ -219,3 +219,48 @@ fn issue16270() { // Do not lint, `..` implements `Index` but is not `usize` _ = &(1..3).collect::>()[..]; } + +#[warn(clippy::needless_collect)] +mod collect_push_then_iter { + use std::collections::{BinaryHeap, LinkedList}; + + fn vec_push(iter: impl Iterator) -> Vec { + + //~^ needless_collect + + iter.chain([1]).map(|x| x + 1).collect() + } + + fn vec_push_no_iter(iter: impl Iterator) { + let mut v = iter.collect::>(); + v.push(1); + } + + fn vec_push_multiple(iter: impl Iterator) -> Vec { + + //~^ needless_collect + + + iter.chain([1]).chain([2]).map(|x| x + 1).collect() + } + + fn linked_list_push(iter: impl Iterator) -> LinkedList { + + //~^ needless_collect + + iter.chain([1]).map(|x| x + 1).collect() + } + + fn binary_heap_push(iter: impl Iterator) -> BinaryHeap { + let mut v = iter.collect::>(); + v.push(1); + v.into_iter().map(|x| x + 1).collect() + } + + fn vec_push_mixed(iter: impl Iterator) -> bool { + let mut v = iter.collect::>(); + let ok = v.contains(&1); + v.push(1); + ok + } +} diff --git a/tests/ui/needless_collect.rs b/tests/ui/needless_collect.rs index 683cc49c9af3..f6e966b09ea5 100644 --- a/tests/ui/needless_collect.rs +++ b/tests/ui/needless_collect.rs @@ -219,3 +219,48 @@ fn issue16270() { // Do not lint, `..` implements `Index` but is not `usize` _ = &(1..3).collect::>()[..]; } + +#[warn(clippy::needless_collect)] +mod collect_push_then_iter { + use std::collections::{BinaryHeap, LinkedList}; + + fn vec_push(iter: impl Iterator) -> Vec { + let mut v = iter.collect::>(); + //~^ needless_collect + v.push(1); + v.into_iter().map(|x| x + 1).collect() + } + + fn vec_push_no_iter(iter: impl Iterator) { + let mut v = iter.collect::>(); + v.push(1); + } + + fn vec_push_multiple(iter: impl Iterator) -> Vec { + let mut v = iter.collect::>(); + //~^ needless_collect + v.push(1); + v.push(2); + v.into_iter().map(|x| x + 1).collect() + } + + fn linked_list_push(iter: impl Iterator) -> LinkedList { + let mut v = iter.collect::>(); + //~^ needless_collect + v.push_back(1); + v.into_iter().map(|x| x + 1).collect() + } + + fn binary_heap_push(iter: impl Iterator) -> BinaryHeap { + let mut v = iter.collect::>(); + v.push(1); + v.into_iter().map(|x| x + 1).collect() + } + + fn vec_push_mixed(iter: impl Iterator) -> bool { + let mut v = iter.collect::>(); + let ok = v.contains(&1); + v.push(1); + ok + } +} diff --git a/tests/ui/needless_collect.stderr b/tests/ui/needless_collect.stderr index c77674dc55d4..93ca32a68d6a 100644 --- a/tests/ui/needless_collect.stderr +++ b/tests/ui/needless_collect.stderr @@ -121,5 +121,57 @@ error: avoid using `collect()` when not needed LL | baz((0..10), (), ('a'..='z').collect::>()) | ^^^^^^^^^^^^^^^^^^^^ help: remove this call -error: aborting due to 20 previous errors +error: avoid using `collect()` when not needed + --> tests/ui/needless_collect.rs:228:26 + | +LL | let mut v = iter.collect::>(); + | ^^^^^^^ +... +LL | v.into_iter().map(|x| x + 1).collect() + | ------------- the iterator could be used here instead + | +help: use the original Iterator instead of collecting it and then producing a new one + | +LL ~ +LL | +LL ~ +LL ~ iter.chain([1]).map(|x| x + 1).collect() + | + +error: avoid using `collect()` when not needed + --> tests/ui/needless_collect.rs:240:26 + | +LL | let mut v = iter.collect::>(); + | ^^^^^^^ +... +LL | v.into_iter().map(|x| x + 1).collect() + | ------------- the iterator could be used here instead + | +help: use the original Iterator instead of collecting it and then producing a new one + | +LL ~ +LL | +LL ~ +LL ~ +LL ~ iter.chain([1]).chain([2]).map(|x| x + 1).collect() + | + +error: avoid using `collect()` when not needed + --> tests/ui/needless_collect.rs:248:26 + | +LL | let mut v = iter.collect::>(); + | ^^^^^^^ +... +LL | v.into_iter().map(|x| x + 1).collect() + | ------------- the iterator could be used here instead + | +help: use the original Iterator instead of collecting it and then producing a new one + | +LL ~ +LL | +LL ~ +LL ~ iter.chain([1]).map(|x| x + 1).collect() + | + +error: aborting due to 23 previous errors From c516c284755130dac7d3232b7c40567a57cfb936 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Mon, 29 Dec 2025 06:45:17 +0800 Subject: [PATCH 0085/1061] Add useless prefix `try_into_` for suggest_name Example --- ```rust enum Foo { Num(i32) } impl Foo { fn try_into_num(self) -> Result { if let Self::Num(v) = self { Ok(v) } else { Err(self) } } } fn handle(foo: Foo) { foo.try_into_num().$0 } ``` **Before this PR** ```rust fn handle(foo: Foo) { if let Ok(${1:try_into_num}) = foo.try_into_num() { $0 } } ``` **After this PR** ```rust fn handle(foo: Foo) { if let Ok(${1:num}) = foo.try_into_num() { $0 } } ``` --- .../crates/ide-db/src/syntax_helpers/suggest_name.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs index 273328a8d270..b8b9a7a76816 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs @@ -44,7 +44,7 @@ const SEQUENCE_TYPES: &[&str] = &["Vec", "VecDeque", "LinkedList"]; /// `vec.as_slice()` -> `slice` /// `args.into_config()` -> `config` /// `bytes.to_vec()` -> `vec` -const USELESS_METHOD_PREFIXES: &[&str] = &["into_", "as_", "to_"]; +const USELESS_METHOD_PREFIXES: &[&str] = &["try_into_", "into_", "as_", "to_"]; /// Useless methods that are stripped from expression /// From 998a0df610eff8c262106c3dc567358d241ef026 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sun, 28 Dec 2025 15:18:30 -0500 Subject: [PATCH 0086/1061] more sophisticated checking --- .../src/error_reporting/traits/suggestions.rs | 49 +++++++++++++------ 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index c5b014293f98..511e9e85b5f6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -4069,24 +4069,45 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { )) && expr.span.hi() != rcvr.span.hi() { - match tcx.hir_node(call_hir_id) { - // Do not suggest removing a method call if the argument is the receiver of the parent call: - // `x.a().b()`, suggesting removing `.a()` would change the type and could make `.b()` unavailable. + let should_sugg = match tcx.hir_node(call_hir_id) { Node::Expr(hir::Expr { kind: hir::ExprKind::MethodCall(_, call_receiver, _, _), .. - }) if call_receiver.hir_id == arg_hir_id => {} - _ => { - err.span_suggestion_verbose( - expr.span.with_lo(rcvr.span.hi()), - format!( - "consider removing this method call, as the receiver has type `{ty}` and \ - `{pred}` trivially holds", - ), - "", - Applicability::MaybeIncorrect, - ); + }) if let Some((DefKind::AssocFn, did)) = + typeck_results.type_dependent_def(call_hir_id) + && call_receiver.hir_id == arg_hir_id => + { + // Avoid suggesting removing a method call if the argument is the receiver of the parent call and + // removing the receiver would make the method inaccessible. i.e. `x.a().b()`, suggesting removing + // `.a()` could change the type and make `.b()` unavailable. + if tcx.inherent_impl_of_assoc(did).is_some() { + // if we're calling an inherent impl method, just try to make sure that the receiver type stays the same. + Some(ty) == typeck_results.node_type_opt(arg_hir_id) + } else { + // we're calling a trait method, so we just check removing the method call still satisfies the trait. + let trait_id = tcx + .trait_of_assoc(did) + .unwrap_or_else(|| tcx.impl_trait_id(tcx.parent(did))); + let args = typeck_results.node_args(call_hir_id); + let tr = ty::TraitRef::from_assoc(tcx, trait_id, args) + .with_replaced_self_ty(tcx, ty); + self.type_implements_trait(tr.def_id, tr.args, param_env) + .must_apply_modulo_regions() + } } + _ => true, + }; + + if should_sugg { + err.span_suggestion_verbose( + expr.span.with_lo(rcvr.span.hi()), + format!( + "consider removing this method call, as the receiver has type `{ty}` and \ + `{pred}` trivially holds", + ), + "", + Applicability::MaybeIncorrect, + ); } } if let hir::Expr { kind: hir::ExprKind::Block(block, _), .. } = expr { From cfd4d099f2644b12803dd469d6228a77d9a005e2 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Mon, 29 Dec 2025 04:27:59 +0000 Subject: [PATCH 0087/1061] Prepare for merging from rust-lang/rust This updates the rust-version file to 7fefa09b90ca57b8a0e0e4717d672d38a0ae58b5. --- src/doc/rustc-dev-guide/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index 7345c25066a8..d32b6d0d2fc7 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -2dc30247c5d8293aaa31e1d7dae2ed2fde908ada +7fefa09b90ca57b8a0e0e4717d672d38a0ae58b5 From 2ac2b18910fcfca41d90b80f866b84ff23f0a2e2 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Wed, 19 Nov 2025 11:17:00 +0530 Subject: [PATCH 0088/1061] std: sys: fs: uefi: Implement initial File - Implement basic opening and creating files. - Also implement debug. Signed-off-by: Ayush Singh --- library/std/src/sys/fs/uefi.rs | 153 ++++++++++++++++++++------------- 1 file changed, 95 insertions(+), 58 deletions(-) diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index 1c65e3e2b155..41d35c01252a 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -11,7 +11,7 @@ use crate::sys::{helpers, unsupported}; const FILE_PERMISSIONS_MASK: u64 = r_efi::protocols::file::READ_ONLY; -pub struct File(!); +pub struct File(uefi_fs::File); #[derive(Clone)] pub struct FileAttr { @@ -235,9 +235,11 @@ impl OpenOptions { pub fn create_new(&mut self, create_new: bool) { self.create_new = create_new; + if create_new { + self.create(true); + } } - #[expect(dead_code)] const fn is_mode_valid(&self) -> bool { // Valid Combinations: Read, Read/Write, Read/Write/Create self.mode == file::MODE_READ @@ -247,100 +249,125 @@ impl OpenOptions { } impl File { - pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result { - unsupported() + pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { + if !opts.is_mode_valid() { + return Err(io::const_error!(io::ErrorKind::InvalidInput, "Invalid open options")); + } + + if opts.create_new && exists(path)? { + return Err(io::const_error!(io::ErrorKind::AlreadyExists, "File already exists")); + } + + let f = uefi_fs::File::from_path(path, opts.mode, 0).map(Self)?; + + if opts.truncate { + f.truncate(0)?; + } + + if opts.append { + f.seek(io::SeekFrom::End(0))?; + } + + Ok(f) } pub fn file_attr(&self) -> io::Result { - self.0 + self.0.file_info().map(FileAttr::from_uefi) } pub fn fsync(&self) -> io::Result<()> { - self.0 + unsupported() } pub fn datasync(&self) -> io::Result<()> { - self.0 + unsupported() } pub fn lock(&self) -> io::Result<()> { - self.0 + unsupported() } pub fn lock_shared(&self) -> io::Result<()> { - self.0 + unsupported() } pub fn try_lock(&self) -> Result<(), TryLockError> { - self.0 + unsupported().map_err(TryLockError::Error) } pub fn try_lock_shared(&self) -> Result<(), TryLockError> { - self.0 + unsupported().map_err(TryLockError::Error) } pub fn unlock(&self) -> io::Result<()> { - self.0 + unsupported() } - pub fn truncate(&self, _size: u64) -> io::Result<()> { - self.0 + pub fn truncate(&self, size: u64) -> io::Result<()> { + let mut file_info = self.0.file_info()?; + + unsafe { (*file_info.as_mut_ptr()).file_size = size }; + + self.0.set_file_info(file_info) } pub fn read(&self, _buf: &mut [u8]) -> io::Result { - self.0 + unsupported() } - pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { - self.0 + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + crate::io::default_read_vectored(|b| self.read(b), bufs) } pub fn is_read_vectored(&self) -> bool { - self.0 + false } - pub fn read_buf(&self, _cursor: BorrowedCursor<'_>) -> io::Result<()> { - self.0 + pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + crate::io::default_read_buf(|buf| self.read(buf), cursor) } pub fn write(&self, _buf: &[u8]) -> io::Result { - self.0 + unsupported() } - pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { - self.0 + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + crate::io::default_write_vectored(|b| self.write(b), bufs) } pub fn is_write_vectored(&self) -> bool { - self.0 + false } pub fn flush(&self) -> io::Result<()> { - self.0 + unsupported() } pub fn seek(&self, _pos: SeekFrom) -> io::Result { - self.0 + unsupported() } pub fn size(&self) -> Option> { - self.0 + match self.file_attr() { + Ok(x) => Some(Ok(x.size())), + Err(e) => Some(Err(e)), + } } pub fn tell(&self) -> io::Result { - self.0 + unsupported() } pub fn duplicate(&self) -> io::Result { - self.0 + unsupported() } - pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { - self.0 + pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> { + set_perm_inner(&self.0, perm) } - pub fn set_times(&self, _times: FileTimes) -> io::Result<()> { - self.0 + pub fn set_times(&self, times: FileTimes) -> io::Result<()> { + set_times_inner(&self.0, times) } } @@ -355,8 +382,10 @@ impl DirBuilder { } impl fmt::Debug for File { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0 + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut b = f.debug_struct("File"); + b.field("path", &self.0.path()); + b.finish() } } @@ -391,14 +420,7 @@ pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { let f = uefi_fs::File::from_path(p, file::MODE_READ | file::MODE_WRITE, 0)?; - let mut file_info = f.file_info()?; - - unsafe { - (*file_info.as_mut_ptr()).attribute = - ((*file_info.as_ptr()).attribute & !FILE_PERMISSIONS_MASK) | perm.to_attr() - }; - - f.set_file_info(file_info) + set_perm_inner(&f, perm) } pub fn set_times(p: &Path, times: FileTimes) -> io::Result<()> { @@ -408,21 +430,7 @@ pub fn set_times(p: &Path, times: FileTimes) -> io::Result<()> { pub fn set_times_nofollow(p: &Path, times: FileTimes) -> io::Result<()> { let f = uefi_fs::File::from_path(p, file::MODE_READ | file::MODE_WRITE, 0)?; - let mut file_info = f.file_info()?; - - if let Some(x) = times.accessed { - unsafe { - (*file_info.as_mut_ptr()).last_access_time = uefi_fs::systemtime_to_uefi(x); - } - } - - if let Some(x) = times.modified { - unsafe { - (*file_info.as_mut_ptr()).modification_time = uefi_fs::systemtime_to_uefi(x); - } - } - - f.set_file_info(file_info) + set_times_inner(&f, times) } pub fn rmdir(p: &Path) -> io::Result<()> { @@ -480,6 +488,35 @@ pub fn copy(_from: &Path, _to: &Path) -> io::Result { unsupported() } +fn set_perm_inner(f: &uefi_fs::File, perm: FilePermissions) -> io::Result<()> { + let mut file_info = f.file_info()?; + + unsafe { + (*file_info.as_mut_ptr()).attribute = + ((*file_info.as_ptr()).attribute & !FILE_PERMISSIONS_MASK) | perm.to_attr() + }; + + f.set_file_info(file_info) +} + +fn set_times_inner(f: &uefi_fs::File, times: FileTimes) -> io::Result<()> { + let mut file_info = f.file_info()?; + + if let Some(x) = times.accessed { + unsafe { + (*file_info.as_mut_ptr()).last_access_time = uefi_fs::systemtime_to_uefi(x); + } + } + + if let Some(x) = times.modified { + unsafe { + (*file_info.as_mut_ptr()).modification_time = uefi_fs::systemtime_to_uefi(x); + } + } + + f.set_file_info(file_info) +} + mod uefi_fs { use r_efi::protocols::{device_path, file, simple_file_system}; From dc85816f912581d8114978d86e29ff5d31fcb6af Mon Sep 17 00:00:00 2001 From: Redddy Date: Mon, 29 Dec 2025 16:53:16 +0900 Subject: [PATCH 0089/1061] Add link for perf run Zulip channel --- src/doc/rustc-dev-guide/src/tests/perf.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/tests/perf.md b/src/doc/rustc-dev-guide/src/tests/perf.md index e460ed8187eb..18762556137e 100644 --- a/src/doc/rustc-dev-guide/src/tests/perf.md +++ b/src/doc/rustc-dev-guide/src/tests/perf.md @@ -41,7 +41,9 @@ To evaluate the performance impact of a PR, write this comment on the PR: > repository](https://github.com/rust-lang/team) with the `perf = true` value in > the `[permissions]` section (and bors permissions are also required). If you > are not on one of those teams, feel free to ask for someone to post it for you -> (either on Zulip or ask the assigned reviewer). +> (either on [Zulip][perf run] or ask the assigned reviewer). + +[perf run]: https://rust-lang.zulipchat.com/#narrow/channel/182449-t-compiler.2Fhelp/topic/perf.20run This will first tell bors to do a "try" build which do a full release build for `x86_64-unknown-linux-gnu`. After the build finishes, it will place it in the From 440bf4ded9c7bcc9e597d914c5883ac04edb9b5e Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Mon, 8 Dec 2025 18:24:51 +0100 Subject: [PATCH 0090/1061] =?UTF-8?q?`crate::io::Result`=20=E2=86=92=20`io?= =?UTF-8?q?::Result`=20in=20most=20places?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I don't know why many places refer to the type as `crate::io::Result` when `crate::io` is already imported. --- library/std/src/os/fd/owned.rs | 12 ++-- library/std/src/os/solid/io.rs | 8 +-- library/std/src/os/unix/net/addr.rs | 2 +- library/std/src/os/windows/io/handle.rs | 18 ++--- library/std/src/sys/pal/hermit/mod.rs | 51 +++++++-------- library/std/src/sys/pal/itron/error.rs | 35 +++++----- library/std/src/sys/pal/motor/mod.rs | 65 +++++++++---------- .../std/src/sys/pal/sgx/abi/usercalls/mod.rs | 42 ++++++------ library/std/src/sys/pal/sgx/mod.rs | 54 +++++++-------- library/std/src/sys/pal/sgx/thread_parking.rs | 4 +- library/std/src/sys/pal/solid/error.rs | 20 +++--- library/std/src/sys/pal/solid/mod.rs | 10 +-- library/std/src/sys/pal/teeos/mod.rs | 25 ++++--- library/std/src/sys/pal/uefi/mod.rs | 60 ++++++++--------- library/std/src/sys/pal/uefi/os.rs | 6 +- library/std/src/sys/pal/unix/mod.rs | 16 ++--- library/std/src/sys/pal/unix/os.rs | 15 ++--- library/std/src/sys/pal/wasi/os.rs | 2 +- library/std/src/sys/pal/windows/handle.rs | 6 +- library/std/src/sys/pal/windows/mod.rs | 34 +++++----- library/std/src/thread/builder.rs | 4 -- library/std/src/thread/scoped.rs | 2 - 22 files changed, 237 insertions(+), 254 deletions(-) diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index 846ad37aad22..2acac6f086e4 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -91,7 +91,7 @@ impl OwnedFd { /// Creates a new `OwnedFd` instance that shares the same underlying file /// description as the existing `OwnedFd` instance. #[stable(feature = "io_safety", since = "1.63.0")] - pub fn try_clone(&self) -> crate::io::Result { + pub fn try_clone(&self) -> io::Result { self.as_fd().try_clone_to_owned() } } @@ -106,7 +106,7 @@ impl BorrowedFd<'_> { target_os = "motor" )))] #[stable(feature = "io_safety", since = "1.63.0")] - pub fn try_clone_to_owned(&self) -> crate::io::Result { + pub fn try_clone_to_owned(&self) -> io::Result { // We want to atomically duplicate this file descriptor and set the // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This // is a POSIX flag that was added to Linux in 2.6.24. @@ -129,15 +129,15 @@ impl BorrowedFd<'_> { /// description as the existing `BorrowedFd` instance. #[cfg(any(target_arch = "wasm32", target_os = "hermit", target_os = "trusty"))] #[stable(feature = "io_safety", since = "1.63.0")] - pub fn try_clone_to_owned(&self) -> crate::io::Result { - Err(crate::io::Error::UNSUPPORTED_PLATFORM) + pub fn try_clone_to_owned(&self) -> io::Result { + Err(io::Error::UNSUPPORTED_PLATFORM) } /// Creates a new `OwnedFd` instance that shares the same underlying file /// description as the existing `BorrowedFd` instance. #[cfg(target_os = "motor")] #[stable(feature = "io_safety", since = "1.63.0")] - pub fn try_clone_to_owned(&self) -> crate::io::Result { + pub fn try_clone_to_owned(&self) -> io::Result { let fd = moto_rt::fs::duplicate(self.as_raw_fd()).map_err(crate::sys::map_motor_error)?; Ok(unsafe { OwnedFd::from_raw_fd(fd) }) } @@ -233,7 +233,7 @@ macro_rules! impl_is_terminal { impl crate::sealed::Sealed for $t {} #[stable(feature = "is_terminal", since = "1.70.0")] - impl crate::io::IsTerminal for $t { + impl io::IsTerminal for $t { #[inline] fn is_terminal(&self) -> bool { crate::sys::io::is_terminal(self) diff --git a/library/std/src/os/solid/io.rs b/library/std/src/os/solid/io.rs index a1c8a86c9861..ac112e739170 100644 --- a/library/std/src/os/solid/io.rs +++ b/library/std/src/os/solid/io.rs @@ -49,7 +49,7 @@ use crate::marker::PhantomData; use crate::mem::ManuallyDrop; use crate::sys::{AsInner, FromInner, IntoInner}; -use crate::{fmt, net, sys}; +use crate::{fmt, io, net, sys}; /// Raw file descriptors. pub type RawFd = i32; @@ -110,7 +110,7 @@ impl BorrowedFd<'_> { impl OwnedFd { /// Creates a new `OwnedFd` instance that shares the same underlying file /// description as the existing `OwnedFd` instance. - pub fn try_clone(&self) -> crate::io::Result { + pub fn try_clone(&self) -> io::Result { self.as_fd().try_clone_to_owned() } } @@ -118,7 +118,7 @@ impl OwnedFd { impl BorrowedFd<'_> { /// Creates a new `OwnedFd` instance that shares the same underlying file /// description as the existing `BorrowedFd` instance. - pub fn try_clone_to_owned(&self) -> crate::io::Result { + pub fn try_clone_to_owned(&self) -> io::Result { let fd = sys::net::cvt(unsafe { crate::sys::abi::sockets::dup(self.as_raw_fd()) })?; Ok(unsafe { OwnedFd::from_raw_fd(fd) }) } @@ -184,7 +184,7 @@ macro_rules! impl_is_terminal { impl crate::sealed::Sealed for $t {} #[stable(feature = "is_terminal", since = "1.70.0")] - impl crate::io::IsTerminal for $t { + impl io::IsTerminal for $t { #[inline] fn is_terminal(&self) -> bool { crate::sys::io::is_terminal(self) diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index 25b95014e08b..0748f6984a82 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -264,7 +264,7 @@ impl linux_ext::addr::SocketAddrExt for SocketAddr { if let AddressKind::Abstract(name) = self.address() { Some(name.as_bytes()) } else { None } } - fn from_abstract_name(name: N) -> crate::io::Result + fn from_abstract_name(name: N) -> io::Result where N: AsRef<[u8]>, { diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index afc58ca59cfa..13c0752b560b 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -184,7 +184,7 @@ impl OwnedHandle { /// Creates a new `OwnedHandle` instance that shares the same underlying /// object as the existing `OwnedHandle` instance. #[stable(feature = "io_safety", since = "1.63.0")] - pub fn try_clone(&self) -> crate::io::Result { + pub fn try_clone(&self) -> io::Result { self.as_handle().try_clone_to_owned() } } @@ -193,7 +193,7 @@ impl BorrowedHandle<'_> { /// Creates a new `OwnedHandle` instance that shares the same underlying /// object as the existing `BorrowedHandle` instance. #[stable(feature = "io_safety", since = "1.63.0")] - pub fn try_clone_to_owned(&self) -> crate::io::Result { + pub fn try_clone_to_owned(&self) -> io::Result { self.duplicate(0, false, sys::c::DUPLICATE_SAME_ACCESS) } @@ -409,7 +409,7 @@ macro_rules! impl_is_terminal { impl crate::sealed::Sealed for $t {} #[stable(feature = "is_terminal", since = "1.70.0")] - impl crate::io::IsTerminal for $t { + impl io::IsTerminal for $t { #[inline] fn is_terminal(&self) -> bool { crate::sys::io::is_terminal(self) @@ -546,7 +546,7 @@ impl From for fs::File { } #[stable(feature = "io_safety", since = "1.63.0")] -impl AsHandle for crate::io::Stdin { +impl AsHandle for io::Stdin { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } @@ -554,7 +554,7 @@ impl AsHandle for crate::io::Stdin { } #[stable(feature = "io_safety", since = "1.63.0")] -impl<'a> AsHandle for crate::io::StdinLock<'a> { +impl<'a> AsHandle for io::StdinLock<'a> { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } @@ -562,7 +562,7 @@ impl<'a> AsHandle for crate::io::StdinLock<'a> { } #[stable(feature = "io_safety", since = "1.63.0")] -impl AsHandle for crate::io::Stdout { +impl AsHandle for io::Stdout { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } @@ -570,7 +570,7 @@ impl AsHandle for crate::io::Stdout { } #[stable(feature = "io_safety", since = "1.63.0")] -impl<'a> AsHandle for crate::io::StdoutLock<'a> { +impl<'a> AsHandle for io::StdoutLock<'a> { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } @@ -578,7 +578,7 @@ impl<'a> AsHandle for crate::io::StdoutLock<'a> { } #[stable(feature = "io_safety", since = "1.63.0")] -impl AsHandle for crate::io::Stderr { +impl AsHandle for io::Stderr { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } @@ -586,7 +586,7 @@ impl AsHandle for crate::io::Stderr { } #[stable(feature = "io_safety", since = "1.63.0")] -impl<'a> AsHandle for crate::io::StderrLock<'a> { +impl<'a> AsHandle for io::StderrLock<'a> { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs index 52bcd8da2420..0e1328a7972f 100644 --- a/library/std/src/sys/pal/hermit/mod.rs +++ b/library/std/src/sys/pal/hermit/mod.rs @@ -16,7 +16,7 @@ #![deny(unsafe_op_in_unsafe_fn)] #![allow(missing_docs, nonstandard_style)] -use crate::io::ErrorKind; +use crate::io; use crate::os::hermit::hermit_abi; use crate::os::raw::c_char; use crate::sys::env; @@ -25,15 +25,12 @@ pub mod futex; pub mod os; pub mod time; -pub fn unsupported() -> crate::io::Result { +pub fn unsupported() -> io::Result { Err(unsupported_err()) } -pub fn unsupported_err() -> crate::io::Error { - crate::io::const_error!( - crate::io::ErrorKind::Unsupported, - "operation not supported on HermitCore yet", - ) +pub fn unsupported_err() -> io::Error { + io::const_error!(io::ErrorKind::Unsupported, "operation not supported on HermitCore yet") } pub fn abort_internal() -> ! { @@ -83,24 +80,24 @@ pub(crate) fn is_interrupted(errno: i32) -> bool { errno == hermit_abi::errno::EINTR } -pub fn decode_error_kind(errno: i32) -> ErrorKind { +pub fn decode_error_kind(errno: i32) -> io::ErrorKind { match errno { - hermit_abi::errno::EACCES => ErrorKind::PermissionDenied, - hermit_abi::errno::EADDRINUSE => ErrorKind::AddrInUse, - hermit_abi::errno::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable, - hermit_abi::errno::EAGAIN => ErrorKind::WouldBlock, - hermit_abi::errno::ECONNABORTED => ErrorKind::ConnectionAborted, - hermit_abi::errno::ECONNREFUSED => ErrorKind::ConnectionRefused, - hermit_abi::errno::ECONNRESET => ErrorKind::ConnectionReset, - hermit_abi::errno::EEXIST => ErrorKind::AlreadyExists, - hermit_abi::errno::EINTR => ErrorKind::Interrupted, - hermit_abi::errno::EINVAL => ErrorKind::InvalidInput, - hermit_abi::errno::ENOENT => ErrorKind::NotFound, - hermit_abi::errno::ENOTCONN => ErrorKind::NotConnected, - hermit_abi::errno::EPERM => ErrorKind::PermissionDenied, - hermit_abi::errno::EPIPE => ErrorKind::BrokenPipe, - hermit_abi::errno::ETIMEDOUT => ErrorKind::TimedOut, - _ => ErrorKind::Uncategorized, + hermit_abi::errno::EACCES => io::ErrorKind::PermissionDenied, + hermit_abi::errno::EADDRINUSE => io::ErrorKind::AddrInUse, + hermit_abi::errno::EADDRNOTAVAIL => io::ErrorKind::AddrNotAvailable, + hermit_abi::errno::EAGAIN => io::ErrorKind::WouldBlock, + hermit_abi::errno::ECONNABORTED => io::ErrorKind::ConnectionAborted, + hermit_abi::errno::ECONNREFUSED => io::ErrorKind::ConnectionRefused, + hermit_abi::errno::ECONNRESET => io::ErrorKind::ConnectionReset, + hermit_abi::errno::EEXIST => io::ErrorKind::AlreadyExists, + hermit_abi::errno::EINTR => io::ErrorKind::Interrupted, + hermit_abi::errno::EINVAL => io::ErrorKind::InvalidInput, + hermit_abi::errno::ENOENT => io::ErrorKind::NotFound, + hermit_abi::errno::ENOTCONN => io::ErrorKind::NotConnected, + hermit_abi::errno::EPERM => io::ErrorKind::PermissionDenied, + hermit_abi::errno::EPIPE => io::ErrorKind::BrokenPipe, + hermit_abi::errno::ETIMEDOUT => io::ErrorKind::TimedOut, + _ => io::ErrorKind::Uncategorized, } } @@ -133,16 +130,16 @@ impl IsNegative for i32 { } impl_is_negative! { i8 i16 i64 isize } -pub fn cvt(t: T) -> crate::io::Result { +pub fn cvt(t: T) -> io::Result { if t.is_negative() { let e = decode_error_kind(t.negate()); - Err(crate::io::Error::from(e)) + Err(io::Error::from(e)) } else { Ok(t) } } -pub fn cvt_r(mut f: F) -> crate::io::Result +pub fn cvt_r(mut f: F) -> io::Result where T: IsNegative, F: FnMut() -> T, diff --git a/library/std/src/sys/pal/itron/error.rs b/library/std/src/sys/pal/itron/error.rs index 8ff3017c6147..87be7d5b3546 100644 --- a/library/std/src/sys/pal/itron/error.rs +++ b/library/std/src/sys/pal/itron/error.rs @@ -1,6 +1,5 @@ use super::abi; -use crate::fmt; -use crate::io::ErrorKind; +use crate::{fmt, io}; /// Wraps a μITRON error code. #[derive(Debug, Copy, Clone)] @@ -84,39 +83,39 @@ pub fn is_interrupted(er: abi::ER) -> bool { er == abi::E_RLWAI } -pub fn decode_error_kind(er: abi::ER) -> ErrorKind { +pub fn decode_error_kind(er: abi::ER) -> io::ErrorKind { match er { // Success - er if er >= 0 => ErrorKind::Uncategorized, + er if er >= 0 => io::ErrorKind::Uncategorized, // μITRON 4.0 // abi::E_SYS - abi::E_NOSPT => ErrorKind::Unsupported, // Some("unsupported function"), - abi::E_RSFN => ErrorKind::InvalidInput, // Some("reserved function code"), - abi::E_RSATR => ErrorKind::InvalidInput, // Some("reserved attribute"), - abi::E_PAR => ErrorKind::InvalidInput, // Some("parameter error"), - abi::E_ID => ErrorKind::NotFound, // Some("invalid ID number"), + abi::E_NOSPT => io::ErrorKind::Unsupported, // Some("unsupported function"), + abi::E_RSFN => io::ErrorKind::InvalidInput, // Some("reserved function code"), + abi::E_RSATR => io::ErrorKind::InvalidInput, // Some("reserved attribute"), + abi::E_PAR => io::ErrorKind::InvalidInput, // Some("parameter error"), + abi::E_ID => io::ErrorKind::NotFound, // Some("invalid ID number"), // abi::E_CTX - abi::E_MACV => ErrorKind::PermissionDenied, // Some("memory access violation"), - abi::E_OACV => ErrorKind::PermissionDenied, // Some("object access violation"), + abi::E_MACV => io::ErrorKind::PermissionDenied, // Some("memory access violation"), + abi::E_OACV => io::ErrorKind::PermissionDenied, // Some("object access violation"), // abi::E_ILUSE - abi::E_NOMEM => ErrorKind::OutOfMemory, // Some("insufficient memory"), - abi::E_NOID => ErrorKind::OutOfMemory, // Some("no ID number available"), + abi::E_NOMEM => io::ErrorKind::OutOfMemory, // Some("insufficient memory"), + abi::E_NOID => io::ErrorKind::OutOfMemory, // Some("no ID number available"), // abi::E_OBJ - abi::E_NOEXS => ErrorKind::NotFound, // Some("non-existent object"), + abi::E_NOEXS => io::ErrorKind::NotFound, // Some("non-existent object"), // abi::E_QOVR - abi::E_RLWAI => ErrorKind::Interrupted, // Some("forced release from waiting"), - abi::E_TMOUT => ErrorKind::TimedOut, // Some("polling failure or timeout"), + abi::E_RLWAI => io::ErrorKind::Interrupted, // Some("forced release from waiting"), + abi::E_TMOUT => io::ErrorKind::TimedOut, // Some("polling failure or timeout"), // abi::E_DLT // abi::E_CLS // abi::E_WBLK // abi::E_BOVR // The TOPPERS third generation kernels - abi::E_NORES => ErrorKind::OutOfMemory, // Some("insufficient system resources"), + abi::E_NORES => io::ErrorKind::OutOfMemory, // Some("insufficient system resources"), // abi::E_RASTER // abi::E_COMM - _ => ErrorKind::Uncategorized, + _ => io::ErrorKind::Uncategorized, } } diff --git a/library/std/src/sys/pal/motor/mod.rs b/library/std/src/sys/pal/motor/mod.rs index e4860b1542f0..016fbe5c154c 100644 --- a/library/std/src/sys/pal/motor/mod.rs +++ b/library/std/src/sys/pal/motor/mod.rs @@ -5,12 +5,11 @@ pub mod time; pub use moto_rt::futex; -use crate::io as std_io; -use crate::sys::io::RawOsError; +use crate::io; -pub(crate) fn map_motor_error(err: moto_rt::Error) -> crate::io::Error { +pub(crate) fn map_motor_error(err: moto_rt::Error) -> io::Error { let error_code: moto_rt::ErrorCode = err.into(); - crate::io::Error::from_raw_os_error(error_code.into()) + io::Error::from_raw_os_error(error_code.into()) } #[cfg(not(test))] @@ -37,50 +36,50 @@ pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {} // NOTE: this is not guaranteed to run, for example when the program aborts. pub unsafe fn cleanup() {} -pub fn unsupported() -> std_io::Result { +pub fn unsupported() -> io::Result { Err(unsupported_err()) } -pub fn unsupported_err() -> std_io::Error { - std_io::Error::UNSUPPORTED_PLATFORM +pub fn unsupported_err() -> io::Error { + io::Error::UNSUPPORTED_PLATFORM } -pub fn is_interrupted(_code: RawOsError) -> bool { +pub fn is_interrupted(_code: io::RawOsError) -> bool { false // Motor OS doesn't have signals. } -pub fn decode_error_kind(code: RawOsError) -> crate::io::ErrorKind { - use std_io::ErrorKind; +pub fn decode_error_kind(code: io::RawOsError) -> io::ErrorKind { + use moto_rt::error::*; if code < 0 || code > u16::MAX.into() { - return std_io::ErrorKind::Uncategorized; + return io::ErrorKind::Uncategorized; } let error = moto_rt::Error::from(code as moto_rt::ErrorCode); match error { - moto_rt::Error::Unspecified => ErrorKind::Uncategorized, - moto_rt::Error::Unknown => ErrorKind::Uncategorized, - moto_rt::Error::NotReady => ErrorKind::WouldBlock, - moto_rt::Error::NotImplemented => ErrorKind::Unsupported, - moto_rt::Error::VersionTooHigh => ErrorKind::Unsupported, - moto_rt::Error::VersionTooLow => ErrorKind::Unsupported, - moto_rt::Error::InvalidArgument => ErrorKind::InvalidInput, - moto_rt::Error::OutOfMemory => ErrorKind::OutOfMemory, - moto_rt::Error::NotAllowed => ErrorKind::PermissionDenied, - moto_rt::Error::NotFound => ErrorKind::NotFound, - moto_rt::Error::InternalError => ErrorKind::Other, - moto_rt::Error::TimedOut => ErrorKind::TimedOut, - moto_rt::Error::AlreadyInUse => ErrorKind::AlreadyExists, - moto_rt::Error::UnexpectedEof => ErrorKind::UnexpectedEof, - moto_rt::Error::InvalidFilename => ErrorKind::InvalidFilename, - moto_rt::Error::NotADirectory => ErrorKind::NotADirectory, - moto_rt::Error::BadHandle => ErrorKind::InvalidInput, - moto_rt::Error::FileTooLarge => ErrorKind::FileTooLarge, - moto_rt::Error::NotConnected => ErrorKind::NotConnected, - moto_rt::Error::StorageFull => ErrorKind::StorageFull, - moto_rt::Error::InvalidData => ErrorKind::InvalidData, - _ => crate::io::ErrorKind::Uncategorized, + moto_rt::Error::Unspecified => io::ErrorKind::Uncategorized, + moto_rt::Error::Unknown => io::ErrorKind::Uncategorized, + moto_rt::Error::NotReady => io::ErrorKind::WouldBlock, + moto_rt::Error::NotImplemented => io::ErrorKind::Unsupported, + moto_rt::Error::VersionTooHigh => io::ErrorKind::Unsupported, + moto_rt::Error::VersionTooLow => io::ErrorKind::Unsupported, + moto_rt::Error::InvalidArgument => io::ErrorKind::InvalidInput, + moto_rt::Error::OutOfMemory => io::ErrorKind::OutOfMemory, + moto_rt::Error::NotAllowed => io::ErrorKind::PermissionDenied, + moto_rt::Error::NotFound => io::ErrorKind::NotFound, + moto_rt::Error::InternalError => io::ErrorKind::Other, + moto_rt::Error::TimedOut => io::ErrorKind::TimedOut, + moto_rt::Error::AlreadyInUse => io::ErrorKind::AlreadyExists, + moto_rt::Error::UnexpectedEof => io::ErrorKind::UnexpectedEof, + moto_rt::Error::InvalidFilename => io::ErrorKind::InvalidFilename, + moto_rt::Error::NotADirectory => io::ErrorKind::NotADirectory, + moto_rt::Error::BadHandle => io::ErrorKind::InvalidInput, + moto_rt::Error::FileTooLarge => io::ErrorKind::FileTooLarge, + moto_rt::Error::NotConnected => io::ErrorKind::NotConnected, + moto_rt::Error::StorageFull => io::ErrorKind::StorageFull, + moto_rt::Error::InvalidData => io::ErrorKind::InvalidData, + _ => io::ErrorKind::Uncategorized, } } diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs b/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs index 5041770faf66..f49e940c5044 100644 --- a/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs +++ b/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs @@ -1,7 +1,5 @@ use crate::cmp; -use crate::io::{ - BorrowedCursor, Error as IoError, ErrorKind, IoSlice, IoSliceMut, Result as IoResult, -}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::random::random; use crate::time::{Duration, Instant}; @@ -18,7 +16,7 @@ use self::raw::*; /// This will do a single `read` usercall and scatter the read data among /// `bufs`. To read to a single buffer, just pass a slice of length one. #[unstable(feature = "sgx_platform", issue = "56975")] -pub fn read(fd: Fd, bufs: &mut [IoSliceMut<'_>]) -> IoResult { +pub fn read(fd: Fd, bufs: &mut [IoSliceMut<'_>]) -> io::Result { unsafe { let total_len = bufs.iter().fold(0usize, |sum, buf| sum.saturating_add(buf.len())); let mut userbuf = alloc::User::<[u8]>::uninitialized(total_len); @@ -41,7 +39,7 @@ pub fn read(fd: Fd, bufs: &mut [IoSliceMut<'_>]) -> IoResult { /// Usercall `read` with an uninitialized buffer. See the ABI documentation for /// more information. #[unstable(feature = "sgx_platform", issue = "56975")] -pub fn read_buf(fd: Fd, mut buf: BorrowedCursor<'_>) -> IoResult<()> { +pub fn read_buf(fd: Fd, mut buf: BorrowedCursor<'_>) -> io::Result<()> { unsafe { let mut userbuf = alloc::User::<[u8]>::uninitialized(buf.capacity()); let len = raw::read(fd, userbuf.as_mut_ptr().cast(), userbuf.len()).from_sgx_result()?; @@ -53,7 +51,7 @@ pub fn read_buf(fd: Fd, mut buf: BorrowedCursor<'_>) -> IoResult<()> { /// Usercall `read_alloc`. See the ABI documentation for more information. #[unstable(feature = "sgx_platform", issue = "56975")] -pub fn read_alloc(fd: Fd) -> IoResult> { +pub fn read_alloc(fd: Fd) -> io::Result> { unsafe { let userbuf = ByteBuffer { data: crate::ptr::null_mut(), len: 0 }; let mut userbuf = alloc::User::new_from_enclave(&userbuf); @@ -67,7 +65,7 @@ pub fn read_alloc(fd: Fd) -> IoResult> { /// This will do a single `write` usercall and gather the written data from /// `bufs`. To write from a single buffer, just pass a slice of length one. #[unstable(feature = "sgx_platform", issue = "56975")] -pub fn write(fd: Fd, bufs: &[IoSlice<'_>]) -> IoResult { +pub fn write(fd: Fd, bufs: &[IoSlice<'_>]) -> io::Result { unsafe { let total_len = bufs.iter().fold(0usize, |sum, buf| sum.saturating_add(buf.len())); let mut userbuf = alloc::User::<[u8]>::uninitialized(total_len); @@ -87,7 +85,7 @@ pub fn write(fd: Fd, bufs: &[IoSlice<'_>]) -> IoResult { /// Usercall `flush`. See the ABI documentation for more information. #[unstable(feature = "sgx_platform", issue = "56975")] -pub fn flush(fd: Fd) -> IoResult<()> { +pub fn flush(fd: Fd) -> io::Result<()> { unsafe { raw::flush(fd).from_sgx_result() } } @@ -104,7 +102,7 @@ fn string_from_bytebuffer(buf: &alloc::UserRef, usercall: &str, arg: /// Usercall `bind_stream`. See the ABI documentation for more information. #[unstable(feature = "sgx_platform", issue = "56975")] -pub fn bind_stream(addr: &str) -> IoResult<(Fd, String)> { +pub fn bind_stream(addr: &str) -> io::Result<(Fd, String)> { unsafe { let addr_user = alloc::User::new_from_enclave(addr.as_bytes()); let mut local = alloc::User::::uninitialized(); @@ -117,7 +115,7 @@ pub fn bind_stream(addr: &str) -> IoResult<(Fd, String)> { /// Usercall `accept_stream`. See the ABI documentation for more information. #[unstable(feature = "sgx_platform", issue = "56975")] -pub fn accept_stream(fd: Fd) -> IoResult<(Fd, String, String)> { +pub fn accept_stream(fd: Fd) -> io::Result<(Fd, String, String)> { unsafe { let mut bufs = alloc::User::<[ByteBuffer; 2]>::uninitialized(); let mut buf_it = alloc::UserRef::iter_mut(&mut *bufs); // FIXME: can this be done @@ -133,7 +131,7 @@ pub fn accept_stream(fd: Fd) -> IoResult<(Fd, String, String)> { /// Usercall `connect_stream`. See the ABI documentation for more information. #[unstable(feature = "sgx_platform", issue = "56975")] -pub fn connect_stream(addr: &str) -> IoResult<(Fd, String, String)> { +pub fn connect_stream(addr: &str) -> io::Result<(Fd, String, String)> { unsafe { let addr_user = alloc::User::new_from_enclave(addr.as_bytes()); let mut bufs = alloc::User::<[ByteBuffer; 2]>::uninitialized(); @@ -155,7 +153,7 @@ pub fn connect_stream(addr: &str) -> IoResult<(Fd, String, String)> { /// Usercall `launch_thread`. See the ABI documentation for more information. #[unstable(feature = "sgx_platform", issue = "56975")] -pub unsafe fn launch_thread() -> IoResult<()> { +pub unsafe fn launch_thread() -> io::Result<()> { // SAFETY: The caller must uphold the safety contract for `launch_thread`. unsafe { raw::launch_thread().from_sgx_result() } } @@ -168,7 +166,7 @@ pub fn exit(panic: bool) -> ! { /// Usercall `wait`. See the ABI documentation for more information. #[unstable(feature = "sgx_platform", issue = "56975")] -pub fn wait(event_mask: u64, mut timeout: u64) -> IoResult { +pub fn wait(event_mask: u64, mut timeout: u64) -> io::Result { if timeout != WAIT_NO && timeout != WAIT_INDEFINITE { // We don't want people to rely on accuracy of timeouts to make // security decisions in an SGX enclave. That's why we add a random @@ -216,7 +214,9 @@ where true } Err(e) => { - rtassert!(e.kind() == ErrorKind::TimedOut || e.kind() == ErrorKind::WouldBlock); + rtassert!( + e.kind() == io::ErrorKind::TimedOut || e.kind() == io::ErrorKind::WouldBlock + ); false } } @@ -260,7 +260,7 @@ where /// Usercall `send`. See the ABI documentation for more information. #[unstable(feature = "sgx_platform", issue = "56975")] -pub fn send(event_set: u64, tcs: Option) -> IoResult<()> { +pub fn send(event_set: u64, tcs: Option) -> io::Result<()> { unsafe { raw::send(event_set, tcs).from_sgx_result() } } @@ -273,7 +273,7 @@ pub fn insecure_time() -> Duration { /// Usercall `alloc`. See the ABI documentation for more information. #[unstable(feature = "sgx_platform", issue = "56975")] -pub fn alloc(size: usize, alignment: usize) -> IoResult<*mut u8> { +pub fn alloc(size: usize, alignment: usize) -> io::Result<*mut u8> { unsafe { raw::alloc(size, alignment).from_sgx_result() } } @@ -316,18 +316,18 @@ pub trait FromSgxResult { type Return; /// Translate the raw result of an SGX usercall. - fn from_sgx_result(self) -> IoResult; + fn from_sgx_result(self) -> io::Result; } #[unstable(feature = "sgx_platform", issue = "56975")] impl FromSgxResult for (Result, T) { type Return = T; - fn from_sgx_result(self) -> IoResult { + fn from_sgx_result(self) -> io::Result { if self.0 == RESULT_SUCCESS { Ok(self.1) } else { - Err(IoError::from_raw_os_error(check_os_error(self.0))) + Err(io::Error::from_raw_os_error(check_os_error(self.0))) } } } @@ -336,11 +336,11 @@ impl FromSgxResult for (Result, T) { impl FromSgxResult for Result { type Return = (); - fn from_sgx_result(self) -> IoResult { + fn from_sgx_result(self) -> io::Result { if self == RESULT_SUCCESS { Ok(()) } else { - Err(IoError::from_raw_os_error(check_os_error(self))) + Err(io::Error::from_raw_os_error(check_os_error(self))) } } } diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs index 7a207ceb329e..a067480508c7 100644 --- a/library/std/src/sys/pal/sgx/mod.rs +++ b/library/std/src/sys/pal/sgx/mod.rs @@ -5,7 +5,7 @@ #![deny(unsafe_op_in_unsafe_fn)] #![allow(fuzzy_provenance_casts)] // FIXME: this entire module systematically confuses pointers and integers -use crate::io::ErrorKind; +use crate::io; use crate::sync::atomic::{Atomic, AtomicBool, Ordering}; pub mod abi; @@ -29,12 +29,12 @@ pub unsafe fn cleanup() {} /// This function is used to implement functionality that simply doesn't exist. /// Programs relying on this functionality will need to deal with the error. -pub fn unsupported() -> crate::io::Result { +pub fn unsupported() -> io::Result { Err(unsupported_err()) } -pub fn unsupported_err() -> crate::io::Error { - crate::io::const_error!(ErrorKind::Unsupported, "operation not supported on SGX yet") +pub fn unsupported_err() -> io::Error { + io::const_error!(io::ErrorKind::Unsupported, "operation not supported on SGX yet") } /// This function is used to implement various functions that doesn't exist, @@ -42,11 +42,11 @@ pub fn unsupported_err() -> crate::io::Error { /// returned, the program might very well be able to function normally. This is /// what happens when `SGX_INEFFECTIVE_ERROR` is set to `true`. If it is /// `false`, the behavior is the same as `unsupported`. -pub fn sgx_ineffective(v: T) -> crate::io::Result { +pub fn sgx_ineffective(v: T) -> io::Result { static SGX_INEFFECTIVE_ERROR: Atomic = AtomicBool::new(false); if SGX_INEFFECTIVE_ERROR.load(Ordering::Relaxed) { - Err(crate::io::const_error!( - ErrorKind::Uncategorized, + Err(io::const_error!( + io::ErrorKind::Uncategorized, "operation can't be trusted to have any effect on SGX", )) } else { @@ -59,48 +59,48 @@ pub fn is_interrupted(code: i32) -> bool { code == fortanix_sgx_abi::Error::Interrupted as _ } -pub fn decode_error_kind(code: i32) -> ErrorKind { +pub fn decode_error_kind(code: i32) -> io::ErrorKind { use fortanix_sgx_abi::Error; // FIXME: not sure how to make sure all variants of Error are covered if code == Error::NotFound as _ { - ErrorKind::NotFound + io::ErrorKind::NotFound } else if code == Error::PermissionDenied as _ { - ErrorKind::PermissionDenied + io::ErrorKind::PermissionDenied } else if code == Error::ConnectionRefused as _ { - ErrorKind::ConnectionRefused + io::ErrorKind::ConnectionRefused } else if code == Error::ConnectionReset as _ { - ErrorKind::ConnectionReset + io::ErrorKind::ConnectionReset } else if code == Error::ConnectionAborted as _ { - ErrorKind::ConnectionAborted + io::ErrorKind::ConnectionAborted } else if code == Error::NotConnected as _ { - ErrorKind::NotConnected + io::ErrorKind::NotConnected } else if code == Error::AddrInUse as _ { - ErrorKind::AddrInUse + io::ErrorKind::AddrInUse } else if code == Error::AddrNotAvailable as _ { - ErrorKind::AddrNotAvailable + io::ErrorKind::AddrNotAvailable } else if code == Error::BrokenPipe as _ { - ErrorKind::BrokenPipe + io::ErrorKind::BrokenPipe } else if code == Error::AlreadyExists as _ { - ErrorKind::AlreadyExists + io::ErrorKind::AlreadyExists } else if code == Error::WouldBlock as _ { - ErrorKind::WouldBlock + io::ErrorKind::WouldBlock } else if code == Error::InvalidInput as _ { - ErrorKind::InvalidInput + io::ErrorKind::InvalidInput } else if code == Error::InvalidData as _ { - ErrorKind::InvalidData + io::ErrorKind::InvalidData } else if code == Error::TimedOut as _ { - ErrorKind::TimedOut + io::ErrorKind::TimedOut } else if code == Error::WriteZero as _ { - ErrorKind::WriteZero + io::ErrorKind::WriteZero } else if code == Error::Interrupted as _ { - ErrorKind::Interrupted + io::ErrorKind::Interrupted } else if code == Error::Other as _ { - ErrorKind::Uncategorized + io::ErrorKind::Uncategorized } else if code == Error::UnexpectedEof as _ { - ErrorKind::UnexpectedEof + io::ErrorKind::UnexpectedEof } else { - ErrorKind::Uncategorized + io::ErrorKind::Uncategorized } } diff --git a/library/std/src/sys/pal/sgx/thread_parking.rs b/library/std/src/sys/pal/sgx/thread_parking.rs index 660624ea9c3b..6510a3ab211f 100644 --- a/library/std/src/sys/pal/sgx/thread_parking.rs +++ b/library/std/src/sys/pal/sgx/thread_parking.rs @@ -1,7 +1,7 @@ use fortanix_sgx_abi::{EV_UNPARK, WAIT_INDEFINITE}; use super::abi::usercalls; -use crate::io::ErrorKind; +use crate::io; use crate::time::Duration; pub type ThreadId = fortanix_sgx_abi::Tcs; @@ -15,7 +15,7 @@ pub fn park(_hint: usize) { pub fn park_timeout(dur: Duration, _hint: usize) { let timeout = u128::min(dur.as_nanos(), WAIT_INDEFINITE as u128 - 1) as u64; if let Err(e) = usercalls::wait(EV_UNPARK, timeout) { - assert!(matches!(e.kind(), ErrorKind::TimedOut | ErrorKind::WouldBlock)) + assert!(matches!(e.kind(), io::ErrorKind::TimedOut | io::ErrorKind::WouldBlock)) } } diff --git a/library/std/src/sys/pal/solid/error.rs b/library/std/src/sys/pal/solid/error.rs index b399463c0c28..3e85cdb3c1d9 100644 --- a/library/std/src/sys/pal/solid/error.rs +++ b/library/std/src/sys/pal/solid/error.rs @@ -1,6 +1,6 @@ pub use self::itron::error::{ItronError as SolidError, expect_success}; use super::{abi, itron}; -use crate::io::ErrorKind; +use crate::io; use crate::sys::net; /// Describe the specified SOLID error code. Returns `None` if it's an @@ -31,23 +31,23 @@ pub fn error_name(er: abi::ER) -> Option<&'static str> { } } -pub fn decode_error_kind(er: abi::ER) -> ErrorKind { +pub fn decode_error_kind(er: abi::ER) -> io::ErrorKind { match er { // Success - er if er >= 0 => ErrorKind::Uncategorized, + er if er >= 0 => io::ErrorKind::Uncategorized, er if er < abi::sockets::SOLID_NET_ERR_BASE => net::decode_error_kind(er), - abi::SOLID_ERR_NOTFOUND => ErrorKind::NotFound, - abi::SOLID_ERR_NOTSUPPORTED => ErrorKind::Unsupported, - abi::SOLID_ERR_EBADF => ErrorKind::InvalidInput, - abi::SOLID_ERR_INVALIDCONTENT => ErrorKind::InvalidData, + abi::SOLID_ERR_NOTFOUND => io::ErrorKind::NotFound, + abi::SOLID_ERR_NOTSUPPORTED => io::ErrorKind::Unsupported, + abi::SOLID_ERR_EBADF => io::ErrorKind::InvalidInput, + abi::SOLID_ERR_INVALIDCONTENT => io::ErrorKind::InvalidData, // abi::SOLID_ERR_NOTUSED // abi::SOLID_ERR_ALREADYUSED - abi::SOLID_ERR_OUTOFBOUND => ErrorKind::InvalidInput, + abi::SOLID_ERR_OUTOFBOUND => io::ErrorKind::InvalidInput, // abi::SOLID_ERR_BADSEQUENCE - abi::SOLID_ERR_UNKNOWNDEVICE => ErrorKind::NotFound, + abi::SOLID_ERR_UNKNOWNDEVICE => io::ErrorKind::NotFound, // abi::SOLID_ERR_BUSY - abi::SOLID_ERR_TIMEOUT => ErrorKind::TimedOut, + abi::SOLID_ERR_TIMEOUT => io::ErrorKind::TimedOut, // abi::SOLID_ERR_INVALIDACCESS // abi::SOLID_ERR_NOTREADY _ => itron::error::decode_error_kind(er), diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs index 33df9116f5c2..01477c7dc5e9 100644 --- a/library/std/src/sys/pal/solid/mod.rs +++ b/library/std/src/sys/pal/solid/mod.rs @@ -2,6 +2,8 @@ #![allow(missing_docs, nonstandard_style)] #![forbid(unsafe_op_in_unsafe_fn)] +use crate::io; + pub mod abi; #[path = "../itron"] @@ -28,12 +30,12 @@ pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {} // SAFETY: must be called only once during runtime cleanup. pub unsafe fn cleanup() {} -pub fn unsupported() -> crate::io::Result { +pub fn unsupported() -> io::Result { Err(unsupported_err()) } -pub fn unsupported_err() -> crate::io::Error { - crate::io::Error::UNSUPPORTED_PLATFORM +pub fn unsupported_err() -> io::Error { + io::Error::UNSUPPORTED_PLATFORM } #[inline] @@ -41,7 +43,7 @@ pub fn is_interrupted(code: i32) -> bool { crate::sys::net::is_interrupted(code) } -pub fn decode_error_kind(code: i32) -> crate::io::ErrorKind { +pub fn decode_error_kind(code: i32) -> io::ErrorKind { error::decode_error_kind(code) } diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs index fe2dd9c6c493..627096b11c38 100644 --- a/library/std/src/sys/pal/teeos/mod.rs +++ b/library/std/src/sys/pal/teeos/mod.rs @@ -19,7 +19,7 @@ pub mod sync { pub use mutex::Mutex; } -use crate::io::ErrorKind; +use crate::io; pub fn abort_internal() -> ! { unsafe { libc::abort() } @@ -44,8 +44,8 @@ pub(crate) fn is_interrupted(errno: i32) -> bool { } // Note: code below is 1:1 copied from unix/mod.rs -pub fn decode_error_kind(errno: i32) -> ErrorKind { - use ErrorKind::*; +pub fn decode_error_kind(errno: i32) -> io::ErrorKind { + use io::ErrorKind::*; match errno as libc::c_int { libc::E2BIG => ArgumentListTooLong, libc::EADDRINUSE => AddrInUse, @@ -108,32 +108,31 @@ macro_rules! impl_is_minus_one { impl_is_minus_one! { i8 i16 i32 i64 isize } -pub fn cvt(t: T) -> crate::io::Result { - if t.is_minus_one() { Err(crate::io::Error::last_os_error()) } else { Ok(t) } +pub fn cvt(t: T) -> io::Result { + if t.is_minus_one() { Err(io::Error::last_os_error()) } else { Ok(t) } } -pub fn cvt_r(mut f: F) -> crate::io::Result +pub fn cvt_r(mut f: F) -> io::Result where T: IsMinusOne, F: FnMut() -> T, { loop { match cvt(f()) { - Err(ref e) if e.kind() == ErrorKind::Interrupted => {} + Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} other => return other, } } } -pub fn cvt_nz(error: libc::c_int) -> crate::io::Result<()> { - if error == 0 { Ok(()) } else { Err(crate::io::Error::from_raw_os_error(error)) } +pub fn cvt_nz(error: libc::c_int) -> io::Result<()> { + if error == 0 { Ok(()) } else { Err(io::Error::from_raw_os_error(error)) } } -use crate::io as std_io; -pub fn unsupported() -> std_io::Result { +pub fn unsupported() -> io::Result { Err(unsupported_err()) } -pub fn unsupported_err() -> std_io::Error { - std_io::Error::UNSUPPORTED_PLATFORM +pub fn unsupported_err() -> io::Error { + io::Error::UNSUPPORTED_PLATFORM } diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs index 61725b2ed048..e2f99d6751f5 100644 --- a/library/std/src/sys/pal/uefi/mod.rs +++ b/library/std/src/sys/pal/uefi/mod.rs @@ -13,8 +13,6 @@ //! [`OsString`]: crate::ffi::OsString #![forbid(unsafe_op_in_unsafe_fn)] -use crate::io::RawOsError; - pub mod helpers; pub mod os; pub mod time; @@ -22,7 +20,7 @@ pub mod time; #[cfg(test)] mod tests; -use crate::io as std_io; +use crate::io; use crate::os::uefi; use crate::ptr::NonNull; use crate::sync::atomic::{Atomic, AtomicPtr, Ordering}; @@ -76,20 +74,18 @@ pub unsafe fn cleanup() { } #[inline] -pub const fn unsupported() -> std_io::Result { +pub const fn unsupported() -> io::Result { Err(unsupported_err()) } #[inline] -pub const fn unsupported_err() -> std_io::Error { - std_io::const_error!(std_io::ErrorKind::Unsupported, "operation not supported on UEFI") +pub const fn unsupported_err() -> io::Error { + io::const_error!(io::ErrorKind::Unsupported, "operation not supported on UEFI") } -pub fn decode_error_kind(code: RawOsError) -> crate::io::ErrorKind { +pub fn decode_error_kind(code: io::RawOsError) -> io::ErrorKind { use r_efi::efi::Status; - use crate::io::ErrorKind; - match r_efi::efi::Status::from_usize(code) { Status::ALREADY_STARTED | Status::COMPROMISED_DATA @@ -108,28 +104,28 @@ pub fn decode_error_kind(code: RawOsError) -> crate::io::ErrorKind { | Status::PROTOCOL_ERROR | Status::PROTOCOL_UNREACHABLE | Status::TFTP_ERROR - | Status::VOLUME_CORRUPTED => ErrorKind::Other, - Status::BAD_BUFFER_SIZE | Status::INVALID_LANGUAGE => ErrorKind::InvalidData, - Status::ABORTED => ErrorKind::ConnectionAborted, - Status::ACCESS_DENIED => ErrorKind::PermissionDenied, - Status::BUFFER_TOO_SMALL => ErrorKind::FileTooLarge, - Status::CONNECTION_REFUSED => ErrorKind::ConnectionRefused, - Status::CONNECTION_RESET => ErrorKind::ConnectionReset, - Status::END_OF_FILE => ErrorKind::UnexpectedEof, - Status::HOST_UNREACHABLE => ErrorKind::HostUnreachable, - Status::INVALID_PARAMETER => ErrorKind::InvalidInput, - Status::IP_ADDRESS_CONFLICT => ErrorKind::AddrInUse, - Status::NETWORK_UNREACHABLE => ErrorKind::NetworkUnreachable, - Status::NO_RESPONSE => ErrorKind::HostUnreachable, - Status::NOT_FOUND => ErrorKind::NotFound, - Status::NOT_READY => ErrorKind::ResourceBusy, - Status::OUT_OF_RESOURCES => ErrorKind::OutOfMemory, - Status::SECURITY_VIOLATION => ErrorKind::PermissionDenied, - Status::TIMEOUT => ErrorKind::TimedOut, - Status::UNSUPPORTED => ErrorKind::Unsupported, - Status::VOLUME_FULL => ErrorKind::StorageFull, - Status::WRITE_PROTECTED => ErrorKind::ReadOnlyFilesystem, - _ => ErrorKind::Uncategorized, + | Status::VOLUME_CORRUPTED => io::ErrorKind::Other, + Status::BAD_BUFFER_SIZE | Status::INVALID_LANGUAGE => io::ErrorKind::InvalidData, + Status::ABORTED => io::ErrorKind::ConnectionAborted, + Status::ACCESS_DENIED => io::ErrorKind::PermissionDenied, + Status::BUFFER_TOO_SMALL => io::ErrorKind::FileTooLarge, + Status::CONNECTION_REFUSED => io::ErrorKind::ConnectionRefused, + Status::CONNECTION_RESET => io::ErrorKind::ConnectionReset, + Status::END_OF_FILE => io::ErrorKind::UnexpectedEof, + Status::HOST_UNREACHABLE => io::ErrorKind::HostUnreachable, + Status::INVALID_PARAMETER => io::ErrorKind::InvalidInput, + Status::IP_ADDRESS_CONFLICT => io::ErrorKind::AddrInUse, + Status::NETWORK_UNREACHABLE => io::ErrorKind::NetworkUnreachable, + Status::NO_RESPONSE => io::ErrorKind::HostUnreachable, + Status::NOT_FOUND => io::ErrorKind::NotFound, + Status::NOT_READY => io::ErrorKind::ResourceBusy, + Status::OUT_OF_RESOURCES => io::ErrorKind::OutOfMemory, + Status::SECURITY_VIOLATION => io::ErrorKind::PermissionDenied, + Status::TIMEOUT => io::ErrorKind::TimedOut, + Status::UNSUPPORTED => io::ErrorKind::Unsupported, + Status::VOLUME_FULL => io::ErrorKind::StorageFull, + Status::WRITE_PROTECTED => io::ErrorKind::ReadOnlyFilesystem, + _ => io::ErrorKind::Uncategorized, } } @@ -163,6 +159,6 @@ extern "efiapi" fn exit_boot_service_handler(_e: r_efi::efi::Event, _ctx: *mut c uefi::env::disable_boot_services(); } -pub fn is_interrupted(_code: RawOsError) -> bool { +pub fn is_interrupted(_code: io::RawOsError) -> bool { false } diff --git a/library/std/src/sys/pal/uefi/os.rs b/library/std/src/sys/pal/uefi/os.rs index aae6cb9e0646..5593e195178d 100644 --- a/library/std/src/sys/pal/uefi/os.rs +++ b/library/std/src/sys/pal/uefi/os.rs @@ -1,7 +1,7 @@ use r_efi::efi::Status; use r_efi::efi::protocols::{device_path, loaded_image_device_path}; -use super::{RawOsError, helpers, unsupported_err}; +use super::{helpers, unsupported_err}; use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; use crate::os::uefi; @@ -9,11 +9,11 @@ use crate::path::{self, PathBuf}; use crate::ptr::NonNull; use crate::{fmt, io}; -pub fn errno() -> RawOsError { +pub fn errno() -> io::RawOsError { 0 } -pub fn error_string(errno: RawOsError) -> String { +pub fn error_string(errno: io::RawOsError) -> String { // Keep the List in Alphabetical Order // The Messages are taken from UEFI Specification Appendix D - Status Codes #[rustfmt::skip] diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index a6c5decf2d34..f24898671af8 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -1,6 +1,6 @@ #![allow(missing_docs, nonstandard_style)] -use crate::io::ErrorKind; +use crate::io; #[cfg(target_os = "fuchsia")] pub mod fuchsia; @@ -229,8 +229,8 @@ pub(crate) fn is_interrupted(errno: i32) -> bool { errno == libc::EINTR } -pub fn decode_error_kind(errno: i32) -> ErrorKind { - use ErrorKind::*; +pub fn decode_error_kind(errno: i32) -> io::ErrorKind { + use io::ErrorKind::*; match errno as libc::c_int { libc::E2BIG => ArgumentListTooLong, libc::EADDRINUSE => AddrInUse, @@ -298,12 +298,12 @@ impl_is_minus_one! { i8 i16 i32 i64 isize } /// Converts native return values to Result using the *-1 means error is in `errno`* convention. /// Non-error values are `Ok`-wrapped. -pub fn cvt(t: T) -> crate::io::Result { - if t.is_minus_one() { Err(crate::io::Error::last_os_error()) } else { Ok(t) } +pub fn cvt(t: T) -> io::Result { + if t.is_minus_one() { Err(io::Error::last_os_error()) } else { Ok(t) } } /// `-1` → look at `errno` → retry on `EINTR`. Otherwise `Ok()`-wrap the closure return value. -pub fn cvt_r(mut f: F) -> crate::io::Result +pub fn cvt_r(mut f: F) -> io::Result where T: IsMinusOne, F: FnMut() -> T, @@ -318,8 +318,8 @@ where #[allow(dead_code)] // Not used on all platforms. /// Zero means `Ok()`, all other values are treated as raw OS errors. Does not look at `errno`. -pub fn cvt_nz(error: libc::c_int) -> crate::io::Result<()> { - if error == 0 { Ok(()) } else { Err(crate::io::Error::from_raw_os_error(error)) } +pub fn cvt_nz(error: libc::c_int) -> io::Result<()> { + if error == 0 { Ok(()) } else { Err(io::Error::from_raw_os_error(error)) } } // libc::abort() will run the SIGABRT handler. That's fine because anyone who diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index 7c9f3b7992f7..edb7b604415b 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -244,10 +244,10 @@ pub fn current_exe() -> io::Result { #[cfg(not(test))] use crate::env; - use crate::io::ErrorKind; + use crate::io; let exe_path = env::args().next().ok_or(io::const_error!( - ErrorKind::NotFound, + io::ErrorKind::NotFound, "an executable path was not found because no arguments were provided through argv", ))?; let path = PathBuf::from(exe_path); @@ -272,7 +272,7 @@ pub fn current_exe() -> io::Result { } } } - Err(io::const_error!(ErrorKind::NotFound, "an executable path was not found")) + Err(io::const_error!(io::ErrorKind::NotFound, "an executable path was not found")) } #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] @@ -463,8 +463,7 @@ pub fn current_exe() -> io::Result { name.len(), ); if result != libc::B_OK { - use crate::io::ErrorKind; - Err(io::const_error!(ErrorKind::Uncategorized, "error getting executable path")) + Err(io::const_error!(io::ErrorKind::Uncategorized, "error getting executable path")) } else { // find_path adds the null terminator. let name = CStr::from_ptr(name.as_ptr()).to_bytes(); @@ -485,8 +484,7 @@ pub fn current_exe() -> io::Result { #[cfg(target_os = "l4re")] pub fn current_exe() -> io::Result { - use crate::io::ErrorKind; - Err(io::const_error!(ErrorKind::Unsupported, "not yet implemented!")) + Err(io::const_error!(io::ErrorKind::Unsupported, "not yet implemented!")) } #[cfg(target_os = "vxworks")] @@ -514,10 +512,9 @@ pub fn current_exe() -> io::Result { #[cfg(not(test))] use crate::env; - use crate::io::ErrorKind; let exe_path = env::args().next().ok_or(io::const_error!( - ErrorKind::Uncategorized, + io::ErrorKind::Uncategorized, "an executable path was not found because no arguments were provided through argv", ))?; let path = PathBuf::from(exe_path); diff --git a/library/std/src/sys/pal/wasi/os.rs b/library/std/src/sys/pal/wasi/os.rs index 367c63dfc59e..a3bb329c2c4f 100644 --- a/library/std/src/sys/pal/wasi/os.rs +++ b/library/std/src/sys/pal/wasi/os.rs @@ -157,7 +157,7 @@ pub fn cvt(t: T) -> io::Result { if t.is_minus_one() { Err(io::Error::last_os_error()) } else { Ok(t) } } -pub fn cvt_r(mut f: F) -> crate::io::Result +pub fn cvt_r(mut f: F) -> io::Result where T: IsMinusOne, F: FnMut() -> T, diff --git a/library/std/src/sys/pal/windows/handle.rs b/library/std/src/sys/pal/windows/handle.rs index 90e243e1aa03..9b92cd79c06f 100644 --- a/library/std/src/sys/pal/windows/handle.rs +++ b/library/std/src/sys/pal/windows/handle.rs @@ -3,7 +3,7 @@ use core::ffi::c_void; use core::{cmp, mem, ptr}; -use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut, Read}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read}; use crate::os::windows::io::{ AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle, }; @@ -83,7 +83,7 @@ impl Handle { // pipe semantics, which yields this error when *reading* from // a pipe after the other end has closed; we interpret that as // EOF on the pipe. - Err(ref e) if e.kind() == ErrorKind::BrokenPipe => Ok(0), + Err(ref e) if e.kind() == io::ErrorKind::BrokenPipe => Ok(0), Err(e) => Err(e), } @@ -126,7 +126,7 @@ impl Handle { // pipe semantics, which yields this error when *reading* from // a pipe after the other end has closed; we interpret that as // EOF on the pipe. - Err(ref e) if e.kind() == ErrorKind::BrokenPipe => Ok(()), + Err(ref e) if e.kind() == io::ErrorKind::BrokenPipe => Ok(()), Err(e) => Err(e), } diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index 32bd6ea3a4f6..2db88d7e1fc3 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -2,7 +2,7 @@ #![forbid(unsafe_op_in_unsafe_fn)] use crate::ffi::{OsStr, OsString}; -use crate::io::ErrorKind; +use crate::io; use crate::mem::MaybeUninit; use crate::os::windows::ffi::{OsStrExt, OsStringExt}; use crate::path::PathBuf; @@ -32,13 +32,13 @@ cfg_select! { } pub mod winsock; -/// Map a [`Result`] to [`io::Result`](crate::io::Result). +/// Map a [`Result`] to [`io::Result`]. pub trait IoResult { - fn io_result(self) -> crate::io::Result; + fn io_result(self) -> io::Result; } impl IoResult for Result { - fn io_result(self) -> crate::io::Result { - self.map_err(|e| crate::io::Error::from_raw_os_error(e.code as i32)) + fn io_result(self) -> io::Result { + self.map_err(|e| io::Error::from_raw_os_error(e.code as i32)) } } @@ -65,8 +65,8 @@ pub fn is_interrupted(_errno: i32) -> bool { false } -pub fn decode_error_kind(errno: i32) -> ErrorKind { - use ErrorKind::*; +pub fn decode_error_kind(errno: i32) -> io::ErrorKind { + use io::ErrorKind::*; match errno as u32 { c::ERROR_ACCESS_DENIED => return PermissionDenied, @@ -167,8 +167,8 @@ pub fn unrolled_find_u16s(needle: u16, haystack: &[u16]) -> Option { None } -pub fn to_u16s>(s: S) -> crate::io::Result> { - fn inner(s: &OsStr) -> crate::io::Result> { +pub fn to_u16s>(s: S) -> io::Result> { + fn inner(s: &OsStr) -> io::Result> { // Most paths are ASCII, so reserve capacity for as much as there are bytes // in the OsStr plus one for the null-terminating character. We are not // wasting bytes here as paths created by this function are primarily used @@ -177,8 +177,8 @@ pub fn to_u16s>(s: S) -> crate::io::Result> { maybe_result.extend(s.encode_wide()); if unrolled_find_u16s(0, &maybe_result).is_some() { - return Err(crate::io::const_error!( - ErrorKind::InvalidInput, + return Err(io::const_error!( + io::ErrorKind::InvalidInput, "strings passed to WinAPI cannot contain NULs", )); } @@ -209,7 +209,7 @@ pub fn to_u16s>(s: S) -> crate::io::Result> { // Once the syscall has completed (errors bail out early) the second closure is // passed the data which has been read from the syscall. The return value // from this closure is then the return value of the function. -pub fn fill_utf16_buf(mut f1: F1, f2: F2) -> crate::io::Result +pub fn fill_utf16_buf(mut f1: F1, f2: F2) -> io::Result where F1: FnMut(*mut u16, u32) -> u32, F2: FnOnce(&[u16]) -> T, @@ -251,7 +251,7 @@ where c::SetLastError(0); let k = match f1(buf.as_mut_ptr().cast::(), n as u32) { 0 if api::get_last_error().code == 0 => 0, - 0 => return Err(crate::io::Error::last_os_error()), + 0 => return Err(io::Error::last_os_error()), n => n, } as usize; if k == n && api::get_last_error().code == c::ERROR_INSUFFICIENT_BUFFER { @@ -285,9 +285,9 @@ pub fn truncate_utf16_at_nul(v: &[u16]) -> &[u16] { } } -pub fn ensure_no_nuls>(s: T) -> crate::io::Result { +pub fn ensure_no_nuls>(s: T) -> io::Result { if s.as_ref().encode_wide().any(|b| b == 0) { - Err(crate::io::const_error!(ErrorKind::InvalidInput, "nul byte found in provided data")) + Err(io::const_error!(io::ErrorKind::InvalidInput, "nul byte found in provided data")) } else { Ok(s) } @@ -307,8 +307,8 @@ macro_rules! impl_is_zero { impl_is_zero! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } -pub fn cvt(i: I) -> crate::io::Result { - if i.is_zero() { Err(crate::io::Error::last_os_error()) } else { Ok(i) } +pub fn cvt(i: I) -> io::Result { + if i.is_zero() { Err(io::Error::last_os_error()) } else { Ok(i) } } pub fn dur2timeout(dur: Duration) -> u32 { diff --git a/library/std/src/thread/builder.rs b/library/std/src/thread/builder.rs index f4abe074ab9d..baec8c905d80 100644 --- a/library/std/src/thread/builder.rs +++ b/library/std/src/thread/builder.rs @@ -40,7 +40,6 @@ use crate::io; /// [`name`]: Builder::name /// [`spawn`]: Builder::spawn /// [`thread::spawn`]: super::spawn -/// [`io::Result`]: crate::io::Result /// [`unwrap`]: crate::result::Result::unwrap /// [naming-threads]: ./index.html#naming-threads /// [stack-size]: ./index.html#stack-size @@ -161,8 +160,6 @@ impl Builder { /// [`io::Result`] to capture any failure to create the thread at /// the OS level. /// - /// [`io::Result`]: crate::io::Result - /// /// # Panics /// /// Panics if a thread name was set and it contained null bytes. @@ -250,7 +247,6 @@ impl Builder { /// handler.join().unwrap(); /// ``` /// - /// [`io::Result`]: crate::io::Result /// [`thread::spawn`]: super::spawn /// [`spawn`]: super::spawn #[stable(feature = "thread_spawn_unchecked", since = "1.82.0")] diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs index 301f5e949cac..3ac9956336d7 100644 --- a/library/std/src/thread/scoped.rs +++ b/library/std/src/thread/scoped.rs @@ -210,8 +210,6 @@ impl Builder { /// Unlike [`Scope::spawn`], this method yields an [`io::Result`] to /// capture any failure to create the thread at the OS level. /// - /// [`io::Result`]: crate::io::Result - /// /// # Panics /// /// Panics if a thread name was set and it contained null bytes. From 866598d912e032c7fe4c859ce217338ae530b086 Mon Sep 17 00:00:00 2001 From: Redddy Date: Tue, 30 Dec 2025 00:20:18 +0900 Subject: [PATCH 0091/1061] Add guidance on suppressing warnings in tests --- src/doc/rustc-dev-guide/src/tests/best-practices.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/rustc-dev-guide/src/tests/best-practices.md b/src/doc/rustc-dev-guide/src/tests/best-practices.md index 10372c36ac99..ff4ea11bbc7a 100644 --- a/src/doc/rustc-dev-guide/src/tests/best-practices.md +++ b/src/doc/rustc-dev-guide/src/tests/best-practices.md @@ -153,6 +153,7 @@ This may include remarks on: - Try to make sure the test is as minimal as possible. - Minimize non-critical code and especially minimize unnecessary syntax and type errors which can clutter stderr snapshots. +- Use `#![allow(...)]` or `#![expect(...)]` to suppress unrelated warnings. - Where possible, use semantically meaningful names (e.g. `fn bare_coverage_attributes() {}`). From 67a76f9fb5893c87bee0360e72a74ed33e2b0741 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Mon, 29 Dec 2025 18:32:24 +0000 Subject: [PATCH 0092/1061] fix: `implicit_saturating_sub` suggests wrongly on untyped int literal --- clippy_lints/src/implicit_saturating_sub.rs | 27 ++++++++++++++++----- clippy_utils/src/lib.rs | 13 +++++++++- clippy_utils/src/sugg.rs | 2 +- tests/ui/implicit_saturating_sub.fixed | 8 ++++++ tests/ui/implicit_saturating_sub.rs | 8 ++++++ tests/ui/implicit_saturating_sub.stderr | 8 +++++- 6 files changed, 57 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 7b6f8729cb75..516f9e3aa60c 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -1,9 +1,13 @@ +use std::borrow::Cow; + use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::{Sugg, make_binop}; use clippy_utils::{ - SpanlessEq, eq_expr_value, higher, is_in_const_context, is_integer_literal, peel_blocks, peel_blocks_with_stmt, sym, + SpanlessEq, eq_expr_value, higher, is_in_const_context, is_integer_literal, is_integer_literal_untyped, + peel_blocks, peel_blocks_with_stmt, sym, }; use rustc_ast::ast::LitKind; use rustc_data_structures::packed::Pu128; @@ -238,10 +242,21 @@ fn check_subtraction( if eq_expr_value(cx, left, big_expr) && eq_expr_value(cx, right, little_expr) { // This part of the condition is voluntarily split from the one before to ensure that // if `snippet_opt` fails, it won't try the next conditions. - if (!is_in_const_context(cx) || msrv.meets(cx, msrvs::SATURATING_SUB_CONST)) - && let Some(big_expr_sugg) = Sugg::hir_opt(cx, big_expr).map(Sugg::maybe_paren) - && let Some(little_expr_sugg) = Sugg::hir_opt(cx, little_expr) - { + if !is_in_const_context(cx) || msrv.meets(cx, msrvs::SATURATING_SUB_CONST) { + let mut applicability = Applicability::MachineApplicable; + let big_expr_sugg = (if is_integer_literal_untyped(big_expr) { + let get_snippet = |span: Span| { + let snippet = snippet_with_applicability(cx, span, "..", &mut applicability); + let big_expr_ty = cx.typeck_results().expr_ty(big_expr); + Cow::Owned(format!("{snippet}_{big_expr_ty}")) + }; + Sugg::hir_from_snippet(cx, big_expr, get_snippet) + } else { + Sugg::hir_with_applicability(cx, big_expr, "..", &mut applicability) + }) + .maybe_paren(); + let little_expr_sugg = Sugg::hir_with_applicability(cx, little_expr, "..", &mut applicability); + let sugg = format!( "{}{big_expr_sugg}.saturating_sub({little_expr_sugg}){}", if is_composited { "{ " } else { "" }, @@ -254,7 +269,7 @@ fn check_subtraction( "manual arithmetic check found", "replace it with", sugg, - Applicability::MachineApplicable, + applicability, ); } } else if eq_expr_value(cx, left, little_expr) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 954c32687af6..2d079deb0ce4 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -90,7 +90,7 @@ use std::sync::{Mutex, MutexGuard, OnceLock}; use itertools::Itertools; use rustc_abi::Integer; use rustc_ast::ast::{self, LitKind, RangeLimits}; -use rustc_ast::join_path_syms; +use rustc_ast::{LitIntType, join_path_syms}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexmap; use rustc_data_structures::packed::Pu128; @@ -1385,6 +1385,17 @@ pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool { false } +/// Checks whether the given expression is an untyped integer literal. +pub fn is_integer_literal_untyped(expr: &Expr<'_>) -> bool { + if let ExprKind::Lit(spanned) = expr.kind + && let LitKind::Int(_, suffix) = spanned.node + { + return suffix == LitIntType::Unsuffixed; + } + + false +} + /// Checks whether the given expression is a constant literal of the given value. pub fn is_float_literal(expr: &Expr<'_>, value: f64) -> bool { if let ExprKind::Lit(spanned) = expr.kind diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index 2ef2afb45071..3ade38bea8ed 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -127,7 +127,7 @@ impl<'a> Sugg<'a> { /// Generate a suggestion for an expression with the given snippet. This is used by the `hir_*` /// function variants of `Sugg`, since these use different snippet functions. - fn hir_from_snippet( + pub fn hir_from_snippet( cx: &LateContext<'_>, expr: &hir::Expr<'_>, mut get_snippet: impl FnMut(Span) -> Cow<'a, str>, diff --git a/tests/ui/implicit_saturating_sub.fixed b/tests/ui/implicit_saturating_sub.fixed index 1aab6c54407e..22e59bbd2705 100644 --- a/tests/ui/implicit_saturating_sub.fixed +++ b/tests/ui/implicit_saturating_sub.fixed @@ -252,3 +252,11 @@ fn arbitrary_expression() { 0 }; } + +fn issue16307() { + let x: u8 = 100; + let y = 100_u8.saturating_sub(x); + //~^ implicit_saturating_sub + + println!("{y}"); +} diff --git a/tests/ui/implicit_saturating_sub.rs b/tests/ui/implicit_saturating_sub.rs index 7ca57a2902db..7fa19f0c8ad2 100644 --- a/tests/ui/implicit_saturating_sub.rs +++ b/tests/ui/implicit_saturating_sub.rs @@ -326,3 +326,11 @@ fn arbitrary_expression() { 0 }; } + +fn issue16307() { + let x: u8 = 100; + let y = if x >= 100 { 0 } else { 100 - x }; + //~^ implicit_saturating_sub + + println!("{y}"); +} diff --git a/tests/ui/implicit_saturating_sub.stderr b/tests/ui/implicit_saturating_sub.stderr index 0c225856fd07..2f3d2ba787e8 100644 --- a/tests/ui/implicit_saturating_sub.stderr +++ b/tests/ui/implicit_saturating_sub.stderr @@ -238,5 +238,11 @@ error: manual arithmetic check found LL | let _ = if a < b * 2 { 0 } else { a - b * 2 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.saturating_sub(b * 2)` -error: aborting due to 27 previous errors +error: manual arithmetic check found + --> tests/ui/implicit_saturating_sub.rs:332:13 + | +LL | let y = if x >= 100 { 0 } else { 100 - x }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `100_u8.saturating_sub(x)` + +error: aborting due to 28 previous errors From 1ff953d63e8d470892d13cb99abeadb42bc1d997 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Mon, 29 Dec 2025 19:23:26 +0000 Subject: [PATCH 0093/1061] Fix and expand direct-access-external-data test This test currently doesn't fulfill its purpose, as `external dso_local` can still match `external {{.*}}`. Fix this by using CHECK-NOT directives. Also, this test is expanded to all platforms where it makes sense, instead of restricting to loongarch. --- .../direct-access-external-data.rs | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/tests/codegen-llvm/direct-access-external-data.rs b/tests/codegen-llvm/direct-access-external-data.rs index 5b2ff41ef052..c2c32d17ff7e 100644 --- a/tests/codegen-llvm/direct-access-external-data.rs +++ b/tests/codegen-llvm/direct-access-external-data.rs @@ -1,21 +1,25 @@ -//@ only-loongarch64-unknown-linux-gnu +//@ ignore-powerpc64 (handles dso_local differently) +//@ ignore-apple (handles dso_local differently) -//@ revisions: DEFAULT DIRECT INDIRECT +//@ revisions: DEFAULT PIE DIRECT INDIRECT //@ [DEFAULT] compile-flags: -C relocation-model=static -//@ [DIRECT] compile-flags: -C relocation-model=static -Z direct-access-external-data=yes +//@ [PIE] compile-flags: -C relocation-model=pie +//@ [DIRECT] compile-flags: -C relocation-model=pie -Z direct-access-external-data=yes //@ [INDIRECT] compile-flags: -C relocation-model=static -Z direct-access-external-data=no #![crate_type = "rlib"] -// DEFAULT: @VAR = external {{.*}} global i32 -// DIRECT: @VAR = external dso_local {{.*}} global i32 -// INDIRECT: @VAR = external {{.*}} global i32 - -extern "C" { - static VAR: i32; +unsafe extern "C" { + // CHECK: @VAR = external + // DEFAULT-SAME: dso_local + // PIE-NOT: dso_local + // DIRECT-SAME: dso_local + // INDIRECT-NOT: dso_local + // CHECK-SAME: global i32 + safe static VAR: i32; } #[no_mangle] -pub fn get() -> i32 { - unsafe { VAR } +pub fn refer() { + core::hint::black_box(VAR); } From 5467a398c2a33c9a49db2117c2c6f9e12015dd16 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Mon, 29 Dec 2025 17:21:29 +0000 Subject: [PATCH 0094/1061] Fix dso_local for external statics with linkage The current code applies `dso_local` to the internal generated symbols instead of the actually-externally one. --- compiler/rustc_codegen_llvm/src/consts.rs | 4 ++++ .../direct-access-external-data.rs | 23 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 08c53179bc14..2b04f81c267f 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -187,6 +187,10 @@ fn check_and_apply_linkage<'ll, 'tcx>( }; llvm::set_linkage(g1, base::linkage_to_llvm(linkage)); + // Normally this is done in `get_static_inner`, but when as we generate an internal global, + // it will apply the dso_local to the internal global instead, so do it here, too. + cx.assume_dso_local(g1, true); + // Declare an internal global `extern_with_linkage_foo` which // is initialized with the address of `foo`. If `foo` is // discarded during linking (for example, if `foo` has weak diff --git a/tests/codegen-llvm/direct-access-external-data.rs b/tests/codegen-llvm/direct-access-external-data.rs index c2c32d17ff7e..73dc08dc2b57 100644 --- a/tests/codegen-llvm/direct-access-external-data.rs +++ b/tests/codegen-llvm/direct-access-external-data.rs @@ -8,6 +8,7 @@ //@ [INDIRECT] compile-flags: -C relocation-model=static -Z direct-access-external-data=no #![crate_type = "rlib"] +#![feature(linkage)] unsafe extern "C" { // CHECK: @VAR = external @@ -17,9 +18,31 @@ unsafe extern "C" { // INDIRECT-NOT: dso_local // CHECK-SAME: global i32 safe static VAR: i32; + + // When "linkage" is used, we generate an indirection global. + // Check dso_local is still applied to the actual global. + // CHECK: @EXTERNAL = external + // DEFAULT-SAME: dso_local + // PIE-NOT: dso_local + // DIRECT-SAME: dso_local + // INDIRECT-NOT: dso_local + // CHECK-SAME: global i8 + #[linkage = "external"] + safe static EXTERNAL: *const u32; + + // CHECK: @WEAK = extern_weak + // DEFAULT-SAME: dso_local + // PIE-NOT: dso_local + // DIRECT-SAME: dso_local + // INDIRECT-NOT: dso_local + // CHECK-SAME: global i8 + #[linkage = "extern_weak"] + safe static WEAK: *const u32; } #[no_mangle] pub fn refer() { core::hint::black_box(VAR); + core::hint::black_box(EXTERNAL); + core::hint::black_box(WEAK); } From 36d8e77439b37c5bec246700d8778fce5a626119 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Mon, 29 Dec 2025 11:40:41 -0600 Subject: [PATCH 0095/1061] Correct hexagon "unwinder_private_data_size" Discovered while porting libstd to hexagon-unknown-qurt: the unwinder data size refers to the count of pointers in _Unwind_Exception but when I put the value "35" intiially for hexagon linux, I incorrectly considered the size of the exception context hexagon_thread_state_t data structure. Correct the value for hexagon linux and expand it to cover all hexagon architecture instead. --- library/unwind/src/libunwind.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index 9ac9b54ed4a2..091efa9c5129 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -78,8 +78,8 @@ pub const unwinder_private_data_size: usize = 20; #[cfg(all(target_arch = "wasm32", target_os = "linux"))] pub const unwinder_private_data_size: usize = 2; -#[cfg(all(target_arch = "hexagon", target_os = "linux"))] -pub const unwinder_private_data_size: usize = 35; +#[cfg(target_arch = "hexagon")] +pub const unwinder_private_data_size: usize = 5; #[cfg(any(target_arch = "loongarch32", target_arch = "loongarch64"))] pub const unwinder_private_data_size: usize = 2; From 8cd16cd18bf3259dd765e67456ee8c7095c85d98 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 7 Dec 2025 00:06:07 +0100 Subject: [PATCH 0096/1061] adjust how backtraces get rendered; always show thread name when there are multiple threads --- src/tools/miri/src/diagnostics.rs | 67 ++++++++++++------- ...pple_os_unfair_lock_move_with_queue.stderr | 1 + .../libc_pthread_cond_move.init.stderr | 5 +- ...thread_cond_move.static_initializer.stderr | 5 +- .../libc_pthread_join_detached.stderr | 1 + .../libc_pthread_join_joined.stderr | 1 + .../concurrency/libc_pthread_join_main.stderr | 1 + .../libc_pthread_join_multiple.stderr | 1 + .../concurrency/libc_pthread_join_self.stderr | 1 + .../libc_pthread_mutex_deadlock.stderr | 15 +++-- ...ibc_pthread_mutex_free_while_queued.stderr | 9 ++- .../libc_pthread_mutex_move.init.stderr | 5 +- ...hread_mutex_move.static_initializer.stderr | 5 +- ...libc_pthread_mutex_normal_reentrant.stderr | 2 +- ...ibc_pthread_mutex_read_while_queued.stderr | 1 + ...bc_pthread_mutex_write_while_queued.stderr | 1 + .../libc_pthread_mutex_wrong_owner.stderr | 1 + ...k_read_write_deadlock_single_thread.stderr | 2 +- ...ibc_pthread_rwlock_read_wrong_owner.stderr | 1 + ..._pthread_rwlock_write_read_deadlock.stderr | 15 +++-- ...k_write_read_deadlock_single_thread.stderr | 2 +- ...pthread_rwlock_write_write_deadlock.stderr | 15 +++-- ..._write_write_deadlock_single_thread.stderr | 2 +- ...bc_pthread_rwlock_write_wrong_owner.stderr | 1 + .../concurrency/windows_join_detached.stderr | 9 ++- .../concurrency/windows_join_main.stderr | 14 ++-- .../concurrency/windows_join_self.stderr | 15 +++-- .../libc/env-set_var-data-race.stderr | 1 + .../libc/eventfd_block_read_twice.stderr | 15 +++-- .../libc/eventfd_block_write_twice.stderr | 15 +++-- .../libc/fcntl_fsetfl_while_blocking.stderr | 4 +- .../libc/fs/mkstemp_immutable_arg.stderr | 5 +- .../fs/unix_open_missing_required_mode.stderr | 5 +- .../fail-dep/libc/libc-epoll-data-race.stderr | 1 + .../libc/libc_epoll_block_two_thread.stderr | 15 +++-- .../socketpair-close-while-blocked.stderr | 15 +++-- .../fail-dep/libc/socketpair-data-race.stderr | 1 + .../libc/socketpair_block_read_twice.stderr | 15 +++-- .../libc/socketpair_block_write_twice.stderr | 15 +++-- .../fail/alloc/alloc_error_handler.stderr | 15 ++--- .../alloc/alloc_error_handler_custom.stderr | 11 ++- .../alloc/alloc_error_handler_no_std.stderr | 11 ++- .../fail/alloc/global_system_mixup.stderr | 7 +- .../miri/tests/fail/alloc/stack_free.stderr | 9 ++- .../fail/async-shared-mutable.stack.stderr | 13 ++-- .../fail/async-shared-mutable.tree.stderr | 13 ++-- .../both_borrows/aliasing_mut1.stack.stderr | 9 ++- .../both_borrows/aliasing_mut1.tree.stderr | 9 ++- .../both_borrows/aliasing_mut2.stack.stderr | 9 ++- .../both_borrows/aliasing_mut2.tree.stderr | 9 ++- .../both_borrows/aliasing_mut3.stack.stderr | 9 ++- .../both_borrows/aliasing_mut3.tree.stderr | 9 ++- .../both_borrows/aliasing_mut4.stack.stderr | 9 ++- .../both_borrows/aliasing_mut4.tree.stderr | 15 +++-- .../box_exclusive_violation1.stack.stderr | 11 +-- .../box_exclusive_violation1.tree.stderr | 11 +-- .../box_noalias_violation.stack.stderr | 9 ++- .../box_noalias_violation.tree.stderr | 9 ++- .../buggy_split_at_mut.stack.stderr | 9 ++- .../both_borrows/illegal_write6.stack.stderr | 9 ++- .../both_borrows/illegal_write6.tree.stderr | 9 ++- ...invalidate_against_protector2.stack.stderr | 9 ++- .../invalidate_against_protector2.tree.stderr | 9 ++- ...invalidate_against_protector3.stack.stderr | 9 ++- .../invalidate_against_protector3.tree.stderr | 9 ++- .../issue-miri-1050-1.stack.stderr | 11 +-- .../issue-miri-1050-1.tree.stderr | 11 +-- .../issue-miri-1050-2.stack.stderr | 7 +- .../issue-miri-1050-2.tree.stderr | 7 +- .../mut_exclusive_violation1.stack.stderr | 11 +-- .../mut_exclusive_violation1.tree.stderr | 11 +-- .../newtype_pair_retagging.stack.stderr | 15 +++-- .../newtype_pair_retagging.tree.stderr | 17 +++-- .../newtype_retagging.stack.stderr | 15 +++-- .../newtype_retagging.tree.stderr | 17 +++-- .../retag_data_race_write.stack.stderr | 9 ++- .../retag_data_race_write.tree.stderr | 9 ++- .../return_invalid_shr.stack.stderr | 9 ++- .../return_invalid_shr.tree.stderr | 9 ++- .../return_invalid_shr_option.stack.stderr | 9 ++- .../return_invalid_shr_option.tree.stderr | 9 ++- .../return_invalid_shr_tuple.stack.stderr | 9 ++- .../return_invalid_shr_tuple.tree.stderr | 9 ++- .../shr_frozen_violation1.stack.stderr | 11 +-- .../shr_frozen_violation1.tree.stderr | 11 +-- .../miri/tests/fail/box-cell-alias.stderr | 9 ++- .../fail/closures/uninhabited-variant.stderr | 5 +- .../concurrency/mutex-leak-move-deadlock.rs | 2 +- .../mutex-leak-move-deadlock.stderr | 4 +- .../tests/fail/coroutine-pinned-moved.stderr | 13 ++-- .../dangling_pointer_to_raw_pointer.stderr | 5 +- .../storage_dead_dangling.stderr | 5 +- .../fail/data_race/alloc_read_race.stderr | 1 + .../fail/data_race/alloc_write_race.stderr | 1 + .../atomic_read_na_write_race1.stderr | 1 + .../atomic_read_na_write_race2.stderr | 1 + .../atomic_write_na_read_race1.stderr | 1 + .../atomic_write_na_read_race2.stderr | 1 + .../atomic_write_na_write_race1.stderr | 1 + .../atomic_write_na_write_race2.stderr | 1 + .../dangling_thread_async_race.stderr | 1 + .../data_race/dangling_thread_race.stderr | 1 + .../fail/data_race/dealloc_read_race1.stderr | 1 + .../fail/data_race/dealloc_read_race2.stderr | 1 + .../data_race/dealloc_read_race_stack.stderr | 1 + .../fail/data_race/dealloc_write_race1.stderr | 1 + .../fail/data_race/dealloc_write_race2.stderr | 1 + .../data_race/dealloc_write_race_stack.stderr | 1 + .../enable_after_join_to_main.stderr | 1 + .../fail/data_race/fence_after_load.stderr | 1 + .../local_variable_alloc_race.stderr | 1 + .../data_race/local_variable_read_race.stderr | 1 + .../local_variable_write_race.stderr | 1 + ...ze_read_read_write.match_first_load.stderr | 1 + ...e_read_read_write.match_second_load.stderr | 1 + .../mixed_size_read_write.read_write.stderr | 1 + .../mixed_size_read_write.write_read.stderr | 1 + .../mixed_size_read_write_read.stderr | 1 + .../mixed_size_write_write.fst.stderr | 1 + .../mixed_size_write_write.snd.stderr | 1 + .../fail/data_race/read_write_race.stderr | 1 + .../data_race/read_write_race_stack.stderr | 1 + .../fail/data_race/relax_acquire_race.stderr | 1 + .../fail/data_race/release_seq_race.stderr | 1 + .../release_seq_race_same_thread.stderr | 1 + .../miri/tests/fail/data_race/rmw_race.stderr | 1 + .../fail/data_race/stack_pop_race.stderr | 1 + .../fail/data_race/write_write_race.stderr | 1 + .../data_race/write_write_race_stack.stderr | 1 + ...et-discriminant-niche-variant-wrong.stderr | 5 +- .../arg_inplace_mutate.stack.stderr | 9 ++- .../arg_inplace_mutate.tree.stderr | 9 ++- .../arg_inplace_observe_during.none.stderr | 5 +- .../arg_inplace_observe_during.stack.stderr | 9 ++- .../arg_inplace_observe_during.tree.stderr | 9 ++- .../exported_symbol_bad_unwind2.both.stderr | 17 +++-- ...orted_symbol_bad_unwind2.definition.stderr | 17 +++-- .../return_pointer_aliasing_read.none.stderr | 5 +- .../return_pointer_aliasing_read.stack.stderr | 9 ++- .../return_pointer_aliasing_read.tree.stderr | 9 ++- ...return_pointer_aliasing_write.stack.stderr | 9 ++- .../return_pointer_aliasing_write.tree.stderr | 9 ++- ...nter_aliasing_write_tail_call.stack.stderr | 9 ++- ...inter_aliasing_write_tail_call.tree.stderr | 9 ++- .../simd_feature_flag_difference.stderr | 5 +- .../ptr_metadata_uninit_slice_data.stderr | 5 +- .../ptr_metadata_uninit_slice_len.stderr | 5 +- .../ptr_metadata_uninit_thin.stderr | 5 +- .../typed-swap-invalid-array.stderr | 5 +- .../typed-swap-invalid-scalar.left.stderr | 5 +- .../typed-swap-invalid-scalar.right.stderr | 5 +- .../miri/tests/fail/issue-miri-1112.stderr | 5 +- src/tools/miri/tests/fail/memleak_rc.stderr | 5 +- .../tests/fail/never_transmute_void.stderr | 5 +- .../tests/fail/overlapping_assignment.stderr | 5 +- .../miri/tests/fail/panic/abort_unwind.stderr | 17 +++-- .../miri/tests/fail/panic/bad_unwind.stderr | 11 ++- .../miri/tests/fail/panic/double_panic.stderr | 15 ++--- src/tools/miri/tests/fail/panic/no_std.stderr | 5 +- .../miri/tests/fail/panic/panic_abort1.stderr | 17 +++-- .../miri/tests/fail/panic/panic_abort2.stderr | 17 +++-- .../miri/tests/fail/panic/panic_abort3.stderr | 17 +++-- .../miri/tests/fail/panic/panic_abort4.stderr | 17 +++-- .../provenance/provenance_transmute.stderr | 5 +- .../tests/fail/ptr_swap_nonoverlapping.stderr | 11 ++- .../tests/fail/shims/fs/isolated_file.stderr | 25 ++++--- .../tests/fail/shims/isolated_stdin.stderr | 2 +- .../deallocate_against_protector1.stderr | 15 ++--- .../drop_in_place_protector.stderr | 13 ++-- .../drop_in_place_retag.stderr | 11 ++- .../invalidate_against_protector1.stderr | 9 ++- .../stacked_borrows/pointer_smuggling.stderr | 9 ++- .../retag_data_race_protected_read.stderr | 1 + .../retag_data_race_read.stderr | 9 ++- .../stacked_borrows/return_invalid_mut.stderr | 9 ++- .../return_invalid_mut_option.stderr | 9 ++- .../return_invalid_mut_tuple.stderr | 9 ++- .../tests/fail/tail_calls/cc-mismatch.stderr | 27 ++++---- .../fail/tail_calls/dangling-local-var.stderr | 9 ++- .../tests/fail/terminate-terminator.stderr | 19 +++--- .../tests/fail/tls/tls_static_dealloc.stderr | 1 + .../miri/tests/fail/tls_macro_leak.stderr | 9 ++- .../fail/tree_borrows/outside-range.stderr | 9 ++- .../fail/tree_borrows/pass_invalid_mut.stderr | 9 ++- ...peated_foreign_read_lazy_conflicted.stderr | 9 ++- .../reserved/cell-protected-write.stderr | 9 ++- .../reserved/int-protected-write.stderr | 9 ++- .../reservedim_spurious_write.with.stderr | 1 + .../reservedim_spurious_write.without.stderr | 1 + .../fail/tree_borrows/spurious_read.stderr | 9 ++- .../tree_borrows/strongly-protected.stderr | 19 +++--- ...tree_traversal_skipping_diagnostics.stderr | 9 ++- .../wildcard/protected_wildcard.stderr | 9 ++- .../wildcard/protector_conflicted.stderr | 5 +- .../strongly_protected_wildcard.stderr | 19 +++--- .../tree_borrows/write-during-2phase.stderr | 9 ++- .../unaligned_pointers/drop_in_place.stderr | 5 +- ...ld_requires_parent_struct_alignment.stderr | 5 +- ...d_requires_parent_struct_alignment2.stderr | 5 +- .../reference_to_packed.stderr | 5 +- .../uninit/uninit_alloc_diagnostic.stderr | 7 +- ...it_alloc_diagnostic_with_provenance.stderr | 7 +- .../tests/fail/unwind-action-terminate.stderr | 17 +++-- .../cast_fn_ptr_invalid_caller_arg.stderr | 5 +- .../fail/validity/invalid_char_cast.stderr | 5 +- .../fail/validity/invalid_char_match.stderr | 5 +- .../fail/validity/invalid_enum_cast.stderr | 5 +- .../tests/fail/weak_memory/weak_uninit.stderr | 1 + .../atomics/atomic_ptr_double_free.stderr | 13 ++-- .../atomic_ptr_alloc_race.dealloc.stderr | 7 +- .../atomic_ptr_alloc_race.write.stderr | 7 +- .../atomic_ptr_dealloc_write_race.stderr | 11 +-- .../atomic_ptr_write_dealloc_race.stderr | 7 +- .../genmc/fail/data_race/mpu2_rels_rlx.stderr | 7 +- .../data_race/weak_orderings.rel_rlx.stderr | 7 +- .../data_race/weak_orderings.rlx_acq.stderr | 7 +- .../data_race/weak_orderings.rlx_rlx.stderr | 7 +- .../tests/genmc/fail/loom/buggy_inc.stderr | 2 + .../fail/loom/store_buffering.genmc.stderr | 2 + .../loom/store_buffering.non_genmc.stderr | 2 + .../shims/mutex_diff_thread_unlock.stderr | 11 ++- .../fail/shims/mutex_double_unlock.stderr | 9 ++- .../fail/simple/2w2w_weak.relaxed4.stderr | 2 + .../fail/simple/2w2w_weak.release4.stderr | 2 + .../fail/simple/2w2w_weak.sc3_rel1.stderr | 2 + .../fail/simple/alloc_large.multiple.stderr | 13 ++-- .../fail/simple/alloc_large.single.stderr | 13 ++-- .../cas_failure_ord_racy_key_init.stderr | 9 ++- .../fail/tracing/partial_init.stderr | 10 ++- .../tracing/unexposed_reachable_alloc.stderr | 10 ++- .../pass/ptr_read_access.notrace.stderr | 10 ++- .../pass/ptr_read_access.trace.stderr | 10 ++- .../pass/ptr_write_access.notrace.stderr | 5 +- .../pass/ptr_write_access.trace.stderr | 5 +- .../tests/pass/alloc-access-tracking.stderr | 7 +- 235 files changed, 1000 insertions(+), 768 deletions(-) diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 10467fa79d9e..fb4029d10454 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -250,7 +250,7 @@ pub fn report_result<'tcx>( StackedBorrowsUb { .. } | TreeBorrowsUb { .. } | DataRace { .. } => Some("Undefined Behavior"), LocalDeadlock => { - labels.push(format!("this thread got stuck here")); + labels.push(format!("thread got stuck here")); None } GlobalDeadlock => { @@ -264,10 +264,7 @@ pub fn report_result<'tcx>( report_msg( DiagLevel::Error, format!("the evaluated program deadlocked"), - vec![format!( - "thread `{}` got stuck here", - ecx.machine.threads.get_thread_display_name(thread) - )], + vec![format!("thread got stuck here")], vec![], vec![], &stacktrace, @@ -563,6 +560,7 @@ fn report_msg<'tcx>( None => match thread { Some(thread_id) => machine.threads.thread_ref(thread_id).origin_span, + // This fallback is super rare, but can happen e.g. when `main` has the wrong ABI None => DUMMY_SP, }, }; @@ -608,36 +606,53 @@ fn report_msg<'tcx>( } // Add backtrace - if stacktrace.len() > 1 { - let mut backtrace_title = String::from("BACKTRACE"); - if extra_span { - write!(backtrace_title, " (of the first span)").unwrap(); + if let Some((first, rest)) = stacktrace.split_first() { + // Start with the function and thread that contain the first span. + let mut fn_and_thread = String::new(); + // Only print thread name if there are multiple threads. + if let Some(thread) = thread + && machine.threads.get_total_thread_count() > 1 + { + write!( + fn_and_thread, + "on thread `{}`", + machine.threads.get_thread_display_name(thread) + ) + .unwrap(); } - if let Some(thread) = thread { - let thread_name = machine.threads.get_thread_display_name(thread); - if thread_name != "main" { - // Only print thread name if it is not `main`. - write!(backtrace_title, " on thread `{thread_name}`").unwrap(); - }; + // Only print function name if we show a backtrace + if rest.len() > 0 { + if !fn_and_thread.is_empty() { + fn_and_thread.push_str(", "); + } + write!(fn_and_thread, "{first}").unwrap(); } - write!(backtrace_title, ":").unwrap(); - err.note(backtrace_title); - for (idx, frame_info) in stacktrace.iter().enumerate() { + if !fn_and_thread.is_empty() { + if extra_span && rest.len() > 0 { + // Print a `span_note` as otherwise the backtrace looks attached to the last + // `span_help`. We somewhat arbitrarily use the span of the surrounding function. + err.span_note( + machine.tcx.def_span(first.instance.def_id()), + format!("{level} occurred {fn_and_thread}"), + ); + } else { + err.note(format!("this is {fn_and_thread}")); + } + } + // Continue with where that function got called. + for frame_info in rest.iter() { let is_local = machine.is_local(frame_info.instance); // No span for non-local frames and the first frame (which is the error site). - if is_local && idx > 0 { - err.subdiagnostic(frame_info.as_note(machine.tcx)); + if is_local { + err.span_note(frame_info.span, format!("which got called {frame_info}")); } else { let sm = sess.source_map(); let span = sm.span_to_diagnostic_string(frame_info.span); - err.note(format!("{frame_info} at {span}")); + err.note(format!("which got called {frame_info} (at {span})")); } } - } else if stacktrace.len() == 0 && !span.is_dummy() { - err.note(format!( - "this {} occurred while pushing a call frame onto an empty stack", - level.to_str() - )); + } else if !span.is_dummy() { + err.note(format!("this {level} occurred while pushing a call frame onto an empty stack")); err.note("the span indicates which code caused the function to be called, but may not be the literal call site"); } diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_move_with_queue.stderr b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_move_with_queue.stderr index 003ddb9b287d..e86395fae201 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_move_with_queue.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_move_with_queue.stderr @@ -6,6 +6,7 @@ LL | let _val = atomic_ref.load(Ordering::Relaxed); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_move.init.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_move.init.stderr index f3f64a60a89b..4507c1bfa227 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_move.init.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_move.init.stderr @@ -6,9 +6,8 @@ LL | libc::pthread_cond_destroy(cond2.as_mut_ptr()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `check` at tests/fail-dep/concurrency/libc_pthread_cond_move.rs:LL:CC -note: inside `main` + = note: this is inside `check` +note: which got called inside `main` --> tests/fail-dep/concurrency/libc_pthread_cond_move.rs:LL:CC | LL | check() diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_move.static_initializer.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_move.static_initializer.stderr index 4056f7d9d41b..6132785b13dd 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_move.static_initializer.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_move.static_initializer.stderr @@ -6,9 +6,8 @@ LL | libc::pthread_cond_destroy(&mut cond2 as *mut _); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `check` at tests/fail-dep/concurrency/libc_pthread_cond_move.rs:LL:CC -note: inside `main` + = note: this is inside `check` +note: which got called inside `main` --> tests/fail-dep/concurrency/libc_pthread_cond_move.rs:LL:CC | LL | check() diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_detached.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_detached.stderr index 618584a117e4..60c4bd7f0589 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_detached.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_detached.stderr @@ -6,6 +6,7 @@ LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `main` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_joined.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_joined.stderr index a9f16a96adc2..87eed26bcaa3 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_joined.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_joined.stderr @@ -6,6 +6,7 @@ LL | ... assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `main` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.stderr index 46c9c5d3d714..85d7fae892d1 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.stderr @@ -6,6 +6,7 @@ LL | ... assert_eq!(libc::pthread_join(thread_id, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.stderr index 8a16f82a9307..72c778fd0beb 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.stderr @@ -6,6 +6,7 @@ LL | ... assert_eq!(libc::pthread_join(native_copy, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.stderr index dec0139bd89a..250b9ef9dfa1 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.stderr @@ -6,6 +6,7 @@ LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr index e3b0036c9aa9..db4811b52a3a 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr @@ -2,13 +2,12 @@ error: the evaluated program deadlocked --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC | LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; - | ^ thread `main` got stuck here + | ^ thread got stuck here | - = note: BACKTRACE: - = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC - = note: inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC - = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/join_handle.rs:LL:CC -note: inside `main` + = note: this is on thread `main`, inside `std::sys::thread::PLATFORM::Thread::join` + = note: which got called inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` (at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC) + = note: which got called inside `std::thread::JoinHandle::<()>::join` (at RUSTLIB/std/src/thread/join_handle.rs:LL:CC) +note: which got called inside `main` --> tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs:LL:CC | LL | / thread::spawn(move || { @@ -21,7 +20,9 @@ error: the evaluated program deadlocked --> tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs:LL:CC | LL | assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _), 0); - | ^ thread `unnamed-ID` got stuck here + | ^ thread got stuck here + | + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_free_while_queued.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_free_while_queued.stderr index 7b6e05828cea..cd6f6563469e 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_free_while_queued.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_free_while_queued.stderr @@ -6,11 +6,10 @@ LL | self.1.deallocate(From::from(ptr.cast()), layout); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE on thread `unnamed-ID`: - = note: inside ` as std::ops::Drop>::drop` at RUSTLIB/alloc/src/boxed.rs:LL:CC - = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC - = note: inside `std::mem::drop::>` at RUSTLIB/core/src/mem/mod.rs:LL:CC -note: inside closure + = note: this is on thread `unnamed-ID`, inside ` as std::ops::Drop>::drop` + = note: which got called inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` (at RUSTLIB/core/src/ptr/mod.rs:LL:CC) + = note: which got called inside `std::mem::drop::>` (at RUSTLIB/core/src/mem/mod.rs:LL:CC) +note: which got called inside closure --> tests/fail-dep/concurrency/libc_pthread_mutex_free_while_queued.rs:LL:CC | LL | drop(unsafe { Box::from_raw(m.get().cast::()) }); diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_move.init.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_move.init.stderr index a7cba0f00fe9..f9e06c75e06d 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_move.init.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_move.init.stderr @@ -6,9 +6,8 @@ LL | libc::pthread_mutex_lock(&mut m2 as *mut _); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `check` at tests/fail-dep/concurrency/libc_pthread_mutex_move.rs:LL:CC -note: inside `main` + = note: this is inside `check` +note: which got called inside `main` --> tests/fail-dep/concurrency/libc_pthread_mutex_move.rs:LL:CC | LL | check(); diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_move.static_initializer.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_move.static_initializer.stderr index 71f71efa0d96..643518c60617 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_move.static_initializer.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_move.static_initializer.stderr @@ -6,9 +6,8 @@ LL | libc::pthread_mutex_unlock(&mut m2 as *mut _); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `check` at tests/fail-dep/concurrency/libc_pthread_mutex_move.rs:LL:CC -note: inside `main` + = note: this is inside `check` +note: which got called inside `main` --> tests/fail-dep/concurrency/libc_pthread_mutex_move.rs:LL:CC | LL | check(); diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_reentrant.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_reentrant.stderr index 782322d5c32b..d7c69e088461 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_reentrant.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_reentrant.stderr @@ -2,7 +2,7 @@ error: a thread deadlocked --> tests/fail-dep/concurrency/libc_pthread_mutex_normal_reentrant.rs:LL:CC | LL | libc::pthread_mutex_lock(&mut mutex as *mut _); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this thread got stuck here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ thread got stuck here note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_read_while_queued.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_read_while_queued.stderr index 42dbd5f02cb3..6b46b6f1a7f9 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_read_while_queued.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_read_while_queued.stderr @@ -6,6 +6,7 @@ LL | ... let _val = atomic_ref.load(Ordering::Relaxed); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_write_while_queued.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_write_while_queued.stderr index 4705f9a1b5f0..641150a9d31e 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_write_while_queued.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_write_while_queued.stderr @@ -6,6 +6,7 @@ LL | atomic_ref.store(0, Ordering::Relaxed); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.stderr index c7d858a444cc..39765c8ec830 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.stderr @@ -6,6 +6,7 @@ LL | ... assert_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr index ea8cbcada970..57bd956dd3aa 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr @@ -2,7 +2,7 @@ error: the evaluated program deadlocked --> tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.rs:LL:CC | LL | libc::pthread_rwlock_wrlock(rw.get()); - | ^ thread `main` got stuck here + | ^ thread got stuck here note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.stderr index f1f5c50baf47..3b90bd446e54 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.stderr @@ -6,6 +6,7 @@ LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr index 255632870efc..c1722e33b615 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr @@ -2,13 +2,12 @@ error: the evaluated program deadlocked --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC | LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; - | ^ thread `main` got stuck here + | ^ thread got stuck here | - = note: BACKTRACE: - = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC - = note: inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC - = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/join_handle.rs:LL:CC -note: inside `main` + = note: this is on thread `main`, inside `std::sys::thread::PLATFORM::Thread::join` + = note: which got called inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` (at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC) + = note: which got called inside `std::thread::JoinHandle::<()>::join` (at RUSTLIB/std/src/thread/join_handle.rs:LL:CC) +note: which got called inside `main` --> tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC | LL | / thread::spawn(move || { @@ -21,7 +20,9 @@ error: the evaluated program deadlocked --> tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC | LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); - | ^ thread `unnamed-ID` got stuck here + | ^ thread got stuck here + | + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr index 0208a5bae4f5..e6b692623590 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr @@ -2,7 +2,7 @@ error: the evaluated program deadlocked --> tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.rs:LL:CC | LL | libc::pthread_rwlock_rdlock(rw.get()); - | ^ thread `main` got stuck here + | ^ thread got stuck here note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr index 6891b989d05f..ce1e0d83c772 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr @@ -2,13 +2,12 @@ error: the evaluated program deadlocked --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC | LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; - | ^ thread `main` got stuck here + | ^ thread got stuck here | - = note: BACKTRACE: - = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC - = note: inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC - = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/join_handle.rs:LL:CC -note: inside `main` + = note: this is on thread `main`, inside `std::sys::thread::PLATFORM::Thread::join` + = note: which got called inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` (at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC) + = note: which got called inside `std::thread::JoinHandle::<()>::join` (at RUSTLIB/std/src/thread/join_handle.rs:LL:CC) +note: which got called inside `main` --> tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC | LL | / thread::spawn(move || { @@ -21,7 +20,9 @@ error: the evaluated program deadlocked --> tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC | LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); - | ^ thread `unnamed-ID` got stuck here + | ^ thread got stuck here + | + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr index 314e60b02360..25435eadd735 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr @@ -2,7 +2,7 @@ error: the evaluated program deadlocked --> tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.rs:LL:CC | LL | libc::pthread_rwlock_wrlock(rw.get()); - | ^ thread `main` got stuck here + | ^ thread got stuck here note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.stderr index fdf4297c56ae..0a4037305c77 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.stderr @@ -6,6 +6,7 @@ LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_detached.stderr b/src/tools/miri/tests/fail-dep/concurrency/windows_join_detached.stderr index 52affb767db5..1765f0a18041 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_detached.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_detached.stderr @@ -6,11 +6,10 @@ LL | let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle( | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC - = note: inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC - = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/join_handle.rs:LL:CC -note: inside `main` + = note: this is on thread `main`, inside `std::sys::thread::PLATFORM::Thread::join` + = note: which got called inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` (at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC) + = note: which got called inside `std::thread::JoinHandle::<()>::join` (at RUSTLIB/std/src/thread/join_handle.rs:LL:CC) +note: which got called inside `main` --> tests/fail-dep/concurrency/windows_join_detached.rs:LL:CC | LL | thread.join().unwrap(); diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr index d9cc93d0fc49..d07f16eb6a99 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr @@ -2,13 +2,12 @@ error: the evaluated program deadlocked --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC | LL | let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) }; - | ^ thread `main` got stuck here + | ^ thread got stuck here | - = note: BACKTRACE: - = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC - = note: inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC - = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/join_handle.rs:LL:CC -note: inside `main` + = note: this is on thread `main`, inside `std::sys::thread::PLATFORM::Thread::join` + = note: which got called inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` (at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC) + = note: which got called inside `std::thread::JoinHandle::<()>::join` (at RUSTLIB/std/src/thread/join_handle.rs:LL:CC) +note: which got called inside `main` --> tests/fail-dep/concurrency/windows_join_main.rs:LL:CC | LL | / thread::spawn(|| { @@ -22,8 +21,9 @@ error: the evaluated program deadlocked --> tests/fail-dep/concurrency/windows_join_main.rs:LL:CC | LL | assert_eq!(WaitForSingleObject(MAIN_THREAD, INFINITE), WAIT_OBJECT_0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ thread `unnamed-ID` got stuck here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ thread got stuck here | + = note: this is on thread `unnamed-ID` = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr b/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr index f5515983da2b..d82e273677e4 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr @@ -2,13 +2,12 @@ error: the evaluated program deadlocked --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC | LL | let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) }; - | ^ thread `main` got stuck here + | ^ thread got stuck here | - = note: BACKTRACE: - = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC - = note: inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC - = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/join_handle.rs:LL:CC -note: inside `main` + = note: this is on thread `main`, inside `std::sys::thread::PLATFORM::Thread::join` + = note: which got called inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` (at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC) + = note: which got called inside `std::thread::JoinHandle::<()>::join` (at RUSTLIB/std/src/thread/join_handle.rs:LL:CC) +note: which got called inside `main` --> tests/fail-dep/concurrency/windows_join_self.rs:LL:CC | LL | / thread::spawn(|| { @@ -24,7 +23,9 @@ error: the evaluated program deadlocked --> tests/fail-dep/concurrency/windows_join_self.rs:LL:CC | LL | assert_eq!(WaitForSingleObject(native, INFINITE), WAIT_OBJECT_0); - | ^ thread `unnamed-ID` got stuck here + | ^ thread got stuck here + | + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr index 2b10a322b0be..c326bb8c3c3f 100644 --- a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr +++ b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr @@ -11,6 +11,7 @@ LL | env::set_var("MY_RUST_VAR", "Ferris"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.stderr b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.stderr index 53ae7ea82bd9..dc34f4748cd2 100644 --- a/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.stderr +++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.stderr @@ -2,13 +2,12 @@ error: the evaluated program deadlocked --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC | LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; - | ^ thread `main` got stuck here + | ^ thread got stuck here | - = note: BACKTRACE: - = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC - = note: inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC - = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/join_handle.rs:LL:CC -note: inside `main` + = note: this is on thread `main`, inside `std::sys::thread::PLATFORM::Thread::join` + = note: which got called inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` (at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC) + = note: which got called inside `std::thread::JoinHandle::<()>::join` (at RUSTLIB/std/src/thread/join_handle.rs:LL:CC) +note: which got called inside `main` --> tests/fail-dep/libc/eventfd_block_read_twice.rs:LL:CC | LL | thread2.join().unwrap(); @@ -18,7 +17,9 @@ error: the evaluated program deadlocked --> tests/fail-dep/libc/eventfd_block_read_twice.rs:LL:CC | LL | let res: i64 = unsafe { libc::read(fd, buf.as_mut_ptr().cast(), 8).try_into().unwrap() }; - | ^ thread `unnamed-ID` got stuck here + | ^ thread got stuck here + | + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.stderr b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.stderr index 62810f17be88..3758484bb05e 100644 --- a/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.stderr +++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.stderr @@ -2,13 +2,12 @@ error: the evaluated program deadlocked --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC | LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; - | ^ thread `main` got stuck here + | ^ thread got stuck here | - = note: BACKTRACE: - = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC - = note: inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC - = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/join_handle.rs:LL:CC -note: inside `main` + = note: this is on thread `main`, inside `std::sys::thread::PLATFORM::Thread::join` + = note: which got called inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` (at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC) + = note: which got called inside `std::thread::JoinHandle::<()>::join` (at RUSTLIB/std/src/thread/join_handle.rs:LL:CC) +note: which got called inside `main` --> tests/fail-dep/libc/eventfd_block_write_twice.rs:LL:CC | LL | thread2.join().unwrap(); @@ -18,7 +17,9 @@ error: the evaluated program deadlocked --> tests/fail-dep/libc/eventfd_block_write_twice.rs:LL:CC | LL | libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8).try_into().unwrap() - | ^ thread `unnamed-ID` got stuck here + | ^ thread got stuck here + | + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/fcntl_fsetfl_while_blocking.stderr b/src/tools/miri/tests/fail-dep/libc/fcntl_fsetfl_while_blocking.stderr index 307762fb12c6..f2f6f373a2a7 100644 --- a/src/tools/miri/tests/fail-dep/libc/fcntl_fsetfl_while_blocking.stderr +++ b/src/tools/miri/tests/fail-dep/libc/fcntl_fsetfl_while_blocking.stderr @@ -2,7 +2,9 @@ error: the evaluated program deadlocked --> tests/fail-dep/libc/fcntl_fsetfl_while_blocking.rs:LL:CC | LL | let _res = unsafe { libc::read(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) }; - | ^ thread `main` got stuck here + | ^ thread got stuck here + | + = note: this is on thread `main` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.stderr b/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.stderr index 981f055e1294..ec7b681dfad4 100644 --- a/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.stderr +++ b/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.stderr @@ -6,9 +6,8 @@ LL | let _fd = unsafe { libc::mkstemp(s) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `test_mkstemp_immutable_arg` at tests/fail-dep/libc/fs/mkstemp_immutable_arg.rs:LL:CC -note: inside `main` + = note: this is inside `test_mkstemp_immutable_arg` +note: which got called inside `main` --> tests/fail-dep/libc/fs/mkstemp_immutable_arg.rs:LL:CC | LL | test_mkstemp_immutable_arg(); diff --git a/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr index 298e67f1468b..9f5ea4ed021f 100644 --- a/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr +++ b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr @@ -6,9 +6,8 @@ LL | let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `test_file_open_missing_needed_mode` at tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs:LL:CC -note: inside `main` + = note: this is inside `test_file_open_missing_needed_mode` +note: which got called inside `main` --> tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs:LL:CC | LL | test_file_open_missing_needed_mode(); diff --git a/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.stderr b/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.stderr index a322de74b510..e606a03e46fa 100644 --- a/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.stderr +++ b/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.stderr @@ -11,6 +11,7 @@ LL | unsafe { VAL_TWO = 51 }; | ^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `main` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.stderr b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.stderr index dba12d190317..e883bd9bd025 100644 --- a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.stderr +++ b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.stderr @@ -2,13 +2,12 @@ error: the evaluated program deadlocked --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC | LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; - | ^ thread `main` got stuck here + | ^ thread got stuck here | - = note: BACKTRACE: - = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC - = note: inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC - = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/join_handle.rs:LL:CC -note: inside `main` + = note: this is on thread `main`, inside `std::sys::thread::PLATFORM::Thread::join` + = note: which got called inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` (at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC) + = note: which got called inside `std::thread::JoinHandle::<()>::join` (at RUSTLIB/std/src/thread/join_handle.rs:LL:CC) +note: which got called inside `main` --> tests/fail-dep/libc/libc_epoll_block_two_thread.rs:LL:CC | LL | thread2.join().unwrap(); @@ -18,7 +17,9 @@ error: the evaluated program deadlocked --> tests/fail-dep/libc/libc_epoll_block_two_thread.rs:LL:CC | LL | check_epoll_wait::(epfd, &expected, -1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ thread `unnamed-ID` got stuck here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ thread got stuck here + | + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr index a7c660e1adcc..a7d0b60dfcb3 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr +++ b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr @@ -2,13 +2,12 @@ error: the evaluated program deadlocked --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC | LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; - | ^ thread `main` got stuck here + | ^ thread got stuck here | - = note: BACKTRACE: - = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC - = note: inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC - = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/join_handle.rs:LL:CC -note: inside `main` + = note: this is on thread `main`, inside `std::sys::thread::PLATFORM::Thread::join` + = note: which got called inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` (at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC) + = note: which got called inside `std::thread::JoinHandle::<()>::join` (at RUSTLIB/std/src/thread/join_handle.rs:LL:CC) +note: which got called inside `main` --> tests/fail-dep/libc/socketpair-close-while-blocked.rs:LL:CC | LL | thread1.join().unwrap(); @@ -18,7 +17,9 @@ error: the evaluated program deadlocked --> tests/fail-dep/libc/socketpair-close-while-blocked.rs:LL:CC | LL | libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) - | ^ thread `unnamed-ID` got stuck here + | ^ thread got stuck here + | + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.stderr index 7cee4b83ba90..fa7e45bccdc5 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.stderr +++ b/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.stderr @@ -11,6 +11,7 @@ LL | unsafe { VAL = 1 }; | ^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `main` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr index faab75f7840b..a817f2867284 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr @@ -2,13 +2,12 @@ error: the evaluated program deadlocked --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC | LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; - | ^ thread `main` got stuck here + | ^ thread got stuck here | - = note: BACKTRACE: - = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC - = note: inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC - = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/join_handle.rs:LL:CC -note: inside `main` + = note: this is on thread `main`, inside `std::sys::thread::PLATFORM::Thread::join` + = note: which got called inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` (at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC) + = note: which got called inside `std::thread::JoinHandle::<()>::join` (at RUSTLIB/std/src/thread/join_handle.rs:LL:CC) +note: which got called inside `main` --> tests/fail-dep/libc/socketpair_block_read_twice.rs:LL:CC | LL | thread2.join().unwrap(); @@ -18,7 +17,9 @@ error: the evaluated program deadlocked --> tests/fail-dep/libc/socketpair_block_read_twice.rs:LL:CC | LL | libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) - | ^ thread `unnamed-ID` got stuck here + | ^ thread got stuck here + | + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr index 9f95d98beb6f..18e6222589f0 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr @@ -2,13 +2,12 @@ error: the evaluated program deadlocked --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC | LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; - | ^ thread `main` got stuck here + | ^ thread got stuck here | - = note: BACKTRACE: - = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC - = note: inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC - = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/join_handle.rs:LL:CC -note: inside `main` + = note: this is on thread `main`, inside `std::sys::thread::PLATFORM::Thread::join` + = note: which got called inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` (at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC) + = note: which got called inside `std::thread::JoinHandle::<()>::join` (at RUSTLIB/std/src/thread/join_handle.rs:LL:CC) +note: which got called inside `main` --> tests/fail-dep/libc/socketpair_block_write_twice.rs:LL:CC | LL | thread2.join().unwrap(); @@ -18,7 +17,9 @@ error: the evaluated program deadlocked --> tests/fail-dep/libc/socketpair_block_write_twice.rs:LL:CC | LL | let res = unsafe { libc::write(fds[0], data.as_ptr() as *const libc::c_void, data.len()) }; - | ^ thread `unnamed-ID` got stuck here + | ^ thread got stuck here + | + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr b/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr index b85a23e3c7db..bd62bf148d7a 100644 --- a/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr +++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr @@ -7,14 +7,13 @@ error: abnormal termination: the program aborted execution LL | crate::process::abort() | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: BACKTRACE: - = note: inside closure at RUSTLIB/std/src/alloc.rs:LL:CC - = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::alloc::rust_oom::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC - = note: inside `std::alloc::rust_oom` at RUSTLIB/std/src/alloc.rs:LL:CC - = note: inside `std::alloc::_::__rust_alloc_error_handler` at RUSTLIB/std/src/alloc.rs:LL:CC - = note: inside `std::alloc::handle_alloc_error::rt_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `std::alloc::handle_alloc_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC -note: inside `main` + = note: this is inside closure + = note: which got called inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::alloc::rust_oom::{closure#0}}, !>` (at RUSTLIB/std/src/sys/backtrace.rs:LL:CC) + = note: which got called inside `std::alloc::rust_oom` (at RUSTLIB/std/src/alloc.rs:LL:CC) + = note: which got called inside `std::alloc::_::__rust_alloc_error_handler` (at RUSTLIB/std/src/alloc.rs:LL:CC) + = note: which got called inside `std::alloc::handle_alloc_error::rt_error` (at RUSTLIB/alloc/src/alloc.rs:LL:CC) + = note: which got called inside `std::alloc::handle_alloc_error` (at RUSTLIB/alloc/src/alloc.rs:LL:CC) +note: which got called inside `main` --> tests/fail/alloc/alloc_error_handler.rs:LL:CC | LL | handle_alloc_error(Layout::for_value(&0)); diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr b/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr index f8a96758aa2d..7e7871dc89bc 100644 --- a/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr +++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr @@ -5,18 +5,17 @@ error: abnormal termination: the program aborted execution LL | core::intrinsics::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: BACKTRACE: - = note: inside `alloc_error_handler` at tests/fail/alloc/alloc_error_handler_custom.rs:LL:CC -note: inside `_::__rust_alloc_error_handler` + = note: this is inside `alloc_error_handler` +note: which got called inside `_::__rust_alloc_error_handler` --> tests/fail/alloc/alloc_error_handler_custom.rs:LL:CC | LL | #[alloc_error_handler] | ---------------------- in this attribute macro expansion LL | fn alloc_error_handler(layout: Layout) -> ! { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: inside `alloc::alloc::handle_alloc_error::rt_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `alloc::alloc::handle_alloc_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC -note: inside `miri_start` + = note: which got called inside `alloc::alloc::handle_alloc_error::rt_error` (at RUSTLIB/alloc/src/alloc.rs:LL:CC) + = note: which got called inside `alloc::alloc::handle_alloc_error` (at RUSTLIB/alloc/src/alloc.rs:LL:CC) +note: which got called inside `miri_start` --> tests/fail/alloc/alloc_error_handler_custom.rs:LL:CC | LL | handle_alloc_error(Layout::for_value(&0)); diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr b/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr index 488b1d879e87..b126cb042bee 100644 --- a/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr +++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr @@ -7,12 +7,11 @@ error: abnormal termination: the program aborted execution LL | core::intrinsics::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: BACKTRACE: - = note: inside `panic_handler` at tests/fail/alloc/alloc_error_handler_no_std.rs:LL:CC - = note: inside `alloc::alloc::__alloc_error_handler::__rdl_alloc_error_handler` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `alloc::alloc::handle_alloc_error::rt_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `alloc::alloc::handle_alloc_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC -note: inside `miri_start` + = note: this is inside `panic_handler` + = note: which got called inside `alloc::alloc::__alloc_error_handler::__rdl_alloc_error_handler` (at RUSTLIB/alloc/src/alloc.rs:LL:CC) + = note: which got called inside `alloc::alloc::handle_alloc_error::rt_error` (at RUSTLIB/alloc/src/alloc.rs:LL:CC) + = note: which got called inside `alloc::alloc::handle_alloc_error` (at RUSTLIB/alloc/src/alloc.rs:LL:CC) +note: which got called inside `miri_start` --> tests/fail/alloc/alloc_error_handler_no_std.rs:LL:CC | LL | handle_alloc_error(Layout::for_value(&0)); diff --git a/src/tools/miri/tests/fail/alloc/global_system_mixup.stderr b/src/tools/miri/tests/fail/alloc/global_system_mixup.stderr index 5a5f7496237c..27464a5a29e8 100644 --- a/src/tools/miri/tests/fail/alloc/global_system_mixup.stderr +++ b/src/tools/miri/tests/fail/alloc/global_system_mixup.stderr @@ -6,10 +6,9 @@ LL | FREE(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `std::sys::alloc::PLATFORM::::dealloc` at RUSTLIB/std/src/sys/alloc/PLATFORM.rs:LL:CC - = note: inside `::deallocate` at RUSTLIB/std/src/alloc.rs:LL:CC -note: inside `main` + = note: this is inside `std::sys::alloc::PLATFORM::::dealloc` + = note: which got called inside `::deallocate` (at RUSTLIB/std/src/alloc.rs:LL:CC) +note: which got called inside `main` --> tests/fail/alloc/global_system_mixup.rs:LL:CC | LL | unsafe { System.deallocate(ptr, l) }; diff --git a/src/tools/miri/tests/fail/alloc/stack_free.stderr b/src/tools/miri/tests/fail/alloc/stack_free.stderr index 6e98a7abc760..ec052fcb6b9a 100644 --- a/src/tools/miri/tests/fail/alloc/stack_free.stderr +++ b/src/tools/miri/tests/fail/alloc/stack_free.stderr @@ -6,11 +6,10 @@ LL | self.1.deallocate(From::from(ptr.cast()), layout); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside ` as std::ops::Drop>::drop` at RUSTLIB/alloc/src/boxed.rs:LL:CC - = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC - = note: inside `std::mem::drop::>` at RUSTLIB/core/src/mem/mod.rs:LL:CC -note: inside `main` + = note: this is inside ` as std::ops::Drop>::drop` + = note: which got called inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` (at RUSTLIB/core/src/ptr/mod.rs:LL:CC) + = note: which got called inside `std::mem::drop::>` (at RUSTLIB/core/src/mem/mod.rs:LL:CC) +note: which got called inside `main` --> tests/fail/alloc/stack_free.rs:LL:CC | LL | drop(bad_box); diff --git a/src/tools/miri/tests/fail/async-shared-mutable.stack.stderr b/src/tools/miri/tests/fail/async-shared-mutable.stack.stderr index bc3db8c6801b..9949dad12867 100644 --- a/src/tools/miri/tests/fail/async-shared-mutable.stack.stderr +++ b/src/tools/miri/tests/fail/async-shared-mutable.stack.stderr @@ -20,15 +20,18 @@ help: was later invalidated at offsets [OFFSET] by a SharedReadOnly retag | LL | let _: Pin<&_> = f.as_ref(); // Or: `f.as_mut().into_ref()`. | ^^^^^^^^^^ - = note: BACKTRACE (of the first span): - = note: inside closure at tests/fail/async-shared-mutable.rs:LL:CC - = note: inside ` as std::future::Future>::poll` at RUSTLIB/core/src/future/poll_fn.rs:LL:CC -note: inside closure +note: error occurred inside closure + --> tests/fail/async-shared-mutable.rs:LL:CC + | +LL | core::future::poll_fn(move |_| { + | ^^^^^^^^ + = note: which got called inside ` as std::future::Future>::poll` (at RUSTLIB/core/src/future/poll_fn.rs:LL:CC) +note: which got called inside closure --> tests/fail/async-shared-mutable.rs:LL:CC | LL | .await | ^^^^^ -note: inside `main` +note: which got called inside `main` --> tests/fail/async-shared-mutable.rs:LL:CC | LL | assert_eq!(f.as_mut().poll(&mut cx), Poll::Pending); diff --git a/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr b/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr index dc8b4f6665a0..c204f75c4f21 100644 --- a/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr +++ b/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr @@ -28,15 +28,18 @@ help: the accessed tag later transitioned to Frozen due to a reborrow (act LL | let _: Pin<&_> = f.as_ref(); // Or: `f.as_mut().into_ref()`. | ^^^^^^^^^^ = help: this transition corresponds to a loss of write permissions - = note: BACKTRACE (of the first span): - = note: inside closure at tests/fail/async-shared-mutable.rs:LL:CC - = note: inside ` as std::future::Future>::poll` at RUSTLIB/core/src/future/poll_fn.rs:LL:CC -note: inside closure +note: error occurred inside closure + --> tests/fail/async-shared-mutable.rs:LL:CC + | +LL | core::future::poll_fn(move |_| { + | ^^^^^^^^ + = note: which got called inside ` as std::future::Future>::poll` (at RUSTLIB/core/src/future/poll_fn.rs:LL:CC) +note: which got called inside closure --> tests/fail/async-shared-mutable.rs:LL:CC | LL | .await | ^^^^^ -note: inside `main` +note: which got called inside `main` --> tests/fail/async-shared-mutable.rs:LL:CC | LL | assert_eq!(f.as_mut().poll(&mut cx), Poll::Pending); diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.stack.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.stack.stderr index 196eaeb3fb6c..bb5e731545b7 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.stack.stderr @@ -16,9 +16,12 @@ help: is this argument | LL | fn safe(x: &mut i32, y: &mut i32) { | ^ - = note: BACKTRACE (of the first span): - = note: inside `safe` at tests/fail/both_borrows/aliasing_mut1.rs:LL:CC -note: inside `main` +note: error occurred inside `safe` + --> tests/fail/both_borrows/aliasing_mut1.rs:LL:CC + | +LL | fn safe(x: &mut i32, y: &mut i32) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/both_borrows/aliasing_mut1.rs:LL:CC | LL | safe_raw(xraw, xraw); diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.tree.stderr index b9e6e2547806..34f56696e000 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.tree.stderr @@ -18,9 +18,12 @@ help: the accessed tag later transitioned to Reserved (conflicted) due to LL | fn safe(x: &mut i32, y: &mut i32) { | ^ = help: this transition corresponds to a temporary loss of write permissions until function exit - = note: BACKTRACE (of the first span): - = note: inside `safe` at tests/fail/both_borrows/aliasing_mut1.rs:LL:CC -note: inside `main` +note: error occurred inside `safe` + --> tests/fail/both_borrows/aliasing_mut1.rs:LL:CC + | +LL | fn safe(x: &mut i32, y: &mut i32) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/both_borrows/aliasing_mut1.rs:LL:CC | LL | safe_raw(xraw, xraw); diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.stack.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.stack.stderr index e70e5b10793c..5c574f13ff70 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.stack.stderr @@ -16,9 +16,12 @@ help: is this argument | LL | fn safe(x: &i32, y: &mut i32) { | ^ - = note: BACKTRACE (of the first span): - = note: inside `safe` at tests/fail/both_borrows/aliasing_mut2.rs:LL:CC -note: inside `main` +note: error occurred inside `safe` + --> tests/fail/both_borrows/aliasing_mut2.rs:LL:CC + | +LL | fn safe(x: &i32, y: &mut i32) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/both_borrows/aliasing_mut2.rs:LL:CC | LL | safe_raw(xshr, xraw); diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.tree.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.tree.stderr index aed59b21f137..639a4ef57efe 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.tree.stderr @@ -18,9 +18,12 @@ help: the accessed tag later transitioned to Reserved (conflicted) due to LL | let _v = *x; | ^^ = help: this transition corresponds to a temporary loss of write permissions until function exit - = note: BACKTRACE (of the first span): - = note: inside `safe` at tests/fail/both_borrows/aliasing_mut2.rs:LL:CC -note: inside `main` +note: error occurred inside `safe` + --> tests/fail/both_borrows/aliasing_mut2.rs:LL:CC + | +LL | fn safe(x: &i32, y: &mut i32) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/both_borrows/aliasing_mut2.rs:LL:CC | LL | safe_raw(xshr, xraw); diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.stack.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.stack.stderr index 9980d14e1054..4be06c65f191 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.stack.stderr @@ -16,9 +16,12 @@ help: was later invalidated at offsets [0x0..0x4] by a Unique function-ent | LL | safe_raw(xraw, xshr); | ^^^^^^^^^^^^^^^^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `safe` at tests/fail/both_borrows/aliasing_mut3.rs:LL:CC -note: inside `main` +note: error occurred inside `safe` + --> tests/fail/both_borrows/aliasing_mut3.rs:LL:CC + | +LL | fn safe(x: &mut i32, y: &i32) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/both_borrows/aliasing_mut3.rs:LL:CC | LL | safe_raw(xraw, xshr); diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.tree.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.tree.stderr index 357d7d220192..09a54f8199c7 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.tree.stderr @@ -18,9 +18,12 @@ help: the accessed tag later transitioned to Reserved (conflicted) due to LL | fn safe(x: &mut i32, y: &i32) { | ^ = help: this transition corresponds to a temporary loss of write permissions until function exit - = note: BACKTRACE (of the first span): - = note: inside `safe` at tests/fail/both_borrows/aliasing_mut3.rs:LL:CC -note: inside `main` +note: error occurred inside `safe` + --> tests/fail/both_borrows/aliasing_mut3.rs:LL:CC + | +LL | fn safe(x: &mut i32, y: &i32) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/both_borrows/aliasing_mut3.rs:LL:CC | LL | safe_raw(xraw, xshr); diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.stack.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.stack.stderr index eb2514df588a..e72996d43d7b 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.stack.stderr @@ -16,9 +16,12 @@ help: is this argument | LL | fn safe(x: &i32, y: &mut Cell) { | ^ - = note: BACKTRACE (of the first span): - = note: inside `safe` at tests/fail/both_borrows/aliasing_mut4.rs:LL:CC -note: inside `main` +note: error occurred inside `safe` + --> tests/fail/both_borrows/aliasing_mut4.rs:LL:CC + | +LL | fn safe(x: &i32, y: &mut Cell) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/both_borrows/aliasing_mut4.rs:LL:CC | LL | safe_raw(xshr, xraw as *mut _); diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.tree.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.tree.stderr index c06ae0e92138..d2a533a3da8e 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.tree.stderr @@ -19,16 +19,19 @@ help: the protected tag was created here, in the initial state Frozen | LL | fn safe(x: &i32, y: &mut Cell) { | ^ - = note: BACKTRACE (of the first span): - = note: inside `std::mem::replace::` at RUSTLIB/core/src/mem/mod.rs:LL:CC - = note: inside `std::cell::Cell::::replace` at RUSTLIB/core/src/cell.rs:LL:CC - = note: inside `std::cell::Cell::::set` at RUSTLIB/core/src/cell.rs:LL:CC -note: inside `safe` +note: error occurred inside `std::mem::replace::` + --> RUSTLIB/core/src/mem/mod.rs:LL:CC + | +LL | pub const fn replace(dest: &mut T, src: T) -> T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: which got called inside `std::cell::Cell::::replace` (at RUSTLIB/core/src/cell.rs:LL:CC) + = note: which got called inside `std::cell::Cell::::set` (at RUSTLIB/core/src/cell.rs:LL:CC) +note: which got called inside `safe` --> tests/fail/both_borrows/aliasing_mut4.rs:LL:CC | LL | y.set(1); | ^^^^^^^^ -note: inside `main` +note: which got called inside `main` --> tests/fail/both_borrows/aliasing_mut4.rs:LL:CC | LL | safe_raw(xshr, xraw as *mut _); diff --git a/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.stack.stderr b/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.stack.stderr index 009ec2dd4aaa..c9341ccdb037 100644 --- a/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.stack.stderr @@ -16,14 +16,17 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | *our = 5; | ^^^^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `unknown_code_2` at tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC -note: inside `demo_box_advanced_unique` +note: error occurred inside `unknown_code_2` + --> tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC + | +LL | fn unknown_code_2() { + | ^^^^^^^^^^^^^^^^^^^ +note: which got called inside `demo_box_advanced_unique` --> tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC | LL | unknown_code_2(); | ^^^^^^^^^^^^^^^^ -note: inside `main` +note: which got called inside `main` --> tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC | LL | demo_box_advanced_unique(Box::new(0)); diff --git a/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.tree.stderr index d4cfab024bae..446d283694a1 100644 --- a/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.tree.stderr @@ -18,14 +18,17 @@ help: the accessed tag later transitioned to Disabled due to a foreign wri LL | *our = 5; | ^^^^^^^^ = help: this transition corresponds to a loss of read permissions - = note: BACKTRACE (of the first span): - = note: inside `unknown_code_2` at tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC -note: inside `demo_box_advanced_unique` +note: error occurred inside `unknown_code_2` + --> tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC + | +LL | fn unknown_code_2() { + | ^^^^^^^^^^^^^^^^^^^ +note: which got called inside `demo_box_advanced_unique` --> tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC | LL | unknown_code_2(); | ^^^^^^^^^^^^^^^^ -note: inside `main` +note: which got called inside `main` --> tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC | LL | demo_box_advanced_unique(Box::new(0)); diff --git a/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.stack.stderr b/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.stack.stderr index cc6633eb24f9..1a5662b74693 100644 --- a/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.stack.stderr @@ -16,9 +16,12 @@ help: is this argument | LL | unsafe fn test(mut x: Box, y: *const i32) -> i32 { | ^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `test` at tests/fail/both_borrows/box_noalias_violation.rs:LL:CC -note: inside `main` +note: error occurred inside `test` + --> tests/fail/both_borrows/box_noalias_violation.rs:LL:CC + | +LL | unsafe fn test(mut x: Box, y: *const i32) -> i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/both_borrows/box_noalias_violation.rs:LL:CC | LL | test(Box::from_raw(ptr), ptr); diff --git a/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr b/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr index 6a1f7761a410..6ec056828fd5 100644 --- a/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr @@ -25,9 +25,12 @@ help: the protected tag later transitioned to Unique due to a child write LL | *x = 5; | ^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference - = note: BACKTRACE (of the first span): - = note: inside `test` at tests/fail/both_borrows/box_noalias_violation.rs:LL:CC -note: inside `main` +note: error occurred inside `test` + --> tests/fail/both_borrows/box_noalias_violation.rs:LL:CC + | +LL | unsafe fn test(mut x: Box, y: *const i32) -> i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/both_borrows/box_noalias_violation.rs:LL:CC | LL | test(Box::from_raw(ptr), ptr); diff --git a/src/tools/miri/tests/fail/both_borrows/buggy_split_at_mut.stack.stderr b/src/tools/miri/tests/fail/both_borrows/buggy_split_at_mut.stack.stderr index c4cb2c7ae4d6..2b0d5f07994c 100644 --- a/src/tools/miri/tests/fail/both_borrows/buggy_split_at_mut.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/buggy_split_at_mut.stack.stderr @@ -22,9 +22,12 @@ help: was later invalidated at offsets [0x0..0x10] by a Unique retag | LL | from_raw_parts_mut(ptr.offset(mid as isize), len - mid), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `safe::split_at_mut::` at tests/fail/both_borrows/buggy_split_at_mut.rs:LL:CC -note: inside `main` +note: error occurred inside `safe::split_at_mut::` + --> tests/fail/both_borrows/buggy_split_at_mut.rs:LL:CC + | +LL | pub fn split_at_mut(self_: &mut [T], mid: usize) -> (&mut [T], &mut [T]) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/both_borrows/buggy_split_at_mut.rs:LL:CC | LL | let (a, b) = safe::split_at_mut(&mut array, 0); diff --git a/src/tools/miri/tests/fail/both_borrows/illegal_write6.stack.stderr b/src/tools/miri/tests/fail/both_borrows/illegal_write6.stack.stderr index 40b44d77e3df..3c09bec03d6a 100644 --- a/src/tools/miri/tests/fail/both_borrows/illegal_write6.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/illegal_write6.stack.stderr @@ -16,9 +16,12 @@ help: is this argument | LL | fn foo(a: &mut u32, y: *mut u32) -> u32 { | ^ - = note: BACKTRACE (of the first span): - = note: inside `foo` at tests/fail/both_borrows/illegal_write6.rs:LL:CC -note: inside `main` +note: error occurred inside `foo` + --> tests/fail/both_borrows/illegal_write6.rs:LL:CC + | +LL | fn foo(a: &mut u32, y: *mut u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/both_borrows/illegal_write6.rs:LL:CC | LL | foo(x, p); diff --git a/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr b/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr index 1547a6ca73a0..69bb914236da 100644 --- a/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr @@ -25,9 +25,12 @@ help: the protected tag later transitioned to Unique due to a child write LL | *a = 1; | ^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference - = note: BACKTRACE (of the first span): - = note: inside `foo` at tests/fail/both_borrows/illegal_write6.rs:LL:CC -note: inside `main` +note: error occurred inside `foo` + --> tests/fail/both_borrows/illegal_write6.rs:LL:CC + | +LL | fn foo(a: &mut u32, y: *mut u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/both_borrows/illegal_write6.rs:LL:CC | LL | foo(x, p); diff --git a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.stack.stderr b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.stack.stderr index ef531be496af..d298d511d3e1 100644 --- a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.stack.stderr @@ -16,9 +16,12 @@ help: is this argument | LL | fn inner(x: *mut i32, _y: &i32) { | ^^ - = note: BACKTRACE (of the first span): - = note: inside `inner` at tests/fail/both_borrows/invalidate_against_protector2.rs:LL:CC -note: inside `main` +note: error occurred inside `inner` + --> tests/fail/both_borrows/invalidate_against_protector2.rs:LL:CC + | +LL | fn inner(x: *mut i32, _y: &i32) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/both_borrows/invalidate_against_protector2.rs:LL:CC | LL | inner(xraw, xref); diff --git a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.tree.stderr b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.tree.stderr index 90a89e48e61b..b83217bce7e9 100644 --- a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.tree.stderr @@ -19,9 +19,12 @@ help: the protected tag was created here, in the initial state Frozen | LL | fn inner(x: *mut i32, _y: &i32) { | ^^ - = note: BACKTRACE (of the first span): - = note: inside `inner` at tests/fail/both_borrows/invalidate_against_protector2.rs:LL:CC -note: inside `main` +note: error occurred inside `inner` + --> tests/fail/both_borrows/invalidate_against_protector2.rs:LL:CC + | +LL | fn inner(x: *mut i32, _y: &i32) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/both_borrows/invalidate_against_protector2.rs:LL:CC | LL | inner(xraw, xref); diff --git a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.stack.stderr b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.stack.stderr index caf2b702fec6..ebbc3a7ae8c0 100644 --- a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.stack.stderr @@ -16,9 +16,12 @@ help: is this argument | LL | fn inner(x: *mut i32, _y: &i32) { | ^^ - = note: BACKTRACE (of the first span): - = note: inside `inner` at tests/fail/both_borrows/invalidate_against_protector3.rs:LL:CC -note: inside `main` +note: error occurred inside `inner` + --> tests/fail/both_borrows/invalidate_against_protector3.rs:LL:CC + | +LL | fn inner(x: *mut i32, _y: &i32) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/both_borrows/invalidate_against_protector3.rs:LL:CC | LL | inner(ptr, &*ptr); diff --git a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.tree.stderr b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.tree.stderr index 8bac71dcd468..1a1eb89d25f7 100644 --- a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.tree.stderr @@ -19,9 +19,12 @@ help: the protected tag was created here, in the initial state Frozen | LL | fn inner(x: *mut i32, _y: &i32) { | ^^ - = note: BACKTRACE (of the first span): - = note: inside `inner` at tests/fail/both_borrows/invalidate_against_protector3.rs:LL:CC -note: inside `main` +note: error occurred inside `inner` + --> tests/fail/both_borrows/invalidate_against_protector3.rs:LL:CC + | +LL | fn inner(x: *mut i32, _y: &i32) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/both_borrows/invalidate_against_protector3.rs:LL:CC | LL | inner(ptr, &*ptr); diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr index 9927d90c6469..2b2e16d1ecff 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr @@ -11,10 +11,13 @@ help: ALLOC was allocated here: | LL | let ptr = Box::into_raw(Box::new(0u16)); | ^^^^^^^^^^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC - = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC -note: inside `main` +note: error occurred inside `std::boxed::Box::::from_raw_in` + --> RUSTLIB/alloc/src/boxed.rs:LL:CC + | +LL | pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: which got called inside `std::boxed::Box::::from_raw` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) +note: which got called inside `main` --> tests/fail/both_borrows/issue-miri-1050-1.rs:LL:CC | LL | drop(Box::from_raw(ptr as *mut u32)); diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr index 9927d90c6469..2b2e16d1ecff 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr @@ -11,10 +11,13 @@ help: ALLOC was allocated here: | LL | let ptr = Box::into_raw(Box::new(0u16)); | ^^^^^^^^^^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC - = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC -note: inside `main` +note: error occurred inside `std::boxed::Box::::from_raw_in` + --> RUSTLIB/alloc/src/boxed.rs:LL:CC + | +LL | pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: which got called inside `std::boxed::Box::::from_raw` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) +note: which got called inside `main` --> tests/fail/both_borrows/issue-miri-1050-1.rs:LL:CC | LL | drop(Box::from_raw(ptr as *mut u32)); diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr index c704085f9583..f33b6cf77e4d 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr @@ -6,10 +6,9 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC - = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC -note: inside `main` + = note: this is inside `std::boxed::Box::::from_raw_in` + = note: which got called inside `std::boxed::Box::::from_raw` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) +note: which got called inside `main` --> tests/fail/both_borrows/issue-miri-1050-2.rs:LL:CC | LL | drop(Box::from_raw(ptr.as_ptr())); diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr index c704085f9583..f33b6cf77e4d 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr @@ -6,10 +6,9 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC - = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC -note: inside `main` + = note: this is inside `std::boxed::Box::::from_raw_in` + = note: which got called inside `std::boxed::Box::::from_raw` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) +note: which got called inside `main` --> tests/fail/both_borrows/issue-miri-1050-2.rs:LL:CC | LL | drop(Box::from_raw(ptr.as_ptr())); diff --git a/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.stack.stderr b/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.stack.stderr index 3c8316ca5bc1..290f50f60c2b 100644 --- a/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.stack.stderr @@ -16,14 +16,17 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | *our = 5; | ^^^^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `unknown_code_2` at tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC -note: inside `demo_mut_advanced_unique` +note: error occurred inside `unknown_code_2` + --> tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC + | +LL | fn unknown_code_2() { + | ^^^^^^^^^^^^^^^^^^^ +note: which got called inside `demo_mut_advanced_unique` --> tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC | LL | unknown_code_2(); | ^^^^^^^^^^^^^^^^ -note: inside `main` +note: which got called inside `main` --> tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC | LL | demo_mut_advanced_unique(&mut 0); diff --git a/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.tree.stderr index f5c1dea69f02..608e41341c3f 100644 --- a/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.tree.stderr @@ -18,14 +18,17 @@ help: the accessed tag later transitioned to Disabled due to a foreign wri LL | *our = 5; | ^^^^^^^^ = help: this transition corresponds to a loss of read permissions - = note: BACKTRACE (of the first span): - = note: inside `unknown_code_2` at tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC -note: inside `demo_mut_advanced_unique` +note: error occurred inside `unknown_code_2` + --> tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC + | +LL | fn unknown_code_2() { + | ^^^^^^^^^^^^^^^^^^^ +note: which got called inside `demo_mut_advanced_unique` --> tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC | LL | unknown_code_2(); | ^^^^^^^^^^^^^^^^ -note: inside `main` +note: which got called inside `main` --> tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC | LL | demo_mut_advanced_unique(&mut 0); diff --git a/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.stack.stderr b/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.stack.stderr index 7cee5fb1369d..68fd20ba942a 100644 --- a/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.stack.stderr @@ -16,20 +16,23 @@ help: is this argument | LL | fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { | ^^ - = note: BACKTRACE (of the first span): - = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC - = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC -note: inside closure +note: error occurred inside `std::boxed::Box::::from_raw_in` + --> RUSTLIB/alloc/src/boxed.rs:LL:CC + | +LL | pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: which got called inside `std::boxed::Box::::from_raw` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) +note: which got called inside closure --> tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC | LL | || drop(Box::from_raw(ptr)), | ^^^^^^^^^^^^^^^^^^ -note: inside `dealloc_while_running::<{closure@tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC}>` +note: which got called inside `dealloc_while_running::<{closure@tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC}>` --> tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC | LL | dealloc(); | ^^^^^^^^^ -note: inside `main` +note: which got called inside `main` --> tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC | LL | / dealloc_while_running( diff --git a/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.tree.stderr b/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.tree.stderr index aa07ef53b315..f0dffb8f14ad 100644 --- a/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.tree.stderr @@ -25,21 +25,24 @@ help: the protected tag later transitioned to Reserved (conflicted) due to LL | || drop(Box::from_raw(ptr)), | ^^^^^^^^^^^^^^^^^^ = help: this transition corresponds to a temporary loss of write permissions until function exit - = note: BACKTRACE (of the first span): - = note: inside ` as std::ops::Drop>::drop` at RUSTLIB/alloc/src/boxed.rs:LL:CC - = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC - = note: inside `std::mem::drop::>` at RUSTLIB/core/src/mem/mod.rs:LL:CC -note: inside closure +note: error occurred inside ` as std::ops::Drop>::drop` + --> RUSTLIB/alloc/src/boxed.rs:LL:CC + | +LL | fn drop(&mut self) { + | ^^^^^^^^^^^^^^^^^^ + = note: which got called inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` (at RUSTLIB/core/src/ptr/mod.rs:LL:CC) + = note: which got called inside `std::mem::drop::>` (at RUSTLIB/core/src/mem/mod.rs:LL:CC) +note: which got called inside closure --> tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC | LL | || drop(Box::from_raw(ptr)), | ^^^^^^^^^^^^^^^^^^^^^^^^ -note: inside `dealloc_while_running::<{closure@tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC}>` +note: which got called inside `dealloc_while_running::<{closure@tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC}>` --> tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC | LL | dealloc(); | ^^^^^^^^^ -note: inside `main` +note: which got called inside `main` --> tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC | LL | / dealloc_while_running( diff --git a/src/tools/miri/tests/fail/both_borrows/newtype_retagging.stack.stderr b/src/tools/miri/tests/fail/both_borrows/newtype_retagging.stack.stderr index 7bd42fc20ce7..8f1619bda403 100644 --- a/src/tools/miri/tests/fail/both_borrows/newtype_retagging.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/newtype_retagging.stack.stderr @@ -16,20 +16,23 @@ help: is this argument | LL | fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { | ^^ - = note: BACKTRACE (of the first span): - = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC - = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC -note: inside closure +note: error occurred inside `std::boxed::Box::::from_raw_in` + --> RUSTLIB/alloc/src/boxed.rs:LL:CC + | +LL | pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: which got called inside `std::boxed::Box::::from_raw` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) +note: which got called inside closure --> tests/fail/both_borrows/newtype_retagging.rs:LL:CC | LL | || drop(Box::from_raw(ptr)), | ^^^^^^^^^^^^^^^^^^ -note: inside `dealloc_while_running::<{closure@tests/fail/both_borrows/newtype_retagging.rs:LL:CC}>` +note: which got called inside `dealloc_while_running::<{closure@tests/fail/both_borrows/newtype_retagging.rs:LL:CC}>` --> tests/fail/both_borrows/newtype_retagging.rs:LL:CC | LL | dealloc(); | ^^^^^^^^^ -note: inside `main` +note: which got called inside `main` --> tests/fail/both_borrows/newtype_retagging.rs:LL:CC | LL | / dealloc_while_running( diff --git a/src/tools/miri/tests/fail/both_borrows/newtype_retagging.tree.stderr b/src/tools/miri/tests/fail/both_borrows/newtype_retagging.tree.stderr index c8a72c591762..f7a2d63dc8a9 100644 --- a/src/tools/miri/tests/fail/both_borrows/newtype_retagging.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/newtype_retagging.tree.stderr @@ -25,21 +25,24 @@ help: the protected tag later transitioned to Reserved (conflicted) due to LL | || drop(Box::from_raw(ptr)), | ^^^^^^^^^^^^^^^^^^ = help: this transition corresponds to a temporary loss of write permissions until function exit - = note: BACKTRACE (of the first span): - = note: inside ` as std::ops::Drop>::drop` at RUSTLIB/alloc/src/boxed.rs:LL:CC - = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC - = note: inside `std::mem::drop::>` at RUSTLIB/core/src/mem/mod.rs:LL:CC -note: inside closure +note: error occurred inside ` as std::ops::Drop>::drop` + --> RUSTLIB/alloc/src/boxed.rs:LL:CC + | +LL | fn drop(&mut self) { + | ^^^^^^^^^^^^^^^^^^ + = note: which got called inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` (at RUSTLIB/core/src/ptr/mod.rs:LL:CC) + = note: which got called inside `std::mem::drop::>` (at RUSTLIB/core/src/mem/mod.rs:LL:CC) +note: which got called inside closure --> tests/fail/both_borrows/newtype_retagging.rs:LL:CC | LL | || drop(Box::from_raw(ptr)), | ^^^^^^^^^^^^^^^^^^^^^^^^ -note: inside `dealloc_while_running::<{closure@tests/fail/both_borrows/newtype_retagging.rs:LL:CC}>` +note: which got called inside `dealloc_while_running::<{closure@tests/fail/both_borrows/newtype_retagging.rs:LL:CC}>` --> tests/fail/both_borrows/newtype_retagging.rs:LL:CC | LL | dealloc(); | ^^^^^^^^^ -note: inside `main` +note: which got called inside `main` --> tests/fail/both_borrows/newtype_retagging.rs:LL:CC | LL | / dealloc_while_running( diff --git a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr index d97850d7a444..8624205444bc 100644 --- a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr @@ -14,9 +14,12 @@ LL | let _r = &mut *p; = help: therefore from the perspective of data races, a retag has the same implications as a read or write = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside `thread_2` at tests/fail/both_borrows/retag_data_race_write.rs:LL:CC -note: inside closure +note: error occurred on thread `unnamed-ID`, inside `thread_2` + --> tests/fail/both_borrows/retag_data_race_write.rs:LL:CC + | +LL | fn thread_2(p: SendPtr) { + | ^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside closure --> tests/fail/both_borrows/retag_data_race_write.rs:LL:CC | LL | let t2 = std::thread::spawn(move || thread_2(p)); diff --git a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr index c1b37f8a9bfc..6d1dff0d5f53 100644 --- a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr @@ -14,9 +14,12 @@ LL | let _r = &mut *p; = help: therefore from the perspective of data races, a retag has the same implications as a read or write = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside `thread_2` at tests/fail/both_borrows/retag_data_race_write.rs:LL:CC -note: inside closure +note: error occurred on thread `unnamed-ID`, inside `thread_2` + --> tests/fail/both_borrows/retag_data_race_write.rs:LL:CC + | +LL | fn thread_2(p: SendPtr) { + | ^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside closure --> tests/fail/both_borrows/retag_data_race_write.rs:LL:CC | LL | let t2 = std::thread::spawn(move || thread_2(p)); diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.stack.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.stack.stderr index 7c4fe7487012..ff9968802809 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.stack.stderr @@ -16,9 +16,12 @@ help: was later invalidated at offsets [0x4..0x8] by a write access | LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `foo` at tests/fail/both_borrows/return_invalid_shr.rs:LL:CC -note: inside `main` +note: error occurred inside `foo` + --> tests/fail/both_borrows/return_invalid_shr.rs:LL:CC + | +LL | fn foo(x: &mut (i32, i32)) -> &i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/both_borrows/return_invalid_shr.rs:LL:CC | LL | foo(&mut (1, 2)); diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.tree.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.tree.stderr index a8e3553aae2c..598a95dd96c9 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.tree.stderr @@ -18,9 +18,12 @@ help: the accessed tag later transitioned to Disabled due to a foreign wri LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ = help: this transition corresponds to a loss of read permissions - = note: BACKTRACE (of the first span): - = note: inside `foo` at tests/fail/both_borrows/return_invalid_shr.rs:LL:CC -note: inside `main` +note: error occurred inside `foo` + --> tests/fail/both_borrows/return_invalid_shr.rs:LL:CC + | +LL | fn foo(x: &mut (i32, i32)) -> &i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/both_borrows/return_invalid_shr.rs:LL:CC | LL | foo(&mut (1, 2)); diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.stack.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.stack.stderr index 8411437ea4c9..d33782301180 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.stack.stderr @@ -19,9 +19,12 @@ help: was later invalidated at offsets [0x4..0x8] by a write access | LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `foo` at tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC -note: inside `main` +note: error occurred inside `foo` + --> tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC + | +LL | fn foo(x: &mut (i32, i32)) -> Option<&i32> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC | LL | match foo(&mut (1, 2)) { diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.tree.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.tree.stderr index 39da45ad6db4..d303cc9b22e8 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.tree.stderr @@ -18,9 +18,12 @@ help: the accessed tag later transitioned to Disabled due to a foreign wri LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ = help: this transition corresponds to a loss of read permissions - = note: BACKTRACE (of the first span): - = note: inside `foo` at tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC -note: inside `main` +note: error occurred inside `foo` + --> tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC + | +LL | fn foo(x: &mut (i32, i32)) -> Option<&i32> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC | LL | match foo(&mut (1, 2)) { diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.stack.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.stack.stderr index a7c422aa73f2..d6063168d33d 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.stack.stderr @@ -19,9 +19,12 @@ help: was later invalidated at offsets [0x4..0x8] by a write access | LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `foo` at tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC -note: inside `main` +note: error occurred inside `foo` + --> tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC + | +LL | fn foo(x: &mut (i32, i32)) -> (&i32,) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC | LL | foo(&mut (1, 2)).0; diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.tree.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.tree.stderr index 66b03e57905e..0c5b05ce1b94 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.tree.stderr @@ -18,9 +18,12 @@ help: the accessed tag later transitioned to Disabled due to a foreign wri LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ = help: this transition corresponds to a loss of read permissions - = note: BACKTRACE (of the first span): - = note: inside `foo` at tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC -note: inside `main` +note: error occurred inside `foo` + --> tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC + | +LL | fn foo(x: &mut (i32, i32)) -> (&i32,) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC | LL | foo(&mut (1, 2)).0; diff --git a/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.stack.stderr b/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.stack.stderr index eed8c0273ab1..3a05fb151cf1 100644 --- a/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.stack.stderr @@ -11,14 +11,17 @@ help: was created by a SharedReadOnly retag at offsets [0x0..0x4] | LL | *(x as *const i32 as *mut i32) = 7; | ^ - = note: BACKTRACE (of the first span): - = note: inside `unknown_code` at tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC -note: inside `foo` +note: error occurred inside `unknown_code` + --> tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC + | +LL | fn unknown_code(x: &i32) { + | ^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `foo` --> tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC | LL | unknown_code(&*x); | ^^^^^^^^^^^^^^^^^ -note: inside `main` +note: which got called inside `main` --> tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC | LL | println!("{}", foo(&mut 0)); diff --git a/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.tree.stderr index d9b75f65f752..8040cfa212a9 100644 --- a/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.tree.stderr @@ -12,14 +12,17 @@ help: the accessed tag was created here, in the initial state Frozen | LL | fn unknown_code(x: &i32) { | ^ - = note: BACKTRACE (of the first span): - = note: inside `unknown_code` at tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC -note: inside `foo` +note: error occurred inside `unknown_code` + --> tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC + | +LL | fn unknown_code(x: &i32) { + | ^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `foo` --> tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC | LL | unknown_code(&*x); | ^^^^^^^^^^^^^^^^^ -note: inside `main` +note: which got called inside `main` --> tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC | LL | println!("{}", foo(&mut 0)); diff --git a/src/tools/miri/tests/fail/box-cell-alias.stderr b/src/tools/miri/tests/fail/box-cell-alias.stderr index 8e1e9370c707..c5ce263ff1c9 100644 --- a/src/tools/miri/tests/fail/box-cell-alias.stderr +++ b/src/tools/miri/tests/fail/box-cell-alias.stderr @@ -16,9 +16,12 @@ help: was later invalidated at offsets [0x0..0x1] by a Unique retag | LL | let res = helper(val, ptr); | ^^^ - = note: BACKTRACE (of the first span): - = note: inside `helper` at tests/fail/box-cell-alias.rs:LL:CC -note: inside `main` +note: error occurred inside `helper` + --> tests/fail/box-cell-alias.rs:LL:CC + | +LL | fn helper(val: Box>, ptr: *const Cell) -> u8 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/box-cell-alias.rs:LL:CC | LL | let res = helper(val, ptr); diff --git a/src/tools/miri/tests/fail/closures/uninhabited-variant.stderr b/src/tools/miri/tests/fail/closures/uninhabited-variant.stderr index 995a5e3eac14..f0f145fd1366 100644 --- a/src/tools/miri/tests/fail/closures/uninhabited-variant.stderr +++ b/src/tools/miri/tests/fail/closures/uninhabited-variant.stderr @@ -6,9 +6,8 @@ LL | match r { | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside closure at tests/fail/closures/uninhabited-variant.rs:LL:CC -note: inside `main` + = note: this is inside closure +note: which got called inside `main` --> tests/fail/closures/uninhabited-variant.rs:LL:CC | LL | f(); diff --git a/src/tools/miri/tests/fail/concurrency/mutex-leak-move-deadlock.rs b/src/tools/miri/tests/fail/concurrency/mutex-leak-move-deadlock.rs index 9c73f6c03edd..5afa6c71700e 100644 --- a/src/tools/miri/tests/fail/concurrency/mutex-leak-move-deadlock.rs +++ b/src/tools/miri/tests/fail/concurrency/mutex-leak-move-deadlock.rs @@ -4,7 +4,7 @@ //@normalize-stderr-test: "\| +\^+" -> "| ^" //@normalize-stderr-test: "\n *= note:.*" -> "" // On macOS we use chekced pthread mutexes which changes the error -//@normalize-stderr-test: "this thread got stuck here" -> "thread `main` got stuck here" +//@normalize-stderr-test: "a thread got stuck here" -> "thread `main` got stuck here" //@normalize-stderr-test: "a thread deadlocked" -> "the evaluated program deadlocked" use std::mem; use std::sync::Mutex; diff --git a/src/tools/miri/tests/fail/concurrency/mutex-leak-move-deadlock.stderr b/src/tools/miri/tests/fail/concurrency/mutex-leak-move-deadlock.stderr index 7784132a54ce..258f5a823fcd 100644 --- a/src/tools/miri/tests/fail/concurrency/mutex-leak-move-deadlock.stderr +++ b/src/tools/miri/tests/fail/concurrency/mutex-leak-move-deadlock.stderr @@ -2,9 +2,9 @@ error: the evaluated program deadlocked --> RUSTLIB/std/$FILE:LL:CC | LL | $CODE - | ^ thread `main` got stuck here + | ^ thread got stuck here | -note: inside `main` +note: which got called inside `main` --> tests/fail/concurrency/mutex-leak-move-deadlock.rs:LL:CC | LL | $CODE diff --git a/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr b/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr index 70ecfa9379a7..2cc3b845deba 100644 --- a/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr +++ b/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr @@ -16,15 +16,18 @@ help: ALLOC was deallocated here: | LL | }; // *deallocate* coroutine_iterator | ^ - = note: BACKTRACE (of the first span): - = note: inside closure at tests/fail/coroutine-pinned-moved.rs:LL:CC -note: inside ` as std::iter::Iterator>::next` +note: error occurred inside closure + --> tests/fail/coroutine-pinned-moved.rs:LL:CC + | +LL | static move || { + | ^^^^^^^^^^^^^^ +note: which got called inside ` as std::iter::Iterator>::next` --> tests/fail/coroutine-pinned-moved.rs:LL:CC | LL | match me.resume(()) { | ^^^^^^^^^^^^^ - = note: inside `std::boxed::iter::>>::next` at RUSTLIB/alloc/src/boxed/iter.rs:LL:CC -note: inside `main` + = note: which got called inside `std::boxed::iter::>>::next` (at RUSTLIB/alloc/src/boxed/iter.rs:LL:CC) +note: which got called inside `main` --> tests/fail/coroutine-pinned-moved.rs:LL:CC | LL | coroutine_iterator_2.next(); // and use moved value diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr index df2b227c8097..e5471e094bc8 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr @@ -6,9 +6,8 @@ LL | unsafe { &(*x).0 as *const i32 } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `via_ref` at tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs:LL:CC -note: inside `main` + = note: this is inside `via_ref` +note: which got called inside `main` --> tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs:LL:CC | LL | via_ref(ptr); // this is not diff --git a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr index 3a3133049b21..93bb9603ae5b 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr @@ -6,9 +6,8 @@ LL | let _ref = unsafe { &mut *(LEAK as *mut i32) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `evil` at tests/fail/dangling_pointers/storage_dead_dangling.rs:LL:CC -note: inside `main` + = note: this is inside `evil` +note: which got called inside `main` --> tests/fail/dangling_pointers/storage_dead_dangling.rs:LL:CC | LL | evil(); diff --git a/src/tools/miri/tests/fail/data_race/alloc_read_race.stderr b/src/tools/miri/tests/fail/data_race/alloc_read_race.stderr index d4933db2ed57..c9e9059ef085 100644 --- a/src/tools/miri/tests/fail/data_race/alloc_read_race.stderr +++ b/src/tools/miri/tests/fail/data_race/alloc_read_race.stderr @@ -11,6 +11,7 @@ LL | pointer.store(Box::into_raw(Box::new_uninit()), Ordering::Relax | ^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/alloc_write_race.stderr b/src/tools/miri/tests/fail/data_race/alloc_write_race.stderr index da7f5ed869db..110c013ec0cc 100644 --- a/src/tools/miri/tests/fail/data_race/alloc_write_race.stderr +++ b/src/tools/miri/tests/fail/data_race/alloc_write_race.stderr @@ -11,6 +11,7 @@ LL | .store(Box::into_raw(Box::::new_uninit()) as *mut us | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.stderr b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.stderr index 203e6a10e497..2d0317c7ffdf 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.stderr @@ -11,6 +11,7 @@ LL | *(c.0 as *mut usize) = 32; | ^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.stderr b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.stderr index 791dc71f9930..a5c1006e31f6 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.stderr @@ -11,6 +11,7 @@ LL | atomic_ref.load(Ordering::SeqCst) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.stderr b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.stderr index 73d963875fb1..bef2f1f6fa1a 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.stderr @@ -11,6 +11,7 @@ LL | atomic_ref.store(32, Ordering::SeqCst) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.stderr b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.stderr index 066fff5e3d36..56c669549106 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.stderr @@ -11,6 +11,7 @@ LL | let _val = *(c.0 as *mut usize); | ^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.stderr b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.stderr index 10b7d8398d9d..3b79801bfab8 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.stderr @@ -11,6 +11,7 @@ LL | *(c.0 as *mut usize) = 32; | ^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.stderr b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.stderr index bb854bc4235c..069dc9ac8de8 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.stderr @@ -11,6 +11,7 @@ LL | atomic_ref.store(64, Ordering::SeqCst); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.stderr b/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.stderr index 8cecfbee9d95..a01f85ab6ce1 100644 --- a/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.stderr +++ b/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.stderr @@ -11,6 +11,7 @@ LL | *c.0 = 32; | ^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/dangling_thread_race.stderr b/src/tools/miri/tests/fail/data_race/dangling_thread_race.stderr index 7260776043ea..67b254c265da 100644 --- a/src/tools/miri/tests/fail/data_race/dangling_thread_race.stderr +++ b/src/tools/miri/tests/fail/data_race/dangling_thread_race.stderr @@ -11,6 +11,7 @@ LL | *c.0 = 32; | ^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `main` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race1.stderr b/src/tools/miri/tests/fail/data_race/dealloc_read_race1.stderr index c4200ea96153..afe1125e7514 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race1.stderr @@ -16,6 +16,7 @@ LL | let _val = *ptr.0; | ^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race2.stderr b/src/tools/miri/tests/fail/data_race/dealloc_read_race2.stderr index 5ab5c9655d78..a741203dcf6d 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race2.stderr @@ -20,6 +20,7 @@ LL | | std::mem::size_of::(), LL | | std::mem::align_of::(), LL | | ) | |_____________^ + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.stderr b/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.stderr index b52e48827b4b..4adf3f3d58d3 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.stderr @@ -11,6 +11,7 @@ LL | *pointer.load(Ordering::Acquire) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race1.stderr b/src/tools/miri/tests/fail/data_race/dealloc_write_race1.stderr index 0a574068d4e7..cfa4f06f9a9f 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race1.stderr @@ -16,6 +16,7 @@ LL | *ptr.0 = 2; | ^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race2.stderr b/src/tools/miri/tests/fail/data_race/dealloc_write_race2.stderr index 9fbae21eb891..3a843a4eba5d 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race2.stderr @@ -20,6 +20,7 @@ LL | | std::mem::size_of::(), LL | | std::mem::align_of::(), LL | | ); | |_____________^ + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.stderr b/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.stderr index 0c853ccb8cc1..708fddb8f0be 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.stderr @@ -11,6 +11,7 @@ LL | *pointer.load(Ordering::Acquire) = 3; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.stderr b/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.stderr index a8eee1241b65..adcf00c8a88f 100644 --- a/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.stderr +++ b/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.stderr @@ -11,6 +11,7 @@ LL | *c.0 = 32; | ^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/fence_after_load.stderr b/src/tools/miri/tests/fail/data_race/fence_after_load.stderr index bf2ac30a1e3f..f2098e1d3e2d 100644 --- a/src/tools/miri/tests/fail/data_race/fence_after_load.stderr +++ b/src/tools/miri/tests/fail/data_race/fence_after_load.stderr @@ -11,6 +11,7 @@ LL | unsafe { V = 1 } | ^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `main` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.stderr b/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.stderr index 52bd7721ef22..676a62b8fefe 100644 --- a/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.stderr +++ b/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.stderr @@ -11,6 +11,7 @@ LL | StorageLive(val); | ^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/local_variable_read_race.stderr b/src/tools/miri/tests/fail/data_race/local_variable_read_race.stderr index 969b6faadbe1..269676caf5c7 100644 --- a/src/tools/miri/tests/fail/data_race/local_variable_read_race.stderr +++ b/src/tools/miri/tests/fail/data_race/local_variable_read_race.stderr @@ -11,6 +11,7 @@ LL | let _val = val; | ^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/local_variable_write_race.stderr b/src/tools/miri/tests/fail/data_race/local_variable_write_race.stderr index 0bf7dd28c0f9..5e26e88ce98c 100644 --- a/src/tools/miri/tests/fail/data_race/local_variable_write_race.stderr +++ b/src/tools/miri/tests/fail/data_race/local_variable_write_race.stderr @@ -11,6 +11,7 @@ LL | let mut val: u8 = 0; | ^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_first_load.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_first_load.stderr index 087f326053b5..95b41a232b2c 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_first_load.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_first_load.stderr @@ -13,6 +13,7 @@ LL | a16.load(Ordering::SeqCst); = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_second_load.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_second_load.stderr index 66aee703e4f3..96b0c00e08cc 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_second_load.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_second_load.stderr @@ -13,6 +13,7 @@ LL | a16.load(Ordering::SeqCst); = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_write.read_write.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.read_write.stderr index 967fd45c5b36..e795f7ec8120 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read_write.read_write.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.read_write.stderr @@ -13,6 +13,7 @@ LL | a8[0].load(Ordering::SeqCst); = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_write.write_read.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.write_read.stderr index 7664c3f13e3d..ecdbb49e8b86 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read_write.write_read.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.write_read.stderr @@ -13,6 +13,7 @@ LL | a16.store(1, Ordering::SeqCst); = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_write_read.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read_write_read.stderr index f1884bf404f1..be1bb4e507f6 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read_write_read.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_write_read.stderr @@ -19,6 +19,7 @@ LL | | ); = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.fst.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.fst.stderr index 7e30cf6856de..0b1eac5d5d03 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.fst.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.fst.stderr @@ -13,6 +13,7 @@ LL | a16.store(1, Ordering::SeqCst); = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.snd.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.snd.stderr index 74bb72b986af..da62f537903a 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.snd.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.snd.stderr @@ -13,6 +13,7 @@ LL | a16.store(1, Ordering::SeqCst); = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/read_write_race.stderr b/src/tools/miri/tests/fail/data_race/read_write_race.stderr index ce063d8c532f..9163bff917e4 100644 --- a/src/tools/miri/tests/fail/data_race/read_write_race.stderr +++ b/src/tools/miri/tests/fail/data_race/read_write_race.stderr @@ -11,6 +11,7 @@ LL | let _val = *c.0; | ^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/read_write_race_stack.stderr b/src/tools/miri/tests/fail/data_race/read_write_race_stack.stderr index 5ac78a2ecf6b..719a7162690a 100644 --- a/src/tools/miri/tests/fail/data_race/read_write_race_stack.stderr +++ b/src/tools/miri/tests/fail/data_race/read_write_race_stack.stderr @@ -11,6 +11,7 @@ LL | *pointer.load(Ordering::Acquire) = 3; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/relax_acquire_race.stderr b/src/tools/miri/tests/fail/data_race/relax_acquire_race.stderr index fffde0370a2a..ea441ab36722 100644 --- a/src/tools/miri/tests/fail/data_race/relax_acquire_race.stderr +++ b/src/tools/miri/tests/fail/data_race/relax_acquire_race.stderr @@ -11,6 +11,7 @@ LL | *c.0 = 1; | ^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/release_seq_race.stderr b/src/tools/miri/tests/fail/data_race/release_seq_race.stderr index 61f5501434b8..8cb1fd7ce613 100644 --- a/src/tools/miri/tests/fail/data_race/release_seq_race.stderr +++ b/src/tools/miri/tests/fail/data_race/release_seq_race.stderr @@ -11,6 +11,7 @@ LL | *c.0 = 1; | ^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.stderr b/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.stderr index 2c28ee03e786..d9a4b71ca21f 100644 --- a/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.stderr +++ b/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.stderr @@ -11,6 +11,7 @@ LL | *c.0 = 1; | ^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/rmw_race.stderr b/src/tools/miri/tests/fail/data_race/rmw_race.stderr index 04621ff07b81..c1eeef1dca76 100644 --- a/src/tools/miri/tests/fail/data_race/rmw_race.stderr +++ b/src/tools/miri/tests/fail/data_race/rmw_race.stderr @@ -11,6 +11,7 @@ LL | *c.0 = 1; | ^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/stack_pop_race.stderr b/src/tools/miri/tests/fail/data_race/stack_pop_race.stderr index 130a31ebeef0..c543bcf11150 100644 --- a/src/tools/miri/tests/fail/data_race/stack_pop_race.stderr +++ b/src/tools/miri/tests/fail/data_race/stack_pop_race.stderr @@ -11,6 +11,7 @@ LL | let _val = unsafe { *ptr.0 }; | ^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `main` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/write_write_race.stderr b/src/tools/miri/tests/fail/data_race/write_write_race.stderr index 03bee0060a4e..13f798e4da56 100644 --- a/src/tools/miri/tests/fail/data_race/write_write_race.stderr +++ b/src/tools/miri/tests/fail/data_race/write_write_race.stderr @@ -11,6 +11,7 @@ LL | *c.0 = 32; | ^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/write_write_race_stack.stderr b/src/tools/miri/tests/fail/data_race/write_write_race_stack.stderr index cb2faf4ac274..eb8c2747b40e 100644 --- a/src/tools/miri/tests/fail/data_race/write_write_race_stack.stderr +++ b/src/tools/miri/tests/fail/data_race/write_write_race_stack.stderr @@ -11,6 +11,7 @@ LL | *pointer.load(Ordering::Acquire) = 3; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.stderr b/src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.stderr index f3ec20837d37..068d4b4f1329 100644 --- a/src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.stderr +++ b/src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.stderr @@ -6,9 +6,8 @@ LL | SetDiscriminant(*ptr, 1); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `set_discriminant` at tests/fail/enum-set-discriminant-niche-variant-wrong.rs:LL:CC -note: inside `main` + = note: this is inside `set_discriminant` +note: which got called inside `main` --> tests/fail/enum-set-discriminant-niche-variant-wrong.rs:LL:CC | LL | set_discriminant(&mut v); diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.stack.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.stack.stderr index 8a454bedb281..f45f5c26bacb 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.stack.stderr @@ -21,9 +21,12 @@ help: is this argument | LL | unsafe { ptr.write(S(0)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `callee` at tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC -note: inside `main` +note: error occurred inside `callee` + --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC + | +LL | fn callee(x: S, ptr: *mut S) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC | LL | Call(_unit = callee(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue()) diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr index 74706d6b9f6b..044026ee8ddc 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr @@ -30,9 +30,12 @@ help: the protected tag later transitioned to Unique due to a child write LL | unsafe { ptr.write(S(0)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference - = note: BACKTRACE (of the first span): - = note: inside `callee` at tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC -note: inside `main` +note: error occurred inside `callee` + --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC + | +LL | fn callee(x: S, ptr: *mut S) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC | LL | Call(_unit = callee(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue()) diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr index 09a5b9a64961..b66d13cede1f 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr @@ -6,9 +6,8 @@ LL | unsafe { ptr.read() }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `change_arg` at tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC -note: inside `main` + = note: this is inside `change_arg` +note: which got called inside `main` --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC | LL | Call(_unit = change_arg(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue()) diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr index 609599ef6ca8..9dc9adc13ae3 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr @@ -21,9 +21,12 @@ help: is this argument | LL | x.0 = 0; | ^^^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `change_arg` at tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC -note: inside `main` +note: error occurred inside `change_arg` + --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC + | +LL | fn change_arg(mut x: S, ptr: *mut S) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC | LL | Call(_unit = change_arg(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue()) diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr index c8c0e5c37efe..0a6c6e615a16 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr @@ -30,9 +30,12 @@ help: the protected tag later transitioned to Unique due to a child write LL | x.0 = 0; | ^^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference - = note: BACKTRACE (of the first span): - = note: inside `change_arg` at tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC -note: inside `main` +note: error occurred inside `change_arg` + --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC + | +LL | fn change_arg(mut x: S, ptr: *mut S) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC | LL | Call(_unit = change_arg(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue()) diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr index 95f79aae6c17..dd7f52d03f20 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr @@ -14,21 +14,20 @@ error: abnormal termination: the program aborted execution LL | crate::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: BACKTRACE: - = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC - = note: inside `std::panicking::panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC - = note: inside `core::panicking::panic_cannot_unwind` at RUSTLIB/core/src/panicking.rs:LL:CC -note: inside `nounwind` + = note: this is inside `std::panicking::panic_with_hook` + = note: which got called inside closure (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` (at RUSTLIB/std/src/sys/backtrace.rs:LL:CC) + = note: which got called inside `std::panicking::panic_handler` (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `core::panicking::panic_nounwind` (at RUSTLIB/core/src/panicking.rs:LL:CC) + = note: which got called inside `core::panicking::panic_cannot_unwind` (at RUSTLIB/core/src/panicking.rs:LL:CC) +note: which got called inside `nounwind` --> tests/fail/function_calls/exported_symbol_bad_unwind2.rs:LL:CC | LL | / extern "C-unwind" fn nounwind() { LL | | panic!(); LL | | } | |_^ -note: inside `main` +note: which got called inside `main` --> tests/fail/function_calls/exported_symbol_bad_unwind2.rs:LL:CC | LL | unsafe { nounwind() } diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr index 95f79aae6c17..dd7f52d03f20 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr @@ -14,21 +14,20 @@ error: abnormal termination: the program aborted execution LL | crate::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: BACKTRACE: - = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC - = note: inside `std::panicking::panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC - = note: inside `core::panicking::panic_cannot_unwind` at RUSTLIB/core/src/panicking.rs:LL:CC -note: inside `nounwind` + = note: this is inside `std::panicking::panic_with_hook` + = note: which got called inside closure (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` (at RUSTLIB/std/src/sys/backtrace.rs:LL:CC) + = note: which got called inside `std::panicking::panic_handler` (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `core::panicking::panic_nounwind` (at RUSTLIB/core/src/panicking.rs:LL:CC) + = note: which got called inside `core::panicking::panic_cannot_unwind` (at RUSTLIB/core/src/panicking.rs:LL:CC) +note: which got called inside `nounwind` --> tests/fail/function_calls/exported_symbol_bad_unwind2.rs:LL:CC | LL | / extern "C-unwind" fn nounwind() { LL | | panic!(); LL | | } | |_^ -note: inside `main` +note: which got called inside `main` --> tests/fail/function_calls/exported_symbol_bad_unwind2.rs:LL:CC | LL | unsafe { nounwind() } diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr index d478568ceaeb..32e80ed0e61e 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr @@ -6,9 +6,8 @@ LL | unsafe { ptr.read() }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `myfun` at tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC -note: inside `main` + = note: this is inside `myfun` +note: which got called inside `main` --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr index 86adbab353b4..14c8e5cb8960 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr @@ -21,9 +21,12 @@ help: was later invalidated at offsets [0x0..0x4] by a Unique in-place fun | LL | unsafe { ptr.read() }; | ^^^^^^^^^^^^^^^^^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `myfun` at tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC -note: inside `main` +note: error occurred inside `myfun` + --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC + | +LL | fn myfun(ptr: *mut i32) -> i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr index b43e19c3905c..2e5b687f90ac 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr @@ -30,9 +30,12 @@ help: the protected tag later transitioned to Unique due to a child write LL | unsafe { ptr.read() }; | ^^^^^^^^^^^^^^^^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference - = note: BACKTRACE (of the first span): - = note: inside `myfun` at tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC -note: inside `main` +note: error occurred inside `myfun` + --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC + | +LL | fn myfun(ptr: *mut i32) -> i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr index faae6172d751..63dee06563d1 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr @@ -21,9 +21,12 @@ help: was later invalidated at offsets [0x0..0x4] by a Unique in-place fun | LL | unsafe { ptr.write(0) }; | ^^^^^^^^^^^^^^^^^^^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `myfun` at tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC -note: inside `main` +note: error occurred inside `myfun` + --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC + | +LL | fn myfun(ptr: *mut i32) -> i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr index deefb24b7850..80c111d4ddb4 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr @@ -30,9 +30,12 @@ help: the protected tag later transitioned to Unique due to a child write LL | unsafe { ptr.write(0) }; | ^^^^^^^^^^^^^^^^^^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference - = note: BACKTRACE (of the first span): - = note: inside `myfun` at tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC -note: inside `main` +note: error occurred inside `myfun` + --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC + | +LL | fn myfun(ptr: *mut i32) -> i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr index 1a18857bb175..a6129451530a 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr @@ -21,9 +21,12 @@ help: was later invalidated at offsets [0x0..0x4] by a Unique in-place fun | LL | become myfun2(ptr) | ^^^^^^^^^^^^^^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `myfun2` at tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC -note: inside `main` +note: error occurred inside `myfun2` + --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC + | +LL | fn myfun2(ptr: *mut i32) -> i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr index 76ccf39744d9..a6fff1c26683 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr @@ -30,9 +30,12 @@ help: the protected tag later transitioned to Unique due to a child write LL | unsafe { ptr.write(0) }; | ^^^^^^^^^^^^^^^^^^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference - = note: BACKTRACE (of the first span): - = note: inside `myfun2` at tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC -note: inside `main` +note: error occurred inside `myfun2` + --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC + | +LL | fn myfun2(ptr: *mut i32) -> i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) diff --git a/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr b/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr index 755bc3e7c2c0..ef6decaece35 100644 --- a/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr +++ b/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr @@ -6,9 +6,8 @@ LL | unsafe { foo(0.0, x) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `bar` at tests/fail/function_calls/simd_feature_flag_difference.rs:LL:CC -note: inside `main` + = note: this is inside `bar` +note: which got called inside `main` --> tests/fail/function_calls/simd_feature_flag_difference.rs:LL:CC | LL | let copy = bar(input); diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr index 1e7f500edb2d..697e35a660ca 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr @@ -6,9 +6,8 @@ LL | RET = PtrMetadata(*p); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `deref_meta` at tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs:LL:CC -note: inside `main` + = note: this is inside `deref_meta` +note: which got called inside `main` --> tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs:LL:CC | LL | let _meta = deref_meta(p.as_ptr().cast()); diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr index d284a6f6d019..ba711710b41e 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr @@ -18,9 +18,8 @@ LL | RET = PtrMetadata(*p); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `deref_meta` at tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs:LL:CC -note: inside `main` + = note: this is inside `deref_meta` +note: which got called inside `main` --> tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs:LL:CC | LL | let _meta = deref_meta(p.as_ptr().cast()); diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr index 7a1f3d6ea84f..104e281f2a8e 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr @@ -6,9 +6,8 @@ LL | RET = PtrMetadata(*p); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `deref_meta` at tests/fail/intrinsics/ptr_metadata_uninit_thin.rs:LL:CC -note: inside `main` + = note: this is inside `deref_meta` +note: which got called inside `main` --> tests/fail/intrinsics/ptr_metadata_uninit_thin.rs:LL:CC | LL | let _meta = deref_meta(p.as_ptr()); diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr index 7db795829925..619925f28968 100644 --- a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr +++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr @@ -6,9 +6,8 @@ LL | typed_swap_nonoverlapping(a, b); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `invalid_array` at tests/fail/intrinsics/typed-swap-invalid-array.rs:LL:CC -note: inside `main` + = note: this is inside `invalid_array` +note: which got called inside `main` --> tests/fail/intrinsics/typed-swap-invalid-array.rs:LL:CC | LL | invalid_array(); diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.left.stderr b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.left.stderr index 7edf72205d9e..42bea7dd5e34 100644 --- a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.left.stderr +++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.left.stderr @@ -6,9 +6,8 @@ LL | typed_swap_nonoverlapping(a, b); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `invalid_scalar` at tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC -note: inside `main` + = note: this is inside `invalid_scalar` +note: which got called inside `main` --> tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC | LL | invalid_scalar(); diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.right.stderr b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.right.stderr index aece0b6cb98a..13e8c7f9c5ae 100644 --- a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.right.stderr +++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.right.stderr @@ -6,9 +6,8 @@ LL | typed_swap_nonoverlapping(a, b); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `invalid_scalar` at tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC -note: inside `main` + = note: this is inside `invalid_scalar` +note: which got called inside `main` --> tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC | LL | invalid_scalar(); diff --git a/src/tools/miri/tests/fail/issue-miri-1112.stderr b/src/tools/miri/tests/fail/issue-miri-1112.stderr index 98f04ff1af65..0fc67c6d4fd9 100644 --- a/src/tools/miri/tests/fail/issue-miri-1112.stderr +++ b/src/tools/miri/tests/fail/issue-miri-1112.stderr @@ -6,9 +6,8 @@ LL | let obj = std::mem::transmute::(obj) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `FunnyPointer::from_data_ptr` at tests/fail/issue-miri-1112.rs:LL:CC -note: inside `main` + = note: this is inside `FunnyPointer::from_data_ptr` +note: which got called inside `main` --> tests/fail/issue-miri-1112.rs:LL:CC | LL | let _raw: &FunnyPointer = FunnyPointer::from_data_ptr(&hello, &meta as *const _); diff --git a/src/tools/miri/tests/fail/memleak_rc.stderr b/src/tools/miri/tests/fail/memleak_rc.stderr index df12eeed6ac6..f7b0950ef6ce 100644 --- a/src/tools/miri/tests/fail/memleak_rc.stderr +++ b/src/tools/miri/tests/fail/memleak_rc.stderr @@ -4,9 +4,8 @@ error: memory leaked: ALLOC (Rust heap, SIZE, ALIGN), allocated here: LL | Box::leak(Box::new(RcInner { strong: Cell::new(1), weak: Cell::new(1), value })) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: BACKTRACE: - = note: inside `std::rc::Rc::>>::new` at RUSTLIB/alloc/src/rc.rs:LL:CC -note: inside `main` + = note: this is inside `std::rc::Rc::>>::new` +note: which got called inside `main` --> tests/fail/memleak_rc.rs:LL:CC | LL | let x = Dummy(Rc::new(RefCell::new(None))); diff --git a/src/tools/miri/tests/fail/never_transmute_void.stderr b/src/tools/miri/tests/fail/never_transmute_void.stderr index 10ef783f2201..a236d17c49dd 100644 --- a/src/tools/miri/tests/fail/never_transmute_void.stderr +++ b/src/tools/miri/tests/fail/never_transmute_void.stderr @@ -6,9 +6,8 @@ LL | match v.0 {} | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `m::f` at tests/fail/never_transmute_void.rs:LL:CC -note: inside `main` + = note: this is inside `m::f` +note: which got called inside `main` --> tests/fail/never_transmute_void.rs:LL:CC | LL | m::f(v); diff --git a/src/tools/miri/tests/fail/overlapping_assignment.stderr b/src/tools/miri/tests/fail/overlapping_assignment.stderr index a479e8be6481..6bf7fa446598 100644 --- a/src/tools/miri/tests/fail/overlapping_assignment.stderr +++ b/src/tools/miri/tests/fail/overlapping_assignment.stderr @@ -6,9 +6,8 @@ LL | *ptr1 = *ptr2; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `self_copy` at tests/fail/overlapping_assignment.rs:LL:CC -note: inside `main` + = note: this is inside `self_copy` +note: which got called inside `main` --> tests/fail/overlapping_assignment.rs:LL:CC | LL | self_copy(ptr, ptr); diff --git a/src/tools/miri/tests/fail/panic/abort_unwind.stderr b/src/tools/miri/tests/fail/panic/abort_unwind.stderr index 23dbc2fb8f39..1f45211c5ee4 100644 --- a/src/tools/miri/tests/fail/panic/abort_unwind.stderr +++ b/src/tools/miri/tests/fail/panic/abort_unwind.stderr @@ -14,15 +14,14 @@ error: abnormal termination: the program aborted execution LL | crate::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: BACKTRACE: - = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC - = note: inside `std::panicking::panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC - = note: inside `core::panicking::panic_cannot_unwind` at RUSTLIB/core/src/panicking.rs:LL:CC - = note: inside `std::panic::abort_unwind::<{closure@tests/fail/panic/abort_unwind.rs:LL:CC}, ()>` at RUSTLIB/core/src/panic.rs:LL:CC -note: inside `main` + = note: this is inside `std::panicking::panic_with_hook` + = note: which got called inside closure (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` (at RUSTLIB/std/src/sys/backtrace.rs:LL:CC) + = note: which got called inside `std::panicking::panic_handler` (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `core::panicking::panic_nounwind` (at RUSTLIB/core/src/panicking.rs:LL:CC) + = note: which got called inside `core::panicking::panic_cannot_unwind` (at RUSTLIB/core/src/panicking.rs:LL:CC) + = note: which got called inside `std::panic::abort_unwind::<{closure@tests/fail/panic/abort_unwind.rs:LL:CC}, ()>` (at RUSTLIB/core/src/panic.rs:LL:CC) +note: which got called inside `main` --> tests/fail/panic/abort_unwind.rs:LL:CC | LL | std::panic::abort_unwind(|| panic!("PANIC!!!")); diff --git a/src/tools/miri/tests/fail/panic/bad_unwind.stderr b/src/tools/miri/tests/fail/panic/bad_unwind.stderr index b0a8492b6a61..06e019bb6978 100644 --- a/src/tools/miri/tests/fail/panic/bad_unwind.stderr +++ b/src/tools/miri/tests/fail/panic/bad_unwind.stderr @@ -11,12 +11,11 @@ LL | std::panic::catch_unwind(|| unwind()).unwrap_err(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside closure at tests/fail/panic/bad_unwind.rs:LL:CC - = note: inside `std::panicking::catch_unwind::do_call::<{closure@tests/fail/panic/bad_unwind.rs:LL:CC}, ()>` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::panicking::catch_unwind::<(), {closure@tests/fail/panic/bad_unwind.rs:LL:CC}>` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::panic::catch_unwind::<{closure@tests/fail/panic/bad_unwind.rs:LL:CC}, ()>` at RUSTLIB/std/src/panic.rs:LL:CC -note: inside `main` + = note: this is inside closure + = note: which got called inside `std::panicking::catch_unwind::do_call::<{closure@tests/fail/panic/bad_unwind.rs:LL:CC}, ()>` (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `std::panicking::catch_unwind::<(), {closure@tests/fail/panic/bad_unwind.rs:LL:CC}>` (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `std::panic::catch_unwind::<{closure@tests/fail/panic/bad_unwind.rs:LL:CC}, ()>` (at RUSTLIB/std/src/panic.rs:LL:CC) +note: which got called inside `main` --> tests/fail/panic/bad_unwind.rs:LL:CC | LL | std::panic::catch_unwind(|| unwind()).unwrap_err(); diff --git a/src/tools/miri/tests/fail/panic/double_panic.stderr b/src/tools/miri/tests/fail/panic/double_panic.stderr index edbc0d8fc571..4beadb6aa647 100644 --- a/src/tools/miri/tests/fail/panic/double_panic.stderr +++ b/src/tools/miri/tests/fail/panic/double_panic.stderr @@ -17,14 +17,13 @@ error: abnormal termination: the program aborted execution LL | crate::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: BACKTRACE: - = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC - = note: inside `std::panicking::panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `core::panicking::panic_nounwind_nobacktrace` at RUSTLIB/core/src/panicking.rs:LL:CC - = note: inside `core::panicking::panic_in_cleanup` at RUSTLIB/core/src/panicking.rs:LL:CC -note: inside `main` + = note: this is inside `std::panicking::panic_with_hook` + = note: which got called inside closure (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` (at RUSTLIB/std/src/sys/backtrace.rs:LL:CC) + = note: which got called inside `std::panicking::panic_handler` (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `core::panicking::panic_nounwind_nobacktrace` (at RUSTLIB/core/src/panicking.rs:LL:CC) + = note: which got called inside `core::panicking::panic_in_cleanup` (at RUSTLIB/core/src/panicking.rs:LL:CC) +note: which got called inside `main` --> tests/fail/panic/double_panic.rs:LL:CC | LL | / fn main() { diff --git a/src/tools/miri/tests/fail/panic/no_std.stderr b/src/tools/miri/tests/fail/panic/no_std.stderr index dbd29e43069e..128dfddc215e 100644 --- a/src/tools/miri/tests/fail/panic/no_std.stderr +++ b/src/tools/miri/tests/fail/panic/no_std.stderr @@ -6,9 +6,8 @@ error: abnormal termination: the program aborted execution LL | core::intrinsics::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: BACKTRACE: - = note: inside `panic_handler` at tests/fail/panic/no_std.rs:LL:CC -note: inside `miri_start` + = note: this is inside `panic_handler` +note: which got called inside `miri_start` --> tests/fail/panic/no_std.rs:LL:CC | LL | panic!("blarg I am dead") diff --git a/src/tools/miri/tests/fail/panic/panic_abort1.stderr b/src/tools/miri/tests/fail/panic/panic_abort1.stderr index c389a9bc0750..57c8ee843b86 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort1.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort1.stderr @@ -9,15 +9,14 @@ error: abnormal termination: the program aborted execution LL | crate::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: BACKTRACE: - = note: inside `std::rt::__rust_abort` at RUSTLIB/std/src/rt.rs:LL:CC - = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC - = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC - = note: inside `std::panicking::panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC -note: inside `main` + = note: this is inside `std::rt::__rust_abort` + = note: which got called inside `panic_abort::__rust_start_panic` (at RUSTLIB/panic_abort/src/lib.rs:LL:CC) + = note: which got called inside `std::panicking::rust_panic` (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `std::panicking::panic_with_hook` (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside closure (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` (at RUSTLIB/std/src/sys/backtrace.rs:LL:CC) + = note: which got called inside `std::panicking::panic_handler` (at RUSTLIB/std/src/panicking.rs:LL:CC) +note: which got called inside `main` --> tests/fail/panic/panic_abort1.rs:LL:CC | LL | std::panic!("panicking from libstd"); diff --git a/src/tools/miri/tests/fail/panic/panic_abort2.stderr b/src/tools/miri/tests/fail/panic/panic_abort2.stderr index 5fe2245cbe00..7c145634a102 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort2.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort2.stderr @@ -9,15 +9,14 @@ error: abnormal termination: the program aborted execution LL | crate::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: BACKTRACE: - = note: inside `std::rt::__rust_abort` at RUSTLIB/std/src/rt.rs:LL:CC - = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC - = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC - = note: inside `std::panicking::panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC -note: inside `main` + = note: this is inside `std::rt::__rust_abort` + = note: which got called inside `panic_abort::__rust_start_panic` (at RUSTLIB/panic_abort/src/lib.rs:LL:CC) + = note: which got called inside `std::panicking::rust_panic` (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `std::panicking::panic_with_hook` (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside closure (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` (at RUSTLIB/std/src/sys/backtrace.rs:LL:CC) + = note: which got called inside `std::panicking::panic_handler` (at RUSTLIB/std/src/panicking.rs:LL:CC) +note: which got called inside `main` --> tests/fail/panic/panic_abort2.rs:LL:CC | LL | std::panic!("{}-panicking from libstd", 42); diff --git a/src/tools/miri/tests/fail/panic/panic_abort3.stderr b/src/tools/miri/tests/fail/panic/panic_abort3.stderr index cac24ca41c71..71877122b625 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort3.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort3.stderr @@ -9,15 +9,14 @@ error: abnormal termination: the program aborted execution LL | crate::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: BACKTRACE: - = note: inside `std::rt::__rust_abort` at RUSTLIB/std/src/rt.rs:LL:CC - = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC - = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC - = note: inside `std::panicking::panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC -note: inside `main` + = note: this is inside `std::rt::__rust_abort` + = note: which got called inside `panic_abort::__rust_start_panic` (at RUSTLIB/panic_abort/src/lib.rs:LL:CC) + = note: which got called inside `std::panicking::rust_panic` (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `std::panicking::panic_with_hook` (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside closure (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` (at RUSTLIB/std/src/sys/backtrace.rs:LL:CC) + = note: which got called inside `std::panicking::panic_handler` (at RUSTLIB/std/src/panicking.rs:LL:CC) +note: which got called inside `main` --> tests/fail/panic/panic_abort3.rs:LL:CC | LL | core::panic!("panicking from libcore"); diff --git a/src/tools/miri/tests/fail/panic/panic_abort4.stderr b/src/tools/miri/tests/fail/panic/panic_abort4.stderr index 21195729ae82..2b4c6bea5605 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort4.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort4.stderr @@ -9,15 +9,14 @@ error: abnormal termination: the program aborted execution LL | crate::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: BACKTRACE: - = note: inside `std::rt::__rust_abort` at RUSTLIB/std/src/rt.rs:LL:CC - = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC - = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC - = note: inside `std::panicking::panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC -note: inside `main` + = note: this is inside `std::rt::__rust_abort` + = note: which got called inside `panic_abort::__rust_start_panic` (at RUSTLIB/panic_abort/src/lib.rs:LL:CC) + = note: which got called inside `std::panicking::rust_panic` (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `std::panicking::panic_with_hook` (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside closure (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` (at RUSTLIB/std/src/sys/backtrace.rs:LL:CC) + = note: which got called inside `std::panicking::panic_handler` (at RUSTLIB/std/src/panicking.rs:LL:CC) +note: which got called inside `main` --> tests/fail/panic/panic_abort4.rs:LL:CC | LL | core::panic!("{}-panicking from libcore", 42); diff --git a/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr b/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr index 013c39a22462..6af86ffdb2bd 100644 --- a/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr +++ b/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr @@ -6,9 +6,8 @@ LL | let _val = *left_ptr; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `deref` at tests/fail/provenance/provenance_transmute.rs:LL:CC -note: inside `main` + = note: this is inside `deref` +note: which got called inside `main` --> tests/fail/provenance/provenance_transmute.rs:LL:CC | LL | deref(ptr1, ptr2.with_addr(ptr1.addr())); diff --git a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr index c5f6e62b8690..7fc54636b552 100644 --- a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr +++ b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr @@ -12,12 +12,11 @@ error: abnormal termination: the program aborted execution LL | crate::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: BACKTRACE: - = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC - = note: inside `std::panicking::panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC -note: inside `main` + = note: this is inside `std::panicking::panic_with_hook` + = note: which got called inside closure (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` (at RUSTLIB/std/src/sys/backtrace.rs:LL:CC) + = note: which got called inside `std::panicking::panic_handler` (at RUSTLIB/std/src/panicking.rs:LL:CC) +note: which got called inside `main` --> tests/fail/ptr_swap_nonoverlapping.rs:LL:CC | LL | std::ptr::swap_nonoverlapping(ptr, ptr, 1); diff --git a/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr b/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr index f08909d44276..eb7f70a351ad 100644 --- a/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr +++ b/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr @@ -6,19 +6,18 @@ LL | let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode a | = help: set `MIRIFLAGS=-Zmiri-disable-isolation` to disable isolation; = help: or set `MIRIFLAGS=-Zmiri-isolation-error=warn` to make Miri return an error code from isolated operations (if supported for that operation) and continue with a warning - = note: BACKTRACE: - = note: inside closure at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC - = note: inside `std::sys::pal::PLATFORM::cvt_r::` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC - = note: inside `std::sys::fs::PLATFORM::File::open_c` at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC - = note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr_stack::` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC - = note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr::` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC - = note: inside `std::sys::pal::PLATFORM::small_c_string::run_path_with_cstr::` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC - = note: inside `std::sys::fs::PLATFORM::File::open` at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC - = note: inside `std::fs::OpenOptions::_open` at RUSTLIB/std/src/fs.rs:LL:CC - = note: inside `std::fs::OpenOptions::open::<&std::path::Path>` at RUSTLIB/std/src/fs.rs:LL:CC - = note: inside `std::fs::File::open::<&str>` at RUSTLIB/std/src/fs.rs:LL:CC -note: inside `main` + = note: this is inside closure + = note: which got called inside `std::sys::pal::PLATFORM::cvt_r::` (at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC) + = note: which got called inside `std::sys::fs::PLATFORM::File::open_c` (at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC) + = note: which got called inside closure (at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC) + = note: which got called inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr_stack::` (at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC) + = note: which got called inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr::` (at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC) + = note: which got called inside `std::sys::pal::PLATFORM::small_c_string::run_path_with_cstr::` (at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC) + = note: which got called inside `std::sys::fs::PLATFORM::File::open` (at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC) + = note: which got called inside `std::fs::OpenOptions::_open` (at RUSTLIB/std/src/fs.rs:LL:CC) + = note: which got called inside `std::fs::OpenOptions::open::<&std::path::Path>` (at RUSTLIB/std/src/fs.rs:LL:CC) + = note: which got called inside `std::fs::File::open::<&str>` (at RUSTLIB/std/src/fs.rs:LL:CC) +note: which got called inside `main` --> tests/fail/shims/fs/isolated_file.rs:LL:CC | LL | let _file = std::fs::File::open("file.txt").unwrap(); diff --git a/src/tools/miri/tests/fail/shims/isolated_stdin.stderr b/src/tools/miri/tests/fail/shims/isolated_stdin.stderr index 5fda90b46ef6..58f0957a668c 100644 --- a/src/tools/miri/tests/fail/shims/isolated_stdin.stderr +++ b/src/tools/miri/tests/fail/shims/isolated_stdin.stderr @@ -5,7 +5,7 @@ error: unsupported operation: `read` from stdin not available when isolation is | = help: set `MIRIFLAGS=-Zmiri-disable-isolation` to disable isolation; = help: or set `MIRIFLAGS=-Zmiri-isolation-error=warn` to make Miri return an error code from isolated operations (if supported for that operation) and continue with a warning -note: inside `main` +note: which got called inside `main` --> tests/fail/shims/isolated_stdin.rs:LL:CC | | ^ diff --git a/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector1.stderr b/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector1.stderr index 8d18e5a7d605..84051e688aab 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector1.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector1.stderr @@ -6,22 +6,21 @@ LL | self.1.deallocate(From::from(ptr.cast()), layout); | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - = note: BACKTRACE: - = note: inside ` as std::ops::Drop>::drop` at RUSTLIB/alloc/src/boxed.rs:LL:CC - = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC - = note: inside `std::mem::drop::>` at RUSTLIB/core/src/mem/mod.rs:LL:CC -note: inside closure + = note: this is inside ` as std::ops::Drop>::drop` + = note: which got called inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` (at RUSTLIB/core/src/ptr/mod.rs:LL:CC) + = note: which got called inside `std::mem::drop::>` (at RUSTLIB/core/src/mem/mod.rs:LL:CC) +note: which got called inside closure --> tests/fail/stacked_borrows/deallocate_against_protector1.rs:LL:CC | LL | drop(unsafe { Box::from_raw(raw) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: inside `<{closure@tests/fail/stacked_borrows/deallocate_against_protector1.rs:LL:CC} as std::ops::FnOnce<(&mut i32,)>>::call_once - shim` at RUSTLIB/core/src/ops/function.rs:LL:CC -note: inside `inner` + = note: which got called inside `<{closure@tests/fail/stacked_borrows/deallocate_against_protector1.rs:LL:CC} as std::ops::FnOnce<(&mut i32,)>>::call_once - shim` (at RUSTLIB/core/src/ops/function.rs:LL:CC) +note: which got called inside `inner` --> tests/fail/stacked_borrows/deallocate_against_protector1.rs:LL:CC | LL | f(x) | ^^^^ -note: inside `main` +note: which got called inside `main` --> tests/fail/stacked_borrows/deallocate_against_protector1.rs:LL:CC | LL | / inner(Box::leak(Box::new(0)), |x| { diff --git a/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_protector.stderr b/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_protector.stderr index 464c44802ec3..7f4899bb0d6f 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_protector.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_protector.stderr @@ -16,11 +16,14 @@ help: is this argument | LL | core::ptr::drop_in_place(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `::drop` at tests/fail/stacked_borrows/drop_in_place_protector.rs:LL:CC - = note: inside `std::ptr::drop_in_place:: - shim(Some(HasDrop))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC - = note: inside `std::ptr::drop_in_place::<(HasDrop, u8)> - shim(Some((HasDrop, u8)))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC -note: inside `main` +note: error occurred inside `::drop` + --> tests/fail/stacked_borrows/drop_in_place_protector.rs:LL:CC + | +LL | fn drop(&mut self) { + | ^^^^^^^^^^^^^^^^^^ + = note: which got called inside `std::ptr::drop_in_place:: - shim(Some(HasDrop))` (at RUSTLIB/core/src/ptr/mod.rs:LL:CC) + = note: which got called inside `std::ptr::drop_in_place::<(HasDrop, u8)> - shim(Some((HasDrop, u8)))` (at RUSTLIB/core/src/ptr/mod.rs:LL:CC) +note: which got called inside `main` --> tests/fail/stacked_borrows/drop_in_place_protector.rs:LL:CC | LL | core::ptr::drop_in_place(x); diff --git a/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.stderr b/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.stderr index e586d3f03994..11b3e49b852e 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.stderr @@ -13,9 +13,14 @@ help: was created by a SharedReadOnly retag at offsets [0x0..0x1] | LL | let x = core::ptr::addr_of!(x); | ^^^^^^^^^^^^^^^^^^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `std::ptr::drop_in_place:: - shim(None)` at RUSTLIB/core/src/ptr/mod.rs:LL:CC -note: inside `main` +note: error occurred inside `std::ptr::drop_in_place:: - shim(None)` + --> RUSTLIB/core/src/ptr/mod.rs:LL:CC + | +LL | / pub const unsafe fn drop_in_place(to_drop: *mut T) +LL | | where +LL | | T: [const] Destruct, + | |________________________^ +note: which got called inside `main` --> tests/fail/stacked_borrows/drop_in_place_retag.rs:LL:CC | LL | core::ptr::drop_in_place(x.cast_mut()); diff --git a/src/tools/miri/tests/fail/stacked_borrows/invalidate_against_protector1.stderr b/src/tools/miri/tests/fail/stacked_borrows/invalidate_against_protector1.stderr index b082abe7b25b..17abcf0a4643 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/invalidate_against_protector1.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/invalidate_against_protector1.stderr @@ -16,9 +16,12 @@ help: is this argument | LL | fn inner(x: *mut i32, _y: &mut i32) { | ^^ - = note: BACKTRACE (of the first span): - = note: inside `inner` at tests/fail/stacked_borrows/invalidate_against_protector1.rs:LL:CC -note: inside `main` +note: error occurred inside `inner` + --> tests/fail/stacked_borrows/invalidate_against_protector1.rs:LL:CC + | +LL | fn inner(x: *mut i32, _y: &mut i32) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/stacked_borrows/invalidate_against_protector1.rs:LL:CC | LL | inner(xraw, xref); diff --git a/src/tools/miri/tests/fail/stacked_borrows/pointer_smuggling.stderr b/src/tools/miri/tests/fail/stacked_borrows/pointer_smuggling.stderr index b07599a500ee..a13ff30deda7 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/pointer_smuggling.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/pointer_smuggling.stderr @@ -16,9 +16,12 @@ help: was later invalidated at offsets [0x0..0x1] by a write access | LL | *val = 2; // this invalidates any raw ptrs `fun1` might have created. | ^^^^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `fun2` at tests/fail/stacked_borrows/pointer_smuggling.rs:LL:CC -note: inside `main` +note: error occurred inside `fun2` + --> tests/fail/stacked_borrows/pointer_smuggling.rs:LL:CC + | +LL | fn fun2() { + | ^^^^^^^^^ +note: which got called inside `main` --> tests/fail/stacked_borrows/pointer_smuggling.rs:LL:CC | LL | fun2(); // if they now use a raw ptr they break our reference diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr index 5b8f77600cd2..c8662628c033 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr @@ -14,6 +14,7 @@ LL | unsafe { ptr.0.read() }; = help: therefore from the perspective of data races, a retag has the same implications as a read or write = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr index ee82bbbb1ed1..3a95e13f5bc0 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr @@ -14,9 +14,12 @@ LL | let _r = &*p; = help: therefore from the perspective of data races, a retag has the same implications as a read or write = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside `thread_2` at tests/fail/stacked_borrows/retag_data_race_read.rs:LL:CC -note: inside closure +note: error occurred on thread `unnamed-ID`, inside `thread_2` + --> tests/fail/stacked_borrows/retag_data_race_read.rs:LL:CC + | +LL | fn thread_2(p: SendPtr) { + | ^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside closure --> tests/fail/stacked_borrows/retag_data_race_read.rs:LL:CC | LL | let t2 = std::thread::spawn(move || thread_2(p)); diff --git a/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut.stderr b/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut.stderr index 4ac82192a9fb..9148f5ae817c 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut.stderr @@ -16,9 +16,12 @@ help: was later invalidated at offsets [0x0..0x8] by a read access | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `foo` at tests/fail/stacked_borrows/return_invalid_mut.rs:LL:CC -note: inside `main` +note: error occurred inside `foo` + --> tests/fail/stacked_borrows/return_invalid_mut.rs:LL:CC + | +LL | fn foo(x: &mut (i32, i32)) -> &mut i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/stacked_borrows/return_invalid_mut.rs:LL:CC | LL | foo(&mut (1, 2)); diff --git a/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_option.stderr b/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_option.stderr index 7e7670e49f17..6cce7f9f246e 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_option.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_option.stderr @@ -19,9 +19,12 @@ help: was later invalidated at offsets [0x0..0x8] by a read access | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `foo` at tests/fail/stacked_borrows/return_invalid_mut_option.rs:LL:CC -note: inside `main` +note: error occurred inside `foo` + --> tests/fail/stacked_borrows/return_invalid_mut_option.rs:LL:CC + | +LL | fn foo(x: &mut (i32, i32)) -> Option<&mut i32> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/stacked_borrows/return_invalid_mut_option.rs:LL:CC | LL | match foo(&mut (1, 2)) { diff --git a/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr b/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr index aeaa694d2923..37d18f122b68 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr @@ -19,9 +19,12 @@ help: was later invalidated at offsets [0x0..0x8] by a read access | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `foo` at tests/fail/stacked_borrows/return_invalid_mut_tuple.rs:LL:CC -note: inside `main` +note: error occurred inside `foo` + --> tests/fail/stacked_borrows/return_invalid_mut_tuple.rs:LL:CC + | +LL | fn foo(x: &mut (i32, i32)) -> (&mut i32,) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/stacked_borrows/return_invalid_mut_tuple.rs:LL:CC | LL | foo(&mut (1, 2)).0; diff --git a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr index 61a57a64116b..00dd2999f540 100644 --- a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr +++ b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr @@ -6,20 +6,19 @@ LL | extern "rust-call" fn call_once(self, args: Args) -> Self::Output; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `>::call_once - shim(fn())` at RUSTLIB/core/src/ops/function.rs:LL:CC - = note: inside `std::sys::backtrace::__rust_begin_short_backtrace::` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC - = note: inside `std::ops::function::impls:: for &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>::call_once` at RUSTLIB/core/src/ops/function.rs:LL:CC - = note: inside `std::panicking::catch_unwind::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::panicking::catch_unwind:: i32 + std::marker::Sync + std::panic::RefUnwindSafe>` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at RUSTLIB/std/src/panic.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC - = note: inside `std::panicking::catch_unwind::do_call::<{closure@std::rt::lang_start_internal::{closure#0}}, isize>` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::panicking::catch_unwind::` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::panic::catch_unwind::<{closure@std::rt::lang_start_internal::{closure#0}}, isize>` at RUSTLIB/std/src/panic.rs:LL:CC - = note: inside `std::rt::lang_start_internal` at RUSTLIB/std/src/rt.rs:LL:CC - = note: inside `std::rt::lang_start::<()>` at RUSTLIB/std/src/rt.rs:LL:CC + = note: this is inside `>::call_once - shim(fn())` + = note: which got called inside `std::sys::backtrace::__rust_begin_short_backtrace::` (at RUSTLIB/std/src/sys/backtrace.rs:LL:CC) + = note: which got called inside closure (at RUSTLIB/std/src/rt.rs:LL:CC) + = note: which got called inside `std::ops::function::impls:: for &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>::call_once` (at RUSTLIB/core/src/ops/function.rs:LL:CC) + = note: which got called inside `std::panicking::catch_unwind::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `std::panicking::catch_unwind:: i32 + std::marker::Sync + std::panic::RefUnwindSafe>` (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` (at RUSTLIB/std/src/panic.rs:LL:CC) + = note: which got called inside closure (at RUSTLIB/std/src/rt.rs:LL:CC) + = note: which got called inside `std::panicking::catch_unwind::do_call::<{closure@std::rt::lang_start_internal::{closure#0}}, isize>` (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `std::panicking::catch_unwind::` (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `std::panic::catch_unwind::<{closure@std::rt::lang_start_internal::{closure#0}}, isize>` (at RUSTLIB/std/src/panic.rs:LL:CC) + = note: which got called inside `std::rt::lang_start_internal` (at RUSTLIB/std/src/rt.rs:LL:CC) + = note: which got called inside `std::rt::lang_start::<()>` (at RUSTLIB/std/src/rt.rs:LL:CC) error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr index 965dd5b399f7..a48673fb4b23 100644 --- a/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr +++ b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr @@ -16,9 +16,12 @@ help: ALLOC was deallocated here: | LL | f(std::ptr::null()); | ^^^^^^^^^^^^^^^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `g` at tests/fail/tail_calls/dangling-local-var.rs:LL:CC -note: inside `main` +note: error occurred inside `g` + --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC + | +LL | fn g(x: *const i32) { + | ^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC | LL | f(std::ptr::null()); diff --git a/src/tools/miri/tests/fail/terminate-terminator.stderr b/src/tools/miri/tests/fail/terminate-terminator.stderr index 8ae649a392bd..7d8ae128b5d6 100644 --- a/src/tools/miri/tests/fail/terminate-terminator.stderr +++ b/src/tools/miri/tests/fail/terminate-terminator.stderr @@ -16,14 +16,13 @@ error: abnormal termination: the program aborted execution LL | crate::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: BACKTRACE: - = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC - = note: inside `std::panicking::panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC - = note: inside `core::panicking::panic_cannot_unwind` at RUSTLIB/core/src/panicking.rs:LL:CC -note: inside `has_cleanup` + = note: this is inside `std::panicking::panic_with_hook` + = note: which got called inside closure (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` (at RUSTLIB/std/src/sys/backtrace.rs:LL:CC) + = note: which got called inside `std::panicking::panic_handler` (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `core::panicking::panic_nounwind` (at RUSTLIB/core/src/panicking.rs:LL:CC) + = note: which got called inside `core::panicking::panic_cannot_unwind` (at RUSTLIB/core/src/panicking.rs:LL:CC) +note: which got called inside `has_cleanup` --> tests/fail/terminate-terminator.rs:LL:CC | LL | / fn has_cleanup() { @@ -31,12 +30,12 @@ LL | | let _f = Foo; LL | | panic!(); LL | | } | |_^ -note: inside `panic_abort` +note: which got called inside `panic_abort` --> tests/fail/terminate-terminator.rs:LL:CC | LL | has_cleanup(); | ^^^^^^^^^^^^^ -note: inside `main` +note: which got called inside `main` --> tests/fail/terminate-terminator.rs:LL:CC | LL | panic_abort(); diff --git a/src/tools/miri/tests/fail/tls/tls_static_dealloc.stderr b/src/tools/miri/tests/fail/tls/tls_static_dealloc.stderr index db113b6cf457..efc4bead418e 100644 --- a/src/tools/miri/tests/fail/tls/tls_static_dealloc.stderr +++ b/src/tools/miri/tests/fail/tls/tls_static_dealloc.stderr @@ -6,6 +6,7 @@ LL | let _val = *dangling_ptr.0; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `main` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tls_macro_leak.stderr b/src/tools/miri/tests/fail/tls_macro_leak.stderr index 512932b3cb8a..c3029bb5b4de 100644 --- a/src/tools/miri/tests/fail/tls_macro_leak.stderr +++ b/src/tools/miri/tests/fail/tls_macro_leak.stderr @@ -4,11 +4,10 @@ error: memory leaked: ALLOC (Rust heap, size: 4, align: 4), allocated here: LL | cell.set(Some(Box::leak(Box::new(123)))); | ^^^^^^^^^^^^^ | - = note: BACKTRACE: - = note: inside closure at tests/fail/tls_macro_leak.rs:LL:CC - = note: inside `std::thread::LocalKey::>>::try_with::<{closure@tests/fail/tls_macro_leak.rs:LL:CC}, ()>` at RUSTLIB/std/src/thread/local.rs:LL:CC - = note: inside `std::thread::LocalKey::>>::with::<{closure@tests/fail/tls_macro_leak.rs:LL:CC}, ()>` at RUSTLIB/std/src/thread/local.rs:LL:CC -note: inside closure + = note: this is inside closure + = note: which got called inside `std::thread::LocalKey::>>::try_with::<{closure@tests/fail/tls_macro_leak.rs:LL:CC}, ()>` (at RUSTLIB/std/src/thread/local.rs:LL:CC) + = note: which got called inside `std::thread::LocalKey::>>::with::<{closure@tests/fail/tls_macro_leak.rs:LL:CC}, ()>` (at RUSTLIB/std/src/thread/local.rs:LL:CC) +note: which got called inside closure --> tests/fail/tls_macro_leak.rs:LL:CC | LL | / TLS.with(|cell| { diff --git a/src/tools/miri/tests/fail/tree_borrows/outside-range.stderr b/src/tools/miri/tests/fail/tree_borrows/outside-range.stderr index 7960f42faa51..e504f8dde717 100644 --- a/src/tools/miri/tests/fail/tree_borrows/outside-range.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/outside-range.stderr @@ -19,9 +19,12 @@ help: the protected tag was created here, in the initial state Reserved | LL | unsafe fn stuff(x: &mut u8, y: *mut u8) { | ^ - = note: BACKTRACE (of the first span): - = note: inside `stuff` at tests/fail/tree_borrows/outside-range.rs:LL:CC -note: inside `main` +note: error occurred inside `stuff` + --> tests/fail/tree_borrows/outside-range.rs:LL:CC + | +LL | unsafe fn stuff(x: &mut u8, y: *mut u8) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/tree_borrows/outside-range.rs:LL:CC | LL | stuff(&mut *raw, raw); diff --git a/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr b/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr index 9a70d248aa0c..48527fedcc35 100644 --- a/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr @@ -30,9 +30,12 @@ help: the conflicting tag later transitioned to Frozen due to a foreign re LL | let _val = unsafe { *xraw }; // invalidate xref for writing | ^^^^^ = help: this transition corresponds to a loss of write permissions - = note: BACKTRACE (of the first span): - = note: inside `foo` at tests/fail/tree_borrows/pass_invalid_mut.rs:LL:CC -note: inside `main` +note: error occurred inside `foo` + --> tests/fail/tree_borrows/pass_invalid_mut.rs:LL:CC + | +LL | fn foo(nope: &mut i32) { + | ^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/tree_borrows/pass_invalid_mut.rs:LL:CC | LL | foo(xref); diff --git a/src/tools/miri/tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.stderr b/src/tools/miri/tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.stderr index 012d7caef501..40a3989c2dc4 100644 --- a/src/tools/miri/tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.stderr @@ -18,9 +18,12 @@ help: the accessed tag later transitioned to Reserved (conflicted) due to LL | do_something(*orig_ptr); | ^^^^^^^^^ = help: this transition corresponds to a temporary loss of write permissions until function exit - = note: BACKTRACE (of the first span): - = note: inside `access_after_sub_1` at tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.rs:LL:CC -note: inside `main` +note: error occurred inside `access_after_sub_1` + --> tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.rs:LL:CC + | +LL | unsafe fn access_after_sub_1(x: &mut u8, orig_ptr: *mut u8) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.rs:LL:CC | LL | access_after_sub_1(&mut *(foo as *mut u8).byte_add(1), orig_ptr); diff --git a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr index b1c3ffe86ef7..8effbe30dd6a 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr @@ -29,9 +29,12 @@ help: the protected tag was created here, in the initial state Reserved | LL | unsafe fn write_second(x: &mut UnsafeCell, y: *mut u8) { | ^ - = note: BACKTRACE (of the first span): - = note: inside `main::write_second` at tests/fail/tree_borrows/reserved/cell-protected-write.rs:LL:CC -note: inside `main` +note: error occurred inside `main::write_second` + --> tests/fail/tree_borrows/reserved/cell-protected-write.rs:LL:CC + | +LL | unsafe fn write_second(x: &mut UnsafeCell, y: *mut u8) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/tree_borrows/reserved/cell-protected-write.rs:LL:CC | LL | write_second(x, y); diff --git a/src/tools/miri/tests/fail/tree_borrows/reserved/int-protected-write.stderr b/src/tools/miri/tests/fail/tree_borrows/reserved/int-protected-write.stderr index 5f3129b9dc08..1bc337eb1e7a 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reserved/int-protected-write.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/reserved/int-protected-write.stderr @@ -29,9 +29,12 @@ help: the protected tag was created here, in the initial state Reserved | LL | unsafe fn write_second(x: &mut u8, y: *mut u8) { | ^ - = note: BACKTRACE (of the first span): - = note: inside `main::write_second` at tests/fail/tree_borrows/reserved/int-protected-write.rs:LL:CC -note: inside `main` +note: error occurred inside `main::write_second` + --> tests/fail/tree_borrows/reserved/int-protected-write.rs:LL:CC + | +LL | unsafe fn write_second(x: &mut u8, y: *mut u8) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/tree_borrows/reserved/int-protected-write.rs:LL:CC | LL | write_second(x, y); diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr index 15365e5c8bcc..c5a0b58c2185 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr @@ -32,6 +32,7 @@ help: the accessed tag later transitioned to Disabled due to a foreign wri LL | *x = 64; | ^^^^^^^ = help: this transition corresponds to a loss of read and write permissions + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr index 4065c822866c..75c11f09ce52 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr @@ -32,6 +32,7 @@ help: the accessed tag later transitioned to Disabled due to a protector r LL | } | ^ = help: this transition corresponds to a loss of read and write permissions + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/spurious_read.stderr b/src/tools/miri/tests/fail/tree_borrows/spurious_read.stderr index 8f2534d6b6e9..eef8766fd652 100644 --- a/src/tools/miri/tests/fail/tree_borrows/spurious_read.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/spurious_read.stderr @@ -31,9 +31,12 @@ help: the accessed tag later transitioned to Reserved (conflicted) due to LL | } | ^ = help: this transition corresponds to a temporary loss of write permissions until function exit - = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside `retagx_retagy_retx_writey_rety::{closure#1}::as_mut` at tests/fail/tree_borrows/spurious_read.rs:LL:CC -note: inside closure +note: error occurred on thread `unnamed-ID`, inside `retagx_retagy_retx_writey_rety::{closure#1}::as_mut` + --> tests/fail/tree_borrows/spurious_read.rs:LL:CC + | +LL | fn as_mut(y: &mut u8, b: (usize, Arc)) -> *mut u8 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside closure --> tests/fail/tree_borrows/spurious_read.rs:LL:CC | LL | let _y = as_mut(unsafe { &mut *ptr.0 }, b.clone()); diff --git a/src/tools/miri/tests/fail/tree_borrows/strongly-protected.stderr b/src/tools/miri/tests/fail/tree_borrows/strongly-protected.stderr index 685abee3292f..9545ebf39a27 100644 --- a/src/tools/miri/tests/fail/tree_borrows/strongly-protected.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/strongly-protected.stderr @@ -18,22 +18,25 @@ help: the strongly protected tag was created here, in the initial state Re | LL | fn inner(x: &mut i32, f: fn(*mut i32)) { | ^ - = note: BACKTRACE (of the first span): - = note: inside ` as std::ops::Drop>::drop` at RUSTLIB/alloc/src/boxed.rs:LL:CC - = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC - = note: inside `std::mem::drop::>` at RUSTLIB/core/src/mem/mod.rs:LL:CC -note: inside closure +note: error occurred inside ` as std::ops::Drop>::drop` + --> RUSTLIB/alloc/src/boxed.rs:LL:CC + | +LL | fn drop(&mut self) { + | ^^^^^^^^^^^^^^^^^^ + = note: which got called inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` (at RUSTLIB/core/src/ptr/mod.rs:LL:CC) + = note: which got called inside `std::mem::drop::>` (at RUSTLIB/core/src/mem/mod.rs:LL:CC) +note: which got called inside closure --> tests/fail/tree_borrows/strongly-protected.rs:LL:CC | LL | drop(unsafe { Box::from_raw(raw) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: inside `<{closure@tests/fail/tree_borrows/strongly-protected.rs:LL:CC} as std::ops::FnOnce<(*mut i32,)>>::call_once - shim` at RUSTLIB/core/src/ops/function.rs:LL:CC -note: inside `inner` + = note: which got called inside `<{closure@tests/fail/tree_borrows/strongly-protected.rs:LL:CC} as std::ops::FnOnce<(*mut i32,)>>::call_once - shim` (at RUSTLIB/core/src/ops/function.rs:LL:CC) +note: which got called inside `inner` --> tests/fail/tree_borrows/strongly-protected.rs:LL:CC | LL | f(x) | ^^^^ -note: inside `main` +note: which got called inside `main` --> tests/fail/tree_borrows/strongly-protected.rs:LL:CC | LL | / inner(Box::leak(Box::new(0)), |raw| { diff --git a/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.stderr b/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.stderr index b98d2fafcf4e..3db6dab3167b 100644 --- a/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.stderr @@ -18,9 +18,12 @@ help: the conflicting tag was created here, in the initial state Frozen | LL | let intermediary = &root; | ^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `write_to_mut` at tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs:LL:CC -note: inside `main` +note: error occurred inside `write_to_mut` + --> tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs:LL:CC + | +LL | fn write_to_mut(m: &mut u8, other_ptr: *const u8) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs:LL:CC | LL | write_to_mut(data, core::ptr::addr_of!(root)); diff --git a/src/tools/miri/tests/fail/tree_borrows/wildcard/protected_wildcard.stderr b/src/tools/miri/tests/fail/tree_borrows/wildcard/protected_wildcard.stderr index e257a3511f75..d61fe47a871b 100644 --- a/src/tools/miri/tests/fail/tree_borrows/wildcard/protected_wildcard.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/protected_wildcard.stderr @@ -23,9 +23,12 @@ help: the protected tag was created here, in the initial state Reserved | LL | let mut protect = |_arg: &mut u32| { | ^^^^ - = note: BACKTRACE (of the first span): - = note: inside closure at tests/fail/tree_borrows/wildcard/protected_wildcard.rs:LL:CC -note: inside `main` +note: error occurred inside closure + --> tests/fail/tree_borrows/wildcard/protected_wildcard.rs:LL:CC + | +LL | let mut protect = |_arg: &mut u32| { + | ^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/tree_borrows/wildcard/protected_wildcard.rs:LL:CC | LL | protect(wild_ref); diff --git a/src/tools/miri/tests/fail/tree_borrows/wildcard/protector_conflicted.stderr b/src/tools/miri/tests/fail/tree_borrows/wildcard/protector_conflicted.stderr index 5486eee4f063..cd797cdc0c79 100644 --- a/src/tools/miri/tests/fail/tree_borrows/wildcard/protector_conflicted.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/protector_conflicted.stderr @@ -7,9 +7,8 @@ LL | unsafe { *wild = 4 }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: there are no exposed tags which may perform this access here - = note: BACKTRACE: - = note: inside closure at tests/fail/tree_borrows/wildcard/protector_conflicted.rs:LL:CC -note: inside `main` + = note: this is inside closure +note: which got called inside `main` --> tests/fail/tree_borrows/wildcard/protector_conflicted.rs:LL:CC | LL | protect(ref1); diff --git a/src/tools/miri/tests/fail/tree_borrows/wildcard/strongly_protected_wildcard.stderr b/src/tools/miri/tests/fail/tree_borrows/wildcard/strongly_protected_wildcard.stderr index 6e115b22feb1..bcc6b5f5b879 100644 --- a/src/tools/miri/tests/fail/tree_borrows/wildcard/strongly_protected_wildcard.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/strongly_protected_wildcard.stderr @@ -18,22 +18,25 @@ help: the strongly protected tag was created here, in the initial state Re | LL | fn inner(x: &mut i32, f: fn(usize)) { | ^ - = note: BACKTRACE (of the first span): - = note: inside ` as std::ops::Drop>::drop` at RUSTLIB/alloc/src/boxed.rs:LL:CC - = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC - = note: inside `std::mem::drop::>` at RUSTLIB/core/src/mem/mod.rs:LL:CC -note: inside closure +note: error occurred inside ` as std::ops::Drop>::drop` + --> RUSTLIB/alloc/src/boxed.rs:LL:CC + | +LL | fn drop(&mut self) { + | ^^^^^^^^^^^^^^^^^^ + = note: which got called inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` (at RUSTLIB/core/src/ptr/mod.rs:LL:CC) + = note: which got called inside `std::mem::drop::>` (at RUSTLIB/core/src/mem/mod.rs:LL:CC) +note: which got called inside closure --> tests/fail/tree_borrows/wildcard/strongly_protected_wildcard.rs:LL:CC | LL | drop(unsafe { Box::from_raw(raw as *mut i32) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: inside `<{closure@tests/fail/tree_borrows/wildcard/strongly_protected_wildcard.rs:LL:CC} as std::ops::FnOnce<(usize,)>>::call_once - shim` at RUSTLIB/core/src/ops/function.rs:LL:CC -note: inside `inner` + = note: which got called inside `<{closure@tests/fail/tree_borrows/wildcard/strongly_protected_wildcard.rs:LL:CC} as std::ops::FnOnce<(usize,)>>::call_once - shim` (at RUSTLIB/core/src/ops/function.rs:LL:CC) +note: which got called inside `inner` --> tests/fail/tree_borrows/wildcard/strongly_protected_wildcard.rs:LL:CC | LL | f(x as *mut i32 as usize) | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: inside `main` +note: which got called inside `main` --> tests/fail/tree_borrows/wildcard/strongly_protected_wildcard.rs:LL:CC | LL | / inner(Box::leak(Box::new(0)), |raw| { diff --git a/src/tools/miri/tests/fail/tree_borrows/write-during-2phase.stderr b/src/tools/miri/tests/fail/tree_borrows/write-during-2phase.stderr index 7f55e06a6bb7..11d148bc872e 100644 --- a/src/tools/miri/tests/fail/tree_borrows/write-during-2phase.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/write-during-2phase.stderr @@ -18,9 +18,12 @@ help: the accessed tag later transitioned to Disabled due to a foreign wri LL | *alias = 42; | ^^^^^^^^^^^ = help: this transition corresponds to a loss of read and write permissions - = note: BACKTRACE (of the first span): - = note: inside `Foo::add` at tests/fail/tree_borrows/write-during-2phase.rs:LL:CC -note: inside `main` +note: error occurred inside `Foo::add` + --> tests/fail/tree_borrows/write-during-2phase.rs:LL:CC + | +LL | fn add(&mut self, n: u64) -> u64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside `main` --> tests/fail/tree_borrows/write-during-2phase.rs:LL:CC | LL | let res = f.add(unsafe { diff --git a/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr b/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr index ea144f206643..6fb62b766440 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr @@ -8,9 +8,8 @@ LL | | T: [const] Destruct, | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `std::ptr::drop_in_place:: - shim(Some(PartialDrop))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC -note: inside `main` + = note: this is inside `std::ptr::drop_in_place:: - shim(Some(PartialDrop))` +note: which got called inside `main` --> tests/fail/unaligned_pointers/drop_in_place.rs:LL:CC | LL | core::ptr::drop_in_place(p); diff --git a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.stderr b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.stderr index d2a5f83a43da..61915490917e 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.stderr @@ -6,9 +6,8 @@ LL | unsafe { (*x).x } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `foo` at tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.rs:LL:CC -note: inside `main` + = note: this is inside `foo` +note: which got called inside `main` --> tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.rs:LL:CC | LL | foo(odd_ptr.cast()); diff --git a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.stderr b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.stderr index 39540fc8320d..58db5dda6a2e 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.stderr @@ -6,9 +6,8 @@ LL | unsafe { (*x).packed.x } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `foo` at tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.rs:LL:CC -note: inside `main` + = note: this is inside `foo` +note: which got called inside `main` --> tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.rs:LL:CC | LL | foo(odd_ptr.cast()); diff --git a/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.stderr b/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.stderr index a91be376bd16..56a3bf129ab2 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.stderr @@ -6,9 +6,8 @@ LL | mem::transmute(x) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `raw_to_ref::<'_, i32>` at tests/fail/unaligned_pointers/reference_to_packed.rs:LL:CC -note: inside `main` + = note: this is inside `raw_to_ref::<'_, i32>` +note: which got called inside `main` --> tests/fail/unaligned_pointers/reference_to_packed.rs:LL:CC | LL | let p: &i32 = unsafe { raw_to_ref(ptr::addr_of!(foo.x)) }; diff --git a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.stderr b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.stderr index 25a9bddb42c7..6a2f038017c0 100644 --- a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.stderr +++ b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.stderr @@ -6,10 +6,9 @@ LL | let mut order = unsafe { compare_bytes(left, right, len) as isize } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `::compare` at RUSTLIB/core/src/slice/cmp.rs:LL:CC - = note: inside `core::slice::cmp::::cmp` at RUSTLIB/core/src/slice/cmp.rs:LL:CC -note: inside `main` + = note: this is inside `::compare` + = note: which got called inside `core::slice::cmp::::cmp` (at RUSTLIB/core/src/slice/cmp.rs:LL:CC) +note: which got called inside `main` --> tests/fail/uninit/uninit_alloc_diagnostic.rs:LL:CC | LL | drop(slice1.cmp(slice2)); diff --git a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr index 305d8d4fbede..f40e796cca61 100644 --- a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr +++ b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr @@ -6,10 +6,9 @@ LL | let mut order = unsafe { compare_bytes(left, right, len) as isize } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `::compare` at RUSTLIB/core/src/slice/cmp.rs:LL:CC - = note: inside `core::slice::cmp::::cmp` at RUSTLIB/core/src/slice/cmp.rs:LL:CC -note: inside `main` + = note: this is inside `::compare` + = note: which got called inside `core::slice::cmp::::cmp` (at RUSTLIB/core/src/slice/cmp.rs:LL:CC) +note: which got called inside `main` --> tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.rs:LL:CC | LL | drop(slice1.cmp(slice2)); diff --git a/src/tools/miri/tests/fail/unwind-action-terminate.stderr b/src/tools/miri/tests/fail/unwind-action-terminate.stderr index cf41c88ce377..c86d94a82025 100644 --- a/src/tools/miri/tests/fail/unwind-action-terminate.stderr +++ b/src/tools/miri/tests/fail/unwind-action-terminate.stderr @@ -14,21 +14,20 @@ error: abnormal termination: the program aborted execution LL | crate::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: BACKTRACE: - = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC - = note: inside `std::panicking::panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC - = note: inside `core::panicking::panic_cannot_unwind` at RUSTLIB/core/src/panicking.rs:LL:CC -note: inside `panic_abort` + = note: this is inside `std::panicking::panic_with_hook` + = note: which got called inside closure (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` (at RUSTLIB/std/src/sys/backtrace.rs:LL:CC) + = note: which got called inside `std::panicking::panic_handler` (at RUSTLIB/std/src/panicking.rs:LL:CC) + = note: which got called inside `core::panicking::panic_nounwind` (at RUSTLIB/core/src/panicking.rs:LL:CC) + = note: which got called inside `core::panicking::panic_cannot_unwind` (at RUSTLIB/core/src/panicking.rs:LL:CC) +note: which got called inside `panic_abort` --> tests/fail/unwind-action-terminate.rs:LL:CC | LL | / extern "C" fn panic_abort() { LL | | panic!() LL | | } | |_^ -note: inside `main` +note: which got called inside `main` --> tests/fail/unwind-action-terminate.rs:LL:CC | LL | panic_abort(); diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr index c370e19ef313..5c7572c76a13 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr @@ -6,9 +6,8 @@ LL | Call(_res = f(*ptr), ReturnTo(retblock), UnwindContinue()) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `call` at tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs:LL:CC -note: inside `main` + = note: this is inside `call` +note: which got called inside `main` --> tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs:LL:CC | LL | call(f); diff --git a/src/tools/miri/tests/fail/validity/invalid_char_cast.stderr b/src/tools/miri/tests/fail/validity/invalid_char_cast.stderr index c435e51d6be8..6612bcd22394 100644 --- a/src/tools/miri/tests/fail/validity/invalid_char_cast.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_char_cast.stderr @@ -6,9 +6,8 @@ LL | RET = *ptr as u32; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `cast` at tests/fail/validity/invalid_char_cast.rs:LL:CC -note: inside `main` + = note: this is inside `cast` +note: which got called inside `main` --> tests/fail/validity/invalid_char_cast.rs:LL:CC | LL | cast(&v as *const u32 as *const char); diff --git a/src/tools/miri/tests/fail/validity/invalid_char_match.stderr b/src/tools/miri/tests/fail/validity/invalid_char_match.stderr index 141305a00170..cda730172177 100644 --- a/src/tools/miri/tests/fail/validity/invalid_char_match.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_char_match.stderr @@ -9,9 +9,8 @@ LL | | } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `switch_int` at tests/fail/validity/invalid_char_match.rs:LL:CC -note: inside `main` + = note: this is inside `switch_int` +note: which got called inside `main` --> tests/fail/validity/invalid_char_match.rs:LL:CC | LL | switch_int(&v as *const u32 as *const char); diff --git a/src/tools/miri/tests/fail/validity/invalid_enum_cast.stderr b/src/tools/miri/tests/fail/validity/invalid_enum_cast.stderr index b2d876419034..6a4d0e0375af 100644 --- a/src/tools/miri/tests/fail/validity/invalid_enum_cast.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_enum_cast.stderr @@ -6,9 +6,8 @@ LL | let _val = *ptr as u32; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `cast` at tests/fail/validity/invalid_enum_cast.rs:LL:CC -note: inside `main` + = note: this is inside `cast` +note: which got called inside `main` --> tests/fail/validity/invalid_enum_cast.rs:LL:CC | LL | cast(&v as *const u32 as *const E); diff --git a/src/tools/miri/tests/fail/weak_memory/weak_uninit.stderr b/src/tools/miri/tests/fail/weak_memory/weak_uninit.stderr index 99e06e7febf5..605767db22b1 100644 --- a/src/tools/miri/tests/fail/weak_memory/weak_uninit.stderr +++ b/src/tools/miri/tests/fail/weak_memory/weak_uninit.stderr @@ -6,6 +6,7 @@ LL | let j2 = spawn(move || x.load(Ordering::Relaxed)); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/genmc/fail/atomics/atomic_ptr_double_free.stderr b/src/tools/miri/tests/genmc/fail/atomics/atomic_ptr_double_free.stderr index 7d03bd9a8eb8..333405a9172b 100644 --- a/src/tools/miri/tests/genmc/fail/atomics/atomic_ptr_double_free.stderr +++ b/src/tools/miri/tests/genmc/fail/atomics/atomic_ptr_double_free.stderr @@ -17,15 +17,18 @@ help: ALLOC was deallocated here: | LL | dealloc(ptr as *mut u8, Layout::new::()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside `free` at tests/genmc/fail/atomics/atomic_ptr_double_free.rs:LL:CC -note: inside closure +note: error occurred on thread `unnamed-ID`, inside `free` + --> tests/genmc/fail/atomics/atomic_ptr_double_free.rs:LL:CC + | +LL | unsafe fn free(ptr: *mut u64) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called inside closure --> tests/genmc/fail/atomics/atomic_ptr_double_free.rs:LL:CC | LL | free(b); | ^^^^^^^ - = note: inside ` as std::ops::FnOnce<()>>::call_once` at RUSTLIB/alloc/src/boxed.rs:LL:CC -note: inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/atomics/atomic_ptr_double_free.rs:LL:CC}>` + = note: which got called inside ` as std::ops::FnOnce<()>>::call_once` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) +note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/atomics/atomic_ptr_double_free.rs:LL:CC}>` --> tests/genmc/fail/atomics/../../../utils/genmc.rs:LL:CC | LL | f(); diff --git a/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_alloc_race.dealloc.stderr b/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_alloc_race.dealloc.stderr index bde793014bbf..6ec5843c3a0c 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_alloc_race.dealloc.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_alloc_race.dealloc.stderr @@ -7,10 +7,9 @@ LL | dealloc(b as *mut u8, Layout::new::()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE on thread `unnamed-ID`: - = note: inside closure at tests/genmc/fail/data_race/atomic_ptr_alloc_race.rs:LL:CC - = note: inside ` as std::ops::FnOnce<()>>::call_once` at RUSTLIB/alloc/src/boxed.rs:LL:CC -note: inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/atomic_ptr_alloc_race.rs:LL:CC}>` + = note: this is on thread `unnamed-ID`, inside closure + = note: which got called inside ` as std::ops::FnOnce<()>>::call_once` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) +note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/atomic_ptr_alloc_race.rs:LL:CC}>` --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC | LL | f(); diff --git a/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_alloc_race.write.stderr b/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_alloc_race.write.stderr index 7bfafe0ca086..fb29e326ba83 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_alloc_race.write.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_alloc_race.write.stderr @@ -7,10 +7,9 @@ LL | *b = 42; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE on thread `unnamed-ID`: - = note: inside closure at tests/genmc/fail/data_race/atomic_ptr_alloc_race.rs:LL:CC - = note: inside ` as std::ops::FnOnce<()>>::call_once` at RUSTLIB/alloc/src/boxed.rs:LL:CC -note: inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/atomic_ptr_alloc_race.rs:LL:CC}>` + = note: this is on thread `unnamed-ID`, inside closure + = note: which got called inside ` as std::ops::FnOnce<()>>::call_once` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) +note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/atomic_ptr_alloc_race.rs:LL:CC}>` --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC | LL | f(); diff --git a/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_dealloc_write_race.stderr b/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_dealloc_write_race.stderr index 0facf6a5d177..e4af214bfb99 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_dealloc_write_race.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_dealloc_write_race.stderr @@ -17,10 +17,13 @@ help: ALLOC was deallocated here: | LL | }), | ^ - = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at tests/genmc/fail/data_race/atomic_ptr_dealloc_write_race.rs:LL:CC - = note: inside ` as std::ops::FnOnce<()>>::call_once` at RUSTLIB/alloc/src/boxed.rs:LL:CC -note: inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/atomic_ptr_dealloc_write_race.rs:LL:CC}>` +note: error occurred on thread `unnamed-ID`, inside closure + --> tests/genmc/fail/data_race/atomic_ptr_dealloc_write_race.rs:LL:CC + | +LL | spawn_pthread_closure(|| { + | ^^ + = note: which got called inside ` as std::ops::FnOnce<()>>::call_once` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) +note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/atomic_ptr_dealloc_write_race.rs:LL:CC}>` --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC | LL | f(); diff --git a/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_write_dealloc_race.stderr b/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_write_dealloc_race.stderr index 8e4ed1aba043..f5986d50bafc 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_write_dealloc_race.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_write_dealloc_race.stderr @@ -7,10 +7,9 @@ LL | }), | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE on thread `unnamed-ID`: - = note: inside closure at tests/genmc/fail/data_race/atomic_ptr_write_dealloc_race.rs:LL:CC - = note: inside ` as std::ops::FnOnce<()>>::call_once` at RUSTLIB/alloc/src/boxed.rs:LL:CC -note: inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/atomic_ptr_write_dealloc_race.rs:LL:CC}>` + = note: this is on thread `unnamed-ID`, inside closure + = note: which got called inside ` as std::ops::FnOnce<()>>::call_once` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) +note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/atomic_ptr_write_dealloc_race.rs:LL:CC}>` --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC | LL | f(); diff --git a/src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.stderr b/src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.stderr index 1ffb55f22e6e..b061b9029b3d 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.stderr @@ -7,10 +7,9 @@ LL | X = 2; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE on thread `unnamed-ID`: - = note: inside closure at tests/genmc/fail/data_race/mpu2_rels_rlx.rs:LL:CC - = note: inside ` as std::ops::FnOnce<()>>::call_once` at RUSTLIB/alloc/src/boxed.rs:LL:CC -note: inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/mpu2_rels_rlx.rs:LL:CC}>` + = note: this is on thread `unnamed-ID`, inside closure + = note: which got called inside ` as std::ops::FnOnce<()>>::call_once` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) +note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/mpu2_rels_rlx.rs:LL:CC}>` --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC | LL | f(); diff --git a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rel_rlx.stderr b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rel_rlx.stderr index b0037c211c69..ad5047be60c1 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rel_rlx.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rel_rlx.stderr @@ -7,10 +7,9 @@ LL | X = 2; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE on thread `unnamed-ID`: - = note: inside closure at tests/genmc/fail/data_race/weak_orderings.rs:LL:CC - = note: inside ` as std::ops::FnOnce<()>>::call_once` at RUSTLIB/alloc/src/boxed.rs:LL:CC -note: inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/weak_orderings.rs:LL:CC}>` + = note: this is on thread `unnamed-ID`, inside closure + = note: which got called inside ` as std::ops::FnOnce<()>>::call_once` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) +note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/weak_orderings.rs:LL:CC}>` --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC | LL | f(); diff --git a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_acq.stderr b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_acq.stderr index b0037c211c69..ad5047be60c1 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_acq.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_acq.stderr @@ -7,10 +7,9 @@ LL | X = 2; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE on thread `unnamed-ID`: - = note: inside closure at tests/genmc/fail/data_race/weak_orderings.rs:LL:CC - = note: inside ` as std::ops::FnOnce<()>>::call_once` at RUSTLIB/alloc/src/boxed.rs:LL:CC -note: inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/weak_orderings.rs:LL:CC}>` + = note: this is on thread `unnamed-ID`, inside closure + = note: which got called inside ` as std::ops::FnOnce<()>>::call_once` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) +note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/weak_orderings.rs:LL:CC}>` --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC | LL | f(); diff --git a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_rlx.stderr b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_rlx.stderr index b0037c211c69..ad5047be60c1 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_rlx.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_rlx.stderr @@ -7,10 +7,9 @@ LL | X = 2; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE on thread `unnamed-ID`: - = note: inside closure at tests/genmc/fail/data_race/weak_orderings.rs:LL:CC - = note: inside ` as std::ops::FnOnce<()>>::call_once` at RUSTLIB/alloc/src/boxed.rs:LL:CC -note: inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/weak_orderings.rs:LL:CC}>` + = note: this is on thread `unnamed-ID`, inside closure + = note: which got called inside ` as std::ops::FnOnce<()>>::call_once` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) +note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/weak_orderings.rs:LL:CC}>` --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC | LL | f(); diff --git a/src/tools/miri/tests/genmc/fail/loom/buggy_inc.stderr b/src/tools/miri/tests/genmc/fail/loom/buggy_inc.stderr index ad98ba6aeb9a..abda3e31189e 100644 --- a/src/tools/miri/tests/genmc/fail/loom/buggy_inc.stderr +++ b/src/tools/miri/tests/genmc/fail/loom/buggy_inc.stderr @@ -4,6 +4,8 @@ error: abnormal termination: the program aborted execution | LL | std::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here + | + = note: this is on thread `main` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/genmc/fail/loom/store_buffering.genmc.stderr b/src/tools/miri/tests/genmc/fail/loom/store_buffering.genmc.stderr index 658914ba088d..176ab6a573c8 100644 --- a/src/tools/miri/tests/genmc/fail/loom/store_buffering.genmc.stderr +++ b/src/tools/miri/tests/genmc/fail/loom/store_buffering.genmc.stderr @@ -4,6 +4,8 @@ error: abnormal termination: the program aborted execution | LL | std::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here + | + = note: this is on thread `main` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/genmc/fail/loom/store_buffering.non_genmc.stderr b/src/tools/miri/tests/genmc/fail/loom/store_buffering.non_genmc.stderr index d2036d464bb5..487ab21f28b3 100644 --- a/src/tools/miri/tests/genmc/fail/loom/store_buffering.non_genmc.stderr +++ b/src/tools/miri/tests/genmc/fail/loom/store_buffering.non_genmc.stderr @@ -3,6 +3,8 @@ error: abnormal termination: the program aborted execution | LL | std::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here + | + = note: this is on thread `main` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/genmc/fail/shims/mutex_diff_thread_unlock.stderr b/src/tools/miri/tests/genmc/fail/shims/mutex_diff_thread_unlock.stderr index db465969cda8..5adfb066e6f1 100644 --- a/src/tools/miri/tests/genmc/fail/shims/mutex_diff_thread_unlock.stderr +++ b/src/tools/miri/tests/genmc/fail/shims/mutex_diff_thread_unlock.stderr @@ -7,12 +7,11 @@ LL | self.lock.inner.unlock(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE on thread `unnamed-ID`: - = note: inside ` as std::ops::Drop>::drop` at RUSTLIB/std/src/sync/poison/mutex.rs:LL:CC - = note: inside `std::ptr::drop_in_place::> - shim(Some(std::sync::MutexGuard<'_, u64>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC - = note: inside `std::ptr::drop_in_place::>> - shim(Some(EvilSend>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC - = note: inside `std::mem::drop::>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC -note: inside closure + = note: this is on thread `unnamed-ID`, inside ` as std::ops::Drop>::drop` + = note: which got called inside `std::ptr::drop_in_place::> - shim(Some(std::sync::MutexGuard<'_, u64>))` (at RUSTLIB/core/src/ptr/mod.rs:LL:CC) + = note: which got called inside `std::ptr::drop_in_place::>> - shim(Some(EvilSend>))` (at RUSTLIB/core/src/ptr/mod.rs:LL:CC) + = note: which got called inside `std::mem::drop::>>` (at RUSTLIB/core/src/mem/mod.rs:LL:CC) +note: which got called inside closure --> tests/genmc/fail/shims/mutex_diff_thread_unlock.rs:LL:CC | LL | drop(guard); diff --git a/src/tools/miri/tests/genmc/fail/shims/mutex_double_unlock.stderr b/src/tools/miri/tests/genmc/fail/shims/mutex_double_unlock.stderr index 3ba863668f1e..9fec95ae6770 100644 --- a/src/tools/miri/tests/genmc/fail/shims/mutex_double_unlock.stderr +++ b/src/tools/miri/tests/genmc/fail/shims/mutex_double_unlock.stderr @@ -7,11 +7,10 @@ LL | self.lock.inner.unlock(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside ` as std::ops::Drop>::drop` at RUSTLIB/std/src/sync/poison/mutex.rs:LL:CC - = note: inside `std::ptr::drop_in_place::> - shim(Some(std::sync::MutexGuard<'_, u64>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC - = note: inside `std::mem::drop::>` at RUSTLIB/core/src/mem/mod.rs:LL:CC -note: inside `miri_start` + = note: this is inside ` as std::ops::Drop>::drop` + = note: which got called inside `std::ptr::drop_in_place::> - shim(Some(std::sync::MutexGuard<'_, u64>))` (at RUSTLIB/core/src/ptr/mod.rs:LL:CC) + = note: which got called inside `std::mem::drop::>` (at RUSTLIB/core/src/mem/mod.rs:LL:CC) +note: which got called inside `miri_start` --> tests/genmc/fail/shims/mutex_double_unlock.rs:LL:CC | LL | drop(guard); diff --git a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.relaxed4.stderr b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.relaxed4.stderr index d6c66bf8f5c4..f7942d8ff749 100644 --- a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.relaxed4.stderr +++ b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.relaxed4.stderr @@ -4,6 +4,8 @@ error: abnormal termination: the program aborted execution | LL | std::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here + | + = note: this is on thread `main` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.release4.stderr b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.release4.stderr index d6c66bf8f5c4..f7942d8ff749 100644 --- a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.release4.stderr +++ b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.release4.stderr @@ -4,6 +4,8 @@ error: abnormal termination: the program aborted execution | LL | std::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here + | + = note: this is on thread `main` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.sc3_rel1.stderr b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.sc3_rel1.stderr index d6c66bf8f5c4..f7942d8ff749 100644 --- a/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.sc3_rel1.stderr +++ b/src/tools/miri/tests/genmc/fail/simple/2w2w_weak.sc3_rel1.stderr @@ -4,6 +4,8 @@ error: abnormal termination: the program aborted execution | LL | std::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here + | + = note: this is on thread `main` note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/genmc/fail/simple/alloc_large.multiple.stderr b/src/tools/miri/tests/genmc/fail/simple/alloc_large.multiple.stderr index 1d56614c7f03..2fc6e3d47229 100644 --- a/src/tools/miri/tests/genmc/fail/simple/alloc_large.multiple.stderr +++ b/src/tools/miri/tests/genmc/fail/simple/alloc_large.multiple.stderr @@ -6,13 +6,12 @@ LL | AllocInit::Uninitialized => alloc.allocate(layout), | ^^^^^^^^^^^^^^^^^^^^^^ resource exhaustion occurred here | = help: in GenMC mode, the address space is limited to 4GB per thread, and addresses cannot be reused - = note: BACKTRACE: - = note: inside `alloc::raw_vec::RawVecInner::try_allocate_in` at RUSTLIB/alloc/src/raw_vec/mod.rs:LL:CC - = note: inside `alloc::raw_vec::RawVecInner::with_capacity_in` at RUSTLIB/alloc/src/raw_vec/mod.rs:LL:CC - = note: inside `alloc::raw_vec::RawVec::::with_capacity_in` at RUSTLIB/alloc/src/raw_vec/mod.rs:LL:CC - = note: inside `std::vec::Vec::::with_capacity_in` at RUSTLIB/alloc/src/vec/mod.rs:LL:CC - = note: inside `std::vec::Vec::::with_capacity` at RUSTLIB/alloc/src/vec/mod.rs:LL:CC -note: inside `miri_start` + = note: this is inside `alloc::raw_vec::RawVecInner::try_allocate_in` + = note: which got called inside `alloc::raw_vec::RawVecInner::with_capacity_in` (at RUSTLIB/alloc/src/raw_vec/mod.rs:LL:CC) + = note: which got called inside `alloc::raw_vec::RawVec::::with_capacity_in` (at RUSTLIB/alloc/src/raw_vec/mod.rs:LL:CC) + = note: which got called inside `std::vec::Vec::::with_capacity_in` (at RUSTLIB/alloc/src/vec/mod.rs:LL:CC) + = note: which got called inside `std::vec::Vec::::with_capacity` (at RUSTLIB/alloc/src/vec/mod.rs:LL:CC) +note: which got called inside `miri_start` --> tests/genmc/fail/simple/alloc_large.rs:LL:CC | LL | let _v = Vec::::with_capacity(1024 * 1024 * 1024); diff --git a/src/tools/miri/tests/genmc/fail/simple/alloc_large.single.stderr b/src/tools/miri/tests/genmc/fail/simple/alloc_large.single.stderr index 8595612811fd..dbd39e4727c2 100644 --- a/src/tools/miri/tests/genmc/fail/simple/alloc_large.single.stderr +++ b/src/tools/miri/tests/genmc/fail/simple/alloc_large.single.stderr @@ -6,13 +6,12 @@ LL | AllocInit::Uninitialized => alloc.allocate(layout), | ^^^^^^^^^^^^^^^^^^^^^^ resource exhaustion occurred here | = help: in GenMC mode, the address space is limited to 4GB per thread, and addresses cannot be reused - = note: BACKTRACE: - = note: inside `alloc::raw_vec::RawVecInner::try_allocate_in` at RUSTLIB/alloc/src/raw_vec/mod.rs:LL:CC - = note: inside `alloc::raw_vec::RawVecInner::with_capacity_in` at RUSTLIB/alloc/src/raw_vec/mod.rs:LL:CC - = note: inside `alloc::raw_vec::RawVec::::with_capacity_in` at RUSTLIB/alloc/src/raw_vec/mod.rs:LL:CC - = note: inside `std::vec::Vec::::with_capacity_in` at RUSTLIB/alloc/src/vec/mod.rs:LL:CC - = note: inside `std::vec::Vec::::with_capacity` at RUSTLIB/alloc/src/vec/mod.rs:LL:CC -note: inside `miri_start` + = note: this is inside `alloc::raw_vec::RawVecInner::try_allocate_in` + = note: which got called inside `alloc::raw_vec::RawVecInner::with_capacity_in` (at RUSTLIB/alloc/src/raw_vec/mod.rs:LL:CC) + = note: which got called inside `alloc::raw_vec::RawVec::::with_capacity_in` (at RUSTLIB/alloc/src/raw_vec/mod.rs:LL:CC) + = note: which got called inside `std::vec::Vec::::with_capacity_in` (at RUSTLIB/alloc/src/vec/mod.rs:LL:CC) + = note: which got called inside `std::vec::Vec::::with_capacity` (at RUSTLIB/alloc/src/vec/mod.rs:LL:CC) +note: which got called inside `miri_start` --> tests/genmc/fail/simple/alloc_large.rs:LL:CC | LL | let _v = Vec::::with_capacity(8 * 1024 * 1024 * 1024); diff --git a/src/tools/miri/tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.stderr b/src/tools/miri/tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.stderr index 31438f9352fe..71a01d8f754b 100644 --- a/src/tools/miri/tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.stderr +++ b/src/tools/miri/tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.stderr @@ -5,15 +5,14 @@ warning: GenMC currently does not model the failure ordering for `compare_exchan LL | match KEY.compare_exchange(KEY_SENTVAL, key, Release, Acquire) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code | - = note: BACKTRACE on thread `unnamed-ID`: - = note: inside `get_or_init` at tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.rs:LL:CC -note: inside closure + = note: this is on thread `unnamed-ID`, inside `get_or_init` +note: which got called inside closure --> tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.rs:LL:CC | LL | let key = get_or_init(0); | ^^^^^^^^^^^^^^ - = note: inside ` as std::ops::FnOnce<()>>::call_once` at RUSTLIB/alloc/src/boxed.rs:LL:CC -note: inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.rs:LL:CC}>` + = note: which got called inside ` as std::ops::FnOnce<()>>::call_once` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) +note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.rs:LL:CC}>` --> tests/genmc/pass/atomics/../../../utils/genmc.rs:LL:CC | LL | f(); diff --git a/src/tools/miri/tests/native-lib/fail/tracing/partial_init.stderr b/src/tools/miri/tests/native-lib/fail/tracing/partial_init.stderr index 1c0ad2f0dc91..4a7d24090641 100644 --- a/src/tools/miri/tests/native-lib/fail/tracing/partial_init.stderr +++ b/src/tools/miri/tests/native-lib/fail/tracing/partial_init.stderr @@ -9,9 +9,8 @@ LL | init_n(2, slice_ptr); = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free = help: tracing memory accesses in native code is not yet fully implemented, so there can be further imprecisions beyond what is documented here - = note: BACKTRACE: - = note: inside `partial_init` at tests/native-lib/fail/tracing/partial_init.rs:LL:CC -note: inside `main` + = note: this is inside `partial_init` +note: which got called inside `main` --> tests/native-lib/fail/tracing/partial_init.rs:LL:CC | LL | partial_init(); @@ -25,9 +24,8 @@ LL | let _val = *slice_ptr.offset(2); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `partial_init` at tests/native-lib/fail/tracing/partial_init.rs:LL:CC -note: inside `main` + = note: this is inside `partial_init` +note: which got called inside `main` --> tests/native-lib/fail/tracing/partial_init.rs:LL:CC | LL | partial_init(); diff --git a/src/tools/miri/tests/native-lib/fail/tracing/unexposed_reachable_alloc.stderr b/src/tools/miri/tests/native-lib/fail/tracing/unexposed_reachable_alloc.stderr index 2d34dac1b3ff..825c9666b749 100644 --- a/src/tools/miri/tests/native-lib/fail/tracing/unexposed_reachable_alloc.stderr +++ b/src/tools/miri/tests/native-lib/fail/tracing/unexposed_reachable_alloc.stderr @@ -9,9 +9,8 @@ LL | unsafe { do_one_deref(exposed) }; = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free = help: tracing memory accesses in native code is not yet fully implemented, so there can be further imprecisions beyond what is documented here - = note: BACKTRACE: - = note: inside `unexposed_reachable_alloc` at tests/native-lib/fail/tracing/unexposed_reachable_alloc.rs:LL:CC -note: inside `main` + = note: this is inside `unexposed_reachable_alloc` +note: which got called inside `main` --> tests/native-lib/fail/tracing/unexposed_reachable_alloc.rs:LL:CC | LL | unexposed_reachable_alloc(); @@ -25,9 +24,8 @@ LL | let _not_ok = *invalid; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `unexposed_reachable_alloc` at tests/native-lib/fail/tracing/unexposed_reachable_alloc.rs:LL:CC -note: inside `main` + = note: this is inside `unexposed_reachable_alloc` +note: which got called inside `main` --> tests/native-lib/fail/tracing/unexposed_reachable_alloc.rs:LL:CC | LL | unexposed_reachable_alloc(); diff --git a/src/tools/miri/tests/native-lib/pass/ptr_read_access.notrace.stderr b/src/tools/miri/tests/native-lib/pass/ptr_read_access.notrace.stderr index 200eba8050bb..cbccd8fb62f4 100644 --- a/src/tools/miri/tests/native-lib/pass/ptr_read_access.notrace.stderr +++ b/src/tools/miri/tests/native-lib/pass/ptr_read_access.notrace.stderr @@ -8,9 +8,8 @@ LL | unsafe { print_pointer(&x) }; = help: in particular, Miri assumes that the native call initializes all memory it has access to = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free - = note: BACKTRACE: - = note: inside `test_access_pointer` at tests/native-lib/pass/ptr_read_access.rs:LL:CC -note: inside `main` + = note: this is inside `test_access_pointer` +note: which got called inside `main` --> tests/native-lib/pass/ptr_read_access.rs:LL:CC | LL | test_access_pointer(); @@ -23,9 +22,8 @@ LL | pass_fn_ptr(Some(nop)); // this one is not | ^^^^^^^^^^^^^^^^^^^^^^ sharing a function pointer with a native function | = help: calling Rust functions from C is not supported and will, in the best case, crash the program - = note: BACKTRACE: - = note: inside `pass_fn_ptr` at tests/native-lib/pass/ptr_read_access.rs:LL:CC -note: inside `main` + = note: this is inside `pass_fn_ptr` +note: which got called inside `main` --> tests/native-lib/pass/ptr_read_access.rs:LL:CC | LL | pass_fn_ptr(); diff --git a/src/tools/miri/tests/native-lib/pass/ptr_read_access.trace.stderr b/src/tools/miri/tests/native-lib/pass/ptr_read_access.trace.stderr index 5c0e954deb9b..2697fb6d4353 100644 --- a/src/tools/miri/tests/native-lib/pass/ptr_read_access.trace.stderr +++ b/src/tools/miri/tests/native-lib/pass/ptr_read_access.trace.stderr @@ -9,9 +9,8 @@ LL | unsafe { print_pointer(&x) }; = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free = help: tracing memory accesses in native code is not yet fully implemented, so there can be further imprecisions beyond what is documented here - = note: BACKTRACE: - = note: inside `test_access_pointer` at tests/native-lib/pass/ptr_read_access.rs:LL:CC -note: inside `main` + = note: this is inside `test_access_pointer` +note: which got called inside `main` --> tests/native-lib/pass/ptr_read_access.rs:LL:CC | LL | test_access_pointer(); @@ -24,9 +23,8 @@ LL | pass_fn_ptr(Some(nop)); // this one is not | ^^^^^^^^^^^^^^^^^^^^^^ sharing a function pointer with a native function | = help: calling Rust functions from C is not supported and will, in the best case, crash the program - = note: BACKTRACE: - = note: inside `pass_fn_ptr` at tests/native-lib/pass/ptr_read_access.rs:LL:CC -note: inside `main` + = note: this is inside `pass_fn_ptr` +note: which got called inside `main` --> tests/native-lib/pass/ptr_read_access.rs:LL:CC | LL | pass_fn_ptr(); diff --git a/src/tools/miri/tests/native-lib/pass/ptr_write_access.notrace.stderr b/src/tools/miri/tests/native-lib/pass/ptr_write_access.notrace.stderr index c893b0d9f656..c7edaa373167 100644 --- a/src/tools/miri/tests/native-lib/pass/ptr_write_access.notrace.stderr +++ b/src/tools/miri/tests/native-lib/pass/ptr_write_access.notrace.stderr @@ -8,9 +8,8 @@ LL | unsafe { increment_int(&mut x) }; = help: in particular, Miri assumes that the native call initializes all memory it has access to = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free - = note: BACKTRACE: - = note: inside `test_increment_int` at tests/native-lib/pass/ptr_write_access.rs:LL:CC -note: inside `main` + = note: this is inside `test_increment_int` +note: which got called inside `main` --> tests/native-lib/pass/ptr_write_access.rs:LL:CC | LL | test_increment_int(); diff --git a/src/tools/miri/tests/native-lib/pass/ptr_write_access.trace.stderr b/src/tools/miri/tests/native-lib/pass/ptr_write_access.trace.stderr index dbf021b15bec..dacde45e17a1 100644 --- a/src/tools/miri/tests/native-lib/pass/ptr_write_access.trace.stderr +++ b/src/tools/miri/tests/native-lib/pass/ptr_write_access.trace.stderr @@ -9,9 +9,8 @@ LL | unsafe { increment_int(&mut x) }; = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free = help: tracing memory accesses in native code is not yet fully implemented, so there can be further imprecisions beyond what is documented here - = note: BACKTRACE: - = note: inside `test_increment_int` at tests/native-lib/pass/ptr_write_access.rs:LL:CC -note: inside `main` + = note: this is inside `test_increment_int` +note: which got called inside `main` --> tests/native-lib/pass/ptr_write_access.rs:LL:CC | LL | test_increment_int(); diff --git a/src/tools/miri/tests/pass/alloc-access-tracking.stderr b/src/tools/miri/tests/pass/alloc-access-tracking.stderr index 745fd89f9f54..b5b1bc2a7bc2 100644 --- a/src/tools/miri/tests/pass/alloc-access-tracking.stderr +++ b/src/tools/miri/tests/pass/alloc-access-tracking.stderr @@ -24,10 +24,9 @@ note: freed allocation ALLOC LL | self.1.deallocate(From::from(ptr.cast()), layout); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tracking was triggered here | - = note: BACKTRACE: - = note: inside `> as std::ops::Drop>::drop` at RUSTLIB/alloc/src/boxed.rs:LL:CC - = note: inside `std::ptr::drop_in_place::>> - shim(Some(std::boxed::Box>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC -note: inside `main` + = note: this is inside `> as std::ops::Drop>::drop` + = note: which got called inside `std::ptr::drop_in_place::>> - shim(Some(std::boxed::Box>))` (at RUSTLIB/core/src/ptr/mod.rs:LL:CC) +note: which got called inside `main` --> tests/pass/alloc-access-tracking.rs:LL:CC | LL | } From b49e56d5a887a2c4dd8d78e9f215a219bd03a1ac Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Mon, 29 Dec 2025 22:11:16 +0000 Subject: [PATCH 0097/1061] fix typo (this commit will be squashed after review) --- src/tools/tidy/src/extra_checks/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index d5b360cbe549..bedcd08ca13f 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -754,7 +754,7 @@ enum ExtraCheckParseError { /// `auto` specified without lang part. AutoRequiresLang, /// `if-installed` specified without lang part. - IfInsatlledRequiresLang, + IfInstalledRequiresLang, } struct ExtraCheckArg { @@ -874,7 +874,7 @@ impl FromStr for ExtraCheckArg { if !if_installed && first == "if-installed" { let Some(part) = parts.next() else { - return Err(ExtraCheckParseError::IfInsatlledRequiresLang); + return Err(ExtraCheckParseError::IfInstalledRequiresLang); }; if_installed = true; first = part; From 1514495151d4d2e0aa5a1d7157d1a4ce87e443ce Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 7 Dec 2025 10:20:33 +0100 Subject: [PATCH 0098/1061] always show the origin_span of the failing thread --- src/tools/miri/src/diagnostics.rs | 40 ++++++++----------- ...pple_os_unfair_lock_move_with_queue.stderr | 10 ++++- .../concurrency/libc_pthread_join_main.stderr | 12 +++++- .../libc_pthread_join_multiple.stderr | 10 ++++- .../concurrency/libc_pthread_join_self.stderr | 13 +++++- .../libc_pthread_mutex_deadlock.stderr | 9 ++++- ...ibc_pthread_mutex_free_while_queued.stderr | 9 +++++ ...ibc_pthread_mutex_read_while_queued.stderr | 10 ++++- ...bc_pthread_mutex_write_while_queued.stderr | 10 ++++- .../libc_pthread_mutex_wrong_owner.stderr | 9 ++++- ...ibc_pthread_rwlock_read_wrong_owner.stderr | 9 ++++- ..._pthread_rwlock_write_read_deadlock.stderr | 9 ++++- ...pthread_rwlock_write_write_deadlock.stderr | 9 ++++- ...bc_pthread_rwlock_write_wrong_owner.stderr | 9 ++++- .../concurrency/windows_join_main.stderr | 11 ++++- .../concurrency/windows_join_self.stderr | 12 +++++- .../libc/env-set_var-data-race.stderr | 12 +++++- .../libc/eventfd_block_read_twice.stderr | 12 +++++- .../libc/eventfd_block_write_twice.stderr | 14 ++++++- .../libc/libc_epoll_block_two_thread.stderr | 11 ++++- .../socketpair-close-while-blocked.stderr | 14 ++++++- .../libc/socketpair_block_read_twice.stderr | 14 ++++++- .../libc/socketpair_block_write_twice.stderr | 14 ++++++- .../retag_data_race_write.stack.stderr | 5 +++ .../retag_data_race_write.tree.stderr | 5 +++ .../fail/data_race/alloc_read_race.stderr | 13 +++++- .../fail/data_race/alloc_write_race.stderr | 12 +++++- .../atomic_read_na_write_race1.stderr | 11 ++++- .../atomic_read_na_write_race2.stderr | 12 +++++- .../atomic_write_na_read_race1.stderr | 12 +++++- .../atomic_write_na_read_race2.stderr | 11 ++++- .../atomic_write_na_write_race1.stderr | 11 ++++- .../atomic_write_na_write_race2.stderr | 12 +++++- .../dangling_thread_async_race.stderr | 10 ++++- .../fail/data_race/dealloc_read_race1.stderr | 13 +++++- .../fail/data_race/dealloc_read_race2.stderr | 11 ++++- .../data_race/dealloc_read_race_stack.stderr | 13 +++++- .../fail/data_race/dealloc_write_race1.stderr | 13 +++++- .../fail/data_race/dealloc_write_race2.stderr | 11 ++++- .../data_race/dealloc_write_race_stack.stderr | 13 +++++- .../enable_after_join_to_main.stderr | 11 ++++- .../local_variable_alloc_race.stderr | 11 ++++- .../data_race/local_variable_read_race.stderr | 12 +++++- .../local_variable_write_race.stderr | 12 +++++- ...ze_read_read_write.match_first_load.stderr | 12 +++++- ...e_read_read_write.match_second_load.stderr | 12 +++++- .../mixed_size_read_write.read_write.stderr | 12 +++++- .../mixed_size_read_write.write_read.stderr | 12 +++++- .../mixed_size_read_write_read.stderr | 9 ++++- .../mixed_size_write_write.fst.stderr | 11 ++++- .../mixed_size_write_write.snd.stderr | 11 ++++- .../fail/data_race/read_write_race.stderr | 11 ++++- .../data_race/read_write_race_stack.stderr | 12 +++++- .../fail/data_race/relax_acquire_race.stderr | 13 +++++- .../fail/data_race/release_seq_race.stderr | 13 +++++- .../release_seq_race_same_thread.stderr | 13 +++++- .../miri/tests/fail/data_race/rmw_race.stderr | 13 +++++- .../fail/data_race/write_write_race.stderr | 11 ++++- .../data_race/write_write_race_stack.stderr | 12 +++++- src/tools/miri/tests/fail/shims/ctor_ub.rs | 39 ++++++++++++++++++ .../miri/tests/fail/shims/ctor_ub.stderr | 23 +++++++++++ .../retag_data_race_protected_read.stderr | 13 +++++- .../retag_data_race_read.stderr | 5 +++ .../reservedim_spurious_write.with.stderr | 14 ++++++- .../reservedim_spurious_write.without.stderr | 14 ++++++- .../fail/tree_borrows/spurious_read.stderr | 12 ++++++ .../tests/fail/weak_memory/weak_uninit.stderr | 7 +++- .../atomics/atomic_ptr_double_free.stderr | 10 +++++ .../atomic_ptr_alloc_race.dealloc.stderr | 10 +++++ .../atomic_ptr_alloc_race.write.stderr | 10 +++++ .../atomic_ptr_dealloc_write_race.stderr | 10 +++++ .../atomic_ptr_write_dealloc_race.stderr | 10 +++++ .../genmc/fail/data_race/mpu2_rels_rlx.stderr | 10 +++++ .../data_race/weak_orderings.rel_rlx.stderr | 10 +++++ .../data_race/weak_orderings.rlx_acq.stderr | 10 +++++ .../data_race/weak_orderings.rlx_rlx.stderr | 10 +++++ .../miri/tests/genmc/fail/shims/exit.stderr | 8 ++++ .../shims/mutex_diff_thread_unlock.stderr | 9 +++++ .../cas_failure_ord_racy_key_init.stderr | 10 +++++ 79 files changed, 854 insertions(+), 83 deletions(-) create mode 100644 src/tools/miri/tests/fail/shims/ctor_ub.rs create mode 100644 src/tools/miri/tests/fail/shims/ctor_ub.stderr diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index fb4029d10454..8de30d870327 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -555,35 +555,24 @@ fn report_msg<'tcx>( thread: Option, machine: &MiriMachine<'tcx>, ) { - let span = match stacktrace.first() { - Some(fi) => fi.span, - None => - match thread { - Some(thread_id) => machine.threads.thread_ref(thread_id).origin_span, - // This fallback is super rare, but can happen e.g. when `main` has the wrong ABI - None => DUMMY_SP, - }, - }; - let sess = machine.tcx.sess; + let origin_span = thread.map(|t| machine.threads.thread_ref(t).origin_span).unwrap_or(DUMMY_SP); + let span = stacktrace.first().map(|fi| fi.span).unwrap_or(origin_span); + // The only time we do not have an origin span is for `main`, and there we check the signature + // upfront. So we should always have a span here. + assert!(!span.is_dummy()); + + let tcx = machine.tcx; let level = match diag_level { DiagLevel::Error => Level::Error, DiagLevel::Warning => Level::Warning, DiagLevel::Note => Level::Note, }; - let mut err = Diag::<()>::new(sess.dcx(), level, title); + let mut err = Diag::<()>::new(tcx.sess.dcx(), level, title); err.span(span); // Show main message. - if !span.is_dummy() { - for line in span_msg { - err.span_label(span, line); - } - } else { - // Make sure we show the message even when it is a dummy span. - for line in span_msg { - err.note(line); - } - err.note("(no span available)"); + for line in span_msg { + err.span_label(span, line); } // Show note and help messages. @@ -621,7 +610,7 @@ fn report_msg<'tcx>( .unwrap(); } // Only print function name if we show a backtrace - if rest.len() > 0 { + if rest.len() > 0 || !origin_span.is_dummy() { if !fn_and_thread.is_empty() { fn_and_thread.push_str(", "); } @@ -632,7 +621,7 @@ fn report_msg<'tcx>( // Print a `span_note` as otherwise the backtrace looks attached to the last // `span_help`. We somewhat arbitrarily use the span of the surrounding function. err.span_note( - machine.tcx.def_span(first.instance.def_id()), + tcx.def_span(first.instance.def_id()), format!("{level} occurred {fn_and_thread}"), ); } else { @@ -646,11 +635,14 @@ fn report_msg<'tcx>( if is_local { err.span_note(frame_info.span, format!("which got called {frame_info}")); } else { - let sm = sess.source_map(); + let sm = tcx.sess.source_map(); let span = sm.span_to_diagnostic_string(frame_info.span); err.note(format!("which got called {frame_info} (at {span})")); } } + if !origin_span.is_dummy() { + err.span_note(origin_span, format!("which got called indirectly due to this code")); + } } else if !span.is_dummy() { err.note(format!("this {level} occurred while pushing a call frame onto an empty stack")); err.note("the span indicates which code caused the function to be called, but may not be the literal call site"); diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_move_with_queue.stderr b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_move_with_queue.stderr index e86395fae201..b943ac1f61ef 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_move_with_queue.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_move_with_queue.stderr @@ -6,7 +6,15 @@ LL | let _val = atomic_ref.load(Ordering::Relaxed); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail-dep/concurrency/apple_os_unfair_lock_move_with_queue.rs:LL:CC + | +LL | / ... s.spawn(|| { +LL | | ... let atomic_ref = unsafe { &*lock.get().cast::() }; +LL | | ... let _val = atomic_ref.load(Ordering::Relaxed); +LL | | ... }); + | |________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.stderr index 85d7fae892d1..c364642fc629 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.stderr @@ -6,7 +6,17 @@ LL | ... assert_eq!(libc::pthread_join(thread_id, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail-dep/concurrency/libc_pthread_join_main.rs:LL:CC + | +LL | let handle = thread::spawn(move || { + | __________________^ +LL | | unsafe { +LL | | assert_eq!(libc::pthread_join(thread_id, ptr::null_mut()), 0); +LL | | } +LL | | }); + | |______^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.stderr index 72c778fd0beb..b9bf801eaf61 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.stderr @@ -6,7 +6,15 @@ LL | ... assert_eq!(libc::pthread_join(native_copy, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail-dep/concurrency/libc_pthread_join_multiple.rs:LL:CC + | +LL | ... let handle = thread::spawn(move || { + | ____________________^ +LL | | ... assert_eq!(libc::pthread_join(native_copy, ptr::null_mut()), 0); +LL | | ... }); + | |________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.stderr index 250b9ef9dfa1..ddf3372a7277 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.stderr @@ -6,7 +6,18 @@ LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail-dep/concurrency/libc_pthread_join_self.rs:LL:CC + | +LL | let handle = thread::spawn(|| { + | __________________^ +LL | | unsafe { +LL | | let native: libc::pthread_t = libc::pthread_self(); +LL | | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); +LL | | } +LL | | }); + | |______^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr index db4811b52a3a..1e7b0abf341a 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr @@ -22,7 +22,14 @@ error: the evaluated program deadlocked LL | assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _), 0); | ^ thread got stuck here | - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs:LL:CC + | +LL | / thread::spawn(move || { +LL | | assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _), 0); +LL | | }) + | |__________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_free_while_queued.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_free_while_queued.stderr index cd6f6563469e..765604ea0060 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_free_while_queued.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_free_while_queued.stderr @@ -14,6 +14,15 @@ note: which got called inside closure | LL | drop(unsafe { Box::from_raw(m.get().cast::()) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called indirectly due to this code + --> tests/fail-dep/concurrency/libc_pthread_mutex_free_while_queued.rs:LL:CC + | +LL | / s.spawn(|| { +LL | | // Ensure we happen-after the initialization write. +LL | | assert!(initialized.load(Ordering::Acquire)); +... | +LL | | }); + | |__________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_read_while_queued.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_read_while_queued.stderr index 6b46b6f1a7f9..fd9cddebabc7 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_read_while_queued.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_read_while_queued.stderr @@ -6,7 +6,15 @@ LL | ... let _val = atomic_ref.load(Ordering::Relaxed); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail-dep/concurrency/libc_pthread_mutex_read_while_queued.rs:LL:CC + | +LL | / ... s.spawn(|| { +LL | | ... let atomic_ref = unsafe { &*m.get().byte_add(OFFSET).cast::() }; +LL | | ... let _val = atomic_ref.load(Ordering::Relaxed); +LL | | ... }); + | |________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_write_while_queued.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_write_while_queued.stderr index 641150a9d31e..02a0f25af492 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_write_while_queued.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_write_while_queued.stderr @@ -6,7 +6,15 @@ LL | atomic_ref.store(0, Ordering::Relaxed); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail-dep/concurrency/libc_pthread_mutex_write_while_queued.rs:LL:CC + | +LL | / s.spawn(|| { +LL | | let atomic_ref = unsafe { &*m.get().byte_add(OFFSET).cast::() }; +LL | | atomic_ref.store(0, Ordering::Relaxed); +LL | | }); + | |__________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.stderr index 39765c8ec830..25dae98ef5d9 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.stderr @@ -6,7 +6,14 @@ LL | ... assert_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.rs:LL:CC + | +LL | / ... thread::spawn(move || { +LL | | ... assert_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0); +LL | | ... }) + | |________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.stderr index 3b90bd446e54..37c7540afb27 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.stderr @@ -6,7 +6,14 @@ LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.rs:LL:CC + | +LL | / ... thread::spawn(move || { +LL | | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), 0); +LL | | ... }) + | |________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr index c1722e33b615..0818f213f5e7 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr @@ -22,7 +22,14 @@ error: the evaluated program deadlocked LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); | ^ thread got stuck here | - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC + | +LL | / thread::spawn(move || { +LL | | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); +LL | | }) + | |__________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr index ce1e0d83c772..4ee88c0059d2 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr @@ -22,7 +22,14 @@ error: the evaluated program deadlocked LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); | ^ thread got stuck here | - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC + | +LL | / thread::spawn(move || { +LL | | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); +LL | | }) + | |__________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.stderr index 0a4037305c77..94578338f40b 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.stderr @@ -6,7 +6,14 @@ LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.rs:LL:CC + | +LL | / ... thread::spawn(move || { +LL | | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), 0); +LL | | ... }) + | |________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr index d07f16eb6a99..ee0aa254abaf 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr @@ -23,7 +23,16 @@ error: the evaluated program deadlocked LL | assert_eq!(WaitForSingleObject(MAIN_THREAD, INFINITE), WAIT_OBJECT_0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ thread got stuck here | - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail-dep/concurrency/windows_join_main.rs:LL:CC + | +LL | / thread::spawn(|| { +LL | | unsafe { +LL | | assert_eq!(WaitForSingleObject(MAIN_THREAD, INFINITE), WAIT_OBJECT_0); +LL | | } +LL | | }) + | |______^ = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr b/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr index d82e273677e4..561464d47179 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr @@ -25,7 +25,17 @@ error: the evaluated program deadlocked LL | assert_eq!(WaitForSingleObject(native, INFINITE), WAIT_OBJECT_0); | ^ thread got stuck here | - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail-dep/concurrency/windows_join_self.rs:LL:CC + | +LL | / thread::spawn(|| { +LL | | unsafe { +LL | | let native = GetCurrentThread(); +LL | | assert_eq!(WaitForSingleObject(native, INFINITE), WAIT_OBJECT_0); +LL | | } +LL | | }) + | |______^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr index c326bb8c3c3f..eed33569af11 100644 --- a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr +++ b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr @@ -11,7 +11,17 @@ LL | env::set_var("MY_RUST_VAR", "Ferris"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail-dep/libc/env-set_var-data-race.rs:LL:CC + | +LL | let t = thread::spawn(|| unsafe { + | _____________^ +LL | | // Access the environment in another thread without taking the env lock. +LL | | // This represents some C code that queries the environment. +LL | | libc::getenv(b"TZ/0".as_ptr().cast()); +LL | | }); + | |______^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.stderr b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.stderr index dc34f4748cd2..d0c8169fe7d2 100644 --- a/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.stderr +++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.stderr @@ -19,7 +19,17 @@ error: the evaluated program deadlocked LL | let res: i64 = unsafe { libc::read(fd, buf.as_mut_ptr().cast(), 8).try_into().unwrap() }; | ^ thread got stuck here | - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail-dep/libc/eventfd_block_read_twice.rs:LL:CC + | +LL | let thread2 = thread::spawn(move || { + | ___________________^ +LL | | let mut buf: [u8; 8] = [0; 8]; +... | +LL | | assert_eq!(counter, 1_u64); +LL | | }); + | |______^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.stderr b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.stderr index 3758484bb05e..878059cb5ef2 100644 --- a/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.stderr +++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.stderr @@ -19,7 +19,19 @@ error: the evaluated program deadlocked LL | libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8).try_into().unwrap() | ^ thread got stuck here | - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail-dep/libc/eventfd_block_write_twice.rs:LL:CC + | +LL | let thread2 = thread::spawn(move || { + | ___________________^ +LL | | let sized_8_data = (u64::MAX - 1).to_ne_bytes(); +LL | | // Write u64::MAX - 1, so that all subsequent writes will block. +LL | | let res: i64 = unsafe { +... | +LL | | assert_eq!(res, 8); +LL | | }); + | |______^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.stderr b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.stderr index e883bd9bd025..f7f77647acb5 100644 --- a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.stderr +++ b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.stderr @@ -19,7 +19,16 @@ error: the evaluated program deadlocked LL | check_epoll_wait::(epfd, &expected, -1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ thread got stuck here | - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail-dep/libc/libc_epoll_block_two_thread.rs:LL:CC + | +LL | let thread2 = thread::spawn(move || { + | ___________________^ +LL | | check_epoll_wait::(epfd, &expected, -1); +LL | | +LL | | }); + | |______^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr index a7d0b60dfcb3..b1b1fddc6735 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr +++ b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr @@ -19,7 +19,19 @@ error: the evaluated program deadlocked LL | libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) | ^ thread got stuck here | - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail-dep/libc/socketpair-close-while-blocked.rs:LL:CC + | +LL | let thread1 = thread::spawn(move || { + | ___________________^ +LL | | let mut buf: [u8; 1] = [0; 1]; +LL | | let _res: i32 = unsafe { +LL | | libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) +... | +LL | | }; +LL | | }); + | |______^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr index a817f2867284..a556ba592ec8 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr @@ -19,7 +19,19 @@ error: the evaluated program deadlocked LL | libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) | ^ thread got stuck here | - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail-dep/libc/socketpair_block_read_twice.rs:LL:CC + | +LL | let thread2 = thread::spawn(move || { + | ___________________^ +LL | | // Let this thread block on read. +LL | | let mut buf: [u8; 1] = [0; 1]; +LL | | let res = unsafe { +... | +LL | | assert_eq!(&buf, "a".as_bytes()); +LL | | }); + | |______^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr index 18e6222589f0..259ca6bd8347 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr @@ -19,7 +19,19 @@ error: the evaluated program deadlocked LL | let res = unsafe { libc::write(fds[0], data.as_ptr() as *const libc::c_void, data.len()) }; | ^ thread got stuck here | - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail-dep/libc/socketpair_block_write_twice.rs:LL:CC + | +LL | let thread2 = thread::spawn(move || { + | ___________________^ +LL | | let data = "a".as_bytes(); +LL | | // The write below will be blocked because the buffer is already full. +LL | | let res = unsafe { libc::write(fds[0], data.as_ptr() as *const libc::c_void, data.len()) }; +LL | | +LL | | assert_eq!(res, data.len().cast_signed()); +LL | | }); + | |______^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr index 8624205444bc..d1dbdbc67f1b 100644 --- a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr @@ -24,6 +24,11 @@ note: which got called inside closure | LL | let t2 = std::thread::spawn(move || thread_2(p)); | ^^^^^^^^^^^ +note: which got called indirectly due to this code + --> tests/fail/both_borrows/retag_data_race_write.rs:LL:CC + | +LL | let t2 = std::thread::spawn(move || thread_2(p)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr index 6d1dff0d5f53..47abf74cb8a2 100644 --- a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr @@ -24,6 +24,11 @@ note: which got called inside closure | LL | let t2 = std::thread::spawn(move || thread_2(p)); | ^^^^^^^^^^^ +note: which got called indirectly due to this code + --> tests/fail/both_borrows/retag_data_race_write.rs:LL:CC + | +LL | let t2 = std::thread::spawn(move || thread_2(p)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/alloc_read_race.stderr b/src/tools/miri/tests/fail/data_race/alloc_read_race.stderr index c9e9059ef085..67edbfb4658e 100644 --- a/src/tools/miri/tests/fail/data_race/alloc_read_race.stderr +++ b/src/tools/miri/tests/fail/data_race/alloc_read_race.stderr @@ -11,7 +11,18 @@ LL | pointer.store(Box::into_raw(Box::new_uninit()), Ordering::Relax | ^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/alloc_read_race.rs:LL:CC + | +LL | ... let j2 = spawn(move || { + | ________________^ +LL | | ... let ptr = ptr; // avoid field capturing +LL | | ... let pointer = &*ptr.0; +... | +LL | | ... *pointer.load(Ordering::Relaxed) +LL | | ... }); + | |________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/alloc_write_race.stderr b/src/tools/miri/tests/fail/data_race/alloc_write_race.stderr index 110c013ec0cc..33c562958e20 100644 --- a/src/tools/miri/tests/fail/data_race/alloc_write_race.stderr +++ b/src/tools/miri/tests/fail/data_race/alloc_write_race.stderr @@ -11,7 +11,17 @@ LL | .store(Box::into_raw(Box::::new_uninit()) as *mut us | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/alloc_write_race.rs:LL:CC + | +LL | ... let j2 = spawn(move || { + | ________________^ +LL | | ... let ptr = ptr; // avoid field capturing +LL | | ... let pointer = &*ptr.0; +LL | | ... *pointer.load(Ordering::Relaxed) = 2; +LL | | ... }); + | |________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.stderr b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.stderr index 2d0317c7ffdf..6f0332e46fa3 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.stderr @@ -11,7 +11,16 @@ LL | *(c.0 as *mut usize) = 32; | ^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/atomic_read_na_write_race1.rs:LL:CC + | +LL | ... let j2 = spawn(move || { + | ________________^ +LL | | ... let c = c; // avoid field capturing +LL | | ... (&*c.0).load(Ordering::SeqCst) +LL | | ... }); + | |________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.stderr b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.stderr index a5c1006e31f6..13f95e85242a 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.stderr @@ -11,7 +11,17 @@ LL | atomic_ref.load(Ordering::SeqCst) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/atomic_read_na_write_race2.rs:LL:CC + | +LL | ... let j2 = spawn(move || { + | ________________^ +LL | | ... let c = c; // avoid field capturing +LL | | ... let atomic_ref = &mut *c.0; +LL | | ... *atomic_ref.get_mut() = 32; +LL | | ... }); + | |________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.stderr b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.stderr index bef2f1f6fa1a..0907ed3cd0a3 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.stderr @@ -11,7 +11,17 @@ LL | atomic_ref.store(32, Ordering::SeqCst) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/atomic_write_na_read_race1.rs:LL:CC + | +LL | ... let j2 = spawn(move || { + | ________________^ +LL | | ... let c = c; // avoid field capturing +LL | | ... let atomic_ref = &mut *c.0; +LL | | ... *atomic_ref.get_mut() +LL | | ... }); + | |________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.stderr b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.stderr index 56c669549106..dfc7ed012725 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.stderr @@ -11,7 +11,16 @@ LL | let _val = *(c.0 as *mut usize); | ^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/atomic_write_na_read_race2.rs:LL:CC + | +LL | ... let j2 = spawn(move || { + | ________________^ +LL | | ... let c = c; // avoid field capturing +LL | | ... (&*c.0).store(32, Ordering::SeqCst); +LL | | ... }); + | |________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.stderr b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.stderr index 3b79801bfab8..018db8364ed0 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.stderr @@ -11,7 +11,16 @@ LL | *(c.0 as *mut usize) = 32; | ^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/atomic_write_na_write_race1.rs:LL:CC + | +LL | ... let j2 = spawn(move || { + | ________________^ +LL | | ... let c = c; // avoid field capturing +LL | | ... (&*c.0).store(64, Ordering::SeqCst); +LL | | ... }); + | |________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.stderr b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.stderr index 069dc9ac8de8..ef5521448676 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.stderr @@ -11,7 +11,17 @@ LL | atomic_ref.store(64, Ordering::SeqCst); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/atomic_write_na_write_race2.rs:LL:CC + | +LL | ... let j2 = spawn(move || { + | ________________^ +LL | | ... let c = c; // avoid field capturing +LL | | ... let atomic_ref = &mut *c.0; +LL | | ... *atomic_ref.get_mut() = 32; +LL | | ... }); + | |________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.stderr b/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.stderr index a01f85ab6ce1..da13b62b1cf0 100644 --- a/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.stderr +++ b/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.stderr @@ -11,7 +11,15 @@ LL | *c.0 = 32; | ^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/dangling_thread_async_race.rs:LL:CC + | +LL | / ... spawn(move || { +LL | | ... let c = c; // capture `c`, not just its field. +LL | | ... *c.0 = 64; +LL | | ... }) + | |________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race1.stderr b/src/tools/miri/tests/fail/data_race/dealloc_read_race1.stderr index afe1125e7514..798c6c490b4c 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race1.stderr @@ -16,7 +16,18 @@ LL | let _val = *ptr.0; | ^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/dealloc_read_race1.rs:LL:CC + | +LL | let j2 = spawn(move || { + | __________________^ +LL | | let ptr = ptr; // avoid field capturing +LL | | __rust_dealloc( +... | +LL | | ); +LL | | }); + | |__________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race2.stderr b/src/tools/miri/tests/fail/data_race/dealloc_read_race2.stderr index a741203dcf6d..4a9e6e832b8e 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race2.stderr @@ -20,7 +20,16 @@ LL | | std::mem::size_of::(), LL | | std::mem::align_of::(), LL | | ) | |_____________^ - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/dealloc_read_race2.rs:LL:CC + | +LL | let j2 = spawn(move || { + | __________________^ +LL | | let ptr = ptr; // avoid field capturing +... | +LL | | }); + | |__________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.stderr b/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.stderr index 4adf3f3d58d3..8b8cfaf9930c 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.stderr @@ -11,7 +11,18 @@ LL | *pointer.load(Ordering::Acquire) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/dealloc_read_race_stack.rs:LL:CC + | +LL | ... let j1 = spawn(move || { + | ________________^ +LL | | ... let ptr = ptr; // avoid field capturing +LL | | ... let pointer = &*ptr.0; +... | +LL | | ... } +LL | | ... }); + | |________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race1.stderr b/src/tools/miri/tests/fail/data_race/dealloc_write_race1.stderr index cfa4f06f9a9f..18924d7d65ce 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race1.stderr @@ -16,7 +16,18 @@ LL | *ptr.0 = 2; | ^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/dealloc_write_race1.rs:LL:CC + | +LL | let j2 = spawn(move || { + | __________________^ +LL | | let ptr = ptr; // avoid field capturing +LL | | __rust_dealloc( +... | +LL | | ); +LL | | }); + | |__________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race2.stderr b/src/tools/miri/tests/fail/data_race/dealloc_write_race2.stderr index 3a843a4eba5d..2029e0632141 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race2.stderr @@ -20,7 +20,16 @@ LL | | std::mem::size_of::(), LL | | std::mem::align_of::(), LL | | ); | |_____________^ - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/dealloc_write_race2.rs:LL:CC + | +LL | let j2 = spawn(move || { + | __________________^ +LL | | let ptr = ptr; // avoid field capturing +... | +LL | | }); + | |__________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.stderr b/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.stderr index 708fddb8f0be..3ce6e6ce5661 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.stderr @@ -11,7 +11,18 @@ LL | *pointer.load(Ordering::Acquire) = 3; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/dealloc_write_race_stack.rs:LL:CC + | +LL | ... let j1 = spawn(move || { + | ________________^ +LL | | ... let ptr = ptr; // avoid field capturing +LL | | ... let pointer = &*ptr.0; +... | +LL | | ... } +LL | | ... }); + | |________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.stderr b/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.stderr index adcf00c8a88f..f9a18008ab75 100644 --- a/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.stderr +++ b/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.stderr @@ -11,7 +11,16 @@ LL | *c.0 = 32; | ^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/enable_after_join_to_main.rs:LL:CC + | +LL | ... let j2 = spawn(move || { + | ________________^ +LL | | ... let c = c; // avoid field capturing +LL | | ... *c.0 = 64; +LL | | ... }); + | |________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.stderr b/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.stderr index 676a62b8fefe..6caeacfb5e25 100644 --- a/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.stderr +++ b/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.stderr @@ -11,7 +11,16 @@ LL | StorageLive(val); | ^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/local_variable_alloc_race.rs:LL:CC + | +LL | / std::thread::spawn(|| { +LL | | while P.load(Relaxed).is_null() { +LL | | std::hint::spin_loop(); +... | +LL | | }) + | |______^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/local_variable_read_race.stderr b/src/tools/miri/tests/fail/data_race/local_variable_read_race.stderr index 269676caf5c7..5dfa6917e3ba 100644 --- a/src/tools/miri/tests/fail/data_race/local_variable_read_race.stderr +++ b/src/tools/miri/tests/fail/data_race/local_variable_read_race.stderr @@ -11,7 +11,17 @@ LL | let _val = val; | ^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/local_variable_read_race.rs:LL:CC + | +LL | let t1 = std::thread::spawn(|| { + | ______________^ +LL | | while P.load(Relaxed).is_null() { +LL | | std::hint::spin_loop(); +... | +LL | | }); + | |______^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/local_variable_write_race.stderr b/src/tools/miri/tests/fail/data_race/local_variable_write_race.stderr index 5e26e88ce98c..2f9e22f66fff 100644 --- a/src/tools/miri/tests/fail/data_race/local_variable_write_race.stderr +++ b/src/tools/miri/tests/fail/data_race/local_variable_write_race.stderr @@ -11,7 +11,17 @@ LL | let mut val: u8 = 0; | ^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/local_variable_write_race.rs:LL:CC + | +LL | let t1 = std::thread::spawn(|| { + | ______________^ +LL | | while P.load(Relaxed).is_null() { +LL | | std::hint::spin_loop(); +... | +LL | | }); + | |______^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_first_load.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_first_load.stderr index 95b41a232b2c..10b5539a5b8c 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_first_load.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_first_load.stderr @@ -13,7 +13,17 @@ LL | a16.load(Ordering::SeqCst); = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/mixed_size_read_read_write.rs:LL:CC + | +LL | / s.spawn(|| { +LL | | thread::yield_now(); // make sure this happens last +LL | | if cfg!(match_first_load) { +LL | | a16.store(0, Ordering::SeqCst); +... | +LL | | }); + | |__________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_second_load.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_second_load.stderr index 96b0c00e08cc..8e37e6161c31 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_second_load.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_second_load.stderr @@ -13,7 +13,17 @@ LL | a16.load(Ordering::SeqCst); = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/mixed_size_read_read_write.rs:LL:CC + | +LL | / s.spawn(|| { +LL | | thread::yield_now(); // make sure this happens last +LL | | if cfg!(match_first_load) { +LL | | a16.store(0, Ordering::SeqCst); +... | +LL | | }); + | |__________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_write.read_write.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.read_write.stderr index e795f7ec8120..ec86c41cd160 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read_write.read_write.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.read_write.stderr @@ -13,7 +13,17 @@ LL | a8[0].load(Ordering::SeqCst); = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/mixed_size_read_write.rs:LL:CC + | +LL | / s.spawn(|| { +LL | | if cfg!(read_write) { +LL | | // Let the other one go first. +LL | | thread::yield_now(); +... | +LL | | }); + | |__________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_write.write_read.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.write_read.stderr index ecdbb49e8b86..d4d03b96a3e5 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read_write.write_read.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.write_read.stderr @@ -13,7 +13,17 @@ LL | a16.store(1, Ordering::SeqCst); = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/mixed_size_read_write.rs:LL:CC + | +LL | / s.spawn(|| { +LL | | if cfg!(write_read) { +LL | | // Let the other one go first. +LL | | thread::yield_now(); +... | +LL | | }); + | |__________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_write_read.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read_write_read.stderr index be1bb4e507f6..98565708f881 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read_write_read.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_write_read.stderr @@ -19,7 +19,14 @@ LL | | ); = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/mixed_size_read_write_read.rs:LL:CC + | +LL | / ... s.spawn(|| { +LL | | ... let _val = data.load(Ordering::Relaxed); +LL | | ... }); + | |________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.fst.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.fst.stderr index 0b1eac5d5d03..9033bc2c922d 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.fst.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.fst.stderr @@ -13,7 +13,16 @@ LL | a16.store(1, Ordering::SeqCst); = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/mixed_size_write_write.rs:LL:CC + | +LL | / s.spawn(|| { +LL | | let idx = if cfg!(fst) { 0 } else { 1 }; +LL | | a8[idx].store(1, Ordering::SeqCst); +LL | | +LL | | }); + | |__________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.snd.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.snd.stderr index da62f537903a..b0e771c40b91 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.snd.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.snd.stderr @@ -13,7 +13,16 @@ LL | a16.store(1, Ordering::SeqCst); = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/mixed_size_write_write.rs:LL:CC + | +LL | / s.spawn(|| { +LL | | let idx = if cfg!(fst) { 0 } else { 1 }; +LL | | a8[idx].store(1, Ordering::SeqCst); +LL | | +LL | | }); + | |__________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/read_write_race.stderr b/src/tools/miri/tests/fail/data_race/read_write_race.stderr index 9163bff917e4..1922ce949f6b 100644 --- a/src/tools/miri/tests/fail/data_race/read_write_race.stderr +++ b/src/tools/miri/tests/fail/data_race/read_write_race.stderr @@ -11,7 +11,16 @@ LL | let _val = *c.0; | ^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/read_write_race.rs:LL:CC + | +LL | ... let j2 = spawn(move || { + | ________________^ +LL | | ... let c = c; // avoid field capturing +LL | | ... *c.0 = 64; +LL | | ... }); + | |________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/read_write_race_stack.stderr b/src/tools/miri/tests/fail/data_race/read_write_race_stack.stderr index 719a7162690a..a6bdac409d9d 100644 --- a/src/tools/miri/tests/fail/data_race/read_write_race_stack.stderr +++ b/src/tools/miri/tests/fail/data_race/read_write_race_stack.stderr @@ -11,7 +11,17 @@ LL | *pointer.load(Ordering::Acquire) = 3; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/read_write_race_stack.rs:LL:CC + | +LL | ... let j1 = spawn(move || { + | ________________^ +LL | | ... let ptr = ptr; // avoid field capturing +... | +LL | | ... stack_var +LL | | ... }); + | |________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/relax_acquire_race.stderr b/src/tools/miri/tests/fail/data_race/relax_acquire_race.stderr index ea441ab36722..6c77bf6b3d8b 100644 --- a/src/tools/miri/tests/fail/data_race/relax_acquire_race.stderr +++ b/src/tools/miri/tests/fail/data_race/relax_acquire_race.stderr @@ -11,7 +11,18 @@ LL | *c.0 = 1; | ^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/relax_acquire_race.rs:LL:CC + | +LL | ... let j3 = spawn(move || { + | ________________^ +LL | | ... let c = c; // avoid field capturing +LL | | ... if SYNC.load(Ordering::Acquire) == 2 { +LL | | ... *c.0 +... | +LL | | ... }); + | |________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/release_seq_race.stderr b/src/tools/miri/tests/fail/data_race/release_seq_race.stderr index 8cb1fd7ce613..528db7ed2479 100644 --- a/src/tools/miri/tests/fail/data_race/release_seq_race.stderr +++ b/src/tools/miri/tests/fail/data_race/release_seq_race.stderr @@ -11,7 +11,18 @@ LL | *c.0 = 1; | ^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/release_seq_race.rs:LL:CC + | +LL | let j3 = spawn(move || { + | __________________^ +LL | | let c = c; // avoid field capturing +LL | | sleep(Duration::from_millis(500)); +LL | | if SYNC.load(Ordering::Acquire) == 3 { +... | +LL | | }); + | |__________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.stderr b/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.stderr index d9a4b71ca21f..1b2daf8b256b 100644 --- a/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.stderr +++ b/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.stderr @@ -11,7 +11,18 @@ LL | *c.0 = 1; | ^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/release_seq_race_same_thread.rs:LL:CC + | +LL | ... let j2 = spawn(move || { + | ________________^ +LL | | ... let c = c; // avoid field capturing +LL | | ... if SYNC.load(Ordering::Acquire) == 2 { +LL | | ... *c.0 +... | +LL | | ... }); + | |________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/rmw_race.stderr b/src/tools/miri/tests/fail/data_race/rmw_race.stderr index c1eeef1dca76..21f710e16b0d 100644 --- a/src/tools/miri/tests/fail/data_race/rmw_race.stderr +++ b/src/tools/miri/tests/fail/data_race/rmw_race.stderr @@ -11,7 +11,18 @@ LL | *c.0 = 1; | ^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/rmw_race.rs:LL:CC + | +LL | ... let j3 = spawn(move || { + | ________________^ +LL | | ... let c = c; // capture `c`, not just its field. +LL | | ... if SYNC.load(Ordering::Acquire) == 3 { +LL | | ... *c.0 +... | +LL | | ... }); + | |________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/write_write_race.stderr b/src/tools/miri/tests/fail/data_race/write_write_race.stderr index 13f798e4da56..112cdb278196 100644 --- a/src/tools/miri/tests/fail/data_race/write_write_race.stderr +++ b/src/tools/miri/tests/fail/data_race/write_write_race.stderr @@ -11,7 +11,16 @@ LL | *c.0 = 32; | ^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/write_write_race.rs:LL:CC + | +LL | ... let j2 = spawn(move || { + | ________________^ +LL | | ... let c = c; // avoid field capturing +LL | | ... *c.0 = 64; +LL | | ... }); + | |________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/write_write_race_stack.stderr b/src/tools/miri/tests/fail/data_race/write_write_race_stack.stderr index eb8c2747b40e..c70dbb4e619f 100644 --- a/src/tools/miri/tests/fail/data_race/write_write_race_stack.stderr +++ b/src/tools/miri/tests/fail/data_race/write_write_race_stack.stderr @@ -11,7 +11,17 @@ LL | *pointer.load(Ordering::Acquire) = 3; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/data_race/write_write_race_stack.rs:LL:CC + | +LL | let j1 = spawn(move || { + | __________________^ +LL | | let ptr = ptr; // avoid field capturing +... | +LL | | stack_var +LL | | }); + | |__________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/shims/ctor_ub.rs b/src/tools/miri/tests/fail/shims/ctor_ub.rs new file mode 100644 index 000000000000..860f602e69d0 --- /dev/null +++ b/src/tools/miri/tests/fail/shims/ctor_ub.rs @@ -0,0 +1,39 @@ +unsafe extern "C" fn ctor() { + std::hint::unreachable_unchecked() + //~^ERROR: unreachable +} + +#[rustfmt::skip] +macro_rules! ctor { + ($ident:ident = $ctor:ident) => { + #[cfg_attr( + all(any( + target_os = "linux", + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_os = "none", + target_family = "wasm", + )), + link_section = ".init_array" + )] + #[cfg_attr(windows, link_section = ".CRT$XCU")] + #[cfg_attr( + any(target_os = "macos", target_os = "ios"), + // We do not set the `mod_init_funcs` flag here since ctor/inventory also do not do + // that. See . + link_section = "__DATA,__mod_init_func" + )] + #[used] + static $ident: unsafe extern "C" fn() = $ctor; + }; +} + +ctor! { CTOR = ctor } + +fn main() {} diff --git a/src/tools/miri/tests/fail/shims/ctor_ub.stderr b/src/tools/miri/tests/fail/shims/ctor_ub.stderr new file mode 100644 index 000000000000..ab8a8f633638 --- /dev/null +++ b/src/tools/miri/tests/fail/shims/ctor_ub.stderr @@ -0,0 +1,23 @@ +error: Undefined Behavior: entering unreachable code + --> tests/fail/shims/ctor_ub.rs:LL:CC + | +LL | std::hint::unreachable_unchecked() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is inside `ctor` +note: which got called indirectly due to this code + --> tests/fail/shims/ctor_ub.rs:LL:CC + | +LL | static $ident: unsafe extern "C" fn() = $ctor; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | ctor! { CTOR = ctor } + | --------------------- in this macro invocation + = note: this error originates in the macro `ctor` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr index c8662628c033..f50b05712ee2 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr @@ -14,7 +14,18 @@ LL | unsafe { ptr.0.read() }; = help: therefore from the perspective of data races, a retag has the same implications as a read or write = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/stacked_borrows/retag_data_race_protected_read.rs:LL:CC + | +LL | let t = thread::spawn(move || { + | _____________^ +LL | | let ptr = ptr; +LL | | // We do a protected mutable retag (but no write!) in this thread. +LL | | fn retag(_x: &mut i32) {} +LL | | retag(unsafe { &mut *ptr.0 }); +LL | | }); + | |______^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr index 3a95e13f5bc0..67b1cdab911a 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr @@ -24,6 +24,11 @@ note: which got called inside closure | LL | let t2 = std::thread::spawn(move || thread_2(p)); | ^^^^^^^^^^^ +note: which got called indirectly due to this code + --> tests/fail/stacked_borrows/retag_data_race_read.rs:LL:CC + | +LL | let t2 = std::thread::spawn(move || thread_2(p)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr index c5a0b58c2185..3567340f2202 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr @@ -32,7 +32,19 @@ help: the accessed tag later transitioned to Disabled due to a foreign wri LL | *x = 64; | ^^^^^^^ = help: this transition corresponds to a loss of read and write permissions - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/tree_borrows/reservedim_spurious_write.rs:LL:CC + | +LL | let thread_2 = thread::spawn(move || { + | ____________________^ +LL | | let b = (2, by); +LL | | synchronized!(b, "start"); +LL | | let ptr = ptr; +... | +LL | | synchronized!(b, "end"); +LL | | }); + | |______^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr index 75c11f09ce52..a28730abd953 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr @@ -32,7 +32,19 @@ help: the accessed tag later transitioned to Disabled due to a protector r LL | } | ^ = help: this transition corresponds to a loss of read and write permissions - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/tree_borrows/reservedim_spurious_write.rs:LL:CC + | +LL | let thread_2 = thread::spawn(move || { + | ____________________^ +LL | | let b = (2, by); +LL | | synchronized!(b, "start"); +LL | | let ptr = ptr; +... | +LL | | synchronized!(b, "end"); +LL | | }); + | |______^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/spurious_read.stderr b/src/tools/miri/tests/fail/tree_borrows/spurious_read.stderr index eef8766fd652..9e20ec238ed8 100644 --- a/src/tools/miri/tests/fail/tree_borrows/spurious_read.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/spurious_read.stderr @@ -41,6 +41,18 @@ note: which got called inside closure | LL | let _y = as_mut(unsafe { &mut *ptr.0 }, b.clone()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: which got called indirectly due to this code + --> tests/fail/tree_borrows/spurious_read.rs:LL:CC + | +LL | let thread_y = thread::spawn(move || { + | ____________________^ +LL | | let b = (2, by); +LL | | synchronized!(b, "start"); +LL | | let ptr = ptr; +... | +LL | | synchronized!(b, "end"); +LL | | }); + | |______^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/weak_memory/weak_uninit.stderr b/src/tools/miri/tests/fail/weak_memory/weak_uninit.stderr index 605767db22b1..9f3792e0e409 100644 --- a/src/tools/miri/tests/fail/weak_memory/weak_uninit.stderr +++ b/src/tools/miri/tests/fail/weak_memory/weak_uninit.stderr @@ -6,7 +6,12 @@ LL | let j2 = spawn(move || x.load(Ordering::Relaxed)); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID` + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/fail/weak_memory/weak_uninit.rs:LL:CC + | +LL | let j2 = spawn(move || x.load(Ordering::Relaxed)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/genmc/fail/atomics/atomic_ptr_double_free.stderr b/src/tools/miri/tests/genmc/fail/atomics/atomic_ptr_double_free.stderr index 333405a9172b..85e2810f1f30 100644 --- a/src/tools/miri/tests/genmc/fail/atomics/atomic_ptr_double_free.stderr +++ b/src/tools/miri/tests/genmc/fail/atomics/atomic_ptr_double_free.stderr @@ -33,6 +33,16 @@ note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{clos | LL | f(); | ^^^ +note: which got called indirectly due to this code + --> tests/genmc/fail/atomics/../../../utils/genmc.rs:LL:CC + | +LL | / libc::pthread_create( +LL | | &raw mut thread_id, +LL | | attr, +LL | | thread_func::, +LL | | Box::into_raw(f) as *mut c_void, +LL | | ) + | |_________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_alloc_race.dealloc.stderr b/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_alloc_race.dealloc.stderr index 6ec5843c3a0c..4bca53961f5f 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_alloc_race.dealloc.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_alloc_race.dealloc.stderr @@ -14,6 +14,16 @@ note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{clos | LL | f(); | ^^^ +note: which got called indirectly due to this code + --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC + | +LL | / libc::pthread_create( +LL | | &raw mut thread_id, +LL | | attr, +LL | | thread_func::, +LL | | Box::into_raw(f) as *mut c_void, +LL | | ) + | |_________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_alloc_race.write.stderr b/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_alloc_race.write.stderr index fb29e326ba83..0a03363285b6 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_alloc_race.write.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_alloc_race.write.stderr @@ -14,6 +14,16 @@ note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{clos | LL | f(); | ^^^ +note: which got called indirectly due to this code + --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC + | +LL | / libc::pthread_create( +LL | | &raw mut thread_id, +LL | | attr, +LL | | thread_func::, +LL | | Box::into_raw(f) as *mut c_void, +LL | | ) + | |_________^ note: add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report diff --git a/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_dealloc_write_race.stderr b/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_dealloc_write_race.stderr index e4af214bfb99..29a2e371bb3c 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_dealloc_write_race.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_dealloc_write_race.stderr @@ -28,6 +28,16 @@ note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{clos | LL | f(); | ^^^ +note: which got called indirectly due to this code + --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC + | +LL | / libc::pthread_create( +LL | | &raw mut thread_id, +LL | | attr, +LL | | thread_func::, +LL | | Box::into_raw(f) as *mut c_void, +LL | | ) + | |_________^ note: add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report diff --git a/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_write_dealloc_race.stderr b/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_write_dealloc_race.stderr index f5986d50bafc..3f5d0bdf346e 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_write_dealloc_race.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_write_dealloc_race.stderr @@ -14,6 +14,16 @@ note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{clos | LL | f(); | ^^^ +note: which got called indirectly due to this code + --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC + | +LL | / libc::pthread_create( +LL | | &raw mut thread_id, +LL | | attr, +LL | | thread_func::, +LL | | Box::into_raw(f) as *mut c_void, +LL | | ) + | |_________^ note: add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report diff --git a/src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.stderr b/src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.stderr index b061b9029b3d..48b8a16c8b10 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.stderr @@ -14,6 +14,16 @@ note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{clos | LL | f(); | ^^^ +note: which got called indirectly due to this code + --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC + | +LL | / libc::pthread_create( +LL | | &raw mut thread_id, +LL | | attr, +LL | | thread_func::, +LL | | Box::into_raw(f) as *mut c_void, +LL | | ) + | |_________^ note: add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report diff --git a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rel_rlx.stderr b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rel_rlx.stderr index ad5047be60c1..2eb3791aaf08 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rel_rlx.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rel_rlx.stderr @@ -14,6 +14,16 @@ note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{clos | LL | f(); | ^^^ +note: which got called indirectly due to this code + --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC + | +LL | / libc::pthread_create( +LL | | &raw mut thread_id, +LL | | attr, +LL | | thread_func::, +LL | | Box::into_raw(f) as *mut c_void, +LL | | ) + | |_________^ note: add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report diff --git a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_acq.stderr b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_acq.stderr index ad5047be60c1..2eb3791aaf08 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_acq.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_acq.stderr @@ -14,6 +14,16 @@ note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{clos | LL | f(); | ^^^ +note: which got called indirectly due to this code + --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC + | +LL | / libc::pthread_create( +LL | | &raw mut thread_id, +LL | | attr, +LL | | thread_func::, +LL | | Box::into_raw(f) as *mut c_void, +LL | | ) + | |_________^ note: add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report diff --git a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_rlx.stderr b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_rlx.stderr index ad5047be60c1..2eb3791aaf08 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_rlx.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_rlx.stderr @@ -14,6 +14,16 @@ note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{clos | LL | f(); | ^^^ +note: which got called indirectly due to this code + --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC + | +LL | / libc::pthread_create( +LL | | &raw mut thread_id, +LL | | attr, +LL | | thread_func::, +LL | | Box::into_raw(f) as *mut c_void, +LL | | ) + | |_________^ note: add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report diff --git a/src/tools/miri/tests/genmc/fail/shims/exit.stderr b/src/tools/miri/tests/genmc/fail/shims/exit.stderr index f27860b82fe7..573c8b14fae3 100644 --- a/src/tools/miri/tests/genmc/fail/shims/exit.stderr +++ b/src/tools/miri/tests/genmc/fail/shims/exit.stderr @@ -7,6 +7,14 @@ LL | unsafe { std::hint::unreachable_unchecked() }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID`, inside closure +note: which got called indirectly due to this code + --> tests/genmc/fail/shims/exit.rs:LL:CC + | +LL | / std::thread::spawn(|| { +LL | | unsafe { std::hint::unreachable_unchecked() }; +LL | | }); + | |______^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/genmc/fail/shims/mutex_diff_thread_unlock.stderr b/src/tools/miri/tests/genmc/fail/shims/mutex_diff_thread_unlock.stderr index 5adfb066e6f1..e32548c4b5d5 100644 --- a/src/tools/miri/tests/genmc/fail/shims/mutex_diff_thread_unlock.stderr +++ b/src/tools/miri/tests/genmc/fail/shims/mutex_diff_thread_unlock.stderr @@ -16,6 +16,15 @@ note: which got called inside closure | LL | drop(guard); | ^^^^^^^^^^^ +note: which got called indirectly due to this code + --> tests/genmc/fail/shims/mutex_diff_thread_unlock.rs:LL:CC + | +LL | let handle = std::thread::spawn(move || { + | __________________^ +LL | | let guard = guard; // avoid field capturing +LL | | drop(guard); +LL | | }); + | |______^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.stderr b/src/tools/miri/tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.stderr index 71a01d8f754b..6d597aaa6342 100644 --- a/src/tools/miri/tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.stderr +++ b/src/tools/miri/tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.stderr @@ -17,5 +17,15 @@ note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{clos | LL | f(); | ^^^ +note: which got called indirectly due to this code + --> tests/genmc/pass/atomics/../../../utils/genmc.rs:LL:CC + | +LL | / libc::pthread_create( +LL | | &raw mut thread_id, +LL | | attr, +LL | | thread_func::, +LL | | Box::into_raw(f) as *mut c_void, +LL | | ) + | |_________^ Verification complete with 2 executions. No errors found. From b12b766cf33791020f453198f1545592c424c3c3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 7 Dec 2025 10:43:07 +0100 Subject: [PATCH 0099/1061] fix previously dead android tests and remove some dangling files --- src/tools/miri/ci/ci.sh | 2 +- .../libc/prctl-get-name-buffer-too-small.rs | 2 +- .../prctl-get-name-buffer-too-small.stderr | 10 +++---- .../libc/socketpair_read_blocking.stderr | 13 ---------- .../libc/socketpair_write_blocking.stderr | 13 ---------- .../data_race/mixed_size_write_write.stderr | 22 ---------------- .../retag_data_race_read.stack.stderr | 25 ------------------ .../retag_data_race_read.tree.stderr | 26 ------------------- 8 files changed, 6 insertions(+), 107 deletions(-) delete mode 100644 src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.stderr delete mode 100644 src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.stderr delete mode 100644 src/tools/miri/tests/fail/data_race/mixed_size_write_write.stderr delete mode 100644 src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stack.stderr delete mode 100644 src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.tree.stderr diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 2d27f0274999..2dd8fc77459a 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -152,7 +152,7 @@ case $HOST_TARGET in # Partially supported targets (tier 2) BASIC="empty_main integer heap_alloc libc-mem vec string btreemap" # ensures we have the basics: pre-main code, system allocator UNIX="hello panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there - TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency epoll eventfd + TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency epoll eventfd prctl TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std ;; diff --git a/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.rs b/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.rs index 4b731866aca1..d923667d8741 100644 --- a/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.rs +++ b/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.rs @@ -5,6 +5,6 @@ fn main() { let mut buf = vec![0u8; 15]; unsafe { - libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr().cast::()); //~ ERROR: memory access failed: expected a pointer to 16 bytes of memory, but got alloc952 which is only 15 bytes from the end of the allocation + libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr().cast::()); //~ ERROR: memory access failed } } diff --git a/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.stderr b/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.stderr index 275a38e593c8..cc50564a43f5 100644 --- a/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.stderr +++ b/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.stderr @@ -1,18 +1,16 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 16 bytes of memory, but got ALLOC which is only 15 bytes from the end of the allocation - --> tests/fail-dep/libc/prctl-threadname.rs:LL:CC +error: Undefined Behavior: memory access failed: attempting to access 16 bytes, but got ALLOC which is only 15 bytes from the end of the allocation + --> tests/fail-dep/libc/prctl-get-name-buffer-too-small.rs:LL:CC | LL | libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr().cast::()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 16 bytes of memory, but got ALLOC which is only 15 bytes from the end of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information help: ALLOC was allocated here: - --> tests/fail-dep/libc/prctl-threadname.rs:LL:CC + --> tests/fail-dep/libc/prctl-get-name-buffer-too-small.rs:LL:CC | LL | let mut buf = vec![0u8; 15]; | ^^^^^^^^^^^^^ - = note: BACKTRACE (of the first span): - = note: inside `main` at tests/fail-dep/libc/prctl-threadname.rs:LL:CC = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.stderr deleted file mode 100644 index caf23da1150f..000000000000 --- a/src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error: deadlock: the evaluated program deadlocked - --> tests/fail-dep/libc/socketpair_read_blocking.rs:LL:CC - | -LL | let _res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) }; - | ^ the evaluated program deadlocked - | - = note: BACKTRACE: - = note: inside `main` at tests/fail-dep/libc/socketpair_read_blocking.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.stderr deleted file mode 100644 index 2dc420d5f1ef..000000000000 --- a/src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error: deadlock: the evaluated program deadlocked - --> tests/fail-dep/libc/socketpair_write_blocking.rs:LL:CC - | -LL | let _ = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) }; - | ^ the evaluated program deadlocked - | - = note: BACKTRACE: - = note: inside `main` at tests/fail-dep/libc/socketpair_write_blocking.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.stderr deleted file mode 100644 index 1f22413bc5f9..000000000000 --- a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error: Undefined Behavior: Race condition detected between (1) 2-byte atomic store on thread `unnamed-ID` and (2) 1-byte atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here - --> tests/fail/data_race/mixed_size_write_write.rs:LL:CC - | -LL | a8[0].store(1, Ordering::SeqCst); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 2-byte atomic store on thread `unnamed-ID` and (2) 1-byte atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here - | -help: and (1) occurred earlier here - --> tests/fail/data_race/mixed_size_write_write.rs:LL:CC - | -LL | a16.store(1, Ordering::SeqCst); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: overlapping unsynchronized atomic accesses must use the same access size - = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at tests/fail/data_race/mixed_size_write_write.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stack.stderr b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stack.stderr deleted file mode 100644 index 1d7ea18982d1..000000000000 --- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stack.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error: Undefined Behavior: Data race detected between (1) Read on thread `unnamed-ID` and (2) Write on thread `unnamed-ID` at ALLOC. (2) just happened here - --> $DIR/retag_data_race_read.rs:LL:CC - | -LL | *p = 5; - | ^^^^^^ Data race detected between (1) Read on thread `unnamed-ID` and (2) Write on thread `unnamed-ID` at ALLOC. (2) just happened here - | -help: and (1) occurred earlier here - --> $DIR/retag_data_race_read.rs:LL:CC - | -LL | let _r = &*p; - | ^^^ - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE (of the first span): - = note: inside `thread_2` at $DIR/retag_data_race_read.rs:LL:CC -note: inside closure - --> $DIR/retag_data_race_read.rs:LL:CC - | -LL | let t2 = std::thread::spawn(move || thread_2(p)); - | ^^^^^^^^^^^ - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.tree.stderr b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.tree.stderr deleted file mode 100644 index e6c1745d321c..000000000000 --- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.tree.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error: Undefined Behavior: reborrow through (root of the allocation) is forbidden - --> RUSTLIB/std/src/rt.rs:LL:CC - | -LL | panic::catch_unwind(move || unsafe { init(argc, argv, sigpipe) }).map_err(rt_abort)?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reborrow through (root of the allocation) is forbidden - | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental - = help: the accessed tag (root of the allocation) is foreign to the protected tag (i.e., it is not a child) - = help: this reborrow (acting as a foreign read access) would cause the protected tag (currently Active) to become Disabled - = help: protected tags must never be Disabled -help: the accessed tag was created here - --> RUSTLIB/std/src/rt.rs:LL:CC - | -LL | panic::catch_unwind(move || unsafe { init(argc, argv, sigpipe) }).map_err(rt_abort)?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: the protected tag was created here, in the initial state Active - --> RUSTLIB/std/src/panic.rs:LL:CC - | -LL | fn catch_unwind R + UnwindSafe, R>(f: F) -> Result { - | ^ - = note: BACKTRACE (of the first span): - = note: inside `std::rt::lang_start_internal` at RUSTLIB/std/src/rt.rs:LL:CC - = note: inside `std::rt::lang_start::<()>` at RUSTLIB/std/src/rt.rs:LL:CC - -error: aborting due to 1 previous error - From 065791ee0603a45fefd686fb13b1e55dbf831ab3 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Wed, 5 Nov 2025 13:01:12 -0800 Subject: [PATCH 0100/1061] Add allocator parameter to HashMap --- library/std/src/collections/hash/map.rs | 289 ++++++++++++++++++------ 1 file changed, 216 insertions(+), 73 deletions(-) diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 251d62bd2033..ad6328f76ed6 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -4,6 +4,7 @@ mod tests; use hashbrown::hash_map as base; use self::Entry::*; +use crate::alloc::{Allocator, Global}; use crate::borrow::Borrow; use crate::collections::{TryReserveError, TryReserveErrorKind}; use crate::error::Error; @@ -243,8 +244,13 @@ use crate::ops::Index; #[cfg_attr(not(test), rustc_diagnostic_item = "HashMap")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_insignificant_dtor] -pub struct HashMap { - base: base::HashMap, +pub struct HashMap< + K, + V, + S = RandomState, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::HashMap, } impl HashMap { @@ -286,6 +292,46 @@ impl HashMap { } } +impl HashMap { + /// Creates an empty `HashMap` using the given allocator. + /// + /// The hash map is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// let mut map: HashMap<&str, i32> = HashMap::new(); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn new_in(alloc: A) -> Self { + HashMap::with_hasher_in(Default::default(), alloc) + } + + /// Creates an empty `HashMap` with at least the specified capacity using + /// the given allocator. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is zero, the hash map will not allocate. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// let mut map: HashMap<&str, i32> = HashMap::with_capacity(10); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + HashMap::with_capacity_and_hasher_in(capacity, Default::default(), alloc) + } +} + impl HashMap { /// Creates an empty `HashMap` which will use the given hash builder to hash /// keys. @@ -347,6 +393,47 @@ impl HashMap { pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashMap { HashMap { base: base::HashMap::with_capacity_and_hasher(capacity, hasher) } } +} + +impl HashMap { + /// Creates an empty `HashMap` which will use the given hash builder and + /// allocator. + /// + /// The created map has the default initial capacity. + /// + /// Warning: `hash_builder` is normally randomly generated, and + /// is designed to allow HashMaps to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashMap` to be useful, see its documentation for details. + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn with_hasher_in(hash_builder: S, alloc: A) -> Self { + HashMap { base: base::HashMap::with_hasher_in(hash_builder, alloc) } + } + + /// Creates an empty `HashMap` with at least the specified capacity, using + /// `hasher` to hash the keys and `alloc` to allocate memory. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is zero, the hash map will not allocate. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow HashMaps to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hasher` passed should implement the [`BuildHasher`] trait for + /// the `HashMap` to be useful, see its documentation for details. + /// + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn with_capacity_and_hasher_in(capacity: usize, hash_builder: S, alloc: A) -> Self { + HashMap { base: base::HashMap::with_capacity_and_hasher_in(capacity, hash_builder, alloc) } + } /// Returns the number of elements the map can hold without reallocating. /// @@ -424,7 +511,7 @@ impl HashMap { #[inline] #[rustc_lint_query_instability] #[stable(feature = "map_into_keys_values", since = "1.54.0")] - pub fn into_keys(self) -> IntoKeys { + pub fn into_keys(self) -> IntoKeys { IntoKeys { inner: self.into_iter() } } @@ -519,7 +606,7 @@ impl HashMap { #[inline] #[rustc_lint_query_instability] #[stable(feature = "map_into_keys_values", since = "1.54.0")] - pub fn into_values(self) -> IntoValues { + pub fn into_values(self) -> IntoValues { IntoValues { inner: self.into_iter() } } @@ -648,7 +735,7 @@ impl HashMap { #[inline] #[rustc_lint_query_instability] #[stable(feature = "drain", since = "1.6.0")] - pub fn drain(&mut self) -> Drain<'_, K, V> { + pub fn drain(&mut self) -> Drain<'_, K, V, A> { Drain { base: self.base.drain() } } @@ -688,7 +775,7 @@ impl HashMap { #[inline] #[rustc_lint_query_instability] #[stable(feature = "hash_extract_if", since = "1.88.0")] - pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, K, V, F> + pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, K, V, F, A> where F: FnMut(&K, &mut V) -> bool, { @@ -762,10 +849,11 @@ impl HashMap { } } -impl HashMap +impl HashMap where K: Eq + Hash, S: BuildHasher, + A: Allocator, { /// Reserves capacity for at least `additional` more elements to be inserted /// in the `HashMap`. The collection may reserve more space to speculatively @@ -884,7 +972,7 @@ where /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn entry(&mut self, key: K) -> Entry<'_, K, V> { + pub fn entry(&mut self, key: K) -> Entry<'_, K, V, A> { map_entry(self.base.rustc_entry(key)) } @@ -1232,7 +1320,7 @@ where /// assert_eq!(err.value, "b"); /// ``` #[unstable(feature = "map_try_insert", issue = "82766")] - pub fn try_insert(&mut self, key: K, value: V) -> Result<&mut V, OccupiedError<'_, K, V>> { + pub fn try_insert(&mut self, key: K, value: V) -> Result<&mut V, OccupiedError<'_, K, V, A>> { match self.entry(key) { Occupied(entry) => Err(OccupiedError { entry, value }), Vacant(entry) => Ok(entry.insert(value)), @@ -1298,11 +1386,12 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for HashMap +impl Clone for HashMap where K: Clone, V: Clone, S: Clone, + A: Allocator + Clone, { #[inline] fn clone(&self) -> Self { @@ -1316,13 +1405,14 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for HashMap +impl PartialEq for HashMap where K: Eq + Hash, V: PartialEq, S: BuildHasher, + A: Allocator, { - fn eq(&self, other: &HashMap) -> bool { + fn eq(&self, other: &HashMap) -> bool { if self.len() != other.len() { return false; } @@ -1332,19 +1422,21 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Eq for HashMap +impl Eq for HashMap where K: Eq + Hash, V: Eq, S: BuildHasher, + A: Allocator, { } #[stable(feature = "rust1", since = "1.0.0")] -impl Debug for HashMap +impl Debug for HashMap where K: Debug, V: Debug, + A: Allocator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_map().entries(self.iter()).finish() @@ -1364,11 +1456,12 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Index<&Q> for HashMap +impl Index<&Q> for HashMap where K: Eq + Hash + Borrow, Q: Eq + Hash, S: BuildHasher, + A: Allocator, { type Output = V; @@ -1523,11 +1616,15 @@ impl Default for IterMut<'_, K, V> { /// let iter = map.into_iter(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub struct IntoIter { - base: base::IntoIter, +pub struct IntoIter< + K, + V, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::IntoIter, } -impl IntoIter { +impl IntoIter { /// Returns an iterator of references over the remaining items. #[inline] pub(super) fn iter(&self) -> Iter<'_, K, V> { @@ -1656,11 +1753,16 @@ impl fmt::Debug for Values<'_, K, V> { /// ``` #[stable(feature = "drain", since = "1.6.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_drain_ty")] -pub struct Drain<'a, K: 'a, V: 'a> { - base: base::Drain<'a, K, V>, +pub struct Drain< + 'a, + K: 'a, + V: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::Drain<'a, K, V, A>, } -impl<'a, K, V> Drain<'a, K, V> { +impl<'a, K, V, A: Allocator> Drain<'a, K, V, A> { /// Returns an iterator of references over the remaining items. #[inline] pub(super) fn iter(&self) -> Iter<'_, K, V> { @@ -1687,8 +1789,14 @@ impl<'a, K, V> Drain<'a, K, V> { #[stable(feature = "hash_extract_if", since = "1.88.0")] #[must_use = "iterators are lazy and do nothing unless consumed; \ use `retain` to remove and discard elements"] -pub struct ExtractIf<'a, K, V, F> { - base: base::ExtractIf<'a, K, V, F>, +pub struct ExtractIf< + 'a, + K, + V, + F, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::ExtractIf<'a, K, V, F, A>, } /// A mutable iterator over the values of a `HashMap`. @@ -1740,8 +1848,12 @@ impl Default for ValuesMut<'_, K, V> { /// let iter_keys = map.into_keys(); /// ``` #[stable(feature = "map_into_keys_values", since = "1.54.0")] -pub struct IntoKeys { - inner: IntoIter, +pub struct IntoKeys< + K, + V, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + inner: IntoIter, } #[stable(feature = "default_iters_hash", since = "1.83.0")] @@ -1770,8 +1882,12 @@ impl Default for IntoKeys { /// let iter_keys = map.into_values(); /// ``` #[stable(feature = "map_into_keys_values", since = "1.54.0")] -pub struct IntoValues { - inner: IntoIter, +pub struct IntoValues< + K, + V, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + inner: IntoIter, } #[stable(feature = "default_iters_hash", since = "1.83.0")] @@ -1789,14 +1905,19 @@ impl Default for IntoValues { /// [`entry`]: HashMap::entry #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "HashMapEntry")] -pub enum Entry<'a, K: 'a, V: 'a> { +pub enum Entry< + 'a, + K: 'a, + V: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { /// An occupied entry. #[stable(feature = "rust1", since = "1.0.0")] - Occupied(#[stable(feature = "rust1", since = "1.0.0")] OccupiedEntry<'a, K, V>), + Occupied(#[stable(feature = "rust1", since = "1.0.0")] OccupiedEntry<'a, K, V, A>), /// A vacant entry. #[stable(feature = "rust1", since = "1.0.0")] - Vacant(#[stable(feature = "rust1", since = "1.0.0")] VacantEntry<'a, K, V>), + Vacant(#[stable(feature = "rust1", since = "1.0.0")] VacantEntry<'a, K, V, A>), } #[stable(feature = "debug_hash_map", since = "1.12.0")] @@ -1812,12 +1933,17 @@ impl Debug for Entry<'_, K, V> { /// A view into an occupied entry in a `HashMap`. /// It is part of the [`Entry`] enum. #[stable(feature = "rust1", since = "1.0.0")] -pub struct OccupiedEntry<'a, K: 'a, V: 'a> { - base: base::RustcOccupiedEntry<'a, K, V>, +pub struct OccupiedEntry< + 'a, + K: 'a, + V: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::RustcOccupiedEntry<'a, K, V, A>, } #[stable(feature = "debug_hash_map", since = "1.12.0")] -impl Debug for OccupiedEntry<'_, K, V> { +impl Debug for OccupiedEntry<'_, K, V, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OccupiedEntry") .field("key", self.key()) @@ -1829,12 +1955,17 @@ impl Debug for OccupiedEntry<'_, K, V> { /// A view into a vacant entry in a `HashMap`. /// It is part of the [`Entry`] enum. #[stable(feature = "rust1", since = "1.0.0")] -pub struct VacantEntry<'a, K: 'a, V: 'a> { - base: base::RustcVacantEntry<'a, K, V>, +pub struct VacantEntry< + 'a, + K: 'a, + V: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::RustcVacantEntry<'a, K, V, A>, } #[stable(feature = "debug_hash_map", since = "1.12.0")] -impl Debug for VacantEntry<'_, K, V> { +impl Debug for VacantEntry<'_, K, V, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("VacantEntry").field(self.key()).finish() } @@ -1844,15 +1975,20 @@ impl Debug for VacantEntry<'_, K, V> { /// /// Contains the occupied entry, and the value that was not inserted. #[unstable(feature = "map_try_insert", issue = "82766")] -pub struct OccupiedError<'a, K: 'a, V: 'a> { +pub struct OccupiedError< + 'a, + K: 'a, + V: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { /// The entry in the map that was already occupied. - pub entry: OccupiedEntry<'a, K, V>, + pub entry: OccupiedEntry<'a, K, V, A>, /// The value which was not inserted, because the entry was already occupied. pub value: V, } #[unstable(feature = "map_try_insert", issue = "82766")] -impl Debug for OccupiedError<'_, K, V> { +impl Debug for OccupiedError<'_, K, V, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OccupiedError") .field("key", self.entry.key()) @@ -1863,7 +1999,7 @@ impl Debug for OccupiedError<'_, K, V> { } #[unstable(feature = "map_try_insert", issue = "82766")] -impl<'a, K: Debug, V: Debug> fmt::Display for OccupiedError<'a, K, V> { +impl<'a, K: Debug, V: Debug, A: Allocator> fmt::Display for OccupiedError<'a, K, V, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, @@ -1876,10 +2012,10 @@ impl<'a, K: Debug, V: Debug> fmt::Display for OccupiedError<'a, K, V> { } #[unstable(feature = "map_try_insert", issue = "82766")] -impl<'a, K: Debug, V: Debug> Error for OccupiedError<'a, K, V> {} +impl<'a, K: Debug, V: Debug, A: Allocator> Error for OccupiedError<'a, K, V, A> {} #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V, S> IntoIterator for &'a HashMap { +impl<'a, K, V, S, A: Allocator> IntoIterator for &'a HashMap { type Item = (&'a K, &'a V); type IntoIter = Iter<'a, K, V>; @@ -1891,7 +2027,7 @@ impl<'a, K, V, S> IntoIterator for &'a HashMap { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V, S> IntoIterator for &'a mut HashMap { +impl<'a, K, V, S, A: Allocator> IntoIterator for &'a mut HashMap { type Item = (&'a K, &'a mut V); type IntoIter = IterMut<'a, K, V>; @@ -1903,9 +2039,9 @@ impl<'a, K, V, S> IntoIterator for &'a mut HashMap { } #[stable(feature = "rust1", since = "1.0.0")] -impl IntoIterator for HashMap { +impl IntoIterator for HashMap { type Item = (K, V); - type IntoIter = IntoIter; + type IntoIter = IntoIter; /// Creates a consuming iterator, that is, one that moves each key-value /// pair out of the map in arbitrary order. The map cannot be used after @@ -1927,7 +2063,7 @@ impl IntoIterator for HashMap { /// ``` #[inline] #[rustc_lint_query_instability] - fn into_iter(self) -> IntoIter { + fn into_iter(self) -> IntoIter { IntoIter { base: self.base.into_iter() } } } @@ -2015,7 +2151,7 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for IntoIter { +impl Iterator for IntoIter { type Item = (K, V); #[inline] @@ -2040,17 +2176,17 @@ impl Iterator for IntoIter { } } #[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for IntoIter { +impl ExactSizeIterator for IntoIter { #[inline] fn len(&self) -> usize { self.base.len() } } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for IntoIter {} +impl FusedIterator for IntoIter {} #[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for IntoIter { +impl fmt::Debug for IntoIter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.iter()).finish() } @@ -2169,7 +2305,7 @@ impl fmt::Debug for ValuesMut<'_, K, V> { } #[stable(feature = "map_into_keys_values", since = "1.54.0")] -impl Iterator for IntoKeys { +impl Iterator for IntoKeys { type Item = K; #[inline] @@ -2194,24 +2330,24 @@ impl Iterator for IntoKeys { } } #[stable(feature = "map_into_keys_values", since = "1.54.0")] -impl ExactSizeIterator for IntoKeys { +impl ExactSizeIterator for IntoKeys { #[inline] fn len(&self) -> usize { self.inner.len() } } #[stable(feature = "map_into_keys_values", since = "1.54.0")] -impl FusedIterator for IntoKeys {} +impl FusedIterator for IntoKeys {} #[stable(feature = "map_into_keys_values", since = "1.54.0")] -impl fmt::Debug for IntoKeys { +impl fmt::Debug for IntoKeys { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.inner.iter().map(|(k, _)| k)).finish() } } #[stable(feature = "map_into_keys_values", since = "1.54.0")] -impl Iterator for IntoValues { +impl Iterator for IntoValues { type Item = V; #[inline] @@ -2236,24 +2372,24 @@ impl Iterator for IntoValues { } } #[stable(feature = "map_into_keys_values", since = "1.54.0")] -impl ExactSizeIterator for IntoValues { +impl ExactSizeIterator for IntoValues { #[inline] fn len(&self) -> usize { self.inner.len() } } #[stable(feature = "map_into_keys_values", since = "1.54.0")] -impl FusedIterator for IntoValues {} +impl FusedIterator for IntoValues {} #[stable(feature = "map_into_keys_values", since = "1.54.0")] -impl fmt::Debug for IntoValues { +impl fmt::Debug for IntoValues { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.inner.iter().map(|(_, v)| v)).finish() } } #[stable(feature = "drain", since = "1.6.0")] -impl<'a, K, V> Iterator for Drain<'a, K, V> { +impl<'a, K, V, A: Allocator> Iterator for Drain<'a, K, V, A> { type Item = (K, V); #[inline] @@ -2274,17 +2410,17 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> { } } #[stable(feature = "drain", since = "1.6.0")] -impl ExactSizeIterator for Drain<'_, K, V> { +impl ExactSizeIterator for Drain<'_, K, V, A> { #[inline] fn len(&self) -> usize { self.base.len() } } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Drain<'_, K, V> {} +impl FusedIterator for Drain<'_, K, V, A> {} #[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Drain<'_, K, V> +impl fmt::Debug for Drain<'_, K, V, A> where K: fmt::Debug, V: fmt::Debug, @@ -2295,7 +2431,7 @@ where } #[stable(feature = "hash_extract_if", since = "1.88.0")] -impl Iterator for ExtractIf<'_, K, V, F> +impl Iterator for ExtractIf<'_, K, V, F, A> where F: FnMut(&K, &mut V) -> bool, { @@ -2312,10 +2448,13 @@ where } #[stable(feature = "hash_extract_if", since = "1.88.0")] -impl FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} +impl FusedIterator for ExtractIf<'_, K, V, F, A> where + F: FnMut(&K, &mut V) -> bool +{ +} #[stable(feature = "hash_extract_if", since = "1.88.0")] -impl fmt::Debug for ExtractIf<'_, K, V, F> +impl fmt::Debug for ExtractIf<'_, K, V, F, A> where K: fmt::Debug, V: fmt::Debug, @@ -2325,7 +2464,7 @@ where } } -impl<'a, K, V> Entry<'a, K, V> { +impl<'a, K, V, A: Allocator> Entry<'a, K, V, A> { /// Ensures a value is in the entry by inserting the default if empty, and returns /// a mutable reference to the value in the entry. /// @@ -2473,7 +2612,7 @@ impl<'a, K, V> Entry<'a, K, V> { /// ``` #[inline] #[stable(feature = "entry_insert", since = "1.83.0")] - pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V> { + pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V, A> { match self { Occupied(mut entry) => { entry.insert(value); @@ -2510,7 +2649,7 @@ impl<'a, K, V: Default> Entry<'a, K, V> { } } -impl<'a, K, V> OccupiedEntry<'a, K, V> { +impl<'a, K, V, A: Allocator> OccupiedEntry<'a, K, V, A> { /// Gets a reference to the key in the entry. /// /// # Examples @@ -2682,7 +2821,7 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { } } -impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { +impl<'a, K: 'a, V: 'a, A: Allocator> VacantEntry<'a, K, V, A> { /// Gets a reference to the key that would be used when inserting a value /// through the `VacantEntry`. /// @@ -2760,7 +2899,7 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { /// ``` #[inline] #[stable(feature = "entry_insert", since = "1.83.0")] - pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V> { + pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V, A> { let base = self.base.insert_entry(value); OccupiedEntry { base } } @@ -2786,10 +2925,11 @@ where /// Inserts all new key-values from the iterator and replaces values with existing /// keys with new values returned from the iterator. #[stable(feature = "rust1", since = "1.0.0")] -impl Extend<(K, V)> for HashMap +impl Extend<(K, V)> for HashMap where K: Eq + Hash, S: BuildHasher, + A: Allocator, { #[inline] fn extend>(&mut self, iter: T) { @@ -2808,11 +2948,12 @@ where } #[stable(feature = "hash_extend_copy", since = "1.4.0")] -impl<'a, K, V, S> Extend<(&'a K, &'a V)> for HashMap +impl<'a, K, V, S, A> Extend<(&'a K, &'a V)> for HashMap where K: Eq + Hash + Copy, V: Copy, S: BuildHasher, + A: Allocator, { #[inline] fn extend>(&mut self, iter: T) { @@ -2831,7 +2972,9 @@ where } #[inline] -fn map_entry<'a, K: 'a, V: 'a>(raw: base::RustcEntry<'a, K, V>) -> Entry<'a, K, V> { +fn map_entry<'a, K: 'a, V: 'a, A: Allocator>( + raw: base::RustcEntry<'a, K, V, A>, +) -> Entry<'a, K, V, A> { match raw { base::RustcEntry::Occupied(base) => Entry::Occupied(OccupiedEntry { base }), base::RustcEntry::Vacant(base) => Entry::Vacant(VacantEntry { base }), From 0f516ec9294746eb781feb3c2787f0c9591e1c50 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Wed, 5 Nov 2025 15:05:58 -0800 Subject: [PATCH 0101/1061] Update UI tests for addition of HashMap allocator --- tests/ui/generics/wrong-number-of-args.rs | 4 --- tests/ui/generics/wrong-number-of-args.stderr | 24 ++++++------------ tests/ui/inference/issue-71732.stderr | 2 +- ...clone-when-some-obligation-is-unmet.stderr | 2 +- tests/ui/privacy/suggest-box-new.rs | 2 +- tests/ui/privacy/suggest-box-new.stderr | 21 +++++++++------- .../suggestions/multi-suggestion.ascii.stderr | 21 +++++++++------- tests/ui/suggestions/multi-suggestion.rs | 2 +- .../multi-suggestion.unicode.stderr | 25 +++++++++++-------- tests/ui/traits/issue-77982.stderr | 2 +- 10 files changed, 51 insertions(+), 54 deletions(-) diff --git a/tests/ui/generics/wrong-number-of-args.rs b/tests/ui/generics/wrong-number-of-args.rs index 6524bd538b6b..8bc384a3d817 100644 --- a/tests/ui/generics/wrong-number-of-args.rs +++ b/tests/ui/generics/wrong-number-of-args.rs @@ -321,10 +321,6 @@ mod stdlib { //~| ERROR struct takes at least 2 //~| HELP add missing - type D = HashMap; - //~^ ERROR struct takes at most 3 - //~| HELP remove the - type E = HashMap<>; //~^ ERROR struct takes at least 2 generic arguments but 0 generic arguments //~| HELP add missing diff --git a/tests/ui/generics/wrong-number-of-args.stderr b/tests/ui/generics/wrong-number-of-args.stderr index bac0d26b622d..bedeeb812fc9 100644 --- a/tests/ui/generics/wrong-number-of-args.stderr +++ b/tests/ui/generics/wrong-number-of-args.stderr @@ -926,16 +926,8 @@ help: add missing generic arguments LL | type C = HashMap<'static, K, V>; | ++++++ -error[E0107]: struct takes at most 3 generic arguments but 4 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:324:18 - | -LL | type D = HashMap; - | ^^^^^^^ ----- help: remove the unnecessary generic argument - | | - | expected at most 3 generic arguments - error[E0107]: struct takes at least 2 generic arguments but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:328:18 + --> $DIR/wrong-number-of-args.rs:324:18 | LL | type E = HashMap<>; | ^^^^^^^ expected at least 2 generic arguments @@ -946,7 +938,7 @@ LL | type E = HashMap; | ++++ error[E0107]: missing generics for enum `Result` - --> $DIR/wrong-number-of-args.rs:334:18 + --> $DIR/wrong-number-of-args.rs:330:18 | LL | type A = Result; | ^^^^^^ expected 2 generic arguments @@ -957,7 +949,7 @@ LL | type A = Result; | ++++++ error[E0107]: enum takes 2 generic arguments but 1 generic argument was supplied - --> $DIR/wrong-number-of-args.rs:338:18 + --> $DIR/wrong-number-of-args.rs:334:18 | LL | type B = Result; | ^^^^^^ ------ supplied 1 generic argument @@ -970,7 +962,7 @@ LL | type B = Result; | +++ error[E0107]: enum takes 0 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/wrong-number-of-args.rs:342:18 + --> $DIR/wrong-number-of-args.rs:338:18 | LL | type C = Result<'static>; | ^^^^^^--------- help: remove the unnecessary generics @@ -978,7 +970,7 @@ LL | type C = Result<'static>; | expected 0 lifetime arguments error[E0107]: enum takes 2 generic arguments but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:342:18 + --> $DIR/wrong-number-of-args.rs:338:18 | LL | type C = Result<'static>; | ^^^^^^ expected 2 generic arguments @@ -989,7 +981,7 @@ LL | type C = Result<'static, T, E>; | ++++++ error[E0107]: enum takes 2 generic arguments but 3 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:348:18 + --> $DIR/wrong-number-of-args.rs:344:18 | LL | type D = Result; | ^^^^^^ ------ help: remove the unnecessary generic argument @@ -997,7 +989,7 @@ LL | type D = Result; | expected 2 generic arguments error[E0107]: enum takes 2 generic arguments but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:352:18 + --> $DIR/wrong-number-of-args.rs:348:18 | LL | type E = Result<>; | ^^^^^^ expected 2 generic arguments @@ -1007,7 +999,7 @@ help: add missing generic arguments LL | type E = Result; | ++++ -error: aborting due to 71 previous errors +error: aborting due to 70 previous errors Some errors have detailed explanations: E0106, E0107. For more information about an error, try `rustc --explain E0106`. diff --git a/tests/ui/inference/issue-71732.stderr b/tests/ui/inference/issue-71732.stderr index af8b310fd1d9..e79131694856 100644 --- a/tests/ui/inference/issue-71732.stderr +++ b/tests/ui/inference/issue-71732.stderr @@ -10,7 +10,7 @@ LL | .get(&"key".into()) - impl Borrow for String; - impl Borrow for T where T: ?Sized; -note: required by a bound in `HashMap::::get` +note: required by a bound in `HashMap::::get` --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL help: consider specifying the generic argument | diff --git a/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr b/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr index 6272455cc57e..af0f67b7c1c0 100644 --- a/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr +++ b/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr @@ -6,7 +6,7 @@ LL | let mut copy: Vec = map.clone().into_values().collect(); | | | move occurs because value has type `HashMap`, which does not implement the `Copy` trait | -note: `HashMap::::into_values` takes ownership of the receiver `self`, which moves value +note: `HashMap::::into_values` takes ownership of the receiver `self`, which moves value --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL note: if `Hash128_1` implemented `Clone`, you could clone the value --> $DIR/suggest-clone-when-some-obligation-is-unmet.rs:8:1 diff --git a/tests/ui/privacy/suggest-box-new.rs b/tests/ui/privacy/suggest-box-new.rs index ff585387020e..87ee13d15edb 100644 --- a/tests/ui/privacy/suggest-box-new.rs +++ b/tests/ui/privacy/suggest-box-new.rs @@ -14,7 +14,7 @@ fn main() { let _ = std::collections::HashMap(); //~^ ERROR expected function, tuple struct or tuple variant, found struct `std::collections::HashMap` let _ = std::collections::HashMap {}; - //~^ ERROR cannot construct `HashMap<_, _, _>` with struct literal syntax due to private fields + //~^ ERROR cannot construct `HashMap<_, _, _, _>` with struct literal syntax due to private fields let _ = Box {}; //~ ERROR cannot construct `Box<_, _>` with struct literal syntax due to private fields // test that we properly instantiate the parameter of `Box::::new` with an inference variable diff --git a/tests/ui/privacy/suggest-box-new.stderr b/tests/ui/privacy/suggest-box-new.stderr index e3a7e5f62017..7367672351d6 100644 --- a/tests/ui/privacy/suggest-box-new.stderr +++ b/tests/ui/privacy/suggest-box-new.stderr @@ -5,6 +5,7 @@ LL | let _ = std::collections::HashMap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL + ::: $SRC_DIR/std/src/collections/hash/map.rs:LL:COL | = note: `std::collections::HashMap` defined here help: you might have meant to use an associated function to build this type @@ -12,14 +13,15 @@ help: you might have meant to use an associated function to build this type LL | let _ = std::collections::HashMap::new(); | +++++ LL - let _ = std::collections::HashMap(); +LL + let _ = std::collections::HashMap::new_in(_); + | +LL - let _ = std::collections::HashMap(); LL + let _ = std::collections::HashMap::with_capacity(_); | LL - let _ = std::collections::HashMap(); -LL + let _ = std::collections::HashMap::with_hasher(_); - | -LL - let _ = std::collections::HashMap(); -LL + let _ = std::collections::HashMap::with_capacity_and_hasher(_, _); +LL + let _ = std::collections::HashMap::with_capacity_in(_, _); | + = and 4 other candidates help: consider using the `Default` trait | LL | let _ = ::default(); @@ -73,7 +75,7 @@ LL - })), LL + wtf: Some(::default()), | -error: cannot construct `HashMap<_, _, _>` with struct literal syntax due to private fields +error: cannot construct `HashMap<_, _, _, _>` with struct literal syntax due to private fields --> $DIR/suggest-box-new.rs:16:13 | LL | let _ = std::collections::HashMap {}; @@ -86,14 +88,15 @@ LL - let _ = std::collections::HashMap {}; LL + let _ = std::collections::HashMap::new(); | LL - let _ = std::collections::HashMap {}; +LL + let _ = std::collections::HashMap::new_in(_); + | +LL - let _ = std::collections::HashMap {}; LL + let _ = std::collections::HashMap::with_capacity(_); | LL - let _ = std::collections::HashMap {}; -LL + let _ = std::collections::HashMap::with_hasher(_); - | -LL - let _ = std::collections::HashMap {}; -LL + let _ = std::collections::HashMap::with_capacity_and_hasher(_, _); +LL + let _ = std::collections::HashMap::with_capacity_in(_, _); | + = and 4 other candidates help: consider using the `Default` trait | LL - let _ = std::collections::HashMap {}; diff --git a/tests/ui/suggestions/multi-suggestion.ascii.stderr b/tests/ui/suggestions/multi-suggestion.ascii.stderr index c2ae19b1ae9a..2da0f9bd12c2 100644 --- a/tests/ui/suggestions/multi-suggestion.ascii.stderr +++ b/tests/ui/suggestions/multi-suggestion.ascii.stderr @@ -5,6 +5,7 @@ LL | let _ = std::collections::HashMap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL + ::: $SRC_DIR/std/src/collections/hash/map.rs:LL:COL | = note: `std::collections::HashMap` defined here help: you might have meant to use an associated function to build this type @@ -12,14 +13,15 @@ help: you might have meant to use an associated function to build this type LL | let _ = std::collections::HashMap::new(); | +++++ LL - let _ = std::collections::HashMap(); +LL + let _ = std::collections::HashMap::new_in(_); + | +LL - let _ = std::collections::HashMap(); LL + let _ = std::collections::HashMap::with_capacity(_); | LL - let _ = std::collections::HashMap(); -LL + let _ = std::collections::HashMap::with_hasher(_); - | -LL - let _ = std::collections::HashMap(); -LL + let _ = std::collections::HashMap::with_capacity_and_hasher(_, _); +LL + let _ = std::collections::HashMap::with_capacity_in(_, _); | + = and 4 other candidates help: consider using the `Default` trait | LL | let _ = ::default(); @@ -73,7 +75,7 @@ LL - })), LL + wtf: Some(::default()), | -error: cannot construct `HashMap<_, _, _>` with struct literal syntax due to private fields +error: cannot construct `HashMap<_, _, _, _>` with struct literal syntax due to private fields --> $DIR/multi-suggestion.rs:19:13 | LL | let _ = std::collections::HashMap {}; @@ -86,14 +88,15 @@ LL - let _ = std::collections::HashMap {}; LL + let _ = std::collections::HashMap::new(); | LL - let _ = std::collections::HashMap {}; +LL + let _ = std::collections::HashMap::new_in(_); + | +LL - let _ = std::collections::HashMap {}; LL + let _ = std::collections::HashMap::with_capacity(_); | LL - let _ = std::collections::HashMap {}; -LL + let _ = std::collections::HashMap::with_hasher(_); - | -LL - let _ = std::collections::HashMap {}; -LL + let _ = std::collections::HashMap::with_capacity_and_hasher(_, _); +LL + let _ = std::collections::HashMap::with_capacity_in(_, _); | + = and 4 other candidates help: consider using the `Default` trait | LL - let _ = std::collections::HashMap {}; diff --git a/tests/ui/suggestions/multi-suggestion.rs b/tests/ui/suggestions/multi-suggestion.rs index 99d2407aa212..6d822a8e5aff 100644 --- a/tests/ui/suggestions/multi-suggestion.rs +++ b/tests/ui/suggestions/multi-suggestion.rs @@ -17,6 +17,6 @@ fn main() { let _ = std::collections::HashMap(); //[ascii]~^ ERROR expected function, tuple struct or tuple variant, found struct `std::collections::HashMap` let _ = std::collections::HashMap {}; - //[ascii]~^ ERROR cannot construct `HashMap<_, _, _>` with struct literal syntax due to private fields + //[ascii]~^ ERROR cannot construct `HashMap<_, _, _, _>` with struct literal syntax due to private fields let _ = Box {}; //[ascii]~ ERROR cannot construct `Box<_, _>` with struct literal syntax due to private fields } diff --git a/tests/ui/suggestions/multi-suggestion.unicode.stderr b/tests/ui/suggestions/multi-suggestion.unicode.stderr index fc187cac91d1..69529b67b775 100644 --- a/tests/ui/suggestions/multi-suggestion.unicode.stderr +++ b/tests/ui/suggestions/multi-suggestion.unicode.stderr @@ -5,6 +5,7 @@ LL │ let _ = std::collections::HashMap(); │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━ ╰╴ ╭▸ $SRC_DIR/std/src/collections/hash/map.rs:LL:COL + ⸬ $SRC_DIR/std/src/collections/hash/map.rs:LL:COL │ ╰ note: `std::collections::HashMap` defined here help: you might have meant to use an associated function to build this type @@ -12,14 +13,15 @@ help: you might have meant to use an associated function to build this type LL │ let _ = std::collections::HashMap::new(); ├╴ +++++ LL - let _ = std::collections::HashMap(); +LL + let _ = std::collections::HashMap::new_in(_); + ├╴ +LL - let _ = std::collections::HashMap(); LL + let _ = std::collections::HashMap::with_capacity(_); ├╴ LL - let _ = std::collections::HashMap(); -LL + let _ = std::collections::HashMap::with_hasher(_); - ├╴ -LL - let _ = std::collections::HashMap(); -LL + let _ = std::collections::HashMap::with_capacity_and_hasher(_, _); - ╰╴ +LL + let _ = std::collections::HashMap::with_capacity_in(_, _); + │ + ╰ and 4 other candidates help: consider using the `Default` trait ╭╴ LL │ let _ = ::default(); @@ -73,7 +75,7 @@ LL - })), LL + wtf: Some(::default()), ╰╴ -error: cannot construct `HashMap<_, _, _>` with struct literal syntax due to private fields +error: cannot construct `HashMap<_, _, _, _>` with struct literal syntax due to private fields ╭▸ $DIR/multi-suggestion.rs:19:13 │ LL │ let _ = std::collections::HashMap {}; @@ -86,14 +88,15 @@ LL - let _ = std::collections::HashMap {}; LL + let _ = std::collections::HashMap::new(); ├╴ LL - let _ = std::collections::HashMap {}; +LL + let _ = std::collections::HashMap::new_in(_); + ├╴ +LL - let _ = std::collections::HashMap {}; LL + let _ = std::collections::HashMap::with_capacity(_); ├╴ LL - let _ = std::collections::HashMap {}; -LL + let _ = std::collections::HashMap::with_hasher(_); - ├╴ -LL - let _ = std::collections::HashMap {}; -LL + let _ = std::collections::HashMap::with_capacity_and_hasher(_, _); - ╰╴ +LL + let _ = std::collections::HashMap::with_capacity_in(_, _); + │ + ╰ and 4 other candidates help: consider using the `Default` trait ╭╴ LL - let _ = std::collections::HashMap {}; diff --git a/tests/ui/traits/issue-77982.stderr b/tests/ui/traits/issue-77982.stderr index edc7f56ea467..4bc24e81215a 100644 --- a/tests/ui/traits/issue-77982.stderr +++ b/tests/ui/traits/issue-77982.stderr @@ -10,7 +10,7 @@ LL | opts.get(opt.as_ref()); - impl Borrow for String; - impl Borrow for T where T: ?Sized; -note: required by a bound in `HashMap::::get` +note: required by a bound in `HashMap::::get` --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL help: consider specifying the generic argument | From ef7616dbaa9378ac8028f76f9ce74a9c4237565e Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Wed, 5 Nov 2025 14:44:14 -0800 Subject: [PATCH 0102/1061] Add allocator parameter to HashSet --- library/std/src/collections/hash/set.rs | 429 ++++++++++++++++-------- 1 file changed, 286 insertions(+), 143 deletions(-) diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index 6795da80aacb..02a4a0d9c815 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -4,6 +4,7 @@ mod tests; use hashbrown::hash_set as base; use super::map::map_try_reserve_error; +use crate::alloc::{Allocator, Global}; use crate::borrow::Borrow; use crate::collections::TryReserveError; use crate::fmt; @@ -122,8 +123,12 @@ use crate::ops::{BitAnd, BitOr, BitXor, Sub}; /// ``` #[cfg_attr(not(test), rustc_diagnostic_item = "HashSet")] #[stable(feature = "rust1", since = "1.0.0")] -pub struct HashSet { - base: base::HashSet, +pub struct HashSet< + T, + S = RandomState, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::HashSet, } impl HashSet { @@ -166,7 +171,141 @@ impl HashSet { } } +impl HashSet { + /// Creates an empty `HashSet` in the provided allocator. + /// + /// The hash set is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + #[inline] + #[must_use] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn new_in(alloc: A) -> HashSet { + HashSet::with_hasher_in(Default::default(), alloc) + } + + /// Creates an empty `HashSet` with at least the specified capacity. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is zero, the hash set will not allocate. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// let set: HashSet = HashSet::with_capacity(10); + /// assert!(set.capacity() >= 10); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn with_capacity_in(capacity: usize, alloc: A) -> HashSet { + HashSet::with_capacity_and_hasher_in(capacity, Default::default(), alloc) + } +} + impl HashSet { + /// Creates a new empty hash set which will use the given hasher to hash + /// keys. + /// + /// The hash set is also created with the default initial capacity. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow `HashSet`s to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashSet` to be useful, see its documentation for details. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// use std::hash::RandomState; + /// + /// let s = RandomState::new(); + /// let mut set = HashSet::with_hasher(s); + /// set.insert(2); + /// ``` + #[inline] + #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] + #[rustc_const_stable(feature = "const_collections_with_hasher", since = "1.85.0")] + pub const fn with_hasher(hasher: S) -> HashSet { + HashSet { base: base::HashSet::with_hasher(hasher) } + } + + /// Creates an empty `HashSet` with at least the specified capacity, using + /// `hasher` to hash the keys. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is zero, the hash set will not allocate. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow `HashSet`s to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashSet` to be useful, see its documentation for details. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// use std::hash::RandomState; + /// + /// let s = RandomState::new(); + /// let mut set = HashSet::with_capacity_and_hasher(10, s); + /// set.insert(1); + /// ``` + #[inline] + #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] + pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashSet { + HashSet { base: base::HashSet::with_capacity_and_hasher(capacity, hasher) } + } +} + +impl HashSet { + /// Creates a new empty hash set which will use the given hasher to hash + /// keys and will allocate memory using the provided allocator. + /// + /// The hash set is also created with the default initial capacity. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow `HashSet`s to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashSet` to be useful, see its documentation for details. + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn with_hasher_in(hasher: S, alloc: A) -> HashSet { + HashSet { base: base::HashSet::with_hasher_in(hasher, alloc) } + } + + /// Creates an empty `HashSet` with at least the specified capacity, using + /// `hasher` to hash the keys and `alloc` to allocate memory. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is zero, the hash set will not allocate. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow `HashSet`s to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashSet` to be useful, see its documentation for details. + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn with_capacity_and_hasher_in(capacity: usize, hasher: S, alloc: A) -> HashSet { + HashSet { base: base::HashSet::with_capacity_and_hasher_in(capacity, hasher, alloc) } + } + /// Returns the number of elements the set can hold without reallocating. /// /// # Examples @@ -272,7 +411,7 @@ impl HashSet { #[inline] #[rustc_lint_query_instability] #[stable(feature = "drain", since = "1.6.0")] - pub fn drain(&mut self) -> Drain<'_, T> { + pub fn drain(&mut self) -> Drain<'_, T, A> { Drain { base: self.base.drain() } } @@ -309,7 +448,7 @@ impl HashSet { #[inline] #[rustc_lint_query_instability] #[stable(feature = "hash_extract_if", since = "1.88.0")] - pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, T, F> + pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, T, F, A> where F: FnMut(&T) -> bool, { @@ -362,67 +501,6 @@ impl HashSet { self.base.clear() } - /// Creates a new empty hash set which will use the given hasher to hash - /// keys. - /// - /// The hash set is also created with the default initial capacity. - /// - /// Warning: `hasher` is normally randomly generated, and - /// is designed to allow `HashSet`s to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. - /// - /// The `hash_builder` passed should implement the [`BuildHasher`] trait for - /// the `HashSet` to be useful, see its documentation for details. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// use std::hash::RandomState; - /// - /// let s = RandomState::new(); - /// let mut set = HashSet::with_hasher(s); - /// set.insert(2); - /// ``` - #[inline] - #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] - #[rustc_const_stable(feature = "const_collections_with_hasher", since = "1.85.0")] - pub const fn with_hasher(hasher: S) -> HashSet { - HashSet { base: base::HashSet::with_hasher(hasher) } - } - - /// Creates an empty `HashSet` with at least the specified capacity, using - /// `hasher` to hash the keys. - /// - /// The hash set will be able to hold at least `capacity` elements without - /// reallocating. This method is allowed to allocate for more elements than - /// `capacity`. If `capacity` is zero, the hash set will not allocate. - /// - /// Warning: `hasher` is normally randomly generated, and - /// is designed to allow `HashSet`s to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. - /// - /// The `hash_builder` passed should implement the [`BuildHasher`] trait for - /// the `HashSet` to be useful, see its documentation for details. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// use std::hash::RandomState; - /// - /// let s = RandomState::new(); - /// let mut set = HashSet::with_capacity_and_hasher(10, s); - /// set.insert(1); - /// ``` - #[inline] - #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] - pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashSet { - HashSet { base: base::HashSet::with_capacity_and_hasher(capacity, hasher) } - } - /// Returns a reference to the set's [`BuildHasher`]. /// /// # Examples @@ -442,10 +520,11 @@ impl HashSet { } } -impl HashSet +impl HashSet where T: Eq + Hash, S: BuildHasher, + A: Allocator, { /// Reserves capacity for at least `additional` more elements to be inserted /// in the `HashSet`. The collection may reserve more space to speculatively @@ -569,7 +648,7 @@ where #[inline] #[rustc_lint_query_instability] #[stable(feature = "rust1", since = "1.0.0")] - pub fn difference<'a>(&'a self, other: &'a HashSet) -> Difference<'a, T, S> { + pub fn difference<'a>(&'a self, other: &'a HashSet) -> Difference<'a, T, S, A> { Difference { iter: self.iter(), other } } @@ -599,8 +678,8 @@ where #[stable(feature = "rust1", since = "1.0.0")] pub fn symmetric_difference<'a>( &'a self, - other: &'a HashSet, - ) -> SymmetricDifference<'a, T, S> { + other: &'a HashSet, + ) -> SymmetricDifference<'a, T, S, A> { SymmetricDifference { iter: self.difference(other).chain(other.difference(self)) } } @@ -631,7 +710,7 @@ where #[inline] #[rustc_lint_query_instability] #[stable(feature = "rust1", since = "1.0.0")] - pub fn intersection<'a>(&'a self, other: &'a HashSet) -> Intersection<'a, T, S> { + pub fn intersection<'a>(&'a self, other: &'a HashSet) -> Intersection<'a, T, S, A> { if self.len() <= other.len() { Intersection { iter: self.iter(), other } } else { @@ -660,7 +739,7 @@ where #[inline] #[rustc_lint_query_instability] #[stable(feature = "rust1", since = "1.0.0")] - pub fn union<'a>(&'a self, other: &'a HashSet) -> Union<'a, T, S> { + pub fn union<'a>(&'a self, other: &'a HashSet) -> Union<'a, T, S, A> { if self.len() >= other.len() { Union { iter: self.iter().chain(other.difference(self)) } } else { @@ -812,7 +891,7 @@ where /// ``` #[inline] #[unstable(feature = "hash_set_entry", issue = "60896")] - pub fn entry(&mut self, value: T) -> Entry<'_, T, S> { + pub fn entry(&mut self, value: T) -> Entry<'_, T, S, A> { map_entry(self.base.entry(value)) } @@ -834,7 +913,7 @@ where /// assert_eq!(a.is_disjoint(&b), false); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_disjoint(&self, other: &HashSet) -> bool { + pub fn is_disjoint(&self, other: &HashSet) -> bool { if self.len() <= other.len() { self.iter().all(|v| !other.contains(v)) } else { @@ -860,7 +939,7 @@ where /// assert_eq!(set.is_subset(&sup), false); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_subset(&self, other: &HashSet) -> bool { + pub fn is_subset(&self, other: &HashSet) -> bool { if self.len() <= other.len() { self.iter().all(|v| other.contains(v)) } else { false } } @@ -886,7 +965,7 @@ where /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_superset(&self, other: &HashSet) -> bool { + pub fn is_superset(&self, other: &HashSet) -> bool { other.is_subset(self) } @@ -995,7 +1074,7 @@ where } #[inline] -fn map_entry<'a, K: 'a, V: 'a>(raw: base::Entry<'a, K, V>) -> Entry<'a, K, V> { +fn map_entry<'a, K: 'a, V: 'a, A: Allocator>(raw: base::Entry<'a, K, V, A>) -> Entry<'a, K, V, A> { match raw { base::Entry::Occupied(base) => Entry::Occupied(OccupiedEntry { base }), base::Entry::Vacant(base) => Entry::Vacant(VacantEntry { base }), @@ -1003,10 +1082,11 @@ fn map_entry<'a, K: 'a, V: 'a>(raw: base::Entry<'a, K, V>) -> Entry<'a, K, V> { } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for HashSet +impl Clone for HashSet where T: Clone, S: Clone, + A: Allocator + Clone, { #[inline] fn clone(&self) -> Self { @@ -1024,12 +1104,13 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for HashSet +impl PartialEq for HashSet where T: Eq + Hash, S: BuildHasher, + A: Allocator, { - fn eq(&self, other: &HashSet) -> bool { + fn eq(&self, other: &HashSet) -> bool { if self.len() != other.len() { return false; } @@ -1039,17 +1120,19 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Eq for HashSet +impl Eq for HashSet where T: Eq + Hash, S: BuildHasher, + A: Allocator, { } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for HashSet +impl fmt::Debug for HashSet where T: fmt::Debug, + A: Allocator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_set().entries(self.iter()).finish() @@ -1107,10 +1190,11 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Extend for HashSet +impl Extend for HashSet where T: Eq + Hash, S: BuildHasher, + A: Allocator, { #[inline] fn extend>(&mut self, iter: I) { @@ -1129,10 +1213,11 @@ where } #[stable(feature = "hash_extend_copy", since = "1.4.0")] -impl<'a, T, S> Extend<&'a T> for HashSet +impl<'a, T, S, A> Extend<&'a T> for HashSet where T: 'a + Eq + Hash + Copy, S: BuildHasher, + A: Allocator, { #[inline] fn extend>(&mut self, iter: I) { @@ -1341,8 +1426,11 @@ impl Default for Iter<'_, K> { /// let mut iter = a.into_iter(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub struct IntoIter { - base: base::IntoIter, +pub struct IntoIter< + K, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::IntoIter, } #[stable(feature = "default_iters_hash", since = "1.83.0")] @@ -1371,8 +1459,12 @@ impl Default for IntoIter { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "hashset_drain_ty")] -pub struct Drain<'a, K: 'a> { - base: base::Drain<'a, K>, +pub struct Drain< + 'a, + K: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::Drain<'a, K, A>, } /// A draining, filtering iterator over the items of a `HashSet`. @@ -1393,8 +1485,13 @@ pub struct Drain<'a, K: 'a> { #[stable(feature = "hash_extract_if", since = "1.88.0")] #[must_use = "iterators are lazy and do nothing unless consumed; \ use `retain` to remove and discard elements"] -pub struct ExtractIf<'a, K, F> { - base: base::ExtractIf<'a, K, F>, +pub struct ExtractIf< + 'a, + K, + F, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::ExtractIf<'a, K, F, A>, } /// A lazy iterator producing elements in the intersection of `HashSet`s. @@ -1417,11 +1514,16 @@ pub struct ExtractIf<'a, K, F> { #[must_use = "this returns the intersection as an iterator, \ without modifying either input set"] #[stable(feature = "rust1", since = "1.0.0")] -pub struct Intersection<'a, T: 'a, S: 'a> { +pub struct Intersection< + 'a, + T: 'a, + S: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { // iterator of the first set iter: Iter<'a, T>, // the second set - other: &'a HashSet, + other: &'a HashSet, } /// A lazy iterator producing elements in the difference of `HashSet`s. @@ -1444,11 +1546,16 @@ pub struct Intersection<'a, T: 'a, S: 'a> { #[must_use = "this returns the difference as an iterator, \ without modifying either input set"] #[stable(feature = "rust1", since = "1.0.0")] -pub struct Difference<'a, T: 'a, S: 'a> { +pub struct Difference< + 'a, + T: 'a, + S: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { // iterator of the first set iter: Iter<'a, T>, // the second set - other: &'a HashSet, + other: &'a HashSet, } /// A lazy iterator producing elements in the symmetric difference of `HashSet`s. @@ -1471,8 +1578,13 @@ pub struct Difference<'a, T: 'a, S: 'a> { #[must_use = "this returns the difference as an iterator, \ without modifying either input set"] #[stable(feature = "rust1", since = "1.0.0")] -pub struct SymmetricDifference<'a, T: 'a, S: 'a> { - iter: Chain, Difference<'a, T, S>>, +pub struct SymmetricDifference< + 'a, + T: 'a, + S: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + iter: Chain, Difference<'a, T, S, A>>, } /// A lazy iterator producing elements in the union of `HashSet`s. @@ -1495,12 +1607,17 @@ pub struct SymmetricDifference<'a, T: 'a, S: 'a> { #[must_use = "this returns the union as an iterator, \ without modifying either input set"] #[stable(feature = "rust1", since = "1.0.0")] -pub struct Union<'a, T: 'a, S: 'a> { - iter: Chain, Difference<'a, T, S>>, +pub struct Union< + 'a, + T: 'a, + S: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + iter: Chain, Difference<'a, T, S, A>>, } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, S> IntoIterator for &'a HashSet { +impl<'a, T, S, A: Allocator> IntoIterator for &'a HashSet { type Item = &'a T; type IntoIter = Iter<'a, T>; @@ -1512,9 +1629,9 @@ impl<'a, T, S> IntoIterator for &'a HashSet { } #[stable(feature = "rust1", since = "1.0.0")] -impl IntoIterator for HashSet { +impl IntoIterator for HashSet { type Item = T; - type IntoIter = IntoIter; + type IntoIter = IntoIter; /// Creates a consuming iterator, that is, one that moves each value out /// of the set in arbitrary order. The set cannot be used after calling @@ -1538,7 +1655,7 @@ impl IntoIterator for HashSet { /// ``` #[inline] #[rustc_lint_query_instability] - fn into_iter(self) -> IntoIter { + fn into_iter(self) -> IntoIter { IntoIter { base: self.base.into_iter() } } } @@ -1593,7 +1710,7 @@ impl fmt::Debug for Iter<'_, K> { } #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for IntoIter { +impl Iterator for IntoIter { type Item = K; #[inline] @@ -1618,24 +1735,24 @@ impl Iterator for IntoIter { } } #[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for IntoIter { +impl ExactSizeIterator for IntoIter { #[inline] fn len(&self) -> usize { self.base.len() } } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for IntoIter {} +impl FusedIterator for IntoIter {} #[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for IntoIter { +impl fmt::Debug for IntoIter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.base, f) } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K> Iterator for Drain<'a, K> { +impl<'a, K, A: Allocator> Iterator for Drain<'a, K, A> { type Item = K; #[inline] @@ -1656,24 +1773,24 @@ impl<'a, K> Iterator for Drain<'a, K> { } } #[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Drain<'_, K> { +impl ExactSizeIterator for Drain<'_, K, A> { #[inline] fn len(&self) -> usize { self.base.len() } } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Drain<'_, K> {} +impl FusedIterator for Drain<'_, K, A> {} #[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Drain<'_, K> { +impl fmt::Debug for Drain<'_, K, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.base, f) } } #[stable(feature = "hash_extract_if", since = "1.88.0")] -impl Iterator for ExtractIf<'_, K, F> +impl Iterator for ExtractIf<'_, K, F, A> where F: FnMut(&K) -> bool, { @@ -1690,10 +1807,10 @@ where } #[stable(feature = "hash_extract_if", since = "1.88.0")] -impl FusedIterator for ExtractIf<'_, K, F> where F: FnMut(&K) -> bool {} +impl FusedIterator for ExtractIf<'_, K, F, A> where F: FnMut(&K) -> bool {} #[stable(feature = "hash_extract_if", since = "1.88.0")] -impl fmt::Debug for ExtractIf<'_, K, F> +impl fmt::Debug for ExtractIf<'_, K, F, A> where K: fmt::Debug, { @@ -1703,7 +1820,7 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Intersection<'_, T, S> { +impl Clone for Intersection<'_, T, S, A> { #[inline] fn clone(&self) -> Self { Intersection { iter: self.iter.clone(), ..*self } @@ -1711,10 +1828,11 @@ impl Clone for Intersection<'_, T, S> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, S> Iterator for Intersection<'a, T, S> +impl<'a, T, S, A> Iterator for Intersection<'a, T, S, A> where T: Eq + Hash, S: BuildHasher, + A: Allocator, { type Item = &'a T; @@ -1745,10 +1863,11 @@ where } #[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Intersection<'_, T, S> +impl fmt::Debug for Intersection<'_, T, S, A> where T: fmt::Debug + Eq + Hash, S: BuildHasher, + A: Allocator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() @@ -1756,15 +1875,16 @@ where } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Intersection<'_, T, S> +impl FusedIterator for Intersection<'_, T, S, A> where T: Eq + Hash, S: BuildHasher, + A: Allocator, { } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Difference<'_, T, S> { +impl Clone for Difference<'_, T, S, A> { #[inline] fn clone(&self) -> Self { Difference { iter: self.iter.clone(), ..*self } @@ -1772,10 +1892,11 @@ impl Clone for Difference<'_, T, S> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, S> Iterator for Difference<'a, T, S> +impl<'a, T, S, A> Iterator for Difference<'a, T, S, A> where T: Eq + Hash, S: BuildHasher, + A: Allocator, { type Item = &'a T; @@ -1806,18 +1927,20 @@ where } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Difference<'_, T, S> +impl FusedIterator for Difference<'_, T, S, A> where T: Eq + Hash, S: BuildHasher, + A: Allocator, { } #[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Difference<'_, T, S> +impl fmt::Debug for Difference<'_, T, S, A> where T: fmt::Debug + Eq + Hash, S: BuildHasher, + A: Allocator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() @@ -1825,7 +1948,7 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for SymmetricDifference<'_, T, S> { +impl Clone for SymmetricDifference<'_, T, S, A> { #[inline] fn clone(&self) -> Self { SymmetricDifference { iter: self.iter.clone() } @@ -1833,10 +1956,11 @@ impl Clone for SymmetricDifference<'_, T, S> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, S> Iterator for SymmetricDifference<'a, T, S> +impl<'a, T, S, A> Iterator for SymmetricDifference<'a, T, S, A> where T: Eq + Hash, S: BuildHasher, + A: Allocator, { type Item = &'a T; @@ -1859,18 +1983,20 @@ where } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for SymmetricDifference<'_, T, S> +impl FusedIterator for SymmetricDifference<'_, T, S, A> where T: Eq + Hash, S: BuildHasher, + A: Allocator, { } #[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for SymmetricDifference<'_, T, S> +impl fmt::Debug for SymmetricDifference<'_, T, S, A> where T: fmt::Debug + Eq + Hash, S: BuildHasher, + A: Allocator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() @@ -1878,7 +2004,7 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Union<'_, T, S> { +impl Clone for Union<'_, T, S, A> { #[inline] fn clone(&self) -> Self { Union { iter: self.iter.clone() } @@ -1886,7 +2012,7 @@ impl Clone for Union<'_, T, S> { } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Union<'_, T, S> +impl FusedIterator for Union<'_, T, S, A> where T: Eq + Hash, S: BuildHasher, @@ -1894,10 +2020,11 @@ where } #[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Union<'_, T, S> +impl fmt::Debug for Union<'_, T, S, A> where T: fmt::Debug + Eq + Hash, S: BuildHasher, + A: Allocator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() @@ -1905,10 +2032,11 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, S> Iterator for Union<'a, T, S> +impl<'a, T, S, A> Iterator for Union<'a, T, S, A> where T: Eq + Hash, S: BuildHasher, + A: Allocator, { type Item = &'a T; @@ -1973,7 +2101,12 @@ where /// assert_eq!(vec, ["a", "b", "c", "d", "e"]); /// ``` #[unstable(feature = "hash_set_entry", issue = "60896")] -pub enum Entry<'a, T, S> { +pub enum Entry< + 'a, + T, + S, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { /// An occupied entry. /// /// # Examples @@ -1990,7 +2123,7 @@ pub enum Entry<'a, T, S> { /// Entry::Occupied(_) => { } /// } /// ``` - Occupied(OccupiedEntry<'a, T, S>), + Occupied(OccupiedEntry<'a, T, S, A>), /// A vacant entry. /// @@ -2008,11 +2141,11 @@ pub enum Entry<'a, T, S> { /// Entry::Vacant(_) => { } /// } /// ``` - Vacant(VacantEntry<'a, T, S>), + Vacant(VacantEntry<'a, T, S, A>), } #[unstable(feature = "hash_set_entry", issue = "60896")] -impl fmt::Debug for Entry<'_, T, S> { +impl fmt::Debug for Entry<'_, T, S, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), @@ -2060,12 +2193,17 @@ impl fmt::Debug for Entry<'_, T, S> { /// assert_eq!(set.len(), 2); /// ``` #[unstable(feature = "hash_set_entry", issue = "60896")] -pub struct OccupiedEntry<'a, T, S> { - base: base::OccupiedEntry<'a, T, S>, +pub struct OccupiedEntry< + 'a, + T, + S, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::OccupiedEntry<'a, T, S, A>, } #[unstable(feature = "hash_set_entry", issue = "60896")] -impl fmt::Debug for OccupiedEntry<'_, T, S> { +impl fmt::Debug for OccupiedEntry<'_, T, S, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OccupiedEntry").field("value", self.get()).finish() } @@ -2100,18 +2238,23 @@ impl fmt::Debug for OccupiedEntry<'_, T, S> { /// assert!(set.contains("b") && set.len() == 2); /// ``` #[unstable(feature = "hash_set_entry", issue = "60896")] -pub struct VacantEntry<'a, T, S> { - base: base::VacantEntry<'a, T, S>, +pub struct VacantEntry< + 'a, + T, + S, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::VacantEntry<'a, T, S, A>, } #[unstable(feature = "hash_set_entry", issue = "60896")] -impl fmt::Debug for VacantEntry<'_, T, S> { +impl fmt::Debug for VacantEntry<'_, T, S, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("VacantEntry").field(self.get()).finish() } } -impl<'a, T, S> Entry<'a, T, S> { +impl<'a, T, S, A: Allocator> Entry<'a, T, S, A> { /// Sets the value of the entry, and returns an OccupiedEntry. /// /// # Examples @@ -2128,7 +2271,7 @@ impl<'a, T, S> Entry<'a, T, S> { /// ``` #[inline] #[unstable(feature = "hash_set_entry", issue = "60896")] - pub fn insert(self) -> OccupiedEntry<'a, T, S> + pub fn insert(self) -> OccupiedEntry<'a, T, S, A> where T: Hash, S: BuildHasher, @@ -2198,7 +2341,7 @@ impl<'a, T, S> Entry<'a, T, S> { } } -impl OccupiedEntry<'_, T, S> { +impl OccupiedEntry<'_, T, S, A> { /// Gets a reference to the value in the entry. /// /// # Examples @@ -2255,7 +2398,7 @@ impl OccupiedEntry<'_, T, S> { } } -impl<'a, T, S> VacantEntry<'a, T, S> { +impl<'a, T, S, A: Allocator> VacantEntry<'a, T, S, A> { /// Gets a reference to the value that would be used when inserting /// through the `VacantEntry`. /// @@ -2325,7 +2468,7 @@ impl<'a, T, S> VacantEntry<'a, T, S> { } #[inline] - fn insert_entry(self) -> OccupiedEntry<'a, T, S> + fn insert_entry(self) -> OccupiedEntry<'a, T, S, A> where T: Hash, S: BuildHasher, From 72c6b0714142f45b7c8989b2bc54de22c4a38c6d Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Tue, 30 Dec 2025 10:57:15 +0800 Subject: [PATCH 0103/1061] Migrate `move_arm_cond_to_match_guard` assist to use `SyntaxEditor` --- .../ide-assists/src/handlers/move_guard.rs | 74 ++++++++++--------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs index 8daf86923d92..1c0c6e43d53b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs @@ -1,6 +1,11 @@ +use itertools::Itertools; use syntax::{ SyntaxKind::WHITESPACE, - ast::{AstNode, BlockExpr, ElseBranch, Expr, IfExpr, MatchArm, Pat, edit::AstNodeEdit, make}, + ast::{ + AstNode, BlockExpr, ElseBranch, Expr, IfExpr, MatchArm, Pat, edit::AstNodeEdit, make, + syntax_factory::SyntaxFactory, + }, + syntax_editor::Element, }; use crate::{AssistContext, AssistId, Assists}; @@ -131,8 +136,10 @@ pub(crate) fn move_arm_cond_to_match_guard( AssistId::refactor_rewrite("move_arm_cond_to_match_guard"), "Move condition to match guard", replace_node.text_range(), - |edit| { - edit.delete(match_arm.syntax().text_range()); + |builder| { + let make = SyntaxFactory::without_mappings(); + let mut replace_arms = vec![]; + // Dedent if if_expr is in a BlockExpr let dedent = if needs_dedent { cov_mark::hit!(move_guard_ifelse_in_block); @@ -141,47 +148,30 @@ pub(crate) fn move_arm_cond_to_match_guard( cov_mark::hit!(move_guard_ifelse_else_block); 0 }; - let then_arm_end = match_arm.syntax().text_range().end(); let indent_level = match_arm.indent_level(); - let spaces = indent_level; - let mut first = true; for (cond, block) in conds_blocks { - if !first { - edit.insert(then_arm_end, format!("\n{spaces}")); - } else { - first = false; - } - let guard = format!("{match_pat} if {cond} => "); - edit.insert(then_arm_end, guard); let only_expr = block.statements().next().is_none(); - match &block.tail_expr() { - Some(then_expr) if only_expr => { - edit.insert(then_arm_end, then_expr.syntax().text()); - edit.insert(then_arm_end, ","); - } - _ => { - let to_insert = block.dedent(dedent.into()).syntax().text(); - edit.insert(then_arm_end, to_insert) - } - } + let expr = match block.tail_expr() { + Some(then_expr) if only_expr => then_expr, + _ => block.dedent(dedent.into()).into(), + }; + let guard = make.match_guard(cond); + let new_arm = make.match_arm(match_pat.clone(), Some(guard), expr); + replace_arms.push(new_arm); } - if let Some(e) = tail { + if let Some(block) = tail { cov_mark::hit!(move_guard_ifelse_else_tail); - let guard = format!("\n{spaces}{match_pat} => "); - edit.insert(then_arm_end, guard); - let only_expr = e.statements().next().is_none(); - match &e.tail_expr() { + let only_expr = block.statements().next().is_none(); + let expr = match block.tail_expr() { Some(expr) if only_expr => { cov_mark::hit!(move_guard_ifelse_expr_only); - edit.insert(then_arm_end, expr.syntax().text()); - edit.insert(then_arm_end, ","); + expr } - _ => { - let to_insert = e.dedent(dedent.into()).syntax().text(); - edit.insert(then_arm_end, to_insert) - } - } + _ => block.dedent(dedent.into()).into(), + }; + let new_arm = make.match_arm(match_pat, None, expr); + replace_arms.push(new_arm); } else { // There's no else branch. Add a pattern without guard, unless the following match // arm is `_ => ...` @@ -193,9 +183,21 @@ pub(crate) fn move_arm_cond_to_match_guard( { cov_mark::hit!(move_guard_ifelse_has_wildcard); } - _ => edit.insert(then_arm_end, format!("\n{spaces}{match_pat} => {{}}")), + _ => { + let block_expr = make.expr_empty_block().into(); + replace_arms.push(make.match_arm(match_pat, None, block_expr)); + } } } + + let mut edit = builder.make_editor(match_arm.syntax()); + + let newline = make.whitespace(&format!("\n{indent_level}")); + let replace_arms = replace_arms.iter().map(|it| it.syntax().syntax_element()); + let replace_arms = Itertools::intersperse(replace_arms, newline.syntax_element()); + edit.replace_with_many(match_arm.syntax(), replace_arms.collect()); + + builder.add_file_edits(ctx.vfs_file_id(), edit); }, ) } From b3c3604f624ec256da9a18cd25b9260dd6717d8c Mon Sep 17 00:00:00 2001 From: AprilNEA Date: Tue, 30 Dec 2025 17:51:49 +0800 Subject: [PATCH 0104/1061] Add regression test for issue 99173 Adds a test for nested proc-macro calls where the inner macro returns an empty TokenStream. This previously caused an ICE in rustc_resolve. --- .../auxiliary/nested-empty-proc-macro.rs | 18 ++++++++++++++++++ tests/ui/proc-macro/nested-empty-proc-macro.rs | 12 ++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 tests/ui/proc-macro/auxiliary/nested-empty-proc-macro.rs create mode 100644 tests/ui/proc-macro/nested-empty-proc-macro.rs diff --git a/tests/ui/proc-macro/auxiliary/nested-empty-proc-macro.rs b/tests/ui/proc-macro/auxiliary/nested-empty-proc-macro.rs new file mode 100644 index 000000000000..a1cb4c1c7638 --- /dev/null +++ b/tests/ui/proc-macro/auxiliary/nested-empty-proc-macro.rs @@ -0,0 +1,18 @@ +// Auxiliary proc-macro for issue #99173 +// Tests that nested proc-macro calls with empty output don't cause ICE + +extern crate proc_macro; + +use proc_macro::TokenStream; + +// This macro returns an empty TokenStream +#[proc_macro] +pub fn ignore(_input: TokenStream) -> TokenStream { + TokenStream::new() +} + +// This macro generates code that calls the `ignore` macro +#[proc_macro] +pub fn outer_macro(_input: TokenStream) -> TokenStream { + "nested_empty_proc_macro::ignore!(42)".parse().unwrap() +} diff --git a/tests/ui/proc-macro/nested-empty-proc-macro.rs b/tests/ui/proc-macro/nested-empty-proc-macro.rs new file mode 100644 index 000000000000..d1c2c8a01412 --- /dev/null +++ b/tests/ui/proc-macro/nested-empty-proc-macro.rs @@ -0,0 +1,12 @@ +//@ check-pass +//@ proc-macro: nested-empty-proc-macro.rs + +// Regression test for issue #99173 +// Tests that nested proc-macro calls where the inner macro returns +// an empty TokenStream don't cause an ICE. + +extern crate nested_empty_proc_macro; + +fn main() { + nested_empty_proc_macro::outer_macro!(1 * 2 * 3 * 7); +} From 791fa37df5e91619afe0d0d7d4e0b04b167b3ddd Mon Sep 17 00:00:00 2001 From: tiif Date: Sun, 28 Dec 2025 05:51:01 +0000 Subject: [PATCH 0105/1061] Move c-variadic arguments handling into compute_inputs_and_output --- .../rustc_borrowck/src/universal_regions.rs | 66 ++++++++++--------- tests/ui/c-variadic/variadic-ffi-4.stderr | 8 +-- 2 files changed, 39 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index a0d5e1ce780d..fda4719fc3f5 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -543,38 +543,9 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { &indices, ); - let (unnormalized_output_ty, mut unnormalized_input_tys) = + let (unnormalized_output_ty, unnormalized_input_tys) = inputs_and_output.split_last().unwrap(); - // C-variadic fns also have a `VaList` input that's not listed in the signature - // (as it's created inside the body itself, not passed in from outside). - if let DefiningTy::FnDef(def_id, _) = defining_ty { - if self.infcx.tcx.fn_sig(def_id).skip_binder().c_variadic() { - let va_list_did = self - .infcx - .tcx - .require_lang_item(LangItem::VaList, self.infcx.tcx.def_span(self.mir_def)); - - let reg_vid = self - .infcx - .next_nll_region_var(NllRegionVariableOrigin::FreeRegion, || { - RegionCtxt::Free(sym::c_dash_variadic) - }) - .as_var(); - - let region = ty::Region::new_var(self.infcx.tcx, reg_vid); - let va_list_ty = self - .infcx - .tcx - .type_of(va_list_did) - .instantiate(self.infcx.tcx, &[region.into()]); - - unnormalized_input_tys = self.infcx.tcx.mk_type_list_from_iter( - unnormalized_input_tys.iter().copied().chain(iter::once(va_list_ty)), - ); - } - } - let fr_fn_body = self .infcx .next_nll_region_var(NllRegionVariableOrigin::FreeRegion, || { @@ -816,7 +787,40 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { DefiningTy::FnDef(def_id, _) => { let sig = tcx.fn_sig(def_id).instantiate_identity(); let sig = indices.fold_to_region_vids(tcx, sig); - sig.inputs_and_output() + let inputs_and_output = sig.inputs_and_output(); + + // C-variadic fns also have a `VaList` input that's not listed in the signature + // (as it's created inside the body itself, not passed in from outside). + if self.infcx.tcx.fn_sig(def_id).skip_binder().c_variadic() { + let va_list_did = self + .infcx + .tcx + .require_lang_item(LangItem::VaList, self.infcx.tcx.def_span(self.mir_def)); + + let reg_vid = self + .infcx + .next_nll_region_var(NllRegionVariableOrigin::FreeRegion, || { + RegionCtxt::Free(sym::c_dash_variadic) + }) + .as_var(); + + let region = ty::Region::new_var(self.infcx.tcx, reg_vid); + let va_list_ty = self + .infcx + .tcx + .type_of(va_list_did) + .instantiate(self.infcx.tcx, &[region.into()]); + + // The signature needs to follow the order [input_tys, va_list_ty, output_ty] + return inputs_and_output.map_bound(|tys| { + let (output_ty, input_tys) = tys.split_last().unwrap(); + tcx.mk_type_list_from_iter( + input_tys.iter().copied().chain([va_list_ty, *output_ty]), + ) + }); + } + + inputs_and_output } DefiningTy::Const(def_id, _) => { diff --git a/tests/ui/c-variadic/variadic-ffi-4.stderr b/tests/ui/c-variadic/variadic-ffi-4.stderr index a230bb6f5861..01ace5c79680 100644 --- a/tests/ui/c-variadic/variadic-ffi-4.stderr +++ b/tests/ui/c-variadic/variadic-ffi-4.stderr @@ -30,9 +30,9 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:22:5 | LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) { - | ------- ------- has type `VaList<'2>` + | ------- ------- has type `VaList<'1>` | | - | has type `&mut VaList<'1>` + | has type `&mut VaList<'2>` LL | ap0 = &mut ap1; | ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` | @@ -44,9 +44,9 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:22:5 | LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) { - | ------- ------- has type `VaList<'2>` + | ------- ------- has type `VaList<'1>` | | - | has type `&mut VaList<'1>` + | has type `&mut VaList<'2>` LL | ap0 = &mut ap1; | ^^^^^^^^^^^^^^ assignment requires that `'2` must outlive `'1` | From ea3839ae18ff5850e35820017a583235722e8f7f Mon Sep 17 00:00:00 2001 From: Alejandra Gonzalez Date: Tue, 30 Dec 2025 14:15:00 +0100 Subject: [PATCH 0106/1061] Remove a single allocation on doc lints --- clippy_lints/src/doc/mod.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index 120da92da944..5ff66f10a3fe 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -869,10 +869,12 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &[ }), true, ); - let mut doc = fragments.iter().fold(String::new(), |mut acc, fragment| { - add_doc_fragment(&mut acc, fragment); - acc - }); + + let mut doc = String::with_capacity(fragments.iter().map(|frag| frag.doc.as_str().len() + 1).sum()); + + for fragment in &fragments { + add_doc_fragment(&mut doc, fragment); + } doc.pop(); if doc.trim().is_empty() { From a74de276d1e847ae8ecb8107d7b7f10dd7f4486f Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Tue, 30 Dec 2025 17:55:07 +0100 Subject: [PATCH 0107/1061] remove another single allocation --- clippy_lints/src/booleans.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index a04a56d72bc0..0bd459d8b021 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -15,6 +15,7 @@ use rustc_lint::{LateContext, LateLintPass, Level}; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{Span, Symbol, SyntaxContext}; +use std::fmt::Write as _; declare_clippy_lint! { /// ### What it does @@ -356,7 +357,7 @@ impl SuggestContext<'_, '_, '_> { if app != Applicability::MachineApplicable { return None; } - self.output.push_str(&(!snip).to_string()); + let _cannot_fail = write!(&mut self.output, "{}", &(!snip)); } }, True | False | Not(_) => { From 58715c3cceb1e644692f3d736a0b155509b8ab4b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Dec 2025 19:28:01 +0100 Subject: [PATCH 0108/1061] make backtrace look a lot like panics --- src/tools/miri/src/diagnostics.rs | 71 +++++++------------ ...pple_os_unfair_lock_move_with_queue.stderr | 4 +- .../libc_pthread_cond_move.init.stderr | 11 ++- ...thread_cond_move.static_initializer.stderr | 11 ++- .../libc_pthread_create_too_few_args.stderr | 1 + .../libc_pthread_create_too_many_args.stderr | 1 + .../concurrency/libc_pthread_join_main.stderr | 4 +- .../libc_pthread_join_multiple.stderr | 4 +- .../concurrency/libc_pthread_join_self.stderr | 4 +- .../libc_pthread_mutex_deadlock.stderr | 25 ++++--- ...ibc_pthread_mutex_free_while_queued.stderr | 20 +++--- .../libc_pthread_mutex_move.init.stderr | 11 ++- ...hread_mutex_move.static_initializer.stderr | 11 ++- ...ibc_pthread_mutex_read_while_queued.stderr | 4 +- ...bc_pthread_mutex_write_while_queued.stderr | 4 +- .../libc_pthread_mutex_wrong_owner.stderr | 4 +- ...ibc_pthread_rwlock_read_wrong_owner.stderr | 4 +- ..._pthread_rwlock_write_read_deadlock.stderr | 25 ++++--- ...pthread_rwlock_write_write_deadlock.stderr | 25 ++++--- ...bc_pthread_rwlock_write_wrong_owner.stderr | 4 +- .../concurrency/windows_join_detached.stderr | 18 ++--- .../concurrency/windows_join_main.stderr | 26 ++++--- .../concurrency/windows_join_self.stderr | 28 ++++---- .../libc/env-set_var-data-race.stderr | 4 +- .../libc/eventfd_block_read_twice.stderr | 22 +++--- .../libc/eventfd_block_write_twice.stderr | 22 +++--- .../libc/fs/mkstemp_immutable_arg.stderr | 11 ++- .../fs/unix_open_missing_required_mode.stderr | 11 ++- .../libc/libc_epoll_block_two_thread.stderr | 22 +++--- .../socketpair-close-while-blocked.stderr | 22 +++--- .../libc/socketpair_block_read_twice.stderr | 22 +++--- .../libc/socketpair_block_write_twice.stderr | 22 +++--- .../fail/alloc/alloc_error_handler.stderr | 26 ++++--- .../alloc/alloc_error_handler_custom.stderr | 26 +++---- .../alloc/alloc_error_handler_no_std.stderr | 20 +++--- .../fail/alloc/global_system_mixup.stderr | 14 ++-- .../miri/tests/fail/alloc/stack_free.stderr | 17 ++--- .../fail/async-shared-mutable.stack.stderr | 25 +++---- .../fail/async-shared-mutable.tree.stderr | 25 +++---- .../both_borrows/aliasing_mut1.stack.stderr | 15 ++-- .../both_borrows/aliasing_mut1.tree.stderr | 15 ++-- .../both_borrows/aliasing_mut2.stack.stderr | 15 ++-- .../both_borrows/aliasing_mut2.tree.stderr | 15 ++-- .../both_borrows/aliasing_mut3.stack.stderr | 15 ++-- .../both_borrows/aliasing_mut3.tree.stderr | 15 ++-- .../both_borrows/aliasing_mut4.stack.stderr | 15 ++-- .../both_borrows/aliasing_mut4.tree.stderr | 28 +++----- .../box_exclusive_violation1.stack.stderr | 22 ++---- .../box_exclusive_violation1.tree.stderr | 22 ++---- .../box_noalias_violation.stack.stderr | 15 ++-- .../box_noalias_violation.tree.stderr | 15 ++-- .../buggy_split_at_mut.stack.stderr | 15 ++-- .../both_borrows/illegal_write6.stack.stderr | 15 ++-- .../both_borrows/illegal_write6.tree.stderr | 15 ++-- ...invalidate_against_protector2.stack.stderr | 15 ++-- .../invalidate_against_protector2.tree.stderr | 15 ++-- ...invalidate_against_protector3.stack.stderr | 15 ++-- .../invalidate_against_protector3.tree.stderr | 15 ++-- .../issue-miri-1050-1.stack.stderr | 18 ++--- .../issue-miri-1050-1.tree.stderr | 18 ++--- .../issue-miri-1050-2.stack.stderr | 14 ++-- .../issue-miri-1050-2.tree.stderr | 14 ++-- .../mut_exclusive_violation1.stack.stderr | 22 ++---- .../mut_exclusive_violation1.tree.stderr | 22 ++---- .../newtype_pair_retagging.stack.stderr | 35 +++------ .../newtype_pair_retagging.tree.stderr | 38 ++++------ .../newtype_retagging.stack.stderr | 35 +++------ .../newtype_retagging.tree.stderr | 38 ++++------ .../retag_data_race_write.stack.stderr | 18 ++--- .../retag_data_race_write.tree.stderr | 18 ++--- .../return_invalid_shr.stack.stderr | 15 ++-- .../return_invalid_shr.tree.stderr | 15 ++-- .../return_invalid_shr_option.stack.stderr | 15 ++-- .../return_invalid_shr_option.tree.stderr | 15 ++-- .../return_invalid_shr_tuple.stack.stderr | 15 ++-- .../return_invalid_shr_tuple.tree.stderr | 15 ++-- .../shr_frozen_violation1.stack.stderr | 22 ++---- .../shr_frozen_violation1.tree.stderr | 22 ++---- .../miri/tests/fail/box-cell-alias.stderr | 15 ++-- .../fail/closures/uninhabited-variant.stderr | 11 ++- .../concurrency/mutex-leak-move-deadlock.rs | 1 + .../mutex-leak-move-deadlock.stderr | 5 -- .../tests/fail/coroutine-pinned-moved.stderr | 25 +++---- .../dangling_pointer_to_raw_pointer.stderr | 11 ++- .../storage_dead_dangling.stderr | 11 ++- .../fail/data_race/alloc_read_race.stderr | 4 +- .../fail/data_race/alloc_write_race.stderr | 4 +- .../atomic_read_na_write_race1.stderr | 4 +- .../atomic_read_na_write_race2.stderr | 4 +- .../atomic_write_na_read_race1.stderr | 4 +- .../atomic_write_na_read_race2.stderr | 4 +- .../atomic_write_na_write_race1.stderr | 4 +- .../atomic_write_na_write_race2.stderr | 4 +- .../dangling_thread_async_race.stderr | 4 +- .../fail/data_race/dealloc_read_race1.stderr | 4 +- .../fail/data_race/dealloc_read_race2.stderr | 4 +- .../data_race/dealloc_read_race_stack.stderr | 4 +- .../fail/data_race/dealloc_write_race1.stderr | 4 +- .../fail/data_race/dealloc_write_race2.stderr | 4 +- .../data_race/dealloc_write_race_stack.stderr | 4 +- .../enable_after_join_to_main.stderr | 4 +- .../local_variable_alloc_race.stderr | 4 +- .../data_race/local_variable_read_race.stderr | 4 +- .../local_variable_write_race.stderr | 4 +- ...ze_read_read_write.match_first_load.stderr | 4 +- ...e_read_read_write.match_second_load.stderr | 4 +- .../mixed_size_read_write.read_write.stderr | 4 +- .../mixed_size_read_write.write_read.stderr | 4 +- .../mixed_size_read_write_read.stderr | 4 +- .../mixed_size_write_write.fst.stderr | 4 +- .../mixed_size_write_write.snd.stderr | 4 +- .../fail/data_race/read_write_race.stderr | 4 +- .../data_race/read_write_race_stack.stderr | 4 +- .../fail/data_race/relax_acquire_race.stderr | 4 +- .../fail/data_race/release_seq_race.stderr | 4 +- .../release_seq_race_same_thread.stderr | 4 +- .../miri/tests/fail/data_race/rmw_race.stderr | 4 +- .../fail/data_race/write_write_race.stderr | 4 +- .../data_race/write_write_race_stack.stderr | 4 +- ...et-discriminant-niche-variant-wrong.stderr | 11 ++- .../arg_inplace_mutate.stack.stderr | 15 ++-- .../arg_inplace_mutate.tree.stderr | 15 ++-- .../arg_inplace_observe_during.none.stderr | 11 ++- .../arg_inplace_observe_during.stack.stderr | 15 ++-- .../arg_inplace_observe_during.tree.stderr | 15 ++-- .../exported_symbol_bad_unwind2.both.stderr | 19 +---- ...orted_symbol_bad_unwind2.definition.stderr | 19 +---- .../return_pointer_aliasing_read.none.stderr | 11 ++- .../return_pointer_aliasing_read.stack.stderr | 15 ++-- .../return_pointer_aliasing_read.tree.stderr | 15 ++-- ...return_pointer_aliasing_write.stack.stderr | 15 ++-- .../return_pointer_aliasing_write.tree.stderr | 15 ++-- ...nter_aliasing_write_tail_call.stack.stderr | 15 ++-- ...inter_aliasing_write_tail_call.tree.stderr | 15 ++-- .../simd_feature_flag_difference.stderr | 11 ++- .../ptr_metadata_uninit_slice_data.stderr | 11 ++- .../ptr_metadata_uninit_slice_len.stderr | 11 ++- .../ptr_metadata_uninit_thin.stderr | 11 ++- .../typed-swap-invalid-array.stderr | 11 ++- .../typed-swap-invalid-scalar.left.stderr | 11 ++- .../typed-swap-invalid-scalar.right.stderr | 11 ++- .../miri/tests/fail/issue-miri-1112.stderr | 11 ++- src/tools/miri/tests/fail/memleak_rc.stderr | 11 ++- .../miri/tests/fail/never_transmute_void.rs | 2 - .../tests/fail/never_transmute_void.stderr | 11 ++- .../tests/fail/overlapping_assignment.stderr | 11 ++- .../miri/tests/fail/panic/abort_unwind.stderr | 13 +--- .../miri/tests/fail/panic/bad_unwind.stderr | 20 +++--- .../miri/tests/fail/panic/double_panic.stderr | 15 +--- src/tools/miri/tests/fail/panic/no_std.stderr | 11 ++- .../miri/tests/fail/panic/panic_abort1.stderr | 29 ++++---- .../miri/tests/fail/panic/panic_abort2.stderr | 29 ++++---- .../miri/tests/fail/panic/panic_abort3.stderr | 29 ++++---- .../miri/tests/fail/panic/panic_abort4.stderr | 29 ++++---- .../fail/panic/tls_macro_const_drop_panic.rs | 1 + .../tests/fail/panic/tls_macro_drop_panic.rs | 3 +- .../fail/panic/tls_macro_drop_panic.stderr | 1 + .../provenance/provenance_transmute.stderr | 11 ++- .../tests/fail/ptr_swap_nonoverlapping.stderr | 10 +-- .../miri/tests/fail/shims/ctor_ub.stderr | 3 +- .../tests/fail/shims/fs/isolated_file.stderr | 41 ++++++----- .../tests/fail/shims/isolated_stdin.stderr | 4 -- .../deallocate_against_protector1.stderr | 37 ++++------ .../drop_in_place_protector.stderr | 21 +++--- .../drop_in_place_retag.stderr | 17 ++--- .../invalidate_against_protector1.stderr | 15 ++-- .../stacked_borrows/pointer_smuggling.stderr | 15 ++-- .../retag_data_race_protected_read.stderr | 4 +- .../retag_data_race_read.stderr | 18 ++--- .../stacked_borrows/return_invalid_mut.stderr | 15 ++-- .../return_invalid_mut_option.stderr | 15 ++-- .../return_invalid_mut_tuple.stderr | 15 ++-- .../tests/fail/tail_calls/cc-mismatch.stderr | 40 +++++++---- .../fail/tail_calls/dangling-local-var.stderr | 15 ++-- .../tests/fail/terminate-terminator.stderr | 25 +------ .../miri/tests/fail/tls_macro_leak.stderr | 19 +++-- .../fail/tree_borrows/outside-range.stderr | 15 ++-- .../fail/tree_borrows/pass_invalid_mut.stderr | 15 ++-- ...peated_foreign_read_lazy_conflicted.stderr | 15 ++-- .../reserved/cell-protected-write.stderr | 15 ++-- .../reserved/int-protected-write.stderr | 15 ++-- .../reservedim_spurious_write.with.stderr | 4 +- .../reservedim_spurious_write.without.stderr | 4 +- .../fail/tree_borrows/spurious_read.stderr | 18 ++--- .../tree_borrows/strongly-protected.stderr | 40 ++++------- ...tree_traversal_skipping_diagnostics.stderr | 15 ++-- .../wildcard/protected_wildcard.stderr | 15 ++-- .../wildcard/protector_conflicted.stderr | 11 ++- .../strongly_protected_wildcard.stderr | 40 ++++------- .../tree_borrows/write-during-2phase.stderr | 21 ++---- .../unaligned_pointers/drop_in_place.stderr | 11 ++- ...ld_requires_parent_struct_alignment.stderr | 11 ++- ...d_requires_parent_struct_alignment2.stderr | 11 ++- .../reference_to_packed.stderr | 11 ++- .../uninit/uninit_alloc_diagnostic.stderr | 14 ++-- ...it_alloc_diagnostic_with_provenance.stderr | 14 ++-- .../tests/fail/unwind-action-terminate.stderr | 19 +---- .../cast_fn_ptr_invalid_caller_arg.stderr | 11 ++- .../fail/validity/invalid_char_cast.stderr | 11 ++- .../fail/validity/invalid_char_match.stderr | 11 ++- .../fail/validity/invalid_enum_cast.stderr | 11 ++- .../tests/fail/weak_memory/weak_uninit.stderr | 4 +- .../atomics/atomic_ptr_double_free.stderr | 28 +++----- .../atomic_ptr_alloc_race.dealloc.stderr | 17 ++--- .../atomic_ptr_alloc_race.write.stderr | 17 ++--- .../atomic_ptr_dealloc_write_race.stderr | 21 +++--- .../atomic_ptr_write_dealloc_race.stderr | 17 ++--- .../genmc/fail/data_race/mpu2_rels_rlx.stderr | 17 ++--- .../data_race/weak_orderings.rel_rlx.stderr | 17 ++--- .../data_race/weak_orderings.rlx_acq.stderr | 17 ++--- .../data_race/weak_orderings.rlx_rlx.stderr | 17 ++--- .../miri/tests/genmc/fail/shims/exit.stderr | 4 +- .../shims/mutex_diff_thread_unlock.stderr | 23 +++--- .../fail/shims/mutex_double_unlock.stderr | 17 ++--- .../fail/simple/alloc_large.multiple.stderr | 23 +++--- .../fail/simple/alloc_large.single.stderr | 23 +++--- .../cas_failure_ord_racy_key_init.stderr | 24 +++---- .../fail/tracing/partial_init.stderr | 22 +++--- .../tracing/unexposed_reachable_alloc.stderr | 22 +++--- .../pass/ptr_read_access.notrace.stderr | 22 +++--- .../pass/ptr_read_access.trace.stderr | 22 +++--- .../pass/ptr_write_access.notrace.stderr | 11 ++- .../pass/ptr_write_access.trace.stderr | 11 ++- src/tools/miri/tests/panic/panic1.stderr | 8 +-- .../tests/pass/alloc-access-tracking.stderr | 14 ++-- .../backtrace/backtrace-global-alloc.stderr | 28 ++++---- .../tests/pass/backtrace/backtrace-std.stderr | 36 +++++----- src/tools/miri/tests/ui.rs | 2 - 228 files changed, 1381 insertions(+), 1927 deletions(-) diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 8de30d870327..1f87ac60c17a 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -576,11 +576,9 @@ fn report_msg<'tcx>( } // Show note and help messages. - let mut extra_span = false; for (span_data, note) in notes { if let Some(span_data) = span_data { err.span_note(span_data.span(), note); - extra_span = true; } else { err.note(note); } @@ -588,60 +586,41 @@ fn report_msg<'tcx>( for (span_data, help) in helps { if let Some(span_data) = span_data { err.span_help(span_data.span(), help); - extra_span = true; } else { err.help(help); } } + // Only print thread name if there are multiple threads. + if let Some(thread) = thread + && machine.threads.get_total_thread_count() > 1 + { + err.note(format!( + "this is on thread `{}`", + machine.threads.get_thread_display_name(thread) + )); + } // Add backtrace - if let Some((first, rest)) = stacktrace.split_first() { - // Start with the function and thread that contain the first span. - let mut fn_and_thread = String::new(); - // Only print thread name if there are multiple threads. - if let Some(thread) = thread - && machine.threads.get_total_thread_count() > 1 - { - write!( - fn_and_thread, - "on thread `{}`", - machine.threads.get_thread_display_name(thread) - ) - .unwrap(); - } - // Only print function name if we show a backtrace - if rest.len() > 0 || !origin_span.is_dummy() { - if !fn_and_thread.is_empty() { - fn_and_thread.push_str(", "); - } - write!(fn_and_thread, "{first}").unwrap(); - } - if !fn_and_thread.is_empty() { - if extra_span && rest.len() > 0 { - // Print a `span_note` as otherwise the backtrace looks attached to the last - // `span_help`. We somewhat arbitrarily use the span of the surrounding function. - err.span_note( - tcx.def_span(first.instance.def_id()), - format!("{level} occurred {fn_and_thread}"), - ); - } else { - err.note(format!("this is {fn_and_thread}")); - } - } - // Continue with where that function got called. - for frame_info in rest.iter() { - let is_local = machine.is_local(frame_info.instance); - // No span for non-local frames and the first frame (which is the error site). - if is_local { - err.span_note(frame_info.span, format!("which got called {frame_info}")); - } else { - let sm = tcx.sess.source_map(); + if stacktrace.len() > 0 { + // Skip it if we'd only shpw the span we have already shown + if stacktrace.len() > 1 { + let sm = tcx.sess.source_map(); + let mut out = format!("stack backtrace:"); + for (idx, frame_info) in stacktrace.iter().enumerate() { let span = sm.span_to_diagnostic_string(frame_info.span); - err.note(format!("which got called {frame_info} (at {span})")); + write!(out, "\n{idx}: {}", frame_info.instance).unwrap(); + write!(out, "\n at {span}").unwrap(); } + err.note(out); } + // For TLS dtors and non-main threads, show the "origin" if !origin_span.is_dummy() { - err.span_note(origin_span, format!("which got called indirectly due to this code")); + let what = if stacktrace.len() > 1 { + "the last function in that backtrace" + } else { + "the current function" + }; + err.span_note(origin_span, format!("{what} got called indirectly due to this code")); } } else if !span.is_dummy() { err.note(format!("this {level} occurred while pushing a call frame onto an empty stack")); diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_move_with_queue.stderr b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_move_with_queue.stderr index b943ac1f61ef..b4d2d2be6530 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_move_with_queue.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_move_with_queue.stderr @@ -6,8 +6,8 @@ LL | let _val = atomic_ref.load(Ordering::Relaxed); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail-dep/concurrency/apple_os_unfair_lock_move_with_queue.rs:LL:CC | LL | / ... s.spawn(|| { diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_move.init.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_move.init.stderr index 4507c1bfa227..4e494e1d2a2c 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_move.init.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_move.init.stderr @@ -6,12 +6,11 @@ LL | libc::pthread_cond_destroy(cond2.as_mut_ptr()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `check` -note: which got called inside `main` - --> tests/fail-dep/concurrency/libc_pthread_cond_move.rs:LL:CC - | -LL | check() - | ^^^^^^^ + = note: stack backtrace: + 0: check + at tests/fail-dep/concurrency/libc_pthread_cond_move.rs:LL:CC + 1: main + at tests/fail-dep/concurrency/libc_pthread_cond_move.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_move.static_initializer.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_move.static_initializer.stderr index 6132785b13dd..8b8ead3976f9 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_move.static_initializer.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_move.static_initializer.stderr @@ -6,12 +6,11 @@ LL | libc::pthread_cond_destroy(&mut cond2 as *mut _); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `check` -note: which got called inside `main` - --> tests/fail-dep/concurrency/libc_pthread_cond_move.rs:LL:CC - | -LL | check() - | ^^^^^^^ + = note: stack backtrace: + 0: check + at tests/fail-dep/concurrency/libc_pthread_cond_move.rs:LL:CC + 1: main + at tests/fail-dep/concurrency/libc_pthread_cond_move.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr index fef91e85470d..979a1a8337b5 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr @@ -6,6 +6,7 @@ LL | libc::pthread_create(&mut native, ptr::null(), thread_start, pt | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` = note: this error occurred while pushing a call frame onto an empty stack = note: the span indicates which code caused the function to be called, but may not be the literal call site diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr index 4d70576d784c..e8ad65a74ac8 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr @@ -6,6 +6,7 @@ LL | libc::pthread_create(&mut native, ptr::null(), thread_start, pt | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: this is on thread `unnamed-ID` = note: this error occurred while pushing a call frame onto an empty stack = note: the span indicates which code caused the function to be called, but may not be the literal call site diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.stderr index c364642fc629..0d07c2bfa351 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.stderr @@ -6,8 +6,8 @@ LL | ... assert_eq!(libc::pthread_join(thread_id, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail-dep/concurrency/libc_pthread_join_main.rs:LL:CC | LL | let handle = thread::spawn(move || { diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.stderr index b9bf801eaf61..8754aaecef94 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.stderr @@ -6,8 +6,8 @@ LL | ... assert_eq!(libc::pthread_join(native_copy, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail-dep/concurrency/libc_pthread_join_multiple.rs:LL:CC | LL | ... let handle = thread::spawn(move || { diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.stderr index ddf3372a7277..ffc7f2fe4cac 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.stderr @@ -6,8 +6,8 @@ LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail-dep/concurrency/libc_pthread_join_self.rs:LL:CC | LL | let handle = thread::spawn(|| { diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr index 1e7b0abf341a..468c0e63cc34 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr @@ -4,17 +4,16 @@ error: the evaluated program deadlocked LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; | ^ thread got stuck here | - = note: this is on thread `main`, inside `std::sys::thread::PLATFORM::Thread::join` - = note: which got called inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` (at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC) - = note: which got called inside `std::thread::JoinHandle::<()>::join` (at RUSTLIB/std/src/thread/join_handle.rs:LL:CC) -note: which got called inside `main` - --> tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs:LL:CC - | -LL | / thread::spawn(move || { -LL | | assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _), 0); -LL | | }) -LL | | .join() - | |_______________^ + = note: this is on thread `main` + = note: stack backtrace: + 0: std::sys::thread::PLATFORM::Thread::join + at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC + 1: std::thread::lifecycle::JoinInner::join + at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC + 2: std::thread::JoinHandle::join + at RUSTLIB/std/src/thread/join_handle.rs:LL:CC + 3: main + at tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs:LL:CC error: the evaluated program deadlocked --> tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs:LL:CC @@ -22,8 +21,8 @@ error: the evaluated program deadlocked LL | assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _), 0); | ^ thread got stuck here | - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs:LL:CC | LL | / thread::spawn(move || { diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_free_while_queued.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_free_while_queued.stderr index 765604ea0060..96be3f5764a3 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_free_while_queued.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_free_while_queued.stderr @@ -6,15 +6,17 @@ LL | self.1.deallocate(From::from(ptr.cast()), layout); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside ` as std::ops::Drop>::drop` - = note: which got called inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` (at RUSTLIB/core/src/ptr/mod.rs:LL:CC) - = note: which got called inside `std::mem::drop::>` (at RUSTLIB/core/src/mem/mod.rs:LL:CC) -note: which got called inside closure - --> tests/fail-dep/concurrency/libc_pthread_mutex_free_while_queued.rs:LL:CC - | -LL | drop(unsafe { Box::from_raw(m.get().cast::()) }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` + = note: stack backtrace: + 0: as std::ops::Drop>::drop + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 1: std::ptr::drop_in_place)) + at RUSTLIB/core/src/ptr/mod.rs:LL:CC + 2: std::mem::drop + at RUSTLIB/core/src/mem/mod.rs:LL:CC + 3: main::{closure#0}::{closure#2} + at tests/fail-dep/concurrency/libc_pthread_mutex_free_while_queued.rs:LL:CC +note: the last function in that backtrace got called indirectly due to this code --> tests/fail-dep/concurrency/libc_pthread_mutex_free_while_queued.rs:LL:CC | LL | / s.spawn(|| { diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_move.init.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_move.init.stderr index f9e06c75e06d..389b014ed647 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_move.init.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_move.init.stderr @@ -6,12 +6,11 @@ LL | libc::pthread_mutex_lock(&mut m2 as *mut _); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `check` -note: which got called inside `main` - --> tests/fail-dep/concurrency/libc_pthread_mutex_move.rs:LL:CC - | -LL | check(); - | ^^^^^^^ + = note: stack backtrace: + 0: check + at tests/fail-dep/concurrency/libc_pthread_mutex_move.rs:LL:CC + 1: main + at tests/fail-dep/concurrency/libc_pthread_mutex_move.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_move.static_initializer.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_move.static_initializer.stderr index 643518c60617..ba281a548c24 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_move.static_initializer.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_move.static_initializer.stderr @@ -6,12 +6,11 @@ LL | libc::pthread_mutex_unlock(&mut m2 as *mut _); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `check` -note: which got called inside `main` - --> tests/fail-dep/concurrency/libc_pthread_mutex_move.rs:LL:CC - | -LL | check(); - | ^^^^^^^ + = note: stack backtrace: + 0: check + at tests/fail-dep/concurrency/libc_pthread_mutex_move.rs:LL:CC + 1: main + at tests/fail-dep/concurrency/libc_pthread_mutex_move.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_read_while_queued.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_read_while_queued.stderr index fd9cddebabc7..a8d9679eb959 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_read_while_queued.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_read_while_queued.stderr @@ -6,8 +6,8 @@ LL | ... let _val = atomic_ref.load(Ordering::Relaxed); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail-dep/concurrency/libc_pthread_mutex_read_while_queued.rs:LL:CC | LL | / ... s.spawn(|| { diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_write_while_queued.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_write_while_queued.stderr index 02a0f25af492..9bc413fe8d53 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_write_while_queued.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_write_while_queued.stderr @@ -6,8 +6,8 @@ LL | atomic_ref.store(0, Ordering::Relaxed); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail-dep/concurrency/libc_pthread_mutex_write_while_queued.rs:LL:CC | LL | / s.spawn(|| { diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.stderr index 25dae98ef5d9..0a1de6332562 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.stderr @@ -6,8 +6,8 @@ LL | ... assert_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.rs:LL:CC | LL | / ... thread::spawn(move || { diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.stderr index 37c7540afb27..d077c6a552ae 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.stderr @@ -6,8 +6,8 @@ LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.rs:LL:CC | LL | / ... thread::spawn(move || { diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr index 0818f213f5e7..e00c297a9b29 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr @@ -4,17 +4,16 @@ error: the evaluated program deadlocked LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; | ^ thread got stuck here | - = note: this is on thread `main`, inside `std::sys::thread::PLATFORM::Thread::join` - = note: which got called inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` (at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC) - = note: which got called inside `std::thread::JoinHandle::<()>::join` (at RUSTLIB/std/src/thread/join_handle.rs:LL:CC) -note: which got called inside `main` - --> tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC - | -LL | / thread::spawn(move || { -LL | | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); -LL | | }) -LL | | .join() - | |_______________^ + = note: this is on thread `main` + = note: stack backtrace: + 0: std::sys::thread::PLATFORM::Thread::join + at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC + 1: std::thread::lifecycle::JoinInner::join + at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC + 2: std::thread::JoinHandle::join + at RUSTLIB/std/src/thread/join_handle.rs:LL:CC + 3: main + at tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC error: the evaluated program deadlocked --> tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC @@ -22,8 +21,8 @@ error: the evaluated program deadlocked LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); | ^ thread got stuck here | - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC | LL | / thread::spawn(move || { diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr index 4ee88c0059d2..21fa8dcbd18d 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr @@ -4,17 +4,16 @@ error: the evaluated program deadlocked LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; | ^ thread got stuck here | - = note: this is on thread `main`, inside `std::sys::thread::PLATFORM::Thread::join` - = note: which got called inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` (at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC) - = note: which got called inside `std::thread::JoinHandle::<()>::join` (at RUSTLIB/std/src/thread/join_handle.rs:LL:CC) -note: which got called inside `main` - --> tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC - | -LL | / thread::spawn(move || { -LL | | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); -LL | | }) -LL | | .join() - | |_______________^ + = note: this is on thread `main` + = note: stack backtrace: + 0: std::sys::thread::PLATFORM::Thread::join + at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC + 1: std::thread::lifecycle::JoinInner::join + at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC + 2: std::thread::JoinHandle::join + at RUSTLIB/std/src/thread/join_handle.rs:LL:CC + 3: main + at tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC error: the evaluated program deadlocked --> tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC @@ -22,8 +21,8 @@ error: the evaluated program deadlocked LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); | ^ thread got stuck here | - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC | LL | / thread::spawn(move || { diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.stderr index 94578338f40b..ceba695ce5fb 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.stderr @@ -6,8 +6,8 @@ LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.rs:LL:CC | LL | / ... thread::spawn(move || { diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_detached.stderr b/src/tools/miri/tests/fail-dep/concurrency/windows_join_detached.stderr index 1765f0a18041..73e79852d63a 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_detached.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_detached.stderr @@ -6,14 +6,16 @@ LL | let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle( | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `main`, inside `std::sys::thread::PLATFORM::Thread::join` - = note: which got called inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` (at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC) - = note: which got called inside `std::thread::JoinHandle::<()>::join` (at RUSTLIB/std/src/thread/join_handle.rs:LL:CC) -note: which got called inside `main` - --> tests/fail-dep/concurrency/windows_join_detached.rs:LL:CC - | -LL | thread.join().unwrap(); - | ^^^^^^^^^^^^^ + = note: this is on thread `main` + = note: stack backtrace: + 0: std::sys::thread::PLATFORM::Thread::join + at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC + 1: std::thread::lifecycle::JoinInner::join + at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC + 2: std::thread::JoinHandle::join + at RUSTLIB/std/src/thread/join_handle.rs:LL:CC + 3: main + at tests/fail-dep/concurrency/windows_join_detached.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr index ee0aa254abaf..3d324ad0bdef 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr @@ -4,18 +4,16 @@ error: the evaluated program deadlocked LL | let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) }; | ^ thread got stuck here | - = note: this is on thread `main`, inside `std::sys::thread::PLATFORM::Thread::join` - = note: which got called inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` (at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC) - = note: which got called inside `std::thread::JoinHandle::<()>::join` (at RUSTLIB/std/src/thread/join_handle.rs:LL:CC) -note: which got called inside `main` - --> tests/fail-dep/concurrency/windows_join_main.rs:LL:CC - | -LL | / thread::spawn(|| { -LL | | unsafe { -LL | | assert_eq!(WaitForSingleObject(MAIN_THREAD, INFINITE), WAIT_OBJECT_0); -... | -LL | | .join() - | |___________^ + = note: this is on thread `main` + = note: stack backtrace: + 0: std::sys::thread::PLATFORM::Thread::join + at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC + 1: std::thread::lifecycle::JoinInner::join + at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC + 2: std::thread::JoinHandle::join + at RUSTLIB/std/src/thread/join_handle.rs:LL:CC + 3: main + at tests/fail-dep/concurrency/windows_join_main.rs:LL:CC error: the evaluated program deadlocked --> tests/fail-dep/concurrency/windows_join_main.rs:LL:CC @@ -23,8 +21,8 @@ error: the evaluated program deadlocked LL | assert_eq!(WaitForSingleObject(MAIN_THREAD, INFINITE), WAIT_OBJECT_0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ thread got stuck here | - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail-dep/concurrency/windows_join_main.rs:LL:CC | LL | / thread::spawn(|| { diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr b/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr index 561464d47179..8f28324363b3 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr @@ -4,20 +4,16 @@ error: the evaluated program deadlocked LL | let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) }; | ^ thread got stuck here | - = note: this is on thread `main`, inside `std::sys::thread::PLATFORM::Thread::join` - = note: which got called inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` (at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC) - = note: which got called inside `std::thread::JoinHandle::<()>::join` (at RUSTLIB/std/src/thread/join_handle.rs:LL:CC) -note: which got called inside `main` - --> tests/fail-dep/concurrency/windows_join_self.rs:LL:CC - | -LL | / thread::spawn(|| { -LL | | unsafe { -LL | | let native = GetCurrentThread(); -LL | | assert_eq!(WaitForSingleObject(native, INFINITE), WAIT_OBJECT_0); -LL | | } -LL | | }) -LL | | .join() - | |___________^ + = note: this is on thread `main` + = note: stack backtrace: + 0: std::sys::thread::PLATFORM::Thread::join + at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC + 1: std::thread::lifecycle::JoinInner::join + at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC + 2: std::thread::JoinHandle::join + at RUSTLIB/std/src/thread/join_handle.rs:LL:CC + 3: main + at tests/fail-dep/concurrency/windows_join_self.rs:LL:CC error: the evaluated program deadlocked --> tests/fail-dep/concurrency/windows_join_self.rs:LL:CC @@ -25,8 +21,8 @@ error: the evaluated program deadlocked LL | assert_eq!(WaitForSingleObject(native, INFINITE), WAIT_OBJECT_0); | ^ thread got stuck here | - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail-dep/concurrency/windows_join_self.rs:LL:CC | LL | / thread::spawn(|| { diff --git a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr index eed33569af11..635091cc0173 100644 --- a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr +++ b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr @@ -11,8 +11,8 @@ LL | env::set_var("MY_RUST_VAR", "Ferris"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail-dep/libc/env-set_var-data-race.rs:LL:CC | LL | let t = thread::spawn(|| unsafe { diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.stderr b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.stderr index d0c8169fe7d2..f5cfd35847af 100644 --- a/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.stderr +++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.stderr @@ -4,14 +4,16 @@ error: the evaluated program deadlocked LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; | ^ thread got stuck here | - = note: this is on thread `main`, inside `std::sys::thread::PLATFORM::Thread::join` - = note: which got called inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` (at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC) - = note: which got called inside `std::thread::JoinHandle::<()>::join` (at RUSTLIB/std/src/thread/join_handle.rs:LL:CC) -note: which got called inside `main` - --> tests/fail-dep/libc/eventfd_block_read_twice.rs:LL:CC - | -LL | thread2.join().unwrap(); - | ^^^^^^^^^^^^^^ + = note: this is on thread `main` + = note: stack backtrace: + 0: std::sys::thread::PLATFORM::Thread::join + at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC + 1: std::thread::lifecycle::JoinInner::join + at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC + 2: std::thread::JoinHandle::join + at RUSTLIB/std/src/thread/join_handle.rs:LL:CC + 3: main + at tests/fail-dep/libc/eventfd_block_read_twice.rs:LL:CC error: the evaluated program deadlocked --> tests/fail-dep/libc/eventfd_block_read_twice.rs:LL:CC @@ -19,8 +21,8 @@ error: the evaluated program deadlocked LL | let res: i64 = unsafe { libc::read(fd, buf.as_mut_ptr().cast(), 8).try_into().unwrap() }; | ^ thread got stuck here | - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail-dep/libc/eventfd_block_read_twice.rs:LL:CC | LL | let thread2 = thread::spawn(move || { diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.stderr b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.stderr index 878059cb5ef2..92c3fc47c4fd 100644 --- a/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.stderr +++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.stderr @@ -4,14 +4,16 @@ error: the evaluated program deadlocked LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; | ^ thread got stuck here | - = note: this is on thread `main`, inside `std::sys::thread::PLATFORM::Thread::join` - = note: which got called inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` (at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC) - = note: which got called inside `std::thread::JoinHandle::<()>::join` (at RUSTLIB/std/src/thread/join_handle.rs:LL:CC) -note: which got called inside `main` - --> tests/fail-dep/libc/eventfd_block_write_twice.rs:LL:CC - | -LL | thread2.join().unwrap(); - | ^^^^^^^^^^^^^^ + = note: this is on thread `main` + = note: stack backtrace: + 0: std::sys::thread::PLATFORM::Thread::join + at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC + 1: std::thread::lifecycle::JoinInner::join + at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC + 2: std::thread::JoinHandle::join + at RUSTLIB/std/src/thread/join_handle.rs:LL:CC + 3: main + at tests/fail-dep/libc/eventfd_block_write_twice.rs:LL:CC error: the evaluated program deadlocked --> tests/fail-dep/libc/eventfd_block_write_twice.rs:LL:CC @@ -19,8 +21,8 @@ error: the evaluated program deadlocked LL | libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8).try_into().unwrap() | ^ thread got stuck here | - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail-dep/libc/eventfd_block_write_twice.rs:LL:CC | LL | let thread2 = thread::spawn(move || { diff --git a/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.stderr b/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.stderr index ec7b681dfad4..edf428ae8dda 100644 --- a/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.stderr +++ b/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.stderr @@ -6,12 +6,11 @@ LL | let _fd = unsafe { libc::mkstemp(s) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `test_mkstemp_immutable_arg` -note: which got called inside `main` - --> tests/fail-dep/libc/fs/mkstemp_immutable_arg.rs:LL:CC - | -LL | test_mkstemp_immutable_arg(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: test_mkstemp_immutable_arg + at tests/fail-dep/libc/fs/mkstemp_immutable_arg.rs:LL:CC + 1: main + at tests/fail-dep/libc/fs/mkstemp_immutable_arg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr index 9f5ea4ed021f..a85fae9c7dd2 100644 --- a/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr +++ b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr @@ -6,12 +6,11 @@ LL | let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `test_file_open_missing_needed_mode` -note: which got called inside `main` - --> tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs:LL:CC - | -LL | test_file_open_missing_needed_mode(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: test_file_open_missing_needed_mode + at tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs:LL:CC + 1: main + at tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.stderr b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.stderr index f7f77647acb5..af6578357a59 100644 --- a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.stderr +++ b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.stderr @@ -4,14 +4,16 @@ error: the evaluated program deadlocked LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; | ^ thread got stuck here | - = note: this is on thread `main`, inside `std::sys::thread::PLATFORM::Thread::join` - = note: which got called inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` (at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC) - = note: which got called inside `std::thread::JoinHandle::<()>::join` (at RUSTLIB/std/src/thread/join_handle.rs:LL:CC) -note: which got called inside `main` - --> tests/fail-dep/libc/libc_epoll_block_two_thread.rs:LL:CC - | -LL | thread2.join().unwrap(); - | ^^^^^^^^^^^^^^ + = note: this is on thread `main` + = note: stack backtrace: + 0: std::sys::thread::PLATFORM::Thread::join + at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC + 1: std::thread::lifecycle::JoinInner::join + at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC + 2: std::thread::JoinHandle::join + at RUSTLIB/std/src/thread/join_handle.rs:LL:CC + 3: main + at tests/fail-dep/libc/libc_epoll_block_two_thread.rs:LL:CC error: the evaluated program deadlocked --> tests/fail-dep/libc/libc_epoll_block_two_thread.rs:LL:CC @@ -19,8 +21,8 @@ error: the evaluated program deadlocked LL | check_epoll_wait::(epfd, &expected, -1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ thread got stuck here | - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail-dep/libc/libc_epoll_block_two_thread.rs:LL:CC | LL | let thread2 = thread::spawn(move || { diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr index b1b1fddc6735..b40c35d6d266 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr +++ b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr @@ -4,14 +4,16 @@ error: the evaluated program deadlocked LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; | ^ thread got stuck here | - = note: this is on thread `main`, inside `std::sys::thread::PLATFORM::Thread::join` - = note: which got called inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` (at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC) - = note: which got called inside `std::thread::JoinHandle::<()>::join` (at RUSTLIB/std/src/thread/join_handle.rs:LL:CC) -note: which got called inside `main` - --> tests/fail-dep/libc/socketpair-close-while-blocked.rs:LL:CC - | -LL | thread1.join().unwrap(); - | ^^^^^^^^^^^^^^ + = note: this is on thread `main` + = note: stack backtrace: + 0: std::sys::thread::PLATFORM::Thread::join + at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC + 1: std::thread::lifecycle::JoinInner::join + at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC + 2: std::thread::JoinHandle::join + at RUSTLIB/std/src/thread/join_handle.rs:LL:CC + 3: main + at tests/fail-dep/libc/socketpair-close-while-blocked.rs:LL:CC error: the evaluated program deadlocked --> tests/fail-dep/libc/socketpair-close-while-blocked.rs:LL:CC @@ -19,8 +21,8 @@ error: the evaluated program deadlocked LL | libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) | ^ thread got stuck here | - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail-dep/libc/socketpair-close-while-blocked.rs:LL:CC | LL | let thread1 = thread::spawn(move || { diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr index a556ba592ec8..d649076374f5 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr @@ -4,14 +4,16 @@ error: the evaluated program deadlocked LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; | ^ thread got stuck here | - = note: this is on thread `main`, inside `std::sys::thread::PLATFORM::Thread::join` - = note: which got called inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` (at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC) - = note: which got called inside `std::thread::JoinHandle::<()>::join` (at RUSTLIB/std/src/thread/join_handle.rs:LL:CC) -note: which got called inside `main` - --> tests/fail-dep/libc/socketpair_block_read_twice.rs:LL:CC - | -LL | thread2.join().unwrap(); - | ^^^^^^^^^^^^^^ + = note: this is on thread `main` + = note: stack backtrace: + 0: std::sys::thread::PLATFORM::Thread::join + at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC + 1: std::thread::lifecycle::JoinInner::join + at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC + 2: std::thread::JoinHandle::join + at RUSTLIB/std/src/thread/join_handle.rs:LL:CC + 3: main + at tests/fail-dep/libc/socketpair_block_read_twice.rs:LL:CC error: the evaluated program deadlocked --> tests/fail-dep/libc/socketpair_block_read_twice.rs:LL:CC @@ -19,8 +21,8 @@ error: the evaluated program deadlocked LL | libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) | ^ thread got stuck here | - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail-dep/libc/socketpair_block_read_twice.rs:LL:CC | LL | let thread2 = thread::spawn(move || { diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr index 259ca6bd8347..66f3359a1292 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr @@ -4,14 +4,16 @@ error: the evaluated program deadlocked LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; | ^ thread got stuck here | - = note: this is on thread `main`, inside `std::sys::thread::PLATFORM::Thread::join` - = note: which got called inside `std::thread::lifecycle::JoinInner::<'_, ()>::join` (at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC) - = note: which got called inside `std::thread::JoinHandle::<()>::join` (at RUSTLIB/std/src/thread/join_handle.rs:LL:CC) -note: which got called inside `main` - --> tests/fail-dep/libc/socketpair_block_write_twice.rs:LL:CC - | -LL | thread2.join().unwrap(); - | ^^^^^^^^^^^^^^ + = note: this is on thread `main` + = note: stack backtrace: + 0: std::sys::thread::PLATFORM::Thread::join + at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC + 1: std::thread::lifecycle::JoinInner::join + at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC + 2: std::thread::JoinHandle::join + at RUSTLIB/std/src/thread/join_handle.rs:LL:CC + 3: main + at tests/fail-dep/libc/socketpair_block_write_twice.rs:LL:CC error: the evaluated program deadlocked --> tests/fail-dep/libc/socketpair_block_write_twice.rs:LL:CC @@ -19,8 +21,8 @@ error: the evaluated program deadlocked LL | let res = unsafe { libc::write(fds[0], data.as_ptr() as *const libc::c_void, data.len()) }; | ^ thread got stuck here | - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail-dep/libc/socketpair_block_write_twice.rs:LL:CC | LL | let thread2 = thread::spawn(move || { diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr b/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr index bd62bf148d7a..ed9b7ad18b0f 100644 --- a/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr +++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr @@ -7,17 +7,21 @@ error: abnormal termination: the program aborted execution LL | crate::process::abort() | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: this is inside closure - = note: which got called inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::alloc::rust_oom::{closure#0}}, !>` (at RUSTLIB/std/src/sys/backtrace.rs:LL:CC) - = note: which got called inside `std::alloc::rust_oom` (at RUSTLIB/std/src/alloc.rs:LL:CC) - = note: which got called inside `std::alloc::_::__rust_alloc_error_handler` (at RUSTLIB/std/src/alloc.rs:LL:CC) - = note: which got called inside `std::alloc::handle_alloc_error::rt_error` (at RUSTLIB/alloc/src/alloc.rs:LL:CC) - = note: which got called inside `std::alloc::handle_alloc_error` (at RUSTLIB/alloc/src/alloc.rs:LL:CC) -note: which got called inside `main` - --> tests/fail/alloc/alloc_error_handler.rs:LL:CC - | -LL | handle_alloc_error(Layout::for_value(&0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: std::alloc::rust_oom::{closure#0} + at RUSTLIB/std/src/alloc.rs:LL:CC + 1: std::sys::backtrace::__rust_end_short_backtrace + at RUSTLIB/std/src/sys/backtrace.rs:LL:CC + 2: std::alloc::rust_oom + at RUSTLIB/std/src/alloc.rs:LL:CC + 3: std::alloc::_::__rust_alloc_error_handler + at RUSTLIB/std/src/alloc.rs:LL:CC + 4: std::alloc::handle_alloc_error::rt_error + at RUSTLIB/alloc/src/alloc.rs:LL:CC + 5: std::alloc::handle_alloc_error + at RUSTLIB/alloc/src/alloc.rs:LL:CC + 6: main + at tests/fail/alloc/alloc_error_handler.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr b/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr index 7e7871dc89bc..677fa1b1bb9c 100644 --- a/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr +++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr @@ -5,21 +5,17 @@ error: abnormal termination: the program aborted execution LL | core::intrinsics::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: this is inside `alloc_error_handler` -note: which got called inside `_::__rust_alloc_error_handler` - --> tests/fail/alloc/alloc_error_handler_custom.rs:LL:CC - | -LL | #[alloc_error_handler] - | ---------------------- in this attribute macro expansion -LL | fn alloc_error_handler(layout: Layout) -> ! { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: which got called inside `alloc::alloc::handle_alloc_error::rt_error` (at RUSTLIB/alloc/src/alloc.rs:LL:CC) - = note: which got called inside `alloc::alloc::handle_alloc_error` (at RUSTLIB/alloc/src/alloc.rs:LL:CC) -note: which got called inside `miri_start` - --> tests/fail/alloc/alloc_error_handler_custom.rs:LL:CC - | -LL | handle_alloc_error(Layout::for_value(&0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: alloc_error_handler + at tests/fail/alloc/alloc_error_handler_custom.rs:LL:CC + 1: _::__rust_alloc_error_handler + at tests/fail/alloc/alloc_error_handler_custom.rs:LL:CC + 2: alloc::alloc::handle_alloc_error::rt_error + at RUSTLIB/alloc/src/alloc.rs:LL:CC + 3: alloc::alloc::handle_alloc_error + at RUSTLIB/alloc/src/alloc.rs:LL:CC + 4: miri_start + at tests/fail/alloc/alloc_error_handler_custom.rs:LL:CC error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr b/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr index b126cb042bee..386e7cdc2bd8 100644 --- a/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr +++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr @@ -7,15 +7,17 @@ error: abnormal termination: the program aborted execution LL | core::intrinsics::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: this is inside `panic_handler` - = note: which got called inside `alloc::alloc::__alloc_error_handler::__rdl_alloc_error_handler` (at RUSTLIB/alloc/src/alloc.rs:LL:CC) - = note: which got called inside `alloc::alloc::handle_alloc_error::rt_error` (at RUSTLIB/alloc/src/alloc.rs:LL:CC) - = note: which got called inside `alloc::alloc::handle_alloc_error` (at RUSTLIB/alloc/src/alloc.rs:LL:CC) -note: which got called inside `miri_start` - --> tests/fail/alloc/alloc_error_handler_no_std.rs:LL:CC - | -LL | handle_alloc_error(Layout::for_value(&0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: panic_handler + at tests/fail/alloc/alloc_error_handler_no_std.rs:LL:CC + 1: alloc::alloc::__alloc_error_handler::__rdl_alloc_error_handler + at RUSTLIB/alloc/src/alloc.rs:LL:CC + 2: alloc::alloc::handle_alloc_error::rt_error + at RUSTLIB/alloc/src/alloc.rs:LL:CC + 3: alloc::alloc::handle_alloc_error + at RUSTLIB/alloc/src/alloc.rs:LL:CC + 4: miri_start + at tests/fail/alloc/alloc_error_handler_no_std.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/alloc/global_system_mixup.stderr b/src/tools/miri/tests/fail/alloc/global_system_mixup.stderr index 27464a5a29e8..4214e3e7675b 100644 --- a/src/tools/miri/tests/fail/alloc/global_system_mixup.stderr +++ b/src/tools/miri/tests/fail/alloc/global_system_mixup.stderr @@ -6,13 +6,13 @@ LL | FREE(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `std::sys::alloc::PLATFORM::::dealloc` - = note: which got called inside `::deallocate` (at RUSTLIB/std/src/alloc.rs:LL:CC) -note: which got called inside `main` - --> tests/fail/alloc/global_system_mixup.rs:LL:CC - | -LL | unsafe { System.deallocate(ptr, l) }; - | ^ + = note: stack backtrace: + 0: std::sys::alloc::PLATFORM::dealloc + at RUSTLIB/std/src/sys/alloc/PLATFORM.rs:LL:CC + 1: ::deallocate + at RUSTLIB/std/src/alloc.rs:LL:CC + 2: main + at tests/fail/alloc/global_system_mixup.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/alloc/stack_free.stderr b/src/tools/miri/tests/fail/alloc/stack_free.stderr index ec052fcb6b9a..deb42c098679 100644 --- a/src/tools/miri/tests/fail/alloc/stack_free.stderr +++ b/src/tools/miri/tests/fail/alloc/stack_free.stderr @@ -6,14 +6,15 @@ LL | self.1.deallocate(From::from(ptr.cast()), layout); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside ` as std::ops::Drop>::drop` - = note: which got called inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` (at RUSTLIB/core/src/ptr/mod.rs:LL:CC) - = note: which got called inside `std::mem::drop::>` (at RUSTLIB/core/src/mem/mod.rs:LL:CC) -note: which got called inside `main` - --> tests/fail/alloc/stack_free.rs:LL:CC - | -LL | drop(bad_box); - | ^^^^^^^^^^^^^ + = note: stack backtrace: + 0: as std::ops::Drop>::drop + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 1: std::ptr::drop_in_place)) + at RUSTLIB/core/src/ptr/mod.rs:LL:CC + 2: std::mem::drop + at RUSTLIB/core/src/mem/mod.rs:LL:CC + 3: main + at tests/fail/alloc/stack_free.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/async-shared-mutable.stack.stderr b/src/tools/miri/tests/fail/async-shared-mutable.stack.stderr index 9949dad12867..7cedb24a2564 100644 --- a/src/tools/miri/tests/fail/async-shared-mutable.stack.stderr +++ b/src/tools/miri/tests/fail/async-shared-mutable.stack.stderr @@ -20,22 +20,15 @@ help: was later invalidated at offsets [OFFSET] by a SharedReadOnly retag | LL | let _: Pin<&_> = f.as_ref(); // Or: `f.as_mut().into_ref()`. | ^^^^^^^^^^ -note: error occurred inside closure - --> tests/fail/async-shared-mutable.rs:LL:CC - | -LL | core::future::poll_fn(move |_| { - | ^^^^^^^^ - = note: which got called inside ` as std::future::Future>::poll` (at RUSTLIB/core/src/future/poll_fn.rs:LL:CC) -note: which got called inside closure - --> tests/fail/async-shared-mutable.rs:LL:CC - | -LL | .await - | ^^^^^ -note: which got called inside `main` - --> tests/fail/async-shared-mutable.rs:LL:CC - | -LL | assert_eq!(f.as_mut().poll(&mut cx), Poll::Pending); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: main::{closure#0}::{closure#0} + at tests/fail/async-shared-mutable.rs:LL:CC + 1: as std::future::Future>::poll + at RUSTLIB/core/src/future/poll_fn.rs:LL:CC + 2: main::{closure#0} + at tests/fail/async-shared-mutable.rs:LL:CC + 3: main + at tests/fail/async-shared-mutable.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr b/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr index c204f75c4f21..fb6816183768 100644 --- a/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr +++ b/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr @@ -28,22 +28,15 @@ help: the accessed tag later transitioned to Frozen due to a reborrow (act LL | let _: Pin<&_> = f.as_ref(); // Or: `f.as_mut().into_ref()`. | ^^^^^^^^^^ = help: this transition corresponds to a loss of write permissions -note: error occurred inside closure - --> tests/fail/async-shared-mutable.rs:LL:CC - | -LL | core::future::poll_fn(move |_| { - | ^^^^^^^^ - = note: which got called inside ` as std::future::Future>::poll` (at RUSTLIB/core/src/future/poll_fn.rs:LL:CC) -note: which got called inside closure - --> tests/fail/async-shared-mutable.rs:LL:CC - | -LL | .await - | ^^^^^ -note: which got called inside `main` - --> tests/fail/async-shared-mutable.rs:LL:CC - | -LL | assert_eq!(f.as_mut().poll(&mut cx), Poll::Pending); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: main::{closure#0}::{closure#0} + at tests/fail/async-shared-mutable.rs:LL:CC + 1: as std::future::Future>::poll + at RUSTLIB/core/src/future/poll_fn.rs:LL:CC + 2: main::{closure#0} + at tests/fail/async-shared-mutable.rs:LL:CC + 3: main + at tests/fail/async-shared-mutable.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.stack.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.stack.stderr index bb5e731545b7..cdd668f1f633 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.stack.stderr @@ -16,16 +16,11 @@ help: is this argument | LL | fn safe(x: &mut i32, y: &mut i32) { | ^ -note: error occurred inside `safe` - --> tests/fail/both_borrows/aliasing_mut1.rs:LL:CC - | -LL | fn safe(x: &mut i32, y: &mut i32) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/aliasing_mut1.rs:LL:CC - | -LL | safe_raw(xraw, xraw); - | ^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: safe + at tests/fail/both_borrows/aliasing_mut1.rs:LL:CC + 1: main + at tests/fail/both_borrows/aliasing_mut1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.tree.stderr index 34f56696e000..d26a0fc0586e 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.tree.stderr @@ -18,16 +18,11 @@ help: the accessed tag later transitioned to Reserved (conflicted) due to LL | fn safe(x: &mut i32, y: &mut i32) { | ^ = help: this transition corresponds to a temporary loss of write permissions until function exit -note: error occurred inside `safe` - --> tests/fail/both_borrows/aliasing_mut1.rs:LL:CC - | -LL | fn safe(x: &mut i32, y: &mut i32) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/aliasing_mut1.rs:LL:CC - | -LL | safe_raw(xraw, xraw); - | ^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: safe + at tests/fail/both_borrows/aliasing_mut1.rs:LL:CC + 1: main + at tests/fail/both_borrows/aliasing_mut1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.stack.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.stack.stderr index 5c574f13ff70..c050dbb792b5 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.stack.stderr @@ -16,16 +16,11 @@ help: is this argument | LL | fn safe(x: &i32, y: &mut i32) { | ^ -note: error occurred inside `safe` - --> tests/fail/both_borrows/aliasing_mut2.rs:LL:CC - | -LL | fn safe(x: &i32, y: &mut i32) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/aliasing_mut2.rs:LL:CC - | -LL | safe_raw(xshr, xraw); - | ^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: safe + at tests/fail/both_borrows/aliasing_mut2.rs:LL:CC + 1: main + at tests/fail/both_borrows/aliasing_mut2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.tree.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.tree.stderr index 639a4ef57efe..77597e4aa831 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.tree.stderr @@ -18,16 +18,11 @@ help: the accessed tag later transitioned to Reserved (conflicted) due to LL | let _v = *x; | ^^ = help: this transition corresponds to a temporary loss of write permissions until function exit -note: error occurred inside `safe` - --> tests/fail/both_borrows/aliasing_mut2.rs:LL:CC - | -LL | fn safe(x: &i32, y: &mut i32) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/aliasing_mut2.rs:LL:CC - | -LL | safe_raw(xshr, xraw); - | ^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: safe + at tests/fail/both_borrows/aliasing_mut2.rs:LL:CC + 1: main + at tests/fail/both_borrows/aliasing_mut2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.stack.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.stack.stderr index 4be06c65f191..49087d472255 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.stack.stderr @@ -16,16 +16,11 @@ help: was later invalidated at offsets [0x0..0x4] by a Unique function-ent | LL | safe_raw(xraw, xshr); | ^^^^^^^^^^^^^^^^^^^^ -note: error occurred inside `safe` - --> tests/fail/both_borrows/aliasing_mut3.rs:LL:CC - | -LL | fn safe(x: &mut i32, y: &i32) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/aliasing_mut3.rs:LL:CC - | -LL | safe_raw(xraw, xshr); - | ^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: safe + at tests/fail/both_borrows/aliasing_mut3.rs:LL:CC + 1: main + at tests/fail/both_borrows/aliasing_mut3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.tree.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.tree.stderr index 09a54f8199c7..32f980da6f7e 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.tree.stderr @@ -18,16 +18,11 @@ help: the accessed tag later transitioned to Reserved (conflicted) due to LL | fn safe(x: &mut i32, y: &i32) { | ^ = help: this transition corresponds to a temporary loss of write permissions until function exit -note: error occurred inside `safe` - --> tests/fail/both_borrows/aliasing_mut3.rs:LL:CC - | -LL | fn safe(x: &mut i32, y: &i32) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/aliasing_mut3.rs:LL:CC - | -LL | safe_raw(xraw, xshr); - | ^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: safe + at tests/fail/both_borrows/aliasing_mut3.rs:LL:CC + 1: main + at tests/fail/both_borrows/aliasing_mut3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.stack.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.stack.stderr index e72996d43d7b..f56270f48bea 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.stack.stderr @@ -16,16 +16,11 @@ help: is this argument | LL | fn safe(x: &i32, y: &mut Cell) { | ^ -note: error occurred inside `safe` - --> tests/fail/both_borrows/aliasing_mut4.rs:LL:CC - | -LL | fn safe(x: &i32, y: &mut Cell) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/aliasing_mut4.rs:LL:CC - | -LL | safe_raw(xshr, xraw as *mut _); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: safe + at tests/fail/both_borrows/aliasing_mut4.rs:LL:CC + 1: main + at tests/fail/both_borrows/aliasing_mut4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.tree.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.tree.stderr index d2a533a3da8e..11eb1ae7ddee 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.tree.stderr @@ -19,23 +19,17 @@ help: the protected tag was created here, in the initial state Frozen | LL | fn safe(x: &i32, y: &mut Cell) { | ^ -note: error occurred inside `std::mem::replace::` - --> RUSTLIB/core/src/mem/mod.rs:LL:CC - | -LL | pub const fn replace(dest: &mut T, src: T) -> T { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: which got called inside `std::cell::Cell::::replace` (at RUSTLIB/core/src/cell.rs:LL:CC) - = note: which got called inside `std::cell::Cell::::set` (at RUSTLIB/core/src/cell.rs:LL:CC) -note: which got called inside `safe` - --> tests/fail/both_borrows/aliasing_mut4.rs:LL:CC - | -LL | y.set(1); - | ^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/aliasing_mut4.rs:LL:CC - | -LL | safe_raw(xshr, xraw as *mut _); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: std::mem::replace + at RUSTLIB/core/src/mem/mod.rs:LL:CC + 1: std::cell::Cell::replace + at RUSTLIB/core/src/cell.rs:LL:CC + 2: std::cell::Cell::set + at RUSTLIB/core/src/cell.rs:LL:CC + 3: safe + at tests/fail/both_borrows/aliasing_mut4.rs:LL:CC + 4: main + at tests/fail/both_borrows/aliasing_mut4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.stack.stderr b/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.stack.stderr index c9341ccdb037..69f7c908119f 100644 --- a/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.stack.stderr @@ -16,21 +16,13 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | *our = 5; | ^^^^^^^^ -note: error occurred inside `unknown_code_2` - --> tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC - | -LL | fn unknown_code_2() { - | ^^^^^^^^^^^^^^^^^^^ -note: which got called inside `demo_box_advanced_unique` - --> tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC - | -LL | unknown_code_2(); - | ^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC - | -LL | demo_box_advanced_unique(Box::new(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: unknown_code_2 + at tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC + 1: demo_box_advanced_unique + at tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC + 2: main + at tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.tree.stderr index 446d283694a1..b4def1008f7d 100644 --- a/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.tree.stderr @@ -18,21 +18,13 @@ help: the accessed tag later transitioned to Disabled due to a foreign wri LL | *our = 5; | ^^^^^^^^ = help: this transition corresponds to a loss of read permissions -note: error occurred inside `unknown_code_2` - --> tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC - | -LL | fn unknown_code_2() { - | ^^^^^^^^^^^^^^^^^^^ -note: which got called inside `demo_box_advanced_unique` - --> tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC - | -LL | unknown_code_2(); - | ^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC - | -LL | demo_box_advanced_unique(Box::new(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: unknown_code_2 + at tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC + 1: demo_box_advanced_unique + at tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC + 2: main + at tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.stack.stderr b/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.stack.stderr index 1a5662b74693..7bf29bfdcb58 100644 --- a/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.stack.stderr @@ -16,16 +16,11 @@ help: is this argument | LL | unsafe fn test(mut x: Box, y: *const i32) -> i32 { | ^^^^^ -note: error occurred inside `test` - --> tests/fail/both_borrows/box_noalias_violation.rs:LL:CC - | -LL | unsafe fn test(mut x: Box, y: *const i32) -> i32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/box_noalias_violation.rs:LL:CC - | -LL | test(Box::from_raw(ptr), ptr); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: test + at tests/fail/both_borrows/box_noalias_violation.rs:LL:CC + 1: main + at tests/fail/both_borrows/box_noalias_violation.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr b/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr index 6ec056828fd5..0744b0e9499b 100644 --- a/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr @@ -25,16 +25,11 @@ help: the protected tag later transitioned to Unique due to a child write LL | *x = 5; | ^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference -note: error occurred inside `test` - --> tests/fail/both_borrows/box_noalias_violation.rs:LL:CC - | -LL | unsafe fn test(mut x: Box, y: *const i32) -> i32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/box_noalias_violation.rs:LL:CC - | -LL | test(Box::from_raw(ptr), ptr); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: test + at tests/fail/both_borrows/box_noalias_violation.rs:LL:CC + 1: main + at tests/fail/both_borrows/box_noalias_violation.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/buggy_split_at_mut.stack.stderr b/src/tools/miri/tests/fail/both_borrows/buggy_split_at_mut.stack.stderr index 2b0d5f07994c..ef7d54b0b19d 100644 --- a/src/tools/miri/tests/fail/both_borrows/buggy_split_at_mut.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/buggy_split_at_mut.stack.stderr @@ -22,16 +22,11 @@ help: was later invalidated at offsets [0x0..0x10] by a Unique retag | LL | from_raw_parts_mut(ptr.offset(mid as isize), len - mid), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: error occurred inside `safe::split_at_mut::` - --> tests/fail/both_borrows/buggy_split_at_mut.rs:LL:CC - | -LL | pub fn split_at_mut(self_: &mut [T], mid: usize) -> (&mut [T], &mut [T]) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/buggy_split_at_mut.rs:LL:CC - | -LL | let (a, b) = safe::split_at_mut(&mut array, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: safe::split_at_mut + at tests/fail/both_borrows/buggy_split_at_mut.rs:LL:CC + 1: main + at tests/fail/both_borrows/buggy_split_at_mut.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/illegal_write6.stack.stderr b/src/tools/miri/tests/fail/both_borrows/illegal_write6.stack.stderr index 3c09bec03d6a..21d1504b03b1 100644 --- a/src/tools/miri/tests/fail/both_borrows/illegal_write6.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/illegal_write6.stack.stderr @@ -16,16 +16,11 @@ help: is this argument | LL | fn foo(a: &mut u32, y: *mut u32) -> u32 { | ^ -note: error occurred inside `foo` - --> tests/fail/both_borrows/illegal_write6.rs:LL:CC - | -LL | fn foo(a: &mut u32, y: *mut u32) -> u32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/illegal_write6.rs:LL:CC - | -LL | foo(x, p); - | ^^^^^^^^^ + = note: stack backtrace: + 0: foo + at tests/fail/both_borrows/illegal_write6.rs:LL:CC + 1: main + at tests/fail/both_borrows/illegal_write6.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr b/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr index 69bb914236da..923dd33a0a17 100644 --- a/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr @@ -25,16 +25,11 @@ help: the protected tag later transitioned to Unique due to a child write LL | *a = 1; | ^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference -note: error occurred inside `foo` - --> tests/fail/both_borrows/illegal_write6.rs:LL:CC - | -LL | fn foo(a: &mut u32, y: *mut u32) -> u32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/illegal_write6.rs:LL:CC - | -LL | foo(x, p); - | ^^^^^^^^^ + = note: stack backtrace: + 0: foo + at tests/fail/both_borrows/illegal_write6.rs:LL:CC + 1: main + at tests/fail/both_borrows/illegal_write6.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.stack.stderr b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.stack.stderr index d298d511d3e1..12de173519ac 100644 --- a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.stack.stderr @@ -16,16 +16,11 @@ help: is this argument | LL | fn inner(x: *mut i32, _y: &i32) { | ^^ -note: error occurred inside `inner` - --> tests/fail/both_borrows/invalidate_against_protector2.rs:LL:CC - | -LL | fn inner(x: *mut i32, _y: &i32) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/invalidate_against_protector2.rs:LL:CC - | -LL | inner(xraw, xref); - | ^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: inner + at tests/fail/both_borrows/invalidate_against_protector2.rs:LL:CC + 1: main + at tests/fail/both_borrows/invalidate_against_protector2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.tree.stderr b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.tree.stderr index b83217bce7e9..26882ae08024 100644 --- a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.tree.stderr @@ -19,16 +19,11 @@ help: the protected tag was created here, in the initial state Frozen | LL | fn inner(x: *mut i32, _y: &i32) { | ^^ -note: error occurred inside `inner` - --> tests/fail/both_borrows/invalidate_against_protector2.rs:LL:CC - | -LL | fn inner(x: *mut i32, _y: &i32) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/invalidate_against_protector2.rs:LL:CC - | -LL | inner(xraw, xref); - | ^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: inner + at tests/fail/both_borrows/invalidate_against_protector2.rs:LL:CC + 1: main + at tests/fail/both_borrows/invalidate_against_protector2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.stack.stderr b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.stack.stderr index ebbc3a7ae8c0..b1215852a35f 100644 --- a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.stack.stderr @@ -16,16 +16,11 @@ help: is this argument | LL | fn inner(x: *mut i32, _y: &i32) { | ^^ -note: error occurred inside `inner` - --> tests/fail/both_borrows/invalidate_against_protector3.rs:LL:CC - | -LL | fn inner(x: *mut i32, _y: &i32) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/invalidate_against_protector3.rs:LL:CC - | -LL | inner(ptr, &*ptr); - | ^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: inner + at tests/fail/both_borrows/invalidate_against_protector3.rs:LL:CC + 1: main + at tests/fail/both_borrows/invalidate_against_protector3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.tree.stderr b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.tree.stderr index 1a1eb89d25f7..ae2dc93fd109 100644 --- a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.tree.stderr @@ -19,16 +19,11 @@ help: the protected tag was created here, in the initial state Frozen | LL | fn inner(x: *mut i32, _y: &i32) { | ^^ -note: error occurred inside `inner` - --> tests/fail/both_borrows/invalidate_against_protector3.rs:LL:CC - | -LL | fn inner(x: *mut i32, _y: &i32) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/invalidate_against_protector3.rs:LL:CC - | -LL | inner(ptr, &*ptr); - | ^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: inner + at tests/fail/both_borrows/invalidate_against_protector3.rs:LL:CC + 1: main + at tests/fail/both_borrows/invalidate_against_protector3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr index 2b2e16d1ecff..14a4065c1f0a 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr @@ -11,17 +11,13 @@ help: ALLOC was allocated here: | LL | let ptr = Box::into_raw(Box::new(0u16)); | ^^^^^^^^^^^^^^ -note: error occurred inside `std::boxed::Box::::from_raw_in` - --> RUSTLIB/alloc/src/boxed.rs:LL:CC - | -LL | pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: which got called inside `std::boxed::Box::::from_raw` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) -note: which got called inside `main` - --> tests/fail/both_borrows/issue-miri-1050-1.rs:LL:CC - | -LL | drop(Box::from_raw(ptr as *mut u32)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: std::boxed::Box::from_raw_in + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 1: std::boxed::Box::from_raw + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 2: main + at tests/fail/both_borrows/issue-miri-1050-1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr index 2b2e16d1ecff..14a4065c1f0a 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr @@ -11,17 +11,13 @@ help: ALLOC was allocated here: | LL | let ptr = Box::into_raw(Box::new(0u16)); | ^^^^^^^^^^^^^^ -note: error occurred inside `std::boxed::Box::::from_raw_in` - --> RUSTLIB/alloc/src/boxed.rs:LL:CC - | -LL | pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: which got called inside `std::boxed::Box::::from_raw` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) -note: which got called inside `main` - --> tests/fail/both_borrows/issue-miri-1050-1.rs:LL:CC - | -LL | drop(Box::from_raw(ptr as *mut u32)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: std::boxed::Box::from_raw_in + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 1: std::boxed::Box::from_raw + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 2: main + at tests/fail/both_borrows/issue-miri-1050-1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr index f33b6cf77e4d..beb712388f91 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr @@ -6,13 +6,13 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `std::boxed::Box::::from_raw_in` - = note: which got called inside `std::boxed::Box::::from_raw` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) -note: which got called inside `main` - --> tests/fail/both_borrows/issue-miri-1050-2.rs:LL:CC - | -LL | drop(Box::from_raw(ptr.as_ptr())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: std::boxed::Box::from_raw_in + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 1: std::boxed::Box::from_raw + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 2: main + at tests/fail/both_borrows/issue-miri-1050-2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr index f33b6cf77e4d..beb712388f91 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr @@ -6,13 +6,13 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `std::boxed::Box::::from_raw_in` - = note: which got called inside `std::boxed::Box::::from_raw` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) -note: which got called inside `main` - --> tests/fail/both_borrows/issue-miri-1050-2.rs:LL:CC - | -LL | drop(Box::from_raw(ptr.as_ptr())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: std::boxed::Box::from_raw_in + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 1: std::boxed::Box::from_raw + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 2: main + at tests/fail/both_borrows/issue-miri-1050-2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.stack.stderr b/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.stack.stderr index 290f50f60c2b..772e7c03bf6e 100644 --- a/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.stack.stderr @@ -16,21 +16,13 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | *our = 5; | ^^^^^^^^ -note: error occurred inside `unknown_code_2` - --> tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC - | -LL | fn unknown_code_2() { - | ^^^^^^^^^^^^^^^^^^^ -note: which got called inside `demo_mut_advanced_unique` - --> tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC - | -LL | unknown_code_2(); - | ^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC - | -LL | demo_mut_advanced_unique(&mut 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: unknown_code_2 + at tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC + 1: demo_mut_advanced_unique + at tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC + 2: main + at tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.tree.stderr index 608e41341c3f..97400d479d32 100644 --- a/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.tree.stderr @@ -18,21 +18,13 @@ help: the accessed tag later transitioned to Disabled due to a foreign wri LL | *our = 5; | ^^^^^^^^ = help: this transition corresponds to a loss of read permissions -note: error occurred inside `unknown_code_2` - --> tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC - | -LL | fn unknown_code_2() { - | ^^^^^^^^^^^^^^^^^^^ -note: which got called inside `demo_mut_advanced_unique` - --> tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC - | -LL | unknown_code_2(); - | ^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC - | -LL | demo_mut_advanced_unique(&mut 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: unknown_code_2 + at tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC + 1: demo_mut_advanced_unique + at tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC + 2: main + at tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.stack.stderr b/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.stack.stderr index 68fd20ba942a..d7688680e7da 100644 --- a/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.stack.stderr @@ -16,30 +16,17 @@ help: is this argument | LL | fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { | ^^ -note: error occurred inside `std::boxed::Box::::from_raw_in` - --> RUSTLIB/alloc/src/boxed.rs:LL:CC - | -LL | pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: which got called inside `std::boxed::Box::::from_raw` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) -note: which got called inside closure - --> tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC - | -LL | || drop(Box::from_raw(ptr)), - | ^^^^^^^^^^^^^^^^^^ -note: which got called inside `dealloc_while_running::<{closure@tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC}>` - --> tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC - | -LL | dealloc(); - | ^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC - | -LL | / dealloc_while_running( -LL | | Newtype(&mut *ptr, 0), -LL | | || drop(Box::from_raw(ptr)), -LL | | ) - | |_________^ + = note: stack backtrace: + 0: std::boxed::Box::from_raw_in + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 1: std::boxed::Box::from_raw + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 2: main::{closure#0} + at tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC + 3: dealloc_while_running + at tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC + 4: main + at tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.tree.stderr b/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.tree.stderr index f0dffb8f14ad..68b9d1c86d1a 100644 --- a/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.tree.stderr @@ -25,31 +25,19 @@ help: the protected tag later transitioned to Reserved (conflicted) due to LL | || drop(Box::from_raw(ptr)), | ^^^^^^^^^^^^^^^^^^ = help: this transition corresponds to a temporary loss of write permissions until function exit -note: error occurred inside ` as std::ops::Drop>::drop` - --> RUSTLIB/alloc/src/boxed.rs:LL:CC - | -LL | fn drop(&mut self) { - | ^^^^^^^^^^^^^^^^^^ - = note: which got called inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` (at RUSTLIB/core/src/ptr/mod.rs:LL:CC) - = note: which got called inside `std::mem::drop::>` (at RUSTLIB/core/src/mem/mod.rs:LL:CC) -note: which got called inside closure - --> tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC - | -LL | || drop(Box::from_raw(ptr)), - | ^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `dealloc_while_running::<{closure@tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC}>` - --> tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC - | -LL | dealloc(); - | ^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC - | -LL | / dealloc_while_running( -LL | | Newtype(&mut *ptr, 0), -LL | | || drop(Box::from_raw(ptr)), -LL | | ) - | |_________^ + = note: stack backtrace: + 0: as std::ops::Drop>::drop + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 1: std::ptr::drop_in_place)) + at RUSTLIB/core/src/ptr/mod.rs:LL:CC + 2: std::mem::drop + at RUSTLIB/core/src/mem/mod.rs:LL:CC + 3: main::{closure#0} + at tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC + 4: dealloc_while_running + at tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC + 5: main + at tests/fail/both_borrows/newtype_pair_retagging.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/newtype_retagging.stack.stderr b/src/tools/miri/tests/fail/both_borrows/newtype_retagging.stack.stderr index 8f1619bda403..b7b0f2812669 100644 --- a/src/tools/miri/tests/fail/both_borrows/newtype_retagging.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/newtype_retagging.stack.stderr @@ -16,30 +16,17 @@ help: is this argument | LL | fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { | ^^ -note: error occurred inside `std::boxed::Box::::from_raw_in` - --> RUSTLIB/alloc/src/boxed.rs:LL:CC - | -LL | pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: which got called inside `std::boxed::Box::::from_raw` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) -note: which got called inside closure - --> tests/fail/both_borrows/newtype_retagging.rs:LL:CC - | -LL | || drop(Box::from_raw(ptr)), - | ^^^^^^^^^^^^^^^^^^ -note: which got called inside `dealloc_while_running::<{closure@tests/fail/both_borrows/newtype_retagging.rs:LL:CC}>` - --> tests/fail/both_borrows/newtype_retagging.rs:LL:CC - | -LL | dealloc(); - | ^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/newtype_retagging.rs:LL:CC - | -LL | / dealloc_while_running( -LL | | Newtype(&mut *ptr), -LL | | || drop(Box::from_raw(ptr)), -LL | | ) - | |_________^ + = note: stack backtrace: + 0: std::boxed::Box::from_raw_in + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 1: std::boxed::Box::from_raw + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 2: main::{closure#0} + at tests/fail/both_borrows/newtype_retagging.rs:LL:CC + 3: dealloc_while_running + at tests/fail/both_borrows/newtype_retagging.rs:LL:CC + 4: main + at tests/fail/both_borrows/newtype_retagging.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/newtype_retagging.tree.stderr b/src/tools/miri/tests/fail/both_borrows/newtype_retagging.tree.stderr index f7a2d63dc8a9..5069b1d01cd2 100644 --- a/src/tools/miri/tests/fail/both_borrows/newtype_retagging.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/newtype_retagging.tree.stderr @@ -25,31 +25,19 @@ help: the protected tag later transitioned to Reserved (conflicted) due to LL | || drop(Box::from_raw(ptr)), | ^^^^^^^^^^^^^^^^^^ = help: this transition corresponds to a temporary loss of write permissions until function exit -note: error occurred inside ` as std::ops::Drop>::drop` - --> RUSTLIB/alloc/src/boxed.rs:LL:CC - | -LL | fn drop(&mut self) { - | ^^^^^^^^^^^^^^^^^^ - = note: which got called inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` (at RUSTLIB/core/src/ptr/mod.rs:LL:CC) - = note: which got called inside `std::mem::drop::>` (at RUSTLIB/core/src/mem/mod.rs:LL:CC) -note: which got called inside closure - --> tests/fail/both_borrows/newtype_retagging.rs:LL:CC - | -LL | || drop(Box::from_raw(ptr)), - | ^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `dealloc_while_running::<{closure@tests/fail/both_borrows/newtype_retagging.rs:LL:CC}>` - --> tests/fail/both_borrows/newtype_retagging.rs:LL:CC - | -LL | dealloc(); - | ^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/newtype_retagging.rs:LL:CC - | -LL | / dealloc_while_running( -LL | | Newtype(&mut *ptr), -LL | | || drop(Box::from_raw(ptr)), -LL | | ) - | |_________^ + = note: stack backtrace: + 0: as std::ops::Drop>::drop + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 1: std::ptr::drop_in_place)) + at RUSTLIB/core/src/ptr/mod.rs:LL:CC + 2: std::mem::drop + at RUSTLIB/core/src/mem/mod.rs:LL:CC + 3: main::{closure#0} + at tests/fail/both_borrows/newtype_retagging.rs:LL:CC + 4: dealloc_while_running + at tests/fail/both_borrows/newtype_retagging.rs:LL:CC + 5: main + at tests/fail/both_borrows/newtype_retagging.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr index d1dbdbc67f1b..f0d98ee6f20f 100644 --- a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr @@ -14,17 +14,13 @@ LL | let _r = &mut *p; = help: therefore from the perspective of data races, a retag has the same implications as a read or write = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information -note: error occurred on thread `unnamed-ID`, inside `thread_2` - --> tests/fail/both_borrows/retag_data_race_write.rs:LL:CC - | -LL | fn thread_2(p: SendPtr) { - | ^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside closure - --> tests/fail/both_borrows/retag_data_race_write.rs:LL:CC - | -LL | let t2 = std::thread::spawn(move || thread_2(p)); - | ^^^^^^^^^^^ -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` + = note: stack backtrace: + 0: thread_2 + at tests/fail/both_borrows/retag_data_race_write.rs:LL:CC + 1: main::{closure#1} + at tests/fail/both_borrows/retag_data_race_write.rs:LL:CC +note: the last function in that backtrace got called indirectly due to this code --> tests/fail/both_borrows/retag_data_race_write.rs:LL:CC | LL | let t2 = std::thread::spawn(move || thread_2(p)); diff --git a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr index 47abf74cb8a2..bf8b2f8690fe 100644 --- a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr @@ -14,17 +14,13 @@ LL | let _r = &mut *p; = help: therefore from the perspective of data races, a retag has the same implications as a read or write = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information -note: error occurred on thread `unnamed-ID`, inside `thread_2` - --> tests/fail/both_borrows/retag_data_race_write.rs:LL:CC - | -LL | fn thread_2(p: SendPtr) { - | ^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside closure - --> tests/fail/both_borrows/retag_data_race_write.rs:LL:CC - | -LL | let t2 = std::thread::spawn(move || thread_2(p)); - | ^^^^^^^^^^^ -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` + = note: stack backtrace: + 0: thread_2 + at tests/fail/both_borrows/retag_data_race_write.rs:LL:CC + 1: main::{closure#1} + at tests/fail/both_borrows/retag_data_race_write.rs:LL:CC +note: the last function in that backtrace got called indirectly due to this code --> tests/fail/both_borrows/retag_data_race_write.rs:LL:CC | LL | let t2 = std::thread::spawn(move || thread_2(p)); diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.stack.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.stack.stderr index ff9968802809..8ca0cd4bda43 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.stack.stderr @@ -16,16 +16,11 @@ help: was later invalidated at offsets [0x4..0x8] by a write access | LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ -note: error occurred inside `foo` - --> tests/fail/both_borrows/return_invalid_shr.rs:LL:CC - | -LL | fn foo(x: &mut (i32, i32)) -> &i32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/return_invalid_shr.rs:LL:CC - | -LL | foo(&mut (1, 2)); - | ^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: foo + at tests/fail/both_borrows/return_invalid_shr.rs:LL:CC + 1: main + at tests/fail/both_borrows/return_invalid_shr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.tree.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.tree.stderr index 598a95dd96c9..0147769bb949 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.tree.stderr @@ -18,16 +18,11 @@ help: the accessed tag later transitioned to Disabled due to a foreign wri LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ = help: this transition corresponds to a loss of read permissions -note: error occurred inside `foo` - --> tests/fail/both_borrows/return_invalid_shr.rs:LL:CC - | -LL | fn foo(x: &mut (i32, i32)) -> &i32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/return_invalid_shr.rs:LL:CC - | -LL | foo(&mut (1, 2)); - | ^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: foo + at tests/fail/both_borrows/return_invalid_shr.rs:LL:CC + 1: main + at tests/fail/both_borrows/return_invalid_shr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.stack.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.stack.stderr index d33782301180..94d538072ae0 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.stack.stderr @@ -19,16 +19,11 @@ help: was later invalidated at offsets [0x4..0x8] by a write access | LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ -note: error occurred inside `foo` - --> tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC - | -LL | fn foo(x: &mut (i32, i32)) -> Option<&i32> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC - | -LL | match foo(&mut (1, 2)) { - | ^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: foo + at tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC + 1: main + at tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.tree.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.tree.stderr index d303cc9b22e8..f66798c43586 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.tree.stderr @@ -18,16 +18,11 @@ help: the accessed tag later transitioned to Disabled due to a foreign wri LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ = help: this transition corresponds to a loss of read permissions -note: error occurred inside `foo` - --> tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC - | -LL | fn foo(x: &mut (i32, i32)) -> Option<&i32> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC - | -LL | match foo(&mut (1, 2)) { - | ^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: foo + at tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC + 1: main + at tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.stack.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.stack.stderr index d6063168d33d..ffe673e1bcf9 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.stack.stderr @@ -19,16 +19,11 @@ help: was later invalidated at offsets [0x4..0x8] by a write access | LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ -note: error occurred inside `foo` - --> tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC - | -LL | fn foo(x: &mut (i32, i32)) -> (&i32,) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC - | -LL | foo(&mut (1, 2)).0; - | ^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: foo + at tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC + 1: main + at tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.tree.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.tree.stderr index 0c5b05ce1b94..1eee9ed338ec 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.tree.stderr @@ -18,16 +18,11 @@ help: the accessed tag later transitioned to Disabled due to a foreign wri LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ = help: this transition corresponds to a loss of read permissions -note: error occurred inside `foo` - --> tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC - | -LL | fn foo(x: &mut (i32, i32)) -> (&i32,) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC - | -LL | foo(&mut (1, 2)).0; - | ^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: foo + at tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC + 1: main + at tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.stack.stderr b/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.stack.stderr index 3a05fb151cf1..aae9f8efbe9f 100644 --- a/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.stack.stderr @@ -11,21 +11,13 @@ help: was created by a SharedReadOnly retag at offsets [0x0..0x4] | LL | *(x as *const i32 as *mut i32) = 7; | ^ -note: error occurred inside `unknown_code` - --> tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC - | -LL | fn unknown_code(x: &i32) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `foo` - --> tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC - | -LL | unknown_code(&*x); - | ^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC - | -LL | println!("{}", foo(&mut 0)); - | ^^^^^^^^^^^ + = note: stack backtrace: + 0: unknown_code + at tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC + 1: foo + at tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC + 2: main + at tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.tree.stderr index 8040cfa212a9..274d5becddfd 100644 --- a/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.tree.stderr @@ -12,21 +12,13 @@ help: the accessed tag was created here, in the initial state Frozen | LL | fn unknown_code(x: &i32) { | ^ -note: error occurred inside `unknown_code` - --> tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC - | -LL | fn unknown_code(x: &i32) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `foo` - --> tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC - | -LL | unknown_code(&*x); - | ^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC - | -LL | println!("{}", foo(&mut 0)); - | ^^^^^^^^^^^ + = note: stack backtrace: + 0: unknown_code + at tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC + 1: foo + at tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC + 2: main + at tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/box-cell-alias.stderr b/src/tools/miri/tests/fail/box-cell-alias.stderr index c5ce263ff1c9..63cdc98d3054 100644 --- a/src/tools/miri/tests/fail/box-cell-alias.stderr +++ b/src/tools/miri/tests/fail/box-cell-alias.stderr @@ -16,16 +16,11 @@ help: was later invalidated at offsets [0x0..0x1] by a Unique retag | LL | let res = helper(val, ptr); | ^^^ -note: error occurred inside `helper` - --> tests/fail/box-cell-alias.rs:LL:CC - | -LL | fn helper(val: Box>, ptr: *const Cell) -> u8 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/box-cell-alias.rs:LL:CC - | -LL | let res = helper(val, ptr); - | ^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: helper + at tests/fail/box-cell-alias.rs:LL:CC + 1: main + at tests/fail/box-cell-alias.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/closures/uninhabited-variant.stderr b/src/tools/miri/tests/fail/closures/uninhabited-variant.stderr index f0f145fd1366..aea878660115 100644 --- a/src/tools/miri/tests/fail/closures/uninhabited-variant.stderr +++ b/src/tools/miri/tests/fail/closures/uninhabited-variant.stderr @@ -6,12 +6,11 @@ LL | match r { | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside closure -note: which got called inside `main` - --> tests/fail/closures/uninhabited-variant.rs:LL:CC - | -LL | f(); - | ^^^ + = note: stack backtrace: + 0: main::{closure#0} + at tests/fail/closures/uninhabited-variant.rs:LL:CC + 1: main + at tests/fail/closures/uninhabited-variant.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/concurrency/mutex-leak-move-deadlock.rs b/src/tools/miri/tests/fail/concurrency/mutex-leak-move-deadlock.rs index 5afa6c71700e..6d8bd3d3f2a4 100644 --- a/src/tools/miri/tests/fail/concurrency/mutex-leak-move-deadlock.rs +++ b/src/tools/miri/tests/fail/concurrency/mutex-leak-move-deadlock.rs @@ -3,6 +3,7 @@ //@normalize-stderr-test: "LL \| .*" -> "LL | $$CODE" //@normalize-stderr-test: "\| +\^+" -> "| ^" //@normalize-stderr-test: "\n *= note:.*" -> "" +//@normalize-stderr-test: "\n *\d+:.*\n *at .*" -> "" // On macOS we use chekced pthread mutexes which changes the error //@normalize-stderr-test: "a thread got stuck here" -> "thread `main` got stuck here" //@normalize-stderr-test: "a thread deadlocked" -> "the evaluated program deadlocked" diff --git a/src/tools/miri/tests/fail/concurrency/mutex-leak-move-deadlock.stderr b/src/tools/miri/tests/fail/concurrency/mutex-leak-move-deadlock.stderr index 258f5a823fcd..b036141bb267 100644 --- a/src/tools/miri/tests/fail/concurrency/mutex-leak-move-deadlock.stderr +++ b/src/tools/miri/tests/fail/concurrency/mutex-leak-move-deadlock.stderr @@ -4,11 +4,6 @@ error: the evaluated program deadlocked LL | $CODE | ^ thread got stuck here | -note: which got called inside `main` - --> tests/fail/concurrency/mutex-leak-move-deadlock.rs:LL:CC - | -LL | $CODE - | ^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr b/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr index 2cc3b845deba..0c57c6894a08 100644 --- a/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr +++ b/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr @@ -16,22 +16,15 @@ help: ALLOC was deallocated here: | LL | }; // *deallocate* coroutine_iterator | ^ -note: error occurred inside closure - --> tests/fail/coroutine-pinned-moved.rs:LL:CC - | -LL | static move || { - | ^^^^^^^^^^^^^^ -note: which got called inside ` as std::iter::Iterator>::next` - --> tests/fail/coroutine-pinned-moved.rs:LL:CC - | -LL | match me.resume(()) { - | ^^^^^^^^^^^^^ - = note: which got called inside `std::boxed::iter::>>::next` (at RUSTLIB/alloc/src/boxed/iter.rs:LL:CC) -note: which got called inside `main` - --> tests/fail/coroutine-pinned-moved.rs:LL:CC - | -LL | coroutine_iterator_2.next(); // and use moved value - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: firstn::{closure#0} + at tests/fail/coroutine-pinned-moved.rs:LL:CC + 1: as std::iter::Iterator>::next + at tests/fail/coroutine-pinned-moved.rs:LL:CC + 2: std::boxed::iter::next + at RUSTLIB/alloc/src/boxed/iter.rs:LL:CC + 3: main + at tests/fail/coroutine-pinned-moved.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr index e5471e094bc8..feff143cba66 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr @@ -6,12 +6,11 @@ LL | unsafe { &(*x).0 as *const i32 } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `via_ref` -note: which got called inside `main` - --> tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs:LL:CC - | -LL | via_ref(ptr); // this is not - | ^^^^^^^^^^^^ + = note: stack backtrace: + 0: via_ref + at tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs:LL:CC + 1: main + at tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr index 93bb9603ae5b..67b60e6bca41 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr @@ -6,12 +6,11 @@ LL | let _ref = unsafe { &mut *(LEAK as *mut i32) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `evil` -note: which got called inside `main` - --> tests/fail/dangling_pointers/storage_dead_dangling.rs:LL:CC - | -LL | evil(); - | ^^^^^^ + = note: stack backtrace: + 0: evil + at tests/fail/dangling_pointers/storage_dead_dangling.rs:LL:CC + 1: main + at tests/fail/dangling_pointers/storage_dead_dangling.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/alloc_read_race.stderr b/src/tools/miri/tests/fail/data_race/alloc_read_race.stderr index 67edbfb4658e..ddb2edc68d48 100644 --- a/src/tools/miri/tests/fail/data_race/alloc_read_race.stderr +++ b/src/tools/miri/tests/fail/data_race/alloc_read_race.stderr @@ -11,8 +11,8 @@ LL | pointer.store(Box::into_raw(Box::new_uninit()), Ordering::Relax | ^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/alloc_read_race.rs:LL:CC | LL | ... let j2 = spawn(move || { diff --git a/src/tools/miri/tests/fail/data_race/alloc_write_race.stderr b/src/tools/miri/tests/fail/data_race/alloc_write_race.stderr index 33c562958e20..93fe9ff5539a 100644 --- a/src/tools/miri/tests/fail/data_race/alloc_write_race.stderr +++ b/src/tools/miri/tests/fail/data_race/alloc_write_race.stderr @@ -11,8 +11,8 @@ LL | .store(Box::into_raw(Box::::new_uninit()) as *mut us | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/alloc_write_race.rs:LL:CC | LL | ... let j2 = spawn(move || { diff --git a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.stderr b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.stderr index 6f0332e46fa3..aa8a48461208 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.stderr @@ -11,8 +11,8 @@ LL | *(c.0 as *mut usize) = 32; | ^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/atomic_read_na_write_race1.rs:LL:CC | LL | ... let j2 = spawn(move || { diff --git a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.stderr b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.stderr index 13f95e85242a..1d1dc68784d9 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.stderr @@ -11,8 +11,8 @@ LL | atomic_ref.load(Ordering::SeqCst) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/atomic_read_na_write_race2.rs:LL:CC | LL | ... let j2 = spawn(move || { diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.stderr b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.stderr index 0907ed3cd0a3..b65e4e3609e7 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.stderr @@ -11,8 +11,8 @@ LL | atomic_ref.store(32, Ordering::SeqCst) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/atomic_write_na_read_race1.rs:LL:CC | LL | ... let j2 = spawn(move || { diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.stderr b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.stderr index dfc7ed012725..444d73d46b3c 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.stderr @@ -11,8 +11,8 @@ LL | let _val = *(c.0 as *mut usize); | ^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/atomic_write_na_read_race2.rs:LL:CC | LL | ... let j2 = spawn(move || { diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.stderr b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.stderr index 018db8364ed0..ca67861b47ce 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.stderr @@ -11,8 +11,8 @@ LL | *(c.0 as *mut usize) = 32; | ^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/atomic_write_na_write_race1.rs:LL:CC | LL | ... let j2 = spawn(move || { diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.stderr b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.stderr index ef5521448676..b67a2bac102d 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.stderr @@ -11,8 +11,8 @@ LL | atomic_ref.store(64, Ordering::SeqCst); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/atomic_write_na_write_race2.rs:LL:CC | LL | ... let j2 = spawn(move || { diff --git a/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.stderr b/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.stderr index da13b62b1cf0..d90b8f528f3c 100644 --- a/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.stderr +++ b/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.stderr @@ -11,8 +11,8 @@ LL | *c.0 = 32; | ^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/dangling_thread_async_race.rs:LL:CC | LL | / ... spawn(move || { diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race1.stderr b/src/tools/miri/tests/fail/data_race/dealloc_read_race1.stderr index 798c6c490b4c..feb35ddcd34c 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race1.stderr @@ -16,8 +16,8 @@ LL | let _val = *ptr.0; | ^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/dealloc_read_race1.rs:LL:CC | LL | let j2 = spawn(move || { diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race2.stderr b/src/tools/miri/tests/fail/data_race/dealloc_read_race2.stderr index 4a9e6e832b8e..f1bd657cc5a8 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race2.stderr @@ -20,8 +20,8 @@ LL | | std::mem::size_of::(), LL | | std::mem::align_of::(), LL | | ) | |_____________^ - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/dealloc_read_race2.rs:LL:CC | LL | let j2 = spawn(move || { diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.stderr b/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.stderr index 8b8cfaf9930c..a07dd0a1a1da 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.stderr @@ -11,8 +11,8 @@ LL | *pointer.load(Ordering::Acquire) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/dealloc_read_race_stack.rs:LL:CC | LL | ... let j1 = spawn(move || { diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race1.stderr b/src/tools/miri/tests/fail/data_race/dealloc_write_race1.stderr index 18924d7d65ce..f24830d73fb1 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race1.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race1.stderr @@ -16,8 +16,8 @@ LL | *ptr.0 = 2; | ^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/dealloc_write_race1.rs:LL:CC | LL | let j2 = spawn(move || { diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race2.stderr b/src/tools/miri/tests/fail/data_race/dealloc_write_race2.stderr index 2029e0632141..a4712554a087 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race2.stderr @@ -20,8 +20,8 @@ LL | | std::mem::size_of::(), LL | | std::mem::align_of::(), LL | | ); | |_____________^ - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/dealloc_write_race2.rs:LL:CC | LL | let j2 = spawn(move || { diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.stderr b/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.stderr index 3ce6e6ce5661..cc23bc0f611f 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.stderr @@ -11,8 +11,8 @@ LL | *pointer.load(Ordering::Acquire) = 3; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/dealloc_write_race_stack.rs:LL:CC | LL | ... let j1 = spawn(move || { diff --git a/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.stderr b/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.stderr index f9a18008ab75..1cbca79e04a8 100644 --- a/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.stderr +++ b/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.stderr @@ -11,8 +11,8 @@ LL | *c.0 = 32; | ^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/enable_after_join_to_main.rs:LL:CC | LL | ... let j2 = spawn(move || { diff --git a/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.stderr b/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.stderr index 6caeacfb5e25..7f97fc775ca9 100644 --- a/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.stderr +++ b/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.stderr @@ -11,8 +11,8 @@ LL | StorageLive(val); | ^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/local_variable_alloc_race.rs:LL:CC | LL | / std::thread::spawn(|| { diff --git a/src/tools/miri/tests/fail/data_race/local_variable_read_race.stderr b/src/tools/miri/tests/fail/data_race/local_variable_read_race.stderr index 5dfa6917e3ba..e9173feb61dd 100644 --- a/src/tools/miri/tests/fail/data_race/local_variable_read_race.stderr +++ b/src/tools/miri/tests/fail/data_race/local_variable_read_race.stderr @@ -11,8 +11,8 @@ LL | let _val = val; | ^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/local_variable_read_race.rs:LL:CC | LL | let t1 = std::thread::spawn(|| { diff --git a/src/tools/miri/tests/fail/data_race/local_variable_write_race.stderr b/src/tools/miri/tests/fail/data_race/local_variable_write_race.stderr index 2f9e22f66fff..859ade5fb65d 100644 --- a/src/tools/miri/tests/fail/data_race/local_variable_write_race.stderr +++ b/src/tools/miri/tests/fail/data_race/local_variable_write_race.stderr @@ -11,8 +11,8 @@ LL | let mut val: u8 = 0; | ^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/local_variable_write_race.rs:LL:CC | LL | let t1 = std::thread::spawn(|| { diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_first_load.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_first_load.stderr index 10b5539a5b8c..b74351a5f296 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_first_load.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_first_load.stderr @@ -13,8 +13,8 @@ LL | a16.load(Ordering::SeqCst); = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/mixed_size_read_read_write.rs:LL:CC | LL | / s.spawn(|| { diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_second_load.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_second_load.stderr index 8e37e6161c31..be78189a695d 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_second_load.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_second_load.stderr @@ -13,8 +13,8 @@ LL | a16.load(Ordering::SeqCst); = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/mixed_size_read_read_write.rs:LL:CC | LL | / s.spawn(|| { diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_write.read_write.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.read_write.stderr index ec86c41cd160..736509cd3a9e 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read_write.read_write.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.read_write.stderr @@ -13,8 +13,8 @@ LL | a8[0].load(Ordering::SeqCst); = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/mixed_size_read_write.rs:LL:CC | LL | / s.spawn(|| { diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_write.write_read.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.write_read.stderr index d4d03b96a3e5..f4aa4cbd933f 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read_write.write_read.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.write_read.stderr @@ -13,8 +13,8 @@ LL | a16.store(1, Ordering::SeqCst); = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/mixed_size_read_write.rs:LL:CC | LL | / s.spawn(|| { diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_write_read.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read_write_read.stderr index 98565708f881..10356419dc1e 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read_write_read.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_write_read.stderr @@ -19,8 +19,8 @@ LL | | ); = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/mixed_size_read_write_read.rs:LL:CC | LL | / ... s.spawn(|| { diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.fst.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.fst.stderr index 9033bc2c922d..6c5ac0ca2118 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.fst.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.fst.stderr @@ -13,8 +13,8 @@ LL | a16.store(1, Ordering::SeqCst); = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/mixed_size_write_write.rs:LL:CC | LL | / s.spawn(|| { diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.snd.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.snd.stderr index b0e771c40b91..7e7461a7a4f6 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.snd.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.snd.stderr @@ -13,8 +13,8 @@ LL | a16.store(1, Ordering::SeqCst); = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/mixed_size_write_write.rs:LL:CC | LL | / s.spawn(|| { diff --git a/src/tools/miri/tests/fail/data_race/read_write_race.stderr b/src/tools/miri/tests/fail/data_race/read_write_race.stderr index 1922ce949f6b..f0eae9841bee 100644 --- a/src/tools/miri/tests/fail/data_race/read_write_race.stderr +++ b/src/tools/miri/tests/fail/data_race/read_write_race.stderr @@ -11,8 +11,8 @@ LL | let _val = *c.0; | ^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/read_write_race.rs:LL:CC | LL | ... let j2 = spawn(move || { diff --git a/src/tools/miri/tests/fail/data_race/read_write_race_stack.stderr b/src/tools/miri/tests/fail/data_race/read_write_race_stack.stderr index a6bdac409d9d..703a02508727 100644 --- a/src/tools/miri/tests/fail/data_race/read_write_race_stack.stderr +++ b/src/tools/miri/tests/fail/data_race/read_write_race_stack.stderr @@ -11,8 +11,8 @@ LL | *pointer.load(Ordering::Acquire) = 3; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/read_write_race_stack.rs:LL:CC | LL | ... let j1 = spawn(move || { diff --git a/src/tools/miri/tests/fail/data_race/relax_acquire_race.stderr b/src/tools/miri/tests/fail/data_race/relax_acquire_race.stderr index 6c77bf6b3d8b..1fb793912b72 100644 --- a/src/tools/miri/tests/fail/data_race/relax_acquire_race.stderr +++ b/src/tools/miri/tests/fail/data_race/relax_acquire_race.stderr @@ -11,8 +11,8 @@ LL | *c.0 = 1; | ^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/relax_acquire_race.rs:LL:CC | LL | ... let j3 = spawn(move || { diff --git a/src/tools/miri/tests/fail/data_race/release_seq_race.stderr b/src/tools/miri/tests/fail/data_race/release_seq_race.stderr index 528db7ed2479..8f01b7cdad51 100644 --- a/src/tools/miri/tests/fail/data_race/release_seq_race.stderr +++ b/src/tools/miri/tests/fail/data_race/release_seq_race.stderr @@ -11,8 +11,8 @@ LL | *c.0 = 1; | ^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/release_seq_race.rs:LL:CC | LL | let j3 = spawn(move || { diff --git a/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.stderr b/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.stderr index 1b2daf8b256b..a7fdf8e219f5 100644 --- a/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.stderr +++ b/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.stderr @@ -11,8 +11,8 @@ LL | *c.0 = 1; | ^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/release_seq_race_same_thread.rs:LL:CC | LL | ... let j2 = spawn(move || { diff --git a/src/tools/miri/tests/fail/data_race/rmw_race.stderr b/src/tools/miri/tests/fail/data_race/rmw_race.stderr index 21f710e16b0d..8bbd9929517e 100644 --- a/src/tools/miri/tests/fail/data_race/rmw_race.stderr +++ b/src/tools/miri/tests/fail/data_race/rmw_race.stderr @@ -11,8 +11,8 @@ LL | *c.0 = 1; | ^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/rmw_race.rs:LL:CC | LL | ... let j3 = spawn(move || { diff --git a/src/tools/miri/tests/fail/data_race/write_write_race.stderr b/src/tools/miri/tests/fail/data_race/write_write_race.stderr index 112cdb278196..33352a5ded58 100644 --- a/src/tools/miri/tests/fail/data_race/write_write_race.stderr +++ b/src/tools/miri/tests/fail/data_race/write_write_race.stderr @@ -11,8 +11,8 @@ LL | *c.0 = 32; | ^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/write_write_race.rs:LL:CC | LL | ... let j2 = spawn(move || { diff --git a/src/tools/miri/tests/fail/data_race/write_write_race_stack.stderr b/src/tools/miri/tests/fail/data_race/write_write_race_stack.stderr index c70dbb4e619f..a439be859015 100644 --- a/src/tools/miri/tests/fail/data_race/write_write_race_stack.stderr +++ b/src/tools/miri/tests/fail/data_race/write_write_race_stack.stderr @@ -11,8 +11,8 @@ LL | *pointer.load(Ordering::Acquire) = 3; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/data_race/write_write_race_stack.rs:LL:CC | LL | let j1 = spawn(move || { diff --git a/src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.stderr b/src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.stderr index 068d4b4f1329..a9a8deb05aae 100644 --- a/src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.stderr +++ b/src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.stderr @@ -6,12 +6,11 @@ LL | SetDiscriminant(*ptr, 1); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `set_discriminant` -note: which got called inside `main` - --> tests/fail/enum-set-discriminant-niche-variant-wrong.rs:LL:CC - | -LL | set_discriminant(&mut v); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: set_discriminant + at tests/fail/enum-set-discriminant-niche-variant-wrong.rs:LL:CC + 1: main + at tests/fail/enum-set-discriminant-niche-variant-wrong.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.stack.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.stack.stderr index f45f5c26bacb..952f2272f3bf 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.stack.stderr @@ -21,16 +21,11 @@ help: is this argument | LL | unsafe { ptr.write(S(0)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: error occurred inside `callee` - --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC - | -LL | fn callee(x: S, ptr: *mut S) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC - | -LL | Call(_unit = callee(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: callee + at tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC + 1: main + at tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr index 044026ee8ddc..095dc7e1a1fb 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr @@ -30,16 +30,11 @@ help: the protected tag later transitioned to Unique due to a child write LL | unsafe { ptr.write(S(0)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference -note: error occurred inside `callee` - --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC - | -LL | fn callee(x: S, ptr: *mut S) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC - | -LL | Call(_unit = callee(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: callee + at tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC + 1: main + at tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr index b66d13cede1f..22077345243f 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr @@ -6,12 +6,11 @@ LL | unsafe { ptr.read() }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `change_arg` -note: which got called inside `main` - --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC - | -LL | Call(_unit = change_arg(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: change_arg + at tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC + 1: main + at tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: ALLOC (stack variable, size: 4, align: 4) { diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr index 9dc9adc13ae3..d625d1d1d034 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr @@ -21,16 +21,11 @@ help: is this argument | LL | x.0 = 0; | ^^^^^^^ -note: error occurred inside `change_arg` - --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC - | -LL | fn change_arg(mut x: S, ptr: *mut S) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC - | -LL | Call(_unit = change_arg(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: change_arg + at tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC + 1: main + at tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr index 0a6c6e615a16..a01c040fe6f8 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr @@ -30,16 +30,11 @@ help: the protected tag later transitioned to Unique due to a child write LL | x.0 = 0; | ^^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference -note: error occurred inside `change_arg` - --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC - | -LL | fn change_arg(mut x: S, ptr: *mut S) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC - | -LL | Call(_unit = change_arg(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: change_arg + at tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC + 1: main + at tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr index dd7f52d03f20..3c71934ac63e 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr @@ -14,24 +14,7 @@ error: abnormal termination: the program aborted execution LL | crate::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: this is inside `std::panicking::panic_with_hook` - = note: which got called inside closure (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` (at RUSTLIB/std/src/sys/backtrace.rs:LL:CC) - = note: which got called inside `std::panicking::panic_handler` (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `core::panicking::panic_nounwind` (at RUSTLIB/core/src/panicking.rs:LL:CC) - = note: which got called inside `core::panicking::panic_cannot_unwind` (at RUSTLIB/core/src/panicking.rs:LL:CC) -note: which got called inside `nounwind` - --> tests/fail/function_calls/exported_symbol_bad_unwind2.rs:LL:CC - | -LL | / extern "C-unwind" fn nounwind() { -LL | | panic!(); -LL | | } - | |_^ -note: which got called inside `main` - --> tests/fail/function_calls/exported_symbol_bad_unwind2.rs:LL:CC - | -LL | unsafe { nounwind() } - | ^^^^^^^^^^ + = note: stack backtrace: note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr index dd7f52d03f20..3c71934ac63e 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr @@ -14,24 +14,7 @@ error: abnormal termination: the program aborted execution LL | crate::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: this is inside `std::panicking::panic_with_hook` - = note: which got called inside closure (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` (at RUSTLIB/std/src/sys/backtrace.rs:LL:CC) - = note: which got called inside `std::panicking::panic_handler` (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `core::panicking::panic_nounwind` (at RUSTLIB/core/src/panicking.rs:LL:CC) - = note: which got called inside `core::panicking::panic_cannot_unwind` (at RUSTLIB/core/src/panicking.rs:LL:CC) -note: which got called inside `nounwind` - --> tests/fail/function_calls/exported_symbol_bad_unwind2.rs:LL:CC - | -LL | / extern "C-unwind" fn nounwind() { -LL | | panic!(); -LL | | } - | |_^ -note: which got called inside `main` - --> tests/fail/function_calls/exported_symbol_bad_unwind2.rs:LL:CC - | -LL | unsafe { nounwind() } - | ^^^^^^^^^^ + = note: stack backtrace: note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr index 32e80ed0e61e..016849a6a336 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr @@ -6,12 +6,11 @@ LL | unsafe { ptr.read() }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `myfun` -note: which got called inside `main` - --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC - | -LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: myfun + at tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC + 1: main + at tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: ALLOC (stack variable, size: 4, align: 4) { diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr index 14c8e5cb8960..73c562c94e95 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr @@ -21,16 +21,11 @@ help: was later invalidated at offsets [0x0..0x4] by a Unique in-place fun | LL | unsafe { ptr.read() }; | ^^^^^^^^^^^^^^^^^^^^^ -note: error occurred inside `myfun` - --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC - | -LL | fn myfun(ptr: *mut i32) -> i32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC - | -LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: myfun + at tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC + 1: main + at tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr index 2e5b687f90ac..0dc137843c91 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr @@ -30,16 +30,11 @@ help: the protected tag later transitioned to Unique due to a child write LL | unsafe { ptr.read() }; | ^^^^^^^^^^^^^^^^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference -note: error occurred inside `myfun` - --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC - | -LL | fn myfun(ptr: *mut i32) -> i32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC - | -LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: myfun + at tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC + 1: main + at tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr index 63dee06563d1..6654ddc12c29 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr @@ -21,16 +21,11 @@ help: was later invalidated at offsets [0x0..0x4] by a Unique in-place fun | LL | unsafe { ptr.write(0) }; | ^^^^^^^^^^^^^^^^^^^^^^^ -note: error occurred inside `myfun` - --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC - | -LL | fn myfun(ptr: *mut i32) -> i32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC - | -LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: myfun + at tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC + 1: main + at tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr index 80c111d4ddb4..6472dfd4f995 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr @@ -30,16 +30,11 @@ help: the protected tag later transitioned to Unique due to a child write LL | unsafe { ptr.write(0) }; | ^^^^^^^^^^^^^^^^^^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference -note: error occurred inside `myfun` - --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC - | -LL | fn myfun(ptr: *mut i32) -> i32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC - | -LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: myfun + at tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC + 1: main + at tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr index a6129451530a..79f4d2c69f3c 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr @@ -21,16 +21,11 @@ help: was later invalidated at offsets [0x0..0x4] by a Unique in-place fun | LL | become myfun2(ptr) | ^^^^^^^^^^^^^^^^^^ -note: error occurred inside `myfun2` - --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC - | -LL | fn myfun2(ptr: *mut i32) -> i32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC - | -LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: myfun2 + at tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC + 1: main + at tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr index a6fff1c26683..82b898df45b2 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr @@ -30,16 +30,11 @@ help: the protected tag later transitioned to Unique due to a child write LL | unsafe { ptr.write(0) }; | ^^^^^^^^^^^^^^^^^^^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference -note: error occurred inside `myfun2` - --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC - | -LL | fn myfun2(ptr: *mut i32) -> i32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC - | -LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: myfun2 + at tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC + 1: main + at tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr b/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr index ef6decaece35..db7fb1a68790 100644 --- a/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr +++ b/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr @@ -6,12 +6,11 @@ LL | unsafe { foo(0.0, x) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `bar` -note: which got called inside `main` - --> tests/fail/function_calls/simd_feature_flag_difference.rs:LL:CC - | -LL | let copy = bar(input); - | ^^^^^^^^^^ + = note: stack backtrace: + 0: bar + at tests/fail/function_calls/simd_feature_flag_difference.rs:LL:CC + 1: main + at tests/fail/function_calls/simd_feature_flag_difference.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr index 697e35a660ca..249eba76c83d 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr @@ -6,12 +6,11 @@ LL | RET = PtrMetadata(*p); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `deref_meta` -note: which got called inside `main` - --> tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs:LL:CC - | -LL | let _meta = deref_meta(p.as_ptr().cast()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: deref_meta + at tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs:LL:CC + 1: main + at tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs:LL:CC Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation: ALLOC DUMP diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr index ba711710b41e..371802a7bcf2 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr @@ -18,12 +18,11 @@ LL | RET = PtrMetadata(*p); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `deref_meta` -note: which got called inside `main` - --> tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs:LL:CC - | -LL | let _meta = deref_meta(p.as_ptr().cast()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: deref_meta + at tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs:LL:CC + 1: main + at tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs:LL:CC Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation: ALLOC DUMP diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr index 104e281f2a8e..207e7983aab4 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr @@ -6,12 +6,11 @@ LL | RET = PtrMetadata(*p); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `deref_meta` -note: which got called inside `main` - --> tests/fail/intrinsics/ptr_metadata_uninit_thin.rs:LL:CC - | -LL | let _meta = deref_meta(p.as_ptr()); - | ^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: deref_meta + at tests/fail/intrinsics/ptr_metadata_uninit_thin.rs:LL:CC + 1: main + at tests/fail/intrinsics/ptr_metadata_uninit_thin.rs:LL:CC Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation: ALLOC DUMP diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr index 619925f28968..6cdcd114d5cf 100644 --- a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr +++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr @@ -6,12 +6,11 @@ LL | typed_swap_nonoverlapping(a, b); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `invalid_array` -note: which got called inside `main` - --> tests/fail/intrinsics/typed-swap-invalid-array.rs:LL:CC - | -LL | invalid_array(); - | ^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: invalid_array + at tests/fail/intrinsics/typed-swap-invalid-array.rs:LL:CC + 1: main + at tests/fail/intrinsics/typed-swap-invalid-array.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.left.stderr b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.left.stderr index 42bea7dd5e34..223f7430b60a 100644 --- a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.left.stderr +++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.left.stderr @@ -6,12 +6,11 @@ LL | typed_swap_nonoverlapping(a, b); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `invalid_scalar` -note: which got called inside `main` - --> tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC - | -LL | invalid_scalar(); - | ^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: invalid_scalar + at tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC + 1: main + at tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.right.stderr b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.right.stderr index 13e8c7f9c5ae..59e392085001 100644 --- a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.right.stderr +++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.right.stderr @@ -6,12 +6,11 @@ LL | typed_swap_nonoverlapping(a, b); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `invalid_scalar` -note: which got called inside `main` - --> tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC - | -LL | invalid_scalar(); - | ^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: invalid_scalar + at tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC + 1: main + at tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/issue-miri-1112.stderr b/src/tools/miri/tests/fail/issue-miri-1112.stderr index 0fc67c6d4fd9..0c5c6a94baf2 100644 --- a/src/tools/miri/tests/fail/issue-miri-1112.stderr +++ b/src/tools/miri/tests/fail/issue-miri-1112.stderr @@ -6,12 +6,11 @@ LL | let obj = std::mem::transmute::(obj) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `FunnyPointer::from_data_ptr` -note: which got called inside `main` - --> tests/fail/issue-miri-1112.rs:LL:CC - | -LL | let _raw: &FunnyPointer = FunnyPointer::from_data_ptr(&hello, &meta as *const _); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: FunnyPointer::from_data_ptr + at tests/fail/issue-miri-1112.rs:LL:CC + 1: main + at tests/fail/issue-miri-1112.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/memleak_rc.stderr b/src/tools/miri/tests/fail/memleak_rc.stderr index f7b0950ef6ce..91097a99117f 100644 --- a/src/tools/miri/tests/fail/memleak_rc.stderr +++ b/src/tools/miri/tests/fail/memleak_rc.stderr @@ -4,12 +4,11 @@ error: memory leaked: ALLOC (Rust heap, SIZE, ALIGN), allocated here: LL | Box::leak(Box::new(RcInner { strong: Cell::new(1), weak: Cell::new(1), value })) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: this is inside `std::rc::Rc::>>::new` -note: which got called inside `main` - --> tests/fail/memleak_rc.rs:LL:CC - | -LL | let x = Dummy(Rc::new(RefCell::new(None))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: std::rc::Rc::new + at RUSTLIB/alloc/src/rc.rs:LL:CC + 1: main + at tests/fail/memleak_rc.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/never_transmute_void.rs b/src/tools/miri/tests/fail/never_transmute_void.rs index ad67b4446165..a2db2ca9db61 100644 --- a/src/tools/miri/tests/fail/never_transmute_void.rs +++ b/src/tools/miri/tests/fail/never_transmute_void.rs @@ -1,6 +1,5 @@ // This should fail even without validation //@compile-flags: -Zmiri-disable-validation -//@require-annotations-for-level: ERROR #![feature(never_type)] #![allow(unused, invalid_value)] @@ -18,5 +17,4 @@ mod m { fn main() { let v = unsafe { std::mem::transmute::<(), m::Void>(()) }; m::f(v); - //~^ NOTE: inside `main` } diff --git a/src/tools/miri/tests/fail/never_transmute_void.stderr b/src/tools/miri/tests/fail/never_transmute_void.stderr index a236d17c49dd..ce65be6ef1b4 100644 --- a/src/tools/miri/tests/fail/never_transmute_void.stderr +++ b/src/tools/miri/tests/fail/never_transmute_void.stderr @@ -6,12 +6,11 @@ LL | match v.0 {} | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `m::f` -note: which got called inside `main` - --> tests/fail/never_transmute_void.rs:LL:CC - | -LL | m::f(v); - | ^^^^^^^ + = note: stack backtrace: + 0: m::f + at tests/fail/never_transmute_void.rs:LL:CC + 1: main + at tests/fail/never_transmute_void.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/overlapping_assignment.stderr b/src/tools/miri/tests/fail/overlapping_assignment.stderr index 6bf7fa446598..43e767e97555 100644 --- a/src/tools/miri/tests/fail/overlapping_assignment.stderr +++ b/src/tools/miri/tests/fail/overlapping_assignment.stderr @@ -6,12 +6,11 @@ LL | *ptr1 = *ptr2; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `self_copy` -note: which got called inside `main` - --> tests/fail/overlapping_assignment.rs:LL:CC - | -LL | self_copy(ptr, ptr); - | ^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: self_copy + at tests/fail/overlapping_assignment.rs:LL:CC + 1: main + at tests/fail/overlapping_assignment.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/panic/abort_unwind.stderr b/src/tools/miri/tests/fail/panic/abort_unwind.stderr index 1f45211c5ee4..d5699fc41dfe 100644 --- a/src/tools/miri/tests/fail/panic/abort_unwind.stderr +++ b/src/tools/miri/tests/fail/panic/abort_unwind.stderr @@ -14,18 +14,7 @@ error: abnormal termination: the program aborted execution LL | crate::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: this is inside `std::panicking::panic_with_hook` - = note: which got called inside closure (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` (at RUSTLIB/std/src/sys/backtrace.rs:LL:CC) - = note: which got called inside `std::panicking::panic_handler` (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `core::panicking::panic_nounwind` (at RUSTLIB/core/src/panicking.rs:LL:CC) - = note: which got called inside `core::panicking::panic_cannot_unwind` (at RUSTLIB/core/src/panicking.rs:LL:CC) - = note: which got called inside `std::panic::abort_unwind::<{closure@tests/fail/panic/abort_unwind.rs:LL:CC}, ()>` (at RUSTLIB/core/src/panic.rs:LL:CC) -note: which got called inside `main` - --> tests/fail/panic/abort_unwind.rs:LL:CC - | -LL | std::panic::abort_unwind(|| panic!("PANIC!!!")); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/panic/bad_unwind.stderr b/src/tools/miri/tests/fail/panic/bad_unwind.stderr index 06e019bb6978..d47f7b5b10c1 100644 --- a/src/tools/miri/tests/fail/panic/bad_unwind.stderr +++ b/src/tools/miri/tests/fail/panic/bad_unwind.stderr @@ -11,15 +11,17 @@ LL | std::panic::catch_unwind(|| unwind()).unwrap_err(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside closure - = note: which got called inside `std::panicking::catch_unwind::do_call::<{closure@tests/fail/panic/bad_unwind.rs:LL:CC}, ()>` (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `std::panicking::catch_unwind::<(), {closure@tests/fail/panic/bad_unwind.rs:LL:CC}>` (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `std::panic::catch_unwind::<{closure@tests/fail/panic/bad_unwind.rs:LL:CC}, ()>` (at RUSTLIB/std/src/panic.rs:LL:CC) -note: which got called inside `main` - --> tests/fail/panic/bad_unwind.rs:LL:CC - | -LL | std::panic::catch_unwind(|| unwind()).unwrap_err(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: main::{closure#0} + at tests/fail/panic/bad_unwind.rs:LL:CC + 1: std::panicking::catch_unwind::do_call + at RUSTLIB/std/src/panicking.rs:LL:CC + 2: std::panicking::catch_unwind + at RUSTLIB/std/src/panicking.rs:LL:CC + 3: std::panic::catch_unwind + at RUSTLIB/std/src/panic.rs:LL:CC + 4: main + at tests/fail/panic/bad_unwind.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/panic/double_panic.stderr b/src/tools/miri/tests/fail/panic/double_panic.stderr index 4beadb6aa647..34a62a09cc3e 100644 --- a/src/tools/miri/tests/fail/panic/double_panic.stderr +++ b/src/tools/miri/tests/fail/panic/double_panic.stderr @@ -17,20 +17,7 @@ error: abnormal termination: the program aborted execution LL | crate::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: this is inside `std::panicking::panic_with_hook` - = note: which got called inside closure (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` (at RUSTLIB/std/src/sys/backtrace.rs:LL:CC) - = note: which got called inside `std::panicking::panic_handler` (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `core::panicking::panic_nounwind_nobacktrace` (at RUSTLIB/core/src/panicking.rs:LL:CC) - = note: which got called inside `core::panicking::panic_in_cleanup` (at RUSTLIB/core/src/panicking.rs:LL:CC) -note: which got called inside `main` - --> tests/fail/panic/double_panic.rs:LL:CC - | -LL | / fn main() { -LL | | let _foo = Foo; -LL | | panic!("first"); -LL | | } - | |_^ + = note: stack backtrace: note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/panic/no_std.stderr b/src/tools/miri/tests/fail/panic/no_std.stderr index 128dfddc215e..87adb18a7ab9 100644 --- a/src/tools/miri/tests/fail/panic/no_std.stderr +++ b/src/tools/miri/tests/fail/panic/no_std.stderr @@ -6,12 +6,11 @@ error: abnormal termination: the program aborted execution LL | core::intrinsics::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: this is inside `panic_handler` -note: which got called inside `miri_start` - --> tests/fail/panic/no_std.rs:LL:CC - | -LL | panic!("blarg I am dead") - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: panic_handler + at tests/fail/panic/no_std.rs:LL:CC + 1: miri_start + at RUSTLIB/core/src/panic.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/panic/panic_abort1.stderr b/src/tools/miri/tests/fail/panic/panic_abort1.stderr index 57c8ee843b86..4135ceadc539 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort1.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort1.stderr @@ -9,18 +9,23 @@ error: abnormal termination: the program aborted execution LL | crate::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: this is inside `std::rt::__rust_abort` - = note: which got called inside `panic_abort::__rust_start_panic` (at RUSTLIB/panic_abort/src/lib.rs:LL:CC) - = note: which got called inside `std::panicking::rust_panic` (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `std::panicking::panic_with_hook` (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside closure (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` (at RUSTLIB/std/src/sys/backtrace.rs:LL:CC) - = note: which got called inside `std::panicking::panic_handler` (at RUSTLIB/std/src/panicking.rs:LL:CC) -note: which got called inside `main` - --> tests/fail/panic/panic_abort1.rs:LL:CC - | -LL | std::panic!("panicking from libstd"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: std::rt::__rust_abort + at RUSTLIB/std/src/rt.rs:LL:CC + 1: panic_abort::__rust_start_panic + at RUSTLIB/panic_abort/src/lib.rs:LL:CC + 2: std::panicking::rust_panic + at RUSTLIB/std/src/panicking.rs:LL:CC + 3: std::panicking::panic_with_hook + at RUSTLIB/std/src/panicking.rs:LL:CC + 4: std::panicking::panic_handler::{closure#0} + at RUSTLIB/std/src/panicking.rs:LL:CC + 5: std::sys::backtrace::__rust_end_short_backtrace + at RUSTLIB/std/src/sys/backtrace.rs:LL:CC + 6: std::panicking::panic_handler + at RUSTLIB/std/src/panicking.rs:LL:CC + 7: main + at RUSTLIB/core/src/panic.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/panic/panic_abort2.stderr b/src/tools/miri/tests/fail/panic/panic_abort2.stderr index 7c145634a102..5b485604037c 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort2.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort2.stderr @@ -9,18 +9,23 @@ error: abnormal termination: the program aborted execution LL | crate::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: this is inside `std::rt::__rust_abort` - = note: which got called inside `panic_abort::__rust_start_panic` (at RUSTLIB/panic_abort/src/lib.rs:LL:CC) - = note: which got called inside `std::panicking::rust_panic` (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `std::panicking::panic_with_hook` (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside closure (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` (at RUSTLIB/std/src/sys/backtrace.rs:LL:CC) - = note: which got called inside `std::panicking::panic_handler` (at RUSTLIB/std/src/panicking.rs:LL:CC) -note: which got called inside `main` - --> tests/fail/panic/panic_abort2.rs:LL:CC - | -LL | std::panic!("{}-panicking from libstd", 42); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: std::rt::__rust_abort + at RUSTLIB/std/src/rt.rs:LL:CC + 1: panic_abort::__rust_start_panic + at RUSTLIB/panic_abort/src/lib.rs:LL:CC + 2: std::panicking::rust_panic + at RUSTLIB/std/src/panicking.rs:LL:CC + 3: std::panicking::panic_with_hook + at RUSTLIB/std/src/panicking.rs:LL:CC + 4: std::panicking::panic_handler::{closure#0} + at RUSTLIB/std/src/panicking.rs:LL:CC + 5: std::sys::backtrace::__rust_end_short_backtrace + at RUSTLIB/std/src/sys/backtrace.rs:LL:CC + 6: std::panicking::panic_handler + at RUSTLIB/std/src/panicking.rs:LL:CC + 7: main + at RUSTLIB/core/src/panic.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/panic/panic_abort3.stderr b/src/tools/miri/tests/fail/panic/panic_abort3.stderr index 71877122b625..e4179f93f931 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort3.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort3.stderr @@ -9,18 +9,23 @@ error: abnormal termination: the program aborted execution LL | crate::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: this is inside `std::rt::__rust_abort` - = note: which got called inside `panic_abort::__rust_start_panic` (at RUSTLIB/panic_abort/src/lib.rs:LL:CC) - = note: which got called inside `std::panicking::rust_panic` (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `std::panicking::panic_with_hook` (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside closure (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` (at RUSTLIB/std/src/sys/backtrace.rs:LL:CC) - = note: which got called inside `std::panicking::panic_handler` (at RUSTLIB/std/src/panicking.rs:LL:CC) -note: which got called inside `main` - --> tests/fail/panic/panic_abort3.rs:LL:CC - | -LL | core::panic!("panicking from libcore"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: std::rt::__rust_abort + at RUSTLIB/std/src/rt.rs:LL:CC + 1: panic_abort::__rust_start_panic + at RUSTLIB/panic_abort/src/lib.rs:LL:CC + 2: std::panicking::rust_panic + at RUSTLIB/std/src/panicking.rs:LL:CC + 3: std::panicking::panic_with_hook + at RUSTLIB/std/src/panicking.rs:LL:CC + 4: std::panicking::panic_handler::{closure#0} + at RUSTLIB/std/src/panicking.rs:LL:CC + 5: std::sys::backtrace::__rust_end_short_backtrace + at RUSTLIB/std/src/sys/backtrace.rs:LL:CC + 6: std::panicking::panic_handler + at RUSTLIB/std/src/panicking.rs:LL:CC + 7: main + at RUSTLIB/core/src/panic.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/panic/panic_abort4.stderr b/src/tools/miri/tests/fail/panic/panic_abort4.stderr index 2b4c6bea5605..d2e50b87068f 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort4.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort4.stderr @@ -9,18 +9,23 @@ error: abnormal termination: the program aborted execution LL | crate::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: this is inside `std::rt::__rust_abort` - = note: which got called inside `panic_abort::__rust_start_panic` (at RUSTLIB/panic_abort/src/lib.rs:LL:CC) - = note: which got called inside `std::panicking::rust_panic` (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `std::panicking::panic_with_hook` (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside closure (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` (at RUSTLIB/std/src/sys/backtrace.rs:LL:CC) - = note: which got called inside `std::panicking::panic_handler` (at RUSTLIB/std/src/panicking.rs:LL:CC) -note: which got called inside `main` - --> tests/fail/panic/panic_abort4.rs:LL:CC - | -LL | core::panic!("{}-panicking from libcore", 42); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: std::rt::__rust_abort + at RUSTLIB/std/src/rt.rs:LL:CC + 1: panic_abort::__rust_start_panic + at RUSTLIB/panic_abort/src/lib.rs:LL:CC + 2: std::panicking::rust_panic + at RUSTLIB/std/src/panicking.rs:LL:CC + 3: std::panicking::panic_with_hook + at RUSTLIB/std/src/panicking.rs:LL:CC + 4: std::panicking::panic_handler::{closure#0} + at RUSTLIB/std/src/panicking.rs:LL:CC + 5: std::sys::backtrace::__rust_end_short_backtrace + at RUSTLIB/std/src/sys/backtrace.rs:LL:CC + 6: std::panicking::panic_handler + at RUSTLIB/std/src/panicking.rs:LL:CC + 7: main + at RUSTLIB/core/src/panic.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/panic/tls_macro_const_drop_panic.rs b/src/tools/miri/tests/fail/panic/tls_macro_const_drop_panic.rs index 93ad42ea1cce..c25684af5090 100644 --- a/src/tools/miri/tests/fail/panic/tls_macro_const_drop_panic.rs +++ b/src/tools/miri/tests/fail/panic/tls_macro_const_drop_panic.rs @@ -4,6 +4,7 @@ //@compile-flags: -Zmiri-backtrace=full //@normalize-stderr-test: "'main'|''" -> "$$NAME" //@normalize-stderr-test: ".*(note|-->|\|).*\n" -> "" +//@normalize-stderr-test: "\n *\d+:.*\n *at .*" -> "" pub struct NoisyDrop {} diff --git a/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.rs b/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.rs index a207d3923124..32fd8318f796 100644 --- a/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.rs +++ b/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.rs @@ -1,7 +1,8 @@ //@error-in-other-file: aborted execution // Backtraces vary wildly between platforms, we have to normalize away almost the entire thing //@normalize-stderr-test: "'main'|''" -> "$$NAME" -//@normalize-stderr-test: ".*(note|-->|:::|\|).*\n" -> "" +//@normalize-stderr-test: ".*(note|-->|\|).*\n" -> "" +//@normalize-stderr-test: "\n *\d+:.*\n *at .*" -> "" pub struct NoisyDrop {} diff --git a/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.stderr b/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.stderr index 39263a8d61cc..ec243f114af0 100644 --- a/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.stderr +++ b/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.stderr @@ -3,6 +3,7 @@ thread $NAME ($TID) panicked at tests/fail/panic/tls_macro_drop_panic.rs:LL:CC: ow fatal runtime error: thread local panicked on drop, aborting error: abnormal termination: the program aborted execution + ::: RUSTLIB/std/src/sys/thread_local/PLATFORM.rs:LL:CC error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr b/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr index 6af86ffdb2bd..fc9f394a568c 100644 --- a/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr +++ b/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr @@ -6,12 +6,11 @@ LL | let _val = *left_ptr; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `deref` -note: which got called inside `main` - --> tests/fail/provenance/provenance_transmute.rs:LL:CC - | -LL | deref(ptr1, ptr2.with_addr(ptr1.addr())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: deref + at tests/fail/provenance/provenance_transmute.rs:LL:CC + 1: main + at tests/fail/provenance/provenance_transmute.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr index 7fc54636b552..7275be1343ac 100644 --- a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr +++ b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr @@ -12,15 +12,7 @@ error: abnormal termination: the program aborted execution LL | crate::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: this is inside `std::panicking::panic_with_hook` - = note: which got called inside closure (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` (at RUSTLIB/std/src/sys/backtrace.rs:LL:CC) - = note: which got called inside `std::panicking::panic_handler` (at RUSTLIB/std/src/panicking.rs:LL:CC) -note: which got called inside `main` - --> tests/fail/ptr_swap_nonoverlapping.rs:LL:CC - | -LL | std::ptr::swap_nonoverlapping(ptr, ptr, 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/shims/ctor_ub.stderr b/src/tools/miri/tests/fail/shims/ctor_ub.stderr index ab8a8f633638..e89f3b3c9059 100644 --- a/src/tools/miri/tests/fail/shims/ctor_ub.stderr +++ b/src/tools/miri/tests/fail/shims/ctor_ub.stderr @@ -6,8 +6,7 @@ LL | std::hint::unreachable_unchecked() | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `ctor` -note: which got called indirectly due to this code +note: the current function got called indirectly due to this code --> tests/fail/shims/ctor_ub.rs:LL:CC | LL | static $ident: unsafe extern "C" fn() = $ctor; diff --git a/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr b/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr index eb7f70a351ad..af55ccfe5e67 100644 --- a/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr +++ b/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr @@ -6,22 +6,31 @@ LL | let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode a | = help: set `MIRIFLAGS=-Zmiri-disable-isolation` to disable isolation; = help: or set `MIRIFLAGS=-Zmiri-isolation-error=warn` to make Miri return an error code from isolated operations (if supported for that operation) and continue with a warning - = note: this is inside closure - = note: which got called inside `std::sys::pal::PLATFORM::cvt_r::` (at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC) - = note: which got called inside `std::sys::fs::PLATFORM::File::open_c` (at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC) - = note: which got called inside closure (at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC) - = note: which got called inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr_stack::` (at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC) - = note: which got called inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr::` (at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC) - = note: which got called inside `std::sys::pal::PLATFORM::small_c_string::run_path_with_cstr::` (at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC) - = note: which got called inside `std::sys::fs::PLATFORM::File::open` (at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC) - = note: which got called inside `std::fs::OpenOptions::_open` (at RUSTLIB/std/src/fs.rs:LL:CC) - = note: which got called inside `std::fs::OpenOptions::open::<&std::path::Path>` (at RUSTLIB/std/src/fs.rs:LL:CC) - = note: which got called inside `std::fs::File::open::<&str>` (at RUSTLIB/std/src/fs.rs:LL:CC) -note: which got called inside `main` - --> tests/fail/shims/fs/isolated_file.rs:LL:CC - | -LL | let _file = std::fs::File::open("file.txt").unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: std::sys::fs::PLATFORM::File::open_c::{closure#0} + at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC + 1: std::sys::pal::PLATFORM::cvt_r + at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + 2: std::sys::fs::PLATFORM::File::open_c + at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC + 3: std::sys::fs::PLATFORM::File::open::{closure#0} + at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC + 4: std::sys::pal::PLATFORM::small_c_string::run_with_cstr_stack + at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC + 5: std::sys::pal::PLATFORM::small_c_string::run_with_cstr + at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC + 6: std::sys::pal::PLATFORM::small_c_string::run_path_with_cstr + at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC + 7: std::sys::fs::PLATFORM::File::open + at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC + 8: std::fs::OpenOptions::_open + at RUSTLIB/std/src/fs.rs:LL:CC + 9: std::fs::OpenOptions::open + at RUSTLIB/std/src/fs.rs:LL:CC + 10: std::fs::File::open + at RUSTLIB/std/src/fs.rs:LL:CC + 11: main + at tests/fail/shims/fs/isolated_file.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/shims/isolated_stdin.stderr b/src/tools/miri/tests/fail/shims/isolated_stdin.stderr index 58f0957a668c..c478f1412bbf 100644 --- a/src/tools/miri/tests/fail/shims/isolated_stdin.stderr +++ b/src/tools/miri/tests/fail/shims/isolated_stdin.stderr @@ -5,10 +5,6 @@ error: unsupported operation: `read` from stdin not available when isolation is | = help: set `MIRIFLAGS=-Zmiri-disable-isolation` to disable isolation; = help: or set `MIRIFLAGS=-Zmiri-isolation-error=warn` to make Miri return an error code from isolated operations (if supported for that operation) and continue with a warning -note: which got called inside `main` - --> tests/fail/shims/isolated_stdin.rs:LL:CC - | - | ^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector1.stderr b/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector1.stderr index 84051e688aab..266f9247b98d 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector1.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector1.stderr @@ -6,28 +6,21 @@ LL | self.1.deallocate(From::from(ptr.cast()), layout); | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - = note: this is inside ` as std::ops::Drop>::drop` - = note: which got called inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` (at RUSTLIB/core/src/ptr/mod.rs:LL:CC) - = note: which got called inside `std::mem::drop::>` (at RUSTLIB/core/src/mem/mod.rs:LL:CC) -note: which got called inside closure - --> tests/fail/stacked_borrows/deallocate_against_protector1.rs:LL:CC - | -LL | drop(unsafe { Box::from_raw(raw) }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: which got called inside `<{closure@tests/fail/stacked_borrows/deallocate_against_protector1.rs:LL:CC} as std::ops::FnOnce<(&mut i32,)>>::call_once - shim` (at RUSTLIB/core/src/ops/function.rs:LL:CC) -note: which got called inside `inner` - --> tests/fail/stacked_borrows/deallocate_against_protector1.rs:LL:CC - | -LL | f(x) - | ^^^^ -note: which got called inside `main` - --> tests/fail/stacked_borrows/deallocate_against_protector1.rs:LL:CC - | -LL | / inner(Box::leak(Box::new(0)), |x| { -LL | | let raw = x as *mut _; -LL | | drop(unsafe { Box::from_raw(raw) }); -LL | | }); - | |______^ + = note: stack backtrace: + 0: as std::ops::Drop>::drop + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 1: std::ptr::drop_in_place)) + at RUSTLIB/core/src/ptr/mod.rs:LL:CC + 2: std::mem::drop + at RUSTLIB/core/src/mem/mod.rs:LL:CC + 3: main::{closure#0} + at tests/fail/stacked_borrows/deallocate_against_protector1.rs:LL:CC + 4: <{closure@tests/fail/stacked_borrows/deallocate_against_protector1.rs:LL:CC} as std::ops::FnOnce<(&mut i32,)>>::call_once - shim + at RUSTLIB/core/src/ops/function.rs:LL:CC + 5: inner + at tests/fail/stacked_borrows/deallocate_against_protector1.rs:LL:CC + 6: main + at tests/fail/stacked_borrows/deallocate_against_protector1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_protector.stderr b/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_protector.stderr index 7f4899bb0d6f..027fe239319a 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_protector.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_protector.stderr @@ -16,18 +16,15 @@ help: is this argument | LL | core::ptr::drop_in_place(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: error occurred inside `::drop` - --> tests/fail/stacked_borrows/drop_in_place_protector.rs:LL:CC - | -LL | fn drop(&mut self) { - | ^^^^^^^^^^^^^^^^^^ - = note: which got called inside `std::ptr::drop_in_place:: - shim(Some(HasDrop))` (at RUSTLIB/core/src/ptr/mod.rs:LL:CC) - = note: which got called inside `std::ptr::drop_in_place::<(HasDrop, u8)> - shim(Some((HasDrop, u8)))` (at RUSTLIB/core/src/ptr/mod.rs:LL:CC) -note: which got called inside `main` - --> tests/fail/stacked_borrows/drop_in_place_protector.rs:LL:CC - | -LL | core::ptr::drop_in_place(x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: ::drop + at tests/fail/stacked_borrows/drop_in_place_protector.rs:LL:CC + 1: std::ptr::drop_in_place - shim(Some(HasDrop)) + at RUSTLIB/core/src/ptr/mod.rs:LL:CC + 2: std::ptr::drop_in_place - shim(Some((HasDrop, u8))) + at RUSTLIB/core/src/ptr/mod.rs:LL:CC + 3: main + at tests/fail/stacked_borrows/drop_in_place_protector.rs:LL:CC = note: this error originates in the macro `core::ptr::addr_of_mut` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.stderr b/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.stderr index 11b3e49b852e..cffa17556950 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.stderr @@ -13,18 +13,11 @@ help: was created by a SharedReadOnly retag at offsets [0x0..0x1] | LL | let x = core::ptr::addr_of!(x); | ^^^^^^^^^^^^^^^^^^^^^^ -note: error occurred inside `std::ptr::drop_in_place:: - shim(None)` - --> RUSTLIB/core/src/ptr/mod.rs:LL:CC - | -LL | / pub const unsafe fn drop_in_place(to_drop: *mut T) -LL | | where -LL | | T: [const] Destruct, - | |________________________^ -note: which got called inside `main` - --> tests/fail/stacked_borrows/drop_in_place_retag.rs:LL:CC - | -LL | core::ptr::drop_in_place(x.cast_mut()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: std::ptr::drop_in_place - shim(None) + at RUSTLIB/core/src/ptr/mod.rs:LL:CC + 1: main + at tests/fail/stacked_borrows/drop_in_place_retag.rs:LL:CC = note: this error originates in the macro `core::ptr::addr_of` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/invalidate_against_protector1.stderr b/src/tools/miri/tests/fail/stacked_borrows/invalidate_against_protector1.stderr index 17abcf0a4643..336dff598b42 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/invalidate_against_protector1.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/invalidate_against_protector1.stderr @@ -16,16 +16,11 @@ help: is this argument | LL | fn inner(x: *mut i32, _y: &mut i32) { | ^^ -note: error occurred inside `inner` - --> tests/fail/stacked_borrows/invalidate_against_protector1.rs:LL:CC - | -LL | fn inner(x: *mut i32, _y: &mut i32) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/stacked_borrows/invalidate_against_protector1.rs:LL:CC - | -LL | inner(xraw, xref); - | ^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: inner + at tests/fail/stacked_borrows/invalidate_against_protector1.rs:LL:CC + 1: main + at tests/fail/stacked_borrows/invalidate_against_protector1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/pointer_smuggling.stderr b/src/tools/miri/tests/fail/stacked_borrows/pointer_smuggling.stderr index a13ff30deda7..4f6045c7c16a 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/pointer_smuggling.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/pointer_smuggling.stderr @@ -16,16 +16,11 @@ help: was later invalidated at offsets [0x0..0x1] by a write access | LL | *val = 2; // this invalidates any raw ptrs `fun1` might have created. | ^^^^^^^^ -note: error occurred inside `fun2` - --> tests/fail/stacked_borrows/pointer_smuggling.rs:LL:CC - | -LL | fn fun2() { - | ^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/stacked_borrows/pointer_smuggling.rs:LL:CC - | -LL | fun2(); // if they now use a raw ptr they break our reference - | ^^^^^^ + = note: stack backtrace: + 0: fun2 + at tests/fail/stacked_borrows/pointer_smuggling.rs:LL:CC + 1: main + at tests/fail/stacked_borrows/pointer_smuggling.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr index f50b05712ee2..7f112a2e85b6 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr @@ -14,8 +14,8 @@ LL | unsafe { ptr.0.read() }; = help: therefore from the perspective of data races, a retag has the same implications as a read or write = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/stacked_borrows/retag_data_race_protected_read.rs:LL:CC | LL | let t = thread::spawn(move || { diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr index 67b1cdab911a..c162bee0a672 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr @@ -14,17 +14,13 @@ LL | let _r = &*p; = help: therefore from the perspective of data races, a retag has the same implications as a read or write = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information -note: error occurred on thread `unnamed-ID`, inside `thread_2` - --> tests/fail/stacked_borrows/retag_data_race_read.rs:LL:CC - | -LL | fn thread_2(p: SendPtr) { - | ^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside closure - --> tests/fail/stacked_borrows/retag_data_race_read.rs:LL:CC - | -LL | let t2 = std::thread::spawn(move || thread_2(p)); - | ^^^^^^^^^^^ -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` + = note: stack backtrace: + 0: thread_2 + at tests/fail/stacked_borrows/retag_data_race_read.rs:LL:CC + 1: main::{closure#1} + at tests/fail/stacked_borrows/retag_data_race_read.rs:LL:CC +note: the last function in that backtrace got called indirectly due to this code --> tests/fail/stacked_borrows/retag_data_race_read.rs:LL:CC | LL | let t2 = std::thread::spawn(move || thread_2(p)); diff --git a/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut.stderr b/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut.stderr index 9148f5ae817c..88dfd1ec9db9 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut.stderr @@ -16,16 +16,11 @@ help: was later invalidated at offsets [0x0..0x8] by a read access | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ -note: error occurred inside `foo` - --> tests/fail/stacked_borrows/return_invalid_mut.rs:LL:CC - | -LL | fn foo(x: &mut (i32, i32)) -> &mut i32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/stacked_borrows/return_invalid_mut.rs:LL:CC - | -LL | foo(&mut (1, 2)); - | ^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: foo + at tests/fail/stacked_borrows/return_invalid_mut.rs:LL:CC + 1: main + at tests/fail/stacked_borrows/return_invalid_mut.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_option.stderr b/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_option.stderr index 6cce7f9f246e..5ccb09c7fd84 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_option.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_option.stderr @@ -19,16 +19,11 @@ help: was later invalidated at offsets [0x0..0x8] by a read access | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ -note: error occurred inside `foo` - --> tests/fail/stacked_borrows/return_invalid_mut_option.rs:LL:CC - | -LL | fn foo(x: &mut (i32, i32)) -> Option<&mut i32> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/stacked_borrows/return_invalid_mut_option.rs:LL:CC - | -LL | match foo(&mut (1, 2)) { - | ^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: foo + at tests/fail/stacked_borrows/return_invalid_mut_option.rs:LL:CC + 1: main + at tests/fail/stacked_borrows/return_invalid_mut_option.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr b/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr index 37d18f122b68..eb68a637c229 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr @@ -19,16 +19,11 @@ help: was later invalidated at offsets [0x0..0x8] by a read access | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ -note: error occurred inside `foo` - --> tests/fail/stacked_borrows/return_invalid_mut_tuple.rs:LL:CC - | -LL | fn foo(x: &mut (i32, i32)) -> (&mut i32,) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/stacked_borrows/return_invalid_mut_tuple.rs:LL:CC - | -LL | foo(&mut (1, 2)).0; - | ^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: foo + at tests/fail/stacked_borrows/return_invalid_mut_tuple.rs:LL:CC + 1: main + at tests/fail/stacked_borrows/return_invalid_mut_tuple.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr index 00dd2999f540..c7e471f570c8 100644 --- a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr +++ b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr @@ -6,19 +6,33 @@ LL | extern "rust-call" fn call_once(self, args: Args) -> Self::Output; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `>::call_once - shim(fn())` - = note: which got called inside `std::sys::backtrace::__rust_begin_short_backtrace::` (at RUSTLIB/std/src/sys/backtrace.rs:LL:CC) - = note: which got called inside closure (at RUSTLIB/std/src/rt.rs:LL:CC) - = note: which got called inside `std::ops::function::impls:: for &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>::call_once` (at RUSTLIB/core/src/ops/function.rs:LL:CC) - = note: which got called inside `std::panicking::catch_unwind::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `std::panicking::catch_unwind:: i32 + std::marker::Sync + std::panic::RefUnwindSafe>` (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` (at RUSTLIB/std/src/panic.rs:LL:CC) - = note: which got called inside closure (at RUSTLIB/std/src/rt.rs:LL:CC) - = note: which got called inside `std::panicking::catch_unwind::do_call::<{closure@std::rt::lang_start_internal::{closure#0}}, isize>` (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `std::panicking::catch_unwind::` (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `std::panic::catch_unwind::<{closure@std::rt::lang_start_internal::{closure#0}}, isize>` (at RUSTLIB/std/src/panic.rs:LL:CC) - = note: which got called inside `std::rt::lang_start_internal` (at RUSTLIB/std/src/rt.rs:LL:CC) - = note: which got called inside `std::rt::lang_start::<()>` (at RUSTLIB/std/src/rt.rs:LL:CC) + = note: stack backtrace: + 0: >::call_once - shim(fn()) + at RUSTLIB/core/src/ops/function.rs:LL:CC + 1: std::sys::backtrace::__rust_begin_short_backtrace + at RUSTLIB/std/src/sys/backtrace.rs:LL:CC + 2: std::rt::lang_start::{closure#0} + at RUSTLIB/std/src/rt.rs:LL:CC + 3: std::ops::function::impls::call_once + at RUSTLIB/core/src/ops/function.rs:LL:CC + 4: std::panicking::catch_unwind::do_call + at RUSTLIB/std/src/panicking.rs:LL:CC + 5: std::panicking::catch_unwind + at RUSTLIB/std/src/panicking.rs:LL:CC + 6: std::panic::catch_unwind + at RUSTLIB/std/src/panic.rs:LL:CC + 7: std::rt::lang_start_internal::{closure#0} + at RUSTLIB/std/src/rt.rs:LL:CC + 8: std::panicking::catch_unwind::do_call + at RUSTLIB/std/src/panicking.rs:LL:CC + 9: std::panicking::catch_unwind + at RUSTLIB/std/src/panicking.rs:LL:CC + 10: std::panic::catch_unwind + at RUSTLIB/std/src/panic.rs:LL:CC + 11: std::rt::lang_start_internal + at RUSTLIB/std/src/rt.rs:LL:CC + 12: std::rt::lang_start + at RUSTLIB/std/src/rt.rs:LL:CC error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr index a48673fb4b23..1577cceae594 100644 --- a/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr +++ b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr @@ -16,16 +16,11 @@ help: ALLOC was deallocated here: | LL | f(std::ptr::null()); | ^^^^^^^^^^^^^^^^^^^ -note: error occurred inside `g` - --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC - | -LL | fn g(x: *const i32) { - | ^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC - | -LL | f(std::ptr::null()); - | ^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: g + at tests/fail/tail_calls/dangling-local-var.rs:LL:CC + 1: main + at tests/fail/tail_calls/dangling-local-var.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/terminate-terminator.stderr b/src/tools/miri/tests/fail/terminate-terminator.stderr index 7d8ae128b5d6..6c38de9b0314 100644 --- a/src/tools/miri/tests/fail/terminate-terminator.stderr +++ b/src/tools/miri/tests/fail/terminate-terminator.stderr @@ -16,30 +16,7 @@ error: abnormal termination: the program aborted execution LL | crate::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: this is inside `std::panicking::panic_with_hook` - = note: which got called inside closure (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` (at RUSTLIB/std/src/sys/backtrace.rs:LL:CC) - = note: which got called inside `std::panicking::panic_handler` (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `core::panicking::panic_nounwind` (at RUSTLIB/core/src/panicking.rs:LL:CC) - = note: which got called inside `core::panicking::panic_cannot_unwind` (at RUSTLIB/core/src/panicking.rs:LL:CC) -note: which got called inside `has_cleanup` - --> tests/fail/terminate-terminator.rs:LL:CC - | -LL | / fn has_cleanup() { -LL | | let _f = Foo; -LL | | panic!(); -LL | | } - | |_^ -note: which got called inside `panic_abort` - --> tests/fail/terminate-terminator.rs:LL:CC - | -LL | has_cleanup(); - | ^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/terminate-terminator.rs:LL:CC - | -LL | panic_abort(); - | ^^^^^^^^^^^^^ + = note: stack backtrace: note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tls_macro_leak.stderr b/src/tools/miri/tests/fail/tls_macro_leak.stderr index c3029bb5b4de..3f8240f44547 100644 --- a/src/tools/miri/tests/fail/tls_macro_leak.stderr +++ b/src/tools/miri/tests/fail/tls_macro_leak.stderr @@ -4,16 +4,15 @@ error: memory leaked: ALLOC (Rust heap, size: 4, align: 4), allocated here: LL | cell.set(Some(Box::leak(Box::new(123)))); | ^^^^^^^^^^^^^ | - = note: this is inside closure - = note: which got called inside `std::thread::LocalKey::>>::try_with::<{closure@tests/fail/tls_macro_leak.rs:LL:CC}, ()>` (at RUSTLIB/std/src/thread/local.rs:LL:CC) - = note: which got called inside `std::thread::LocalKey::>>::with::<{closure@tests/fail/tls_macro_leak.rs:LL:CC}, ()>` (at RUSTLIB/std/src/thread/local.rs:LL:CC) -note: which got called inside closure - --> tests/fail/tls_macro_leak.rs:LL:CC - | -LL | / TLS.with(|cell| { -LL | | cell.set(Some(Box::leak(Box::new(123)))); -LL | | }); - | |__________^ + = note: stack backtrace: + 0: main::{closure#0}::{closure#0} + at tests/fail/tls_macro_leak.rs:LL:CC + 1: std::thread::LocalKey::>>::try_with + at RUSTLIB/std/src/thread/local.rs:LL:CC + 2: std::thread::LocalKey::>>::with + at RUSTLIB/std/src/thread/local.rs:LL:CC + 3: main::{closure#0} + at tests/fail/tls_macro_leak.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/outside-range.stderr b/src/tools/miri/tests/fail/tree_borrows/outside-range.stderr index e504f8dde717..a51cf50640ba 100644 --- a/src/tools/miri/tests/fail/tree_borrows/outside-range.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/outside-range.stderr @@ -19,16 +19,11 @@ help: the protected tag was created here, in the initial state Reserved | LL | unsafe fn stuff(x: &mut u8, y: *mut u8) { | ^ -note: error occurred inside `stuff` - --> tests/fail/tree_borrows/outside-range.rs:LL:CC - | -LL | unsafe fn stuff(x: &mut u8, y: *mut u8) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/tree_borrows/outside-range.rs:LL:CC - | -LL | stuff(&mut *raw, raw); - | ^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: stuff + at tests/fail/tree_borrows/outside-range.rs:LL:CC + 1: main + at tests/fail/tree_borrows/outside-range.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr b/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr index 48527fedcc35..029b0a56f305 100644 --- a/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr @@ -30,16 +30,11 @@ help: the conflicting tag later transitioned to Frozen due to a foreign re LL | let _val = unsafe { *xraw }; // invalidate xref for writing | ^^^^^ = help: this transition corresponds to a loss of write permissions -note: error occurred inside `foo` - --> tests/fail/tree_borrows/pass_invalid_mut.rs:LL:CC - | -LL | fn foo(nope: &mut i32) { - | ^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/tree_borrows/pass_invalid_mut.rs:LL:CC - | -LL | foo(xref); - | ^^^^^^^^^ + = note: stack backtrace: + 0: foo + at tests/fail/tree_borrows/pass_invalid_mut.rs:LL:CC + 1: main + at tests/fail/tree_borrows/pass_invalid_mut.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.stderr b/src/tools/miri/tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.stderr index 40a3989c2dc4..693afb133967 100644 --- a/src/tools/miri/tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.stderr @@ -18,16 +18,11 @@ help: the accessed tag later transitioned to Reserved (conflicted) due to LL | do_something(*orig_ptr); | ^^^^^^^^^ = help: this transition corresponds to a temporary loss of write permissions until function exit -note: error occurred inside `access_after_sub_1` - --> tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.rs:LL:CC - | -LL | unsafe fn access_after_sub_1(x: &mut u8, orig_ptr: *mut u8) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.rs:LL:CC - | -LL | access_after_sub_1(&mut *(foo as *mut u8).byte_add(1), orig_ptr); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: access_after_sub_1 + at tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.rs:LL:CC + 1: main + at tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr index 8effbe30dd6a..29397a8fd0bc 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr @@ -29,16 +29,11 @@ help: the protected tag was created here, in the initial state Reserved | LL | unsafe fn write_second(x: &mut UnsafeCell, y: *mut u8) { | ^ -note: error occurred inside `main::write_second` - --> tests/fail/tree_borrows/reserved/cell-protected-write.rs:LL:CC - | -LL | unsafe fn write_second(x: &mut UnsafeCell, y: *mut u8) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/tree_borrows/reserved/cell-protected-write.rs:LL:CC - | -LL | write_second(x, y); - | ^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: main::write_second + at tests/fail/tree_borrows/reserved/cell-protected-write.rs:LL:CC + 1: main + at tests/fail/tree_borrows/reserved/cell-protected-write.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/reserved/int-protected-write.stderr b/src/tools/miri/tests/fail/tree_borrows/reserved/int-protected-write.stderr index 1bc337eb1e7a..3bddd2ce1de6 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reserved/int-protected-write.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/reserved/int-protected-write.stderr @@ -29,16 +29,11 @@ help: the protected tag was created here, in the initial state Reserved | LL | unsafe fn write_second(x: &mut u8, y: *mut u8) { | ^ -note: error occurred inside `main::write_second` - --> tests/fail/tree_borrows/reserved/int-protected-write.rs:LL:CC - | -LL | unsafe fn write_second(x: &mut u8, y: *mut u8) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/tree_borrows/reserved/int-protected-write.rs:LL:CC - | -LL | write_second(x, y); - | ^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: main::write_second + at tests/fail/tree_borrows/reserved/int-protected-write.rs:LL:CC + 1: main + at tests/fail/tree_borrows/reserved/int-protected-write.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr index 3567340f2202..619e707f36f7 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr @@ -32,8 +32,8 @@ help: the accessed tag later transitioned to Disabled due to a foreign wri LL | *x = 64; | ^^^^^^^ = help: this transition corresponds to a loss of read and write permissions - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/tree_borrows/reservedim_spurious_write.rs:LL:CC | LL | let thread_2 = thread::spawn(move || { diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr index a28730abd953..2f14900e43e7 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr @@ -32,8 +32,8 @@ help: the accessed tag later transitioned to Disabled due to a protector r LL | } | ^ = help: this transition corresponds to a loss of read and write permissions - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/tree_borrows/reservedim_spurious_write.rs:LL:CC | LL | let thread_2 = thread::spawn(move || { diff --git a/src/tools/miri/tests/fail/tree_borrows/spurious_read.stderr b/src/tools/miri/tests/fail/tree_borrows/spurious_read.stderr index 9e20ec238ed8..12c163aa8754 100644 --- a/src/tools/miri/tests/fail/tree_borrows/spurious_read.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/spurious_read.stderr @@ -31,17 +31,13 @@ help: the accessed tag later transitioned to Reserved (conflicted) due to LL | } | ^ = help: this transition corresponds to a temporary loss of write permissions until function exit -note: error occurred on thread `unnamed-ID`, inside `retagx_retagy_retx_writey_rety::{closure#1}::as_mut` - --> tests/fail/tree_borrows/spurious_read.rs:LL:CC - | -LL | fn as_mut(y: &mut u8, b: (usize, Arc)) -> *mut u8 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside closure - --> tests/fail/tree_borrows/spurious_read.rs:LL:CC - | -LL | let _y = as_mut(unsafe { &mut *ptr.0 }, b.clone()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` + = note: stack backtrace: + 0: retagx_retagy_retx_writey_rety::{closure#1}::as_mut + at tests/fail/tree_borrows/spurious_read.rs:LL:CC + 1: retagx_retagy_retx_writey_rety::{closure#1} + at tests/fail/tree_borrows/spurious_read.rs:LL:CC +note: the last function in that backtrace got called indirectly due to this code --> tests/fail/tree_borrows/spurious_read.rs:LL:CC | LL | let thread_y = thread::spawn(move || { diff --git a/src/tools/miri/tests/fail/tree_borrows/strongly-protected.stderr b/src/tools/miri/tests/fail/tree_borrows/strongly-protected.stderr index 9545ebf39a27..4abaeb66e527 100644 --- a/src/tools/miri/tests/fail/tree_borrows/strongly-protected.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/strongly-protected.stderr @@ -18,31 +18,21 @@ help: the strongly protected tag was created here, in the initial state Re | LL | fn inner(x: &mut i32, f: fn(*mut i32)) { | ^ -note: error occurred inside ` as std::ops::Drop>::drop` - --> RUSTLIB/alloc/src/boxed.rs:LL:CC - | -LL | fn drop(&mut self) { - | ^^^^^^^^^^^^^^^^^^ - = note: which got called inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` (at RUSTLIB/core/src/ptr/mod.rs:LL:CC) - = note: which got called inside `std::mem::drop::>` (at RUSTLIB/core/src/mem/mod.rs:LL:CC) -note: which got called inside closure - --> tests/fail/tree_borrows/strongly-protected.rs:LL:CC - | -LL | drop(unsafe { Box::from_raw(raw) }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: which got called inside `<{closure@tests/fail/tree_borrows/strongly-protected.rs:LL:CC} as std::ops::FnOnce<(*mut i32,)>>::call_once - shim` (at RUSTLIB/core/src/ops/function.rs:LL:CC) -note: which got called inside `inner` - --> tests/fail/tree_borrows/strongly-protected.rs:LL:CC - | -LL | f(x) - | ^^^^ -note: which got called inside `main` - --> tests/fail/tree_borrows/strongly-protected.rs:LL:CC - | -LL | / inner(Box::leak(Box::new(0)), |raw| { -LL | | drop(unsafe { Box::from_raw(raw) }); -LL | | }); - | |______^ + = note: stack backtrace: + 0: as std::ops::Drop>::drop + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 1: std::ptr::drop_in_place)) + at RUSTLIB/core/src/ptr/mod.rs:LL:CC + 2: std::mem::drop + at RUSTLIB/core/src/mem/mod.rs:LL:CC + 3: main::{closure#0} + at tests/fail/tree_borrows/strongly-protected.rs:LL:CC + 4: <{closure@tests/fail/tree_borrows/strongly-protected.rs:LL:CC} as std::ops::FnOnce<(*mut i32,)>>::call_once - shim + at RUSTLIB/core/src/ops/function.rs:LL:CC + 5: inner + at tests/fail/tree_borrows/strongly-protected.rs:LL:CC + 6: main + at tests/fail/tree_borrows/strongly-protected.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.stderr b/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.stderr index 3db6dab3167b..c27db19cd3e9 100644 --- a/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.stderr @@ -18,16 +18,11 @@ help: the conflicting tag was created here, in the initial state Frozen | LL | let intermediary = &root; | ^^^^^ -note: error occurred inside `write_to_mut` - --> tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs:LL:CC - | -LL | fn write_to_mut(m: &mut u8, other_ptr: *const u8) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs:LL:CC - | -LL | write_to_mut(data, core::ptr::addr_of!(root)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: write_to_mut + at tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs:LL:CC + 1: main + at tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/wildcard/protected_wildcard.stderr b/src/tools/miri/tests/fail/tree_borrows/wildcard/protected_wildcard.stderr index d61fe47a871b..28deb09664c7 100644 --- a/src/tools/miri/tests/fail/tree_borrows/wildcard/protected_wildcard.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/protected_wildcard.stderr @@ -23,16 +23,11 @@ help: the protected tag was created here, in the initial state Reserved | LL | let mut protect = |_arg: &mut u32| { | ^^^^ -note: error occurred inside closure - --> tests/fail/tree_borrows/wildcard/protected_wildcard.rs:LL:CC - | -LL | let mut protect = |_arg: &mut u32| { - | ^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/tree_borrows/wildcard/protected_wildcard.rs:LL:CC - | -LL | protect(wild_ref); - | ^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: main::{closure#0} + at tests/fail/tree_borrows/wildcard/protected_wildcard.rs:LL:CC + 1: main + at tests/fail/tree_borrows/wildcard/protected_wildcard.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/wildcard/protector_conflicted.stderr b/src/tools/miri/tests/fail/tree_borrows/wildcard/protector_conflicted.stderr index cd797cdc0c79..dce29e63583e 100644 --- a/src/tools/miri/tests/fail/tree_borrows/wildcard/protector_conflicted.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/protector_conflicted.stderr @@ -7,12 +7,11 @@ LL | unsafe { *wild = 4 }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: there are no exposed tags which may perform this access here - = note: this is inside closure -note: which got called inside `main` - --> tests/fail/tree_borrows/wildcard/protector_conflicted.rs:LL:CC - | -LL | protect(ref1); - | ^^^^^^^^^^^^^ + = note: stack backtrace: + 0: main::{closure#0} + at tests/fail/tree_borrows/wildcard/protector_conflicted.rs:LL:CC + 1: main + at tests/fail/tree_borrows/wildcard/protector_conflicted.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/wildcard/strongly_protected_wildcard.stderr b/src/tools/miri/tests/fail/tree_borrows/wildcard/strongly_protected_wildcard.stderr index bcc6b5f5b879..89d1f8ca556d 100644 --- a/src/tools/miri/tests/fail/tree_borrows/wildcard/strongly_protected_wildcard.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/strongly_protected_wildcard.stderr @@ -18,31 +18,21 @@ help: the strongly protected tag was created here, in the initial state Re | LL | fn inner(x: &mut i32, f: fn(usize)) { | ^ -note: error occurred inside ` as std::ops::Drop>::drop` - --> RUSTLIB/alloc/src/boxed.rs:LL:CC - | -LL | fn drop(&mut self) { - | ^^^^^^^^^^^^^^^^^^ - = note: which got called inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` (at RUSTLIB/core/src/ptr/mod.rs:LL:CC) - = note: which got called inside `std::mem::drop::>` (at RUSTLIB/core/src/mem/mod.rs:LL:CC) -note: which got called inside closure - --> tests/fail/tree_borrows/wildcard/strongly_protected_wildcard.rs:LL:CC - | -LL | drop(unsafe { Box::from_raw(raw as *mut i32) }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: which got called inside `<{closure@tests/fail/tree_borrows/wildcard/strongly_protected_wildcard.rs:LL:CC} as std::ops::FnOnce<(usize,)>>::call_once - shim` (at RUSTLIB/core/src/ops/function.rs:LL:CC) -note: which got called inside `inner` - --> tests/fail/tree_borrows/wildcard/strongly_protected_wildcard.rs:LL:CC - | -LL | f(x as *mut i32 as usize) - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/tree_borrows/wildcard/strongly_protected_wildcard.rs:LL:CC - | -LL | / inner(Box::leak(Box::new(0)), |raw| { -LL | | drop(unsafe { Box::from_raw(raw as *mut i32) }); -LL | | }); - | |______^ + = note: stack backtrace: + 0: as std::ops::Drop>::drop + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 1: std::ptr::drop_in_place)) + at RUSTLIB/core/src/ptr/mod.rs:LL:CC + 2: std::mem::drop + at RUSTLIB/core/src/mem/mod.rs:LL:CC + 3: main::{closure#0} + at tests/fail/tree_borrows/wildcard/strongly_protected_wildcard.rs:LL:CC + 4: <{closure@tests/fail/tree_borrows/wildcard/strongly_protected_wildcard.rs:LL:CC} as std::ops::FnOnce<(usize,)>>::call_once - shim + at RUSTLIB/core/src/ops/function.rs:LL:CC + 5: inner + at tests/fail/tree_borrows/wildcard/strongly_protected_wildcard.rs:LL:CC + 6: main + at tests/fail/tree_borrows/wildcard/strongly_protected_wildcard.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/tree_borrows/write-during-2phase.stderr b/src/tools/miri/tests/fail/tree_borrows/write-during-2phase.stderr index 11d148bc872e..e44f306f7fad 100644 --- a/src/tools/miri/tests/fail/tree_borrows/write-during-2phase.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/write-during-2phase.stderr @@ -18,22 +18,11 @@ help: the accessed tag later transitioned to Disabled due to a foreign wri LL | *alias = 42; | ^^^^^^^^^^^ = help: this transition corresponds to a loss of read and write permissions -note: error occurred inside `Foo::add` - --> tests/fail/tree_borrows/write-during-2phase.rs:LL:CC - | -LL | fn add(&mut self, n: u64) -> u64 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside `main` - --> tests/fail/tree_borrows/write-during-2phase.rs:LL:CC - | -LL | let res = f.add(unsafe { - | _______________^ -LL | | // This is the access at fault, but it's not immediately apparent because -LL | | // the reference that got invalidated is not under a Protector. -LL | | *alias = 42; -LL | | 0 -LL | | }); - | |______^ + = note: stack backtrace: + 0: Foo::add + at tests/fail/tree_borrows/write-during-2phase.rs:LL:CC + 1: main + at tests/fail/tree_borrows/write-during-2phase.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr b/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr index 6fb62b766440..2b98a2f99cf9 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr @@ -8,12 +8,11 @@ LL | | T: [const] Destruct, | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `std::ptr::drop_in_place:: - shim(Some(PartialDrop))` -note: which got called inside `main` - --> tests/fail/unaligned_pointers/drop_in_place.rs:LL:CC - | -LL | core::ptr::drop_in_place(p); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: std::ptr::drop_in_place - shim(Some(PartialDrop)) + at RUSTLIB/core/src/ptr/mod.rs:LL:CC + 1: main + at tests/fail/unaligned_pointers/drop_in_place.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.stderr b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.stderr index 61915490917e..ed5c724a2e2b 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.stderr @@ -6,12 +6,11 @@ LL | unsafe { (*x).x } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `foo` -note: which got called inside `main` - --> tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.rs:LL:CC - | -LL | foo(odd_ptr.cast()); - | ^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: foo + at tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.rs:LL:CC + 1: main + at tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.stderr b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.stderr index 58db5dda6a2e..bd44ed1224ec 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.stderr @@ -6,12 +6,11 @@ LL | unsafe { (*x).packed.x } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `foo` -note: which got called inside `main` - --> tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.rs:LL:CC - | -LL | foo(odd_ptr.cast()); - | ^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: foo + at tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.rs:LL:CC + 1: main + at tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.stderr b/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.stderr index 56a3bf129ab2..2f3079383d12 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.stderr @@ -6,12 +6,11 @@ LL | mem::transmute(x) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `raw_to_ref::<'_, i32>` -note: which got called inside `main` - --> tests/fail/unaligned_pointers/reference_to_packed.rs:LL:CC - | -LL | let p: &i32 = unsafe { raw_to_ref(ptr::addr_of!(foo.x)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: raw_to_ref + at tests/fail/unaligned_pointers/reference_to_packed.rs:LL:CC + 1: main + at tests/fail/unaligned_pointers/reference_to_packed.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.stderr b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.stderr index 6a2f038017c0..e0caff6a21a9 100644 --- a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.stderr +++ b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.stderr @@ -6,13 +6,13 @@ LL | let mut order = unsafe { compare_bytes(left, right, len) as isize } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `::compare` - = note: which got called inside `core::slice::cmp::::cmp` (at RUSTLIB/core/src/slice/cmp.rs:LL:CC) -note: which got called inside `main` - --> tests/fail/uninit/uninit_alloc_diagnostic.rs:LL:CC - | -LL | drop(slice1.cmp(slice2)); - | ^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: ::compare + at RUSTLIB/core/src/slice/cmp.rs:LL:CC + 1: core::slice::cmp::cmp + at RUSTLIB/core/src/slice/cmp.rs:LL:CC + 2: main + at tests/fail/uninit/uninit_alloc_diagnostic.rs:LL:CC Uninitialized memory occurred at ALLOC[0x4..0x10], in this allocation: ALLOC (Rust heap, size: 32, align: 8) { diff --git a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr index f40e796cca61..efad61c14fb8 100644 --- a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr +++ b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr @@ -6,13 +6,13 @@ LL | let mut order = unsafe { compare_bytes(left, right, len) as isize } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `::compare` - = note: which got called inside `core::slice::cmp::::cmp` (at RUSTLIB/core/src/slice/cmp.rs:LL:CC) -note: which got called inside `main` - --> tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.rs:LL:CC - | -LL | drop(slice1.cmp(slice2)); - | ^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: ::compare + at RUSTLIB/core/src/slice/cmp.rs:LL:CC + 1: core::slice::cmp::cmp + at RUSTLIB/core/src/slice/cmp.rs:LL:CC + 2: main + at tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.rs:LL:CC Uninitialized memory occurred at ALLOC[0x4..0x8], in this allocation: ALLOC (Rust heap, size: 16, align: 8) { diff --git a/src/tools/miri/tests/fail/unwind-action-terminate.stderr b/src/tools/miri/tests/fail/unwind-action-terminate.stderr index c86d94a82025..2295d80f45e8 100644 --- a/src/tools/miri/tests/fail/unwind-action-terminate.stderr +++ b/src/tools/miri/tests/fail/unwind-action-terminate.stderr @@ -14,24 +14,7 @@ error: abnormal termination: the program aborted execution LL | crate::process::abort(); | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | - = note: this is inside `std::panicking::panic_with_hook` - = note: which got called inside closure (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` (at RUSTLIB/std/src/sys/backtrace.rs:LL:CC) - = note: which got called inside `std::panicking::panic_handler` (at RUSTLIB/std/src/panicking.rs:LL:CC) - = note: which got called inside `core::panicking::panic_nounwind` (at RUSTLIB/core/src/panicking.rs:LL:CC) - = note: which got called inside `core::panicking::panic_cannot_unwind` (at RUSTLIB/core/src/panicking.rs:LL:CC) -note: which got called inside `panic_abort` - --> tests/fail/unwind-action-terminate.rs:LL:CC - | -LL | / extern "C" fn panic_abort() { -LL | | panic!() -LL | | } - | |_^ -note: which got called inside `main` - --> tests/fail/unwind-action-terminate.rs:LL:CC - | -LL | panic_abort(); - | ^^^^^^^^^^^^^ + = note: stack backtrace: note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr index 5c7572c76a13..c2e647aa18fc 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr @@ -6,12 +6,11 @@ LL | Call(_res = f(*ptr), ReturnTo(retblock), UnwindContinue()) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `call` -note: which got called inside `main` - --> tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs:LL:CC - | -LL | call(f); - | ^^^^^^^ + = note: stack backtrace: + 0: call + at tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs:LL:CC + 1: main + at tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/invalid_char_cast.stderr b/src/tools/miri/tests/fail/validity/invalid_char_cast.stderr index 6612bcd22394..ecccf204cf81 100644 --- a/src/tools/miri/tests/fail/validity/invalid_char_cast.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_char_cast.stderr @@ -6,12 +6,11 @@ LL | RET = *ptr as u32; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `cast` -note: which got called inside `main` - --> tests/fail/validity/invalid_char_cast.rs:LL:CC - | -LL | cast(&v as *const u32 as *const char); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: cast + at tests/fail/validity/invalid_char_cast.rs:LL:CC + 1: main + at tests/fail/validity/invalid_char_cast.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/invalid_char_match.stderr b/src/tools/miri/tests/fail/validity/invalid_char_match.stderr index cda730172177..818b2e26f869 100644 --- a/src/tools/miri/tests/fail/validity/invalid_char_match.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_char_match.stderr @@ -9,12 +9,11 @@ LL | | } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `switch_int` -note: which got called inside `main` - --> tests/fail/validity/invalid_char_match.rs:LL:CC - | -LL | switch_int(&v as *const u32 as *const char); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: switch_int + at tests/fail/validity/invalid_char_match.rs:LL:CC + 1: main + at tests/fail/validity/invalid_char_match.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/invalid_enum_cast.stderr b/src/tools/miri/tests/fail/validity/invalid_enum_cast.stderr index 6a4d0e0375af..a02dc678f018 100644 --- a/src/tools/miri/tests/fail/validity/invalid_enum_cast.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_enum_cast.stderr @@ -6,12 +6,11 @@ LL | let _val = *ptr as u32; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `cast` -note: which got called inside `main` - --> tests/fail/validity/invalid_enum_cast.rs:LL:CC - | -LL | cast(&v as *const u32 as *const E); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: cast + at tests/fail/validity/invalid_enum_cast.rs:LL:CC + 1: main + at tests/fail/validity/invalid_enum_cast.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/weak_memory/weak_uninit.stderr b/src/tools/miri/tests/fail/weak_memory/weak_uninit.stderr index 9f3792e0e409..d2d6da49fc1e 100644 --- a/src/tools/miri/tests/fail/weak_memory/weak_uninit.stderr +++ b/src/tools/miri/tests/fail/weak_memory/weak_uninit.stderr @@ -6,8 +6,8 @@ LL | let j2 = spawn(move || x.load(Ordering::Relaxed)); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/fail/weak_memory/weak_uninit.rs:LL:CC | LL | let j2 = spawn(move || x.load(Ordering::Relaxed)); diff --git a/src/tools/miri/tests/genmc/fail/atomics/atomic_ptr_double_free.stderr b/src/tools/miri/tests/genmc/fail/atomics/atomic_ptr_double_free.stderr index 85e2810f1f30..2ba64ac032a8 100644 --- a/src/tools/miri/tests/genmc/fail/atomics/atomic_ptr_double_free.stderr +++ b/src/tools/miri/tests/genmc/fail/atomics/atomic_ptr_double_free.stderr @@ -17,23 +17,17 @@ help: ALLOC was deallocated here: | LL | dealloc(ptr as *mut u8, Layout::new::()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: error occurred on thread `unnamed-ID`, inside `free` - --> tests/genmc/fail/atomics/atomic_ptr_double_free.rs:LL:CC - | -LL | unsafe fn free(ptr: *mut u64) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: which got called inside closure - --> tests/genmc/fail/atomics/atomic_ptr_double_free.rs:LL:CC - | -LL | free(b); - | ^^^^^^^ - = note: which got called inside ` as std::ops::FnOnce<()>>::call_once` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) -note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/atomics/atomic_ptr_double_free.rs:LL:CC}>` - --> tests/genmc/fail/atomics/../../../utils/genmc.rs:LL:CC - | -LL | f(); - | ^^^ -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` + = note: stack backtrace: + 0: free + at tests/genmc/fail/atomics/atomic_ptr_double_free.rs:LL:CC + 1: miri_start::{closure#1} + at tests/genmc/fail/atomics/atomic_ptr_double_free.rs:LL:CC + 2: as std::ops::FnOnce<()>>::call_once + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 3: genmc::spawn_pthread_closure::thread_func + at tests/genmc/fail/atomics/../../../utils/genmc.rs:LL:CC +note: the last function in that backtrace got called indirectly due to this code --> tests/genmc/fail/atomics/../../../utils/genmc.rs:LL:CC | LL | / libc::pthread_create( diff --git a/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_alloc_race.dealloc.stderr b/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_alloc_race.dealloc.stderr index 4bca53961f5f..7534eaf8f37e 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_alloc_race.dealloc.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_alloc_race.dealloc.stderr @@ -7,14 +7,15 @@ LL | dealloc(b as *mut u8, Layout::new::()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure - = note: which got called inside ` as std::ops::FnOnce<()>>::call_once` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) -note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/atomic_ptr_alloc_race.rs:LL:CC}>` - --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC - | -LL | f(); - | ^^^ -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` + = note: stack backtrace: + 0: miri_start::{closure#1} + at tests/genmc/fail/data_race/atomic_ptr_alloc_race.rs:LL:CC + 1: as std::ops::FnOnce<()>>::call_once + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 2: genmc::spawn_pthread_closure::thread_func + at tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC +note: the last function in that backtrace got called indirectly due to this code --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC | LL | / libc::pthread_create( diff --git a/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_alloc_race.write.stderr b/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_alloc_race.write.stderr index 0a03363285b6..77e9817a55c7 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_alloc_race.write.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_alloc_race.write.stderr @@ -7,14 +7,15 @@ LL | *b = 42; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure - = note: which got called inside ` as std::ops::FnOnce<()>>::call_once` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) -note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/atomic_ptr_alloc_race.rs:LL:CC}>` - --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC - | -LL | f(); - | ^^^ -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` + = note: stack backtrace: + 0: miri_start::{closure#1} + at tests/genmc/fail/data_race/atomic_ptr_alloc_race.rs:LL:CC + 1: as std::ops::FnOnce<()>>::call_once + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 2: genmc::spawn_pthread_closure::thread_func + at tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC +note: the last function in that backtrace got called indirectly due to this code --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC | LL | / libc::pthread_create( diff --git a/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_dealloc_write_race.stderr b/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_dealloc_write_race.stderr index 29a2e371bb3c..47df94404efa 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_dealloc_write_race.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_dealloc_write_race.stderr @@ -17,18 +17,15 @@ help: ALLOC was deallocated here: | LL | }), | ^ -note: error occurred on thread `unnamed-ID`, inside closure - --> tests/genmc/fail/data_race/atomic_ptr_dealloc_write_race.rs:LL:CC - | -LL | spawn_pthread_closure(|| { - | ^^ - = note: which got called inside ` as std::ops::FnOnce<()>>::call_once` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) -note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/atomic_ptr_dealloc_write_race.rs:LL:CC}>` - --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC - | -LL | f(); - | ^^^ -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` + = note: stack backtrace: + 0: miri_start::{closure#1} + at tests/genmc/fail/data_race/atomic_ptr_dealloc_write_race.rs:LL:CC + 1: as std::ops::FnOnce<()>>::call_once + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 2: genmc::spawn_pthread_closure::thread_func + at tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC +note: the last function in that backtrace got called indirectly due to this code --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC | LL | / libc::pthread_create( diff --git a/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_write_dealloc_race.stderr b/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_write_dealloc_race.stderr index 3f5d0bdf346e..e2c87b2d25e1 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_write_dealloc_race.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/atomic_ptr_write_dealloc_race.stderr @@ -7,14 +7,15 @@ LL | }), | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure - = note: which got called inside ` as std::ops::FnOnce<()>>::call_once` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) -note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/atomic_ptr_write_dealloc_race.rs:LL:CC}>` - --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC - | -LL | f(); - | ^^^ -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` + = note: stack backtrace: + 0: miri_start::{closure#1} + at tests/genmc/fail/data_race/atomic_ptr_write_dealloc_race.rs:LL:CC + 1: as std::ops::FnOnce<()>>::call_once + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 2: genmc::spawn_pthread_closure::thread_func + at tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC +note: the last function in that backtrace got called indirectly due to this code --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC | LL | / libc::pthread_create( diff --git a/src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.stderr b/src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.stderr index 48b8a16c8b10..a3a15a71ce15 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/mpu2_rels_rlx.stderr @@ -7,14 +7,15 @@ LL | X = 2; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure - = note: which got called inside ` as std::ops::FnOnce<()>>::call_once` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) -note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/mpu2_rels_rlx.rs:LL:CC}>` - --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC - | -LL | f(); - | ^^^ -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` + = note: stack backtrace: + 0: miri_start::{closure#1} + at tests/genmc/fail/data_race/mpu2_rels_rlx.rs:LL:CC + 1: as std::ops::FnOnce<()>>::call_once + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 2: genmc::spawn_pthread_closure::thread_func + at tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC +note: the last function in that backtrace got called indirectly due to this code --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC | LL | / libc::pthread_create( diff --git a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rel_rlx.stderr b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rel_rlx.stderr index 2eb3791aaf08..1220c0c09cbe 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rel_rlx.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rel_rlx.stderr @@ -7,14 +7,15 @@ LL | X = 2; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure - = note: which got called inside ` as std::ops::FnOnce<()>>::call_once` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) -note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/weak_orderings.rs:LL:CC}>` - --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC - | -LL | f(); - | ^^^ -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` + = note: stack backtrace: + 0: miri_start::{closure#1} + at tests/genmc/fail/data_race/weak_orderings.rs:LL:CC + 1: as std::ops::FnOnce<()>>::call_once + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 2: genmc::spawn_pthread_closure::thread_func + at tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC +note: the last function in that backtrace got called indirectly due to this code --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC | LL | / libc::pthread_create( diff --git a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_acq.stderr b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_acq.stderr index 2eb3791aaf08..1220c0c09cbe 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_acq.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_acq.stderr @@ -7,14 +7,15 @@ LL | X = 2; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure - = note: which got called inside ` as std::ops::FnOnce<()>>::call_once` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) -note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/weak_orderings.rs:LL:CC}>` - --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC - | -LL | f(); - | ^^^ -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` + = note: stack backtrace: + 0: miri_start::{closure#1} + at tests/genmc/fail/data_race/weak_orderings.rs:LL:CC + 1: as std::ops::FnOnce<()>>::call_once + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 2: genmc::spawn_pthread_closure::thread_func + at tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC +note: the last function in that backtrace got called indirectly due to this code --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC | LL | / libc::pthread_create( diff --git a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_rlx.stderr b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_rlx.stderr index 2eb3791aaf08..1220c0c09cbe 100644 --- a/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_rlx.stderr +++ b/src/tools/miri/tests/genmc/fail/data_race/weak_orderings.rlx_rlx.stderr @@ -7,14 +7,15 @@ LL | X = 2; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure - = note: which got called inside ` as std::ops::FnOnce<()>>::call_once` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) -note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/fail/data_race/weak_orderings.rs:LL:CC}>` - --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC - | -LL | f(); - | ^^^ -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` + = note: stack backtrace: + 0: miri_start::{closure#1} + at tests/genmc/fail/data_race/weak_orderings.rs:LL:CC + 1: as std::ops::FnOnce<()>>::call_once + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 2: genmc::spawn_pthread_closure::thread_func + at tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC +note: the last function in that backtrace got called indirectly due to this code --> tests/genmc/fail/data_race/../../../utils/genmc.rs:LL:CC | LL | / libc::pthread_create( diff --git a/src/tools/miri/tests/genmc/fail/shims/exit.stderr b/src/tools/miri/tests/genmc/fail/shims/exit.stderr index 573c8b14fae3..c0d0321defe1 100644 --- a/src/tools/miri/tests/genmc/fail/shims/exit.stderr +++ b/src/tools/miri/tests/genmc/fail/shims/exit.stderr @@ -7,8 +7,8 @@ LL | unsafe { std::hint::unreachable_unchecked() }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside closure -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` +note: the current function got called indirectly due to this code --> tests/genmc/fail/shims/exit.rs:LL:CC | LL | / std::thread::spawn(|| { diff --git a/src/tools/miri/tests/genmc/fail/shims/mutex_diff_thread_unlock.stderr b/src/tools/miri/tests/genmc/fail/shims/mutex_diff_thread_unlock.stderr index e32548c4b5d5..272a52ba7fef 100644 --- a/src/tools/miri/tests/genmc/fail/shims/mutex_diff_thread_unlock.stderr +++ b/src/tools/miri/tests/genmc/fail/shims/mutex_diff_thread_unlock.stderr @@ -7,16 +7,19 @@ LL | self.lock.inner.unlock(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is on thread `unnamed-ID`, inside ` as std::ops::Drop>::drop` - = note: which got called inside `std::ptr::drop_in_place::> - shim(Some(std::sync::MutexGuard<'_, u64>))` (at RUSTLIB/core/src/ptr/mod.rs:LL:CC) - = note: which got called inside `std::ptr::drop_in_place::>> - shim(Some(EvilSend>))` (at RUSTLIB/core/src/ptr/mod.rs:LL:CC) - = note: which got called inside `std::mem::drop::>>` (at RUSTLIB/core/src/mem/mod.rs:LL:CC) -note: which got called inside closure - --> tests/genmc/fail/shims/mutex_diff_thread_unlock.rs:LL:CC - | -LL | drop(guard); - | ^^^^^^^^^^^ -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` + = note: stack backtrace: + 0: as std::ops::Drop>::drop + at RUSTLIB/std/src/sync/poison/mutex.rs:LL:CC + 1: std::ptr::drop_in_place)) + at RUSTLIB/core/src/ptr/mod.rs:LL:CC + 2: std::ptr::drop_in_place)) + at RUSTLIB/core/src/ptr/mod.rs:LL:CC + 3: std::mem::drop + at RUSTLIB/core/src/mem/mod.rs:LL:CC + 4: miri_start::{closure#0} + at tests/genmc/fail/shims/mutex_diff_thread_unlock.rs:LL:CC +note: the last function in that backtrace got called indirectly due to this code --> tests/genmc/fail/shims/mutex_diff_thread_unlock.rs:LL:CC | LL | let handle = std::thread::spawn(move || { diff --git a/src/tools/miri/tests/genmc/fail/shims/mutex_double_unlock.stderr b/src/tools/miri/tests/genmc/fail/shims/mutex_double_unlock.stderr index 9fec95ae6770..d668706f7647 100644 --- a/src/tools/miri/tests/genmc/fail/shims/mutex_double_unlock.stderr +++ b/src/tools/miri/tests/genmc/fail/shims/mutex_double_unlock.stderr @@ -7,14 +7,15 @@ LL | self.lock.inner.unlock(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside ` as std::ops::Drop>::drop` - = note: which got called inside `std::ptr::drop_in_place::> - shim(Some(std::sync::MutexGuard<'_, u64>))` (at RUSTLIB/core/src/ptr/mod.rs:LL:CC) - = note: which got called inside `std::mem::drop::>` (at RUSTLIB/core/src/mem/mod.rs:LL:CC) -note: which got called inside `miri_start` - --> tests/genmc/fail/shims/mutex_double_unlock.rs:LL:CC - | -LL | drop(guard); - | ^^^^^^^^^^^ + = note: stack backtrace: + 0: as std::ops::Drop>::drop + at RUSTLIB/std/src/sync/poison/mutex.rs:LL:CC + 1: std::ptr::drop_in_place)) + at RUSTLIB/core/src/ptr/mod.rs:LL:CC + 2: std::mem::drop + at RUSTLIB/core/src/mem/mod.rs:LL:CC + 3: miri_start + at tests/genmc/fail/shims/mutex_double_unlock.rs:LL:CC note: add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report diff --git a/src/tools/miri/tests/genmc/fail/simple/alloc_large.multiple.stderr b/src/tools/miri/tests/genmc/fail/simple/alloc_large.multiple.stderr index 2fc6e3d47229..5ddcce1fa30c 100644 --- a/src/tools/miri/tests/genmc/fail/simple/alloc_large.multiple.stderr +++ b/src/tools/miri/tests/genmc/fail/simple/alloc_large.multiple.stderr @@ -6,16 +6,19 @@ LL | AllocInit::Uninitialized => alloc.allocate(layout), | ^^^^^^^^^^^^^^^^^^^^^^ resource exhaustion occurred here | = help: in GenMC mode, the address space is limited to 4GB per thread, and addresses cannot be reused - = note: this is inside `alloc::raw_vec::RawVecInner::try_allocate_in` - = note: which got called inside `alloc::raw_vec::RawVecInner::with_capacity_in` (at RUSTLIB/alloc/src/raw_vec/mod.rs:LL:CC) - = note: which got called inside `alloc::raw_vec::RawVec::::with_capacity_in` (at RUSTLIB/alloc/src/raw_vec/mod.rs:LL:CC) - = note: which got called inside `std::vec::Vec::::with_capacity_in` (at RUSTLIB/alloc/src/vec/mod.rs:LL:CC) - = note: which got called inside `std::vec::Vec::::with_capacity` (at RUSTLIB/alloc/src/vec/mod.rs:LL:CC) -note: which got called inside `miri_start` - --> tests/genmc/fail/simple/alloc_large.rs:LL:CC - | -LL | let _v = Vec::::with_capacity(1024 * 1024 * 1024); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: alloc::raw_vec::RawVecInner::try_allocate_in + at RUSTLIB/alloc/src/raw_vec/mod.rs:LL:CC + 1: alloc::raw_vec::RawVecInner::with_capacity_in + at RUSTLIB/alloc/src/raw_vec/mod.rs:LL:CC + 2: alloc::raw_vec::RawVec::with_capacity_in + at RUSTLIB/alloc/src/raw_vec/mod.rs:LL:CC + 3: std::vec::Vec::with_capacity_in + at RUSTLIB/alloc/src/vec/mod.rs:LL:CC + 4: std::vec::Vec::with_capacity + at RUSTLIB/alloc/src/vec/mod.rs:LL:CC + 5: miri_start + at tests/genmc/fail/simple/alloc_large.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/genmc/fail/simple/alloc_large.single.stderr b/src/tools/miri/tests/genmc/fail/simple/alloc_large.single.stderr index dbd39e4727c2..5ddcce1fa30c 100644 --- a/src/tools/miri/tests/genmc/fail/simple/alloc_large.single.stderr +++ b/src/tools/miri/tests/genmc/fail/simple/alloc_large.single.stderr @@ -6,16 +6,19 @@ LL | AllocInit::Uninitialized => alloc.allocate(layout), | ^^^^^^^^^^^^^^^^^^^^^^ resource exhaustion occurred here | = help: in GenMC mode, the address space is limited to 4GB per thread, and addresses cannot be reused - = note: this is inside `alloc::raw_vec::RawVecInner::try_allocate_in` - = note: which got called inside `alloc::raw_vec::RawVecInner::with_capacity_in` (at RUSTLIB/alloc/src/raw_vec/mod.rs:LL:CC) - = note: which got called inside `alloc::raw_vec::RawVec::::with_capacity_in` (at RUSTLIB/alloc/src/raw_vec/mod.rs:LL:CC) - = note: which got called inside `std::vec::Vec::::with_capacity_in` (at RUSTLIB/alloc/src/vec/mod.rs:LL:CC) - = note: which got called inside `std::vec::Vec::::with_capacity` (at RUSTLIB/alloc/src/vec/mod.rs:LL:CC) -note: which got called inside `miri_start` - --> tests/genmc/fail/simple/alloc_large.rs:LL:CC - | -LL | let _v = Vec::::with_capacity(8 * 1024 * 1024 * 1024); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: alloc::raw_vec::RawVecInner::try_allocate_in + at RUSTLIB/alloc/src/raw_vec/mod.rs:LL:CC + 1: alloc::raw_vec::RawVecInner::with_capacity_in + at RUSTLIB/alloc/src/raw_vec/mod.rs:LL:CC + 2: alloc::raw_vec::RawVec::with_capacity_in + at RUSTLIB/alloc/src/raw_vec/mod.rs:LL:CC + 3: std::vec::Vec::with_capacity_in + at RUSTLIB/alloc/src/vec/mod.rs:LL:CC + 4: std::vec::Vec::with_capacity + at RUSTLIB/alloc/src/vec/mod.rs:LL:CC + 5: miri_start + at tests/genmc/fail/simple/alloc_large.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.stderr b/src/tools/miri/tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.stderr index 6d597aaa6342..24bde07924d1 100644 --- a/src/tools/miri/tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.stderr +++ b/src/tools/miri/tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.stderr @@ -5,19 +5,17 @@ warning: GenMC currently does not model the failure ordering for `compare_exchan LL | match KEY.compare_exchange(KEY_SENTVAL, key, Release, Acquire) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code | - = note: this is on thread `unnamed-ID`, inside `get_or_init` -note: which got called inside closure - --> tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.rs:LL:CC - | -LL | let key = get_or_init(0); - | ^^^^^^^^^^^^^^ - = note: which got called inside ` as std::ops::FnOnce<()>>::call_once` (at RUSTLIB/alloc/src/boxed.rs:LL:CC) -note: which got called inside `genmc::spawn_pthread_closure::thread_func::<{closure@tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.rs:LL:CC}>` - --> tests/genmc/pass/atomics/../../../utils/genmc.rs:LL:CC - | -LL | f(); - | ^^^ -note: which got called indirectly due to this code + = note: this is on thread `unnamed-ID` + = note: stack backtrace: + 0: get_or_init + at tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.rs:LL:CC + 1: miri_start::{closure#0} + at tests/genmc/pass/atomics/cas_failure_ord_racy_key_init.rs:LL:CC + 2: as std::ops::FnOnce<()>>::call_once + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 3: genmc::spawn_pthread_closure::thread_func + at tests/genmc/pass/atomics/../../../utils/genmc.rs:LL:CC +note: the last function in that backtrace got called indirectly due to this code --> tests/genmc/pass/atomics/../../../utils/genmc.rs:LL:CC | LL | / libc::pthread_create( diff --git a/src/tools/miri/tests/native-lib/fail/tracing/partial_init.stderr b/src/tools/miri/tests/native-lib/fail/tracing/partial_init.stderr index 4a7d24090641..032461b6ed3f 100644 --- a/src/tools/miri/tests/native-lib/fail/tracing/partial_init.stderr +++ b/src/tools/miri/tests/native-lib/fail/tracing/partial_init.stderr @@ -9,12 +9,11 @@ LL | init_n(2, slice_ptr); = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free = help: tracing memory accesses in native code is not yet fully implemented, so there can be further imprecisions beyond what is documented here - = note: this is inside `partial_init` -note: which got called inside `main` - --> tests/native-lib/fail/tracing/partial_init.rs:LL:CC - | -LL | partial_init(); - | ^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: partial_init + at tests/native-lib/fail/tracing/partial_init.rs:LL:CC + 1: main + at tests/native-lib/fail/tracing/partial_init.rs:LL:CC error: Undefined Behavior: reading memory at ALLOC[0x2..0x3], but memory is uninitialized at [0x2..0x3], and this operation requires initialized memory --> tests/native-lib/fail/tracing/partial_init.rs:LL:CC @@ -24,12 +23,11 @@ LL | let _val = *slice_ptr.offset(2); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `partial_init` -note: which got called inside `main` - --> tests/native-lib/fail/tracing/partial_init.rs:LL:CC - | -LL | partial_init(); - | ^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: partial_init + at tests/native-lib/fail/tracing/partial_init.rs:LL:CC + 1: main + at tests/native-lib/fail/tracing/partial_init.rs:LL:CC Uninitialized memory occurred at ALLOC[0x2..0x3], in this allocation: ALLOC (stack variable, size: 3, align: 1) { diff --git a/src/tools/miri/tests/native-lib/fail/tracing/unexposed_reachable_alloc.stderr b/src/tools/miri/tests/native-lib/fail/tracing/unexposed_reachable_alloc.stderr index 825c9666b749..773d2dd63c3e 100644 --- a/src/tools/miri/tests/native-lib/fail/tracing/unexposed_reachable_alloc.stderr +++ b/src/tools/miri/tests/native-lib/fail/tracing/unexposed_reachable_alloc.stderr @@ -9,12 +9,11 @@ LL | unsafe { do_one_deref(exposed) }; = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free = help: tracing memory accesses in native code is not yet fully implemented, so there can be further imprecisions beyond what is documented here - = note: this is inside `unexposed_reachable_alloc` -note: which got called inside `main` - --> tests/native-lib/fail/tracing/unexposed_reachable_alloc.rs:LL:CC - | -LL | unexposed_reachable_alloc(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: unexposed_reachable_alloc + at tests/native-lib/fail/tracing/unexposed_reachable_alloc.rs:LL:CC + 1: main + at tests/native-lib/fail/tracing/unexposed_reachable_alloc.rs:LL:CC error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> tests/native-lib/fail/tracing/unexposed_reachable_alloc.rs:LL:CC @@ -24,12 +23,11 @@ LL | let _not_ok = *invalid; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: this is inside `unexposed_reachable_alloc` -note: which got called inside `main` - --> tests/native-lib/fail/tracing/unexposed_reachable_alloc.rs:LL:CC - | -LL | unexposed_reachable_alloc(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: unexposed_reachable_alloc + at tests/native-lib/fail/tracing/unexposed_reachable_alloc.rs:LL:CC + 1: main + at tests/native-lib/fail/tracing/unexposed_reachable_alloc.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/native-lib/pass/ptr_read_access.notrace.stderr b/src/tools/miri/tests/native-lib/pass/ptr_read_access.notrace.stderr index cbccd8fb62f4..b6bbb4342b77 100644 --- a/src/tools/miri/tests/native-lib/pass/ptr_read_access.notrace.stderr +++ b/src/tools/miri/tests/native-lib/pass/ptr_read_access.notrace.stderr @@ -8,12 +8,11 @@ LL | unsafe { print_pointer(&x) }; = help: in particular, Miri assumes that the native call initializes all memory it has access to = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free - = note: this is inside `test_access_pointer` -note: which got called inside `main` - --> tests/native-lib/pass/ptr_read_access.rs:LL:CC - | -LL | test_access_pointer(); - | ^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: test_access_pointer + at tests/native-lib/pass/ptr_read_access.rs:LL:CC + 1: main + at tests/native-lib/pass/ptr_read_access.rs:LL:CC warning: sharing a function pointer with a native function called via FFI --> tests/native-lib/pass/ptr_read_access.rs:LL:CC @@ -22,10 +21,9 @@ LL | pass_fn_ptr(Some(nop)); // this one is not | ^^^^^^^^^^^^^^^^^^^^^^ sharing a function pointer with a native function | = help: calling Rust functions from C is not supported and will, in the best case, crash the program - = note: this is inside `pass_fn_ptr` -note: which got called inside `main` - --> tests/native-lib/pass/ptr_read_access.rs:LL:CC - | -LL | pass_fn_ptr(); - | ^^^^^^^^^^^^^ + = note: stack backtrace: + 0: pass_fn_ptr + at tests/native-lib/pass/ptr_read_access.rs:LL:CC + 1: main + at tests/native-lib/pass/ptr_read_access.rs:LL:CC diff --git a/src/tools/miri/tests/native-lib/pass/ptr_read_access.trace.stderr b/src/tools/miri/tests/native-lib/pass/ptr_read_access.trace.stderr index 2697fb6d4353..0d86ea066099 100644 --- a/src/tools/miri/tests/native-lib/pass/ptr_read_access.trace.stderr +++ b/src/tools/miri/tests/native-lib/pass/ptr_read_access.trace.stderr @@ -9,12 +9,11 @@ LL | unsafe { print_pointer(&x) }; = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free = help: tracing memory accesses in native code is not yet fully implemented, so there can be further imprecisions beyond what is documented here - = note: this is inside `test_access_pointer` -note: which got called inside `main` - --> tests/native-lib/pass/ptr_read_access.rs:LL:CC - | -LL | test_access_pointer(); - | ^^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: test_access_pointer + at tests/native-lib/pass/ptr_read_access.rs:LL:CC + 1: main + at tests/native-lib/pass/ptr_read_access.rs:LL:CC warning: sharing a function pointer with a native function called via FFI --> tests/native-lib/pass/ptr_read_access.rs:LL:CC @@ -23,10 +22,9 @@ LL | pass_fn_ptr(Some(nop)); // this one is not | ^^^^^^^^^^^^^^^^^^^^^^ sharing a function pointer with a native function | = help: calling Rust functions from C is not supported and will, in the best case, crash the program - = note: this is inside `pass_fn_ptr` -note: which got called inside `main` - --> tests/native-lib/pass/ptr_read_access.rs:LL:CC - | -LL | pass_fn_ptr(); - | ^^^^^^^^^^^^^ + = note: stack backtrace: + 0: pass_fn_ptr + at tests/native-lib/pass/ptr_read_access.rs:LL:CC + 1: main + at tests/native-lib/pass/ptr_read_access.rs:LL:CC diff --git a/src/tools/miri/tests/native-lib/pass/ptr_write_access.notrace.stderr b/src/tools/miri/tests/native-lib/pass/ptr_write_access.notrace.stderr index c7edaa373167..15b2bc6df63f 100644 --- a/src/tools/miri/tests/native-lib/pass/ptr_write_access.notrace.stderr +++ b/src/tools/miri/tests/native-lib/pass/ptr_write_access.notrace.stderr @@ -8,10 +8,9 @@ LL | unsafe { increment_int(&mut x) }; = help: in particular, Miri assumes that the native call initializes all memory it has access to = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free - = note: this is inside `test_increment_int` -note: which got called inside `main` - --> tests/native-lib/pass/ptr_write_access.rs:LL:CC - | -LL | test_increment_int(); - | ^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: test_increment_int + at tests/native-lib/pass/ptr_write_access.rs:LL:CC + 1: main + at tests/native-lib/pass/ptr_write_access.rs:LL:CC diff --git a/src/tools/miri/tests/native-lib/pass/ptr_write_access.trace.stderr b/src/tools/miri/tests/native-lib/pass/ptr_write_access.trace.stderr index dacde45e17a1..d12a25f84b37 100644 --- a/src/tools/miri/tests/native-lib/pass/ptr_write_access.trace.stderr +++ b/src/tools/miri/tests/native-lib/pass/ptr_write_access.trace.stderr @@ -9,10 +9,9 @@ LL | unsafe { increment_int(&mut x) }; = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free = help: tracing memory accesses in native code is not yet fully implemented, so there can be further imprecisions beyond what is documented here - = note: this is inside `test_increment_int` -note: which got called inside `main` - --> tests/native-lib/pass/ptr_write_access.rs:LL:CC - | -LL | test_increment_int(); - | ^^^^^^^^^^^^^^^^^^^^ + = note: stack backtrace: + 0: test_increment_int + at tests/native-lib/pass/ptr_write_access.rs:LL:CC + 1: main + at tests/native-lib/pass/ptr_write_access.rs:LL:CC diff --git a/src/tools/miri/tests/panic/panic1.stderr b/src/tools/miri/tests/panic/panic1.stderr index ff7e287b5a58..d709428f3115 100644 --- a/src/tools/miri/tests/panic/panic1.stderr +++ b/src/tools/miri/tests/panic/panic1.stderr @@ -3,11 +3,11 @@ thread 'main' ($TID) panicked at tests/panic/panic1.rs:LL:CC: panicking from libstd stack backtrace: 0: std::panicking::panic_handler - at RUSTLIB/std/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 1: std::rt::panic_fmt - at RUSTLIB/core/src/panicking.rs:LL:CC + at RUSTLIB/core/src/panicking.rs:LL:CC 2: main - at tests/panic/panic1.rs:LL:CC + at tests/panic/panic1.rs:LL:CC 3: >::call_once - shim(fn()) - at RUSTLIB/core/src/ops/function.rs:LL:CC + at RUSTLIB/core/src/ops/function.rs:LL:CC note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. diff --git a/src/tools/miri/tests/pass/alloc-access-tracking.stderr b/src/tools/miri/tests/pass/alloc-access-tracking.stderr index b5b1bc2a7bc2..5dfcd0180e4c 100644 --- a/src/tools/miri/tests/pass/alloc-access-tracking.stderr +++ b/src/tools/miri/tests/pass/alloc-access-tracking.stderr @@ -24,11 +24,11 @@ note: freed allocation ALLOC LL | self.1.deallocate(From::from(ptr.cast()), layout); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tracking was triggered here | - = note: this is inside `> as std::ops::Drop>::drop` - = note: which got called inside `std::ptr::drop_in_place::>> - shim(Some(std::boxed::Box>))` (at RUSTLIB/core/src/ptr/mod.rs:LL:CC) -note: which got called inside `main` - --> tests/pass/alloc-access-tracking.rs:LL:CC - | -LL | } - | ^ + = note: stack backtrace: + 0: > as std::ops::Drop>::drop + at RUSTLIB/alloc/src/boxed.rs:LL:CC + 1: std::ptr::drop_in_place)) + at RUSTLIB/core/src/ptr/mod.rs:LL:CC + 2: main + at tests/pass/alloc-access-tracking.rs:LL:CC diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr index 588bb85f35a4..b4ef3f76c20f 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr +++ b/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr @@ -1,28 +1,28 @@ 0: main - at tests/pass/backtrace/backtrace-global-alloc.rs:LL:CC + at tests/pass/backtrace/backtrace-global-alloc.rs:LL:CC 1: >::call_once - shim(fn()) - at RUSTLIB/core/src/ops/function.rs:LL:CC + at RUSTLIB/core/src/ops/function.rs:LL:CC 2: std::sys::backtrace::__rust_begin_short_backtrace - at RUSTLIB/std/src/sys/backtrace.rs:LL:CC + at RUSTLIB/std/src/sys/backtrace.rs:LL:CC 3: std::rt::lang_start::{closure#0} - at RUSTLIB/std/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC 4: std::ops::function::impls::call_once - at RUSTLIB/core/src/ops/function.rs:LL:CC + at RUSTLIB/core/src/ops/function.rs:LL:CC 5: std::panicking::catch_unwind::do_call - at RUSTLIB/std/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 6: std::panicking::catch_unwind - at RUSTLIB/std/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 7: std::panic::catch_unwind - at RUSTLIB/std/src/panic.rs:LL:CC + at RUSTLIB/std/src/panic.rs:LL:CC 8: std::rt::lang_start_internal::{closure#0} - at RUSTLIB/std/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC 9: std::panicking::catch_unwind::do_call - at RUSTLIB/std/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 10: std::panicking::catch_unwind - at RUSTLIB/std/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 11: std::panic::catch_unwind - at RUSTLIB/std/src/panic.rs:LL:CC + at RUSTLIB/std/src/panic.rs:LL:CC 12: std::rt::lang_start_internal - at RUSTLIB/std/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC 13: std::rt::lang_start - at RUSTLIB/std/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr index 9c952755957b..706eacc70fd8 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr +++ b/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr @@ -1,36 +1,36 @@ 0: func_d - at tests/pass/backtrace/backtrace-std.rs:LL:CC + at tests/pass/backtrace/backtrace-std.rs:LL:CC 1: func_c - at tests/pass/backtrace/backtrace-std.rs:LL:CC + at tests/pass/backtrace/backtrace-std.rs:LL:CC 2: func_b - at tests/pass/backtrace/backtrace-std.rs:LL:CC + at tests/pass/backtrace/backtrace-std.rs:LL:CC 3: func_a - at tests/pass/backtrace/backtrace-std.rs:LL:CC + at tests/pass/backtrace/backtrace-std.rs:LL:CC 4: main - at tests/pass/backtrace/backtrace-std.rs:LL:CC + at tests/pass/backtrace/backtrace-std.rs:LL:CC 5: >::call_once - shim(fn()) - at RUSTLIB/core/src/ops/function.rs:LL:CC + at RUSTLIB/core/src/ops/function.rs:LL:CC 6: std::sys::backtrace::__rust_begin_short_backtrace - at RUSTLIB/std/src/sys/backtrace.rs:LL:CC + at RUSTLIB/std/src/sys/backtrace.rs:LL:CC 7: std::rt::lang_start::{closure#0} - at RUSTLIB/std/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC 8: std::ops::function::impls::call_once - at RUSTLIB/core/src/ops/function.rs:LL:CC + at RUSTLIB/core/src/ops/function.rs:LL:CC 9: std::panicking::catch_unwind::do_call - at RUSTLIB/std/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 10: std::panicking::catch_unwind - at RUSTLIB/std/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 11: std::panic::catch_unwind - at RUSTLIB/std/src/panic.rs:LL:CC + at RUSTLIB/std/src/panic.rs:LL:CC 12: std::rt::lang_start_internal::{closure#0} - at RUSTLIB/std/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC 13: std::panicking::catch_unwind::do_call - at RUSTLIB/std/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 14: std::panicking::catch_unwind - at RUSTLIB/std/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 15: std::panic::catch_unwind - at RUSTLIB/std/src/panic.rs:LL:CC + at RUSTLIB/std/src/panic.rs:LL:CC 16: std::rt::lang_start_internal - at RUSTLIB/std/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC 17: std::rt::lang_start - at RUSTLIB/std/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs index 8a3ab658b669..70739eef2883 100644 --- a/src/tools/miri/tests/ui.rs +++ b/src/tools/miri/tests/ui.rs @@ -255,8 +255,6 @@ regexes! { "<[0-9]+=" => " "$1", - // erase whitespace that differs between platforms - r" +at (.*\.rs)" => " at $1", // erase generics in backtraces "([0-9]+: .*)::<.*>" => "$1", // erase long hexadecimals From 262426d5354b69c658faeb54a4642a4a8121a1e0 Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Tue, 30 Dec 2025 16:05:53 -0300 Subject: [PATCH 0109/1061] Avoid index check in char::to_lowercase and char::to_uppercase --- library/core/src/unicode/unicode_data.rs | 6 ++++-- src/tools/unicode-table-generator/src/case_mapping.rs | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/library/core/src/unicode/unicode_data.rs b/library/core/src/unicode/unicode_data.rs index 3c38b44224f8..429b60a68f43 100644 --- a/library/core/src/unicode/unicode_data.rs +++ b/library/core/src/unicode/unicode_data.rs @@ -767,7 +767,8 @@ pub mod conversions { LOWERCASE_TABLE .binary_search_by(|&(key, _)| key.cmp(&c)) .map(|i| { - let u = LOWERCASE_TABLE[i].1; + // SAFETY: i is the result of the binary search + let u = unsafe { LOWERCASE_TABLE.get_unchecked(i) }.1; char::from_u32(u).map(|c| [c, '\0', '\0']).unwrap_or_else(|| { // SAFETY: Index comes from statically generated table unsafe { *LOWERCASE_TABLE_MULTI.get_unchecked((u & (INDEX_MASK - 1)) as usize) } @@ -784,7 +785,8 @@ pub mod conversions { UPPERCASE_TABLE .binary_search_by(|&(key, _)| key.cmp(&c)) .map(|i| { - let u = UPPERCASE_TABLE[i].1; + // SAFETY: i is the result of the binary search + let u = unsafe { UPPERCASE_TABLE.get_unchecked(i) }.1; char::from_u32(u).map(|c| [c, '\0', '\0']).unwrap_or_else(|| { // SAFETY: Index comes from statically generated table unsafe { *UPPERCASE_TABLE_MULTI.get_unchecked((u & (INDEX_MASK - 1)) as usize) } diff --git a/src/tools/unicode-table-generator/src/case_mapping.rs b/src/tools/unicode-table-generator/src/case_mapping.rs index 49aef3ec33ec..437e1e47dd70 100644 --- a/src/tools/unicode-table-generator/src/case_mapping.rs +++ b/src/tools/unicode-table-generator/src/case_mapping.rs @@ -91,7 +91,8 @@ pub fn to_lower(c: char) -> [char; 3] { LOWERCASE_TABLE .binary_search_by(|&(key, _)| key.cmp(&c)) .map(|i| { - let u = LOWERCASE_TABLE[i].1; + // SAFETY: i is the result of the binary search + let u = unsafe { LOWERCASE_TABLE.get_unchecked(i) }.1; char::from_u32(u).map(|c| [c, '\0', '\0']).unwrap_or_else(|| { // SAFETY: Index comes from statically generated table unsafe { *LOWERCASE_TABLE_MULTI.get_unchecked((u & (INDEX_MASK - 1)) as usize) } @@ -108,7 +109,8 @@ pub fn to_upper(c: char) -> [char; 3] { UPPERCASE_TABLE .binary_search_by(|&(key, _)| key.cmp(&c)) .map(|i| { - let u = UPPERCASE_TABLE[i].1; + // SAFETY: i is the result of the binary search + let u = unsafe { UPPERCASE_TABLE.get_unchecked(i) }.1; char::from_u32(u).map(|c| [c, '\0', '\0']).unwrap_or_else(|| { // SAFETY: Index comes from statically generated table unsafe { *UPPERCASE_TABLE_MULTI.get_unchecked((u & (INDEX_MASK - 1)) as usize) } From 319735d8c9851db41a1fd0a1c435a72e5eec9df0 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Tue, 30 Dec 2025 10:35:05 -0800 Subject: [PATCH 0110/1061] Fix parsing of mgca const blocks in array repeat exprs There was an inconsistency where in the case of array repeat expressions, we forgot to eat the `const` keyword of mgca const blocks. Thus, we ended up parsing them as an anon const containing an inline const, instead of simply an anon const as they should be. This commit fixes that issue and also makes the parsing for mgca const blocks more consistent and simpler in general. For example, we avoid doing a lookahead check to ensure there's a curly brace coming. There should always be one after a `const` keyword in an expression context, and that's handled by the mgca const block parsing function. --- compiler/rustc_parse/src/parser/expr.rs | 6 ++--- compiler/rustc_parse/src/parser/mod.rs | 5 ++-- compiler/rustc_parse/src/parser/path.rs | 2 +- compiler/rustc_parse/src/parser/ty.rs | 4 +--- .../assoc-const-eq-ambiguity.stderr | 4 ++-- ...soc-const-eq-bound-var-in-ty-not-wf.stderr | 8 +++---- .../const-block-is-poly.rs | 2 +- .../const-block-is-poly.stderr | 6 +++-- ...nbraced_const_block_const_arg_gated.stderr | 24 +++++++++---------- 9 files changed, 29 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 8bbf534294f4..8835fba1adcd 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1622,15 +1622,13 @@ impl<'a> Parser<'a> { let first_expr = self.parse_expr()?; if self.eat(exp!(Semi)) { // Repeating array syntax: `[ 0; 512 ]` - let count = if self.token.is_keyword(kw::Const) - && self.look_ahead(1, |t| *t == token::OpenBrace) - { + let count = if self.eat_keyword(exp!(Const)) { // While we could just disambiguate `Direct` from `AnonConst` by // treating all const block exprs as `AnonConst`, that would // complicate the DefCollector and likely all other visitors. // So we strip the const blockiness and just store it as a block // in the AST with the extra disambiguator on the AnonConst - self.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)? + self.parse_mgca_const_block(false)? } else { self.parse_expr_anon_const(|this, expr| this.mgca_direct_lit_hack(expr))? }; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index b3df728e8198..4dade1d01282 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1303,9 +1303,8 @@ impl<'a> Parser<'a> { } fn parse_mgca_const_block(&mut self, gate_syntax: bool) -> PResult<'a, AnonConst> { - self.expect_keyword(exp!(Const))?; - let kw_span = self.token.span; - let value = self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)?; + let kw_span = self.prev_token.span; + let value = self.parse_expr_block(None, kw_span, BlockCheckMode::Default)?; if gate_syntax { self.psess.gated_spans.gate(sym::min_generic_const_args, kw_span.to(value.span)); } diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index ce9e9c73669e..dd190707c42b 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -874,7 +874,7 @@ impl<'a> Parser<'a> { let (value, mgca_disambiguation) = if self.token.kind == token::OpenBrace { let value = self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)?; (value, MgcaDisambiguation::Direct) - } else if self.token.is_keyword(kw::Const) { + } else if self.eat_keyword(exp!(Const)) { // While we could just disambiguate `Direct` from `AnonConst` by // treating all const block exprs as `AnonConst`, that would // complicate the DefCollector and likely all other visitors. diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 3ccaae868a65..0185c51c5c56 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -658,9 +658,7 @@ impl<'a> Parser<'a> { }; let ty = if self.eat(exp!(Semi)) { - let mut length = if self.token.is_keyword(kw::Const) - && self.look_ahead(1, |t| *t == token::OpenBrace) - { + let mut length = if self.eat_keyword(exp!(Const)) { // While we could just disambiguate `Direct` from `AnonConst` by // treating all const block exprs as `AnonConst`, that would // complicate the DefCollector and likely all other visitors. diff --git a/tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr b/tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr index 9ab39e6b8a60..cf4805aaf592 100644 --- a/tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr @@ -13,8 +13,8 @@ LL | fn take0(_: impl Trait0) {} = help: consider introducing a new type parameter `T` and adding `where` constraints: where T: Trait0, - T: Parent0::K = { }, - T: Parent0::K = { } + T: Parent0::K = const { }, + T: Parent0::K = const { } error[E0222]: ambiguous associated constant `C` in bounds of `Trait1` --> $DIR/assoc-const-eq-ambiguity.rs:26:25 diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr index 4a4c2b285829..76868715b861 100644 --- a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr @@ -1,14 +1,14 @@ error: higher-ranked subtype error - --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:19 + --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:13 | LL | K = const { () } - | ^^^^^^ + | ^^^^^^^^^^^^ error: higher-ranked subtype error - --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:19 + --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:13 | LL | K = const { () } - | ^^^^^^ + | ^^^^^^^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.rs b/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.rs index f1305202ad45..a6988a492f61 100644 --- a/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.rs +++ b/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.rs @@ -2,7 +2,7 @@ //~^ WARN the feature `generic_const_exprs` is incomplete fn foo() { - let _ = [0u8; const { std::mem::size_of::() }]; + let _ = [0u8; { const { std::mem::size_of::() } }]; //~^ ERROR: overly complex generic constant } diff --git a/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr b/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr index 03b0004bf0bd..db547e6a2481 100644 --- a/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr +++ b/tests/ui/const-generics/generic_const_exprs/const-block-is-poly.stderr @@ -10,8 +10,10 @@ LL | #![feature(generic_const_exprs)] error: overly complex generic constant --> $DIR/const-block-is-poly.rs:5:19 | -LL | let _ = [0u8; const { std::mem::size_of::() }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ const blocks are not supported in generic constants +LL | let _ = [0u8; { const { std::mem::size_of::() } }]; + | ^^----------------------------------^^ + | | + | const blocks are not supported in generic constants | = help: consider moving this anonymous constant into a `const` function = note: this operation may be supported in the future diff --git a/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.stderr b/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.stderr index 30509ddf9b46..00db630c27e9 100644 --- a/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.stderr +++ b/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.stderr @@ -1,58 +1,58 @@ error[E0658]: unbraced const blocks as const args are experimental - --> $DIR/unbraced_const_block_const_arg_gated.rs:7:33 + --> $DIR/unbraced_const_block_const_arg_gated.rs:7:27 | LL | const PARAM_TY: Inner, - | ^^^^^ + | ^^^^^^^^^^^ | = note: see issue #132980 for more information = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: unbraced const blocks as const args are experimental - --> $DIR/unbraced_const_block_const_arg_gated.rs:9:34 + --> $DIR/unbraced_const_block_const_arg_gated.rs:9:28 | LL | const DEFAULT: usize = const { 1 }, - | ^^^^^ + | ^^^^^^^^^^^ | = note: see issue #132980 for more information = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: unbraced const blocks as const args are experimental - --> $DIR/unbraced_const_block_const_arg_gated.rs:14:29 + --> $DIR/unbraced_const_block_const_arg_gated.rs:14:23 | LL | type NormalTy = Inner; - | ^^^^^ + | ^^^^^^^^^^^ | = note: see issue #132980 for more information = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: unbraced const blocks as const args are experimental - --> $DIR/unbraced_const_block_const_arg_gated.rs:22:24 + --> $DIR/unbraced_const_block_const_arg_gated.rs:22:18 | LL | let _: Inner; - | ^^^^^ + | ^^^^^^^^^^^ | = note: see issue #132980 for more information = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: unbraced const blocks as const args are experimental - --> $DIR/unbraced_const_block_const_arg_gated.rs:28:25 + --> $DIR/unbraced_const_block_const_arg_gated.rs:28:19 | LL | generic::(); - | ^^^^^ + | ^^^^^^^^^^^ | = note: see issue #132980 for more information = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: unbraced const blocks as const args are experimental - --> $DIR/unbraced_const_block_const_arg_gated.rs:37:33 + --> $DIR/unbraced_const_block_const_arg_gated.rs:37:27 | LL | const TYPE_CONST: usize = const { 1 }; - | ^^^^^ + | ^^^^^^^^^^^ | = note: see issue #132980 for more information = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable From 59a3ad3e13a87e1b8ab9f4481faf764484509c27 Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Wed, 31 Dec 2025 05:53:50 +0000 Subject: [PATCH 0111/1061] Enable thumb interworking on ARMv7A/R and ARMv8R bare-metal targets --- compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs | 1 + compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs | 1 + compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs | 1 + compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs | 1 + compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs | 1 + compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs | 1 + compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs | 1 + 7 files changed, 7 insertions(+) diff --git a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs index 849a0f4c9a68..7a62464aea4b 100644 --- a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs @@ -31,6 +31,7 @@ pub(crate) fn target() -> Target { emit_debug_gdb_scripts: false, // GCC defaults to 8 for arm-none here. c_enum_min_bits: Some(8), + has_thumb_interworking: true, ..Default::default() }, } diff --git a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs index 0cf3880cadc9..33147c5f1b09 100644 --- a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs @@ -32,6 +32,7 @@ pub(crate) fn target() -> Target { emit_debug_gdb_scripts: false, // GCC defaults to 8 for arm-none here. c_enum_min_bits: Some(8), + has_thumb_interworking: true, ..Default::default() }, } diff --git a/compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs index 13a95a113b13..6b7707a47390 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs @@ -32,6 +32,7 @@ pub(crate) fn target() -> Target { panic_strategy: PanicStrategy::Abort, emit_debug_gdb_scripts: false, c_enum_min_bits: Some(8), + has_thumb_interworking: true, ..Default::default() }; Target { diff --git a/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs index 28efdbe2291f..993390543b96 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs @@ -24,6 +24,7 @@ pub(crate) fn target() -> Target { emit_debug_gdb_scripts: false, // GCC defaults to 8 for arm-none here. c_enum_min_bits: Some(8), + has_thumb_interworking: true, ..Default::default() }; Target { diff --git a/compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs index b490b716f4b0..551cbf4a589f 100644 --- a/compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs @@ -29,6 +29,7 @@ pub(crate) fn target() -> Target { emit_debug_gdb_scripts: false, // GCC defaults to 8 for arm-none here. c_enum_min_bits: Some(8), + has_thumb_interworking: true, ..Default::default() }, } diff --git a/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs index 7a3eb3b811a6..97c911ec8090 100644 --- a/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs @@ -30,6 +30,7 @@ pub(crate) fn target() -> Target { emit_debug_gdb_scripts: false, // GCC defaults to 8 for arm-none here. c_enum_min_bits: Some(8), + has_thumb_interworking: true, ..Default::default() }, } diff --git a/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs index 423bf260d89c..e36240b9c223 100644 --- a/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs @@ -39,6 +39,7 @@ pub(crate) fn target() -> Target { emit_debug_gdb_scripts: false, // GCC defaults to 8 for arm-none here. c_enum_min_bits: Some(8), + has_thumb_interworking: true, ..Default::default() }, } From 862ab4cab6f2031800838c62f6a8b06b825a054a Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 31 Dec 2025 14:23:56 +0530 Subject: [PATCH 0112/1061] remove unwanted comment --- .../rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs index 25a5104c5df3..1a929a02ac3b 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs @@ -81,7 +81,6 @@ fn run_new() -> io::Result<()> { } bidirectional::Request::ApiVersionCheck {} => { - // bidirectional::Response::ApiVersionCheck(CURRENT_API_VERSION).write::<_, C>(stdout) send_response::( &stdout, bidirectional::Response::ApiVersionCheck(CURRENT_API_VERSION), From 03d2bccbe5795450536996d35ba2318cf1ebc71d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 31 Dec 2025 10:28:04 +0100 Subject: [PATCH 0113/1061] Run rustdoc tests in opt-dist tests --- src/tools/opt-dist/src/tests.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/opt-dist/src/tests.rs b/src/tools/opt-dist/src/tests.rs index fa55805bbf21..29168b25f7f6 100644 --- a/src/tools/opt-dist/src/tests.rs +++ b/src/tools/opt-dist/src/tests.rs @@ -123,6 +123,7 @@ llvm-config = "{llvm_config}" "tests/run-make/rust-lld-x86_64-unknown-linux-gnu-dist", "tests/ui", "tests/crashes", + "tests/rustdoc", ]; for test_path in env.skipped_tests() { args.extend(["--skip", test_path]); From 4ba9b739a4b224ed6dd514309653a1db5cdfe486 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Dec 2025 10:51:58 +0100 Subject: [PATCH 0114/1061] fix non-determinism in os_unfair_lock test --- .../fail-dep/concurrency/apple_os_unfair_lock_move_with_queue.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_move_with_queue.rs b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_move_with_queue.rs index 1c31236a2f80..f1389dd0821f 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_move_with_queue.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_move_with_queue.rs @@ -1,4 +1,5 @@ //@only-target: darwin +//@compile-flags: -Zmiri-fixed-schedule #![feature(sync_unsafe_cell)] use std::cell::SyncUnsafeCell; From ec7db072ee3cc62f825f1b918cd8043cca03c6c7 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Wed, 31 Dec 2025 12:59:40 +0200 Subject: [PATCH 0115/1061] Allow finding references from doc comments --- .../crates/ide/src/references.rs | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index ffae7bf6c7c5..4918fe4ff9a4 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -38,7 +38,8 @@ use syntax::{ }; use crate::{ - Analysis, FilePosition, HighlightedRange, NavigationTarget, TryToNav, highlight_related, + Analysis, FilePosition, HighlightedRange, NavigationTarget, TryToNav, + doc_links::token_as_doc_comment, highlight_related, }; /// Result of a reference search operation. @@ -211,6 +212,13 @@ pub(crate) fn find_defs( syntax: &SyntaxNode, offset: TextSize, ) -> Option> { + if let Some(token) = syntax.token_at_offset(offset).left_biased() + && let Some(doc_comment) = token_as_doc_comment(&token) + { + return doc_comment + .get_definition_with_descend_at(sema, offset, |def, _, _| Some(vec![def])); + } + let token = syntax.token_at_offset(offset).find(|t| { matches!( t.kind(), @@ -785,6 +793,23 @@ fn main() { ); } + #[test] + fn test_find_all_refs_in_comments() { + check( + r#" +struct Foo; + +/// $0[`Foo`] is just above +struct Bar; +"#, + expect![[r#" + Foo Struct FileId(0) 0..11 7..10 + + (no references) + "#]], + ); + } + #[test] fn search_filters_by_range() { check( From 2a7e3e6f2361d081d94822ac53474cd9e1010f6a Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 31 Dec 2025 17:50:14 +0530 Subject: [PATCH 0116/1061] add bidirectional flow for file method --- .../crates/load-cargo/src/lib.rs | 14 ++++++++++ .../src/bidirectional_protocol/msg.rs | 2 ++ .../proc-macro-srv-cli/src/main_loop.rs | 26 +++++++++++++++++++ .../crates/proc-macro-srv/src/lib.rs | 1 + .../src/server_impl/rust_analyzer_span.rs | 13 +++++----- 5 files changed, 50 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index 5122051fb3c2..c8a157e88e17 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -546,6 +546,20 @@ impl ProcMacroExpander for Expander { let slice = text.get(start as usize..end as usize).map(ToOwned::to_owned); Ok(SubResponse::SourceTextResult { text: slice }) } + SubRequest::FileName { file_id } => { + let file = FileId::from_raw(file_id); + let source_root_id = db.file_source_root(file).source_root_id(db); + let source_root = db.source_root(source_root_id).source_root(db); + + let name = source_root.path_for_file(&file).and_then(|path| { + path.name_and_extension().map(|(name, ext)| match ext { + Some(ext) => format!("{name}.{ext}"), + None => name.to_owned(), + }) + }); + + Ok(SubResponse::FileNameResult { name: name.unwrap_or_default() }) + } }; match self.0.expand( subtree.view(), diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs index cf8becd922de..7edd9062d994 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs @@ -10,11 +10,13 @@ use crate::{ #[derive(Debug, Serialize, Deserialize)] pub enum SubRequest { + FileName { file_id: u32 }, SourceText { file_id: u32, start: u32, end: u32 }, } #[derive(Debug, Serialize, Deserialize)] pub enum SubResponse { + FileNameResult { name: String }, SourceTextResult { text: Option }, } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs index 1a929a02ac3b..279eab06c0b4 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs @@ -167,6 +167,32 @@ struct ProcMacroClientHandle<'a, C: Codec> { } impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandle<'_, C> { + fn file(&mut self, file_id: u32) -> String { + let req = + bidirectional::BidirectionalMessage::SubRequest(bidirectional::SubRequest::FileName { + file_id, + }); + + if req.write::<_, C>(&mut self.stdout.lock()).is_err() { + return String::new(); + } + + let msg = match bidirectional::BidirectionalMessage::read::<_, C>( + &mut self.stdin.lock(), + self.buf, + ) { + Ok(Some(msg)) => msg, + _ => return String::new(), + }; + + match msg { + bidirectional::BidirectionalMessage::SubResponse( + bidirectional::SubResponse::FileNameResult { name }, + ) => name, + _ => String::new(), + } + } + fn source_text(&mut self, file_id: u32, start: u32, end: u32) -> Option { let req = bidirectional::BidirectionalMessage::SubRequest( bidirectional::SubRequest::SourceText { file_id, start, end }, diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs index 17ffa29ce172..1804238a32a1 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs @@ -94,6 +94,7 @@ impl<'env> ProcMacroSrv<'env> { pub type ProcMacroClientHandle<'a> = &'a mut (dyn ProcMacroClientInterface + Sync + Send); pub trait ProcMacroClientInterface { + fn file(&mut self, file_id: u32) -> String; fn source_text(&mut self, file_id: u32, start: u32, end: u32) -> Option; } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index 5d9090c060e0..7a9d655431f5 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -127,13 +127,14 @@ impl server::Span for RaSpanServer<'_> { fn debug(&mut self, span: Self::Span) -> String { format!("{:?}", span) } - fn file(&mut self, _: Self::Span) -> String { - // FIXME - String::new() + fn file(&mut self, span: Self::Span) -> String { + self.callback + .as_mut() + .map(|cb| cb.file(span.anchor.file_id.file_id().index())) + .unwrap_or_default() } - fn local_file(&mut self, _: Self::Span) -> Option { - // FIXME - None + fn local_file(&mut self, span: Self::Span) -> Option { + self.callback.as_mut().and_then(|cb| cb.local_file(span.anchor.file_id.file_id().index())) } fn save_span(&mut self, _span: Self::Span) -> usize { // FIXME, quote is incompatible with third-party tools From abbf0272fa13f49532ece6a125de288ba39c82c7 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 31 Dec 2025 17:50:20 +0530 Subject: [PATCH 0117/1061] add bidirectional flow for local file method --- .../crates/load-cargo/src/lib.rs | 14 +++++++++++ .../src/bidirectional_protocol/msg.rs | 2 ++ .../proc-macro-srv-cli/src/main_loop.rs | 25 +++++++++++++++++++ .../crates/proc-macro-srv/src/lib.rs | 1 + 4 files changed, 42 insertions(+) diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index c8a157e88e17..dc75abe7ad8c 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -540,6 +540,20 @@ impl ProcMacroExpander for Expander { current_dir: String, ) -> Result { let mut cb = |req| match req { + SubRequest::LocalFileName { file_id } => { + let file = FileId::from_raw(file_id); + let source_root_id = db.file_source_root(file).source_root_id(db); + let source_root = db.source_root(source_root_id).source_root(db); + + let name = source_root + .path_for_file(&file) + .and_then(|path| path.clone().into_abs_path()) + .and_then(|path| { + path.as_path().file_name().map(|filename| filename.to_owned()) + }); + + Ok(SubResponse::LocalFileNameResult { name }) + } SubRequest::SourceText { file_id, start, end } => { let file = FileId::from_raw(file_id); let text = db.file_text(file).text(db); diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs index 7edd9062d994..2819a92fe33a 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs @@ -12,12 +12,14 @@ use crate::{ pub enum SubRequest { FileName { file_id: u32 }, SourceText { file_id: u32, start: u32, end: u32 }, + LocalFileName { file_id: u32 }, } #[derive(Debug, Serialize, Deserialize)] pub enum SubResponse { FileNameResult { name: String }, SourceTextResult { text: Option }, + LocalFileNameResult { name: Option }, } #[derive(Debug, Serialize, Deserialize)] diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs index 279eab06c0b4..76119b27a8b6 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs @@ -217,6 +217,31 @@ impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandl _ => None, } } + + fn local_file(&mut self, file_id: u32) -> Option { + let req = bidirectional::BidirectionalMessage::SubRequest( + bidirectional::SubRequest::LocalFileName { file_id }, + ); + + if req.write::<_, C>(&mut self.stdout.lock()).is_err() { + return Some(String::new()); + } + + let msg = match bidirectional::BidirectionalMessage::read::<_, C>( + &mut self.stdin.lock(), + self.buf, + ) { + Ok(msg) => msg, + _ => return None, + }; + + match msg { + Some(bidirectional::BidirectionalMessage::SubResponse( + bidirectional::SubResponse::LocalFileNameResult { name }, + )) => Some(name.unwrap_or_default()), + _ => None, + } + } } fn handle_expand_ra( diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs index 1804238a32a1..8de712dbd386 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs @@ -96,6 +96,7 @@ pub type ProcMacroClientHandle<'a> = &'a mut (dyn ProcMacroClientInterface + Syn pub trait ProcMacroClientInterface { fn file(&mut self, file_id: u32) -> String; fn source_text(&mut self, file_id: u32, start: u32, end: u32) -> Option; + fn local_file(&mut self, file_id: u32) -> Option; } const EXPANDER_STACK_SIZE: usize = 8 * 1024 * 1024; From c4dd25f6cd2e11e0a4f055bba2cffed5a1553cb2 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 31 Dec 2025 17:54:22 +0530 Subject: [PATCH 0118/1061] add roundtrip abstraction to remove subrequest subresponse boilerplate code --- .../proc-macro-srv-cli/src/main_loop.rs | 79 ++++++------------- 1 file changed, 24 insertions(+), 55 deletions(-) diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs index 76119b27a8b6..77cb8760a100 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs @@ -166,79 +166,48 @@ struct ProcMacroClientHandle<'a, C: Codec> { buf: &'a mut C::Buf, } -impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandle<'_, C> { - fn file(&mut self, file_id: u32) -> String { - let req = - bidirectional::BidirectionalMessage::SubRequest(bidirectional::SubRequest::FileName { - file_id, - }); +impl<'a, C: Codec> ProcMacroClientHandle<'a, C> { + fn roundtrip( + &mut self, + req: bidirectional::SubRequest, + ) -> Option { + let msg = bidirectional::BidirectionalMessage::SubRequest(req); - if req.write::<_, C>(&mut self.stdout.lock()).is_err() { - return String::new(); + if msg.write::<_, C>(&mut self.stdout.lock()).is_err() { + return None; } - let msg = match bidirectional::BidirectionalMessage::read::<_, C>( - &mut self.stdin.lock(), - self.buf, - ) { - Ok(Some(msg)) => msg, - _ => return String::new(), - }; + match bidirectional::BidirectionalMessage::read::<_, C>(&mut self.stdin.lock(), self.buf) { + Ok(Some(msg)) => Some(msg), + _ => None, + } + } +} - match msg { - bidirectional::BidirectionalMessage::SubResponse( +impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandle<'_, C> { + fn file(&mut self, file_id: u32) -> String { + match self.roundtrip(bidirectional::SubRequest::FileName { file_id }) { + Some(bidirectional::BidirectionalMessage::SubResponse( bidirectional::SubResponse::FileNameResult { name }, - ) => name, + )) => name, _ => String::new(), } } fn source_text(&mut self, file_id: u32, start: u32, end: u32) -> Option { - let req = bidirectional::BidirectionalMessage::SubRequest( - bidirectional::SubRequest::SourceText { file_id, start, end }, - ); - - if req.write::<_, C>(&mut self.stdout.lock()).is_err() { - return None; - } - - let msg = match bidirectional::BidirectionalMessage::read::<_, C>( - &mut self.stdin.lock(), - self.buf, - ) { - Ok(Some(msg)) => msg, - _ => return None, - }; - - match msg { - bidirectional::BidirectionalMessage::SubResponse( + match self.roundtrip(bidirectional::SubRequest::SourceText { file_id, start, end }) { + Some(bidirectional::BidirectionalMessage::SubResponse( bidirectional::SubResponse::SourceTextResult { text }, - ) => text, + )) => text, _ => None, } } fn local_file(&mut self, file_id: u32) -> Option { - let req = bidirectional::BidirectionalMessage::SubRequest( - bidirectional::SubRequest::LocalFileName { file_id }, - ); - - if req.write::<_, C>(&mut self.stdout.lock()).is_err() { - return Some(String::new()); - } - - let msg = match bidirectional::BidirectionalMessage::read::<_, C>( - &mut self.stdin.lock(), - self.buf, - ) { - Ok(msg) => msg, - _ => return None, - }; - - match msg { + match self.roundtrip(bidirectional::SubRequest::LocalFileName { file_id }) { Some(bidirectional::BidirectionalMessage::SubResponse( bidirectional::SubResponse::LocalFileNameResult { name }, - )) => Some(name.unwrap_or_default()), + )) => name, _ => None, } } From 55833a9a6dfeff37b3b7701b266dc7a6e6f0a80b Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Tue, 23 Dec 2025 00:16:22 +0100 Subject: [PATCH 0119/1061] tests/codegen-llvm/some-non-zero-from-atomic-optimization.rs: New test --- .../some-non-zero-from-atomic-optimization.rs | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 tests/codegen-llvm/some-non-zero-from-atomic-optimization.rs diff --git a/tests/codegen-llvm/some-non-zero-from-atomic-optimization.rs b/tests/codegen-llvm/some-non-zero-from-atomic-optimization.rs new file mode 100644 index 000000000000..35317b0dd39c --- /dev/null +++ b/tests/codegen-llvm/some-non-zero-from-atomic-optimization.rs @@ -0,0 +1,84 @@ +//! Regression test for . + +// We want to check that `unreachable!()` is optimized away. +//@ compile-flags: -O + +// Don't de-duplicate `some_non_zero_from_atomic_get2()` since we want its LLVM IR. +//@ compile-flags: -Zmerge-functions=disabled + +// So we don't have to worry about usize. +//@ only-64bit + +#![crate_type = "lib"] + +use std::num::NonZeroUsize; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering::Relaxed; + +pub static X: AtomicUsize = AtomicUsize::new(1); + +/// We don't need to check the LLVM IR of this function, but we expect its LLVM +/// IR to be identical to `some_non_zero_from_atomic_get2()`. +#[no_mangle] +pub unsafe fn some_non_zero_from_atomic_get() -> Option { + let x = X.load(Relaxed); + Some(NonZeroUsize::new_unchecked(x)) +} + +/// We want to test that the `unreachable!()` branch is optimized out. +/// +/// When that does not happen, the LLVM IR will look like this: +/// +/// ```sh +/// rustc +nightly-2024-02-08 --emit=llvm-ir -O -Zmerge-functions=disabled \ +/// tests/codegen-llvm/some-non-zero-from-atomic-optimization.rs && \ +/// grep -B 1 -A 13 '@some_non_zero_from_atomic_get2()' some-non-zero-from-atomic-optimization.ll +/// ``` +/// ```llvm +/// ; Function Attrs: nonlazybind uwtable +/// define noundef i64 @some_non_zero_from_atomic_get2() unnamed_addr #1 { +/// start: +/// %0 = load atomic i64, ptr @_ZN38some_non_zero_from_atomic_optimization1X17h monotonic, align 8 +/// %1 = icmp eq i64 %0, 0 +/// br i1 %1, label %bb2, label %bb3 +/// +/// bb2: ; preds = %start +/// ; call core::panicking::panic +/// tail call void @_ZN4core9panicking5panic17h0cc48E(..., ..., ... ) #3 +/// unreachable +/// +/// bb3: ; preds = %start +/// ret i64 %0 +/// } +/// ``` +/// +/// When it _is_ optimized out, the LLVM IR will look like this: +/// +/// ```sh +/// rustc +nightly-2024-02-09 --emit=llvm-ir -O -Zmerge-functions=disabled \ +/// tests/codegen-llvm/some-non-zero-from-atomic-optimization.rs && \ +/// grep -B 1 -A 6 '@some_non_zero_from_atomic_get2()' some-non-zero-from-atomic-optimization.ll +/// ``` +/// ```llvm +/// ; Function Attrs: mustprogress nofree nounwind nonlazybind willreturn memory(...) uwtable +/// define noundef i64 @some_non_zero_from_atomic_get2() unnamed_addr #0 { +/// bb3: +/// %0 = load atomic i64, ptr @_ZN38some_non_zero_from_atomic_optimization1X17h monotonic, align 8 +/// %1 = icmp ne i64 %0, 0 +/// tail call void @llvm.assume(i1 %1) +/// ret i64 %0 +/// } +/// ``` +/// +/// The way we check that the LLVM IR is correct is by making sure that neither +/// `panic` nor `unreachable` is part of the LLVM IR: +// CHECK-LABEL: define {{.*}} i64 @some_non_zero_from_atomic_get2() {{.*}} { +// CHECK-NOT: panic +// CHECK-NOT: unreachable +#[no_mangle] +pub unsafe fn some_non_zero_from_atomic_get2() -> usize { + match some_non_zero_from_atomic_get() { + Some(x) => x.get(), + None => unreachable!(), // shall be optimized out + } +} From cc01b1c3789e628ff2e339e584fd190c051a8c3c Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Wed, 31 Dec 2025 16:09:23 +0100 Subject: [PATCH 0120/1061] Back into rotation --- triagebot.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 5f637205fa65..09dec7675e7e 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -63,7 +63,6 @@ users_on_vacation = [ "Alexendoo", "y21", "blyxyas", - "samueltardieu", ] [assign.owners] From 4ba73c33b8d354724d1d713be177912b1636a67c Mon Sep 17 00:00:00 2001 From: Dushyanth Date: Wed, 31 Dec 2025 21:09:11 +0530 Subject: [PATCH 0121/1061] test: add regression cases for valtree hashing ICE --- .../printing_valtrees_supports_non_values.rs | 11 ++++++ ...inting_valtrees_supports_non_values.stderr | 38 ++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.rs b/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.rs index fbe310f7de4c..484d6f14a82a 100644 --- a/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.rs +++ b/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.rs @@ -25,3 +25,14 @@ fn baz() { } fn main() {} + +fn test_ice_missing_bound() { + foo::<{Option::Some::{0: ::ASSOC}}>(); + //~^ ERROR the trait bound `T: Trait` is not satisfied + //~| ERROR the constant `Option::::Some(_)` is not of type `Foo` +} + +fn test_underscore_inference() { + foo::<{ Option::Some:: { 0: _ } }>(); + //~^ ERROR the constant `Option::::Some(_)` is not of type `Foo` +} diff --git a/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.stderr b/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.stderr index 8b2871f2b6d3..b4f03e07b569 100644 --- a/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.stderr +++ b/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.stderr @@ -22,5 +22,41 @@ note: required by a const generic parameter in `foo` LL | fn foo() {} | ^^^^^^^^^^^^ required by this const generic parameter in `foo` -error: aborting due to 2 previous errors +error[E0277]: the trait bound `T: Trait` is not satisfied + --> $DIR/printing_valtrees_supports_non_values.rs:30:5 + | +LL | foo::<{Option::Some::{0: ::ASSOC}}>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` + | +help: consider restricting type parameter `T` with trait `Trait` + | +LL | fn test_ice_missing_bound() { + | +++++++ +error: the constant `Option::::Some(_)` is not of type `Foo` + --> $DIR/printing_valtrees_supports_non_values.rs:30:12 + | +LL | foo::<{Option::Some::{0: ::ASSOC}}>(); + | ^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option` + | +note: required by a const generic parameter in `foo` + --> $DIR/printing_valtrees_supports_non_values.rs:15:8 + | +LL | fn foo() {} + | ^^^^^^^^^^^^ required by this const generic parameter in `foo` + +error: the constant `Option::::Some(_)` is not of type `Foo` + --> $DIR/printing_valtrees_supports_non_values.rs:36:13 + | +LL | foo::<{ Option::Some:: { 0: _ } }>(); + | ^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option` + | +note: required by a const generic parameter in `foo` + --> $DIR/printing_valtrees_supports_non_values.rs:15:8 + | +LL | fn foo() {} + | ^^^^^^^^^^^^ required by this const generic parameter in `foo` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. From 6b60e81e8c6de24a5d131dab3d5d61541aa0fb96 Mon Sep 17 00:00:00 2001 From: dianne Date: Wed, 31 Dec 2025 08:51:49 -0800 Subject: [PATCH 0122/1061] Rewrite a `loop` as tail recursion --- .../rustc_hir_analysis/src/check/region.rs | 34 ++++++++----------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 0e8cdc266f89..0c611e6c4c9e 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -701,31 +701,25 @@ fn resolve_local<'tcx>( /// Note: ET is intended to match "rvalues or places based on rvalues". fn record_subexpr_extended_temp_scopes( scope_tree: &mut ScopeTree, - mut expr: &hir::Expr<'_>, + expr: &hir::Expr<'_>, lifetime: Option, ) { - debug!(?expr, ?lifetime); + // Note: give all the expressions matching `ET` with the + // extended temporary lifetime, not just the innermost rvalue, + // because in MIR building if we must compile e.g., `*rvalue()` + // into a temporary, we request the temporary scope of the + // outer expression. - loop { - // Note: give all the expressions matching `ET` with the - // extended temporary lifetime, not just the innermost rvalue, - // because in MIR building if we must compile e.g., `*rvalue()` - // into a temporary, we request the temporary scope of the - // outer expression. + scope_tree.record_extended_temp_scope(expr.hir_id.local_id, lifetime); - scope_tree.record_extended_temp_scope(expr.hir_id.local_id, lifetime); - - match expr.kind { - hir::ExprKind::AddrOf(_, _, subexpr) - | hir::ExprKind::Unary(hir::UnOp::Deref, subexpr) - | hir::ExprKind::Field(subexpr, _) - | hir::ExprKind::Index(subexpr, _, _) => { - expr = subexpr; - } - _ => { - return; - } + match expr.kind { + hir::ExprKind::AddrOf(_, _, subexpr) + | hir::ExprKind::Unary(hir::UnOp::Deref, subexpr) + | hir::ExprKind::Field(subexpr, _) + | hir::ExprKind::Index(subexpr, _, _) => { + record_subexpr_extended_temp_scopes(scope_tree, subexpr, lifetime); } + _ => {} } } From 215768a7347ff7388b271ccc7ed6b19c4921b24e Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Wed, 31 Dec 2025 17:05:41 +0000 Subject: [PATCH 0123/1061] fix missing_panics_doc in `std::os::fd::owned` https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc --- library/std/src/os/fd/owned.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index 846ad37aad22..5ba6c9c1fd14 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -77,7 +77,11 @@ impl BorrowedFd<'_> { /// # Safety /// /// The resource pointed to by `fd` must remain open for the duration of - /// the returned `BorrowedFd`, and it must not have the value `-1`. + /// the returned `BorrowedFd`. + /// + /// # Panics + /// + /// Panics if the raw file descriptor has the value `-1`. #[inline] #[track_caller] #[rustc_const_stable(feature = "io_safety", since = "1.63.0")] @@ -177,6 +181,10 @@ impl FromRawFd for OwnedFd { /// [ownership][io-safety]. The resource must not require any cleanup other than `close`. /// /// [io-safety]: io#io-safety + /// + /// # Panics + /// + /// Panics if the raw file descriptor has the value `-1`. #[inline] #[track_caller] unsafe fn from_raw_fd(fd: RawFd) -> Self { From a3d829175a57c49bab675b35e3740685c7ca2b3a Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Wed, 31 Dec 2025 02:32:54 +0100 Subject: [PATCH 0124/1061] Update books --- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- src/tools/rustbook/Cargo.lock | 18 +++++++++++++++++- src/tools/rustbook/Cargo.toml | 2 +- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/doc/reference b/src/doc/reference index ec78de0ffe2f..6363385ac4eb 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit ec78de0ffe2f8344bd0e222b17ac7a7d32dc7a26 +Subproject commit 6363385ac4ebe1763f1e6fb2063c0b1db681a072 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 7d21279e40e8..2e02f22a10e7 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 7d21279e40e8f0e91c2a22c5148dd2d745aef8b6 +Subproject commit 2e02f22a10e7eeb758e6aba484f13d0f1988a3e5 diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index e7b04260e4a9..941bf2829ef7 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -320,6 +320,10 @@ dependencies = [ "syn", ] +[[package]] +name = "diagnostics" +version = "0.0.0" + [[package]] name = "digest" version = "0.10.7" @@ -464,6 +468,16 @@ dependencies = [ "wasip2", ] +[[package]] +name = "grammar" +version = "0.0.0" +dependencies = [ + "diagnostics", + "pathdiff", + "regex", + "walkdir", +] + [[package]] name = "handlebars" version = "6.3.2" @@ -774,9 +788,11 @@ dependencies = [ [[package]] name = "mdbook-spec" -version = "0.1.2" +version = "0.0.0" dependencies = [ "anyhow", + "diagnostics", + "grammar", "mdbook-markdown", "mdbook-preprocessor", "once_cell", diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index 2815f09105b1..6f28ebe51931 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -11,6 +11,6 @@ edition = "2021" clap = { version = "4.0.32", features = ["cargo"] } mdbook-driver = { version = "0.5.2", features = ["search"] } mdbook-i18n-helpers = "0.4.0" -mdbook-spec = { path = "../../doc/reference/mdbook-spec" } +mdbook-spec = { path = "../../doc/reference/tools/mdbook-spec" } mdbook-trpl = { path = "../../doc/book/packages/mdbook-trpl" } tracing-subscriber = { version = "0.3.20", features = ["env-filter"] } From c2f97d194f837a21f80e3c304c0ebe847649f055 Mon Sep 17 00:00:00 2001 From: mnemonikr <138624285+mnemonikr@users.noreply.github.com> Date: Thu, 11 Dec 2025 15:48:21 -0800 Subject: [PATCH 0125/1061] Added check for next_multiple_of in manual_div_ceil --- clippy_lints/src/operators/manual_div_ceil.rs | 127 +++++++++++------- clippy_utils/src/sym.rs | 1 + tests/ui/manual_div_ceil.fixed | 29 ++++ tests/ui/manual_div_ceil.rs | 29 ++++ tests/ui/manual_div_ceil.stderr | 20 ++- tests/ui/manual_div_ceil_with_feature.fixed | 29 ++++ tests/ui/manual_div_ceil_with_feature.rs | 29 ++++ tests/ui/manual_div_ceil_with_feature.stderr | 20 ++- 8 files changed, 233 insertions(+), 51 deletions(-) diff --git a/clippy_lints/src/operators/manual_div_ceil.rs b/clippy_lints/src/operators/manual_div_ceil.rs index 98aa47421537..5ed923d719bc 100644 --- a/clippy_lints/src/operators/manual_div_ceil.rs +++ b/clippy_lints/src/operators/manual_div_ceil.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::res::{MaybeDef, MaybeQPath}; use clippy_utils::sugg::{Sugg, has_enclosing_paren}; use clippy_utils::{SpanlessEq, sym}; use rustc_ast::{BinOpKind, LitIntType, LitKind, UnOp}; @@ -7,7 +8,7 @@ use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_middle::ty::{self}; +use rustc_middle::ty::{self, Ty}; use rustc_span::source_map::Spanned; use super::MANUAL_DIV_CEIL; @@ -16,59 +17,84 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, op: BinOpKind, lhs: & let mut applicability = Applicability::MachineApplicable; if op == BinOpKind::Div - && check_int_ty_and_feature(cx, lhs) - && check_int_ty_and_feature(cx, rhs) - && let ExprKind::Binary(inner_op, inner_lhs, inner_rhs) = lhs.kind + && check_int_ty_and_feature(cx, cx.typeck_results().expr_ty(lhs)) + && check_int_ty_and_feature(cx, cx.typeck_results().expr_ty(rhs)) && msrv.meets(cx, msrvs::DIV_CEIL) { - // (x + (y - 1)) / y - if let ExprKind::Binary(sub_op, sub_lhs, sub_rhs) = inner_rhs.kind - && inner_op.node == BinOpKind::Add - && sub_op.node == BinOpKind::Sub - && check_literal(sub_rhs) - && check_eq_expr(cx, sub_lhs, rhs) - { - build_suggestion(cx, expr, inner_lhs, rhs, &mut applicability); - return; - } + match lhs.kind { + ExprKind::Binary(inner_op, inner_lhs, inner_rhs) => { + // (x + (y - 1)) / y + if let ExprKind::Binary(sub_op, sub_lhs, sub_rhs) = inner_rhs.kind + && inner_op.node == BinOpKind::Add + && sub_op.node == BinOpKind::Sub + && check_literal(sub_rhs) + && check_eq_expr(cx, sub_lhs, rhs) + { + build_suggestion(cx, expr, inner_lhs, rhs, &mut applicability); + return; + } - // ((y - 1) + x) / y - if let ExprKind::Binary(sub_op, sub_lhs, sub_rhs) = inner_lhs.kind - && inner_op.node == BinOpKind::Add - && sub_op.node == BinOpKind::Sub - && check_literal(sub_rhs) - && check_eq_expr(cx, sub_lhs, rhs) - { - build_suggestion(cx, expr, inner_rhs, rhs, &mut applicability); - return; - } + // ((y - 1) + x) / y + if let ExprKind::Binary(sub_op, sub_lhs, sub_rhs) = inner_lhs.kind + && inner_op.node == BinOpKind::Add + && sub_op.node == BinOpKind::Sub + && check_literal(sub_rhs) + && check_eq_expr(cx, sub_lhs, rhs) + { + build_suggestion(cx, expr, inner_rhs, rhs, &mut applicability); + return; + } - // (x + y - 1) / y - if let ExprKind::Binary(add_op, add_lhs, add_rhs) = inner_lhs.kind - && inner_op.node == BinOpKind::Sub - && add_op.node == BinOpKind::Add - && check_literal(inner_rhs) - && check_eq_expr(cx, add_rhs, rhs) - { - build_suggestion(cx, expr, add_lhs, rhs, &mut applicability); - } + // (x + y - 1) / y + if let ExprKind::Binary(add_op, add_lhs, add_rhs) = inner_lhs.kind + && inner_op.node == BinOpKind::Sub + && add_op.node == BinOpKind::Add + && check_literal(inner_rhs) + && check_eq_expr(cx, add_rhs, rhs) + { + build_suggestion(cx, expr, add_lhs, rhs, &mut applicability); + } - // (x + (Y - 1)) / Y - if inner_op.node == BinOpKind::Add && differ_by_one(inner_rhs, rhs) { - build_suggestion(cx, expr, inner_lhs, rhs, &mut applicability); - } + // (x + (Y - 1)) / Y + if inner_op.node == BinOpKind::Add && differ_by_one(inner_rhs, rhs) { + build_suggestion(cx, expr, inner_lhs, rhs, &mut applicability); + } - // ((Y - 1) + x) / Y - if inner_op.node == BinOpKind::Add && differ_by_one(inner_lhs, rhs) { - build_suggestion(cx, expr, inner_rhs, rhs, &mut applicability); - } + // ((Y - 1) + x) / Y + if inner_op.node == BinOpKind::Add && differ_by_one(inner_lhs, rhs) { + build_suggestion(cx, expr, inner_rhs, rhs, &mut applicability); + } - // (x - (-Y - 1)) / Y - if inner_op.node == BinOpKind::Sub - && let ExprKind::Unary(UnOp::Neg, abs_div_rhs) = rhs.kind - && differ_by_one(abs_div_rhs, inner_rhs) - { - build_suggestion(cx, expr, inner_lhs, rhs, &mut applicability); + // (x - (-Y - 1)) / Y + if inner_op.node == BinOpKind::Sub + && let ExprKind::Unary(UnOp::Neg, abs_div_rhs) = rhs.kind + && differ_by_one(abs_div_rhs, inner_rhs) + { + build_suggestion(cx, expr, inner_lhs, rhs, &mut applicability); + } + }, + ExprKind::MethodCall(method, receiver, [next_multiple_of_arg], _) => { + // x.next_multiple_of(Y) / Y + if method.ident.name == sym::next_multiple_of + && check_int_ty(cx.typeck_results().expr_ty(receiver)) + && check_eq_expr(cx, next_multiple_of_arg, rhs) + { + build_suggestion(cx, expr, receiver, rhs, &mut applicability); + } + }, + ExprKind::Call(callee, [receiver, next_multiple_of_arg]) => { + // int_type::next_multiple_of(x, Y) / Y + if let Some(impl_ty_binder) = callee + .ty_rel_def_if_named(cx, sym::next_multiple_of) + .assoc_fn_parent(cx) + .opt_impl_ty(cx) + && check_int_ty(impl_ty_binder.skip_binder()) + && check_eq_expr(cx, next_multiple_of_arg, rhs) + { + build_suggestion(cx, expr, receiver, rhs, &mut applicability); + } + }, + _ => (), } } } @@ -91,8 +117,11 @@ fn differ_by_one(small_expr: &Expr<'_>, large_expr: &Expr<'_>) -> bool { } } -fn check_int_ty_and_feature(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - let expr_ty = cx.typeck_results().expr_ty(expr); +fn check_int_ty(expr_ty: Ty<'_>) -> bool { + matches!(expr_ty.peel_refs().kind(), ty::Int(_) | ty::Uint(_)) +} + +fn check_int_ty_and_feature(cx: &LateContext<'_>, expr_ty: Ty<'_>) -> bool { match expr_ty.peel_refs().kind() { ty::Uint(_) => true, ty::Int(_) => cx.tcx.features().enabled(sym::int_roundings), diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index 00f4a9c7e586..dd20fe16ce61 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -244,6 +244,7 @@ generate! { next_back, next_if, next_if_eq, + next_multiple_of, next_tuple, nth, ok, diff --git a/tests/ui/manual_div_ceil.fixed b/tests/ui/manual_div_ceil.fixed index cd91be87ec17..8ffd107dd42e 100644 --- a/tests/ui/manual_div_ceil.fixed +++ b/tests/ui/manual_div_ceil.fixed @@ -105,3 +105,32 @@ fn issue_15705(size: u64, c: &u64) { let _ = size.div_ceil(*c); //~^ manual_div_ceil } + +struct MyStruct(u32); +impl MyStruct { + // Method matching name on different type should not trigger lint + fn next_multiple_of(self, y: u32) -> u32 { + self.0.next_multiple_of(y) + } +} + +fn issue_16219() { + let x = 33u32; + + // Lint. + let _ = x.div_ceil(8); + //~^ manual_div_ceil + let _ = x.div_ceil(8); + //~^ manual_div_ceil + + let y = &x; + let _ = y.div_ceil(8); + //~^ manual_div_ceil + + // No lint. + let _ = x.next_multiple_of(8) / 7; + let _ = x.next_multiple_of(7) / 8; + + let z = MyStruct(x); + let _ = z.next_multiple_of(8) / 8; +} diff --git a/tests/ui/manual_div_ceil.rs b/tests/ui/manual_div_ceil.rs index 9899c7d775c2..859fb5a13c44 100644 --- a/tests/ui/manual_div_ceil.rs +++ b/tests/ui/manual_div_ceil.rs @@ -105,3 +105,32 @@ fn issue_15705(size: u64, c: &u64) { let _ = (size + c - 1) / c; //~^ manual_div_ceil } + +struct MyStruct(u32); +impl MyStruct { + // Method matching name on different type should not trigger lint + fn next_multiple_of(self, y: u32) -> u32 { + self.0.next_multiple_of(y) + } +} + +fn issue_16219() { + let x = 33u32; + + // Lint. + let _ = x.next_multiple_of(8) / 8; + //~^ manual_div_ceil + let _ = u32::next_multiple_of(x, 8) / 8; + //~^ manual_div_ceil + + let y = &x; + let _ = y.next_multiple_of(8) / 8; + //~^ manual_div_ceil + + // No lint. + let _ = x.next_multiple_of(8) / 7; + let _ = x.next_multiple_of(7) / 8; + + let z = MyStruct(x); + let _ = z.next_multiple_of(8) / 8; +} diff --git a/tests/ui/manual_div_ceil.stderr b/tests/ui/manual_div_ceil.stderr index 44de3ba99be7..0efc114c7078 100644 --- a/tests/ui/manual_div_ceil.stderr +++ b/tests/ui/manual_div_ceil.stderr @@ -131,5 +131,23 @@ error: manually reimplementing `div_ceil` LL | let _ = (size + c - 1) / c; | ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `size.div_ceil(*c)` -error: aborting due to 20 previous errors +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:121:13 + | +LL | let _ = x.next_multiple_of(8) / 8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:123:13 + | +LL | let _ = u32::next_multiple_of(x, 8) / 8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:127:13 + | +LL | let _ = y.next_multiple_of(8) / 8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `y.div_ceil(8)` + +error: aborting due to 23 previous errors diff --git a/tests/ui/manual_div_ceil_with_feature.fixed b/tests/ui/manual_div_ceil_with_feature.fixed index f55999c5ad08..d77b8bc28986 100644 --- a/tests/ui/manual_div_ceil_with_feature.fixed +++ b/tests/ui/manual_div_ceil_with_feature.fixed @@ -84,3 +84,32 @@ fn issue_13950() { let _ = y.div_ceil(-7); //~^ manual_div_ceil } + +struct MyStruct(i32); +impl MyStruct { + // Method matching name on different type should not trigger lint + fn next_multiple_of(self, y: i32) -> i32 { + self.0.next_multiple_of(y) + } +} + +fn issue_16219() { + let x = 33i32; + + // Lint. + let _ = x.div_ceil(8); + //~^ manual_div_ceil + let _ = x.div_ceil(8); + //~^ manual_div_ceil + + let y = &x; + let _ = y.div_ceil(8); + //~^ manual_div_ceil + + // No lint. + let _ = x.next_multiple_of(8) / 7; + let _ = x.next_multiple_of(7) / 8; + + let z = MyStruct(x); + let _ = z.next_multiple_of(8) / 8; +} diff --git a/tests/ui/manual_div_ceil_with_feature.rs b/tests/ui/manual_div_ceil_with_feature.rs index 8a895f634cb4..5b9a4d9156a7 100644 --- a/tests/ui/manual_div_ceil_with_feature.rs +++ b/tests/ui/manual_div_ceil_with_feature.rs @@ -84,3 +84,32 @@ fn issue_13950() { let _ = (y - 8) / -7; //~^ manual_div_ceil } + +struct MyStruct(i32); +impl MyStruct { + // Method matching name on different type should not trigger lint + fn next_multiple_of(self, y: i32) -> i32 { + self.0.next_multiple_of(y) + } +} + +fn issue_16219() { + let x = 33i32; + + // Lint. + let _ = x.next_multiple_of(8) / 8; + //~^ manual_div_ceil + let _ = i32::next_multiple_of(x, 8) / 8; + //~^ manual_div_ceil + + let y = &x; + let _ = y.next_multiple_of(8) / 8; + //~^ manual_div_ceil + + // No lint. + let _ = x.next_multiple_of(8) / 7; + let _ = x.next_multiple_of(7) / 8; + + let z = MyStruct(x); + let _ = z.next_multiple_of(8) / 8; +} diff --git a/tests/ui/manual_div_ceil_with_feature.stderr b/tests/ui/manual_div_ceil_with_feature.stderr index e1160d962996..c5fa15112a87 100644 --- a/tests/ui/manual_div_ceil_with_feature.stderr +++ b/tests/ui/manual_div_ceil_with_feature.stderr @@ -139,5 +139,23 @@ error: manually reimplementing `div_ceil` LL | let _ = (y - 8) / -7; | ^^^^^^^^^^^^ help: consider using `.div_ceil()`: `y.div_ceil(-7)` -error: aborting due to 23 previous errors +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:100:13 + | +LL | let _ = x.next_multiple_of(8) / 8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:102:13 + | +LL | let _ = i32::next_multiple_of(x, 8) / 8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:106:13 + | +LL | let _ = y.next_multiple_of(8) / 8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `y.div_ceil(8)` + +error: aborting due to 26 previous errors From 22bb4fe147127d72f31466e91768fb1de6347fab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 31 Dec 2025 23:40:16 +0000 Subject: [PATCH 0126/1061] Detect cases where `?` is applied on a type that could be coming from a different crate version than expected ``` error[E0277]: `?` couldn't convert the error to `dependency::Error` --> replaced | LL | fn main() -> Result<(), Error> { | ----------------- expected `dependency::Error` because of this ... LL | Err(Error2)?; | -----------^ the trait `From` is not implemented for `dependency::Error` | | | this can't be annotated with `?` because it has type `Result<_, Error2>` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait help: the trait `From` is not implemented for `dependency::Error` but trait `From<()>` is implemented for it --> replaced | LL | impl From<()> for Error { | ^^^^^^^^^^^^^^^^^^^^^^^ = help: for that trait implementation, expected `()`, found `Error2` = note: there are multiple different versions of crate `dependency` in the dependency graph = help: you can use `cargo tree` to explore your dependency tree ``` The existing checks rely on having access to the actual types/traits that diverged to detect they are called the same, come from different crates with the same name. The new check is less specific, merely looking to see if the crate name the involved type belongs has multiple crates. --- .../src/rmeta/decoder/cstore_impl.rs | 9 ++++ compiler/rustc_middle/src/query/mod.rs | 9 ++++ .../traits/fulfillment_errors.rs | 22 +++++++-- .../src/error_reporting/traits/mod.rs | 2 +- .../run-make/crate-loading/dep-2-reexport.rs | 16 ++++++- tests/run-make/crate-loading/dependency-1.rs | 24 ++++++++++ tests/run-make/crate-loading/dependency-2.rs | 24 ++++++++++ .../crate-loading/multiple-dep-versions.rs | 13 ++++-- .../multiple-dep-versions.stderr | 46 ++++++++++++++++++- 9 files changed, 156 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 36fe7f380069..7bd3f7db55f9 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -559,6 +559,15 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { .filter_map(|(cnum, data)| data.used().then_some(cnum)), ) }, + duplicate_crate_names: |tcx, c: CrateNum| { + let name = tcx.crate_name(c); + tcx.arena.alloc_from_iter( + tcx.crates(()) + .into_iter() + .filter(|k| tcx.crate_name(**k) == name && **k != c) + .map(|c| *c), + ) + }, ..providers.queries }; provide_extern(&mut providers.extern_queries); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 676f0d82e4fb..88917ad8db0d 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2339,6 +2339,7 @@ rustc_queries! { eval_always desc { "fetching all foreign CrateNum instances" } } + // Crates that are loaded non-speculatively (not for diagnostics or doc links). // FIXME: This is currently only used for collecting lang items, but should be used instead of // `crates` in most other cases too. @@ -2347,6 +2348,14 @@ rustc_queries! { desc { "fetching `CrateNum`s for all crates loaded non-speculatively" } } + /// All crates that share the same name as crate `c`. + /// + /// This normally occurs when multiple versions of the same dependency are present in the + /// dependency tree. + query duplicate_crate_names(c: CrateNum) -> &'tcx [CrateNum] { + desc { "fetching `CrateNum`s with same name as `{c:?}`" } + } + /// A list of all traits in a crate, used by rustdoc and error reporting. query traits(_: CrateNum) -> &'tcx [DefId] { desc { "fetching all traits in a crate" } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index d96a1b0a8c0e..8d779f40a13a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -33,6 +33,7 @@ use rustc_middle::ty::{ TypeVisitableExt, Upcast, }; use rustc_middle::{bug, span_bug}; +use rustc_span::def_id::CrateNum; use rustc_span::{BytePos, DUMMY_SP, STDLIB_STABLE_CRATES, Span, Symbol, sym}; use tracing::{debug, instrument}; @@ -2172,6 +2173,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.suggest_function_pointers_impl(None, &exp_found, err); } + if let ty::Adt(def, _) = trait_pred.self_ty().skip_binder().peel_refs().kind() + && let crates = self.tcx.duplicate_crate_names(def.did().krate) + && !crates.is_empty() + { + self.note_two_crate_versions(def.did().krate, MultiSpan::new(), err); + err.help("you can use `cargo tree` to explore your dependency tree"); + } true }) }) { @@ -2282,6 +2290,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } )); } + + if let ty::Adt(def, _) = trait_pred.self_ty().skip_binder().peel_refs().kind() + && let crates = self.tcx.duplicate_crate_names(def.did().krate) + && !crates.is_empty() + { + self.note_two_crate_versions(def.did().krate, MultiSpan::new(), err); + err.help("you can use `cargo tree` to explore your dependency tree"); + } true }; @@ -2445,11 +2461,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { pub fn note_two_crate_versions( &self, - did: DefId, + krate: CrateNum, sp: impl Into, err: &mut Diag<'_>, ) { - let crate_name = self.tcx.crate_name(did.krate); + let crate_name = self.tcx.crate_name(krate); let crate_msg = format!( "there are multiple different versions of crate `{crate_name}` in the dependency graph" ); @@ -2514,7 +2530,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { for (similar_item, _) in similar_items { err.span_help(self.tcx.def_span(similar_item), "item with same name found"); - self.note_two_crate_versions(similar_item, MultiSpan::new(), err); + self.note_two_crate_versions(similar_item.krate, MultiSpan::new(), err); } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index 3ba984b90a1d..a7a685d62b34 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -442,7 +442,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } } - self.note_two_crate_versions(expected_did, span, err); + self.note_two_crate_versions(expected_did.krate, span, err); err.help("you can use `cargo tree` to explore your dependency tree"); } suggested diff --git a/tests/run-make/crate-loading/dep-2-reexport.rs b/tests/run-make/crate-loading/dep-2-reexport.rs index 07444511472f..8b6ee6749dcc 100644 --- a/tests/run-make/crate-loading/dep-2-reexport.rs +++ b/tests/run-make/crate-loading/dep-2-reexport.rs @@ -2,9 +2,23 @@ #![crate_type = "rlib"] extern crate dependency; -pub use dependency::{Trait2, Type, do_something_trait, do_something_type}; +pub use dependency::{Error, OtherError, Trait2, Type, do_something_trait, do_something_type}; pub struct OtherType; impl dependency::Trait for OtherType { fn foo(&self) {} fn bar() {} } +#[derive(Debug)] +pub struct Error2; + +impl From for Error2 { + fn from(_: Error) -> Error2 { + Error2 + } +} + +impl From for Error2 { + fn from(_: OtherError) -> Error2 { + Error2 + } +} diff --git a/tests/run-make/crate-loading/dependency-1.rs b/tests/run-make/crate-loading/dependency-1.rs index bfeabccf5c14..0eea7a7fae8b 100644 --- a/tests/run-make/crate-loading/dependency-1.rs +++ b/tests/run-make/crate-loading/dependency-1.rs @@ -13,3 +13,27 @@ impl Trait for Type { pub fn do_something(_: X) {} pub fn do_something_type(_: Type) {} pub fn do_something_trait(_: Box) {} + +#[derive(Debug)] +pub struct Error; + +impl From<()> for Error { + fn from(t: ()) -> Error { + Error + } +} + +#[derive(Debug)] +pub struct OtherError; + +impl From<()> for OtherError { + fn from(t: ()) -> OtherError { + OtherError + } +} + +impl From for OtherError { + fn from(t: i32) -> OtherError { + OtherError + } +} diff --git a/tests/run-make/crate-loading/dependency-2.rs b/tests/run-make/crate-loading/dependency-2.rs index 682d1ff64b82..a07873297c54 100644 --- a/tests/run-make/crate-loading/dependency-2.rs +++ b/tests/run-make/crate-loading/dependency-2.rs @@ -14,3 +14,27 @@ impl Trait for Type { pub fn do_something(_: X) {} pub fn do_something_type(_: Type) {} pub fn do_something_trait(_: Box) {} + +#[derive(Debug)] +pub struct Error; + +impl From<()> for Error { + fn from(t: ()) -> Error { + Error + } +} + +#[derive(Debug)] +pub struct OtherError; + +impl From<()> for OtherError { + fn from(_: ()) -> OtherError { + OtherError + } +} + +impl From for OtherError { + fn from(_: i32) -> OtherError { + OtherError + } +} diff --git a/tests/run-make/crate-loading/multiple-dep-versions.rs b/tests/run-make/crate-loading/multiple-dep-versions.rs index 3a4a20d38fc8..69b8360a8c92 100644 --- a/tests/run-make/crate-loading/multiple-dep-versions.rs +++ b/tests/run-make/crate-loading/multiple-dep-versions.rs @@ -1,13 +1,20 @@ extern crate dep_2_reexport; extern crate dependency; -use dep_2_reexport::{OtherType, Trait2, Type}; -use dependency::{Trait, do_something, do_something_trait, do_something_type}; +use dep_2_reexport::{Error2, OtherType, Trait2, Type}; +use dependency::{Error, OtherError, Trait, do_something, do_something_trait, do_something_type}; -fn main() { +fn main() -> Result<(), Error> { do_something(Type); Type.foo(); Type::bar(); do_something(OtherType); do_something_type(Type); do_something_trait(Box::new(Type) as Box); + Err(Error2)?; + Ok(()) +} + +fn foo() -> Result<(), OtherError> { + Err(Error2)?; + Ok(()) } diff --git a/tests/run-make/crate-loading/multiple-dep-versions.stderr b/tests/run-make/crate-loading/multiple-dep-versions.stderr index 235a44a8ce89..f8f8bfaaff6f 100644 --- a/tests/run-make/crate-loading/multiple-dep-versions.stderr +++ b/tests/run-make/crate-loading/multiple-dep-versions.stderr @@ -144,7 +144,51 @@ note: function defined here LL | pub fn do_something_trait(_: Box) {} | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error[E0277]: `?` couldn't convert the error to `dependency::Error` + --> replaced + | +LL | fn main() -> Result<(), Error> { + | ----------------- expected `dependency::Error` because of this +... +LL | Err(Error2)?; + | -----------^ the trait `From` is not implemented for `dependency::Error` + | | + | this can't be annotated with `?` because it has type `Result<_, Error2>` + | + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait +help: the trait `From` is not implemented for `dependency::Error` + but trait `From<()>` is implemented for it + --> replaced + | +LL | impl From<()> for Error { + | ^^^^^^^^^^^^^^^^^^^^^^^ + = help: for that trait implementation, expected `()`, found `Error2` + = note: there are multiple different versions of crate `dependency` in the dependency graph + = help: you can use `cargo tree` to explore your dependency tree + +error[E0277]: `?` couldn't convert the error to `dependency::OtherError` + --> replaced + | +LL | fn foo() -> Result<(), OtherError> { + | ---------------------- expected `dependency::OtherError` because of this +LL | Err(Error2)?; + | -----------^ the trait `From` is not implemented for `dependency::OtherError` + | | + | this can't be annotated with `?` because it has type `Result<_, Error2>` + | + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait +help: the following other types implement trait `From` + --> replaced + | +LL | impl From<()> for OtherError { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dependency::OtherError` implements `From<()>` +... +LL | impl From for OtherError { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dependency::OtherError` implements `From` + = note: there are multiple different versions of crate `dependency` in the dependency graph + = help: you can use `cargo tree` to explore your dependency tree + +error: aborting due to 8 previous errors Some errors have detailed explanations: E0277, E0308, E0599. For more information about an error, try `rustc --explain E0277`. \ No newline at end of file From c6b03ae9b2fd9dab86662741784c8e34e8538c2b Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Tue, 30 Dec 2025 21:28:44 +0000 Subject: [PATCH 0127/1061] add check for `u8`s and update test --- compiler/rustc_mir_build/src/thir/constant.rs | 10 +++++---- .../byte-string-u8-validation.rs | 18 ++++++++++++++++ .../byte-string-u8-validation.stderr | 21 +++++++++++++++++++ .../mismatch-raw-ptr-in-adt.rs | 1 - .../mismatch-raw-ptr-in-adt.stderr | 13 +----------- 5 files changed, 46 insertions(+), 17 deletions(-) create mode 100644 tests/ui/const-generics/adt_const_params/byte-string-u8-validation.rs create mode 100644 tests/ui/const-generics/adt_const_params/byte-string-u8-validation.stderr diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index 563212a51f31..7964a58a7ab0 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -1,5 +1,5 @@ use rustc_abi::Size; -use rustc_ast::{self as ast}; +use rustc_ast::{self as ast, UintTy}; use rustc_hir::LangItem; use rustc_middle::bug; use rustc_middle::mir::interpret::LitToConstInput; @@ -44,12 +44,14 @@ pub(crate) fn lit_to_const<'tcx>( ty::ValTree::from_raw_bytes(tcx, str_bytes) } (ast::LitKind::ByteStr(byte_sym, _), ty::Ref(_, inner_ty, _)) - if matches!(inner_ty.kind(), ty::Slice(_) | ty::Array(..)) => + if let ty::Slice(ty) | ty::Array(ty, _) = inner_ty.kind() + && let ty::Uint(UintTy::U8) = ty.kind() => { ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()) } - (ast::LitKind::ByteStr(byte_sym, _), ty::Slice(_) | ty::Array(..)) - if tcx.features().deref_patterns() => + (ast::LitKind::ByteStr(byte_sym, _), ty::Slice(inner_ty) | ty::Array(inner_ty, _)) + if tcx.features().deref_patterns() + && let ty::Uint(UintTy::U8) = inner_ty.kind() => { // Byte string literal patterns may have type `[u8]` or `[u8; N]` if `deref_patterns` is // enabled, in order to allow, e.g., `deref!(b"..."): Vec`. diff --git a/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.rs b/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.rs new file mode 100644 index 000000000000..703e63ae047f --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.rs @@ -0,0 +1,18 @@ +// Check that a byte string literal to a const parameter with a non-u8 +// element type isn't lowered to a ValTree with an incorrect type + +#![feature(adt_const_params)] +#![feature(rustc_attrs)] + +#[rustc_dump_predicates] +struct ConstBytes +//~^ ERROR rustc_dump_predicates +//~| NOTE Binder { value: ConstArgHasType(T/#0, &'static [*mut u8; 3_usize]), bound_vars: [] } +//~| NOTE Binder { value: TraitPredicate( as std::marker::Sized>, polarity:Positive), bound_vars: [] } +where + ConstBytes: Sized; +//~^ ERROR mismatched types +//~| NOTE expected `&[*mut u8; 3]`, found `&[u8; 3]` +//~| NOTE expected reference `&'static [*mut u8; 3]` + +fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.stderr b/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.stderr new file mode 100644 index 000000000000..f5f8a420a703 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.stderr @@ -0,0 +1,21 @@ +error: rustc_dump_predicates + --> $DIR/byte-string-u8-validation.rs:8:1 + | +LL | struct ConstBytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: Binder { value: ConstArgHasType(T/#0, &'static [*mut u8; 3_usize]), bound_vars: [] } + = note: Binder { value: TraitPredicate( as std::marker::Sized>, polarity:Positive), bound_vars: [] } + +error[E0308]: mismatched types + --> $DIR/byte-string-u8-validation.rs:13:16 + | +LL | ConstBytes: Sized; + | ^^^^^^ expected `&[*mut u8; 3]`, found `&[u8; 3]` + | + = note: expected reference `&'static [*mut u8; 3]` + found reference `&'static [u8; 3]` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.rs b/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.rs index 7a31cd40207d..d1658bf20a74 100644 --- a/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.rs +++ b/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.rs @@ -9,5 +9,4 @@ pub fn main() { let _: ConstBytes = ConstBytes::; //~^ ERROR mismatched types //~| ERROR mismatched types - //~| ERROR mismatched types } diff --git a/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.stderr b/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.stderr index 3384a8b385cb..717e680ee536 100644 --- a/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.stderr +++ b/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.stderr @@ -7,17 +7,6 @@ LL | struct ConstBytes; = note: `*mut u8` must implement `ConstParamTy_`, but it does not = note: `[*mut u8; 3]` must implement `ConstParamTy_`, but it does not -error[E0308]: mismatched types - --> $DIR/mismatch-raw-ptr-in-adt.rs:9:33 - | -LL | let _: ConstBytes = ConstBytes::; - | ------------------ ^^^^^^^^^^^^^^^^^^^^ expected `&[65, 65, 65]`, found `&[66, 66, 66]` - | | - | expected due to this - | - = note: expected struct `ConstBytes<&[65, 65, 65]>` - found struct `ConstBytes<&[66, 66, 66]>` - error[E0308]: mismatched types --> $DIR/mismatch-raw-ptr-in-adt.rs:9:46 | @@ -36,7 +25,7 @@ LL | let _: ConstBytes = ConstBytes::; = note: expected reference `&'static [*mut u8; 3]` found reference `&'static [u8; 3]` -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0308, E0741. For more information about an error, try `rustc --explain E0308`. From b725981fe266f483da0232ec9abcce8fe43331df Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Wed, 31 Dec 2025 13:17:55 +0530 Subject: [PATCH 0128/1061] std: sys: fs: uefi: Implement rename - Using the file_name field in `EFI_FILE_INFO` works for renaming, even when changing directories. - Does not work for cross-device rename, but that is already expected behaviour according to the docs: "This will not work if the new name is on a different mount point." - Also add some helper code for dealing with UefiBox. - Tested using OVMF in qemu. Signed-off-by: Ayush Singh --- library/std/src/sys/fs/uefi.rs | 48 ++++++++++++++++---- library/std/src/sys/pal/uefi/helpers.rs | 59 ++++++++++++++++++++++++- 2 files changed, 96 insertions(+), 11 deletions(-) diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index 1c65e3e2b155..b38d86afb093 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -385,8 +385,43 @@ pub fn unlink(p: &Path) -> io::Result<()> { } } -pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { - unsupported() +/// The implementation mirrors `mv` implementation in UEFI shell: +/// https://github.com/tianocore/edk2/blob/66346d5edeac2a00d3cf2f2f3b5f66d423c07b3e/ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c#L455 +/// +/// In a nutshell we do the following: +/// 1. Convert both old and new paths to absolute paths. +/// 2. Check that both lie in the same disk. +/// 3. Construct the target path relative to the current disk root. +/// 4. Set this target path as the file_name in the file_info structure. +pub fn rename(old: &Path, new: &Path) -> io::Result<()> { + let old_absolute = crate::path::absolute(old)?; + let new_absolute = crate::path::absolute(new)?; + + let mut old_components = old_absolute.components(); + let mut new_components = new_absolute.components(); + + let Some(old_disk) = old_components.next() else { + return Err(io::const_error!(io::ErrorKind::InvalidInput, "Old path is not valid")); + }; + let Some(new_disk) = new_components.next() else { + return Err(io::const_error!(io::ErrorKind::InvalidInput, "New path is not valid")); + }; + + // Ensure that paths are on the same device. + if old_disk != new_disk { + return Err(io::const_error!(io::ErrorKind::CrossesDevices, "Cannot rename across device")); + } + + // Construct an path relative the current disk root. + let new_relative = + [crate::path::Component::RootDir].into_iter().chain(new_components).collect::(); + + let f = uefi_fs::File::from_path(old, file::MODE_READ | file::MODE_WRITE, 0)?; + let file_info = f.file_info()?; + + let new_info = file_info.with_file_name(new_relative.as_os_str())?; + + f.set_file_info(new_info) } pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { @@ -751,12 +786,7 @@ mod uefi_fs { } pub(crate) fn file_name_from_uefi(info: &UefiBox) -> OsString { - let file_name = { - let size = unsafe { (*info.as_ptr()).size }; - let strlen = (size as usize - crate::mem::size_of::>() - 1) / 2; - unsafe { crate::slice::from_raw_parts((*info.as_ptr()).file_name.as_ptr(), strlen) } - }; - - OsString::from_wide(file_name) + let fname = info.file_name(); + OsString::from_wide(&fname[..fname.len() - 1]) } } diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs index d059be010e98..10749b5519d6 100644 --- a/library/std/src/sys/pal/uefi/helpers.rs +++ b/library/std/src/sys/pal/uefi/helpers.rs @@ -10,7 +10,7 @@ //! - More information about protocols can be found [here](https://edk2-docs.gitbook.io/edk-ii-uefi-driver-writer-s-guide/3_foundation/36_protocols_and_handles) use r_efi::efi::{self, Guid}; -use r_efi::protocols::{device_path, device_path_to_text, service_binding, shell}; +use r_efi::protocols::{device_path, device_path_to_text, file, service_binding, shell}; use crate::alloc::Layout; use crate::ffi::{OsStr, OsString}; @@ -787,7 +787,7 @@ impl UefiBox { match NonNull::new(ptr.cast()) { Some(inner) => Ok(Self { inner, size: len }), - None => Err(io::Error::new(io::ErrorKind::OutOfMemory, "Allocation failed")), + None => Err(const_error!(io::ErrorKind::OutOfMemory, "Allocation failed")), } } @@ -814,3 +814,58 @@ impl Drop for UefiBox { unsafe { crate::alloc::dealloc(self.inner.as_ptr().cast(), layout) }; } } + +impl UefiBox { + fn size(&self) -> u64 { + unsafe { (*self.as_ptr()).size } + } + + fn set_size(&mut self, s: u64) { + unsafe { (*self.as_mut_ptr()).size = s } + } + + // Length of string (including NULL), not number of bytes. + fn file_name_len(&self) -> usize { + (self.size() as usize - size_of::>()) / size_of::() + } + + pub(crate) fn file_name(&self) -> &[u16] { + unsafe { + crate::slice::from_raw_parts((*self.as_ptr()).file_name.as_ptr(), self.file_name_len()) + } + } + + fn file_name_mut(&mut self) -> &mut [u16] { + unsafe { + crate::slice::from_raw_parts_mut( + (*self.as_mut_ptr()).file_name.as_mut_ptr(), + self.file_name_len(), + ) + } + } + + pub(crate) fn with_file_name(mut self, name: &OsStr) -> io::Result { + // os_string_to_raw returns NULL terminated string. So no need to handle it separately. + let fname = os_string_to_raw(name) + .ok_or(const_error!(io::ErrorKind::OutOfMemory, "Allocation failed"))?; + let new_size = size_of::>() + fname.len() * size_of::(); + + // Reuse the current structure if the new name can fit in it. + if self.size() >= new_size as u64 { + self.file_name_mut()[..fname.len()].copy_from_slice(&fname); + self.set_size(new_size as u64); + + return Ok(self); + } + + let mut new_box = UefiBox::new(new_size)?; + + unsafe { + crate::ptr::copy_nonoverlapping(self.as_ptr(), new_box.as_mut_ptr(), 1); + } + new_box.set_size(new_size as u64); + new_box.file_name_mut().copy_from_slice(&fname); + + Ok(new_box) + } +} From 80acf74fb6f5e8a101dddb33973b559ccfb76ecb Mon Sep 17 00:00:00 2001 From: Ryan Ward Date: Thu, 1 Jan 2026 21:54:07 +1030 Subject: [PATCH 0129/1061] test: added codegen tests for permutations of `Option::or` --- .../issues/multiple-option-or-permutations.rs | 155 ++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 tests/codegen-llvm/issues/multiple-option-or-permutations.rs diff --git a/tests/codegen-llvm/issues/multiple-option-or-permutations.rs b/tests/codegen-llvm/issues/multiple-option-or-permutations.rs new file mode 100644 index 000000000000..0106517c6fd5 --- /dev/null +++ b/tests/codegen-llvm/issues/multiple-option-or-permutations.rs @@ -0,0 +1,155 @@ +// Tests output of multiple permutations of `Option::or` +//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled + +#![crate_type = "lib"] + +// CHECK-LABEL: @or_match_u8 +#[no_mangle] +pub fn or_match_u8(opta: Option, optb: Option) -> Option { + // CHECK: start: + // CHECK-NEXT: or i1 %0 + // CHECK-NEXT: select i1 %0 + // CHECK-NEXT: insertvalue { i1, i8 } + // CHECK-NEXT: insertvalue { i1, i8 } + // ret { i1, i8 } + match opta { + Some(x) => Some(x), + None => optb, + } +} + +// CHECK-LABEL: @or_match_alt_u8 +#[no_mangle] +pub fn or_match_alt_u8(opta: Option, optb: Option) -> Option { + // CHECK: start: + // CHECK-NEXT: select i1 + // CHECK-NEXT: or i1 + // CHECK-NEXT: insertvalue { i1, i8 } + // CHECK-NEXT: insertvalue { i1, i8 } + // ret { i1, i8 } + match opta { + Some(_) => opta, + None => optb, + } +} + +// CHECK-LABEL: @option_or_u8 +#[no_mangle] +pub fn option_or_u8(opta: Option, optb: Option) -> Option { + // CHECK: start: + // CHECK-NEXT: select i1 + // CHECK-NEXT: or i1 + // CHECK-NEXT: insertvalue { i1, i8 } + // CHECK-NEXT: insertvalue { i1, i8 } + // ret { i1, i8 } + opta.or(optb) +} + +// CHECK-LABEL: @if_some_u8 +#[no_mangle] +pub fn if_some_u8(opta: Option, optb: Option) -> Option { + // CHECK: start: + // CHECK-NEXT: select i1 + // CHECK-NEXT: or i1 + // CHECK-NEXT: insertvalue { i1, i8 } + // CHECK-NEXT: insertvalue { i1, i8 } + // ret { i1, i8 } + if opta.is_some() { opta } else { optb } +} + +// CHECK-LABEL: @or_match_slice_u8 +#[no_mangle] +pub fn or_match_slice_u8(opta: Option<[u8; 1]>, optb: Option<[u8; 1]>) -> Option<[u8; 1]> { + // CHECK: start: + // CHECK-NEXT: trunc i16 %0 to i1 + // CHECK-NEXT: select i1 %2, i16 %0, i16 %1 + // ret i16 + match opta { + Some(x) => Some(x), + None => optb, + } +} + +// CHECK-LABEL: @or_match_slice_alt_u8 +#[no_mangle] +pub fn or_match_slice_alt_u8(opta: Option<[u8; 1]>, optb: Option<[u8; 1]>) -> Option<[u8; 1]> { + // CHECK: start: + // CHECK-NEXT: trunc i16 %0 to i1 + // CHECK-NEXT: select i1 %2, i16 %0, i16 %1 + // ret i16 + match opta { + Some(_) => opta, + None => optb, + } +} + +// CHECK-LABEL: @option_or_slice_u8 +#[no_mangle] +pub fn option_or_slice_u8(opta: Option<[u8; 1]>, optb: Option<[u8; 1]>) -> Option<[u8; 1]> { + // CHECK: start: + // CHECK-NEXT: trunc i16 %0 to i1 + // CHECK-NEXT: select i1 %2, i16 %0, i16 %1 + // ret i16 + opta.or(optb) +} + +// CHECK-LABEL: @if_some_slice_u8 +#[no_mangle] +pub fn if_some_slice_u8(opta: Option<[u8; 1]>, optb: Option<[u8; 1]>) -> Option<[u8; 1]> { + // CHECK: start: + // CHECK-NEXT: trunc i16 %0 to i1 + // CHECK-NEXT: select i1 %2, i16 %0, i16 %1 + // ret i16 + if opta.is_some() { opta } else { optb } +} + +pub struct Test { + _a: u8, + _b: u8, +} + +// CHECK-LABEL: @or_match_type +#[no_mangle] +pub fn or_match_type(opta: Option, optb: Option) -> Option { + // CHECK: start: + // CHECK-NEXT: trunc i24 %0 to i1 + // CHECK-NEXT: select i1 %2, i24 %0, i24 %1 + // ret i24 + match opta { + Some(x) => Some(x), + None => optb, + } +} + +// CHECK-LABEL: @or_match_alt_type +#[no_mangle] +pub fn or_match_alt_type(opta: Option, optb: Option) -> Option { + // CHECK: start: + // CHECK-NEXT: trunc i24 %0 to i1 + // CHECK-NEXT: select i1 %2, i24 %0, i24 %1 + // ret i24 + match opta { + Some(_) => opta, + None => optb, + } +} + +// CHECK-LABEL: @option_or_type +#[no_mangle] +pub fn option_or_type(opta: Option, optb: Option) -> Option { + // CHECK: start: + // CHECK-NEXT: trunc i24 %0 to i1 + // CHECK-NEXT: select i1 %2, i24 %0, i24 %1 + // ret i24 + opta.or(optb) +} + +// CHECK-LABEL: @if_some_type +#[no_mangle] +pub fn if_some_type(opta: Option, optb: Option) -> Option { + // CHECK: start: + // CHECK-NEXT: trunc i24 %0 to i1 + // CHECK-NEXT: select i1 %2, i24 %0, i24 %1 + // ret i24 + if opta.is_some() { opta } else { optb } +} From f89cce3acb5106b98f6ada765677dc11e41518a0 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 17 Dec 2025 14:33:10 +0100 Subject: [PATCH 0130/1061] `c_variadic`: provide `va_arg` for more targets --- compiler/rustc_codegen_llvm/src/va_arg.rs | 106 +++++++++++++++++----- 1 file changed, 83 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index b23415a732cc..688f461e7478 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -1,12 +1,13 @@ -use rustc_abi::{Align, BackendRepr, Endian, HasDataLayout, Primitive, Size, TyAndLayout}; +use rustc_abi::{Align, BackendRepr, Endian, HasDataLayout, Primitive, Size}; use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::common::IntPredicate; use rustc_codegen_ssa::mir::operand::OperandRef; use rustc_codegen_ssa::traits::{ BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods, LayoutTypeCodegenMethods, }; +use rustc_middle::bug; use rustc_middle::ty::Ty; -use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; +use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; use rustc_target::spec::{Abi, Arch, Env}; use crate::builder::Builder; @@ -82,6 +83,7 @@ enum PassMode { enum SlotSize { Bytes8 = 8, Bytes4 = 4, + Bytes1 = 1, } enum AllowHigherAlign { @@ -728,7 +730,7 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>( fn copy_to_temporary_if_more_aligned<'ll, 'tcx>( bx: &mut Builder<'_, 'll, 'tcx>, reg_addr: &'ll Value, - layout: TyAndLayout<'tcx, Ty<'tcx>>, + layout: TyAndLayout<'tcx>, src_align: Align, ) -> &'ll Value { if layout.layout.align.abi > src_align { @@ -751,7 +753,7 @@ fn copy_to_temporary_if_more_aligned<'ll, 'tcx>( fn x86_64_sysv64_va_arg_from_memory<'ll, 'tcx>( bx: &mut Builder<'_, 'll, 'tcx>, va_list_addr: &'ll Value, - layout: TyAndLayout<'tcx, Ty<'tcx>>, + layout: TyAndLayout<'tcx>, ) -> &'ll Value { let dl = bx.cx.data_layout(); let ptr_align_abi = dl.data_layout().pointer_align().abi; @@ -1003,15 +1005,17 @@ fn emit_xtensa_va_arg<'ll, 'tcx>( return bx.load(layout.llvm_type(bx), value_ptr, layout.align.abi); } +/// Determine the va_arg implementation to use. The LLVM va_arg instruction +/// is lacking in some instances, so we should only use it as a fallback. pub(super) fn emit_va_arg<'ll, 'tcx>( bx: &mut Builder<'_, 'll, 'tcx>, addr: OperandRef<'tcx, &'ll Value>, target_ty: Ty<'tcx>, ) -> &'ll Value { - // Determine the va_arg implementation to use. The LLVM va_arg instruction - // is lacking in some instances, so we should only use it as a fallback. - let target = &bx.cx.tcx.sess.target; + let layout = bx.cx.layout_of(target_ty); + let target_ty_size = layout.layout.size().bytes(); + let target = &bx.cx.tcx.sess.target; match target.arch { Arch::X86 => emit_ptr_va_arg( bx, @@ -1069,23 +1073,79 @@ pub(super) fn emit_va_arg<'ll, 'tcx>( AllowHigherAlign::Yes, ForceRightAdjust::No, ), + Arch::LoongArch32 => emit_ptr_va_arg( + bx, + addr, + target_ty, + if target_ty_size > 2 * 4 { PassMode::Indirect } else { PassMode::Direct }, + SlotSize::Bytes4, + AllowHigherAlign::Yes, + ForceRightAdjust::No, + ), + Arch::LoongArch64 => emit_ptr_va_arg( + bx, + addr, + target_ty, + if target_ty_size > 2 * 8 { PassMode::Indirect } else { PassMode::Direct }, + SlotSize::Bytes8, + AllowHigherAlign::Yes, + ForceRightAdjust::No, + ), + Arch::AmdGpu => emit_ptr_va_arg( + bx, + addr, + target_ty, + PassMode::Direct, + SlotSize::Bytes4, + AllowHigherAlign::No, + ForceRightAdjust::No, + ), + Arch::Nvptx64 => emit_ptr_va_arg( + bx, + addr, + target_ty, + PassMode::Direct, + SlotSize::Bytes1, + AllowHigherAlign::Yes, + ForceRightAdjust::No, + ), + Arch::Wasm32 => emit_ptr_va_arg( + bx, + addr, + target_ty, + if layout.is_aggregate() || layout.is_zst() || layout.is_1zst() { + PassMode::Indirect + } else { + PassMode::Direct + }, + SlotSize::Bytes4, + AllowHigherAlign::Yes, + ForceRightAdjust::No, + ), + Arch::Wasm64 => bug!("c-variadic functions are not fully implemented for wasm64"), + Arch::CSky => emit_ptr_va_arg( + bx, + addr, + target_ty, + PassMode::Direct, + SlotSize::Bytes4, + AllowHigherAlign::Yes, + ForceRightAdjust::No, + ), // Windows x86_64 - Arch::X86_64 if target.is_like_windows => { - let target_ty_size = bx.cx.size_of(target_ty).bytes(); - emit_ptr_va_arg( - bx, - addr, - target_ty, - if target_ty_size > 8 || !target_ty_size.is_power_of_two() { - PassMode::Indirect - } else { - PassMode::Direct - }, - SlotSize::Bytes8, - AllowHigherAlign::No, - ForceRightAdjust::No, - ) - } + Arch::X86_64 if target.is_like_windows => emit_ptr_va_arg( + bx, + addr, + target_ty, + if target_ty_size > 8 || !target_ty_size.is_power_of_two() { + PassMode::Indirect + } else { + PassMode::Direct + }, + SlotSize::Bytes8, + AllowHigherAlign::No, + ForceRightAdjust::No, + ), // This includes `target.is_like_darwin`, which on x86_64 targets is like sysv64. Arch::X86_64 => emit_x86_64_sysv64_va_arg(bx, addr, target_ty), Arch::Xtensa => emit_xtensa_va_arg(bx, addr, target_ty), From 6453a17534cca0089e9711cce8f6799a8433713a Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 18 Dec 2025 14:11:08 +0100 Subject: [PATCH 0131/1061] add `vpdpbusd` avx512 intrinsic --- src/tools/miri/src/shims/x86/avx512.rs | 58 +++++++++++ .../pass/shims/x86/intrinsics-x86-avx512.rs | 99 ++++++++++++++++++- 2 files changed, 156 insertions(+), 1 deletion(-) diff --git a/src/tools/miri/src/shims/x86/avx512.rs b/src/tools/miri/src/shims/x86/avx512.rs index a886f5622ced..0466ba1bd6c0 100644 --- a/src/tools/miri/src/shims/x86/avx512.rs +++ b/src/tools/miri/src/shims/x86/avx512.rs @@ -109,8 +109,66 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { pshufb(this, left, right, dest)?; } + + // Used to implement the _mm512_dpbusd_epi32 function. + "vpdpbusd.512" | "vpdpbusd.256" | "vpdpbusd.128" => { + this.expect_target_feature_for_intrinsic(link_name, "avx512vnni")?; + if matches!(unprefixed_name, "vpdpbusd.128" | "vpdpbusd.256") { + this.expect_target_feature_for_intrinsic(link_name, "avx512vl")?; + } + + let [src, a, b] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + + vpdpbusd(this, src, a, b, dest)?; + } _ => return interp_ok(EmulateItemResult::NotSupported), } interp_ok(EmulateItemResult::NeedsReturn) } } + +/// Multiply groups of 4 adjacent pairs of unsigned 8-bit integers in `a` with corresponding signed +/// 8-bit integers in `b`, producing 4 intermediate signed 16-bit results. Sum these 4 results with +/// the corresponding 32-bit integer in `src` (using wrapping arighmetic), and store the packed +/// 32-bit results in `dst`. +/// +/// +/// +/// +fn vpdpbusd<'tcx>( + ecx: &mut crate::MiriInterpCx<'tcx>, + src: &OpTy<'tcx>, + a: &OpTy<'tcx>, + b: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, +) -> InterpResult<'tcx, ()> { + let (src, src_len) = ecx.project_to_simd(src)?; + let (a, a_len) = ecx.project_to_simd(a)?; + let (b, b_len) = ecx.project_to_simd(b)?; + let (dest, dest_len) = ecx.project_to_simd(dest)?; + + // fn vpdpbusd(src: i32x16, a: i32x16, b: i32x16) -> i32x16; + // fn vpdpbusd256(src: i32x8, a: i32x8, b: i32x8) -> i32x8; + // fn vpdpbusd128(src: i32x4, a: i32x4, b: i32x4) -> i32x4; + assert_eq!(dest_len, src_len); + assert_eq!(dest_len, a_len); + assert_eq!(dest_len, b_len); + + for i in 0..dest_len { + let src = ecx.read_scalar(&ecx.project_index(&src, i)?)?.to_i32()?; + let a = ecx.read_scalar(&ecx.project_index(&a, i)?)?.to_u32()?; + let b = ecx.read_scalar(&ecx.project_index(&b, i)?)?.to_u32()?; + let dest = ecx.project_index(&dest, i)?; + + let zipped = a.to_le_bytes().into_iter().zip(b.to_le_bytes()); + let intermediate_sum: i32 = zipped + .map(|(a, b)| i32::from(a).strict_mul(i32::from(b.cast_signed()))) + .fold(0, |x, y| x.strict_add(y)); + + // Use `wrapping_add` because `src` is an arbitrary i32 and the addition can overflow. + let res = Scalar::from_i32(intermediate_sum.wrapping_add(src)); + ecx.write_scalar(res, &dest)?; + } + + interp_ok(()) +} diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs index f95429d59ebe..42acb6c3fb37 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs @@ -1,6 +1,6 @@ // We're testing x86 target specific features //@only-target: x86_64 i686 -//@compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bitalg,+avx512vpopcntdq +//@compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bitalg,+avx512vpopcntdq,+avx512vnni #[cfg(target_arch = "x86")] use std::arch::x86::*; @@ -13,12 +13,14 @@ fn main() { assert!(is_x86_feature_detected!("avx512vl")); assert!(is_x86_feature_detected!("avx512bitalg")); assert!(is_x86_feature_detected!("avx512vpopcntdq")); + assert!(is_x86_feature_detected!("avx512vnni")); unsafe { test_avx512(); test_avx512bitalg(); test_avx512vpopcntdq(); test_avx512ternarylogic(); + test_avx512vnni(); } } @@ -411,6 +413,101 @@ unsafe fn test_avx512ternarylogic() { test_mm_ternarylogic_epi32(); } +#[target_feature(enable = "avx512vnni")] +unsafe fn test_avx512vnni() { + #[target_feature(enable = "avx512vnni")] + unsafe fn test_mm512_dpbusd_epi32() { + const SRC: [i32; 16] = [ + 1, + // Test that addition with the `src` element uses wrapping arithmetic. + i32::MAX, + i32::MIN, + 0, + 0, + 7, + 12345, + -9876, + 0x01020304, + -1, + 42, + 0, + 1_000_000_000, + -1_000_000_000, + 17, + -17, + ]; + + // The `A` array must be interpreted as a sequence of unsigned 8-bit integers. Setting + // the high bit of a byte tests that this is implemented correctly. + const A: [i32; 16] = [ + 0x01010101, + i32::from_le_bytes([1; 4]), + i32::from_le_bytes([1; 4]), + i32::from_le_bytes([u8::MAX; 4]), + i32::from_le_bytes([u8::MAX; 4]), + 0x02_80_01_FF, + 0x00_FF_00_FF, + 0x7F_80_FF_01, + 0x10_20_30_40, + 0xDE_AD_BE_EFu32 as i32, + 0x00_00_00_FF, + 0x12_34_56_78, + 0xFF_00_FF_00u32 as i32, + 0x01_02_03_04, + 0xAA_55_AA_55u32 as i32, + 0x11_22_33_44, + ]; + + // The `B` array must be interpreted as a sequence of signed 8-bit integers. Setting + // the high bit of a byte tests that this is implemented correctly. + const B: [i32; 16] = [ + 0x01010101, + i32::from_le_bytes([1; 4]), + i32::from_le_bytes([(-1i8).cast_unsigned(); 4]), + i32::from_le_bytes([i8::MAX.cast_unsigned(); 4]), + i32::from_le_bytes([i8::MIN.cast_unsigned(); 4]), + 0xFF_01_80_7Fu32 as i32, + 0x01_FF_01_FF, + 0x80_7F_00_FFu32 as i32, + 0x7F_01_FF_80u32 as i32, + 0x01_02_03_04, + 0xFF_FF_FF_FFu32 as i32, + 0x80_00_7F_FFu32 as i32, + 0x7F_80_7F_80u32 as i32, + 0x40_C0_20_E0u32 as i32, + 0x00_01_02_03, + 0x7F_7E_80_81u32 as i32, + ]; + + const DST: [i32; 16] = [ + 5, + i32::MAX.wrapping_add(4), + i32::MIN.wrapping_add(-4), + 129540, + -130560, + 32390, + 11835, + -9877, + 16902884, + 2093, + -213, + 8498, + 1000064770, + -1000000096, + 697, + -8738, + ]; + + let src = _mm512_loadu_si512(SRC.as_ptr().cast::<__m512i>()); + let a = _mm512_loadu_si512(A.as_ptr().cast::<__m512i>()); + let b = _mm512_loadu_si512(B.as_ptr().cast::<__m512i>()); + let dst = _mm512_loadu_si512(DST.as_ptr().cast::<__m512i>()); + + assert_eq_m512i(_mm512_dpbusd_epi32(src, a, b), dst); + } + test_mm512_dpbusd_epi32(); +} + #[track_caller] unsafe fn assert_eq_m512i(a: __m512i, b: __m512i) { assert_eq!(transmute::<_, [i32; 16]>(a), transmute::<_, [i32; 16]>(b)) From a390881bde042f39c12001044c7476545abcb390 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Thu, 1 Jan 2026 14:46:16 +0100 Subject: [PATCH 0132/1061] Do not make suggestion machine-applicable if it may change semantics When suggesting to replace an iterator method by `.all()` or `.any()`, make the suggestion at most `MaybeIncorrect` instead of `MachineApplicable` and warn about the fact that semantics may change because those two methods are short-circuiting. --- clippy_lints/src/methods/unnecessary_fold.rs | 108 ++++++++++++------- tests/ui/unnecessary_fold.stderr | 7 ++ 2 files changed, 77 insertions(+), 38 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index 9dae6fbb48dd..7802763ef74a 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -1,10 +1,10 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath, MaybeTypeckRes}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{DefinedTy, ExprUseNode, expr_use_ctxt, peel_blocks, strip_pat_refs}; use rustc_ast::ast; use rustc_data_structures::packed::Pu128; -use rustc_errors::Applicability; +use rustc_errors::{Applicability, Diag}; use rustc_hir as hir; use rustc_hir::PatKind; use rustc_hir::def::{DefKind, Res}; @@ -59,6 +59,34 @@ struct Replacement { method_name: &'static str, has_args: bool, has_generic_return: bool, + is_short_circuiting: bool, +} + +impl Replacement { + fn default_applicability(&self) -> Applicability { + if self.is_short_circuiting { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + } + } + + fn maybe_add_note(&self, diag: &mut Diag<'_, ()>) { + if self.is_short_circuiting { + diag.note(format!( + "the `{}` method is short circuiting and may change the program semantics if the iterator has side effects", + self.method_name + )); + } + } + + fn maybe_turbofish(&self, ty: Ty<'_>) -> String { + if self.has_generic_return { + format!("::<{ty}>") + } else { + String::new() + } + } } fn check_fold_with_op( @@ -86,32 +114,29 @@ fn check_fold_with_op( && left_expr.res_local_id() == Some(first_arg_id) && (replacement.has_args || right_expr.res_local_id() == Some(second_arg_id)) { - let mut applicability = Applicability::MachineApplicable; - - let turbofish = if replacement.has_generic_return { - format!("::<{}>", cx.typeck_results().expr_ty_adjusted(right_expr).peel_refs()) - } else { - String::new() - }; - - let sugg = if replacement.has_args { - format!( - "{method}{turbofish}(|{second_arg_ident}| {r})", - method = replacement.method_name, - r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability), - ) - } else { - format!("{method}{turbofish}()", method = replacement.method_name) - }; - - span_lint_and_sugg( + let span = fold_span.with_hi(expr.span.hi()); + span_lint_and_then( cx, UNNECESSARY_FOLD, - fold_span.with_hi(expr.span.hi()), + span, "this `.fold` can be written more succinctly using another method", - "try", - sugg, - applicability, + |diag| { + let mut applicability = replacement.default_applicability(); + let turbofish = + replacement.maybe_turbofish(cx.typeck_results().expr_ty_adjusted(right_expr).peel_refs()); + let sugg = if replacement.has_args { + format!( + "{method}{turbofish}(|{second_arg_ident}| {r})", + method = replacement.method_name, + r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability), + ) + } else { + format!("{method}{turbofish}()", method = replacement.method_name) + }; + + diag.span_suggestion(span, "try", sugg, applicability); + replacement.maybe_add_note(diag); + }, ); return true; } @@ -131,22 +156,25 @@ fn check_fold_with_method( // Check if the function belongs to the operator && cx.tcx.is_diagnostic_item(method, fn_did) { - let applicability = Applicability::MachineApplicable; - - let turbofish = if replacement.has_generic_return { - format!("::<{}>", cx.typeck_results().expr_ty(expr)) - } else { - String::new() - }; - - span_lint_and_sugg( + let span = fold_span.with_hi(expr.span.hi()); + span_lint_and_then( cx, UNNECESSARY_FOLD, - fold_span.with_hi(expr.span.hi()), + span, "this `.fold` can be written more succinctly using another method", - "try", - format!("{method}{turbofish}()", method = replacement.method_name), - applicability, + |diag| { + diag.span_suggestion( + span, + "try", + format!( + "{method}{turbofish}()", + method = replacement.method_name, + turbofish = replacement.maybe_turbofish(cx.typeck_results().expr_ty(expr)) + ), + replacement.default_applicability(), + ); + replacement.maybe_add_note(diag); + }, ); } } @@ -171,6 +199,7 @@ pub(super) fn check<'tcx>( method_name: "any", has_args: true, has_generic_return: false, + is_short_circuiting: true, }; check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, replacement); }, @@ -179,6 +208,7 @@ pub(super) fn check<'tcx>( method_name: "all", has_args: true, has_generic_return: false, + is_short_circuiting: true, }; check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, replacement); }, @@ -187,6 +217,7 @@ pub(super) fn check<'tcx>( method_name: "sum", has_args: false, has_generic_return: needs_turbofish(cx, expr), + is_short_circuiting: false, }; if !check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, replacement) { check_fold_with_method(cx, expr, acc, fold_span, sym::add, replacement); @@ -197,6 +228,7 @@ pub(super) fn check<'tcx>( method_name: "product", has_args: false, has_generic_return: needs_turbofish(cx, expr), + is_short_circuiting: false, }; if !check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, replacement) { check_fold_with_method(cx, expr, acc, fold_span, sym::mul, replacement); diff --git a/tests/ui/unnecessary_fold.stderr b/tests/ui/unnecessary_fold.stderr index bb8aa7e18d34..025a2bd0048b 100644 --- a/tests/ui/unnecessary_fold.stderr +++ b/tests/ui/unnecessary_fold.stderr @@ -4,6 +4,7 @@ error: this `.fold` can be written more succinctly using another method LL | let _ = (0..3).fold(false, |acc, x| acc || x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)` | + = note: the `any` method is short circuiting and may change the program semantics if the iterator has side effects = note: `-D clippy::unnecessary-fold` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_fold)]` @@ -21,6 +22,8 @@ error: this `.fold` can be written more succinctly using another method | LL | let _ = (0..3).fold(true, |acc, x| acc && x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `all(|x| x > 2)` + | + = note: the `all` method is short circuiting and may change the program semantics if the iterator has side effects error: this `.fold` can be written more succinctly using another method --> tests/ui/unnecessary_fold.rs:24:25 @@ -63,12 +66,16 @@ error: this `.fold` can be written more succinctly using another method | LL | let _: bool = (0..3).map(|x| 2 * x).fold(false, |acc, x| acc || x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)` + | + = note: the `any` method is short circuiting and may change the program semantics if the iterator has side effects error: this `.fold` can be written more succinctly using another method --> tests/ui/unnecessary_fold.rs:110:10 | LL | .fold(false, |acc, x| acc || x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)` + | + = note: the `any` method is short circuiting and may change the program semantics if the iterator has side effects error: this `.fold` can be written more succinctly using another method --> tests/ui/unnecessary_fold.rs:123:33 From c71381f55f2cb7431b368142f96ce5d048da7324 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 2 Jan 2026 00:38:22 +0800 Subject: [PATCH 0133/1061] triagebot: remove `compiler-errors` triagebot entries Since they became alumni and don't want to receive pings anymore. --- triagebot.toml | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index de9ac961dc8c..4364bf3bdc52 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -954,15 +954,15 @@ cc = ["@lcnr"] [mentions."compiler/rustc_middle/src/ty/relate.rs"] message = "changes to the core type system" -cc = ["@compiler-errors", "@lcnr"] +cc = ["@lcnr"] [mentions."compiler/rustc_infer/src/infer/relate"] message = "changes to the core type system" -cc = ["@compiler-errors", "@lcnr"] +cc = ["@lcnr"] [mentions."compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs"] message = "changes to `inspect_obligations.rs`" -cc = ["@compiler-errors", "@lcnr"] +cc = ["@lcnr"] [mentions."compiler/rustc_middle/src/mir/interpret"] message = "Some changes occurred to the CTFE / Miri interpreter" @@ -974,7 +974,7 @@ cc = ["@rust-lang/wg-mir-opt"] [mentions."compiler/rustc_trait_selection/src/traits/wf.rs"] message = "changes to the core type system" -cc = ["@compiler-errors", "@lcnr"] +cc = ["@lcnr"] [mentions."compiler/rustc_trait_selection/src/traits/const_evaluatable.rs"] message = "Some changes occurred in `const_evaluatable.rs`" @@ -997,7 +997,7 @@ message = """ Some changes occurred in engine.rs, potentially modifying the public API \ of `ObligationCtxt`. """ -cc = ["@lcnr", "@compiler-errors"] +cc = ["@lcnr"] [mentions."compiler/rustc_hir_analysis/src/hir_ty_lowering"] message = "HIR ty lowering was modified" @@ -1146,7 +1146,7 @@ cc = ["@oli-obk", "@RalfJung", "@JakobDegen", "@vakaras"] [mentions."compiler/rustc_error_messages"] message = "`rustc_error_messages` was changed" -cc = ["@davidtwco", "@compiler-errors", "@TaKO8Ki"] +cc = ["@davidtwco", "@TaKO8Ki"] [mentions."compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs"] message = "`rustc_errors::annotate_snippet_emitter_writer` was changed" @@ -1158,11 +1158,11 @@ cc = ["@Muscraft"] [mentions."compiler/rustc_errors/src/translation.rs"] message = "`rustc_errors::translation` was changed" -cc = ["@davidtwco", "@compiler-errors", "@TaKO8Ki"] +cc = ["@davidtwco", "@TaKO8Ki"] [mentions."compiler/rustc_macros/src/diagnostics"] message = "`rustc_macros::diagnostics` was changed" -cc = ["@davidtwco", "@compiler-errors", "@TaKO8Ki"] +cc = ["@davidtwco", "@TaKO8Ki"] [mentions."compiler/rustc_public"] message = "This PR changes rustc_public" @@ -1427,7 +1427,6 @@ compiler_leads = [ compiler = [ "@BoxyUwU", "@chenyukang", - "@compiler-errors", "@davidtwco", "@eholk", "@fee1-dead", @@ -1486,13 +1485,11 @@ incremental = [ "@wesleywiser", ] diagnostics = [ - "@compiler-errors", "@davidtwco", "@oli-obk", "@chenyukang", ] parser = [ - "@compiler-errors", "@davidtwco", "@nnethercote", "@petrochenkov", @@ -1518,7 +1515,6 @@ mir-opt = [ "@saethlin", ] types = [ - "@compiler-errors", "@jackh726", "@lcnr", "@oli-obk", @@ -1530,7 +1526,6 @@ borrowck = [ "@matthewjasper" ] ast_lowering = [ - "@compiler-errors", "@spastorino", ] debuginfo = [ @@ -1545,7 +1540,6 @@ style-team = [ "@traviscross", ] project-const-traits = [ - "@compiler-errors", "@fee1-dead", "@fmease", "@oli-obk", @@ -1639,7 +1633,7 @@ dep-bumps = [ "/tests/rustdoc-ui" = ["rustdoc"] "/tests/ui" = ["compiler"] "/src/tools/cargo" = ["@ehuss"] -"/src/tools/compiletest" = ["bootstrap", "@wesleywiser", "@oli-obk", "@compiler-errors", "@jieyouxu"] +"/src/tools/compiletest" = ["bootstrap", "@wesleywiser", "@oli-obk", "@jieyouxu"] "/src/tools/linkchecker" = ["@ehuss"] "/src/tools/opt-dist" = ["@kobzol"] "/src/tools/run-make-support" = ["@jieyouxu"] From d7f3c3995c3f0dd70a8babd5a843d057bf4a3c7f Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 2 Jan 2026 00:39:46 +0800 Subject: [PATCH 0134/1061] triagebot: expand eligible reviewer pool for `tests/{run-make,run-make-cargo}` to `compiler` So that I don't become the only automatically-assigned reviewer due to weighting reasons. --- triagebot.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index 4364bf3bdc52..161a339cdb12 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1623,8 +1623,8 @@ dep-bumps = [ "/src/llvm-project" = ["@cuviper"] "/src/rustdoc-json-types" = ["rustdoc"] "/src/stage0" = ["bootstrap"] -"/tests/run-make" = ["@jieyouxu"] -"/tests/run-make-cargo" = ["@jieyouxu"] +"/tests/run-make" = ["compiler"] +"/tests/run-make-cargo" = ["compiler"] "/tests/rustdoc" = ["rustdoc"] "/tests/rustdoc-gui" = ["rustdoc"] "/tests/rustdoc-js-std" = ["rustdoc"] From f716d6ca972294ca327eb383737e2f6c6ace2fdb Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 2 Jan 2026 00:51:22 +0800 Subject: [PATCH 0135/1061] triagebot: add `jieyouxu` to `fallback` `adhoc_group` So that there's `n > 1` selection pool in case one of the eligible reviewers go off rotation. --- triagebot.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 161a339cdb12..fb6660b9dd03 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1532,7 +1532,8 @@ debuginfo = [ "@davidtwco" ] fallback = [ - "@Mark-Simulacrum" + "@Mark-Simulacrum", + "@jieyouxu", ] style-team = [ "@calebcartwright", From 33add367e2b265f4ed0fcc32e7f795f87992c488 Mon Sep 17 00:00:00 2001 From: Flakebi Date: Thu, 1 Jan 2026 18:34:24 +0100 Subject: [PATCH 0136/1061] Add checks for gpu-kernel calling conv The `gpu-kernel` calling convention has several restrictions that were not enforced by the compiler until now. Add the following restrictions: 1. Cannot be async 2. Cannot be called 3. Cannot return values, return type must be `()` or `!` 4. Arguments should be primitives, i.e. passed by value. More complicated types can work when you know what you are doing, but it is rather unintuitive, one needs to know ABI/compiler internals. 5. Export name should be unmangled, either through `no_mangle` or `export_name`. Kernels are searched by name on the CPU side, having a mangled name makes it hard to find and probably almost always unintentional. --- compiler/rustc_abi/src/extern_abi.rs | 1 - .../rustc_ast_passes/src/ast_validation.rs | 34 +-- compiler/rustc_hir_typeck/messages.ftl | 4 + compiler/rustc_hir_typeck/src/callee.rs | 26 +-- compiler/rustc_hir_typeck/src/errors.rs | 8 + compiler/rustc_lint/messages.ftl | 7 + compiler/rustc_lint/src/gpukernel_abi.rs | 194 ++++++++++++++++++ compiler/rustc_lint/src/lib.rs | 3 + compiler/rustc_lint/src/lints.rs | 13 ++ tests/ui/abi/cannot-be-called.amdgpu.stderr | 87 ++++++++ tests/ui/abi/cannot-be-called.avr.stderr | 38 ++-- tests/ui/abi/cannot-be-called.i686.stderr | 38 ++-- tests/ui/abi/cannot-be-called.msp430.stderr | 38 ++-- tests/ui/abi/cannot-be-called.nvptx.stderr | 87 ++++++++ tests/ui/abi/cannot-be-called.riscv32.stderr | 42 ++-- tests/ui/abi/cannot-be-called.riscv64.stderr | 42 ++-- tests/ui/abi/cannot-be-called.rs | 39 ++-- tests/ui/abi/cannot-be-called.x64.stderr | 38 ++-- tests/ui/abi/cannot-be-called.x64_win.stderr | 38 ++-- .../ui/abi/cannot-be-coroutine.amdgpu.stderr | 23 +++ tests/ui/abi/cannot-be-coroutine.avr.stderr | 4 +- tests/ui/abi/cannot-be-coroutine.i686.stderr | 4 +- .../ui/abi/cannot-be-coroutine.msp430.stderr | 4 +- tests/ui/abi/cannot-be-coroutine.nvptx.stderr | 23 +++ .../ui/abi/cannot-be-coroutine.riscv32.stderr | 6 +- .../ui/abi/cannot-be-coroutine.riscv64.stderr | 6 +- tests/ui/abi/cannot-be-coroutine.rs | 13 +- tests/ui/abi/cannot-be-coroutine.x64.stderr | 4 +- .../ui/abi/cannot-be-coroutine.x64_win.stderr | 4 +- tests/ui/abi/cannot-return.amdgpu.stderr | 15 ++ tests/ui/abi/cannot-return.nvptx.stderr | 15 ++ tests/ui/abi/cannot-return.rs | 18 ++ tests/ui/lint/lint-gpu-kernel.amdgpu.stderr | 86 ++++++++ tests/ui/lint/lint-gpu-kernel.nvptx.stderr | 86 ++++++++ tests/ui/lint/lint-gpu-kernel.rs | 62 ++++++ 35 files changed, 998 insertions(+), 152 deletions(-) create mode 100644 compiler/rustc_lint/src/gpukernel_abi.rs create mode 100644 tests/ui/abi/cannot-be-called.amdgpu.stderr create mode 100644 tests/ui/abi/cannot-be-called.nvptx.stderr create mode 100644 tests/ui/abi/cannot-be-coroutine.amdgpu.stderr create mode 100644 tests/ui/abi/cannot-be-coroutine.nvptx.stderr create mode 100644 tests/ui/abi/cannot-return.amdgpu.stderr create mode 100644 tests/ui/abi/cannot-return.nvptx.stderr create mode 100644 tests/ui/abi/cannot-return.rs create mode 100644 tests/ui/lint/lint-gpu-kernel.amdgpu.stderr create mode 100644 tests/ui/lint/lint-gpu-kernel.nvptx.stderr create mode 100644 tests/ui/lint/lint-gpu-kernel.rs diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs index 6a5ea36f2a42..e44dea1ce593 100644 --- a/compiler/rustc_abi/src/extern_abi.rs +++ b/compiler/rustc_abi/src/extern_abi.rs @@ -67,7 +67,6 @@ pub enum ExternAbi { /* gpu */ /// An entry-point function called by the GPU's host - // FIXME: should not be callable from Rust on GPU targets, is for host's use only GpuKernel, /// An entry-point function called by the GPU's host // FIXME: why do we have two of these? diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 0d34ba6c2ca8..3e70687c16d3 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -401,9 +401,16 @@ impl<'a> AstValidator<'a> { | CanonAbi::Rust | CanonAbi::RustCold | CanonAbi::Arm(_) - | CanonAbi::GpuKernel | CanonAbi::X86(_) => { /* nothing to check */ } + CanonAbi::GpuKernel => { + // An `extern "gpu-kernel"` function cannot be `async` and/or `gen`. + self.reject_coroutine(abi, sig); + + // An `extern "gpu-kernel"` function cannot return a value. + self.reject_return(abi, sig); + } + CanonAbi::Custom => { // An `extern "custom"` function must be unsafe. self.reject_safe_fn(abi, ctxt, sig); @@ -433,18 +440,7 @@ impl<'a> AstValidator<'a> { self.dcx().emit_err(errors::AbiX86Interrupt { spans, param_count }); } - if let FnRetTy::Ty(ref ret_ty) = sig.decl.output - && match &ret_ty.kind { - TyKind::Never => false, - TyKind::Tup(tup) if tup.is_empty() => false, - _ => true, - } - { - self.dcx().emit_err(errors::AbiMustNotHaveReturnType { - span: ret_ty.span, - abi, - }); - } + self.reject_return(abi, sig); } else { // An `extern "interrupt"` function must have type `fn()`. self.reject_params_or_return(abi, ident, sig); @@ -496,6 +492,18 @@ impl<'a> AstValidator<'a> { } } + fn reject_return(&self, abi: ExternAbi, sig: &FnSig) { + if let FnRetTy::Ty(ref ret_ty) = sig.decl.output + && match &ret_ty.kind { + TyKind::Never => false, + TyKind::Tup(tup) if tup.is_empty() => false, + _ => true, + } + { + self.dcx().emit_err(errors::AbiMustNotHaveReturnType { span: ret_ty.span, abi }); + } + } + fn reject_params_or_return(&self, abi: ExternAbi, ident: &Ident, sig: &FnSig) { let mut spans: Vec<_> = sig.decl.inputs.iter().map(|p| p.span).collect(); if let FnRetTy::Ty(ref ret_ty) = sig.decl.output diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 325be43a0065..0c4b1f891ead 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -133,6 +133,10 @@ hir_typeck_fru_suggestion = hir_typeck_functional_record_update_on_non_struct = functional record update syntax requires a struct +hir_typeck_gpu_kernel_abi_cannot_be_called = + functions with the "gpu-kernel" ABI cannot be called + .note = an `extern "gpu-kernel"` function must be launched on the GPU by the runtime + hir_typeck_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml` hir_typeck_help_set_edition_standalone = pass `--edition {$edition}` to `rustc` diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 714c6a104a9e..b60d053957a9 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -169,27 +169,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; - let valid = match canon_abi { + match canon_abi { // Rust doesn't know how to call functions with this ABI. - CanonAbi::Custom => false, - - // These is an entry point for the host, and cannot be called on the GPU. - CanonAbi::GpuKernel => false, - + CanonAbi::Custom // The interrupt ABIs should only be called by the CPU. They have complex // pre- and postconditions, and can use non-standard instructions like `iret` on x86. - CanonAbi::Interrupt(_) => false, + | CanonAbi::Interrupt(_) => { + let err = crate::errors::AbiCannotBeCalled { span, abi }; + self.tcx.dcx().emit_err(err); + } + + // This is an entry point for the host, and cannot be called directly. + CanonAbi::GpuKernel => { + let err = crate::errors::GpuKernelAbiCannotBeCalled { span }; + self.tcx.dcx().emit_err(err); + } CanonAbi::C | CanonAbi::Rust | CanonAbi::RustCold | CanonAbi::Arm(_) - | CanonAbi::X86(_) => true, - }; - - if !valid { - let err = crate::errors::AbiCannotBeCalled { span, abi }; - self.tcx.dcx().emit_err(err); + | CanonAbi::X86(_) => {} } } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 620002915fa8..0cf7f09e9376 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -1198,6 +1198,14 @@ pub(crate) struct AbiCannotBeCalled { pub abi: ExternAbi, } +#[derive(Diagnostic)] +#[diag(hir_typeck_gpu_kernel_abi_cannot_be_called)] +pub(crate) struct GpuKernelAbiCannotBeCalled { + #[primary_span] + #[note] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(hir_typeck_const_continue_bad_label)] pub(crate) struct ConstContinueBadLabel { diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 56a0a3ceebf5..2f4537b94da2 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -470,6 +470,9 @@ lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive lint_improper_ctypes_unsafe_binder = unsafe binders are incompatible with foreign function interfaces +lint_improper_gpu_kernel_arg = passing type `{$ty}` to a function with "gpu-kernel" ABI may have unexpected behavior + .help = use primitive types and raw pointers to get reliable behavior + lint_int_to_ptr_transmutes = transmuting an integer to a pointer creates a pointer without provenance .note = this is dangerous because dereferencing the resulting pointer is undefined behavior .note_exposed_provenance = exposed provenance semantics can be used to create a pointer based on some previously exposed provenance @@ -597,6 +600,10 @@ lint_mismatched_lifetime_syntaxes_suggestion_mixed = lint_mismatched_lifetime_syntaxes_suggestion_mixed_only_paths = use `'_` for type paths +lint_missing_gpu_kernel_export_name = function with the "gpu-kernel" ABI has a mangled name + .note = mangled names make it hard to find the kernel, this is usually not intended + .help = use `unsafe(no_mangle)` or `unsafe(export_name = "")` + lint_mixed_script_confusables = the usage of Script Group `{$set}` in this crate consists solely of mixed script confusables .includes_note = the usage includes {$includes} diff --git a/compiler/rustc_lint/src/gpukernel_abi.rs b/compiler/rustc_lint/src/gpukernel_abi.rs new file mode 100644 index 000000000000..dbdf5b6e7955 --- /dev/null +++ b/compiler/rustc_lint/src/gpukernel_abi.rs @@ -0,0 +1,194 @@ +use std::iter; + +use rustc_abi::ExternAbi; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::{self as hir, find_attr}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable}; +use rustc_session::{declare_lint, declare_lint_pass}; +use rustc_span::Span; +use rustc_span::def_id::LocalDefId; + +use crate::lints::{ImproperGpuKernelArg, MissingGpuKernelExportName}; +use crate::{LateContext, LateLintPass, LintContext}; + +declare_lint! { + /// The `improper_gpu_kernel_arg` lint detects incorrect use of types in `gpu-kernel` + /// arguments. + /// + /// ### Example + /// + /// ```rust,ignore (fails on non-GPU targets) + /// #[unsafe(no_mangle)] + /// extern "gpu-kernel" fn kernel(_: [i32; 10]) {} + /// ``` + /// + /// This will produce: + /// + /// ```text + /// warning: passing type `[i32; 10]` to a function with "gpu-kernel" ABI may have unexpected behavior + /// --> t.rs:2:34 + /// | + /// 2 | extern "gpu-kernel" fn kernel(_: [i32; 10]) {} + /// | ^^^^^^^^^ + /// | + /// = help: use primitive types and raw pointers to get reliable behavior + /// = note: `#[warn(improper_gpu_kernel_arg)]` on by default + /// ``` + /// + /// ### Explanation + /// + /// The compiler has several checks to verify that types used as arguments in `gpu-kernel` + /// functions follow certain rules to ensure proper compatibility with the foreign interfaces. + /// This lint is issued when it detects a probable mistake in a signature. + IMPROPER_GPU_KERNEL_ARG, + Warn, + "GPU kernel entry points have a limited ABI" +} + +declare_lint! { + /// The `missing_gpu_kernel_export_name` lint detects `gpu-kernel` functions that have a mangled name. + /// + /// ### Example + /// + /// ```rust,ignore (fails on non-GPU targets) + /// extern "gpu-kernel" fn kernel() { } + /// ``` + /// + /// This will produce: + /// + /// ```text + /// warning: function with the "gpu-kernel" ABI has a mangled name + /// --> t.rs:1:1 + /// | + /// 1 | extern "gpu-kernel" fn kernel() {} + /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + /// | + /// = help: use `unsafe(no_mangle)` or `unsafe(export_name = "")` + /// = note: mangled names make it hard to find the kernel, this is usually not intended + /// = note: `#[warn(missing_gpu_kernel_export_name)]` on by default + /// ``` + /// + /// ### Explanation + /// + /// `gpu-kernel` functions are usually searched by name in the compiled file. + /// A mangled name is usually unintentional as it would need to be searched by the mangled name. + /// + /// To use an unmangled name for the kernel, either `no_mangle` or `export_name` can be used. + /// ```rust,ignore (fails on non-GPU targets) + /// // Can be found by the name "kernel" + /// #[unsafe(no_mangle)] + /// extern "gpu-kernel" fn kernel() { } + /// + /// // Can be found by the name "new_name" + /// #[unsafe(export_name = "new_name")] + /// extern "gpu-kernel" fn other_kernel() { } + /// ``` + MISSING_GPU_KERNEL_EXPORT_NAME, + Warn, + "mangled gpu-kernel function" +} + +declare_lint_pass!(ImproperGpuKernelLint => [ + IMPROPER_GPU_KERNEL_ARG, + MISSING_GPU_KERNEL_EXPORT_NAME, +]); + +/// Check for valid and invalid types. +struct CheckGpuKernelTypes<'tcx> { + tcx: TyCtxt<'tcx>, + // If one or more invalid types were encountered while folding. + has_invalid: bool, +} + +impl<'tcx> TypeFolder> for CheckGpuKernelTypes<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + match ty.kind() { + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => {} + // Thin pointers are allowed but fat pointers with metadata are not + ty::RawPtr(_, _) => { + if !ty.pointee_metadata_ty_or_projection(self.tcx).is_unit() { + self.has_invalid = true; + } + } + + ty::Adt(_, _) + | ty::Alias(_, _) + | ty::Array(_, _) + | ty::Bound(_, _) + | ty::Closure(_, _) + | ty::Coroutine(_, _) + | ty::CoroutineClosure(_, _) + | ty::CoroutineWitness(..) + | ty::Dynamic(_, _) + | ty::FnDef(_, _) + | ty::FnPtr(..) + | ty::Foreign(_) + | ty::Never + | ty::Pat(_, _) + | ty::Placeholder(_) + | ty::Ref(_, _, _) + | ty::Slice(_) + | ty::Str + | ty::Tuple(_) => self.has_invalid = true, + + _ => return ty.super_fold_with(self), + } + ty + } +} + +/// `ImproperGpuKernelLint` checks `gpu-kernel` function definitions: +/// +/// - `extern "gpu-kernel" fn` arguments should be primitive types. +/// - `extern "gpu-kernel" fn` should have an unmangled name. +impl<'tcx> LateLintPass<'tcx> for ImproperGpuKernelLint { + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + kind: hir::intravisit::FnKind<'tcx>, + decl: &'tcx hir::FnDecl<'_>, + _: &'tcx hir::Body<'_>, + span: Span, + id: LocalDefId, + ) { + use hir::intravisit::FnKind; + + let abi = match kind { + FnKind::ItemFn(_, _, header, ..) => header.abi, + FnKind::Method(_, sig, ..) => sig.header.abi, + _ => return, + }; + + if abi != ExternAbi::GpuKernel { + return; + } + + let sig = cx.tcx.fn_sig(id).instantiate_identity(); + let sig = cx.tcx.instantiate_bound_regions_with_erased(sig); + + for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) { + let mut checker = CheckGpuKernelTypes { tcx: cx.tcx, has_invalid: false }; + input_ty.fold_with(&mut checker); + if checker.has_invalid { + cx.tcx.emit_node_span_lint( + IMPROPER_GPU_KERNEL_ARG, + input_hir.hir_id, + input_hir.span, + ImproperGpuKernelArg { ty: *input_ty }, + ); + } + } + + // Check for no_mangle/export_name, so the kernel can be found when querying the compiled object for the kernel function by name + if !find_attr!( + cx.tcx.get_all_attrs(id), + AttributeKind::NoMangle(..) | AttributeKind::ExportName { .. } + ) { + cx.emit_span_lint(MISSING_GPU_KERNEL_EXPORT_NAME, span, MissingGpuKernelExportName); + } + } +} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 49929a0a9bc7..dd2042b57f52 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -47,6 +47,7 @@ mod expect; mod for_loops_over_fallibles; mod foreign_modules; mod function_cast_as_integer; +mod gpukernel_abi; mod if_let_rescope; mod impl_trait_overcaptures; mod interior_mutable_consts; @@ -93,6 +94,7 @@ use drop_forget_useless::*; use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums; use for_loops_over_fallibles::*; use function_cast_as_integer::*; +use gpukernel_abi::*; use if_let_rescope::IfLetRescope; use impl_trait_overcaptures::ImplTraitOvercaptures; use interior_mutable_consts::*; @@ -197,6 +199,7 @@ late_lint_methods!( DerefIntoDynSupertrait: DerefIntoDynSupertrait, DropForgetUseless: DropForgetUseless, ImproperCTypesLint: ImproperCTypesLint, + ImproperGpuKernelLint: ImproperGpuKernelLint, InvalidFromUtf8: InvalidFromUtf8, VariantSizeDifferences: VariantSizeDifferences, PathStatements: PathStatements, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 5017ce7caa52..ba486f95427d 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2008,6 +2008,19 @@ impl<'a> LintDiagnostic<'a, ()> for ImproperCTypes<'_> { } } +#[derive(LintDiagnostic)] +#[diag(lint_improper_gpu_kernel_arg)] +#[help] +pub(crate) struct ImproperGpuKernelArg<'a> { + pub ty: Ty<'a>, +} + +#[derive(LintDiagnostic)] +#[diag(lint_missing_gpu_kernel_export_name)] +#[help] +#[note] +pub(crate) struct MissingGpuKernelExportName; + #[derive(LintDiagnostic)] #[diag(lint_variant_size_differences)] pub(crate) struct VariantSizeDifferencesDiag { diff --git a/tests/ui/abi/cannot-be-called.amdgpu.stderr b/tests/ui/abi/cannot-be-called.amdgpu.stderr new file mode 100644 index 000000000000..039e2d7b4f00 --- /dev/null +++ b/tests/ui/abi/cannot-be-called.amdgpu.stderr @@ -0,0 +1,87 @@ +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:43:8 + | +LL | extern "msp430-interrupt" fn msp430() {} + | ^^^^^^^^^^^^^^^^^^ + +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:45:8 + | +LL | extern "avr-interrupt" fn avr() {} + | ^^^^^^^^^^^^^^^ + +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:47:8 + | +LL | extern "riscv-interrupt-m" fn riscv_m() {} + | ^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:49:8 + | +LL | extern "riscv-interrupt-s" fn riscv_s() {} + | ^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "x86-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:51:8 + | +LL | extern "x86-interrupt" fn x86(_x: *const u8) {} + | ^^^^^^^^^^^^^^^ + +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:76:22 + | +LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { + | ^^^^^^^^^^^^^^^ + +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:82:25 + | +LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^ + +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:88:26 + | +LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { + | ^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:94:26 + | +LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { + | ^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "x86-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:100:22 + | +LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { + | ^^^^^^^^^^^^^^^ + +error: functions with the "gpu-kernel" ABI cannot be called + --> $DIR/cannot-be-called.rs:70:5 + | +LL | gpu_kernel(); + | ^^^^^^^^^^^^ + | +note: an `extern "gpu-kernel"` function must be launched on the GPU by the runtime + --> $DIR/cannot-be-called.rs:70:5 + | +LL | gpu_kernel(); + | ^^^^^^^^^^^^ + +error: functions with the "gpu-kernel" ABI cannot be called + --> $DIR/cannot-be-called.rs:108:5 + | +LL | f() + | ^^^ + | +note: an `extern "gpu-kernel"` function must be launched on the GPU by the runtime + --> $DIR/cannot-be-called.rs:108:5 + | +LL | f() + | ^^^ + +error: aborting due to 12 previous errors + +For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/cannot-be-called.avr.stderr b/tests/ui/abi/cannot-be-called.avr.stderr index 2128991d83cd..752292a58705 100644 --- a/tests/ui/abi/cannot-be-called.avr.stderr +++ b/tests/ui/abi/cannot-be-called.avr.stderr @@ -1,75 +1,87 @@ error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:38:8 + --> $DIR/cannot-be-called.rs:43:8 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:42:8 + --> $DIR/cannot-be-called.rs:47:8 | LL | extern "riscv-interrupt-m" fn riscv_m() {} | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:44:8 + --> $DIR/cannot-be-called.rs:49:8 | LL | extern "riscv-interrupt-s" fn riscv_s() {} | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:46:8 + --> $DIR/cannot-be-called.rs:51:8 | LL | extern "x86-interrupt" fn x86(_x: *const u8) {} | ^^^^^^^^^^^^^^^ +error[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:53:8 + | +LL | extern "gpu-kernel" fn gpu_kernel() {} + | ^^^^^^^^^^^^ + error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:73:25 + --> $DIR/cannot-be-called.rs:82:25 | LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { | ^^^^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:79:26 + --> $DIR/cannot-be-called.rs:88:26 | LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:85:26 + --> $DIR/cannot-be-called.rs:94:26 | LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:91:22 + --> $DIR/cannot-be-called.rs:100:22 | LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { | ^^^^^^^^^^^^^^^ +error[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:106:29 + | +LL | fn gpu_kernel_ptr(f: extern "gpu-kernel" fn()) { + | ^^^^^^^^^^^^ + error: functions with the "avr-interrupt" ABI cannot be called - --> $DIR/cannot-be-called.rs:53:5 + --> $DIR/cannot-be-called.rs:60:5 | LL | avr(); | ^^^^^ | note: an `extern "avr-interrupt"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:53:5 + --> $DIR/cannot-be-called.rs:60:5 | LL | avr(); | ^^^^^ error: functions with the "avr-interrupt" ABI cannot be called - --> $DIR/cannot-be-called.rs:69:5 + --> $DIR/cannot-be-called.rs:78:5 | LL | f() | ^^^ | note: an `extern "avr-interrupt"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:69:5 + --> $DIR/cannot-be-called.rs:78:5 | LL | f() | ^^^ -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/cannot-be-called.i686.stderr b/tests/ui/abi/cannot-be-called.i686.stderr index 9b1755921aea..30e294ad61ec 100644 --- a/tests/ui/abi/cannot-be-called.i686.stderr +++ b/tests/ui/abi/cannot-be-called.i686.stderr @@ -1,75 +1,87 @@ error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:38:8 + --> $DIR/cannot-be-called.rs:43:8 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^ error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:40:8 + --> $DIR/cannot-be-called.rs:45:8 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:42:8 + --> $DIR/cannot-be-called.rs:47:8 | LL | extern "riscv-interrupt-m" fn riscv_m() {} | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:44:8 + --> $DIR/cannot-be-called.rs:49:8 | LL | extern "riscv-interrupt-s" fn riscv_s() {} | ^^^^^^^^^^^^^^^^^^^ +error[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:53:8 + | +LL | extern "gpu-kernel" fn gpu_kernel() {} + | ^^^^^^^^^^^^ + error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:67:22 + --> $DIR/cannot-be-called.rs:76:22 | LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { | ^^^^^^^^^^^^^^^ error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:73:25 + --> $DIR/cannot-be-called.rs:82:25 | LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { | ^^^^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:79:26 + --> $DIR/cannot-be-called.rs:88:26 | LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:85:26 + --> $DIR/cannot-be-called.rs:94:26 | LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { | ^^^^^^^^^^^^^^^^^^^ +error[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:106:29 + | +LL | fn gpu_kernel_ptr(f: extern "gpu-kernel" fn()) { + | ^^^^^^^^^^^^ + error: functions with the "x86-interrupt" ABI cannot be called - --> $DIR/cannot-be-called.rs:61:5 + --> $DIR/cannot-be-called.rs:68:5 | LL | x86(&raw const BYTE); | ^^^^^^^^^^^^^^^^^^^^ | note: an `extern "x86-interrupt"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:61:5 + --> $DIR/cannot-be-called.rs:68:5 | LL | x86(&raw const BYTE); | ^^^^^^^^^^^^^^^^^^^^ error: functions with the "x86-interrupt" ABI cannot be called - --> $DIR/cannot-be-called.rs:93:5 + --> $DIR/cannot-be-called.rs:102:5 | LL | f() | ^^^ | note: an `extern "x86-interrupt"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:93:5 + --> $DIR/cannot-be-called.rs:102:5 | LL | f() | ^^^ -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/cannot-be-called.msp430.stderr b/tests/ui/abi/cannot-be-called.msp430.stderr index 9a047b11cf79..12ab88bc858b 100644 --- a/tests/ui/abi/cannot-be-called.msp430.stderr +++ b/tests/ui/abi/cannot-be-called.msp430.stderr @@ -1,75 +1,87 @@ error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:40:8 + --> $DIR/cannot-be-called.rs:45:8 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:42:8 + --> $DIR/cannot-be-called.rs:47:8 | LL | extern "riscv-interrupt-m" fn riscv_m() {} | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:44:8 + --> $DIR/cannot-be-called.rs:49:8 | LL | extern "riscv-interrupt-s" fn riscv_s() {} | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:46:8 + --> $DIR/cannot-be-called.rs:51:8 | LL | extern "x86-interrupt" fn x86(_x: *const u8) {} | ^^^^^^^^^^^^^^^ +error[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:53:8 + | +LL | extern "gpu-kernel" fn gpu_kernel() {} + | ^^^^^^^^^^^^ + error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:67:22 + --> $DIR/cannot-be-called.rs:76:22 | LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { | ^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:79:26 + --> $DIR/cannot-be-called.rs:88:26 | LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:85:26 + --> $DIR/cannot-be-called.rs:94:26 | LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:91:22 + --> $DIR/cannot-be-called.rs:100:22 | LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { | ^^^^^^^^^^^^^^^ +error[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:106:29 + | +LL | fn gpu_kernel_ptr(f: extern "gpu-kernel" fn()) { + | ^^^^^^^^^^^^ + error: functions with the "msp430-interrupt" ABI cannot be called - --> $DIR/cannot-be-called.rs:55:5 + --> $DIR/cannot-be-called.rs:62:5 | LL | msp430(); | ^^^^^^^^ | note: an `extern "msp430-interrupt"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:55:5 + --> $DIR/cannot-be-called.rs:62:5 | LL | msp430(); | ^^^^^^^^ error: functions with the "msp430-interrupt" ABI cannot be called - --> $DIR/cannot-be-called.rs:75:5 + --> $DIR/cannot-be-called.rs:84:5 | LL | f() | ^^^ | note: an `extern "msp430-interrupt"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:75:5 + --> $DIR/cannot-be-called.rs:84:5 | LL | f() | ^^^ -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/cannot-be-called.nvptx.stderr b/tests/ui/abi/cannot-be-called.nvptx.stderr new file mode 100644 index 000000000000..039e2d7b4f00 --- /dev/null +++ b/tests/ui/abi/cannot-be-called.nvptx.stderr @@ -0,0 +1,87 @@ +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:43:8 + | +LL | extern "msp430-interrupt" fn msp430() {} + | ^^^^^^^^^^^^^^^^^^ + +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:45:8 + | +LL | extern "avr-interrupt" fn avr() {} + | ^^^^^^^^^^^^^^^ + +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:47:8 + | +LL | extern "riscv-interrupt-m" fn riscv_m() {} + | ^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:49:8 + | +LL | extern "riscv-interrupt-s" fn riscv_s() {} + | ^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "x86-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:51:8 + | +LL | extern "x86-interrupt" fn x86(_x: *const u8) {} + | ^^^^^^^^^^^^^^^ + +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:76:22 + | +LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { + | ^^^^^^^^^^^^^^^ + +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:82:25 + | +LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^ + +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:88:26 + | +LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { + | ^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:94:26 + | +LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { + | ^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "x86-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:100:22 + | +LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { + | ^^^^^^^^^^^^^^^ + +error: functions with the "gpu-kernel" ABI cannot be called + --> $DIR/cannot-be-called.rs:70:5 + | +LL | gpu_kernel(); + | ^^^^^^^^^^^^ + | +note: an `extern "gpu-kernel"` function must be launched on the GPU by the runtime + --> $DIR/cannot-be-called.rs:70:5 + | +LL | gpu_kernel(); + | ^^^^^^^^^^^^ + +error: functions with the "gpu-kernel" ABI cannot be called + --> $DIR/cannot-be-called.rs:108:5 + | +LL | f() + | ^^^ + | +note: an `extern "gpu-kernel"` function must be launched on the GPU by the runtime + --> $DIR/cannot-be-called.rs:108:5 + | +LL | f() + | ^^^ + +error: aborting due to 12 previous errors + +For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/cannot-be-called.riscv32.stderr b/tests/ui/abi/cannot-be-called.riscv32.stderr index 135b20c50d58..b1897b74ebbe 100644 --- a/tests/ui/abi/cannot-be-called.riscv32.stderr +++ b/tests/ui/abi/cannot-be-called.riscv32.stderr @@ -1,87 +1,99 @@ error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:38:8 + --> $DIR/cannot-be-called.rs:43:8 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^ error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:40:8 + --> $DIR/cannot-be-called.rs:45:8 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^ error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:46:8 + --> $DIR/cannot-be-called.rs:51:8 | LL | extern "x86-interrupt" fn x86(_x: *const u8) {} | ^^^^^^^^^^^^^^^ +error[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:53:8 + | +LL | extern "gpu-kernel" fn gpu_kernel() {} + | ^^^^^^^^^^^^ + error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:67:22 + --> $DIR/cannot-be-called.rs:76:22 | LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { | ^^^^^^^^^^^^^^^ error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:73:25 + --> $DIR/cannot-be-called.rs:82:25 | LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { | ^^^^^^^^^^^^^^^^^^ error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:91:22 + --> $DIR/cannot-be-called.rs:100:22 | LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { | ^^^^^^^^^^^^^^^ +error[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:106:29 + | +LL | fn gpu_kernel_ptr(f: extern "gpu-kernel" fn()) { + | ^^^^^^^^^^^^ + error: functions with the "riscv-interrupt-m" ABI cannot be called - --> $DIR/cannot-be-called.rs:57:5 + --> $DIR/cannot-be-called.rs:64:5 | LL | riscv_m(); | ^^^^^^^^^ | note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:57:5 + --> $DIR/cannot-be-called.rs:64:5 | LL | riscv_m(); | ^^^^^^^^^ error: functions with the "riscv-interrupt-s" ABI cannot be called - --> $DIR/cannot-be-called.rs:59:5 + --> $DIR/cannot-be-called.rs:66:5 | LL | riscv_s(); | ^^^^^^^^^ | note: an `extern "riscv-interrupt-s"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:59:5 + --> $DIR/cannot-be-called.rs:66:5 | LL | riscv_s(); | ^^^^^^^^^ error: functions with the "riscv-interrupt-m" ABI cannot be called - --> $DIR/cannot-be-called.rs:81:5 + --> $DIR/cannot-be-called.rs:90:5 | LL | f() | ^^^ | note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:81:5 + --> $DIR/cannot-be-called.rs:90:5 | LL | f() | ^^^ error: functions with the "riscv-interrupt-s" ABI cannot be called - --> $DIR/cannot-be-called.rs:87:5 + --> $DIR/cannot-be-called.rs:96:5 | LL | f() | ^^^ | note: an `extern "riscv-interrupt-s"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:87:5 + --> $DIR/cannot-be-called.rs:96:5 | LL | f() | ^^^ -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/cannot-be-called.riscv64.stderr b/tests/ui/abi/cannot-be-called.riscv64.stderr index 135b20c50d58..b1897b74ebbe 100644 --- a/tests/ui/abi/cannot-be-called.riscv64.stderr +++ b/tests/ui/abi/cannot-be-called.riscv64.stderr @@ -1,87 +1,99 @@ error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:38:8 + --> $DIR/cannot-be-called.rs:43:8 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^ error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:40:8 + --> $DIR/cannot-be-called.rs:45:8 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^ error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:46:8 + --> $DIR/cannot-be-called.rs:51:8 | LL | extern "x86-interrupt" fn x86(_x: *const u8) {} | ^^^^^^^^^^^^^^^ +error[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:53:8 + | +LL | extern "gpu-kernel" fn gpu_kernel() {} + | ^^^^^^^^^^^^ + error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:67:22 + --> $DIR/cannot-be-called.rs:76:22 | LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { | ^^^^^^^^^^^^^^^ error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:73:25 + --> $DIR/cannot-be-called.rs:82:25 | LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { | ^^^^^^^^^^^^^^^^^^ error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:91:22 + --> $DIR/cannot-be-called.rs:100:22 | LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { | ^^^^^^^^^^^^^^^ +error[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:106:29 + | +LL | fn gpu_kernel_ptr(f: extern "gpu-kernel" fn()) { + | ^^^^^^^^^^^^ + error: functions with the "riscv-interrupt-m" ABI cannot be called - --> $DIR/cannot-be-called.rs:57:5 + --> $DIR/cannot-be-called.rs:64:5 | LL | riscv_m(); | ^^^^^^^^^ | note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:57:5 + --> $DIR/cannot-be-called.rs:64:5 | LL | riscv_m(); | ^^^^^^^^^ error: functions with the "riscv-interrupt-s" ABI cannot be called - --> $DIR/cannot-be-called.rs:59:5 + --> $DIR/cannot-be-called.rs:66:5 | LL | riscv_s(); | ^^^^^^^^^ | note: an `extern "riscv-interrupt-s"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:59:5 + --> $DIR/cannot-be-called.rs:66:5 | LL | riscv_s(); | ^^^^^^^^^ error: functions with the "riscv-interrupt-m" ABI cannot be called - --> $DIR/cannot-be-called.rs:81:5 + --> $DIR/cannot-be-called.rs:90:5 | LL | f() | ^^^ | note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:81:5 + --> $DIR/cannot-be-called.rs:90:5 | LL | f() | ^^^ error: functions with the "riscv-interrupt-s" ABI cannot be called - --> $DIR/cannot-be-called.rs:87:5 + --> $DIR/cannot-be-called.rs:96:5 | LL | f() | ^^^ | note: an `extern "riscv-interrupt-s"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:87:5 + --> $DIR/cannot-be-called.rs:96:5 | LL | f() | ^^^ -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/cannot-be-called.rs b/tests/ui/abi/cannot-be-called.rs index 315ea1601633..8d1a4ae0b557 100644 --- a/tests/ui/abi/cannot-be-called.rs +++ b/tests/ui/abi/cannot-be-called.rs @@ -4,7 +4,7 @@ Interrupt ABIs share similar semantics, in that they are special entry-points un So we test that they error in essentially all of the same places. */ //@ add-minicore -//@ revisions: x64 x64_win i686 riscv32 riscv64 avr msp430 +//@ revisions: x64 x64_win i686 riscv32 riscv64 avr msp430 amdgpu nvptx // //@ [x64] needs-llvm-components: x86 //@ [x64] compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib @@ -20,6 +20,10 @@ So we test that they error in essentially all of the same places. //@ [avr] compile-flags: --target=avr-none -C target-cpu=atmega328p --crate-type=rlib //@ [msp430] needs-llvm-components: msp430 //@ [msp430] compile-flags: --target=msp430-none-elf --crate-type=rlib +//@ [amdgpu] needs-llvm-components: amdgpu +//@ [amdgpu] compile-flags: --target amdgcn-amd-amdhsa -Ctarget-cpu=gfx900 --crate-type=rlib +//@ [nvptx] needs-llvm-components: nvptx +//@ [nvptx] compile-flags: --target nvptx64-nvidia-cuda --crate-type=rlib //@ ignore-backends: gcc #![no_core] #![feature( @@ -27,7 +31,8 @@ So we test that they error in essentially all of the same places. abi_msp430_interrupt, abi_avr_interrupt, abi_x86_interrupt, - abi_riscv_interrupt + abi_riscv_interrupt, + abi_gpu_kernel )] extern crate minicore; @@ -36,15 +41,17 @@ use minicore::*; /* extern "interrupt" definition */ extern "msp430-interrupt" fn msp430() {} -//[x64,x64_win,i686,riscv32,riscv64,avr]~^ ERROR is not a supported ABI +//[x64,x64_win,i686,riscv32,riscv64,avr,amdgpu,nvptx]~^ ERROR is not a supported ABI extern "avr-interrupt" fn avr() {} -//[x64,x64_win,i686,riscv32,riscv64,msp430]~^ ERROR is not a supported ABI +//[x64,x64_win,i686,riscv32,riscv64,msp430,amdgpu,nvptx]~^ ERROR is not a supported ABI extern "riscv-interrupt-m" fn riscv_m() {} -//[x64,x64_win,i686,avr,msp430]~^ ERROR is not a supported ABI +//[x64,x64_win,i686,avr,msp430,amdgpu,nvptx]~^ ERROR is not a supported ABI extern "riscv-interrupt-s" fn riscv_s() {} -//[x64,x64_win,i686,avr,msp430]~^ ERROR is not a supported ABI +//[x64,x64_win,i686,avr,msp430,amdgpu,nvptx]~^ ERROR is not a supported ABI extern "x86-interrupt" fn x86(_x: *const u8) {} -//[riscv32,riscv64,avr,msp430]~^ ERROR is not a supported ABI +//[riscv32,riscv64,avr,msp430,amdgpu,nvptx]~^ ERROR is not a supported ABI +extern "gpu-kernel" fn gpu_kernel() {} +//[x64,x64_win,i686,riscv32,riscv64,avr,msp430]~^ ERROR is not a supported ABI static BYTE: u8 = 0; @@ -60,36 +67,44 @@ fn call_the_interrupts() { //[riscv32,riscv64]~^ ERROR functions with the "riscv-interrupt-s" ABI cannot be called x86(&raw const BYTE); //[x64,x64_win,i686]~^ ERROR functions with the "x86-interrupt" ABI cannot be called + gpu_kernel(); + //[amdgpu,nvptx]~^ ERROR functions with the "gpu-kernel" ABI cannot be called } /* extern "interrupt" fnptr calls */ fn avr_ptr(f: extern "avr-interrupt" fn()) { - //[x64,x64_win,i686,riscv32,riscv64,msp430]~^ ERROR is not a supported ABI + //[x64,x64_win,i686,riscv32,riscv64,msp430,amdgpu,nvptx]~^ ERROR is not a supported ABI f() //[avr]~^ ERROR functions with the "avr-interrupt" ABI cannot be called } fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - //[x64,x64_win,i686,riscv32,riscv64,avr]~^ ERROR is not a supported ABI + //[x64,x64_win,i686,riscv32,riscv64,avr,amdgpu,nvptx]~^ ERROR is not a supported ABI f() //[msp430]~^ ERROR functions with the "msp430-interrupt" ABI cannot be called } fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { - //[x64,x64_win,i686,avr,msp430]~^ ERROR is not a supported ABI + //[x64,x64_win,i686,avr,msp430,amdgpu,nvptx]~^ ERROR is not a supported ABI f() //[riscv32,riscv64]~^ ERROR functions with the "riscv-interrupt-m" ABI cannot be called } fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { - //[x64,x64_win,i686,avr,msp430]~^ ERROR is not a supported ABI + //[x64,x64_win,i686,avr,msp430,amdgpu,nvptx]~^ ERROR is not a supported ABI f() //[riscv32,riscv64]~^ ERROR functions with the "riscv-interrupt-s" ABI cannot be called } fn x86_ptr(f: extern "x86-interrupt" fn()) { - //[riscv32,riscv64,avr,msp430]~^ ERROR is not a supported ABI + //[riscv32,riscv64,avr,msp430,amdgpu,nvptx]~^ ERROR is not a supported ABI f() //[x64,x64_win,i686]~^ ERROR functions with the "x86-interrupt" ABI cannot be called } + +fn gpu_kernel_ptr(f: extern "gpu-kernel" fn()) { + //[x64,x64_win,i686,riscv32,riscv64,avr,msp430]~^ ERROR is not a supported ABI + f() + //[amdgpu,nvptx]~^ ERROR functions with the "gpu-kernel" ABI cannot be called +} diff --git a/tests/ui/abi/cannot-be-called.x64.stderr b/tests/ui/abi/cannot-be-called.x64.stderr index 9b1755921aea..30e294ad61ec 100644 --- a/tests/ui/abi/cannot-be-called.x64.stderr +++ b/tests/ui/abi/cannot-be-called.x64.stderr @@ -1,75 +1,87 @@ error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:38:8 + --> $DIR/cannot-be-called.rs:43:8 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^ error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:40:8 + --> $DIR/cannot-be-called.rs:45:8 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:42:8 + --> $DIR/cannot-be-called.rs:47:8 | LL | extern "riscv-interrupt-m" fn riscv_m() {} | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:44:8 + --> $DIR/cannot-be-called.rs:49:8 | LL | extern "riscv-interrupt-s" fn riscv_s() {} | ^^^^^^^^^^^^^^^^^^^ +error[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:53:8 + | +LL | extern "gpu-kernel" fn gpu_kernel() {} + | ^^^^^^^^^^^^ + error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:67:22 + --> $DIR/cannot-be-called.rs:76:22 | LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { | ^^^^^^^^^^^^^^^ error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:73:25 + --> $DIR/cannot-be-called.rs:82:25 | LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { | ^^^^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:79:26 + --> $DIR/cannot-be-called.rs:88:26 | LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:85:26 + --> $DIR/cannot-be-called.rs:94:26 | LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { | ^^^^^^^^^^^^^^^^^^^ +error[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:106:29 + | +LL | fn gpu_kernel_ptr(f: extern "gpu-kernel" fn()) { + | ^^^^^^^^^^^^ + error: functions with the "x86-interrupt" ABI cannot be called - --> $DIR/cannot-be-called.rs:61:5 + --> $DIR/cannot-be-called.rs:68:5 | LL | x86(&raw const BYTE); | ^^^^^^^^^^^^^^^^^^^^ | note: an `extern "x86-interrupt"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:61:5 + --> $DIR/cannot-be-called.rs:68:5 | LL | x86(&raw const BYTE); | ^^^^^^^^^^^^^^^^^^^^ error: functions with the "x86-interrupt" ABI cannot be called - --> $DIR/cannot-be-called.rs:93:5 + --> $DIR/cannot-be-called.rs:102:5 | LL | f() | ^^^ | note: an `extern "x86-interrupt"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:93:5 + --> $DIR/cannot-be-called.rs:102:5 | LL | f() | ^^^ -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/cannot-be-called.x64_win.stderr b/tests/ui/abi/cannot-be-called.x64_win.stderr index 9b1755921aea..30e294ad61ec 100644 --- a/tests/ui/abi/cannot-be-called.x64_win.stderr +++ b/tests/ui/abi/cannot-be-called.x64_win.stderr @@ -1,75 +1,87 @@ error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:38:8 + --> $DIR/cannot-be-called.rs:43:8 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^ error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:40:8 + --> $DIR/cannot-be-called.rs:45:8 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:42:8 + --> $DIR/cannot-be-called.rs:47:8 | LL | extern "riscv-interrupt-m" fn riscv_m() {} | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:44:8 + --> $DIR/cannot-be-called.rs:49:8 | LL | extern "riscv-interrupt-s" fn riscv_s() {} | ^^^^^^^^^^^^^^^^^^^ +error[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:53:8 + | +LL | extern "gpu-kernel" fn gpu_kernel() {} + | ^^^^^^^^^^^^ + error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:67:22 + --> $DIR/cannot-be-called.rs:76:22 | LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { | ^^^^^^^^^^^^^^^ error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:73:25 + --> $DIR/cannot-be-called.rs:82:25 | LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { | ^^^^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:79:26 + --> $DIR/cannot-be-called.rs:88:26 | LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:85:26 + --> $DIR/cannot-be-called.rs:94:26 | LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { | ^^^^^^^^^^^^^^^^^^^ +error[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:106:29 + | +LL | fn gpu_kernel_ptr(f: extern "gpu-kernel" fn()) { + | ^^^^^^^^^^^^ + error: functions with the "x86-interrupt" ABI cannot be called - --> $DIR/cannot-be-called.rs:61:5 + --> $DIR/cannot-be-called.rs:68:5 | LL | x86(&raw const BYTE); | ^^^^^^^^^^^^^^^^^^^^ | note: an `extern "x86-interrupt"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:61:5 + --> $DIR/cannot-be-called.rs:68:5 | LL | x86(&raw const BYTE); | ^^^^^^^^^^^^^^^^^^^^ error: functions with the "x86-interrupt" ABI cannot be called - --> $DIR/cannot-be-called.rs:93:5 + --> $DIR/cannot-be-called.rs:102:5 | LL | f() | ^^^ | note: an `extern "x86-interrupt"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:93:5 + --> $DIR/cannot-be-called.rs:102:5 | LL | f() | ^^^ -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/cannot-be-coroutine.amdgpu.stderr b/tests/ui/abi/cannot-be-coroutine.amdgpu.stderr new file mode 100644 index 000000000000..a36ea0caa19e --- /dev/null +++ b/tests/ui/abi/cannot-be-coroutine.amdgpu.stderr @@ -0,0 +1,23 @@ +error: functions with the "gpu-kernel" ABI cannot be `async` + --> $DIR/cannot-be-coroutine.rs:62:1 + | +LL | async extern "gpu-kernel" fn async_kernel() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `async` keyword from this definition + | +LL - async extern "gpu-kernel" fn async_kernel() { +LL + extern "gpu-kernel" fn async_kernel() { + | + +error: requires `ResumeTy` lang_item + --> $DIR/cannot-be-coroutine.rs:38:19 + | +LL | async fn vanilla(){ + | ___________________^ +LL | | +LL | | } + | |_^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/abi/cannot-be-coroutine.avr.stderr b/tests/ui/abi/cannot-be-coroutine.avr.stderr index 11bc93b1eef1..643a575bece1 100644 --- a/tests/ui/abi/cannot-be-coroutine.avr.stderr +++ b/tests/ui/abi/cannot-be-coroutine.avr.stderr @@ -1,5 +1,5 @@ error: functions with the "avr-interrupt" ABI cannot be `async` - --> $DIR/cannot-be-coroutine.rs:37:1 + --> $DIR/cannot-be-coroutine.rs:42:1 | LL | async extern "avr-interrupt" fn avr() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -11,7 +11,7 @@ LL + extern "avr-interrupt" fn avr() { | error: requires `ResumeTy` lang_item - --> $DIR/cannot-be-coroutine.rs:33:19 + --> $DIR/cannot-be-coroutine.rs:38:19 | LL | async fn vanilla(){ | ___________________^ diff --git a/tests/ui/abi/cannot-be-coroutine.i686.stderr b/tests/ui/abi/cannot-be-coroutine.i686.stderr index 4a344bb09020..f618507df47d 100644 --- a/tests/ui/abi/cannot-be-coroutine.i686.stderr +++ b/tests/ui/abi/cannot-be-coroutine.i686.stderr @@ -1,5 +1,5 @@ error: functions with the "x86-interrupt" ABI cannot be `async` - --> $DIR/cannot-be-coroutine.rs:53:1 + --> $DIR/cannot-be-coroutine.rs:58:1 | LL | async extern "x86-interrupt" fn x86(_p: *mut ()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -11,7 +11,7 @@ LL + extern "x86-interrupt" fn x86(_p: *mut ()) { | error: requires `ResumeTy` lang_item - --> $DIR/cannot-be-coroutine.rs:33:19 + --> $DIR/cannot-be-coroutine.rs:38:19 | LL | async fn vanilla(){ | ___________________^ diff --git a/tests/ui/abi/cannot-be-coroutine.msp430.stderr b/tests/ui/abi/cannot-be-coroutine.msp430.stderr index c2867705df78..f2586c8cd975 100644 --- a/tests/ui/abi/cannot-be-coroutine.msp430.stderr +++ b/tests/ui/abi/cannot-be-coroutine.msp430.stderr @@ -1,5 +1,5 @@ error: functions with the "msp430-interrupt" ABI cannot be `async` - --> $DIR/cannot-be-coroutine.rs:41:1 + --> $DIR/cannot-be-coroutine.rs:46:1 | LL | async extern "msp430-interrupt" fn msp430() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -11,7 +11,7 @@ LL + extern "msp430-interrupt" fn msp430() { | error: requires `ResumeTy` lang_item - --> $DIR/cannot-be-coroutine.rs:33:19 + --> $DIR/cannot-be-coroutine.rs:38:19 | LL | async fn vanilla(){ | ___________________^ diff --git a/tests/ui/abi/cannot-be-coroutine.nvptx.stderr b/tests/ui/abi/cannot-be-coroutine.nvptx.stderr new file mode 100644 index 000000000000..a36ea0caa19e --- /dev/null +++ b/tests/ui/abi/cannot-be-coroutine.nvptx.stderr @@ -0,0 +1,23 @@ +error: functions with the "gpu-kernel" ABI cannot be `async` + --> $DIR/cannot-be-coroutine.rs:62:1 + | +LL | async extern "gpu-kernel" fn async_kernel() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `async` keyword from this definition + | +LL - async extern "gpu-kernel" fn async_kernel() { +LL + extern "gpu-kernel" fn async_kernel() { + | + +error: requires `ResumeTy` lang_item + --> $DIR/cannot-be-coroutine.rs:38:19 + | +LL | async fn vanilla(){ + | ___________________^ +LL | | +LL | | } + | |_^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/abi/cannot-be-coroutine.riscv32.stderr b/tests/ui/abi/cannot-be-coroutine.riscv32.stderr index 398f888205df..c5a8c3f60a38 100644 --- a/tests/ui/abi/cannot-be-coroutine.riscv32.stderr +++ b/tests/ui/abi/cannot-be-coroutine.riscv32.stderr @@ -1,5 +1,5 @@ error: functions with the "riscv-interrupt-m" ABI cannot be `async` - --> $DIR/cannot-be-coroutine.rs:45:1 + --> $DIR/cannot-be-coroutine.rs:50:1 | LL | async extern "riscv-interrupt-m" fn riscv_m() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -11,7 +11,7 @@ LL + extern "riscv-interrupt-m" fn riscv_m() { | error: functions with the "riscv-interrupt-s" ABI cannot be `async` - --> $DIR/cannot-be-coroutine.rs:49:1 + --> $DIR/cannot-be-coroutine.rs:54:1 | LL | async extern "riscv-interrupt-s" fn riscv_s() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL + extern "riscv-interrupt-s" fn riscv_s() { | error: requires `ResumeTy` lang_item - --> $DIR/cannot-be-coroutine.rs:33:19 + --> $DIR/cannot-be-coroutine.rs:38:19 | LL | async fn vanilla(){ | ___________________^ diff --git a/tests/ui/abi/cannot-be-coroutine.riscv64.stderr b/tests/ui/abi/cannot-be-coroutine.riscv64.stderr index 398f888205df..c5a8c3f60a38 100644 --- a/tests/ui/abi/cannot-be-coroutine.riscv64.stderr +++ b/tests/ui/abi/cannot-be-coroutine.riscv64.stderr @@ -1,5 +1,5 @@ error: functions with the "riscv-interrupt-m" ABI cannot be `async` - --> $DIR/cannot-be-coroutine.rs:45:1 + --> $DIR/cannot-be-coroutine.rs:50:1 | LL | async extern "riscv-interrupt-m" fn riscv_m() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -11,7 +11,7 @@ LL + extern "riscv-interrupt-m" fn riscv_m() { | error: functions with the "riscv-interrupt-s" ABI cannot be `async` - --> $DIR/cannot-be-coroutine.rs:49:1 + --> $DIR/cannot-be-coroutine.rs:54:1 | LL | async extern "riscv-interrupt-s" fn riscv_s() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL + extern "riscv-interrupt-s" fn riscv_s() { | error: requires `ResumeTy` lang_item - --> $DIR/cannot-be-coroutine.rs:33:19 + --> $DIR/cannot-be-coroutine.rs:38:19 | LL | async fn vanilla(){ | ___________________^ diff --git a/tests/ui/abi/cannot-be-coroutine.rs b/tests/ui/abi/cannot-be-coroutine.rs index c070e8032e1a..239f5aa5c31f 100644 --- a/tests/ui/abi/cannot-be-coroutine.rs +++ b/tests/ui/abi/cannot-be-coroutine.rs @@ -1,6 +1,6 @@ //@ add-minicore //@ edition: 2021 -//@ revisions: x64 x64_win i686 riscv32 riscv64 avr msp430 +//@ revisions: x64 x64_win i686 riscv32 riscv64 avr msp430 amdgpu nvptx // //@ [x64] needs-llvm-components: x86 //@ [x64] compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib @@ -16,6 +16,10 @@ //@ [avr] compile-flags: --target=avr-none -C target-cpu=atmega328p --crate-type=rlib //@ [msp430] needs-llvm-components: msp430 //@ [msp430] compile-flags: --target=msp430-none-elf --crate-type=rlib +//@ [amdgpu] needs-llvm-components: amdgpu +//@ [amdgpu] compile-flags: --target amdgcn-amd-amdhsa -Ctarget-cpu=gfx900 --crate-type=rlib +//@ [nvptx] needs-llvm-components: nvptx +//@ [nvptx] compile-flags: --target nvptx64-nvidia-cuda --crate-type=rlib //@ ignore-backends: gcc #![no_core] #![feature( @@ -23,7 +27,8 @@ abi_msp430_interrupt, abi_avr_interrupt, abi_x86_interrupt, - abi_riscv_interrupt + abi_riscv_interrupt, + abi_gpu_kernel )] extern crate minicore; @@ -53,3 +58,7 @@ async extern "riscv-interrupt-s" fn riscv_s() { async extern "x86-interrupt" fn x86(_p: *mut ()) { //[x64,x64_win,i686]~^ ERROR functions with the "x86-interrupt" ABI cannot be `async` } + +async extern "gpu-kernel" fn async_kernel() { + //[amdgpu,nvptx]~^ ERROR functions with the "gpu-kernel" ABI cannot be `async` +} diff --git a/tests/ui/abi/cannot-be-coroutine.x64.stderr b/tests/ui/abi/cannot-be-coroutine.x64.stderr index 4a344bb09020..f618507df47d 100644 --- a/tests/ui/abi/cannot-be-coroutine.x64.stderr +++ b/tests/ui/abi/cannot-be-coroutine.x64.stderr @@ -1,5 +1,5 @@ error: functions with the "x86-interrupt" ABI cannot be `async` - --> $DIR/cannot-be-coroutine.rs:53:1 + --> $DIR/cannot-be-coroutine.rs:58:1 | LL | async extern "x86-interrupt" fn x86(_p: *mut ()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -11,7 +11,7 @@ LL + extern "x86-interrupt" fn x86(_p: *mut ()) { | error: requires `ResumeTy` lang_item - --> $DIR/cannot-be-coroutine.rs:33:19 + --> $DIR/cannot-be-coroutine.rs:38:19 | LL | async fn vanilla(){ | ___________________^ diff --git a/tests/ui/abi/cannot-be-coroutine.x64_win.stderr b/tests/ui/abi/cannot-be-coroutine.x64_win.stderr index 4a344bb09020..f618507df47d 100644 --- a/tests/ui/abi/cannot-be-coroutine.x64_win.stderr +++ b/tests/ui/abi/cannot-be-coroutine.x64_win.stderr @@ -1,5 +1,5 @@ error: functions with the "x86-interrupt" ABI cannot be `async` - --> $DIR/cannot-be-coroutine.rs:53:1 + --> $DIR/cannot-be-coroutine.rs:58:1 | LL | async extern "x86-interrupt" fn x86(_p: *mut ()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -11,7 +11,7 @@ LL + extern "x86-interrupt" fn x86(_p: *mut ()) { | error: requires `ResumeTy` lang_item - --> $DIR/cannot-be-coroutine.rs:33:19 + --> $DIR/cannot-be-coroutine.rs:38:19 | LL | async fn vanilla(){ | ___________________^ diff --git a/tests/ui/abi/cannot-return.amdgpu.stderr b/tests/ui/abi/cannot-return.amdgpu.stderr new file mode 100644 index 000000000000..f264907d00ec --- /dev/null +++ b/tests/ui/abi/cannot-return.amdgpu.stderr @@ -0,0 +1,15 @@ +error: invalid signature for `extern "gpu-kernel"` function + --> $DIR/cannot-return.rs:17:37 + | +LL | extern "gpu-kernel" fn ret_i32() -> i32 { 0 } + | ^^^ + | + = note: functions with the "gpu-kernel" ABI cannot have a return type +help: remove the return type + --> $DIR/cannot-return.rs:17:37 + | +LL | extern "gpu-kernel" fn ret_i32() -> i32 { 0 } + | ^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/abi/cannot-return.nvptx.stderr b/tests/ui/abi/cannot-return.nvptx.stderr new file mode 100644 index 000000000000..f264907d00ec --- /dev/null +++ b/tests/ui/abi/cannot-return.nvptx.stderr @@ -0,0 +1,15 @@ +error: invalid signature for `extern "gpu-kernel"` function + --> $DIR/cannot-return.rs:17:37 + | +LL | extern "gpu-kernel" fn ret_i32() -> i32 { 0 } + | ^^^ + | + = note: functions with the "gpu-kernel" ABI cannot have a return type +help: remove the return type + --> $DIR/cannot-return.rs:17:37 + | +LL | extern "gpu-kernel" fn ret_i32() -> i32 { 0 } + | ^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/abi/cannot-return.rs b/tests/ui/abi/cannot-return.rs new file mode 100644 index 000000000000..9a5db30431b9 --- /dev/null +++ b/tests/ui/abi/cannot-return.rs @@ -0,0 +1,18 @@ +//@ add-minicore +//@ ignore-backends: gcc +//@ edition: 2024 +//@ revisions: amdgpu nvptx +// +//@ [amdgpu] needs-llvm-components: amdgpu +//@ [amdgpu] compile-flags: --target amdgcn-amd-amdhsa -Ctarget-cpu=gfx900 --crate-type=rlib +//@ [nvptx] needs-llvm-components: nvptx +//@ [nvptx] compile-flags: --target nvptx64-nvidia-cuda --crate-type=rlib +#![no_core] +#![feature(no_core, abi_gpu_kernel)] + +extern crate minicore; +use minicore::*; + +#[unsafe(no_mangle)] +extern "gpu-kernel" fn ret_i32() -> i32 { 0 } +//~^ ERROR invalid signature for `extern "gpu-kernel"` function diff --git a/tests/ui/lint/lint-gpu-kernel.amdgpu.stderr b/tests/ui/lint/lint-gpu-kernel.amdgpu.stderr new file mode 100644 index 000000000000..21eebe42f8b1 --- /dev/null +++ b/tests/ui/lint/lint-gpu-kernel.amdgpu.stderr @@ -0,0 +1,86 @@ +warning: `extern` fn uses type `()`, which is not FFI-safe + --> $DIR/lint-gpu-kernel.rs:36:35 + | +LL | extern "gpu-kernel" fn arg_zst(_: ()) { } + | ^^ not FFI-safe + | + = help: consider using a struct instead + = note: tuples have unspecified layout + = note: `#[warn(improper_ctypes_definitions)]` on by default + +warning: passing type `()` to a function with "gpu-kernel" ABI may have unexpected behavior + --> $DIR/lint-gpu-kernel.rs:36:35 + | +LL | extern "gpu-kernel" fn arg_zst(_: ()) { } + | ^^ + | + = help: use primitive types and raw pointers to get reliable behavior + = note: `#[warn(improper_gpu_kernel_arg)]` on by default + +warning: passing type `&i32` to a function with "gpu-kernel" ABI may have unexpected behavior + --> $DIR/lint-gpu-kernel.rs:41:35 + | +LL | extern "gpu-kernel" fn arg_ref(_: &i32) { } + | ^^^^ + | + = help: use primitive types and raw pointers to get reliable behavior + +warning: passing type `&mut i32` to a function with "gpu-kernel" ABI may have unexpected behavior + --> $DIR/lint-gpu-kernel.rs:44:39 + | +LL | extern "gpu-kernel" fn arg_ref_mut(_: &mut i32) { } + | ^^^^^^^^ + | + = help: use primitive types and raw pointers to get reliable behavior + +warning: `extern` fn uses type `S`, which is not FFI-safe + --> $DIR/lint-gpu-kernel.rs:49:38 + | +LL | extern "gpu-kernel" fn arg_struct(_: S) { } + | ^ not FFI-safe + | + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout +note: the type is defined here + --> $DIR/lint-gpu-kernel.rs:47:1 + | +LL | struct S { a: i32, b: i32 } + | ^^^^^^^^ + +warning: passing type `S` to a function with "gpu-kernel" ABI may have unexpected behavior + --> $DIR/lint-gpu-kernel.rs:49:38 + | +LL | extern "gpu-kernel" fn arg_struct(_: S) { } + | ^ + | + = help: use primitive types and raw pointers to get reliable behavior + +warning: `extern` fn uses type `(i32, i32)`, which is not FFI-safe + --> $DIR/lint-gpu-kernel.rs:54:35 + | +LL | extern "gpu-kernel" fn arg_tup(_: (i32, i32)) { } + | ^^^^^^^^^^ not FFI-safe + | + = help: consider using a struct instead + = note: tuples have unspecified layout + +warning: passing type `(i32, i32)` to a function with "gpu-kernel" ABI may have unexpected behavior + --> $DIR/lint-gpu-kernel.rs:54:35 + | +LL | extern "gpu-kernel" fn arg_tup(_: (i32, i32)) { } + | ^^^^^^^^^^ + | + = help: use primitive types and raw pointers to get reliable behavior + +warning: function with the "gpu-kernel" ABI has a mangled name + --> $DIR/lint-gpu-kernel.rs:61:1 + | +LL | pub extern "gpu-kernel" fn mangled_kernel() { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `unsafe(no_mangle)` or `unsafe(export_name = "")` + = note: mangled names make it hard to find the kernel, this is usually not intended + = note: `#[warn(missing_gpu_kernel_export_name)]` on by default + +warning: 9 warnings emitted + diff --git a/tests/ui/lint/lint-gpu-kernel.nvptx.stderr b/tests/ui/lint/lint-gpu-kernel.nvptx.stderr new file mode 100644 index 000000000000..21eebe42f8b1 --- /dev/null +++ b/tests/ui/lint/lint-gpu-kernel.nvptx.stderr @@ -0,0 +1,86 @@ +warning: `extern` fn uses type `()`, which is not FFI-safe + --> $DIR/lint-gpu-kernel.rs:36:35 + | +LL | extern "gpu-kernel" fn arg_zst(_: ()) { } + | ^^ not FFI-safe + | + = help: consider using a struct instead + = note: tuples have unspecified layout + = note: `#[warn(improper_ctypes_definitions)]` on by default + +warning: passing type `()` to a function with "gpu-kernel" ABI may have unexpected behavior + --> $DIR/lint-gpu-kernel.rs:36:35 + | +LL | extern "gpu-kernel" fn arg_zst(_: ()) { } + | ^^ + | + = help: use primitive types and raw pointers to get reliable behavior + = note: `#[warn(improper_gpu_kernel_arg)]` on by default + +warning: passing type `&i32` to a function with "gpu-kernel" ABI may have unexpected behavior + --> $DIR/lint-gpu-kernel.rs:41:35 + | +LL | extern "gpu-kernel" fn arg_ref(_: &i32) { } + | ^^^^ + | + = help: use primitive types and raw pointers to get reliable behavior + +warning: passing type `&mut i32` to a function with "gpu-kernel" ABI may have unexpected behavior + --> $DIR/lint-gpu-kernel.rs:44:39 + | +LL | extern "gpu-kernel" fn arg_ref_mut(_: &mut i32) { } + | ^^^^^^^^ + | + = help: use primitive types and raw pointers to get reliable behavior + +warning: `extern` fn uses type `S`, which is not FFI-safe + --> $DIR/lint-gpu-kernel.rs:49:38 + | +LL | extern "gpu-kernel" fn arg_struct(_: S) { } + | ^ not FFI-safe + | + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout +note: the type is defined here + --> $DIR/lint-gpu-kernel.rs:47:1 + | +LL | struct S { a: i32, b: i32 } + | ^^^^^^^^ + +warning: passing type `S` to a function with "gpu-kernel" ABI may have unexpected behavior + --> $DIR/lint-gpu-kernel.rs:49:38 + | +LL | extern "gpu-kernel" fn arg_struct(_: S) { } + | ^ + | + = help: use primitive types and raw pointers to get reliable behavior + +warning: `extern` fn uses type `(i32, i32)`, which is not FFI-safe + --> $DIR/lint-gpu-kernel.rs:54:35 + | +LL | extern "gpu-kernel" fn arg_tup(_: (i32, i32)) { } + | ^^^^^^^^^^ not FFI-safe + | + = help: consider using a struct instead + = note: tuples have unspecified layout + +warning: passing type `(i32, i32)` to a function with "gpu-kernel" ABI may have unexpected behavior + --> $DIR/lint-gpu-kernel.rs:54:35 + | +LL | extern "gpu-kernel" fn arg_tup(_: (i32, i32)) { } + | ^^^^^^^^^^ + | + = help: use primitive types and raw pointers to get reliable behavior + +warning: function with the "gpu-kernel" ABI has a mangled name + --> $DIR/lint-gpu-kernel.rs:61:1 + | +LL | pub extern "gpu-kernel" fn mangled_kernel() { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `unsafe(no_mangle)` or `unsafe(export_name = "")` + = note: mangled names make it hard to find the kernel, this is usually not intended + = note: `#[warn(missing_gpu_kernel_export_name)]` on by default + +warning: 9 warnings emitted + diff --git a/tests/ui/lint/lint-gpu-kernel.rs b/tests/ui/lint/lint-gpu-kernel.rs new file mode 100644 index 000000000000..9b3ed0d14d8a --- /dev/null +++ b/tests/ui/lint/lint-gpu-kernel.rs @@ -0,0 +1,62 @@ +// Test argument and return type restrictions of the gpu-kernel ABI and +// check for warnings on mangled gpu-kernels. + +//@ check-pass +//@ ignore-backends: gcc +//@ revisions: amdgpu nvptx +//@ add-minicore +//@ edition: 2024 +//@[amdgpu] compile-flags: --target amdgcn-amd-amdhsa -Ctarget-cpu=gfx900 +//@[amdgpu] needs-llvm-components: amdgpu +//@[nvptx] compile-flags: --target nvptx64-nvidia-cuda +//@[nvptx] needs-llvm-components: nvptx + +#![feature(no_core, abi_gpu_kernel)] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +// Return types can be () or ! +#[unsafe(no_mangle)] +extern "gpu-kernel" fn ret_empty() {} +#[unsafe(no_mangle)] +extern "gpu-kernel" fn ret_never() -> ! { loop {} } + +// Arguments can be scalars or pointers +#[unsafe(no_mangle)] +extern "gpu-kernel" fn arg_i32(_: i32) { } +#[unsafe(no_mangle)] +extern "gpu-kernel" fn arg_ptr(_: *const i32) { } +#[unsafe(no_mangle)] +extern "gpu-kernel" fn arg_ptr_mut(_: *mut i32) { } + +#[unsafe(no_mangle)] +extern "gpu-kernel" fn arg_zst(_: ()) { } +//~^ WARN passing type `()` to a function with "gpu-kernel" ABI may have unexpected behavior +//~^^ WARN `extern` fn uses type `()`, which is not FFI-safe + +#[unsafe(no_mangle)] +extern "gpu-kernel" fn arg_ref(_: &i32) { } +//~^ WARN passing type `&i32` to a function with "gpu-kernel" ABI may have unexpected behavior +#[unsafe(no_mangle)] +extern "gpu-kernel" fn arg_ref_mut(_: &mut i32) { } +//~^ WARN passing type `&mut i32` to a function with "gpu-kernel" ABI may have unexpected behavior + +struct S { a: i32, b: i32 } +#[unsafe(no_mangle)] +extern "gpu-kernel" fn arg_struct(_: S) { } +//~^ WARN passing type `S` to a function with "gpu-kernel" ABI may have unexpected behavior +//~^^ WARN `extern` fn uses type `S`, which is not FFI-safe + +#[unsafe(no_mangle)] +extern "gpu-kernel" fn arg_tup(_: (i32, i32)) { } +//~^ WARN passing type `(i32, i32)` to a function with "gpu-kernel" ABI may have unexpected behavior +//~^^ WARN `extern` fn uses type `(i32, i32)`, which is not FFI-safe + +#[unsafe(export_name = "kernel")] +pub extern "gpu-kernel" fn allowed_kernel_name() {} + +pub extern "gpu-kernel" fn mangled_kernel() { } +//~^ WARN function with the "gpu-kernel" ABI has a mangled name From cde301fabc81b25b6ef54268139d93721448b118 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jan 2026 19:20:42 +0000 Subject: [PATCH 0137/1061] Bump qs from 6.14.0 to 6.14.1 in /editors/code Bumps [qs](https://github.com/ljharb/qs) from 6.14.0 to 6.14.1. - [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md) - [Commits](https://github.com/ljharb/qs/compare/v6.14.0...v6.14.1) --- updated-dependencies: - dependency-name: qs dependency-version: 6.14.1 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- src/tools/rust-analyzer/editors/code/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json index 00d83e906848..57f6bf69beb0 100644 --- a/src/tools/rust-analyzer/editors/code/package-lock.json +++ b/src/tools/rust-analyzer/editors/code/package-lock.json @@ -5584,9 +5584,9 @@ } }, "node_modules/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", "dev": true, "license": "BSD-3-Clause", "dependencies": { From cddda032d5b0c7d485a95f90f781568177d734e9 Mon Sep 17 00:00:00 2001 From: human9000 Date: Fri, 2 Jan 2026 00:48:29 +0500 Subject: [PATCH 0138/1061] test: modified bad-question-mark-on-trait-objects to match expected behaviour --- .../ui/try-trait/bad-question-mark-on-trait-object.rs | 1 - .../bad-question-mark-on-trait-object.stderr | 11 +++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/tests/ui/try-trait/bad-question-mark-on-trait-object.rs b/tests/ui/try-trait/bad-question-mark-on-trait-object.rs index 2a0d14b17503..270ec2c532ac 100644 --- a/tests/ui/try-trait/bad-question-mark-on-trait-object.rs +++ b/tests/ui/try-trait/bad-question-mark-on-trait-object.rs @@ -1,6 +1,5 @@ struct E; //~^ NOTE `E` needs to implement `std::error::Error` -//~| NOTE alternatively, `E` needs to implement `Into` struct X; //~ NOTE `X` needs to implement `From` fn foo() -> Result<(), Box> { //~ NOTE required `E: std::error::Error` because of this diff --git a/tests/ui/try-trait/bad-question-mark-on-trait-object.stderr b/tests/ui/try-trait/bad-question-mark-on-trait-object.stderr index dd380850c9ec..7639489b891a 100644 --- a/tests/ui/try-trait/bad-question-mark-on-trait-object.stderr +++ b/tests/ui/try-trait/bad-question-mark-on-trait-object.stderr @@ -1,5 +1,5 @@ error[E0277]: `?` couldn't convert the error: `E: std::error::Error` is not satisfied - --> $DIR/bad-question-mark-on-trait-object.rs:7:13 + --> $DIR/bad-question-mark-on-trait-object.rs:6:13 | LL | fn foo() -> Result<(), Box> { | -------------------------------------- required `E: std::error::Error` because of this @@ -17,7 +17,7 @@ LL | struct E; = note: required for `Box` to implement `From` error[E0277]: `?` couldn't convert the error to `X` - --> $DIR/bad-question-mark-on-trait-object.rs:18:13 + --> $DIR/bad-question-mark-on-trait-object.rs:17:13 | LL | fn bat() -> Result<(), X> { | ------------- expected `X` because of this @@ -27,15 +27,10 @@ LL | Ok(bar()?) | this can't be annotated with `?` because it has type `Result<_, E>` | note: `X` needs to implement `From` - --> $DIR/bad-question-mark-on-trait-object.rs:4:1 + --> $DIR/bad-question-mark-on-trait-object.rs:3:1 | LL | struct X; | ^^^^^^^^ -note: alternatively, `E` needs to implement `Into` - --> $DIR/bad-question-mark-on-trait-object.rs:1:1 - | -LL | struct E; - | ^^^^^^^^ = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait error: aborting due to 2 previous errors From 97e5cabb9107d5285838fc1ce95665ade98db096 Mon Sep 17 00:00:00 2001 From: human9000 Date: Fri, 2 Jan 2026 00:50:05 +0500 Subject: [PATCH 0139/1061] removed confusing message from diagnostics --- .../src/error_reporting/traits/fulfillment_errors.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index d96a1b0a8c0e..fc5209739f16 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1287,10 +1287,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.tcx.def_span(def.did()), format!("`{self_ty}` needs to implement `From<{ty}>`"), ); - err.span_note( - self.tcx.def_span(found.did()), - format!("alternatively, `{ty}` needs to implement `Into<{self_ty}>`"), - ); } (ty::Adt(def, _), None) if def.did().is_local() => { let trait_path = self.tcx.short_string( From 48657cec85a38c0f1fade3eaf905b19bf23d356f Mon Sep 17 00:00:00 2001 From: Aliaksei Semianiuk Date: Fri, 2 Jan 2026 01:59:16 +0500 Subject: [PATCH 0140/1061] Update year --- COPYRIGHT | 2 +- LICENSE-APACHE | 2 +- LICENSE-MIT | 2 +- README.md | 2 +- clippy_utils/README.md | 2 +- rustc_tools_util/README.md | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/COPYRIGHT b/COPYRIGHT index f402dcf465a3..5d3075903a01 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,6 +1,6 @@ // REUSE-IgnoreStart -Copyright 2014-2025 The Rust Project Developers +Copyright 2014-2026 The Rust Project Developers Licensed under the Apache License, Version 2.0 or the MIT license diff --git a/LICENSE-APACHE b/LICENSE-APACHE index 9990a0cec474..6f6e5844208d 100644 --- a/LICENSE-APACHE +++ b/LICENSE-APACHE @@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work. same "printed page" as the copyright notice for easier identification within third-party archives. -Copyright 2014-2025 The Rust Project Developers +Copyright 2014-2026 The Rust Project Developers Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/LICENSE-MIT b/LICENSE-MIT index 5d6e36ef6bfc..a51639bc0f9b 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2014-2025 The Rust Project Developers +Copyright (c) 2014-2026 The Rust Project Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/README.md b/README.md index 78498c73ae78..287dee82daaa 100644 --- a/README.md +++ b/README.md @@ -277,7 +277,7 @@ If you want to contribute to Clippy, you can find more information in [CONTRIBUT -Copyright 2014-2025 The Rust Project Developers +Copyright 2014-2026 The Rust Project Developers Licensed under the Apache License, Version 2.0 or the MIT license diff --git a/clippy_utils/README.md b/clippy_utils/README.md index 01257c1a3059..e3ce95d30074 100644 --- a/clippy_utils/README.md +++ b/clippy_utils/README.md @@ -30,7 +30,7 @@ Function signatures can change or be removed without replacement without any pri -Copyright 2014-2025 The Rust Project Developers +Copyright 2014-2026 The Rust Project Developers Licensed under the Apache License, Version 2.0 <[https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license diff --git a/rustc_tools_util/README.md b/rustc_tools_util/README.md index f47a4c69c2c3..083814e1e05d 100644 --- a/rustc_tools_util/README.md +++ b/rustc_tools_util/README.md @@ -51,7 +51,7 @@ The changelog for `rustc_tools_util` is available under: -Copyright 2014-2025 The Rust Project Developers +Copyright 2014-2026 The Rust Project Developers Licensed under the Apache License, Version 2.0 or the MIT license From 68ea14a27283bc5e55acbf81ae9dbe6a05506e79 Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Thu, 1 Jan 2026 22:07:57 +0000 Subject: [PATCH 0141/1061] address review --- src/tools/tidy/src/extra_checks/mod.rs | 37 ++++++++++++-------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index bedcd08ca13f..2d654339e883 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -121,9 +121,7 @@ fn check_impl( ck.is_non_auto_or_matches(path) }); } - if lint_args.iter().any(|ck| ck.if_installed) { - lint_args.retain(|ck| ck.is_non_if_installed_or_matches(root_path, outdir)); - } + lint_args.retain(|ck| ck.is_non_if_installed_or_matches(root_path, outdir)); macro_rules! extra_check { ($lang:ident, $kind:ident) => { @@ -597,29 +595,26 @@ fn install_requirements( Ok(()) } +/// Returns `Ok` if shellcheck is installed, `Err` otherwise. fn has_shellcheck() -> Result<(), Error> { match Command::new("shellcheck").arg("--version").status() { Ok(_) => Ok(()), - Err(e) if e.kind() == io::ErrorKind::NotFound => { - return Err(Error::MissingReq( - "shellcheck", - "shell file checks", - Some( - "see \ - for installation instructions" - .to_owned(), - ), - )); - } - Err(e) => return Err(e.into()), + Err(e) if e.kind() == io::ErrorKind::NotFound => Err(Error::MissingReq( + "shellcheck", + "shell file checks", + Some( + "see \ + for installation instructions" + .to_owned(), + ), + )), + Err(e) => Err(e.into()), } } /// Check that shellcheck is installed then run it at the given path fn shellcheck_runner(args: &[&OsStr]) -> Result<(), Error> { - if let Err(err) = has_shellcheck() { - return Err(err); - } + has_shellcheck()?; let status = Command::new("shellcheck").args(args).status()?; if status.success() { Ok(()) } else { Err(Error::FailedCheck("shellcheck")) } @@ -758,6 +753,7 @@ enum ExtraCheckParseError { } struct ExtraCheckArg { + /// Only run the check if files to check have been modified. auto: bool, /// Only run the check if the requisite software is already installed. if_installed: bool, @@ -798,8 +794,7 @@ impl ExtraCheckArg { && rustdoc_js::has_tool(build_dir, "es-check") && rustdoc_js::has_tool(build_dir, "tsc") } - // Unreachable. - Some(_) => false, + Some(_) => unreachable!("js shouldn't have other type of ExtraCheckKind"), } } ExtraCheckLang::Py | ExtraCheckLang::Cpp => { @@ -862,6 +857,8 @@ impl FromStr for ExtraCheckArg { let Some(mut first) = parts.next() else { return Err(ExtraCheckParseError::Empty); }; + // The loop allows users to specify `auto` and `if-installed` in any order. + // Both auto:if-installed: and if-installed:auto: are valid. loop { if !auto && first == "auto" { let Some(part) = parts.next() else { From 8ca47cd1fe50eb4d160d1ab801f159312a35c54a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 2 Jan 2026 09:29:26 +1100 Subject: [PATCH 0142/1061] Clarify `MoveData::init_loc_map`. Change the `SmallVec` size from 4 to 1, because that's sufficient in the vast majority of cases. (This doesn't affect performance in practice, so it's more of a code clarity change than a performance change.) --- compiler/rustc_mir_dataflow/src/move_paths/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs index 800d4e406cf0..8be7d210f8df 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs @@ -177,8 +177,9 @@ pub struct MoveData<'tcx> { pub rev_lookup: MovePathLookup<'tcx>, pub inits: IndexVec, /// Each Location `l` is mapped to the Inits that are effects - /// of executing the code at `l`. - pub init_loc_map: LocationMap>, + /// of executing the code at `l`. Only very rarely (e.g. inline asm) + /// is there more than one Init at any `l`. + pub init_loc_map: LocationMap>, pub init_path_map: IndexVec>, } From 6394373dccc7b4bc49617b03bd505ea0f75a57a7 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Fri, 2 Jan 2026 05:44:43 +0530 Subject: [PATCH 0143/1061] add nits --- src/tools/rust-analyzer/crates/load-cargo/src/lib.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index dc75abe7ad8c..5aa96582e9f3 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -547,10 +547,8 @@ impl ProcMacroExpander for Expander { let name = source_root .path_for_file(&file) - .and_then(|path| path.clone().into_abs_path()) - .and_then(|path| { - path.as_path().file_name().map(|filename| filename.to_owned()) - }); + .and_then(|path| path.as_path()) + .and_then(|path| path.file_name().map(|filename| filename.to_owned())); Ok(SubResponse::LocalFileNameResult { name }) } From 3982d3e70648ce3769d40610d86e330e4456b0ce Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sun, 19 Oct 2025 23:52:19 +0000 Subject: [PATCH 0144/1061] `Vec::push` in consts MVP --- library/alloc/src/alloc.rs | 259 ++++++++++++++---- library/alloc/src/collections/mod.rs | 23 +- library/alloc/src/lib.rs | 6 + library/alloc/src/raw_vec/mod.rs | 81 ++++-- library/alloc/src/vec/mod.rs | 33 ++- library/alloctests/lib.rs | 7 + library/alloctests/tests/lib.rs | 1 + library/alloctests/tests/vec.rs | 16 ++ library/core/src/alloc/mod.rs | 7 +- .../const-eval/heap/vec-not-made-global.rs | 5 + .../heap/vec-not-made-global.stderr | 10 + 11 files changed, 361 insertions(+), 87 deletions(-) create mode 100644 tests/ui/consts/const-eval/heap/vec-not-made-global.rs create mode 100644 tests/ui/consts/const-eval/heap/vec-not-made-global.stderr diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index c5f16f3708d7..ee40596c620f 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -5,8 +5,8 @@ #[stable(feature = "alloc_module", since = "1.28.0")] #[doc(inline)] pub use core::alloc::*; -use core::hint; use core::ptr::{self, NonNull}; +use core::{cmp, hint}; unsafe extern "Rust" { // These are the magic symbols to call the global allocator. rustc generates @@ -182,7 +182,7 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { impl Global { #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result, AllocError> { + fn alloc_impl_runtime(layout: Layout, zeroed: bool) -> Result, AllocError> { match layout.size() { 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)), // SAFETY: `layout` is non-zero in size, @@ -194,10 +194,26 @@ impl Global { } } + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + fn deallocate_impl_runtime(ptr: NonNull, layout: Layout) { + if layout.size() != 0 { + // SAFETY: + // * We have checked that `layout` is non-zero in size. + // * The caller is obligated to provide a layout that "fits", and in this case, + // "fit" always means a layout that is equal to the original, because our + // `allocate()`, `grow()`, and `shrink()` implementations never returns a larger + // allocation than requested. + // * Other conditions must be upheld by the caller, as per `Allocator::deallocate()`'s + // safety documentation. + unsafe { dealloc(ptr.as_ptr(), layout) } + } + } + // SAFETY: Same as `Allocator::grow` #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - unsafe fn grow_impl( + fn grow_impl_runtime( &self, ptr: NonNull, old_layout: Layout, @@ -241,69 +257,16 @@ impl Global { }, } } -} -#[unstable(feature = "allocator_api", issue = "32838")] -unsafe impl Allocator for Global { + // SAFETY: Same as `Allocator::grow` #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - fn allocate(&self, layout: Layout) -> Result, AllocError> { - self.alloc_impl(layout, false) - } - - #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { - self.alloc_impl(layout, true) - } - - #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { - if layout.size() != 0 { - // SAFETY: - // * We have checked that `layout` is non-zero in size. - // * The caller is obligated to provide a layout that "fits", and in this case, - // "fit" always means a layout that is equal to the original, because our - // `allocate()`, `grow()`, and `shrink()` implementations never returns a larger - // allocation than requested. - // * Other conditions must be upheld by the caller, as per `Allocator::deallocate()`'s - // safety documentation. - unsafe { dealloc(ptr.as_ptr(), layout) } - } - } - - #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - unsafe fn grow( - &self, - ptr: NonNull, - old_layout: Layout, - new_layout: Layout, - ) -> Result, AllocError> { - // SAFETY: all conditions must be upheld by the caller - unsafe { self.grow_impl(ptr, old_layout, new_layout, false) } - } - - #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - unsafe fn grow_zeroed( - &self, - ptr: NonNull, - old_layout: Layout, - new_layout: Layout, - ) -> Result, AllocError> { - // SAFETY: all conditions must be upheld by the caller - unsafe { self.grow_impl(ptr, old_layout, new_layout, true) } - } - - #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - unsafe fn shrink( + fn shrink_impl_runtime( &self, ptr: NonNull, old_layout: Layout, new_layout: Layout, + _zeroed: bool, ) -> Result, AllocError> { debug_assert!( new_layout.size() <= old_layout.size(), @@ -340,6 +303,184 @@ unsafe impl Allocator for Global { }, } } + + // SAFETY: Same as `Allocator::allocate` + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result, AllocError> { + core::intrinsics::const_eval_select( + (layout, zeroed), + Global::alloc_impl_const, + Global::alloc_impl_runtime, + ) + } + + // SAFETY: Same as `Allocator::deallocate` + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const unsafe fn deallocate_impl(&self, ptr: NonNull, layout: Layout) { + core::intrinsics::const_eval_select( + (ptr, layout), + Global::deallocate_impl_const, + Global::deallocate_impl_runtime, + ) + } + + // SAFETY: Same as `Allocator::grow` + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const unsafe fn grow_impl( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + zeroed: bool, + ) -> Result, AllocError> { + core::intrinsics::const_eval_select( + (self, ptr, old_layout, new_layout, zeroed), + Global::grow_shrink_impl_const, + Global::grow_impl_runtime, + ) + } + + // SAFETY: Same as `Allocator::shrink` + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const unsafe fn shrink_impl( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + core::intrinsics::const_eval_select( + (self, ptr, old_layout, new_layout, false), + Global::grow_shrink_impl_const, + Global::shrink_impl_runtime, + ) + } + + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const fn alloc_impl_const(layout: Layout, zeroed: bool) -> Result, AllocError> { + match layout.size() { + 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)), + // SAFETY: `layout` is non-zero in size, + size => unsafe { + let raw_ptr = core::intrinsics::const_allocate(layout.size(), layout.align()); + let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; + if zeroed { + let mut offset = 0; + while offset < size { + offset += 1; + // SAFETY: the pointer returned by `const_allocate` is valid to write to. + ptr.add(offset).write(0) + } + } + Ok(NonNull::slice_from_raw_parts(ptr, size)) + }, + } + } + + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const fn deallocate_impl_const(ptr: NonNull, layout: Layout) { + if layout.size() != 0 { + // SAFETY: We checked for nonzero size; other preconditions must be upheld by caller. + unsafe { + core::intrinsics::const_deallocate(ptr.as_ptr(), layout.size(), layout.align()); + } + } + } + + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const fn grow_shrink_impl_const( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + zeroed: bool, + ) -> Result, AllocError> { + let new_ptr = self.alloc_impl(new_layout, zeroed)?; + // SAFETY: both pointers are valid and this operations is in bounds. + unsafe { + ptr::copy_nonoverlapping( + ptr.as_ptr(), + new_ptr.as_mut_ptr(), + cmp::min(old_layout.size(), new_layout.size()), + ); + } + unsafe { + self.deallocate_impl(ptr, old_layout); + } + Ok(new_ptr) + } +} + +#[unstable(feature = "allocator_api", issue = "32838")] +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +unsafe impl const Allocator for Global { + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + fn allocate(&self, layout: Layout) -> Result, AllocError> { + self.alloc_impl(layout, false) + } + + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { + self.alloc_impl(layout, true) + } + + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + // SAFETY: all conditions must be upheld by the caller + unsafe { self.deallocate_impl(ptr, layout) } + } + + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + unsafe fn grow( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: all conditions must be upheld by the caller + unsafe { self.grow_impl(ptr, old_layout, new_layout, false) } + } + + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + unsafe fn grow_zeroed( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: all conditions must be upheld by the caller + unsafe { self.grow_impl(ptr, old_layout, new_layout, true) } + } + + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + unsafe fn shrink( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: all conditions must be upheld by the caller + unsafe { self.shrink_impl(ptr, old_layout, new_layout) } + } } /// The allocator for `Box`. diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs index 212d7c8465b6..e09326759fd1 100644 --- a/library/alloc/src/collections/mod.rs +++ b/library/alloc/src/collections/mod.rs @@ -84,13 +84,14 @@ impl TryReserveError { reason = "Uncertain how much info should be exposed", issue = "48043" )] - pub fn kind(&self) -> TryReserveErrorKind { + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + pub const fn kind(&self) -> TryReserveErrorKind { self.kind.clone() } } /// Details of the allocation that caused a `TryReserveError` -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(PartialEq, Eq, Debug)] #[unstable( feature = "try_reserve_kind", reason = "Uncertain how much info should be exposed", @@ -120,6 +121,24 @@ pub enum TryReserveErrorKind { }, } +#[unstable( + feature = "try_reserve_kind", + reason = "Uncertain how much info should be exposed", + issue = "48043" +)] +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +#[cfg(not(test))] +impl const Clone for TryReserveErrorKind { + fn clone(&self) -> Self { + match self { + TryReserveErrorKind::CapacityOverflow => TryReserveErrorKind::CapacityOverflow, + TryReserveErrorKind::AllocError { layout, non_exhaustive: () } => { + TryReserveErrorKind::AllocError { layout: *layout, non_exhaustive: () } + } + } + } +} + #[cfg(test)] pub use realalloc::collections::TryReserveErrorKind; diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index b659e904c8a0..1aee92424602 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -101,11 +101,16 @@ #![feature(char_internals)] #![feature(clone_to_uninit)] #![feature(coerce_unsized)] +#![feature(const_clone)] +#![feature(const_cmp)] #![feature(const_convert)] #![feature(const_default)] +#![feature(const_destruct)] #![feature(const_eval_select)] #![feature(const_heap)] #![feature(copied_into_inner)] +#![feature(const_option_ops)] +#![feature(const_try)] #![feature(core_intrinsics)] #![feature(deprecated_suggestion)] #![feature(deref_pure_trait)] @@ -171,6 +176,7 @@ #![feature(const_trait_impl)] #![feature(coroutine_trait)] #![feature(decl_macro)] +#![feature(derive_const)] #![feature(dropck_eyepatch)] #![feature(fundamental)] #![feature(hashmap_internals)] diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs index 15b0823df9ec..4994f01047d0 100644 --- a/library/alloc/src/raw_vec/mod.rs +++ b/library/alloc/src/raw_vec/mod.rs @@ -4,7 +4,7 @@ // Note: This module is also included in the alloctests crate using #[path] to // run the tests. See the comment there for an explanation why this is the case. -use core::marker::PhantomData; +use core::marker::{Destruct, PhantomData}; use core::mem::{ManuallyDrop, MaybeUninit, SizedTypeProperties}; use core::ptr::{self, Alignment, NonNull, Unique}; use core::{cmp, hint}; @@ -24,7 +24,7 @@ mod tests; // only one location which panics rather than a bunch throughout the module. #[cfg(not(no_global_oom_handling))] #[cfg_attr(not(panic = "immediate-abort"), inline(never))] -fn capacity_overflow() -> ! { +const fn capacity_overflow() -> ! { panic!("capacity overflow"); } @@ -182,7 +182,11 @@ impl RawVec { /// allocator for the returned `RawVec`. #[cfg(not(no_global_oom_handling))] #[inline] - pub(crate) fn with_capacity_in(capacity: usize, alloc: A) -> Self { + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + pub(crate) const fn with_capacity_in(capacity: usize, alloc: A) -> Self + where + A: [const] Allocator + [const] Destruct, + { Self { inner: RawVecInner::with_capacity_in(capacity, alloc, T::LAYOUT), _marker: PhantomData, @@ -331,7 +335,11 @@ impl RawVec { /// caller to ensure `len == self.capacity()`. #[cfg(not(no_global_oom_handling))] #[inline(never)] - pub(crate) fn grow_one(&mut self) { + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + pub(crate) const fn grow_one(&mut self) + where + A: [const] Allocator, + { // SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout unsafe { self.inner.grow_one(T::LAYOUT) } } @@ -415,7 +423,11 @@ impl RawVecInner { #[cfg(not(no_global_oom_handling))] #[inline] - fn with_capacity_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self { + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const fn with_capacity_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self + where + A: [const] Allocator + [const] Destruct, + { match Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc, elem_layout) { Ok(this) => { unsafe { @@ -446,12 +458,16 @@ impl RawVecInner { } } - fn try_allocate_in( + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const fn try_allocate_in( capacity: usize, init: AllocInit, alloc: A, elem_layout: Layout, - ) -> Result { + ) -> Result + where + A: [const] Allocator + [const] Destruct, + { // We avoid `unwrap_or_else` here because it bloats the amount of // LLVM IR generated. let layout = match layout_array(capacity, elem_layout) { @@ -519,7 +535,8 @@ impl RawVecInner { /// initially construct `self` /// - `elem_layout`'s size must be a multiple of its alignment #[inline] - unsafe fn current_memory(&self, elem_layout: Layout) -> Option<(NonNull, Layout)> { + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const unsafe fn current_memory(&self, elem_layout: Layout) -> Option<(NonNull, Layout)> { if elem_layout.size() == 0 || self.cap.as_inner() == 0 { None } else { @@ -572,7 +589,11 @@ impl RawVecInner { /// - `elem_layout`'s size must be a multiple of its alignment #[cfg(not(no_global_oom_handling))] #[inline] - unsafe fn grow_one(&mut self, elem_layout: Layout) { + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const unsafe fn grow_one(&mut self, elem_layout: Layout) + where + A: [const] Allocator, + { // SAFETY: Precondition passed to caller if let Err(err) = unsafe { self.grow_amortized(self.cap.as_inner(), 1, elem_layout) } { handle_error(err); @@ -651,12 +672,13 @@ impl RawVecInner { } #[inline] - fn needs_to_grow(&self, len: usize, additional: usize, elem_layout: Layout) -> bool { + const fn needs_to_grow(&self, len: usize, additional: usize, elem_layout: Layout) -> bool { additional > self.capacity(elem_layout.size()).wrapping_sub(len) } #[inline] - unsafe fn set_ptr_and_cap(&mut self, ptr: NonNull<[u8]>, cap: usize) { + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const unsafe fn set_ptr_and_cap(&mut self, ptr: NonNull<[u8]>, cap: usize) { // Allocators currently return a `NonNull<[u8]>` whose length matches // the size requested. If that ever changes, the capacity here should // change to `ptr.len() / size_of::()`. @@ -669,12 +691,16 @@ impl RawVecInner { /// initially construct `self` /// - `elem_layout`'s size must be a multiple of its alignment /// - The sum of `len` and `additional` must be greater than the current capacity - unsafe fn grow_amortized( + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const unsafe fn grow_amortized( &mut self, len: usize, additional: usize, elem_layout: Layout, - ) -> Result<(), TryReserveError> { + ) -> Result<(), TryReserveError> + where + A: [const] Allocator, + { // This is ensured by the calling contexts. debug_assert!(additional > 0); @@ -737,15 +763,20 @@ impl RawVecInner { // not marked inline(never) since we want optimizers to be able to observe the specifics of this // function, see tests/codegen-llvm/vec-reserve-extend.rs. #[cold] - unsafe fn finish_grow( + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const unsafe fn finish_grow( &self, cap: usize, elem_layout: Layout, - ) -> Result, TryReserveError> { + ) -> Result, TryReserveError> + where + A: [const] Allocator, + { let new_layout = layout_array(cap, elem_layout)?; let memory = if let Some((ptr, old_layout)) = unsafe { self.current_memory(elem_layout) } { - debug_assert_eq!(old_layout.align(), new_layout.align()); + // FIXME(const-hack): switch to `debug_assert_eq` + debug_assert!(old_layout.align() == new_layout.align()); unsafe { // The allocator checks for alignment equality hint::assert_unchecked(old_layout.align() == new_layout.align()); @@ -755,7 +786,11 @@ impl RawVecInner { self.alloc.allocate(new_layout) }; - memory.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () }.into()) + // FIXME(const-hack): switch back to `map_err` + match memory { + Ok(memory) => Ok(memory), + Err(_) => Err(AllocError { layout: new_layout, non_exhaustive: () }.into()), + } } /// # Safety @@ -839,7 +874,8 @@ impl RawVecInner { #[cfg(not(no_global_oom_handling))] #[cold] #[optimize(size)] -fn handle_error(e: TryReserveError) -> ! { +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +const fn handle_error(e: TryReserveError) -> ! { match e.kind() { CapacityOverflow => capacity_overflow(), AllocError { layout, .. } => handle_alloc_error(layout), @@ -847,6 +883,11 @@ fn handle_error(e: TryReserveError) -> ! { } #[inline] -fn layout_array(cap: usize, elem_layout: Layout) -> Result { - elem_layout.repeat(cap).map(|(layout, _pad)| layout).map_err(|_| CapacityOverflow.into()) +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +const fn layout_array(cap: usize, elem_layout: Layout) -> Result { + // FIXME(const-hack) return to using `map` and `map_err` once `const_closures` is implemented + match elem_layout.repeat(cap) { + Ok((layout, _pad)) => Ok(layout), + Err(_) => Err(CapacityOverflow.into()), + } } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index f8a96e358d6d..10a34d17730f 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -81,6 +81,8 @@ use core::cmp::Ordering; use core::hash::{Hash, Hasher}; #[cfg(not(no_global_oom_handling))] use core::iter; +#[cfg(not(no_global_oom_handling))] +use core::marker::Destruct; use core::marker::PhantomData; use core::mem::{self, Assume, ManuallyDrop, MaybeUninit, SizedTypeProperties, TransmuteFrom}; use core::ops::{self, Index, IndexMut, Range, RangeBounds}; @@ -519,7 +521,8 @@ impl Vec { #[stable(feature = "rust1", since = "1.0.0")] #[must_use] #[rustc_diagnostic_item = "vec_with_capacity"] - pub fn with_capacity(capacity: usize) -> Self { + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + pub const fn with_capacity(capacity: usize) -> Self { Self::with_capacity_in(capacity, Global) } @@ -881,6 +884,16 @@ impl Vec { // SAFETY: A `Vec` always has a non-null pointer. (unsafe { NonNull::new_unchecked(ptr) }, len, capacity) } + + /// Leaks the `Vec` to be interned statically. This mut be done for all + /// `Vec` created during compile time. + #[unstable(feature = "const_heap", issue = "79597")] + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + pub const fn const_leak(mut self) -> &'static [T] { + unsafe { core::intrinsics::const_make_global(self.as_mut_ptr().cast()) }; + let me = ManuallyDrop::new(self); + unsafe { slice::from_raw_parts(me.as_ptr(), me.len) } + } } impl Vec { @@ -962,7 +975,11 @@ impl Vec { #[cfg(not(no_global_oom_handling))] #[inline] #[unstable(feature = "allocator_api", issue = "32838")] - pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + pub const fn with_capacity_in(capacity: usize, alloc: A) -> Self + where + A: [const] Allocator + [const] Destruct, + { Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 } } @@ -2575,7 +2592,11 @@ impl Vec { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("push_back", "put", "append")] - pub fn push(&mut self, value: T) { + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + pub const fn push(&mut self, value: T) + where + A: [const] Allocator, + { let _ = self.push_mut(value); } @@ -2664,7 +2685,11 @@ impl Vec { #[inline] #[unstable(feature = "push_mut", issue = "135974")] #[must_use = "if you don't need a reference to the value, use `Vec::push` instead"] - pub fn push_mut(&mut self, value: T) -> &mut T { + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + pub const fn push_mut(&mut self, value: T) -> &mut T + where + A: [const] Allocator, + { // Inform codegen that the length does not change across grow_one(). let len = self.len; // This will panic or abort if we would allocate > isize::MAX bytes diff --git a/library/alloctests/lib.rs b/library/alloctests/lib.rs index cd02c0a53857..b85fc8eb9970 100644 --- a/library/alloctests/lib.rs +++ b/library/alloctests/lib.rs @@ -20,6 +20,13 @@ #![feature(assert_matches)] #![feature(box_vec_non_null)] #![feature(char_internals)] +#![feature(const_alloc_error)] +#![feature(const_cmp)] +#![feature(const_convert)] +#![feature(const_destruct)] +#![feature(const_heap)] +#![feature(const_option_ops)] +#![feature(const_try)] #![feature(copied_into_inner)] #![feature(core_intrinsics)] #![feature(exact_size_is_empty)] diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index 34c65bf787c8..db01cebe5b27 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -1,5 +1,6 @@ #![feature(allocator_api)] #![feature(alloc_layout_extra)] +#![feature(const_heap)] #![feature(deque_extend_front)] #![feature(iter_array_chunks)] #![feature(assert_matches)] diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs index cd5b14f6eff3..a7997cd060d3 100644 --- a/library/alloctests/tests/vec.rs +++ b/library/alloctests/tests/vec.rs @@ -2749,3 +2749,19 @@ fn zst_collections_iter_nth_back_regression() { list.push_back(Thing); let _ = list.into_iter().nth_back(1); } + +#[test] +fn const_heap() { + const X: &'static [u32] = { + let mut v = Vec::with_capacity(6); + let mut x = 1; + while x < 42 { + v.push(x); + x *= 2; + } + assert!(v.len() == 6); + v.const_leak() + }; + + assert_eq!([1, 2, 4, 8, 16, 32], X); +} diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index 680b1ec105a2..ef1abcaf639a 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -102,6 +102,8 @@ impl fmt::Display for AllocError { /// /// [*currently allocated*]: #currently-allocated-memory #[unstable(feature = "allocator_api", issue = "32838")] +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +#[const_trait] pub unsafe trait Allocator { /// Attempts to allocate a block of memory. /// @@ -368,9 +370,10 @@ pub unsafe trait Allocator { } #[unstable(feature = "allocator_api", issue = "32838")] -unsafe impl Allocator for &A +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +unsafe impl const Allocator for &A where - A: Allocator + ?Sized, + A: [const] Allocator + ?Sized, { #[inline] fn allocate(&self, layout: Layout) -> Result, AllocError> { diff --git a/tests/ui/consts/const-eval/heap/vec-not-made-global.rs b/tests/ui/consts/const-eval/heap/vec-not-made-global.rs new file mode 100644 index 000000000000..4f78e977e4d5 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/vec-not-made-global.rs @@ -0,0 +1,5 @@ +#![feature(const_heap)] +const V: Vec = Vec::with_capacity(1); +//~^ ERROR: encountered `const_allocate` pointer in final value that was not made global + +fn main() {} diff --git a/tests/ui/consts/const-eval/heap/vec-not-made-global.stderr b/tests/ui/consts/const-eval/heap/vec-not-made-global.stderr new file mode 100644 index 000000000000..595cbeb8df26 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/vec-not-made-global.stderr @@ -0,0 +1,10 @@ +error: encountered `const_allocate` pointer in final value that was not made global + --> $DIR/vec-not-made-global.rs:2:1 + | +LL | const V: Vec = Vec::with_capacity(1); + | ^^^^^^^^^^^^^^^^^ + | + = note: use `const_make_global` to turn allocated pointers into immutable globals before returning + +error: aborting due to 1 previous error + From 47864e80cb4b873c1c3090be9923bfdf90148962 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sun, 26 Oct 2025 18:42:13 +0000 Subject: [PATCH 0145/1061] address review comments; fix CI --- library/alloc/src/alloc.rs | 8 ++--- library/alloc/src/lib.rs | 1 + library/alloc/src/vec/mod.rs | 14 +++++--- library/alloctests/tests/vec.rs | 2 +- .../item-collection/opaque-return-impls.rs | 2 +- ...ce.PreCodegen.after.32bit.panic-unwind.mir | 26 ++++++++------ ...ce.PreCodegen.after.64bit.panic-unwind.mir | 26 ++++++++------ ..._constant.main.GVN.32bit.panic-unwind.diff | 36 +++++++++---------- ..._constant.main.GVN.64bit.panic-unwind.diff | 36 +++++++++---------- 9 files changed, 77 insertions(+), 74 deletions(-) diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index ee40596c620f..5dd828bd54e1 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -374,12 +374,8 @@ impl Global { let raw_ptr = core::intrinsics::const_allocate(layout.size(), layout.align()); let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; if zeroed { - let mut offset = 0; - while offset < size { - offset += 1; - // SAFETY: the pointer returned by `const_allocate` is valid to write to. - ptr.add(offset).write(0) - } + // SAFETY: the pointer returned by `const_allocate` is valid to write to. + ptr.write_bytes(0, size); } Ok(NonNull::slice_from_raw_parts(ptr, size)) }, diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 1aee92424602..f15dfc9b5de7 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -124,6 +124,7 @@ #![feature(fmt_internals)] #![feature(fn_traits)] #![feature(formatting_options)] +#![feature(freeze)] #![feature(generic_atomic)] #![feature(hasher_prefixfree_extras)] #![feature(inplace_iteration)] diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 10a34d17730f..29e83113d489 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -83,7 +83,7 @@ use core::hash::{Hash, Hasher}; use core::iter; #[cfg(not(no_global_oom_handling))] use core::marker::Destruct; -use core::marker::PhantomData; +use core::marker::{Freeze, PhantomData}; use core::mem::{self, Assume, ManuallyDrop, MaybeUninit, SizedTypeProperties, TransmuteFrom}; use core::ops::{self, Index, IndexMut, Range, RangeBounds}; use core::ptr::{self, NonNull}; @@ -885,11 +885,17 @@ impl Vec { (unsafe { NonNull::new_unchecked(ptr) }, len, capacity) } - /// Leaks the `Vec` to be interned statically. This mut be done for all - /// `Vec` created during compile time. + /// Interns the `Vec`, making the underlying memory read-only. This method should be + /// called during compile time. (This is a no-op if called during runtime) + /// + /// This method must be called if the memory used by `Vec` needs to appear in the final + /// values of constants. #[unstable(feature = "const_heap", issue = "79597")] #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - pub const fn const_leak(mut self) -> &'static [T] { + pub const fn const_make_global(mut self) -> &'static [T] + where + T: Freeze, + { unsafe { core::intrinsics::const_make_global(self.as_mut_ptr().cast()) }; let me = ManuallyDrop::new(self); unsafe { slice::from_raw_parts(me.as_ptr(), me.len) } diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs index a7997cd060d3..c8f9504ae14e 100644 --- a/library/alloctests/tests/vec.rs +++ b/library/alloctests/tests/vec.rs @@ -2760,7 +2760,7 @@ fn const_heap() { x *= 2; } assert!(v.len() == 6); - v.const_leak() + v.const_make_global() }; assert_eq!([1, 2, 4, 8, 16, 32], X); diff --git a/tests/codegen-units/item-collection/opaque-return-impls.rs b/tests/codegen-units/item-collection/opaque-return-impls.rs index d54951b933fd..54ab656c53db 100644 --- a/tests/codegen-units/item-collection/opaque-return-impls.rs +++ b/tests/codegen-units/item-collection/opaque-return-impls.rs @@ -44,7 +44,7 @@ pub fn foo2() -> Box { //~ MONO_ITEM fn ::test_func2 //~ MONO_ITEM fn alloc::alloc::exchange_malloc //~ MONO_ITEM fn foo2 -//~ MONO_ITEM fn std::alloc::Global::alloc_impl +//~ MONO_ITEM fn std::alloc::Global::alloc_impl_runtime //~ MONO_ITEM fn std::boxed::Box::::new //~ MONO_ITEM fn std::alloc::Layout::from_size_align_unchecked::precondition_check //~ MONO_ITEM fn std::ptr::Alignment::new_unchecked::precondition_check diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir index 791d6b71a6f7..013361d1d2fb 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir @@ -25,17 +25,21 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } } scope 18 (inlined ::deallocate) { - let mut _9: *mut u8; - scope 19 (inlined Layout::size) { - } - scope 20 (inlined NonNull::::as_ptr) { - } - scope 21 (inlined std::alloc::dealloc) { - let mut _10: usize; - scope 22 (inlined Layout::size) { - } - scope 23 (inlined Layout::align) { - scope 24 (inlined std::ptr::Alignment::as_usize) { + scope 19 (inlined std::alloc::Global::deallocate_impl) { + scope 20 (inlined std::alloc::Global::deallocate_impl_runtime) { + let mut _9: *mut u8; + scope 21 (inlined Layout::size) { + } + scope 22 (inlined NonNull::::as_ptr) { + } + scope 23 (inlined std::alloc::dealloc) { + let mut _10: usize; + scope 24 (inlined Layout::size) { + } + scope 25 (inlined Layout::align) { + scope 26 (inlined std::ptr::Alignment::as_usize) { + } + } } } } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir index 791d6b71a6f7..013361d1d2fb 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir @@ -25,17 +25,21 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } } scope 18 (inlined ::deallocate) { - let mut _9: *mut u8; - scope 19 (inlined Layout::size) { - } - scope 20 (inlined NonNull::::as_ptr) { - } - scope 21 (inlined std::alloc::dealloc) { - let mut _10: usize; - scope 22 (inlined Layout::size) { - } - scope 23 (inlined Layout::align) { - scope 24 (inlined std::ptr::Alignment::as_usize) { + scope 19 (inlined std::alloc::Global::deallocate_impl) { + scope 20 (inlined std::alloc::Global::deallocate_impl_runtime) { + let mut _9: *mut u8; + scope 21 (inlined Layout::size) { + } + scope 22 (inlined NonNull::::as_ptr) { + } + scope 23 (inlined std::alloc::dealloc) { + let mut _10: usize; + scope 24 (inlined Layout::size) { + } + scope 25 (inlined Layout::align) { + scope 26 (inlined std::ptr::Alignment::as_usize) { + } + } } } } diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff index 15a9d9e39c49..485ff902a7b9 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff @@ -9,22 +9,22 @@ let mut _4: *mut [u8]; let mut _5: std::ptr::NonNull<[u8]>; let mut _6: std::result::Result, std::alloc::AllocError>; - let mut _7: &std::alloc::Global; - let mut _8: std::alloc::Layout; + let mut _7: std::alloc::Layout; scope 1 { debug layout => _1; - let mut _9: &std::alloc::Global; scope 2 { debug ptr => _3; } scope 5 (inlined ::allocate) { + scope 6 (inlined std::alloc::Global::alloc_impl) { + } } - scope 6 (inlined NonNull::<[u8]>::as_ptr) { + scope 7 (inlined NonNull::<[u8]>::as_ptr) { } } scope 3 (inlined #[track_caller] Option::::unwrap) { - let mut _10: isize; - let mut _11: !; + let mut _8: isize; + let mut _9: !; scope 4 { } } @@ -35,10 +35,10 @@ StorageLive(_2); - _2 = Option::::None; + _2 = const Option::::None; - StorageLive(_10); -- _10 = discriminant(_2); -- switchInt(move _10) -> [0: bb3, 1: bb4, otherwise: bb2]; -+ _10 = const 0_isize; + StorageLive(_8); +- _8 = discriminant(_2); +- switchInt(move _8) -> [0: bb3, 1: bb4, otherwise: bb2]; ++ _8 = const 0_isize; + switchInt(const 0_isize) -> [0: bb3, 1: bb4, otherwise: bb2]; } @@ -59,30 +59,26 @@ } bb3: { - _11 = option::unwrap_failed() -> unwind continue; + _9 = option::unwrap_failed() -> unwind continue; } bb4: { - _1 = move ((_2 as Some).0: std::alloc::Layout); + _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}; - StorageDead(_10); + StorageDead(_8); StorageDead(_2); StorageLive(_3); StorageLive(_4); StorageLive(_5); StorageLive(_6); StorageLive(_7); - _9 = const main::promoted[0]; - _7 = copy _9; - StorageLive(_8); -- _8 = copy _1; -- _6 = std::alloc::Global::alloc_impl(move _7, move _8, const false) -> [return: bb5, unwind continue]; -+ _8 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}; -+ _6 = std::alloc::Global::alloc_impl(copy _9, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}, const false) -> [return: bb5, unwind continue]; +- _7 = copy _1; +- _6 = std::alloc::Global::alloc_impl_runtime(move _7, const false) -> [return: bb5, unwind continue]; ++ _7 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}; ++ _6 = std::alloc::Global::alloc_impl_runtime(const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}, const false) -> [return: bb5, unwind continue]; } bb5: { - StorageDead(_8); StorageDead(_7); _5 = Result::, std::alloc::AllocError>::unwrap(move _6) -> [return: bb1, unwind continue]; } diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff index df008ececae3..beee899dafe6 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff @@ -9,22 +9,22 @@ let mut _4: *mut [u8]; let mut _5: std::ptr::NonNull<[u8]>; let mut _6: std::result::Result, std::alloc::AllocError>; - let mut _7: &std::alloc::Global; - let mut _8: std::alloc::Layout; + let mut _7: std::alloc::Layout; scope 1 { debug layout => _1; - let mut _9: &std::alloc::Global; scope 2 { debug ptr => _3; } scope 5 (inlined ::allocate) { + scope 6 (inlined std::alloc::Global::alloc_impl) { + } } - scope 6 (inlined NonNull::<[u8]>::as_ptr) { + scope 7 (inlined NonNull::<[u8]>::as_ptr) { } } scope 3 (inlined #[track_caller] Option::::unwrap) { - let mut _10: isize; - let mut _11: !; + let mut _8: isize; + let mut _9: !; scope 4 { } } @@ -35,10 +35,10 @@ StorageLive(_2); - _2 = Option::::None; + _2 = const Option::::None; - StorageLive(_10); -- _10 = discriminant(_2); -- switchInt(move _10) -> [0: bb3, 1: bb4, otherwise: bb2]; -+ _10 = const 0_isize; + StorageLive(_8); +- _8 = discriminant(_2); +- switchInt(move _8) -> [0: bb3, 1: bb4, otherwise: bb2]; ++ _8 = const 0_isize; + switchInt(const 0_isize) -> [0: bb3, 1: bb4, otherwise: bb2]; } @@ -59,30 +59,26 @@ } bb3: { - _11 = option::unwrap_failed() -> unwind continue; + _9 = option::unwrap_failed() -> unwind continue; } bb4: { - _1 = move ((_2 as Some).0: std::alloc::Layout); + _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum) }}; - StorageDead(_10); + StorageDead(_8); StorageDead(_2); StorageLive(_3); StorageLive(_4); StorageLive(_5); StorageLive(_6); StorageLive(_7); - _9 = const main::promoted[0]; - _7 = copy _9; - StorageLive(_8); -- _8 = copy _1; -- _6 = std::alloc::Global::alloc_impl(move _7, move _8, const false) -> [return: bb5, unwind continue]; -+ _8 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum) }}; -+ _6 = std::alloc::Global::alloc_impl(copy _9, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum) }}, const false) -> [return: bb5, unwind continue]; +- _7 = copy _1; +- _6 = std::alloc::Global::alloc_impl_runtime(move _7, const false) -> [return: bb5, unwind continue]; ++ _7 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum) }}; ++ _6 = std::alloc::Global::alloc_impl_runtime(const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum) }}, const false) -> [return: bb5, unwind continue]; } bb5: { - StorageDead(_8); StorageDead(_7); _5 = Result::, std::alloc::AllocError>::unwrap(move _6) -> [return: bb1, unwind continue]; } From cf61cbcb07a000ab0303baa601ea5a21f35bccda Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Fri, 21 Nov 2025 23:01:26 +0000 Subject: [PATCH 0146/1061] Move into `const impl` blocks --- library/alloc/src/raw_vec/mod.rs | 306 +++++++++++++++---------------- library/alloc/src/vec/mod.rs | 215 +++++++++++----------- library/core/src/alloc/mod.rs | 3 +- 3 files changed, 255 insertions(+), 269 deletions(-) diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs index 4994f01047d0..c92deb06903d 100644 --- a/library/alloc/src/raw_vec/mod.rs +++ b/library/alloc/src/raw_vec/mod.rs @@ -165,6 +165,32 @@ const fn min_non_zero_cap(size: usize) -> usize { } } +const impl RawVec { + /// Like `with_capacity`, but parameterized over the choice of + /// allocator for the returned `RawVec`. + #[cfg(not(no_global_oom_handling))] + #[inline] + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + pub(crate) fn with_capacity_in(capacity: usize, alloc: A) -> Self + { + Self { + inner: RawVecInner::with_capacity_in(capacity, alloc, T::LAYOUT), + _marker: PhantomData, + } + } + + /// A specialized version of `self.reserve(len, 1)` which requires the + /// caller to ensure `len == self.capacity()`. + #[cfg(not(no_global_oom_handling))] + #[inline(never)] + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + pub(crate) fn grow_one(&mut self) + { + // SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout + unsafe { self.inner.grow_one(T::LAYOUT) } + } +} + impl RawVec { #[cfg(not(no_global_oom_handling))] pub(crate) const MIN_NON_ZERO_CAP: usize = min_non_zero_cap(size_of::()); @@ -178,21 +204,6 @@ impl RawVec { Self { inner: RawVecInner::new_in(alloc, Alignment::of::()), _marker: PhantomData } } - /// Like `with_capacity`, but parameterized over the choice of - /// allocator for the returned `RawVec`. - #[cfg(not(no_global_oom_handling))] - #[inline] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - pub(crate) const fn with_capacity_in(capacity: usize, alloc: A) -> Self - where - A: [const] Allocator + [const] Destruct, - { - Self { - inner: RawVecInner::with_capacity_in(capacity, alloc, T::LAYOUT), - _marker: PhantomData, - } - } - /// Like `try_with_capacity`, but parameterized over the choice of /// allocator for the returned `RawVec`. #[inline] @@ -331,19 +342,6 @@ impl RawVec { unsafe { self.inner.reserve(len, additional, T::LAYOUT) } } - /// A specialized version of `self.reserve(len, 1)` which requires the - /// caller to ensure `len == self.capacity()`. - #[cfg(not(no_global_oom_handling))] - #[inline(never)] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - pub(crate) const fn grow_one(&mut self) - where - A: [const] Allocator, - { - // SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout - unsafe { self.inner.grow_one(T::LAYOUT) } - } - /// The same as `reserve`, but returns on errors instead of panicking or aborting. pub(crate) fn try_reserve( &mut self, @@ -413,20 +411,11 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec { } } -impl RawVecInner { - #[inline] - const fn new_in(alloc: A, align: Alignment) -> Self { - let ptr = Unique::from_non_null(NonNull::without_provenance(align.as_nonzero())); - // `cap: 0` means "unallocated". zero-sized types are ignored. - Self { ptr, cap: ZERO_CAP, alloc } - } - +const impl RawVecInner { #[cfg(not(no_global_oom_handling))] #[inline] #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - const fn with_capacity_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self - where - A: [const] Allocator + [const] Destruct, + fn with_capacity_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self { match Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc, elem_layout) { Ok(this) => { @@ -439,34 +428,13 @@ impl RawVecInner { Err(err) => handle_error(err), } } - - #[inline] - fn try_with_capacity_in( - capacity: usize, - alloc: A, - elem_layout: Layout, - ) -> Result { - Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc, elem_layout) - } - - #[cfg(not(no_global_oom_handling))] - #[inline] - fn with_capacity_zeroed_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self { - match Self::try_allocate_in(capacity, AllocInit::Zeroed, alloc, elem_layout) { - Ok(res) => res, - Err(err) => handle_error(err), - } - } - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - const fn try_allocate_in( + fn try_allocate_in( capacity: usize, init: AllocInit, alloc: A, elem_layout: Layout, ) -> Result - where - A: [const] Allocator + [const] Destruct, { // We avoid `unwrap_or_else` here because it bloats the amount of // LLVM IR generated. @@ -500,6 +468,125 @@ impl RawVecInner { }) } + /// # Safety + /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to + /// initially construct `self` + /// - `elem_layout`'s size must be a multiple of its alignment + #[cfg(not(no_global_oom_handling))] + #[inline] + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + unsafe fn grow_one(&mut self, elem_layout: Layout) + { + // SAFETY: Precondition passed to caller + if let Err(err) = unsafe { self.grow_amortized(self.cap.as_inner(), 1, elem_layout) } { + handle_error(err); + } + } + + + /// # Safety + /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to + /// initially construct `self` + /// - `elem_layout`'s size must be a multiple of its alignment + /// - The sum of `len` and `additional` must be greater than the current capacity + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + unsafe fn grow_amortized( + &mut self, + len: usize, + additional: usize, + elem_layout: Layout, + ) -> Result<(), TryReserveError> + { + // This is ensured by the calling contexts. + debug_assert!(additional > 0); + + if elem_layout.size() == 0 { + // Since we return a capacity of `usize::MAX` when `elem_size` is + // 0, getting to here necessarily means the `RawVec` is overfull. + return Err(CapacityOverflow.into()); + } + + // Nothing we can really do about these checks, sadly. + let required_cap = len.checked_add(additional).ok_or(CapacityOverflow)?; + + // This guarantees exponential growth. The doubling cannot overflow + // because `cap <= isize::MAX` and the type of `cap` is `usize`. + let cap = cmp::max(self.cap.as_inner() * 2, required_cap); + let cap = cmp::max(min_non_zero_cap(elem_layout.size()), cap); + + // SAFETY: + // - cap >= len + additional + // - other preconditions passed to caller + let ptr = unsafe { self.finish_grow(cap, elem_layout)? }; + + // SAFETY: `finish_grow` would have failed if `cap > isize::MAX` + unsafe { self.set_ptr_and_cap(ptr, cap) }; + Ok(()) + } + + /// # Safety + /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to + /// initially construct `self` + /// - `elem_layout`'s size must be a multiple of its alignment + /// - `cap` must be greater than the current capacity + // not marked inline(never) since we want optimizers to be able to observe the specifics of this + // function, see tests/codegen-llvm/vec-reserve-extend.rs. + #[cold] + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + unsafe fn finish_grow( + &self, + cap: usize, + elem_layout: Layout, + ) -> Result, TryReserveError> + { + let new_layout = layout_array(cap, elem_layout)?; + + let memory = if let Some((ptr, old_layout)) = unsafe { self.current_memory(elem_layout) } { + // FIXME(const-hack): switch to `debug_assert_eq` + debug_assert!(old_layout.align() == new_layout.align()); + unsafe { + // The allocator checks for alignment equality + hint::assert_unchecked(old_layout.align() == new_layout.align()); + self.alloc.grow(ptr, old_layout, new_layout) + } + } else { + self.alloc.allocate(new_layout) + }; + + // FIXME(const-hack): switch back to `map_err` + match memory { + Ok(memory) => Ok(memory), + Err(_) => Err(AllocError { layout: new_layout, non_exhaustive: () }.into()), + } + } +} + +impl RawVecInner { + #[inline] + const fn new_in(alloc: A, align: Alignment) -> Self { + let ptr = Unique::from_non_null(NonNull::without_provenance(align.as_nonzero())); + // `cap: 0` means "unallocated". zero-sized types are ignored. + Self { ptr, cap: ZERO_CAP, alloc } + } + + #[inline] + fn try_with_capacity_in( + capacity: usize, + alloc: A, + elem_layout: Layout, + ) -> Result { + Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc, elem_layout) + } + + #[cfg(not(no_global_oom_handling))] + #[inline] + fn with_capacity_zeroed_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self { + match Self::try_allocate_in(capacity, AllocInit::Zeroed, alloc, elem_layout) { + Ok(res) => res, + Err(err) => handle_error(err), + } + } + #[inline] unsafe fn from_raw_parts_in(ptr: *mut u8, cap: Cap, alloc: A) -> Self { Self { ptr: unsafe { Unique::new_unchecked(ptr) }, cap, alloc } @@ -583,23 +670,6 @@ impl RawVecInner { } } - /// # Safety - /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to - /// initially construct `self` - /// - `elem_layout`'s size must be a multiple of its alignment - #[cfg(not(no_global_oom_handling))] - #[inline] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - const unsafe fn grow_one(&mut self, elem_layout: Layout) - where - A: [const] Allocator, - { - // SAFETY: Precondition passed to caller - if let Err(err) = unsafe { self.grow_amortized(self.cap.as_inner(), 1, elem_layout) } { - handle_error(err); - } - } - /// # Safety /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to /// initially construct `self` @@ -686,48 +756,6 @@ impl RawVecInner { self.cap = unsafe { Cap::new_unchecked(cap) }; } - /// # Safety - /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to - /// initially construct `self` - /// - `elem_layout`'s size must be a multiple of its alignment - /// - The sum of `len` and `additional` must be greater than the current capacity - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - const unsafe fn grow_amortized( - &mut self, - len: usize, - additional: usize, - elem_layout: Layout, - ) -> Result<(), TryReserveError> - where - A: [const] Allocator, - { - // This is ensured by the calling contexts. - debug_assert!(additional > 0); - - if elem_layout.size() == 0 { - // Since we return a capacity of `usize::MAX` when `elem_size` is - // 0, getting to here necessarily means the `RawVec` is overfull. - return Err(CapacityOverflow.into()); - } - - // Nothing we can really do about these checks, sadly. - let required_cap = len.checked_add(additional).ok_or(CapacityOverflow)?; - - // This guarantees exponential growth. The doubling cannot overflow - // because `cap <= isize::MAX` and the type of `cap` is `usize`. - let cap = cmp::max(self.cap.as_inner() * 2, required_cap); - let cap = cmp::max(min_non_zero_cap(elem_layout.size()), cap); - - // SAFETY: - // - cap >= len + additional - // - other preconditions passed to caller - let ptr = unsafe { self.finish_grow(cap, elem_layout)? }; - - // SAFETY: `finish_grow` would have failed if `cap > isize::MAX` - unsafe { self.set_ptr_and_cap(ptr, cap) }; - Ok(()) - } - /// # Safety /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to /// initially construct `self` @@ -755,44 +783,6 @@ impl RawVecInner { Ok(()) } - /// # Safety - /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to - /// initially construct `self` - /// - `elem_layout`'s size must be a multiple of its alignment - /// - `cap` must be greater than the current capacity - // not marked inline(never) since we want optimizers to be able to observe the specifics of this - // function, see tests/codegen-llvm/vec-reserve-extend.rs. - #[cold] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - const unsafe fn finish_grow( - &self, - cap: usize, - elem_layout: Layout, - ) -> Result, TryReserveError> - where - A: [const] Allocator, - { - let new_layout = layout_array(cap, elem_layout)?; - - let memory = if let Some((ptr, old_layout)) = unsafe { self.current_memory(elem_layout) } { - // FIXME(const-hack): switch to `debug_assert_eq` - debug_assert!(old_layout.align() == new_layout.align()); - unsafe { - // The allocator checks for alignment equality - hint::assert_unchecked(old_layout.align() == new_layout.align()); - self.alloc.grow(ptr, old_layout, new_layout) - } - } else { - self.alloc.allocate(new_layout) - }; - - // FIXME(const-hack): switch back to `map_err` - match memory { - Ok(memory) => Ok(memory), - Err(_) => Err(AllocError { layout: new_layout, non_exhaustive: () }.into()), - } - } - /// # Safety /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to /// initially construct `self` diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 29e83113d489..e3aa4785b4f5 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -902,27 +902,7 @@ impl Vec { } } -impl Vec { - /// Constructs a new, empty `Vec`. - /// - /// The vector will not allocate until elements are pushed onto it. - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// - /// use std::alloc::System; - /// - /// # #[allow(unused_mut)] - /// let mut vec: Vec = Vec::new_in(System); - /// ``` - #[inline] - #[unstable(feature = "allocator_api", issue = "32838")] - pub const fn new_in(alloc: A) -> Self { - Vec { buf: RawVec::new_in(alloc), len: 0 } - } - +const impl Vec { /// Constructs a new, empty `Vec` with at least the specified capacity /// with the provided allocator. /// @@ -982,13 +962,115 @@ impl Vec { #[inline] #[unstable(feature = "allocator_api", issue = "32838")] #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - pub const fn with_capacity_in(capacity: usize, alloc: A) -> Self - where - A: [const] Allocator + [const] Destruct, + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 } } + + /// Appends an element to the back of a collection. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` _bytes_. + /// + /// # Examples + /// + /// ``` + /// let mut vec = vec![1, 2]; + /// vec.push(3); + /// assert_eq!(vec, [1, 2, 3]); + /// ``` + /// + /// # Time complexity + /// + /// Takes amortized *O*(1) time. If the vector's length would exceed its + /// capacity after the push, *O*(*capacity*) time is taken to copy the + /// vector's elements to a larger allocation. This expensive operation is + /// offset by the *capacity* *O*(1) insertions it allows. + #[cfg(not(no_global_oom_handling))] + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_confusables("push_back", "put", "append")] + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + pub fn push(&mut self, value: T) + { + let _ = self.push_mut(value); + } + + /// Appends an element to the back of a collection, returning a reference to it. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` _bytes_. + /// + /// # Examples + /// + /// ``` + /// #![feature(push_mut)] + /// + /// + /// let mut vec = vec![1, 2]; + /// let last = vec.push_mut(3); + /// assert_eq!(*last, 3); + /// assert_eq!(vec, [1, 2, 3]); + /// + /// let last = vec.push_mut(3); + /// *last += 1; + /// assert_eq!(vec, [1, 2, 3, 4]); + /// ``` + /// + /// # Time complexity + /// + /// Takes amortized *O*(1) time. If the vector's length would exceed its + /// capacity after the push, *O*(*capacity*) time is taken to copy the + /// vector's elements to a larger allocation. This expensive operation is + /// offset by the *capacity* *O*(1) insertions it allows. + #[cfg(not(no_global_oom_handling))] + #[inline] + #[unstable(feature = "push_mut", issue = "135974")] + #[must_use = "if you don't need a reference to the value, use `Vec::push` instead"] + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + pub fn push_mut(&mut self, value: T) -> &mut T + { + // Inform codegen that the length does not change across grow_one(). + let len = self.len; + // This will panic or abort if we would allocate > isize::MAX bytes + // or if the length increment would overflow for zero-sized types. + if len == self.buf.capacity() { + self.buf.grow_one(); + } + unsafe { + let end = self.as_mut_ptr().add(len); + ptr::write(end, value); + self.len = len + 1; + // SAFETY: We just wrote a value to the pointer that will live the lifetime of the reference. + &mut *end + } + } +} + +impl Vec { + /// Constructs a new, empty `Vec`. + /// + /// The vector will not allocate until elements are pushed onto it. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::alloc::System; + /// + /// # #[allow(unused_mut)] + /// let mut vec: Vec = Vec::new_in(System); + /// ``` + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub const fn new_in(alloc: A) -> Self { + Vec { buf: RawVec::new_in(alloc), len: 0 } + } + /// Constructs a new, empty `Vec` with at least the specified capacity /// with the provided allocator. /// @@ -2574,38 +2656,6 @@ impl Vec { } } - /// Appends an element to the back of a collection. - /// - /// # Panics - /// - /// Panics if the new capacity exceeds `isize::MAX` _bytes_. - /// - /// # Examples - /// - /// ``` - /// let mut vec = vec![1, 2]; - /// vec.push(3); - /// assert_eq!(vec, [1, 2, 3]); - /// ``` - /// - /// # Time complexity - /// - /// Takes amortized *O*(1) time. If the vector's length would exceed its - /// capacity after the push, *O*(*capacity*) time is taken to copy the - /// vector's elements to a larger allocation. This expensive operation is - /// offset by the *capacity* *O*(1) insertions it allows. - #[cfg(not(no_global_oom_handling))] - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_confusables("push_back", "put", "append")] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - pub const fn push(&mut self, value: T) - where - A: [const] Allocator, - { - let _ = self.push_mut(value); - } - /// Appends an element and returns a reference to it if there is sufficient spare capacity, /// otherwise an error is returned with the element. /// @@ -2659,59 +2709,6 @@ impl Vec { } } - /// Appends an element to the back of a collection, returning a reference to it. - /// - /// # Panics - /// - /// Panics if the new capacity exceeds `isize::MAX` _bytes_. - /// - /// # Examples - /// - /// ``` - /// #![feature(push_mut)] - /// - /// - /// let mut vec = vec![1, 2]; - /// let last = vec.push_mut(3); - /// assert_eq!(*last, 3); - /// assert_eq!(vec, [1, 2, 3]); - /// - /// let last = vec.push_mut(3); - /// *last += 1; - /// assert_eq!(vec, [1, 2, 3, 4]); - /// ``` - /// - /// # Time complexity - /// - /// Takes amortized *O*(1) time. If the vector's length would exceed its - /// capacity after the push, *O*(*capacity*) time is taken to copy the - /// vector's elements to a larger allocation. This expensive operation is - /// offset by the *capacity* *O*(1) insertions it allows. - #[cfg(not(no_global_oom_handling))] - #[inline] - #[unstable(feature = "push_mut", issue = "135974")] - #[must_use = "if you don't need a reference to the value, use `Vec::push` instead"] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - pub const fn push_mut(&mut self, value: T) -> &mut T - where - A: [const] Allocator, - { - // Inform codegen that the length does not change across grow_one(). - let len = self.len; - // This will panic or abort if we would allocate > isize::MAX bytes - // or if the length increment would overflow for zero-sized types. - if len == self.buf.capacity() { - self.buf.grow_one(); - } - unsafe { - let end = self.as_mut_ptr().add(len); - ptr::write(end, value); - self.len = len + 1; - // SAFETY: We just wrote a value to the pointer that will live the lifetime of the reference. - &mut *end - } - } - /// Removes the last element from a vector and returns it, or [`None`] if it /// is empty. /// diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index ef1abcaf639a..959407b75348 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -103,8 +103,7 @@ impl fmt::Display for AllocError { /// [*currently allocated*]: #currently-allocated-memory #[unstable(feature = "allocator_api", issue = "32838")] #[rustc_const_unstable(feature = "const_heap", issue = "79597")] -#[const_trait] -pub unsafe trait Allocator { +pub const unsafe trait Allocator { /// Attempts to allocate a block of memory. /// /// On success, returns a [`NonNull<[u8]>`][NonNull] meeting the size and alignment guarantees of `layout`. From a913065d80129fa501ee9309fb753378d2f5f3d3 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sun, 21 Dec 2025 14:11:40 -0500 Subject: [PATCH 0147/1061] fix rustfmt and bless tidy/tests --- library/alloc/src/lib.rs | 2 +- library/alloc/src/raw_vec/mod.rs | 34 ++++----- library/alloc/src/vec/mod.rs | 19 ++--- ...ng_operand.test.GVN.32bit.panic-abort.diff | 22 +++--- ...ace.PreCodegen.after.32bit.panic-abort.mir | 26 ++++--- ...d_constant.main.GVN.32bit.panic-abort.diff | 72 +++++++++---------- 6 files changed, 80 insertions(+), 95 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index f15dfc9b5de7..06133ce056df 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -108,9 +108,9 @@ #![feature(const_destruct)] #![feature(const_eval_select)] #![feature(const_heap)] -#![feature(copied_into_inner)] #![feature(const_option_ops)] #![feature(const_try)] +#![feature(copied_into_inner)] #![feature(core_intrinsics)] #![feature(deprecated_suggestion)] #![feature(deref_pure_trait)] diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs index c92deb06903d..1e76710d3536 100644 --- a/library/alloc/src/raw_vec/mod.rs +++ b/library/alloc/src/raw_vec/mod.rs @@ -165,14 +165,14 @@ const fn min_non_zero_cap(size: usize) -> usize { } } +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +#[rustfmt::skip] // FIXME(fee1-dead): temporary measure before rustfmt is bumped const impl RawVec { /// Like `with_capacity`, but parameterized over the choice of /// allocator for the returned `RawVec`. #[cfg(not(no_global_oom_handling))] #[inline] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - pub(crate) fn with_capacity_in(capacity: usize, alloc: A) -> Self - { + pub(crate) fn with_capacity_in(capacity: usize, alloc: A) -> Self { Self { inner: RawVecInner::with_capacity_in(capacity, alloc, T::LAYOUT), _marker: PhantomData, @@ -183,9 +183,7 @@ const impl RawVec { /// caller to ensure `len == self.capacity()`. #[cfg(not(no_global_oom_handling))] #[inline(never)] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - pub(crate) fn grow_one(&mut self) - { + pub(crate) fn grow_one(&mut self) { // SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout unsafe { self.inner.grow_one(T::LAYOUT) } } @@ -411,12 +409,12 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec { } } +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +#[rustfmt::skip] // FIXME(fee1-dead): temporary measure before rustfmt is bumped const impl RawVecInner { #[cfg(not(no_global_oom_handling))] #[inline] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - fn with_capacity_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self - { + fn with_capacity_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self { match Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc, elem_layout) { Ok(this) => { unsafe { @@ -428,14 +426,13 @@ const impl RawVecInner { Err(err) => handle_error(err), } } - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + fn try_allocate_in( capacity: usize, init: AllocInit, alloc: A, elem_layout: Layout, - ) -> Result - { + ) -> Result { // We avoid `unwrap_or_else` here because it bloats the amount of // LLVM IR generated. let layout = match layout_array(capacity, elem_layout) { @@ -474,29 +471,24 @@ const impl RawVecInner { /// - `elem_layout`'s size must be a multiple of its alignment #[cfg(not(no_global_oom_handling))] #[inline] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - unsafe fn grow_one(&mut self, elem_layout: Layout) - { + unsafe fn grow_one(&mut self, elem_layout: Layout) { // SAFETY: Precondition passed to caller if let Err(err) = unsafe { self.grow_amortized(self.cap.as_inner(), 1, elem_layout) } { handle_error(err); } } - /// # Safety /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to /// initially construct `self` /// - `elem_layout`'s size must be a multiple of its alignment /// - The sum of `len` and `additional` must be greater than the current capacity - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] unsafe fn grow_amortized( &mut self, len: usize, additional: usize, elem_layout: Layout, - ) -> Result<(), TryReserveError> - { + ) -> Result<(), TryReserveError> { // This is ensured by the calling contexts. debug_assert!(additional > 0); @@ -532,13 +524,11 @@ const impl RawVecInner { // not marked inline(never) since we want optimizers to be able to observe the specifics of this // function, see tests/codegen-llvm/vec-reserve-extend.rs. #[cold] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] unsafe fn finish_grow( &self, cap: usize, elem_layout: Layout, - ) -> Result, TryReserveError> - { + ) -> Result, TryReserveError> { let new_layout = layout_array(cap, elem_layout)?; let memory = if let Some((ptr, old_layout)) = unsafe { self.current_memory(elem_layout) } { diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index e3aa4785b4f5..5a9887f1de55 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -902,6 +902,9 @@ impl Vec { } } +#[cfg(not(no_global_oom_handling))] +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +#[rustfmt::skip] // FIXME(fee1-dead): temporary measure before rustfmt is bumped const impl Vec { /// Constructs a new, empty `Vec` with at least the specified capacity /// with the provided allocator. @@ -958,16 +961,12 @@ const impl Vec { /// let vec_units = Vec::<(), System>::with_capacity_in(10, System); /// assert_eq!(vec_units.capacity(), usize::MAX); /// ``` - #[cfg(not(no_global_oom_handling))] #[inline] #[unstable(feature = "allocator_api", issue = "32838")] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - pub fn with_capacity_in(capacity: usize, alloc: A) -> Self - { + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 } } - /// Appends an element to the back of a collection. /// /// # Panics @@ -988,13 +987,10 @@ const impl Vec { /// capacity after the push, *O*(*capacity*) time is taken to copy the /// vector's elements to a larger allocation. This expensive operation is /// offset by the *capacity* *O*(1) insertions it allows. - #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("push_back", "put", "append")] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - pub fn push(&mut self, value: T) - { + pub fn push(&mut self, value: T) { let _ = self.push_mut(value); } @@ -1026,13 +1022,10 @@ const impl Vec { /// capacity after the push, *O*(*capacity*) time is taken to copy the /// vector's elements to a larger allocation. This expensive operation is /// offset by the *capacity* *O*(1) insertions it allows. - #[cfg(not(no_global_oom_handling))] #[inline] #[unstable(feature = "push_mut", issue = "135974")] #[must_use = "if you don't need a reference to the value, use `Vec::push` instead"] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - pub fn push_mut(&mut self, value: T) -> &mut T - { + pub fn push_mut(&mut self, value: T) -> &mut T { // Inform codegen that the length does not change across grow_one(). let len = self.len; // This will panic or abort if we would allocate > isize::MAX bytes diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff index 2aa92fd34ebf..bcf0ad7c165f 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff @@ -26,12 +26,12 @@ scope 4 { debug _x => _8; } - scope 18 (inlined foo) { + scope 19 (inlined foo) { let mut _27: *const [()]; } } - scope 16 (inlined slice_from_raw_parts::<()>) { - scope 17 (inlined std::ptr::from_raw_parts::<[()], ()>) { + scope 17 (inlined slice_from_raw_parts::<()>) { + scope 18 (inlined std::ptr::from_raw_parts::<[()], ()>) { } } } @@ -49,19 +49,21 @@ scope 7 { let _21: std::ptr::NonNull<[u8]>; scope 8 { - scope 11 (inlined NonNull::<[u8]>::as_mut_ptr) { - scope 12 (inlined NonNull::<[u8]>::as_non_null_ptr) { - scope 13 (inlined NonNull::<[u8]>::cast::) { + scope 12 (inlined NonNull::<[u8]>::as_mut_ptr) { + scope 13 (inlined NonNull::<[u8]>::as_non_null_ptr) { + scope 14 (inlined NonNull::<[u8]>::cast::) { let mut _25: *mut [u8]; - scope 14 (inlined NonNull::<[u8]>::as_ptr) { + scope 15 (inlined NonNull::<[u8]>::as_ptr) { } } } - scope 15 (inlined NonNull::::as_ptr) { + scope 16 (inlined NonNull::::as_ptr) { } } } scope 10 (inlined ::allocate) { + scope 11 (inlined std::alloc::Global::alloc_impl) { + } } } scope 9 (inlined #[track_caller] Layout::from_size_align_unchecked) { @@ -192,8 +194,8 @@ + _18 = const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}; StorageDead(_24); StorageLive(_19); -- _19 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], copy _18, const false) -> [return: bb7, unwind unreachable]; -+ _19 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}, const false) -> [return: bb7, unwind unreachable]; +- _19 = std::alloc::Global::alloc_impl_runtime(copy _18, const false) -> [return: bb7, unwind unreachable]; ++ _19 = std::alloc::Global::alloc_impl_runtime(const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}, const false) -> [return: bb7, unwind unreachable]; } bb7: { diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir index 791d6b71a6f7..013361d1d2fb 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir @@ -25,17 +25,21 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } } scope 18 (inlined ::deallocate) { - let mut _9: *mut u8; - scope 19 (inlined Layout::size) { - } - scope 20 (inlined NonNull::::as_ptr) { - } - scope 21 (inlined std::alloc::dealloc) { - let mut _10: usize; - scope 22 (inlined Layout::size) { - } - scope 23 (inlined Layout::align) { - scope 24 (inlined std::ptr::Alignment::as_usize) { + scope 19 (inlined std::alloc::Global::deallocate_impl) { + scope 20 (inlined std::alloc::Global::deallocate_impl_runtime) { + let mut _9: *mut u8; + scope 21 (inlined Layout::size) { + } + scope 22 (inlined NonNull::::as_ptr) { + } + scope 23 (inlined std::alloc::dealloc) { + let mut _10: usize; + scope 24 (inlined Layout::size) { + } + scope 25 (inlined Layout::align) { + scope 26 (inlined std::ptr::Alignment::as_usize) { + } + } } } } diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff index 3f854b6cbcfb..d0fda06c115c 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff @@ -9,33 +9,33 @@ let mut _4: *mut [u8]; let mut _5: std::ptr::NonNull<[u8]>; let mut _6: std::result::Result, std::alloc::AllocError>; - let mut _7: &std::alloc::Global; - let mut _8: std::alloc::Layout; + let mut _7: std::alloc::Layout; scope 1 { debug layout => _1; - let mut _9: &std::alloc::Global; scope 2 { debug ptr => _3; } scope 5 (inlined ::allocate) { - } - scope 6 (inlined #[track_caller] Result::, std::alloc::AllocError>::unwrap) { - let mut _12: isize; - let _13: std::alloc::AllocError; - let mut _14: !; - let mut _15: &dyn std::fmt::Debug; - let _16: &std::alloc::AllocError; - scope 7 { + scope 6 (inlined std::alloc::Global::alloc_impl) { } + } + scope 7 (inlined #[track_caller] Result::, std::alloc::AllocError>::unwrap) { + let mut _10: isize; + let _11: std::alloc::AllocError; + let mut _12: !; + let mut _13: &dyn std::fmt::Debug; + let _14: &std::alloc::AllocError; scope 8 { } + scope 9 { + } } - scope 9 (inlined NonNull::<[u8]>::as_ptr) { + scope 10 (inlined NonNull::<[u8]>::as_ptr) { } } scope 3 (inlined #[track_caller] Option::::unwrap) { - let mut _10: isize; - let mut _11: !; + let mut _8: isize; + let mut _9: !; scope 4 { } } @@ -46,10 +46,10 @@ StorageLive(_2); - _2 = Option::::None; + _2 = const Option::::None; - StorageLive(_10); -- _10 = discriminant(_2); -- switchInt(move _10) -> [0: bb2, 1: bb3, otherwise: bb1]; -+ _10 = const 0_isize; + StorageLive(_8); +- _8 = discriminant(_2); +- switchInt(move _8) -> [0: bb2, 1: bb3, otherwise: bb1]; ++ _8 = const 0_isize; + switchInt(const 0_isize) -> [0: bb2, 1: bb3, otherwise: bb1]; } @@ -58,48 +58,44 @@ } bb2: { - _11 = option::unwrap_failed() -> unwind unreachable; + _9 = option::unwrap_failed() -> unwind unreachable; } bb3: { - _1 = move ((_2 as Some).0: std::alloc::Layout); + _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}; - StorageDead(_10); + StorageDead(_8); StorageDead(_2); StorageLive(_3); StorageLive(_4); StorageLive(_5); StorageLive(_6); StorageLive(_7); - _9 = const main::promoted[0]; - _7 = copy _9; - StorageLive(_8); -- _8 = copy _1; -- _6 = std::alloc::Global::alloc_impl(move _7, move _8, const false) -> [return: bb4, unwind unreachable]; -+ _8 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}; -+ _6 = std::alloc::Global::alloc_impl(copy _9, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}, const false) -> [return: bb4, unwind unreachable]; +- _7 = copy _1; +- _6 = std::alloc::Global::alloc_impl_runtime(move _7, const false) -> [return: bb4, unwind unreachable]; ++ _7 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}; ++ _6 = std::alloc::Global::alloc_impl_runtime(const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}, const false) -> [return: bb4, unwind unreachable]; } bb4: { - StorageDead(_8); StorageDead(_7); - StorageLive(_12); - StorageLive(_16); - _12 = discriminant(_6); - switchInt(move _12) -> [0: bb6, 1: bb5, otherwise: bb1]; + StorageLive(_10); + StorageLive(_14); + _10 = discriminant(_6); + switchInt(move _10) -> [0: bb6, 1: bb5, otherwise: bb1]; } bb5: { - StorageLive(_15); - _16 = &_13; - _15 = copy _16 as &dyn std::fmt::Debug (PointerCoercion(Unsize, Implicit)); - _14 = result::unwrap_failed(const "called `Result::unwrap()` on an `Err` value", move _15) -> unwind unreachable; + StorageLive(_13); + _14 = &_11; + _13 = copy _14 as &dyn std::fmt::Debug (PointerCoercion(Unsize, Implicit)); + _12 = result::unwrap_failed(const "called `Result::unwrap()` on an `Err` value", move _13) -> unwind unreachable; } bb6: { _5 = move ((_6 as Ok).0: std::ptr::NonNull<[u8]>); - StorageDead(_16); - StorageDead(_12); + StorageDead(_14); + StorageDead(_10); StorageDead(_6); _4 = copy _5 as *mut [u8] (Transmute); StorageDead(_5); From 6417c8faaedca073da26585187f911946d094d7c Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Sun, 28 Dec 2025 22:26:15 +0000 Subject: [PATCH 0148/1061] Extend `needless_collect` to also cover `extend` --- clippy_lints/src/methods/needless_collect.rs | 89 +++++++++++++++----- tests/ui/needless_collect.fixed | 9 +- tests/ui/needless_collect.rs | 7 ++ tests/ui/needless_collect.stderr | 21 ++++- 4 files changed, 104 insertions(+), 22 deletions(-) diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index 312133689900..4992cdf615fa 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::ops::ControlFlow; use super::NEEDLESS_COLLECT; @@ -144,7 +145,11 @@ pub(super) fn check<'tcx>( iter_replacement.push_str(&iter_call.get_iter_method(cx)); let mut remove_suggestions = vec![(l.span, String::new())]; - remove_suggestions.extend(extra_calls.iter().map(|extra| (extra.span, String::new()))); + remove_suggestions.extend( + extra_calls + .iter() + .flat_map(|extra| extra.span().map(|s| (s, String::new()))), + ); remove_suggestions.push((iter_call.span, iter_replacement)); diag.multipart_suggestion( @@ -325,29 +330,48 @@ enum IterFunctionKind { Contains(Span), } -struct ExtraFunction { - kind: ExtraFunctionKind, - span: Span, +struct ExtraFunctionSpan { + /// Span of the function call + func_span: Span, + /// Span of the argument + arg_span: Span, +} + +enum ExtraFunction { + Push(Vec), + Extend(ExtraFunctionSpan), } impl ExtraFunction { fn get_iter_method(&self, cx: &LateContext<'_>) -> String { - match &self.kind { - ExtraFunctionKind::Push(span) => { - let s = snippet(cx, *span, ".."); + match &self { + ExtraFunction::Push(spans) => { + let s = spans + .iter() + .map(|span| snippet(cx, span.arg_span, "..")) + .intersperse(Cow::Borrowed(", ")) + .collect::(); format!(".chain([{s}])") }, + ExtraFunction::Extend(span) => { + let s = snippet(cx, span.arg_span, ".."); + format!(".chain({s})") + }, } } -} -enum ExtraFunctionKind { - Push(Span), + fn span(&self) -> Box + '_> { + match &self { + ExtraFunction::Push(spans) => Box::new(spans.iter().map(|s| s.func_span)), + ExtraFunction::Extend(span) => Box::new(std::iter::once(span.func_span)), + } + } } #[derive(Clone, Copy)] struct ExtraFunctionSpec { push_symbol: Option, + extend_symbol: Option, } impl ExtraFunctionSpec { @@ -355,14 +379,23 @@ impl ExtraFunctionSpec { match target { sym::Vec => Some(ExtraFunctionSpec { push_symbol: Some(sym::push), + extend_symbol: Some(sym::extend), }), sym::VecDeque | sym::LinkedList => Some(ExtraFunctionSpec { push_symbol: Some(sym::push_back), + extend_symbol: Some(sym::extend), + }), + sym::BinaryHeap => Some(ExtraFunctionSpec { + push_symbol: None, + extend_symbol: None, }), - sym::BinaryHeap => Some(ExtraFunctionSpec { push_symbol: None }), _ => None, } } + + fn is_extra_function(self, name: Symbol) -> bool { + self.push_symbol == Some(name) || self.extend_symbol == Some(name) + } } struct IterFunctionVisitor<'a, 'tcx> { @@ -397,6 +430,7 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> { } } + #[expect(clippy::too_many_lines)] fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { // Check function calls on our collection if let ExprKind::MethodCall(method_name, recv, args, _) = &expr.kind { @@ -446,10 +480,30 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> { if let Node::Stmt(stmt) = self.cx.tcx.parent_hir_node(expr.hir_id) { span = stmt.span; } - self.extras.push(ExtraFunction { - kind: ExtraFunctionKind::Push(args[0].span), - span, - }); + if let Some(ExtraFunction::Push(spans)) = self.extras.last_mut() { + spans.push(ExtraFunctionSpan { + func_span: span, + arg_span: args[0].span, + }); + } else { + self.extras.push(ExtraFunction::Push(vec![ExtraFunctionSpan { + func_span: span, + arg_span: args[0].span, + }])); + } + }, + name if self.extra_spec.extend_symbol.is_some_and(|sym| name == sym) + && self.uses.is_empty() => + { + let mut span = expr.span; + // Remove the statement span if possible + if let Node::Stmt(stmt) = self.cx.tcx.parent_hir_node(expr.hir_id) { + span = stmt.span; + } + self.extras.push(ExtraFunction::Extend(ExtraFunctionSpan { + func_span: span, + arg_span: args[0].span, + })); }, _ => { self.seen_other = true; @@ -551,10 +605,7 @@ impl<'tcx> Visitor<'tcx> for UsedCountVisitor<'_, 'tcx> { let parent = self.cx.tcx.parent_hir_node(expr.hir_id); if let Node::Expr(expr) = parent && let ExprKind::MethodCall(method_name, _, _, _) = &expr.kind - && self - .extra_spec - .push_symbol - .is_some_and(|sym| method_name.ident.name == sym) + && self.extra_spec.is_extra_function(method_name.ident.name) { return; } diff --git a/tests/ui/needless_collect.fixed b/tests/ui/needless_collect.fixed index fff383fb1328..e24c752870cc 100644 --- a/tests/ui/needless_collect.fixed +++ b/tests/ui/needless_collect.fixed @@ -241,7 +241,7 @@ mod collect_push_then_iter { //~^ needless_collect - iter.chain([1]).chain([2]).map(|x| x + 1).collect() + iter.chain([1, 2]).map(|x| x + 1).collect() } fn linked_list_push(iter: impl Iterator) -> LinkedList { @@ -263,4 +263,11 @@ mod collect_push_then_iter { v.push(1); ok } + + fn linked_list_extend(iter: impl Iterator, s: Vec) -> LinkedList { + + //~^ needless_collect + + iter.chain(s).map(|x| x + 1).collect() + } } diff --git a/tests/ui/needless_collect.rs b/tests/ui/needless_collect.rs index f6e966b09ea5..7666d5e33fdb 100644 --- a/tests/ui/needless_collect.rs +++ b/tests/ui/needless_collect.rs @@ -263,4 +263,11 @@ mod collect_push_then_iter { v.push(1); ok } + + fn linked_list_extend(iter: impl Iterator, s: Vec) -> LinkedList { + let mut ll = iter.collect::>(); + //~^ needless_collect + ll.extend(s); + ll.into_iter().map(|x| x + 1).collect() + } } diff --git a/tests/ui/needless_collect.stderr b/tests/ui/needless_collect.stderr index 93ca32a68d6a..0decd8cd136a 100644 --- a/tests/ui/needless_collect.stderr +++ b/tests/ui/needless_collect.stderr @@ -153,7 +153,7 @@ LL ~ LL | LL ~ LL ~ -LL ~ iter.chain([1]).chain([2]).map(|x| x + 1).collect() +LL ~ iter.chain([1, 2]).map(|x| x + 1).collect() | error: avoid using `collect()` when not needed @@ -173,5 +173,22 @@ LL ~ LL ~ iter.chain([1]).map(|x| x + 1).collect() | -error: aborting due to 23 previous errors +error: avoid using `collect()` when not needed + --> tests/ui/needless_collect.rs:268:27 + | +LL | let mut ll = iter.collect::>(); + | ^^^^^^^ +... +LL | ll.into_iter().map(|x| x + 1).collect() + | -------------- the iterator could be used here instead + | +help: use the original Iterator instead of collecting it and then producing a new one + | +LL ~ +LL | +LL ~ +LL ~ iter.chain(s).map(|x| x + 1).collect() + | + +error: aborting due to 24 previous errors From 0127720eb8587a3ffecc293020b0faa79c9b8199 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Fri, 2 Jan 2026 01:26:15 +0000 Subject: [PATCH 0149/1061] Extend `needless_collect` to cover `push_front` --- clippy_lints/src/methods/needless_collect.rs | 128 ++++++++++++++----- clippy_utils/src/sym.rs | 1 + tests/ui/needless_collect.fixed | 26 +++- tests/ui/needless_collect.rs | 26 +++- tests/ui/needless_collect.stderr | 43 ++++++- 5 files changed, 187 insertions(+), 37 deletions(-) diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index 4992cdf615fa..6bdb40e46b38 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -141,7 +141,9 @@ pub(super) fn check<'tcx>( |diag| { let iter_snippet = Sugg::hir(cx, iter_expr, ".."); let mut iter_replacement = iter_snippet.to_string(); - iter_replacement.extend(extra_calls.iter().map(|extra| extra.get_iter_method(cx))); + for extra in &extra_calls { + iter_replacement = extra.apply_iter_method(cx, &iter_replacement); + } iter_replacement.push_str(&iter_call.get_iter_method(cx)); let mut remove_suggestions = vec![(l.span, String::new())]; @@ -338,39 +340,62 @@ struct ExtraFunctionSpan { } enum ExtraFunction { - Push(Vec), + Push { + back: Vec, + front: Vec, + }, Extend(ExtraFunctionSpan), } impl ExtraFunction { - fn get_iter_method(&self, cx: &LateContext<'_>) -> String { + fn apply_iter_method(&self, cx: &LateContext<'_>, inner: &str) -> String { match &self { - ExtraFunction::Push(spans) => { - let s = spans + ExtraFunction::Push { back, front } => { + let back_sugg = back .iter() .map(|span| snippet(cx, span.arg_span, "..")) .intersperse(Cow::Borrowed(", ")) .collect::(); - format!(".chain([{s}])") + let front = front + .iter() + .map(|span| snippet(cx, span.arg_span, "..")) + .intersperse(Cow::Borrowed(", ")) + .collect::(); + match (front.is_empty(), back_sugg.is_empty()) { + (true, true) => inner.to_string(), + (true, false) => format!("{inner}.chain([{back_sugg}])"), + (false, true) => format!("[{front}].into_iter().chain({inner})"), + (false, false) => format!("[{front}].into_iter().chain({inner}).chain([{back_sugg}])"), + } }, ExtraFunction::Extend(span) => { let s = snippet(cx, span.arg_span, ".."); - format!(".chain({s})") + format!("{inner}.chain({s})") }, } } fn span(&self) -> Box + '_> { match &self { - ExtraFunction::Push(spans) => Box::new(spans.iter().map(|s| s.func_span)), + ExtraFunction::Push { back, front } => Box::new( + back.iter() + .map(|s| s.func_span) + .chain(front.iter().map(|s| s.func_span)), + ), ExtraFunction::Extend(span) => Box::new(std::iter::once(span.func_span)), } } } +#[derive(Clone, Copy)] +struct ExtraFunctionPushSpec { + back: Option, + front: Option, +} + #[derive(Clone, Copy)] struct ExtraFunctionSpec { - push_symbol: Option, + push_symbol: ExtraFunctionPushSpec, extend_symbol: Option, } @@ -378,15 +403,24 @@ impl ExtraFunctionSpec { fn new(target: Symbol) -> Option { match target { sym::Vec => Some(ExtraFunctionSpec { - push_symbol: Some(sym::push), + push_symbol: ExtraFunctionPushSpec { + back: Some(sym::push), + front: None, + }, extend_symbol: Some(sym::extend), }), sym::VecDeque | sym::LinkedList => Some(ExtraFunctionSpec { - push_symbol: Some(sym::push_back), + push_symbol: ExtraFunctionPushSpec { + back: Some(sym::push_back), + front: Some(sym::push_front), + }, extend_symbol: Some(sym::extend), }), sym::BinaryHeap => Some(ExtraFunctionSpec { - push_symbol: None, + push_symbol: ExtraFunctionPushSpec { + back: None, + front: None, + }, extend_symbol: None, }), _ => None, @@ -394,7 +428,7 @@ impl ExtraFunctionSpec { } fn is_extra_function(self, name: Symbol) -> bool { - self.push_symbol == Some(name) || self.extend_symbol == Some(name) + self.push_symbol.back == Some(name) || self.push_symbol.front == Some(name) || self.extend_symbol == Some(name) } } @@ -474,32 +508,48 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> { func: IterFunctionKind::Contains(args[0].span), span: expr.span, })), - name if Some(name) == self.extra_spec.push_symbol && self.uses.is_empty() => { - let mut span = expr.span; - // Remove the statement span if possible - if let Node::Stmt(stmt) = self.cx.tcx.parent_hir_node(expr.hir_id) { - span = stmt.span; - } - if let Some(ExtraFunction::Push(spans)) = self.extras.last_mut() { - spans.push(ExtraFunctionSpan { - func_span: span, - arg_span: args[0].span, - }); - } else { - self.extras.push(ExtraFunction::Push(vec![ExtraFunctionSpan { - func_span: span, - arg_span: args[0].span, - }])); + name if let is_push_back = self.extra_spec.push_symbol.back.is_some_and(|sym| name == sym) + && (is_push_back || self.extra_spec.push_symbol.front.is_some_and(|sym| name == sym)) + && self.uses.is_empty() => + { + let span = get_span_of_expr_or_parent_stmt(self.cx, expr); + match self.extras.last_mut() { + Some(ExtraFunction::Push { back, .. }) if is_push_back => { + back.push(ExtraFunctionSpan { + func_span: span, + arg_span: args[0].span, + }); + }, + Some(ExtraFunction::Push { front, .. }) => { + front.push(ExtraFunctionSpan { + func_span: span, + arg_span: args[0].span, + }); + }, + _ if is_push_back => { + self.extras.push(ExtraFunction::Push { + back: vec![ExtraFunctionSpan { + func_span: span, + arg_span: args[0].span, + }], + front: Vec::new(), + }); + }, + _ => { + self.extras.push(ExtraFunction::Push { + back: Vec::new(), + front: vec![ExtraFunctionSpan { + func_span: span, + arg_span: args[0].span, + }], + }); + }, } }, name if self.extra_spec.extend_symbol.is_some_and(|sym| name == sym) && self.uses.is_empty() => { - let mut span = expr.span; - // Remove the statement span if possible - if let Node::Stmt(stmt) = self.cx.tcx.parent_hir_node(expr.hir_id) { - span = stmt.span; - } + let span = get_span_of_expr_or_parent_stmt(self.cx, expr); self.extras.push(ExtraFunction::Extend(ExtraFunctionSpan { func_span: span, arg_span: args[0].span, @@ -542,6 +592,16 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> { } } +/// If parent of the `expr` is a statement, return the span of the statement, otherwise return the +/// span of the expression. +fn get_span_of_expr_or_parent_stmt<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Span { + if let Node::Stmt(stmt) = cx.tcx.parent_hir_node(expr.hir_id) { + stmt.span + } else { + expr.span + } +} + enum LoopKind<'tcx> { Conditional(&'tcx Expr<'tcx>), Loop, diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index a36f4954a06a..fbd5ce2dc2d1 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -272,6 +272,7 @@ generate! { product, push, push_back, + push_front, push_str, read, read_exact, diff --git a/tests/ui/needless_collect.fixed b/tests/ui/needless_collect.fixed index e24c752870cc..2d59c1d42b05 100644 --- a/tests/ui/needless_collect.fixed +++ b/tests/ui/needless_collect.fixed @@ -222,7 +222,7 @@ fn issue16270() { #[warn(clippy::needless_collect)] mod collect_push_then_iter { - use std::collections::{BinaryHeap, LinkedList}; + use std::collections::{BinaryHeap, LinkedList, VecDeque}; fn vec_push(iter: impl Iterator) -> Vec { @@ -270,4 +270,28 @@ mod collect_push_then_iter { iter.chain(s).map(|x| x + 1).collect() } + + fn deque_push_front(iter: impl Iterator) -> VecDeque { + + //~^ needless_collect + + + [1, 2].into_iter().chain(iter).map(|x| x + 1).collect() + } + + fn linked_list_push_front_mixed( + iter: impl Iterator, + iter2: impl Iterator, + ) -> LinkedList { + + //~^ needless_collect + + + + + + + + [5].into_iter().chain([1, 3].into_iter().chain(iter).chain([2]).chain(iter2)).chain([4, 6]).map(|x| x + 1).collect() + } } diff --git a/tests/ui/needless_collect.rs b/tests/ui/needless_collect.rs index 7666d5e33fdb..346cddd88e70 100644 --- a/tests/ui/needless_collect.rs +++ b/tests/ui/needless_collect.rs @@ -222,7 +222,7 @@ fn issue16270() { #[warn(clippy::needless_collect)] mod collect_push_then_iter { - use std::collections::{BinaryHeap, LinkedList}; + use std::collections::{BinaryHeap, LinkedList, VecDeque}; fn vec_push(iter: impl Iterator) -> Vec { let mut v = iter.collect::>(); @@ -270,4 +270,28 @@ mod collect_push_then_iter { ll.extend(s); ll.into_iter().map(|x| x + 1).collect() } + + fn deque_push_front(iter: impl Iterator) -> VecDeque { + let mut v = iter.collect::>(); + //~^ needless_collect + v.push_front(1); + v.push_front(2); + v.into_iter().map(|x| x + 1).collect() + } + + fn linked_list_push_front_mixed( + iter: impl Iterator, + iter2: impl Iterator, + ) -> LinkedList { + let mut v = iter.collect::>(); + //~^ needless_collect + v.push_front(1); + v.push_back(2); + v.push_front(3); + v.extend(iter2); + v.push_back(4); + v.push_front(5); + v.push_back(6); + v.into_iter().map(|x| x + 1).collect() + } } diff --git a/tests/ui/needless_collect.stderr b/tests/ui/needless_collect.stderr index 0decd8cd136a..b10312224c8e 100644 --- a/tests/ui/needless_collect.stderr +++ b/tests/ui/needless_collect.stderr @@ -190,5 +190,46 @@ LL ~ LL ~ iter.chain(s).map(|x| x + 1).collect() | -error: aborting due to 24 previous errors +error: avoid using `collect()` when not needed + --> tests/ui/needless_collect.rs:275:26 + | +LL | let mut v = iter.collect::>(); + | ^^^^^^^ +... +LL | v.into_iter().map(|x| x + 1).collect() + | ------------- the iterator could be used here instead + | +help: use the original Iterator instead of collecting it and then producing a new one + | +LL ~ +LL | +LL ~ +LL ~ +LL ~ [1, 2].into_iter().chain(iter).map(|x| x + 1).collect() + | + +error: avoid using `collect()` when not needed + --> tests/ui/needless_collect.rs:286:26 + | +LL | let mut v = iter.collect::>(); + | ^^^^^^^ +... +LL | v.into_iter().map(|x| x + 1).collect() + | ------------- the iterator could be used here instead + | +help: use the original Iterator instead of collecting it and then producing a new one + | +LL ~ +LL | +LL ~ +LL ~ +LL ~ +LL ~ +LL ~ +LL ~ +LL ~ +LL ~ [5].into_iter().chain([1, 3].into_iter().chain(iter).chain([2]).chain(iter2)).chain([4, 6]).map(|x| x + 1).collect() + | + +error: aborting due to 26 previous errors From f74896fc01a995ea3adea70cf4d658ef0347a8d0 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Thu, 1 Jan 2026 19:30:02 -0600 Subject: [PATCH 0150/1061] Cleanup `debuginfo_compression` unstable flag It isn't necessary to declare the option as a top-level flag when it is accessible from `unstable_opts`. --- compiler/rustc_codegen_llvm/src/back/write.rs | 2 +- compiler/rustc_session/src/config.rs | 3 --- compiler/rustc_session/src/options.rs | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index e9306e050803..bcadb6f0de92 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -250,7 +250,7 @@ pub(crate) fn target_machine_factory( let use_emulated_tls = matches!(sess.tls_model(), TlsModel::Emulated); - let debuginfo_compression = match sess.opts.debuginfo_compression { + let debuginfo_compression = match sess.opts.unstable_opts.debuginfo_compression { config::DebugInfoCompression::None => llvm::CompressionKind::None, config::DebugInfoCompression::Zlib => { if llvm::LLVMRustLLVMHasZlibCompression() { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index f326442c0879..fe96dabf6330 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1376,7 +1376,6 @@ impl Default for Options { crate_types: Vec::new(), optimize: OptLevel::No, debuginfo: DebugInfo::None, - debuginfo_compression: DebugInfoCompression::None, lint_opts: Vec::new(), lint_cap: None, describe_lints: false, @@ -2639,7 +2638,6 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M // for more details. let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No); let debuginfo = select_debuginfo(matches, &cg); - let debuginfo_compression = unstable_opts.debuginfo_compression; if !unstable_options_enabled { if let Err(error) = cg.linker_features.check_unstable_variants(&target_triple) { @@ -2747,7 +2745,6 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M crate_types, optimize: opt_level, debuginfo, - debuginfo_compression, lint_opts, lint_cap, describe_lints, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 2b83d1225c97..f11ad12fb9dd 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -397,7 +397,6 @@ top_level_options!( /// can influence whether overflow checks are done or not. debug_assertions: bool [TRACKED], debuginfo: DebugInfo [TRACKED], - debuginfo_compression: DebugInfoCompression [TRACKED], lint_opts: Vec<(String, lint::Level)> [TRACKED_NO_CRATE_HASH], lint_cap: Option [TRACKED_NO_CRATE_HASH], describe_lints: bool [UNTRACKED], From bf2078bfcad890114e0aa17501e706e3bc1b4df0 Mon Sep 17 00:00:00 2001 From: Ryan <63398895+rwardd@users.noreply.github.com> Date: Fri, 2 Jan 2026 12:01:55 +1030 Subject: [PATCH 0151/1061] fix: add `CHECK-SAME` labels to verify generated function type for `u8` and `[u8; 1]` cases Co-authored-by: scottmcm --- tests/codegen-llvm/issues/multiple-option-or-permutations.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/codegen-llvm/issues/multiple-option-or-permutations.rs b/tests/codegen-llvm/issues/multiple-option-or-permutations.rs index 0106517c6fd5..9fbd77166534 100644 --- a/tests/codegen-llvm/issues/multiple-option-or-permutations.rs +++ b/tests/codegen-llvm/issues/multiple-option-or-permutations.rs @@ -19,6 +19,7 @@ pub fn or_match_u8(opta: Option, optb: Option) -> Option { } // CHECK-LABEL: @or_match_alt_u8 +// CHECK-SAME: (i1{{.+}}%opta.0, i8 %opta.1, i1{{.+}}%optb.0, i8 %optb.1) #[no_mangle] pub fn or_match_alt_u8(opta: Option, optb: Option) -> Option { // CHECK: start: @@ -58,6 +59,7 @@ pub fn if_some_u8(opta: Option, optb: Option) -> Option { } // CHECK-LABEL: @or_match_slice_u8 +// CHECK-SAME: (i16 %0, i16 %1) #[no_mangle] pub fn or_match_slice_u8(opta: Option<[u8; 1]>, optb: Option<[u8; 1]>) -> Option<[u8; 1]> { // CHECK: start: From c7e368543c2728c76a41008577b64b0ede7f708e Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Mon, 29 Dec 2025 23:31:46 -0800 Subject: [PATCH 0152/1061] Use more principled check for generics in const ops Instead of using a visitor in typeck, we just check, whenever lowering a use of a param, whether the parent item is an MCG anon const during hir ty lowering (and instantiate_value_path). If so, we report an error since MCG anon consts should never be able to use generics. All other kinds of anon consts are at least syntactically allowed to use generic params. We use a `TypeFolder` to accomplish this; this way, we look at the fully explicit semantic representation of the type/const/whatever and don't miss subtle cases like `Self` type aliases. --- .../src/hir_ty_lowering/mod.rs | 189 +++++++++++++----- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 5 + compiler/rustc_hir_typeck/src/lib.rs | 12 -- compiler/rustc_middle/src/hir/map.rs | 48 ----- tests/crashes/140891.rs | 6 - ...ttribute-missing-in-dependent-crate-ice.rs | 2 +- tests/ui/const-generics/ice-68875.rs | 2 +- .../ui/const-generics/issues/issue-56445-2.rs | 2 +- .../ui/const-generics/issues/issue-56445-3.rs | 2 +- .../ui/const-generics/issues/issue-67945-2.rs | 2 +- .../mgca/early-bound-param-lt-bad.rs | 13 ++ .../mgca/early-bound-param-lt-bad.stderr | 8 + .../mgca/explicit_anon_consts-7.rs | 10 + .../mgca/explicit_anon_consts-7.stderr | 8 + .../mgca/higher-ranked-lts-bad.rs | 12 ++ .../mgca/higher-ranked-lts-bad.stderr | 8 + .../mgca/higher-ranked-lts-good.rs | 13 ++ .../mgca/late-bound-param-lt-bad.rs | 12 ++ .../mgca/late-bound-param-lt-bad.stderr | 11 + .../mgca/selftyalias-containing-param.rs | 13 ++ .../mgca/selftyalias-containing-param.stderr | 14 ++ tests/ui/const-generics/mgca/selftyparam.rs | 9 + .../ui/const-generics/mgca/selftyparam.stderr | 8 + .../forbid-self-no-normalize.rs | 2 +- .../type-relative-path-144547.min.stderr | 8 + .../type-relative-path-144547.rs | 43 ++++ 26 files changed, 338 insertions(+), 124 deletions(-) delete mode 100644 tests/crashes/140891.rs create mode 100644 tests/ui/const-generics/mgca/early-bound-param-lt-bad.rs create mode 100644 tests/ui/const-generics/mgca/early-bound-param-lt-bad.stderr create mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts-7.rs create mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts-7.stderr create mode 100644 tests/ui/const-generics/mgca/higher-ranked-lts-bad.rs create mode 100644 tests/ui/const-generics/mgca/higher-ranked-lts-bad.stderr create mode 100644 tests/ui/const-generics/mgca/higher-ranked-lts-good.rs create mode 100644 tests/ui/const-generics/mgca/late-bound-param-lt-bad.rs create mode 100644 tests/ui/const-generics/mgca/late-bound-param-lt-bad.stderr create mode 100644 tests/ui/const-generics/mgca/selftyalias-containing-param.rs create mode 100644 tests/ui/const-generics/mgca/selftyalias-containing-param.stderr create mode 100644 tests/ui/const-generics/mgca/selftyparam.rs create mode 100644 tests/ui/const-generics/mgca/selftyparam.stderr create mode 100644 tests/ui/const-generics/type-relative-path-144547.min.stderr create mode 100644 tests/ui/const-generics/type-relative-path-144547.rs diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 23110d2c5c87..4c7cfde638f5 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -38,8 +38,8 @@ use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::mir::interpret::LitToConstInput; use rustc_middle::ty::print::PrintPolyTraitRefExt as _; use rustc_middle::ty::{ - self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, - TypingMode, Upcast, fold_regions, + self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, + TypeSuperFoldable, TypeVisitableExt, TypingMode, Upcast, fold_regions, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; @@ -394,7 +394,118 @@ pub trait GenericArgsLowerer<'a, 'tcx> { ) -> ty::GenericArg<'tcx>; } +struct ForbidMCGParamUsesFolder<'tcx> { + tcx: TyCtxt<'tcx>, + anon_const_def_id: LocalDefId, + span: Span, + is_self_alias: bool, +} + +impl<'tcx> ForbidMCGParamUsesFolder<'tcx> { + fn error(&self) -> ErrorGuaranteed { + let msg = if self.is_self_alias { + "generic `Self` types are currently not permitted in anonymous constants" + } else { + "generic parameters may not be used in const operations" + }; + let mut diag = self.tcx.dcx().struct_span_err(self.span, msg); + if self.is_self_alias { + let anon_const_hir_id: HirId = HirId::make_owner(self.anon_const_def_id); + let parent_impl = self.tcx.hir_parent_owner_iter(anon_const_hir_id).find_map( + |(_, node)| match node { + hir::OwnerNode::Item(hir::Item { + kind: hir::ItemKind::Impl(impl_), .. + }) => Some(impl_), + _ => None, + }, + ); + if let Some(impl_) = parent_impl { + diag.span_note(impl_.self_ty.span, "not a concrete type"); + } + } + diag.emit() + } +} + +impl<'tcx> ty::TypeFolder> for ForbidMCGParamUsesFolder<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + if matches!(t.kind(), ty::Param(..)) { + return Ty::new_error(self.tcx, self.error()); + } + t.super_fold_with(self) + } + + fn fold_const(&mut self, c: Const<'tcx>) -> Const<'tcx> { + if matches!(c.kind(), ty::ConstKind::Param(..)) { + return Const::new_error(self.tcx, self.error()); + } + c.super_fold_with(self) + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + if matches!(r.kind(), ty::RegionKind::ReEarlyParam(..) | ty::RegionKind::ReLateParam(..)) { + return ty::Region::new_error(self.tcx, self.error()); + } + r + } +} + impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { + /// See `check_param_uses_if_mcg`. + /// + /// FIXME(mgca): this is pub only for instantiate_value_path and would be nice to avoid altogether + pub fn check_param_res_if_mcg_for_instantiate_value_path( + &self, + res: Res, + span: Span, + ) -> Result<(), ErrorGuaranteed> { + let tcx = self.tcx(); + let parent_def_id = self.item_def_id(); + if let Res::Def(DefKind::ConstParam, _) = res + && tcx.def_kind(parent_def_id) == DefKind::AnonConst + && let ty::AnonConstKind::MCG = tcx.anon_const_kind(parent_def_id) + { + let folder = ForbidMCGParamUsesFolder { + tcx, + anon_const_def_id: parent_def_id, + span, + is_self_alias: false, + }; + return Err(folder.error()); + } + Ok(()) + } + + /// Check for uses of generic parameters that are not in scope due to this being + /// in a non-generic anon const context. + #[must_use = "need to use transformed output"] + fn check_param_uses_if_mcg(&self, term: T, span: Span, is_self_alias: bool) -> T + where + T: ty::TypeFoldable>, + { + let tcx = self.tcx(); + let parent_def_id = self.item_def_id(); + if tcx.def_kind(parent_def_id) == DefKind::AnonConst + && let ty::AnonConstKind::MCG = tcx.anon_const_kind(parent_def_id) + // Fast path if contains no params/escaping bound vars. + && (term.has_param() || term.has_escaping_bound_vars()) + { + let mut folder = ForbidMCGParamUsesFolder { + tcx, + anon_const_def_id: parent_def_id, + span, + is_self_alias, + }; + term.fold_with(&mut folder) + } else { + term + } + } + /// Lower a lifetime from the HIR to our internal notion of a lifetime called a *region*. #[instrument(level = "debug", skip(self), ret)] pub fn lower_lifetime( @@ -403,7 +514,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { reason: RegionInferReason<'_>, ) -> ty::Region<'tcx> { if let Some(resolved) = self.tcx().named_bound_var(lifetime.hir_id) { - self.lower_resolved_lifetime(resolved) + let region = self.lower_resolved_lifetime(resolved); + self.check_param_uses_if_mcg(region, lifetime.ident.span, false) } else { self.re_infer(lifetime.ident.span, reason) } @@ -411,7 +523,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Lower a lifetime from the HIR to our internal notion of a lifetime called a *region*. #[instrument(level = "debug", skip(self), ret)] - pub fn lower_resolved_lifetime(&self, resolved: rbv::ResolvedArg) -> ty::Region<'tcx> { + fn lower_resolved_lifetime(&self, resolved: rbv::ResolvedArg) -> ty::Region<'tcx> { let tcx = self.tcx(); match resolved { @@ -1256,9 +1368,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { TypeRelativePath::AssocItem(def_id, args) => { let alias_ty = ty::AliasTy::new_from_args(tcx, def_id, args); let ty = Ty::new_alias(tcx, alias_ty.kind(tcx), alias_ty); + let ty = self.check_param_uses_if_mcg(ty, span, false); Ok((ty, tcx.def_kind(def_id), def_id)) } TypeRelativePath::Variant { adt, variant_did } => { + let adt = self.check_param_uses_if_mcg(adt, span, false); Ok((adt, DefKind::Variant, variant_did)) } } @@ -1275,7 +1389,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: Span, ) -> Result, ErrorGuaranteed> { let tcx = self.tcx(); - let (def_id, args) = match self.lower_type_relative_path( + match self.lower_type_relative_path( self_ty, hir_self_ty, segment, @@ -1292,15 +1406,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { err.note("the declaration in the trait must be marked with `#[type_const]`"); return Err(err.emit()); } - (def_id, args) + let ct = Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(def_id, args)); + let ct = self.check_param_uses_if_mcg(ct, span, false); + Ok(ct) } // FIXME(mgca): implement support for this once ready to support all adt ctor expressions, // not just const ctors TypeRelativePath::Variant { .. } => { span_bug!(span, "unexpected variant res for type associated const path") } - }; - Ok(Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(def_id, args))) + } } /// Lower a [type-relative][hir::QPath::TypeRelative] (and type-level) path. @@ -2032,9 +2147,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { GenericsArgsErrExtend::None }, ); - tcx.types.self_param + self.check_param_uses_if_mcg(tcx.types.self_param, span, false) } - Res::SelfTyAlias { alias_to: def_id, forbid_generic, .. } => { + Res::SelfTyAlias { alias_to: def_id, forbid_generic: _, .. } => { // `Self` in impl (we know the concrete type). assert_eq!(opt_self_ty, None); // Try to evaluate any array length constants. @@ -2043,42 +2158,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { path.segments.iter(), GenericsArgsErrExtend::SelfTyAlias { def_id, span }, ); - // HACK(min_const_generics): Forbid generic `Self` types - // here as we can't easily do that during nameres. - // - // We do this before normalization as we otherwise allow - // ```rust - // trait AlwaysApplicable { type Assoc; } - // impl AlwaysApplicable for T { type Assoc = usize; } - // - // trait BindsParam { - // type ArrayTy; - // } - // impl BindsParam for ::Assoc { - // type ArrayTy = [u8; Self::MAX]; - // } - // ``` - // Note that the normalization happens in the param env of - // the anon const, which is empty. This is why the - // `AlwaysApplicable` impl needs a `T: ?Sized` bound for - // this to compile if we were to normalize here. - if forbid_generic && ty.has_param() { - let mut err = self.dcx().struct_span_err( - path.span, - "generic `Self` types are currently not permitted in anonymous constants", - ); - if let Some(hir::Node::Item(&hir::Item { - kind: hir::ItemKind::Impl(impl_), - .. - })) = tcx.hir_get_if_local(def_id) - { - err.span_note(impl_.self_ty.span, "not a concrete type"); - } - let reported = err.emit(); - Ty::new_error(tcx, reported) - } else { - ty - } + self.check_param_uses_if_mcg(ty, span, true) } Res::Def(DefKind::AssocTy, def_id) => { let trait_segment = if let [modules @ .., trait_, _item] = path.segments { @@ -2138,7 +2218,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// and late-bound ones to [`ty::Bound`]. pub(crate) fn lower_ty_param(&self, hir_id: HirId) -> Ty<'tcx> { let tcx = self.tcx(); - match tcx.named_bound_var(hir_id) { + + let ty = match tcx.named_bound_var(hir_id) { Some(rbv::ResolvedArg::LateBound(debruijn, index, def_id)) => { let br = ty::BoundTy { var: ty::BoundVar::from_u32(index), @@ -2154,7 +2235,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } Some(rbv::ResolvedArg::Error(guar)) => Ty::new_error(tcx, guar), arg => bug!("unexpected bound var resolution for {hir_id:?}: {arg:?}"), - } + }; + self.check_param_uses_if_mcg(ty, tcx.hir_span(hir_id), false) } /// Lower a const parameter from the HIR to our internal notion of a constant. @@ -2164,7 +2246,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { pub(crate) fn lower_const_param(&self, param_def_id: DefId, path_hir_id: HirId) -> Const<'tcx> { let tcx = self.tcx(); - match tcx.named_bound_var(path_hir_id) { + let ct = match tcx.named_bound_var(path_hir_id) { Some(rbv::ResolvedArg::EarlyBound(_)) => { // Find the name and index of the const parameter by indexing the generics of // the parent item and construct a `ParamConst`. @@ -2181,7 +2263,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ), Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar), arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", path_hir_id), - } + }; + self.check_param_uses_if_mcg(ct, tcx.hir_span(path_hir_id), false) } /// Lower a [`hir::ConstArg`] to a (type-level) [`ty::Const`](Const). @@ -2386,7 +2469,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) -> Const<'tcx> { let tcx = self.tcx(); let span = path.span; - match path.res { + let ct = match path.res { Res::Def(DefKind::ConstParam, def_id) => { assert_eq!(opt_self_ty, None); let _ = self.prohibit_generic_args( @@ -2475,7 +2558,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span, format!("invalid Res {res:?} for const path"), ), - } + }; + self.check_param_uses_if_mcg(ct, span, false) } /// Literals are eagerly converted to a constant, everything else becomes `Unevaluated`. @@ -2787,6 +2871,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let args = ty::GenericArgs::for_item(tcx, def_id, |param, _| { if let Some(i) = (param.index as usize).checked_sub(offset) { let (lifetime, _) = lifetimes[i]; + // FIXME(mgca): should we be calling self.check_params_use_if_mcg here too? self.lower_resolved_lifetime(lifetime).into() } else { tcx.mk_param_from_def(param) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index ff85f53ddf30..339e77ac6edd 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1004,6 +1004,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err_extend, ); + if let Err(e) = self.lowerer().check_param_res_if_mcg_for_instantiate_value_path(res, span) + { + return (Ty::new_error(self.tcx, e), res); + } + if let Res::Local(hid) = res { let ty = self.local_ty(span, hid); let ty = self.normalize(span, ty); diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index b8a587016427..39c28c4f4e99 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -115,18 +115,6 @@ fn typeck_with_inspect<'tcx>( return tcx.typeck(typeck_root_def_id); } - // We can't handle bodies containing generic parameters even though - // these generic parameters aren't part of its `generics_of` right now. - // - // See the FIXME on `check_anon_const_invalid_param_uses`. - if tcx.features().min_generic_const_args() - && let DefKind::AnonConst = tcx.def_kind(def_id) - && let ty::AnonConstKind::MCG = tcx.anon_const_kind(def_id) - && let Err(e) = tcx.check_anon_const_invalid_param_uses(def_id) - { - e.raise_fatal(); - } - let id = tcx.local_def_id_to_hir_id(def_id); let node = tcx.hir_node(id); let span = tcx.def_span(def_id); diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index d62ddc915d17..8cc66802e435 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -2,8 +2,6 @@ //! eliminated, and all its methods are now on `TyCtxt`. But the module name //! stays as `map` because there isn't an obviously better name for it. -use std::ops::ControlFlow; - use rustc_abi::ExternAbi; use rustc_ast::visit::{VisitorResult, walk_list}; use rustc_data_structures::fingerprint::Fingerprint; @@ -1090,52 +1088,6 @@ impl<'tcx> TyCtxt<'tcx> { None } - - // FIXME(mgca): this is pretty iffy. In the long term we should make - // HIR ty lowering able to return `Error` versions of types/consts when - // lowering them in contexts that aren't supposed to use generic parameters. - // - // This current impl strategy is incomplete and doesn't handle `Self` ty aliases. - pub fn check_anon_const_invalid_param_uses( - self, - anon: LocalDefId, - ) -> Result<(), ErrorGuaranteed> { - struct GenericParamVisitor<'tcx>(TyCtxt<'tcx>); - impl<'tcx> Visitor<'tcx> for GenericParamVisitor<'tcx> { - type NestedFilter = nested_filter::OnlyBodies; - type Result = ControlFlow; - - fn maybe_tcx(&mut self) -> TyCtxt<'tcx> { - self.0 - } - - fn visit_path( - &mut self, - path: &crate::hir::Path<'tcx>, - _id: HirId, - ) -> ControlFlow { - if let Res::Def( - DefKind::TyParam | DefKind::ConstParam | DefKind::LifetimeParam, - _, - ) = path.res - { - let e = self.0.dcx().struct_span_err( - path.span, - "generic parameters may not be used in const operations", - ); - return ControlFlow::Break(e.emit()); - } - - intravisit::walk_path(self, path) - } - } - - let body = self.hir_maybe_body_owned_by(anon).unwrap(); - match GenericParamVisitor(self).visit_expr(&body.value) { - ControlFlow::Break(e) => Err(e), - ControlFlow::Continue(()) => Ok(()), - } - } } impl<'tcx> intravisit::HirTyCtxt<'tcx> for TyCtxt<'tcx> { diff --git a/tests/crashes/140891.rs b/tests/crashes/140891.rs deleted file mode 100644 index 421919403eff..000000000000 --- a/tests/crashes/140891.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ known-bug: #140891 -struct A {} -impl Iterator for A { - fn next() -> [(); std::mem::size_of::>] {} -} -fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/feature-attribute-missing-in-dependent-crate-ice.rs b/tests/ui/const-generics/generic_const_exprs/feature-attribute-missing-in-dependent-crate-ice.rs index b9537014767e..8d7ec1867857 100644 --- a/tests/ui/const-generics/generic_const_exprs/feature-attribute-missing-in-dependent-crate-ice.rs +++ b/tests/ui/const-generics/generic_const_exprs/feature-attribute-missing-in-dependent-crate-ice.rs @@ -11,7 +11,7 @@ struct Wrapper(i64); impl aux::FromSlice for Wrapper { fn validate_slice(_: &[[u8; Self::SIZE]]) -> Result<(), aux::Error> { - //~^ ERROR generic `Self` types are currently not permitted in anonymous constants + //~^ ERROR generic `Self` Ok(()) } } diff --git a/tests/ui/const-generics/ice-68875.rs b/tests/ui/const-generics/ice-68875.rs index cc9546be2c92..7bf6a824729a 100644 --- a/tests/ui/const-generics/ice-68875.rs +++ b/tests/ui/const-generics/ice-68875.rs @@ -1,7 +1,7 @@ //@ check-fail struct DataWrapper<'a> { - data: &'a [u8; Self::SIZE], //~ ERROR generic `Self` types are currently not permitted in anonymous constants + data: &'a [u8; Self::SIZE], //~ ERROR generic `Self` } impl DataWrapper<'_> { diff --git a/tests/ui/const-generics/issues/issue-56445-2.rs b/tests/ui/const-generics/issues/issue-56445-2.rs index e078c8487c72..11c844340080 100644 --- a/tests/ui/const-generics/issues/issue-56445-2.rs +++ b/tests/ui/const-generics/issues/issue-56445-2.rs @@ -5,7 +5,7 @@ impl<'a> OnDiskDirEntry<'a> { const LFN_FRAGMENT_LEN: usize = 2; fn lfn_contents(&self) -> [char; Self::LFN_FRAGMENT_LEN] { loop { } } - //~^ ERROR: generic `Self` types are currently not permitted in anonymous constants + //~^ ERROR: generic `Self` } fn main() {} diff --git a/tests/ui/const-generics/issues/issue-56445-3.rs b/tests/ui/const-generics/issues/issue-56445-3.rs index c29df14586e2..a9a4a48ab675 100644 --- a/tests/ui/const-generics/issues/issue-56445-3.rs +++ b/tests/ui/const-generics/issues/issue-56445-3.rs @@ -2,7 +2,7 @@ pub struct Memory<'rom> { rom: &'rom [u8], ram: [u8; Self::SIZE], - //~^ ERROR: generic `Self` types are currently not permitted in anonymous constants + //~^ ERROR: generic `Self` } impl<'rom> Memory<'rom> { diff --git a/tests/ui/const-generics/issues/issue-67945-2.rs b/tests/ui/const-generics/issues/issue-67945-2.rs index ce48b3f86a65..d3c5c891f760 100644 --- a/tests/ui/const-generics/issues/issue-67945-2.rs +++ b/tests/ui/const-generics/issues/issue-67945-2.rs @@ -7,7 +7,7 @@ struct Bug { A: [(); { //[full]~^ ERROR overly complex generic constant let x: Option> = None; - //[min]~^ ERROR generic `Self` types are currently not permitted in anonymous constants + //[min]~^ ERROR generic `Self` 0 }], B: S diff --git a/tests/ui/const-generics/mgca/early-bound-param-lt-bad.rs b/tests/ui/const-generics/mgca/early-bound-param-lt-bad.rs new file mode 100644 index 000000000000..0ee2b4eb45f6 --- /dev/null +++ b/tests/ui/const-generics/mgca/early-bound-param-lt-bad.rs @@ -0,0 +1,13 @@ +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +trait Trait {} + +fn foo<'a, T>() +where + 'a: 'a, + T: Trait + //~^ ERROR generic parameters may not be used in const operations +{} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/early-bound-param-lt-bad.stderr b/tests/ui/const-generics/mgca/early-bound-param-lt-bad.stderr new file mode 100644 index 000000000000..461a26e33a3c --- /dev/null +++ b/tests/ui/const-generics/mgca/early-bound-param-lt-bad.stderr @@ -0,0 +1,8 @@ +error: generic parameters may not be used in const operations + --> $DIR/early-bound-param-lt-bad.rs:9:30 + | +LL | T: Trait + | ^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts-7.rs b/tests/ui/const-generics/mgca/explicit_anon_consts-7.rs new file mode 100644 index 000000000000..d3288d00ba6e --- /dev/null +++ b/tests/ui/const-generics/mgca/explicit_anon_consts-7.rs @@ -0,0 +1,10 @@ +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] +// library crates exercise weirder code paths around +// DefIds which were created for const args. +#![crate_type = "lib"] + +fn foo() -> [(); N] { + let a: [(); const { N }] = todo!(); + //~^ ERROR: generic parameters may not be used in const operations +} diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts-7.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts-7.stderr new file mode 100644 index 000000000000..1b28c861067d --- /dev/null +++ b/tests/ui/const-generics/mgca/explicit_anon_consts-7.stderr @@ -0,0 +1,8 @@ +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts-7.rs:8:25 + | +LL | let a: [(); const { N }] = todo!(); + | ^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/higher-ranked-lts-bad.rs b/tests/ui/const-generics/mgca/higher-ranked-lts-bad.rs new file mode 100644 index 000000000000..368644b641df --- /dev/null +++ b/tests/ui/const-generics/mgca/higher-ranked-lts-bad.rs @@ -0,0 +1,12 @@ +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +trait Trait {} + +fn foo() +where + for<'a> T: Trait + //~^ ERROR cannot capture late-bound lifetime in constant +{} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/higher-ranked-lts-bad.stderr b/tests/ui/const-generics/mgca/higher-ranked-lts-bad.stderr new file mode 100644 index 000000000000..0f7389cac5cd --- /dev/null +++ b/tests/ui/const-generics/mgca/higher-ranked-lts-bad.stderr @@ -0,0 +1,8 @@ +error: cannot capture late-bound lifetime in constant + --> $DIR/higher-ranked-lts-bad.rs:8:38 + | +LL | for<'a> T: Trait + | -- lifetime defined here ^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/higher-ranked-lts-good.rs b/tests/ui/const-generics/mgca/higher-ranked-lts-good.rs new file mode 100644 index 000000000000..5b455bb1e71e --- /dev/null +++ b/tests/ui/const-generics/mgca/higher-ranked-lts-good.rs @@ -0,0 +1,13 @@ +//@ check-pass + +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +trait Trait {} + +fn foo() +where + T: Trait fn(&'a ()); 1 }> +{} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/late-bound-param-lt-bad.rs b/tests/ui/const-generics/mgca/late-bound-param-lt-bad.rs new file mode 100644 index 000000000000..5c57bdfb9024 --- /dev/null +++ b/tests/ui/const-generics/mgca/late-bound-param-lt-bad.rs @@ -0,0 +1,12 @@ +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +trait Trait {} + +fn foo<'a, T>() +where + T: Trait + //~^ ERROR cannot capture late-bound lifetime in constant +{} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/late-bound-param-lt-bad.stderr b/tests/ui/const-generics/mgca/late-bound-param-lt-bad.stderr new file mode 100644 index 000000000000..e5c22f282544 --- /dev/null +++ b/tests/ui/const-generics/mgca/late-bound-param-lt-bad.stderr @@ -0,0 +1,11 @@ +error: cannot capture late-bound lifetime in constant + --> $DIR/late-bound-param-lt-bad.rs:8:30 + | +LL | fn foo<'a, T>() + | -- lifetime defined here +LL | where +LL | T: Trait + | ^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/selftyalias-containing-param.rs b/tests/ui/const-generics/mgca/selftyalias-containing-param.rs new file mode 100644 index 000000000000..5ab39799078f --- /dev/null +++ b/tests/ui/const-generics/mgca/selftyalias-containing-param.rs @@ -0,0 +1,13 @@ +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +struct S([(); N]); + +impl S { + fn foo() -> [(); const { let _: Self = loop {}; 1 }] { + //~^ ERROR generic `Self` + todo!() + } +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/selftyalias-containing-param.stderr b/tests/ui/const-generics/mgca/selftyalias-containing-param.stderr new file mode 100644 index 000000000000..fdd3e6efdf65 --- /dev/null +++ b/tests/ui/const-generics/mgca/selftyalias-containing-param.stderr @@ -0,0 +1,14 @@ +error: generic `Self` types are currently not permitted in anonymous constants + --> $DIR/selftyalias-containing-param.rs:7:37 + | +LL | fn foo() -> [(); const { let _: Self = loop {}; 1 }] { + | ^^^^ + | +note: not a concrete type + --> $DIR/selftyalias-containing-param.rs:6:22 + | +LL | impl S { + | ^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/selftyparam.rs b/tests/ui/const-generics/mgca/selftyparam.rs new file mode 100644 index 000000000000..58433405b8ca --- /dev/null +++ b/tests/ui/const-generics/mgca/selftyparam.rs @@ -0,0 +1,9 @@ +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +trait Tr { + fn foo() -> [(); const { let _: Self; 1 }]; + //~^ ERROR generic parameters +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/selftyparam.stderr b/tests/ui/const-generics/mgca/selftyparam.stderr new file mode 100644 index 000000000000..376e63da9a75 --- /dev/null +++ b/tests/ui/const-generics/mgca/selftyparam.stderr @@ -0,0 +1,8 @@ +error: generic parameters may not be used in const operations + --> $DIR/selftyparam.rs:5:37 + | +LL | fn foo() -> [(); const { let _: Self; 1 }]; + | ^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/min_const_generics/forbid-self-no-normalize.rs b/tests/ui/const-generics/min_const_generics/forbid-self-no-normalize.rs index e1cf7b579aa5..b8739b263aee 100644 --- a/tests/ui/const-generics/min_const_generics/forbid-self-no-normalize.rs +++ b/tests/ui/const-generics/min_const_generics/forbid-self-no-normalize.rs @@ -9,7 +9,7 @@ trait BindsParam { type ArrayTy; } impl BindsParam for ::Assoc { - type ArrayTy = [u8; Self::MAX]; //~ ERROR generic `Self` types + type ArrayTy = [u8; Self::MAX]; //~ ERROR generic `Self` } fn main() {} diff --git a/tests/ui/const-generics/type-relative-path-144547.min.stderr b/tests/ui/const-generics/type-relative-path-144547.min.stderr new file mode 100644 index 000000000000..1192a7434ec8 --- /dev/null +++ b/tests/ui/const-generics/type-relative-path-144547.min.stderr @@ -0,0 +1,8 @@ +error: generic parameters may not be used in const operations + --> $DIR/type-relative-path-144547.rs:39:35 + | +LL | type SupportedArray = [T; ::SUPPORTED_SLOTS]; + | ^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/type-relative-path-144547.rs b/tests/ui/const-generics/type-relative-path-144547.rs new file mode 100644 index 000000000000..b268055e1f7d --- /dev/null +++ b/tests/ui/const-generics/type-relative-path-144547.rs @@ -0,0 +1,43 @@ +// Regression test for #144547. + +//@ revisions: min mgca +//@[mgca] check-pass + +#![cfg_attr(mgca, feature(min_generic_const_args))] +#![cfg_attr(mgca, expect(incomplete_features))] + +trait UnderlyingImpl { + type InfoType: LevelInfo; + type SupportedArray; +} + +// FIXME: cfg_attr(..., type_const) is broken (search for sym::type_const in compiler/) +trait LevelInfo { + #[cfg(mgca)] + #[type_const] + const SUPPORTED_SLOTS: usize; + + #[cfg(not(mgca))] + const SUPPORTED_SLOTS: usize; +} + +struct Info; + +impl LevelInfo for Info { + #[cfg(mgca)] + #[type_const] + const SUPPORTED_SLOTS: usize = 1; + + #[cfg(not(mgca))] + const SUPPORTED_SLOTS: usize = 1; +} + +struct SomeImpl; + +impl UnderlyingImpl for SomeImpl { + type InfoType = Info; + type SupportedArray = [T; ::SUPPORTED_SLOTS]; + //[min]~^ ERROR generic parameters +} + +fn main() {} From bad0c3230f4adab2dd3cd81ce97f9a3a01e34228 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Tue, 30 Dec 2025 18:13:56 -0800 Subject: [PATCH 0153/1061] mgca: Remove resolved FIXME --- .../rustc_hir_analysis/src/hir_ty_lowering/mod.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 4c7cfde638f5..48b2b80c8af3 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2604,20 +2604,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { _ => expr, }; - // FIXME(mgca): remove this delayed bug once we start checking this - // when lowering `Ty/ConstKind::Param`s more generally. - if let hir::ExprKind::Path(hir::QPath::Resolved( - _, - &hir::Path { res: Res::Def(DefKind::ConstParam, _), .. }, - )) = expr.kind - { - let e = tcx.dcx().span_delayed_bug( - expr.span, - "try_lower_anon_const_lit: received const param which shouldn't be possible", - ); - return Some(ty::Const::new_error(tcx, e)); - }; - let lit_input = match expr.kind { hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: lit.node, ty, neg: false }), hir::ExprKind::Unary(hir::UnOp::Neg, expr) => match expr.kind { From f71e93821eff7df12483ee1cb1d0dd7d397a4555 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 1 Jan 2026 14:44:07 -0800 Subject: [PATCH 0154/1061] mgca: Re-merge split out tests Now that we avoid a fatal error, they can all be one test. --- .../mgca/explicit_anon_consts-2.rs | 10 ---- .../mgca/explicit_anon_consts-2.stderr | 8 ---- .../mgca/explicit_anon_consts-3.rs | 10 ---- .../mgca/explicit_anon_consts-3.stderr | 8 ---- .../mgca/explicit_anon_consts-4.rs | 9 ---- .../mgca/explicit_anon_consts-4.stderr | 8 ---- .../mgca/explicit_anon_consts-5.rs | 16 ------- .../mgca/explicit_anon_consts-5.stderr | 8 ---- .../mgca/explicit_anon_consts-6.rs | 8 ---- .../mgca/explicit_anon_consts-6.stderr | 8 ---- .../mgca/explicit_anon_consts-7.rs | 10 ---- .../mgca/explicit_anon_consts-7.stderr | 8 ---- .../mgca/explicit_anon_consts.rs | 28 +++++------ .../mgca/explicit_anon_consts.stderr | 46 +++++++++++++++++-- 14 files changed, 55 insertions(+), 130 deletions(-) delete mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts-2.rs delete mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts-2.stderr delete mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts-3.rs delete mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts-3.stderr delete mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts-4.rs delete mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts-4.stderr delete mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts-5.rs delete mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts-5.stderr delete mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts-6.rs delete mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts-6.stderr delete mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts-7.rs delete mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts-7.stderr diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts-2.rs b/tests/ui/const-generics/mgca/explicit_anon_consts-2.rs deleted file mode 100644 index 37a3321a291e..000000000000 --- a/tests/ui/const-generics/mgca/explicit_anon_consts-2.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(associated_const_equality, generic_const_items, min_generic_const_args)] -#![expect(incomplete_features)] -// library crates exercise weirder code paths around -// DefIds which were created for const args. -#![crate_type = "lib"] - -struct Foo; - -type Alias = Foo; -//~^ ERROR: generic parameters may not be used in const operations diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts-2.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts-2.stderr deleted file mode 100644 index 8d8abd9ef313..000000000000 --- a/tests/ui/const-generics/mgca/explicit_anon_consts-2.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts-2.rs:9:42 - | -LL | type Alias = Foo; - | ^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts-3.rs b/tests/ui/const-generics/mgca/explicit_anon_consts-3.rs deleted file mode 100644 index ad7ae7c511ff..000000000000 --- a/tests/ui/const-generics/mgca/explicit_anon_consts-3.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(associated_const_equality, generic_const_items, min_generic_const_args)] -#![expect(incomplete_features)] -// library crates exercise weirder code paths around -// DefIds which were created for const args. -#![crate_type = "lib"] - -struct Foo; - -type Alias = [(); const { N }]; -//~^ ERROR: generic parameters may not be used in const operations diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts-3.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts-3.stderr deleted file mode 100644 index fe2c40486aeb..000000000000 --- a/tests/ui/const-generics/mgca/explicit_anon_consts-3.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts-3.rs:9:43 - | -LL | type Alias = [(); const { N }]; - | ^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts-4.rs b/tests/ui/const-generics/mgca/explicit_anon_consts-4.rs deleted file mode 100644 index bcf34bdb13ee..000000000000 --- a/tests/ui/const-generics/mgca/explicit_anon_consts-4.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![feature(associated_const_equality, generic_const_items, min_generic_const_args)] -#![expect(incomplete_features)] -// library crates exercise weirder code paths around -// DefIds which were created for const args. -#![crate_type = "lib"] - -#[type_const] -const ITEM3: usize = const { N }; -//~^ ERROR: generic parameters may not be used in const operations diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts-4.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts-4.stderr deleted file mode 100644 index 7fc78257aa2c..000000000000 --- a/tests/ui/const-generics/mgca/explicit_anon_consts-4.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts-4.rs:8:46 - | -LL | const ITEM3: usize = const { N }; - | ^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts-5.rs b/tests/ui/const-generics/mgca/explicit_anon_consts-5.rs deleted file mode 100644 index aa14ec4275e4..000000000000 --- a/tests/ui/const-generics/mgca/explicit_anon_consts-5.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![feature(associated_const_equality, generic_const_items, min_generic_const_args)] -#![expect(incomplete_features)] -// library crates exercise weirder code paths around -// DefIds which were created for const args. -#![crate_type = "lib"] - -trait Trait { - #[type_const] - const ASSOC: usize; -} - -fn ace_bounds< - const N: usize, - T: Trait, - //~^ ERROR: generic parameters may not be used in const operations ->() {} diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts-5.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts-5.stderr deleted file mode 100644 index 6d2ab078c8cf..000000000000 --- a/tests/ui/const-generics/mgca/explicit_anon_consts-5.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts-5.rs:14:30 - | -LL | T: Trait, - | ^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts-6.rs b/tests/ui/const-generics/mgca/explicit_anon_consts-6.rs deleted file mode 100644 index 600f4b9cd7f9..000000000000 --- a/tests/ui/const-generics/mgca/explicit_anon_consts-6.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(associated_const_equality, generic_const_items, min_generic_const_args)] -#![expect(incomplete_features)] -// library crates exercise weirder code paths around -// DefIds which were created for const args. -#![crate_type = "lib"] - -struct Default3; -//~^ ERROR: generic parameters may not be used in const operations diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts-6.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts-6.stderr deleted file mode 100644 index 727e478bee8e..000000000000 --- a/tests/ui/const-generics/mgca/explicit_anon_consts-6.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts-6.rs:7:58 - | -LL | struct Default3; - | ^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts-7.rs b/tests/ui/const-generics/mgca/explicit_anon_consts-7.rs deleted file mode 100644 index d3288d00ba6e..000000000000 --- a/tests/ui/const-generics/mgca/explicit_anon_consts-7.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(min_generic_const_args)] -#![expect(incomplete_features)] -// library crates exercise weirder code paths around -// DefIds which were created for const args. -#![crate_type = "lib"] - -fn foo() -> [(); N] { - let a: [(); const { N }] = todo!(); - //~^ ERROR: generic parameters may not be used in const operations -} diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts-7.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts-7.stderr deleted file mode 100644 index 1b28c861067d..000000000000 --- a/tests/ui/const-generics/mgca/explicit_anon_consts-7.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts-7.rs:8:25 - | -LL | let a: [(); const { N }] = todo!(); - | ^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts.rs b/tests/ui/const-generics/mgca/explicit_anon_consts.rs index f7df3eddfa64..f3edc0b3fbf3 100644 --- a/tests/ui/const-generics/mgca/explicit_anon_consts.rs +++ b/tests/ui/const-generics/mgca/explicit_anon_consts.rs @@ -4,27 +4,25 @@ // DefIds which were created for const args. #![crate_type = "lib"] -// FIXME(mgca): merge the split out parts of this test back in - struct Foo; type Adt1 = Foo; type Adt2 = Foo<{ N }>; -// explicit_anon_consts-2.rs -// type Adt3 = Foo; +type Adt3 = Foo; +//~^ ERROR: generic parameters may not be used in const operations type Adt4 = Foo<{ 1 + 1 }>; //~^ ERROR: complex const arguments must be placed inside of a `const` block type Adt5 = Foo; type Arr = [(); N]; type Arr2 = [(); { N }]; -// explicit_anon_consts-3.rs -// type Arr3 = [(); const { N }]; +type Arr3 = [(); const { N }]; +//~^ ERROR: generic parameters may not be used in const operations type Arr4 = [(); 1 + 1]; //~^ ERROR: complex const arguments must be placed inside of a `const` block type Arr5 = [(); const { 1 + 1 }]; -fn repeats() { +fn repeats() -> [(); N] { let _1 = [(); N]; let _2 = [(); { N }]; let _3 = [(); const { N }]; @@ -32,15 +30,17 @@ fn repeats() { let _4 = [(); 1 + 1]; //~^ ERROR: complex const arguments must be placed inside of a `const` block let _5 = [(); const { 1 + 1 }]; + let _6: [(); const { N }] = todo!(); + //~^ ERROR: generic parameters may not be used in const operations } #[type_const] const ITEM1: usize = N; #[type_const] const ITEM2: usize = { N }; -// explicit_anon_consts-4.rs -// #[type_const] -// const ITEM3: usize = const { N }; +#[type_const] +const ITEM3: usize = const { N }; +//~^ ERROR: generic parameters may not be used in const operations #[type_const] const ITEM4: usize = { 1 + 1 }; //~^ ERROR: complex const arguments must be placed inside of a `const` block @@ -57,8 +57,8 @@ fn ace_bounds< // We skip the T1 case because it doesn't resolve // T1: Trait, T2: Trait, - // explicit_anon_consts-5.rs - // T3: Trait, + T3: Trait, + //~^ ERROR: generic parameters may not be used in const operations T4: Trait, //~^ ERROR: complex const arguments must be placed inside of a `const` block T5: Trait, @@ -66,8 +66,8 @@ fn ace_bounds< struct Default1; struct Default2; -// explicit_anon_consts-6.rs -// struct Default3; +struct Default3; +//~^ ERROR: generic parameters may not be used in const operations struct Default4; //~^ ERROR: complex const arguments must be placed inside of a `const` block struct Default5; diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts.stderr index 1605dd8069d0..551815c4c31a 100644 --- a/tests/ui/const-generics/mgca/explicit_anon_consts.stderr +++ b/tests/ui/const-generics/mgca/explicit_anon_consts.stderr @@ -1,17 +1,17 @@ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:15:33 + --> $DIR/explicit_anon_consts.rs:13:33 | LL | type Adt4 = Foo<{ 1 + 1 }>; | ^^^^^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:23:34 + --> $DIR/explicit_anon_consts.rs:21:34 | LL | type Arr4 = [(); 1 + 1]; | ^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:32:19 + --> $DIR/explicit_anon_consts.rs:30:19 | LL | let _4 = [(); 1 + 1]; | ^^^^^ @@ -35,10 +35,46 @@ LL | struct Default4; | ^^^^^^^^^ error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts.rs:30:27 + --> $DIR/explicit_anon_consts.rs:42:46 + | +LL | const ITEM3: usize = const { N }; + | ^ + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:60:31 + | +LL | T3: Trait, + | ^ + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:69:58 + | +LL | struct Default3; + | ^ + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:28:27 | LL | let _3 = [(); const { N }]; | ^ -error: aborting due to 7 previous errors +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:33:26 + | +LL | let _6: [(); const { N }] = todo!(); + | ^ + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:11:41 + | +LL | type Adt3 = Foo; + | ^ + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:19:42 + | +LL | type Arr3 = [(); const { N }]; + | ^ + +error: aborting due to 13 previous errors From a3e6de6e81977797fb885e9004a15901d88c7c82 Mon Sep 17 00:00:00 2001 From: Alessio Date: Fri, 2 Jan 2026 03:21:59 +0100 Subject: [PATCH 0155/1061] docs: fix typo in AsMut documentation Corrected "work" to "works", and "byte vector" to "a byte vector" to match the phrasing of "a byte slice" in the documentation of the trait `AsMut` Fixes https://github.com/rust-lang/rust/issues/149609 --- library/core/src/convert/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 89cda30c0303..ef4ab15f93c0 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -308,8 +308,8 @@ pub const trait AsRef: PointeeSized { /// both `AsMut>` and `AsMut<[T]>`. /// /// In the following, the example functions `caesar` and `null_terminate` provide a generic -/// interface which work with any type that can be converted by cheap mutable-to-mutable conversion -/// into a byte slice (`[u8]`) or byte vector (`Vec`), respectively. +/// interface which works with any type that can be converted by cheap mutable-to-mutable conversion +/// into a byte slice (`[u8]`) or a byte vector (`Vec`), respectively. /// /// [dereference]: core::ops::DerefMut /// [target type]: core::ops::Deref::Target From 66c4ead02dda94846a0801cc88c04fb04cc561fe Mon Sep 17 00:00:00 2001 From: Ryan Ward Date: Fri, 2 Jan 2026 12:52:42 +1030 Subject: [PATCH 0156/1061] fix: added further `CHECK-SAME` labels and replaced all `struct` input tests with `NonZero` input --- .../issues/multiple-option-or-permutations.rs | 82 +++++++++++-------- 1 file changed, 50 insertions(+), 32 deletions(-) diff --git a/tests/codegen-llvm/issues/multiple-option-or-permutations.rs b/tests/codegen-llvm/issues/multiple-option-or-permutations.rs index 9fbd77166534..b45402f28a3a 100644 --- a/tests/codegen-llvm/issues/multiple-option-or-permutations.rs +++ b/tests/codegen-llvm/issues/multiple-option-or-permutations.rs @@ -3,12 +3,16 @@ #![crate_type = "lib"] +extern crate core; +use core::num::NonZero; + // CHECK-LABEL: @or_match_u8 +// CHECK-SAME: (i1{{.+}}%0, i8 %1, i1{{.+}}%optb.0, i8 %optb.1) #[no_mangle] pub fn or_match_u8(opta: Option, optb: Option) -> Option { // CHECK: start: - // CHECK-NEXT: or i1 %0 - // CHECK-NEXT: select i1 %0 + // CHECK-DAG: or i1 %0 + // CHECK-DAG: select i1 %0 // CHECK-NEXT: insertvalue { i1, i8 } // CHECK-NEXT: insertvalue { i1, i8 } // ret { i1, i8 } @@ -23,8 +27,8 @@ pub fn or_match_u8(opta: Option, optb: Option) -> Option { #[no_mangle] pub fn or_match_alt_u8(opta: Option, optb: Option) -> Option { // CHECK: start: - // CHECK-NEXT: select i1 - // CHECK-NEXT: or i1 + // CHECK-DAG: select i1 + // CHECK-DAG: or i1 // CHECK-NEXT: insertvalue { i1, i8 } // CHECK-NEXT: insertvalue { i1, i8 } // ret { i1, i8 } @@ -35,11 +39,12 @@ pub fn or_match_alt_u8(opta: Option, optb: Option) -> Option { } // CHECK-LABEL: @option_or_u8 +// CHECK-SAME: (i1{{.+}}%opta.0, i8 %opta.1, i1{{.+}}%optb.0, i8 %optb.1) #[no_mangle] pub fn option_or_u8(opta: Option, optb: Option) -> Option { // CHECK: start: - // CHECK-NEXT: select i1 - // CHECK-NEXT: or i1 + // CHECK-DAG: select i1 + // CHECK-DAG: or i1 // CHECK-NEXT: insertvalue { i1, i8 } // CHECK-NEXT: insertvalue { i1, i8 } // ret { i1, i8 } @@ -47,17 +52,20 @@ pub fn option_or_u8(opta: Option, optb: Option) -> Option { } // CHECK-LABEL: @if_some_u8 +// CHECK-SAME: (i1{{.+}}%opta.0, i8 %opta.1, i1{{.+}}%optb.0, i8 %optb.1) #[no_mangle] pub fn if_some_u8(opta: Option, optb: Option) -> Option { // CHECK: start: - // CHECK-NEXT: select i1 - // CHECK-NEXT: or i1 + // CHECK-DAG: select i1 + // CHECK-DAG: or i1 // CHECK-NEXT: insertvalue { i1, i8 } // CHECK-NEXT: insertvalue { i1, i8 } // ret { i1, i8 } if opta.is_some() { opta } else { optb } } +// Tests a case where an input is a type that is represented as `BackendRepr::Memory` + // CHECK-LABEL: @or_match_slice_u8 // CHECK-SAME: (i16 %0, i16 %1) #[no_mangle] @@ -73,6 +81,7 @@ pub fn or_match_slice_u8(opta: Option<[u8; 1]>, optb: Option<[u8; 1]>) -> Option } // CHECK-LABEL: @or_match_slice_alt_u8 +// CHECK-SAME: (i16 %0, i16 %1) #[no_mangle] pub fn or_match_slice_alt_u8(opta: Option<[u8; 1]>, optb: Option<[u8; 1]>) -> Option<[u8; 1]> { // CHECK: start: @@ -86,6 +95,7 @@ pub fn or_match_slice_alt_u8(opta: Option<[u8; 1]>, optb: Option<[u8; 1]>) -> Op } // CHECK-LABEL: @option_or_slice_u8 +// CHECK-SAME: (i16 %0, i16 %1) #[no_mangle] pub fn option_or_slice_u8(opta: Option<[u8; 1]>, optb: Option<[u8; 1]>) -> Option<[u8; 1]> { // CHECK: start: @@ -96,6 +106,7 @@ pub fn option_or_slice_u8(opta: Option<[u8; 1]>, optb: Option<[u8; 1]>) -> Optio } // CHECK-LABEL: @if_some_slice_u8 +// CHECK-SAME: (i16 %0, i16 %1) #[no_mangle] pub fn if_some_slice_u8(opta: Option<[u8; 1]>, optb: Option<[u8; 1]>) -> Option<[u8; 1]> { // CHECK: start: @@ -105,53 +116,60 @@ pub fn if_some_slice_u8(opta: Option<[u8; 1]>, optb: Option<[u8; 1]>) -> Option< if opta.is_some() { opta } else { optb } } -pub struct Test { - _a: u8, - _b: u8, -} +// Test a niche optimization case of `NonZero` -// CHECK-LABEL: @or_match_type +// CHECK-LABEL: @or_match_nz_u8 +// CHECK-SAME: (i8{{.+}}%0, i8{{.+}}%optb) #[no_mangle] -pub fn or_match_type(opta: Option, optb: Option) -> Option { +pub fn or_match_nz_u8(opta: Option>, optb: Option>) -> Option> { // CHECK: start: - // CHECK-NEXT: trunc i24 %0 to i1 - // CHECK-NEXT: select i1 %2, i24 %0, i24 %1 - // ret i24 + // CHECK-NEXT: [[NOT_A:%.*]] = icmp eq i8 %0, 0 + // CHECK-NEXT: select i1 [[NOT_A]], i8 %optb, i8 %0 + // ret i8 match opta { Some(x) => Some(x), None => optb, } } -// CHECK-LABEL: @or_match_alt_type +// CHECK-LABEL: @or_match_alt_nz_u8 +// CHECK-SAME: (i8{{.+}}%opta, i8{{.+}}%optb) #[no_mangle] -pub fn or_match_alt_type(opta: Option, optb: Option) -> Option { +pub fn or_match_alt_nz_u8( + opta: Option>, + optb: Option>, +) -> Option> { // CHECK: start: - // CHECK-NEXT: trunc i24 %0 to i1 - // CHECK-NEXT: select i1 %2, i24 %0, i24 %1 - // ret i24 + // CHECK-NEXT: [[NOT_A:%.*]] = icmp eq i8 %opta, 0 + // CHECK-NEXT: select i1 [[NOT_A]], i8 %optb, i8 %opta + // ret i8 match opta { Some(_) => opta, None => optb, } } -// CHECK-LABEL: @option_or_type +// CHECK-LABEL: @option_or_nz_u8 +// CHECK-SAME: (i8{{.+}}%opta, i8{{.+}}%optb) #[no_mangle] -pub fn option_or_type(opta: Option, optb: Option) -> Option { +pub fn option_or_nz_u8( + opta: Option>, + optb: Option>, +) -> Option> { // CHECK: start: - // CHECK-NEXT: trunc i24 %0 to i1 - // CHECK-NEXT: select i1 %2, i24 %0, i24 %1 - // ret i24 + // CHECK-NEXT: [[NOT_A:%.*]] = icmp eq i8 %opta, 0 + // CHECK-NEXT: select i1 [[NOT_A]], i8 %optb, i8 %opta + // ret i8 opta.or(optb) } -// CHECK-LABEL: @if_some_type +// CHECK-LABEL: @if_some_nz_u8 +// CHECK-SAME: (i8{{.+}}%opta, i8{{.+}}%optb) #[no_mangle] -pub fn if_some_type(opta: Option, optb: Option) -> Option { +pub fn if_some_nz_u8(opta: Option>, optb: Option>) -> Option> { // CHECK: start: - // CHECK-NEXT: trunc i24 %0 to i1 - // CHECK-NEXT: select i1 %2, i24 %0, i24 %1 - // ret i24 + // CHECK-NEXT: [[NOT_A:%.*]] = icmp eq i8 %opta, 0 + // CHECK-NEXT: select i1 [[NOT_A]], i8 %optb, i8 %opta + // ret i8 if opta.is_some() { opta } else { optb } } From 91e169b1c9e236774bc77683aedf145236ecc8fd Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 2 Jan 2026 13:30:04 +1100 Subject: [PATCH 0157/1061] Use clearer variable names in equality-test lowering --- .../src/builder/matches/test.rs | 50 +++++++++++-------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index 972d9f66fadd..3f402b2ae414 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -141,17 +141,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.terminate(block, self.source_info(match_start_span), terminator); } - TestKind::Eq { value, mut cast_ty } => { + TestKind::Eq { value, cast_ty: pat_ty } => { let tcx = self.tcx; let success_block = target_block(TestBranch::Success); let fail_block = target_block(TestBranch::Failure); - let mut expect_ty = value.ty; - let mut expect = self.literal_operand(test.span, Const::from_ty_value(tcx, value)); + let mut expected_value_ty = value.ty; + let mut expected_value_operand = + self.literal_operand(test.span, Const::from_ty_value(tcx, value)); - let mut place = place; + let mut actual_value_ty = pat_ty; + let mut actual_value_place = place; - match cast_ty.kind() { + match pat_ty.kind() { ty::Str => { // String literal patterns may have type `str` if `deref_patterns` is // enabled, in order to allow `deref!("..."): String`. In this case, `value` @@ -172,11 +174,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ref_place, Rvalue::Ref(re_erased, BorrowKind::Shared, place), ); - place = ref_place; - cast_ty = ref_str_ty; + actual_value_place = ref_place; + actual_value_ty = ref_str_ty; } &ty::Pat(base, _) => { - assert_eq!(cast_ty, value.ty); + assert_eq!(pat_ty, value.ty); assert!(base.is_trivially_pure_clone_copy()); let transmuted_place = self.temp(base, test.span); @@ -184,7 +186,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, self.source_info(scrutinee_span), transmuted_place, - Rvalue::Cast(CastKind::Transmute, Operand::Copy(place), base), + Rvalue::Cast( + CastKind::Transmute, + Operand::Copy(actual_value_place), + base, + ), ); let transmuted_expect = self.temp(base, test.span); @@ -192,19 +198,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, self.source_info(test.span), transmuted_expect, - Rvalue::Cast(CastKind::Transmute, expect, base), + Rvalue::Cast(CastKind::Transmute, expected_value_operand, base), ); - place = transmuted_place; - expect = Operand::Copy(transmuted_expect); - cast_ty = base; - expect_ty = base; + actual_value_place = transmuted_place; + actual_value_ty = base; + expected_value_operand = Operand::Copy(transmuted_expect); + expected_value_ty = base; } _ => {} } - assert_eq!(expect_ty, cast_ty); - if !cast_ty.is_scalar() { + assert_eq!(expected_value_ty, actual_value_ty); + if !actual_value_ty.is_scalar() { // Use `PartialEq::eq` instead of `BinOp::Eq` // (the binop can only handle primitives) // Make sure that we do *not* call any user-defined code here. @@ -212,12 +218,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // comparison defined in `core`. // (Interestingly this means that exhaustiveness analysis relies, for soundness, // on the `PartialEq` impl for `str` to b correct!) - match *cast_ty.kind() { + match *actual_value_ty.kind() { ty::Ref(_, deref_ty, _) if deref_ty == self.tcx.types.str_ => {} _ => { span_bug!( source_info.span, - "invalid type for non-scalar compare: {cast_ty}" + "invalid type for non-scalar compare: {actual_value_ty}" ) } }; @@ -226,8 +232,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { success_block, fail_block, source_info, - expect, - Operand::Copy(place), + expected_value_operand, + Operand::Copy(actual_value_place), ); } else { self.compare( @@ -236,8 +242,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fail_block, source_info, BinOp::Eq, - expect, - Operand::Copy(place), + expected_value_operand, + Operand::Copy(actual_value_place), ); } } From d68c980c22d95c95ce97b82d03cfd9d48badce30 Mon Sep 17 00:00:00 2001 From: Alessio Date: Fri, 2 Jan 2026 03:53:02 +0100 Subject: [PATCH 0158/1061] library: Document panic condition for `Iterator::last` Added a `# Panics` section to `Iterator::last` to match `Iterator::count`, after the change made in Rust 1.92.0 where now `std::iter::Repeat` panics in these methods instead of doing an infinite `loop`. Cites https://github.com/rust-lang/rust/issues/149707 --- library/core/src/iter/traits/iterator.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 29230b166538..84da778c3b91 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -236,6 +236,11 @@ pub trait Iterator { /// doing so, it keeps track of the current element. After [`None`] is /// returned, `last()` will then return the last element it saw. /// + /// # Panics + /// + /// This function might panic if the iterator has more than [`usize::MAX`] + /// elements. + /// /// # Examples /// /// ``` From 3c7c4398121b5752431ea2727534b87e434ebc10 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 2 Jan 2026 13:32:49 +1100 Subject: [PATCH 0159/1061] Split out a separate `PatConstKind::String` --- compiler/rustc_middle/src/ty/sty.rs | 6 +++++ .../src/builder/matches/buckets.rs | 9 ++++++-- .../src/builder/matches/match_pair.rs | 15 +++++++++++- .../src/builder/matches/mod.rs | 23 ++++++++++++------- .../src/builder/matches/test.rs | 10 ++++---- 5 files changed, 47 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index c3834607e923..c282f2211f65 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1218,6 +1218,12 @@ impl<'tcx> Ty<'tcx> { *self.kind() == Str } + /// Returns true if this type is `&str`. The reference's lifetime is ignored. + #[inline] + pub fn is_imm_ref_str(self) -> bool { + matches!(self.kind(), ty::Ref(_, inner, hir::Mutability::Not) if inner.is_str()) + } + #[inline] pub fn is_param(self, index: u32) -> bool { match self.kind() { diff --git a/compiler/rustc_mir_build/src/builder/matches/buckets.rs b/compiler/rustc_mir_build/src/builder/matches/buckets.rs index fce35aa9ef30..0d2e9bf87585 100644 --- a/compiler/rustc_mir_build/src/builder/matches/buckets.rs +++ b/compiler/rustc_mir_build/src/builder/matches/buckets.rs @@ -314,7 +314,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ( - TestKind::Eq { value: test_val, .. }, + TestKind::StringEq { value: test_val, .. }, + TestableCase::Constant { value: case_val, kind: PatConstKind::String }, + ) + | ( + TestKind::ScalarEq { value: test_val, .. }, TestableCase::Constant { value: case_val, kind: PatConstKind::Float | PatConstKind::Other, @@ -347,7 +351,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | TestKind::If | TestKind::SliceLen { .. } | TestKind::Range { .. } - | TestKind::Eq { .. } + | TestKind::StringEq { .. } + | TestKind::ScalarEq { .. } | TestKind::Deref { .. }, _, ) => { diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index 386ca61a6124..f0114c2193c3 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -2,6 +2,7 @@ use std::sync::Arc; use rustc_abi::FieldIdx; use rustc_middle::mir::*; +use rustc_middle::span_bug; use rustc_middle::thir::*; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; @@ -173,9 +174,21 @@ impl<'tcx> MatchPairTree<'tcx> { PatConstKind::IntOrChar } else if pat_ty.is_floating_point() { PatConstKind::Float + } else if pat_ty.is_str() { + // Deref-patterns can cause string-literal patterns to have + // type `str` instead of the usual `&str`. + if !cx.tcx.features().deref_patterns() { + span_bug!( + pattern.span, + "const pattern has type `str` but deref_patterns is not enabled" + ); + } + PatConstKind::String + } else if pat_ty.is_imm_ref_str() { + PatConstKind::String } else { // FIXME(Zalathar): This still covers several different - // categories (e.g. raw pointer, string, pattern-type) + // categories (e.g. raw pointer, pattern-type) // which could be split out into their own kinds. PatConstKind::Other }; diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 421065a89411..9080e2ba801b 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -1290,9 +1290,10 @@ enum PatConstKind { /// These types don't support `SwitchInt` and require an equality test, /// but can also interact with range pattern tests. Float, + /// Constant string values, tested via string equality. + String, /// Any other constant-pattern is usually tested via some kind of equality /// check. Types that might be encountered here include: - /// - `&str` /// - raw pointers derived from integer values /// - pattern types, e.g. `pattern_type!(u32 is 1..)` Other, @@ -1368,14 +1369,20 @@ enum TestKind<'tcx> { /// Test whether a `bool` is `true` or `false`. If, - /// Test for equality with value, possibly after an unsizing coercion to - /// `cast_ty`, - Eq { + /// Tests the place against a string constant using string equality. + StringEq { + /// Constant `&str` value to test against. value: ty::Value<'tcx>, - // Integer types are handled by `SwitchInt`, and constants with ADT - // types and `&[T]` types are converted back into patterns, so this can - // only be `&str` or floats. - cast_ty: Ty<'tcx>, + /// Type of the corresponding pattern node. Usually `&str`, but could + /// be `str` for patterns like `deref!("..."): String`. + pat_ty: Ty<'tcx>, + }, + + /// Tests the place against a constant using scalar equality. + ScalarEq { + value: ty::Value<'tcx>, + /// Type of the corresponding pattern node. + pat_ty: Ty<'tcx>, }, /// Test whether the value falls within an inclusive or exclusive range. diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index 3f402b2ae414..cb0e28c7234f 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -38,11 +38,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TestableCase::Constant { value: _, kind: PatConstKind::IntOrChar } => { TestKind::SwitchInt } - TestableCase::Constant { value, kind: PatConstKind::Float } => { - TestKind::Eq { value, cast_ty: match_pair.pattern_ty } + TestableCase::Constant { value, kind: PatConstKind::String } => { + TestKind::StringEq { value, pat_ty: match_pair.pattern_ty } } - TestableCase::Constant { value, kind: PatConstKind::Other } => { - TestKind::Eq { value, cast_ty: match_pair.pattern_ty } + TestableCase::Constant { value, kind: PatConstKind::Float | PatConstKind::Other } => { + TestKind::ScalarEq { value, pat_ty: match_pair.pattern_ty } } TestableCase::Range(ref range) => { @@ -141,7 +141,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.terminate(block, self.source_info(match_start_span), terminator); } - TestKind::Eq { value, cast_ty: pat_ty } => { + TestKind::StringEq { value, pat_ty } | TestKind::ScalarEq { value, pat_ty } => { let tcx = self.tcx; let success_block = target_block(TestBranch::Success); let fail_block = target_block(TestBranch::Failure); From 7749e75677c55900235f5196cd9921215f555465 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 2 Jan 2026 13:36:01 +1100 Subject: [PATCH 0160/1061] Split the cases for lowering string-equality and scalar-equality tests --- .../src/builder/matches/test.rs | 85 ++++++++++--------- 1 file changed, 46 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index cb0e28c7234f..c2e39d47a92c 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -141,13 +141,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.terminate(block, self.source_info(match_start_span), terminator); } - TestKind::StringEq { value, pat_ty } | TestKind::ScalarEq { value, pat_ty } => { + TestKind::StringEq { value, pat_ty } => { let tcx = self.tcx; let success_block = target_block(TestBranch::Success); let fail_block = target_block(TestBranch::Failure); - let mut expected_value_ty = value.ty; - let mut expected_value_operand = + let expected_value_ty = value.ty; + let expected_value_operand = self.literal_operand(test.span, Const::from_ty_value(tcx, value)); let mut actual_value_ty = pat_ty; @@ -177,6 +177,38 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { actual_value_place = ref_place; actual_value_ty = ref_str_ty; } + _ => {} + } + + assert_eq!(expected_value_ty, actual_value_ty); + assert!(actual_value_ty.is_imm_ref_str()); + + // Compare two strings using `::eq`. + // (Interestingly this means that exhaustiveness analysis relies, for soundness, + // on the `PartialEq` impl for `str` to be correct!) + self.string_compare( + block, + success_block, + fail_block, + source_info, + expected_value_operand, + Operand::Copy(actual_value_place), + ); + } + + TestKind::ScalarEq { value, pat_ty } => { + let tcx = self.tcx; + let success_block = target_block(TestBranch::Success); + let fail_block = target_block(TestBranch::Failure); + + let mut expected_value_ty = value.ty; + let mut expected_value_operand = + self.literal_operand(test.span, Const::from_ty_value(tcx, value)); + + let mut actual_value_ty = pat_ty; + let mut actual_value_place = place; + + match pat_ty.kind() { &ty::Pat(base, _) => { assert_eq!(pat_ty, value.ty); assert!(base.is_trivially_pure_clone_copy()); @@ -210,42 +242,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } assert_eq!(expected_value_ty, actual_value_ty); - if !actual_value_ty.is_scalar() { - // Use `PartialEq::eq` instead of `BinOp::Eq` - // (the binop can only handle primitives) - // Make sure that we do *not* call any user-defined code here. - // The only type that can end up here is string literals, which have their - // comparison defined in `core`. - // (Interestingly this means that exhaustiveness analysis relies, for soundness, - // on the `PartialEq` impl for `str` to b correct!) - match *actual_value_ty.kind() { - ty::Ref(_, deref_ty, _) if deref_ty == self.tcx.types.str_ => {} - _ => { - span_bug!( - source_info.span, - "invalid type for non-scalar compare: {actual_value_ty}" - ) - } - }; - self.string_compare( - block, - success_block, - fail_block, - source_info, - expected_value_operand, - Operand::Copy(actual_value_place), - ); - } else { - self.compare( - block, - success_block, - fail_block, - source_info, - BinOp::Eq, - expected_value_operand, - Operand::Copy(actual_value_place), - ); - } + assert!(actual_value_ty.is_scalar()); + + self.compare( + block, + success_block, + fail_block, + source_info, + BinOp::Eq, + expected_value_operand, + Operand::Copy(actual_value_place), + ); } TestKind::Range(ref range) => { From aa4ec54dfe9e63f146847265ed0655ffa9027cea Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Fri, 2 Jan 2026 04:52:22 +0000 Subject: [PATCH 0161/1061] fix: `cmp_owned` wrongly unmangled macros --- clippy_lints/src/operators/cmp_owned.rs | 58 +++++++++-------------- tests/ui/cmp_owned/with_suggestion.fixed | 29 ++++++++++++ tests/ui/cmp_owned/with_suggestion.rs | 29 ++++++++++++ tests/ui/cmp_owned/with_suggestion.stderr | 8 +++- 4 files changed, 87 insertions(+), 37 deletions(-) diff --git a/clippy_lints/src/operators/cmp_owned.rs b/clippy_lints/src/operators/cmp_owned.rs index 05358de5b348..39097833a6c5 100644 --- a/clippy_lints/src/operators/cmp_owned.rs +++ b/clippy_lints/src/operators/cmp_owned.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeQPath; -use clippy_utils::source::snippet; +use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{implements_trait, is_copy}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; @@ -94,51 +94,37 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) return; } - let arg_snip = snippet(cx, arg_span, ".."); - let expr_snip; - let eq_impl; - if with_deref.is_implemented() && !arg_ty.peel_refs().is_str() { - expr_snip = format!("*{arg_snip}"); - eq_impl = with_deref; + let mut applicability = Applicability::MachineApplicable; + let (arg_snip, _) = snippet_with_context(cx, arg_span, expr.span.ctxt(), "..", &mut applicability); + let (expr_snip, eq_impl) = if with_deref.is_implemented() && !arg_ty.peel_refs().is_str() { + (format!("*{arg_snip}"), with_deref) } else { - expr_snip = arg_snip.to_string(); - eq_impl = without_deref; - } + (arg_snip.to_string(), without_deref) + }; - let span; - let hint; - if (eq_impl.ty_eq_other && left) || (eq_impl.other_eq_ty && !left) { - span = expr.span; - hint = expr_snip; + let (span, hint) = if (eq_impl.ty_eq_other && left) || (eq_impl.other_eq_ty && !left) { + (expr.span, expr_snip) } else { - span = expr.span.to(other.span); + let span = expr.span.to(other.span); let cmp_span = if other.span < expr.span { other.span.between(expr.span) } else { expr.span.between(other.span) }; - if eq_impl.ty_eq_other { - hint = format!( - "{expr_snip}{}{}", - snippet(cx, cmp_span, ".."), - snippet(cx, other.span, "..") - ); - } else { - hint = format!( - "{}{}{expr_snip}", - snippet(cx, other.span, ".."), - snippet(cx, cmp_span, "..") - ); - } - } - diag.span_suggestion( - span, - "try", - hint, - Applicability::MachineApplicable, // snippet - ); + let (cmp_snippet, _) = snippet_with_context(cx, cmp_span, expr.span.ctxt(), "..", &mut applicability); + let (other_snippet, _) = + snippet_with_context(cx, other.span, expr.span.ctxt(), "..", &mut applicability); + + if eq_impl.ty_eq_other { + (span, format!("{expr_snip}{cmp_snippet}{other_snippet}")) + } else { + (span, format!("{other_snippet}{cmp_snippet}{expr_snip}")) + } + }; + + diag.span_suggestion(span, "try", hint, applicability); }, ); } diff --git a/tests/ui/cmp_owned/with_suggestion.fixed b/tests/ui/cmp_owned/with_suggestion.fixed index 85d0991bef05..4c3b13b30043 100644 --- a/tests/ui/cmp_owned/with_suggestion.fixed +++ b/tests/ui/cmp_owned/with_suggestion.fixed @@ -83,3 +83,32 @@ fn issue_8103() { let _ = foo1 == foo2; //~^ cmp_owned } + +macro_rules! issue16322_macro_generator { + ($locale:ident) => { + mod $locale { + macro_rules! _make { + ($token:tt) => { + stringify!($token) + }; + } + + pub(crate) use _make; + } + + macro_rules! t { + ($token:tt) => { + crate::$locale::_make!($token) + }; + } + }; +} + +issue16322_macro_generator!(de); + +fn issue16322(item: String) { + if item == t!(frohes_neu_Jahr) { + //~^ cmp_owned + println!("Ja!"); + } +} diff --git a/tests/ui/cmp_owned/with_suggestion.rs b/tests/ui/cmp_owned/with_suggestion.rs index 2393757d76f2..a9d7509feaaf 100644 --- a/tests/ui/cmp_owned/with_suggestion.rs +++ b/tests/ui/cmp_owned/with_suggestion.rs @@ -83,3 +83,32 @@ fn issue_8103() { let _ = foo1 == foo2.to_owned(); //~^ cmp_owned } + +macro_rules! issue16322_macro_generator { + ($locale:ident) => { + mod $locale { + macro_rules! _make { + ($token:tt) => { + stringify!($token) + }; + } + + pub(crate) use _make; + } + + macro_rules! t { + ($token:tt) => { + crate::$locale::_make!($token) + }; + } + }; +} + +issue16322_macro_generator!(de); + +fn issue16322(item: String) { + if item == t!(frohes_neu_Jahr).to_string() { + //~^ cmp_owned + println!("Ja!"); + } +} diff --git a/tests/ui/cmp_owned/with_suggestion.stderr b/tests/ui/cmp_owned/with_suggestion.stderr index dd9ffa70897a..66544ce0c217 100644 --- a/tests/ui/cmp_owned/with_suggestion.stderr +++ b/tests/ui/cmp_owned/with_suggestion.stderr @@ -49,5 +49,11 @@ error: this creates an owned instance just for comparison LL | let _ = foo1 == foo2.to_owned(); | ^^^^^^^^^^^^^^^ help: try: `foo2` -error: aborting due to 8 previous errors +error: this creates an owned instance just for comparison + --> tests/ui/cmp_owned/with_suggestion.rs:110:16 + | +LL | if item == t!(frohes_neu_Jahr).to_string() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t!(frohes_neu_Jahr)` + +error: aborting due to 9 previous errors From 2c31b0deb13d9d49ea4b651b81765b9acb446d5a Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Fri, 2 Jan 2026 15:59:03 +0900 Subject: [PATCH 0162/1061] check if redundant args spans belong to the same context --- .../errors/wrong_number_of_generic_args.rs | 3 ++ .../generics/wrong-number-of-args-in-macro.rs | 15 +++++++ .../wrong-number-of-args-in-macro.stderr | 44 +++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 tests/ui/generics/wrong-number-of-args-in-macro.rs create mode 100644 tests/ui/generics/wrong-number-of-args-in-macro.stderr diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs index d835a7bbb8d2..2b7854769b42 100644 --- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs @@ -988,6 +988,9 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { gen_arg_spans[self.num_expected_type_or_const_args() - 1] }; let span_hi_redundant_type_or_const_args = gen_arg_spans[gen_arg_spans.len() - 1]; + if !span_lo_redundant_type_or_const_args.eq_ctxt(span_hi_redundant_type_or_const_args) { + return; + } let span_redundant_type_or_const_args = span_lo_redundant_type_or_const_args .shrink_to_hi() .to(span_hi_redundant_type_or_const_args); diff --git a/tests/ui/generics/wrong-number-of-args-in-macro.rs b/tests/ui/generics/wrong-number-of-args-in-macro.rs new file mode 100644 index 000000000000..953e05434d25 --- /dev/null +++ b/tests/ui/generics/wrong-number-of-args-in-macro.rs @@ -0,0 +1,15 @@ +// Regression test for #149559 + +struct Foo; //~ ERROR type parameter `T` is never used + +macro_rules! foo_ty { + ($a:ty, $b:ty) => { + Foo + //~^ ERROR cannot find type `a` in this scope + //~| ERROR struct takes 1 generic argument but 2 generic arguments were supplied + }; +} + +fn foo<'a, 'b>() -> foo_ty!(&'b (), &'b ()) {} + +fn main() {} diff --git a/tests/ui/generics/wrong-number-of-args-in-macro.stderr b/tests/ui/generics/wrong-number-of-args-in-macro.stderr new file mode 100644 index 000000000000..62a5eb9414ed --- /dev/null +++ b/tests/ui/generics/wrong-number-of-args-in-macro.stderr @@ -0,0 +1,44 @@ +error[E0425]: cannot find type `a` in this scope + --> $DIR/wrong-number-of-args-in-macro.rs:7:13 + | +LL | Foo + | ^ not found in this scope +... +LL | fn foo<'a, 'b>() -> foo_ty!(&'b (), &'b ()) {} + | ----------------------- in this macro invocation + | + = note: this error originates in the macro `foo_ty` (in Nightly builds, run with -Z macro-backtrace for more info) +help: you might be missing a type parameter + | +LL | fn foo<'a, 'b, a>() -> foo_ty!(&'b (), &'b ()) {} + | +++ + +error[E0107]: struct takes 1 generic argument but 2 generic arguments were supplied + --> $DIR/wrong-number-of-args-in-macro.rs:7:9 + | +LL | Foo + | ^^^ expected 1 generic argument +... +LL | fn foo<'a, 'b>() -> foo_ty!(&'b (), &'b ()) {} + | ----------------------- in this macro invocation + | +note: struct defined here, with 1 generic parameter: `T` + --> $DIR/wrong-number-of-args-in-macro.rs:3:8 + | +LL | struct Foo; + | ^^^ - + = note: this error originates in the macro `foo_ty` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0392]: type parameter `T` is never used + --> $DIR/wrong-number-of-args-in-macro.rs:3:12 + | +LL | struct Foo; + | ^ unused type parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0107, E0392, E0425. +For more information about an error, try `rustc --explain E0107`. From 7668154418edb8e61c1cec5e5ff05e5430f73d34 Mon Sep 17 00:00:00 2001 From: Aaryan Agrawal Date: Fri, 2 Jan 2026 14:09:39 +0530 Subject: [PATCH 0163/1061] triagebot: add autolabel for rustdoc JS files --- triagebot.toml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index fb6660b9dd03..b17c76adf33b 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -332,6 +332,14 @@ trigger_labels = [ "A-type-based-search", ] +[autolabel."A-rustdoc-js"] +trigger_files = [ + "src/librustdoc/html/static/js/", + "src/librustdoc/html/static/css/", + "tests/rustdoc-js/", + "tests/rustdoc-js-std/", +] + [autolabel."T-compiler"] trigger_files = [ # Source code From 7b8d4c602ee8af316ef06838fafbc1c4da940550 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 31 Dec 2025 11:11:44 +0100 Subject: [PATCH 0164/1061] Rename the `gcc` component to `gcc-dev` To free up the `gcc` name for the actual libgccjit component that we will ship to rustup, and also make it more explicit that this component is internal and for bootstrap usages only. --- src/bootstrap/src/core/build_steps/dist.rs | 14 ++++++++------ src/bootstrap/src/core/builder/mod.rs | 2 +- src/bootstrap/src/core/download.rs | 2 +- .../docker/host-x86_64/dist-x86_64-linux/dist.sh | 4 ++-- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index b9ec063f4352..46cf7aed383b 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -2871,24 +2871,26 @@ impl Step for ReproducibleArtifacts { /// Tarball containing a prebuilt version of the libgccjit library, /// needed as a dependency for the GCC codegen backend (similarly to the LLVM /// backend needing a prebuilt libLLVM). +/// +/// This component is used for `download-ci-gcc`. #[derive(Clone, Debug, Eq, Hash, PartialEq)] -pub struct Gcc { +pub struct GccDev { target: TargetSelection, } -impl Step for Gcc { +impl Step for GccDev { type Output = GeneratedTarball; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.alias("gcc") + run.alias("gcc-dev") } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Gcc { target: run.target }); + run.builder.ensure(GccDev { target: run.target }); } fn run(self, builder: &Builder<'_>) -> Self::Output { - let tarball = Tarball::new(builder, "gcc", &self.target.triple); + let tarball = Tarball::new(builder, "gcc-dev", &self.target.triple); let output = builder .ensure(super::gcc::Gcc { target_pair: GccTargetPair::for_native_build(self.target) }); tarball.add_file(output.libgccjit(), "lib", FileType::NativeLibrary); @@ -2896,6 +2898,6 @@ impl Step for Gcc { } fn metadata(&self) -> Option { - Some(StepMetadata::dist("gcc", self.target)) + Some(StepMetadata::dist("gcc-dev", self.target)) } } diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 7d2b1685bda9..92a6eb8ce837 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -989,7 +989,7 @@ impl<'a> Builder<'a> { dist::PlainSourceTarballGpl, dist::BuildManifest, dist::ReproducibleArtifacts, - dist::Gcc + dist::GccDev ), Kind::Install => describe!( install::Docs, diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index d950dc1a1c58..43efdcd7db17 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -381,7 +381,7 @@ impl Config { } let base = &self.stage0_metadata.config.artifacts_server; let version = self.artifact_version_part(gcc_sha); - let filename = format!("gcc-{version}-{}.tar.xz", self.host_target.triple); + let filename = format!("gcc-dev-{version}-{}.tar.xz", self.host_target.triple); let tarball = gcc_cache.join(&filename); if !tarball.exists() { let help_on_error = "ERROR: failed to download gcc from ci diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh index 4c95d4a401e5..9579e0d79cb0 100755 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh @@ -9,8 +9,8 @@ python3 ../x.py build --set rust.debug=true opt-dist --include-default-paths \ build-manifest bootstrap -# Use GCC for building GCC, as it seems to behave badly when built with Clang +# Use GCC for building GCC components, as it seems to behave badly when built with Clang # Only build GCC on full builds, not try builds if [ "${DIST_TRY_BUILD:-0}" == "0" ]; then - CC=/rustroot/bin/cc CXX=/rustroot/bin/c++ python3 ../x.py dist gcc + CC=/rustroot/bin/cc CXX=/rustroot/bin/c++ python3 ../x.py dist gcc-dev fi From 4129f3aeef37e1ec9d79863f88ece1e13eeb9800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 31 Dec 2025 11:12:05 +0100 Subject: [PATCH 0165/1061] Temporarily disable `gcc.download-ci-gcc` Because we renamed the CI component. We will have to re-enable it in a follow-up PR. --- src/ci/run.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ci/run.sh b/src/ci/run.sh index b486f0525f40..425ad38a6655 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -187,8 +187,9 @@ else RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set llvm.static-libstdcpp" fi - # Download GCC from CI on test builders - RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set gcc.download-ci-gcc=true" + # Download GCC from CI on test builders (temporarily disabled because the CI gcc component + # was renamed). + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set gcc.download-ci-gcc=false" # download-rustc seems to be broken on CI after the stage0 redesign # Disable it until these issues are debugged and resolved From 2a893bd67feeda40adc8fa962988703cda3199b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 31 Dec 2025 13:41:31 +0100 Subject: [PATCH 0166/1061] Remove unused GCC ignore in opt-dist The `CiGcc` step is not enabled by defaut, so it does not have to be skipped. --- src/tools/opt-dist/src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs index 48b25f235dd6..5515dbf1940e 100644 --- a/src/tools/opt-dist/src/main.rs +++ b/src/tools/opt-dist/src/main.rs @@ -454,7 +454,6 @@ fn main() -> anyhow::Result<()> { "clippy", "miri", "rustfmt", - "gcc", "generate-copyright", "bootstrap", ] { From 4b34f4f4fbc1cb43307d31ed349909c53843a6d1 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 2 Jan 2026 10:19:02 +0100 Subject: [PATCH 0167/1061] minor: Fix some minor FIXMEs --- .../crates/hir-def/src/expr_store.rs | 8 ++++---- .../crates/hir-def/src/expr_store/expander.rs | 7 +------ .../crates/hir-def/src/expr_store/lower.rs | 19 +++++++++---------- .../src/expr_store/lower/format_args.rs | 3 ++- .../crates/hir-def/src/hir/generics.rs | 3 +-- .../hir-def/src/nameres/path_resolution.rs | 2 -- .../crates/hir-def/src/resolver.rs | 2 +- .../crates/hir/src/has_source.rs | 2 +- .../crates/rust-analyzer/src/lib.rs | 3 +++ 9 files changed, 22 insertions(+), 27 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs index 66f7e25ffac4..10cd460d1d36 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs @@ -57,8 +57,7 @@ impl HygieneId { Self(ctx) } - // FIXME: Inline this - pub(crate) fn lookup(self) -> SyntaxContext { + pub(crate) fn syntax_context(self) -> SyntaxContext { self.0 } @@ -73,7 +72,8 @@ pub type ExprSource = InFile; pub type PatPtr = AstPtr; pub type PatSource = InFile; -pub type LabelPtr = AstPtr; +/// BlockExpr -> Desugared label from try block +pub type LabelPtr = AstPtr>; pub type LabelSource = InFile; pub type FieldPtr = AstPtr; @@ -942,7 +942,7 @@ impl ExpressionStoreSourceMap { } pub fn node_label(&self, node: InFile<&ast::Label>) -> Option { - let src = node.map(AstPtr::new); + let src = node.map(AstPtr::new).map(AstPtr::wrap_left); self.expr_only()?.label_map.get(&src).cloned() } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs index 6a2f06b0a6f6..de5974fff1ad 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs @@ -11,7 +11,7 @@ use hir_expand::{ ExpandError, ExpandErrorKind, ExpandResult, HirFileId, InFile, Lookup, MacroCallId, eager::EagerCallBackFn, mod_path::ModPath, span_map::SpanMap, }; -use span::{AstIdMap, Edition, SyntaxContext}; +use span::{AstIdMap, SyntaxContext}; use syntax::ast::HasAttrs; use syntax::{AstNode, Parse, ast}; use triomphe::Arc; @@ -75,11 +75,6 @@ impl Expander { AttrFlags::is_cfg_enabled_for(owner, cfg_options) } - pub(super) fn call_syntax_ctx(&self) -> SyntaxContext { - // FIXME: - SyntaxContext::root(Edition::CURRENT_FIXME) - } - pub(super) fn enter_expand( &mut self, db: &dyn DefDatabase, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs index 42b076abb2a6..af274f1a485b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs @@ -1096,7 +1096,7 @@ impl<'db> ExprCollector<'db> { ast::Expr::WhileExpr(e) => self.collect_while_loop(syntax_ptr, e), ast::Expr::ForExpr(e) => self.collect_for_loop(syntax_ptr, e), ast::Expr::CallExpr(e) => { - // FIXME: Remove this once we drop support for <1.86, https://github.com/rust-lang/rust/commit/ac9cb908ac4301dfc25e7a2edee574320022ae2c + // FIXME(MINIMUM_SUPPORTED_TOOLCHAIN_VERSION): Remove this once we drop support for <1.86, https://github.com/rust-lang/rust/commit/ac9cb908ac4301dfc25e7a2edee574320022ae2c let is_rustc_box = { let attrs = e.attrs(); attrs.filter_map(|it| it.as_simple_atom()).any(|it| it == "rustc_box") @@ -1649,7 +1649,7 @@ impl<'db> ExprCollector<'db> { fn desugar_try_block(&mut self, e: BlockExpr) -> ExprId { let try_from_output = self.lang_path(self.lang_items().TryTraitFromOutput); let label = self.generate_new_name(); - let label = self.alloc_label_desugared(Label { name: label }); + let label = self.alloc_label_desugared(Label { name: label }, AstPtr::new(&e).wrap_right()); let old_label = self.current_try_block_label.replace(label); let ptr = AstPtr::new(&e).upcast(); @@ -2399,7 +2399,6 @@ impl<'db> ExprCollector<'db> { }; let start = range_part_lower(p.start()); let end = range_part_lower(p.end()); - // FIXME: Exclusive ended pattern range is stabilised match p.op_kind() { Some(range_type) => Pat::Range { start, end, range_type }, None => Pat::Missing, @@ -2519,9 +2518,9 @@ impl<'db> ExprCollector<'db> { let mut hygiene_info = if hygiene_id.is_root() { None } else { - hygiene_id.lookup().outer_expn(self.db).map(|expansion| { + hygiene_id.syntax_context().outer_expn(self.db).map(|expansion| { let expansion = self.db.lookup_intern_macro_call(expansion.into()); - (hygiene_id.lookup().parent(self.db), expansion.def) + (hygiene_id.syntax_context().parent(self.db), expansion.def) }) }; let name = Name::new_lifetime(&lifetime.text()); @@ -2727,17 +2726,17 @@ impl ExprCollector<'_> { self.store.pats.alloc(Pat::Missing) } - fn alloc_label(&mut self, label: Label, ptr: LabelPtr) -> LabelId { + fn alloc_label(&mut self, label: Label, ptr: AstPtr) -> LabelId { + self.alloc_label_desugared(label, ptr.wrap_left()) + } + + fn alloc_label_desugared(&mut self, label: Label, ptr: LabelPtr) -> LabelId { let src = self.expander.in_file(ptr); let id = self.store.labels.alloc(label); self.store.label_map_back.insert(id, src); self.store.label_map.insert(src, id); id } - // FIXME: desugared labels don't have ptr, that's wrong and should be fixed somehow. - fn alloc_label_desugared(&mut self, label: Label) -> LabelId { - self.store.labels.alloc(label) - } fn is_lowering_awaitable_block(&self) -> &Awaitable { self.awaitable_context.as_ref().unwrap_or(&Awaitable::No("unknown")) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/format_args.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/format_args.rs index 32c9df3dfefb..7ef84f27f664 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/format_args.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/format_args.rs @@ -3,6 +3,7 @@ use base_db::FxIndexSet; use hir_expand::name::Name; use intern::{Symbol, sym}; +use span::SyntaxContext; use syntax::{AstPtr, AstToken as _, ast}; use crate::{ @@ -49,7 +50,7 @@ impl<'db> ExprCollector<'db> { self.expand_macros_to_string(template.clone()).map(|it| (it, template)) }) { Some(((s, is_direct_literal), template)) => { - let call_ctx = self.expander.call_syntax_ctx(); + let call_ctx = SyntaxContext::root(self.def_map.edition()); let hygiene = self.hygiene_id_for(s.syntax().text_range()); let fmt = format_args::parse( &s, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs index 1a2d5ebba467..482cf36f95b0 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs @@ -20,8 +20,7 @@ pub type LocalLifetimeParamId = Idx; /// Data about a generic type parameter (to a function, struct, impl, ...). #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TypeParamData { - /// [`None`] only if the type ref is an [`crate::type_ref::TypeRef::ImplTrait`]. FIXME: Might be better to just - /// make it always be a value, giving impl trait a special name. + /// [`None`] only if the type ref is an [`crate::type_ref::TypeRef::ImplTrait`]. pub name: Option, pub default: Option, pub provenance: TypeParamProvenance, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs index e4b1d2a98735..cf33cecf5fba 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs @@ -267,7 +267,6 @@ impl DefMap { // plain import or absolute path in 2015: crate-relative with // fallback to extern prelude (with the simplification in // rust-lang/rust#57745) - // FIXME there must be a nicer way to write this condition PathKind::Plain | PathKind::Abs if self.data.edition == Edition::Edition2015 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => @@ -383,7 +382,6 @@ impl DefMap { // plain import or absolute path in 2015: crate-relative with // fallback to extern prelude (with the simplification in // rust-lang/rust#57745) - // FIXME there must be a nicer way to write this condition PathKind::Plain | PathKind::Abs if self.data.edition == Edition::Edition2015 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index 263f603a0bfb..f643ed31ad53 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -950,7 +950,7 @@ fn hygiene_info( hygiene_id: HygieneId, ) -> Option<(SyntaxContext, MacroDefId)> { if !hygiene_id.is_root() { - let ctx = hygiene_id.lookup(); + let ctx = hygiene_id.syntax_context(); ctx.outer_expn(db).map(|expansion| { let expansion = db.lookup_intern_macro_call(expansion.into()); (ctx.parent(db), expansion.def) diff --git a/src/tools/rust-analyzer/crates/hir/src/has_source.rs b/src/tools/rust-analyzer/crates/hir/src/has_source.rs index 09c5b1cca7f3..e032a16989ff 100644 --- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/has_source.rs @@ -330,7 +330,7 @@ impl HasSource for Label { let (_body, source_map) = db.body_with_source_map(self.parent); let src = source_map.label_syntax(self.label_id); let root = src.file_syntax(db); - Some(src.map(|ast| ast.to_node(&root))) + src.map(|ast| ast.to_node(&root).left()).transpose() } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs index 971ae2a601f7..4a37bb34aba3 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs @@ -16,6 +16,9 @@ extern crate rustc_driver as _; extern crate ra_ap_rustc_type_ir as rustc_type_ir; +/* + If you bump this, grep for `FIXME(MINIMUM_SUPPORTED_TOOLCHAIN_VERSION)` to check for old support code we can drop +*/ /// Any toolchain less than this version will likely not work with rust-analyzer built from this revision. pub const MINIMUM_SUPPORTED_TOOLCHAIN_VERSION: semver::Version = semver::Version { major: 1, From 31531b3665bba1a98740de4b9264901302b7255d Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 2 Jan 2026 17:26:41 +0800 Subject: [PATCH 0168/1061] Add regression tests for keyword-in-identifier-position recovery ICE ... in macro invocations. Issue: . --- .../kw-in-const-item-pos-recovery-149692.rs | 11 +++++++ ...w-in-const-item-pos-recovery-149692.stderr | 11 +++++++ .../macro/kw-in-item-pos-recovery-149692.rs | 19 ++++++++++++ .../kw-in-item-pos-recovery-149692.stderr | 29 +++++++++++++++++++ 4 files changed, 70 insertions(+) create mode 100644 tests/ui/parser/macro/kw-in-const-item-pos-recovery-149692.rs create mode 100644 tests/ui/parser/macro/kw-in-const-item-pos-recovery-149692.stderr create mode 100644 tests/ui/parser/macro/kw-in-item-pos-recovery-149692.rs create mode 100644 tests/ui/parser/macro/kw-in-item-pos-recovery-149692.stderr diff --git a/tests/ui/parser/macro/kw-in-const-item-pos-recovery-149692.rs b/tests/ui/parser/macro/kw-in-const-item-pos-recovery-149692.rs new file mode 100644 index 000000000000..58bb62bc4bf8 --- /dev/null +++ b/tests/ui/parser/macro/kw-in-const-item-pos-recovery-149692.rs @@ -0,0 +1,11 @@ +//! More test coverage for ; this test is +//! specifically for `const` items. + +macro_rules! m { + (const $id:item()) => {} +} + +m!(const Self()); +//~^ ERROR expected one of `!` or `::`, found `(` + +fn main() {} diff --git a/tests/ui/parser/macro/kw-in-const-item-pos-recovery-149692.stderr b/tests/ui/parser/macro/kw-in-const-item-pos-recovery-149692.stderr new file mode 100644 index 000000000000..f9b73109dbb4 --- /dev/null +++ b/tests/ui/parser/macro/kw-in-const-item-pos-recovery-149692.stderr @@ -0,0 +1,11 @@ +error: expected one of `!` or `::`, found `(` + --> $DIR/kw-in-const-item-pos-recovery-149692.rs:8:14 + | +LL | (const $id:item()) => {} + | -------- while parsing argument for this `item` macro fragment +... +LL | m!(const Self()); + | ^ expected one of `!` or `::` + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/macro/kw-in-item-pos-recovery-149692.rs b/tests/ui/parser/macro/kw-in-item-pos-recovery-149692.rs new file mode 100644 index 000000000000..223864e33296 --- /dev/null +++ b/tests/ui/parser/macro/kw-in-item-pos-recovery-149692.rs @@ -0,0 +1,19 @@ +//! Regression test for a diagnostic ICE where we tried to recover a keyword as the identifier when +//! we are already trying to recover a missing keyword before item. +//! +//! See . + +macro_rules! m { + ($id:item()) => {} +} + +m!(Self()); +//~^ ERROR expected one of `!` or `::`, found `(` + +m!(Self{}); +//~^ ERROR expected one of `!` or `::`, found `{` + +m!(crate()); +//~^ ERROR expected one of `!` or `::`, found `(` + +fn main() {} diff --git a/tests/ui/parser/macro/kw-in-item-pos-recovery-149692.stderr b/tests/ui/parser/macro/kw-in-item-pos-recovery-149692.stderr new file mode 100644 index 000000000000..a65214b0d1f9 --- /dev/null +++ b/tests/ui/parser/macro/kw-in-item-pos-recovery-149692.stderr @@ -0,0 +1,29 @@ +error: expected one of `!` or `::`, found `(` + --> $DIR/kw-in-item-pos-recovery-149692.rs:10:8 + | +LL | ($id:item()) => {} + | -------- while parsing argument for this `item` macro fragment +... +LL | m!(Self()); + | ^ expected one of `!` or `::` + +error: expected one of `!` or `::`, found `{` + --> $DIR/kw-in-item-pos-recovery-149692.rs:13:8 + | +LL | ($id:item()) => {} + | -------- while parsing argument for this `item` macro fragment +... +LL | m!(Self{}); + | ^ expected one of `!` or `::` + +error: expected one of `!` or `::`, found `(` + --> $DIR/kw-in-item-pos-recovery-149692.rs:16:9 + | +LL | ($id:item()) => {} + | -------- while parsing argument for this `item` macro fragment +... +LL | m!(crate()); + | ^ expected one of `!` or `::` + +error: aborting due to 3 previous errors + From 79c47278f1ec8198cb8c0ed53eda46fc43b16a0d Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 2 Jan 2026 17:27:35 +0800 Subject: [PATCH 0169/1061] Don't try to recover keyword as non-keyword identifier There's no sensible recovery scheme here, giving up the recovery is the right thing to do. --- compiler/rustc_parse/src/parser/item.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 26f60c96aed6..ea713b3cdade 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -408,6 +408,7 @@ impl<'a> Parser<'a> { let insert_span = ident_span.shrink_to_lo(); let ident = if self.token.is_ident() + && self.token.is_non_reserved_ident() && (!is_const || self.look_ahead(1, |t| *t == token::OpenParen)) && self.look_ahead(1, |t| { matches!(t.kind, token::Lt | token::OpenBrace | token::OpenParen) From 58e2610f713035778a562cb7131097a504096dfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Dom=C3=ADnguez?= Date: Sat, 27 Dec 2025 21:50:40 +0100 Subject: [PATCH 0170/1061] Expose workgroup/thread dims as intrinsic args --- .../src/builder/gpu_offload.rs | 72 ++++++++++++++++--- compiler/rustc_codegen_llvm/src/intrinsic.rs | 7 +- .../rustc_hir_analysis/src/check/intrinsic.rs | 14 +++- library/core/src/intrinsics/mod.rs | 15 +++- src/doc/rustc-dev-guide/src/offload/usage.md | 2 +- .../codegen-llvm/gpu_offload/control_flow.rs | 9 ++- tests/codegen-llvm/gpu_offload/gpu_host.rs | 14 ++-- 7 files changed, 108 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs index 5c4aa7da5143..fba92f996aa6 100644 --- a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs +++ b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs @@ -2,7 +2,9 @@ use std::ffi::CString; use llvm::Linkage::*; use rustc_abi::Align; +use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods}; +use rustc_middle::bug; use rustc_middle::ty::offload_meta::OffloadMetadata; use crate::builder::Builder; @@ -69,6 +71,57 @@ impl<'ll> OffloadGlobals<'ll> { } } +pub(crate) struct OffloadKernelDims<'ll> { + num_workgroups: &'ll Value, + threads_per_block: &'ll Value, + workgroup_dims: &'ll Value, + thread_dims: &'ll Value, +} + +impl<'ll> OffloadKernelDims<'ll> { + pub(crate) fn from_operands<'tcx>( + builder: &mut Builder<'_, 'll, 'tcx>, + workgroup_op: &OperandRef<'tcx, &'ll llvm::Value>, + thread_op: &OperandRef<'tcx, &'ll llvm::Value>, + ) -> Self { + let cx = builder.cx; + let arr_ty = cx.type_array(cx.type_i32(), 3); + let four = Align::from_bytes(4).unwrap(); + + let OperandValue::Ref(place) = workgroup_op.val else { + bug!("expected array operand by reference"); + }; + let workgroup_val = builder.load(arr_ty, place.llval, four); + + let OperandValue::Ref(place) = thread_op.val else { + bug!("expected array operand by reference"); + }; + let thread_val = builder.load(arr_ty, place.llval, four); + + fn mul_dim3<'ll, 'tcx>( + builder: &mut Builder<'_, 'll, 'tcx>, + arr: &'ll Value, + ) -> &'ll Value { + let x = builder.extract_value(arr, 0); + let y = builder.extract_value(arr, 1); + let z = builder.extract_value(arr, 2); + + let xy = builder.mul(x, y); + builder.mul(xy, z) + } + + let num_workgroups = mul_dim3(builder, workgroup_val); + let threads_per_block = mul_dim3(builder, thread_val); + + OffloadKernelDims { + workgroup_dims: workgroup_val, + thread_dims: thread_val, + num_workgroups, + threads_per_block, + } + } +} + // ; Function Attrs: nounwind // declare i32 @__tgt_target_kernel(ptr, i64, i32, i32, ptr, ptr) #2 fn generate_launcher<'ll>(cx: &CodegenCx<'ll, '_>) -> (&'ll llvm::Value, &'ll llvm::Type) { @@ -204,12 +257,12 @@ impl KernelArgsTy { num_args: u64, memtransfer_types: &'ll Value, geps: [&'ll Value; 3], + workgroup_dims: &'ll Value, + thread_dims: &'ll Value, ) -> [(Align, &'ll Value); 13] { let four = Align::from_bytes(4).expect("4 Byte alignment should work"); let eight = Align::EIGHT; - let ti32 = cx.type_i32(); - let ci32_0 = cx.get_const_i32(0); [ (four, cx.get_const_i32(KernelArgsTy::OFFLOAD_VERSION)), (four, cx.get_const_i32(num_args)), @@ -222,8 +275,8 @@ impl KernelArgsTy { (eight, cx.const_null(cx.type_ptr())), // dbg (eight, cx.get_const_i64(KernelArgsTy::TRIPCOUNT)), (eight, cx.get_const_i64(KernelArgsTy::FLAGS)), - (four, cx.const_array(ti32, &[cx.get_const_i32(2097152), ci32_0, ci32_0])), - (four, cx.const_array(ti32, &[cx.get_const_i32(256), ci32_0, ci32_0])), + (four, workgroup_dims), + (four, thread_dims), (four, cx.get_const_i32(0)), ] } @@ -413,10 +466,13 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>( types: &[&Type], metadata: &[OffloadMetadata], offload_globals: &OffloadGlobals<'ll>, + offload_dims: &OffloadKernelDims<'ll>, ) { let cx = builder.cx; let OffloadKernelGlobals { offload_sizes, offload_entry, memtransfer_types, region_id } = offload_data; + let OffloadKernelDims { num_workgroups, threads_per_block, workgroup_dims, thread_dims } = + offload_dims; let tgt_decl = offload_globals.launcher_fn; let tgt_target_kernel_ty = offload_globals.launcher_ty; @@ -554,7 +610,8 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>( num_args, s_ident_t, ); - let values = KernelArgsTy::new(&cx, num_args, memtransfer_types, geps); + let values = + KernelArgsTy::new(&cx, num_args, memtransfer_types, geps, workgroup_dims, thread_dims); // Step 3) // Here we fill the KernelArgsTy, see the documentation above @@ -567,9 +624,8 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>( s_ident_t, // FIXME(offload) give users a way to select which GPU to use. cx.get_const_i64(u64::MAX), // MAX == -1. - // FIXME(offload): Don't hardcode the numbers of threads in the future. - cx.get_const_i32(2097152), - cx.get_const_i32(256), + num_workgroups, + threads_per_block, region_id, a5, ]; diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index b4057eea735e..481f75f337d6 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -30,7 +30,7 @@ use tracing::debug; use crate::abi::FnAbiLlvmExt; use crate::builder::Builder; use crate::builder::autodiff::{adjust_activity_to_abi, generate_enzyme_call}; -use crate::builder::gpu_offload::{gen_call_handling, gen_define_handling}; +use crate::builder::gpu_offload::{OffloadKernelDims, gen_call_handling, gen_define_handling}; use crate::context::CodegenCx; use crate::declare::declare_raw_fn; use crate::errors::{ @@ -1384,7 +1384,8 @@ fn codegen_offload<'ll, 'tcx>( } }; - let args = get_args_from_tuple(bx, args[1], fn_target); + let offload_dims = OffloadKernelDims::from_operands(bx, &args[1], &args[2]); + let args = get_args_from_tuple(bx, args[3], fn_target); let target_symbol = symbol_name_for_instance_in_crate(tcx, fn_target, LOCAL_CRATE); let sig = tcx.fn_sig(fn_target.def_id()).skip_binder().skip_binder(); @@ -1403,7 +1404,7 @@ fn codegen_offload<'ll, 'tcx>( } }; let offload_data = gen_define_handling(&cx, &metadata, &types, target_symbol, offload_globals); - gen_call_handling(bx, &offload_data, &args, &types, &metadata, offload_globals); + gen_call_handling(bx, &offload_data, &args, &types, &metadata, offload_globals, &offload_dims); } fn get_args_from_tuple<'ll, 'tcx>( diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 4e8333f678b6..9eaf5319cb04 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -4,7 +4,7 @@ use rustc_abi::ExternAbi; use rustc_errors::DiagMessage; use rustc_hir::{self as hir, LangItem}; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Const, Ty, TyCtxt}; use rustc_span::def_id::LocalDefId; use rustc_span::{Span, Symbol, sym}; @@ -315,7 +315,17 @@ pub(crate) fn check_intrinsic_type( let type_id = tcx.type_of(tcx.lang_items().type_id().unwrap()).instantiate_identity(); (0, 0, vec![type_id, type_id], tcx.types.bool) } - sym::offload => (3, 0, vec![param(0), param(1)], param(2)), + sym::offload => ( + 3, + 0, + vec![ + param(0), + Ty::new_array_with_const_len(tcx, tcx.types.u32, Const::from_target_usize(tcx, 3)), + Ty::new_array_with_const_len(tcx, tcx.types.u32, Const::from_target_usize(tcx, 3)), + param(1), + ], + param(2), + ), sym::offset => (2, 0, vec![param(0), param(1)], param(0)), sym::arith_offset => ( 1, diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index d46d3ed9d513..0ae8d3d4a4ce 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -3385,11 +3385,17 @@ pub const fn autodiff(f: F, df: G, args: T) -> /// - `T`: A tuple of arguments passed to `f`. /// - `R`: The return type of the kernel. /// +/// Arguments: +/// - `f`: The kernel function to offload. +/// - `workgroup_dim`: A 3D size specifying the number of workgroups to launch. +/// - `thread_dim`: A 3D size specifying the number of threads per workgroup. +/// - `args`: A tuple of arguments forwarded to `f`. +/// /// Example usage (pseudocode): /// /// ```rust,ignore (pseudocode) /// fn kernel(x: *mut [f64; 128]) { -/// core::intrinsics::offload(kernel_1, (x,)) +/// core::intrinsics::offload(kernel_1, [256, 1, 1], [32, 1, 1], (x,)) /// } /// /// #[cfg(target_os = "linux")] @@ -3408,7 +3414,12 @@ pub const fn autodiff(f: F, df: G, args: T) -> /// . #[rustc_nounwind] #[rustc_intrinsic] -pub const fn offload(f: F, args: T) -> R; +pub const fn offload( + f: F, + workgroup_dim: [u32; 3], + thread_dim: [u32; 3], + args: T, +) -> R; /// Inform Miri that a given pointer definitely has a certain alignment. #[cfg(miri)] diff --git a/src/doc/rustc-dev-guide/src/offload/usage.md b/src/doc/rustc-dev-guide/src/offload/usage.md index 062534a4b655..4d3222123aaf 100644 --- a/src/doc/rustc-dev-guide/src/offload/usage.md +++ b/src/doc/rustc-dev-guide/src/offload/usage.md @@ -57,7 +57,7 @@ fn main() { #[inline(never)] unsafe fn kernel(x: *mut [f64; 256]) { - core::intrinsics::offload(kernel_1, (x,)) + core::intrinsics::offload(_kernel_1, [256, 1, 1], [32, 1, 1], (x,)) } #[cfg(target_os = "linux")] diff --git a/tests/codegen-llvm/gpu_offload/control_flow.rs b/tests/codegen-llvm/gpu_offload/control_flow.rs index 4a213f5a33a8..28ee9c85b0ed 100644 --- a/tests/codegen-llvm/gpu_offload/control_flow.rs +++ b/tests/codegen-llvm/gpu_offload/control_flow.rs @@ -21,14 +21,19 @@ // CHECK-NOT define // CHECK: bb3 // CHECK: call void @__tgt_target_data_begin_mapper(ptr nonnull @anon.{{.*}}.1, i64 -1, i32 1, ptr nonnull %.offload_baseptrs, ptr nonnull %.offload_ptrs, ptr nonnull %.offload_sizes, ptr nonnull @.offload_maptypes.foo, ptr null, ptr null) -// CHECK: %10 = call i32 @__tgt_target_kernel(ptr nonnull @anon.{{.*}}.1, i64 -1, i32 2097152, i32 256, ptr nonnull @.foo.region_id, ptr nonnull %kernel_args) +// CHECK: %10 = call i32 @__tgt_target_kernel(ptr nonnull @anon.{{.*}}.1, i64 -1, i32 256, i32 32, ptr nonnull @.foo.region_id, ptr nonnull %kernel_args) // CHECK-NEXT: call void @__tgt_target_data_end_mapper(ptr nonnull @anon.{{.*}}.1, i64 -1, i32 1, ptr nonnull %.offload_baseptrs, ptr nonnull %.offload_ptrs, ptr nonnull %.offload_sizes, ptr nonnull @.offload_maptypes.foo, ptr null, ptr null) #[unsafe(no_mangle)] unsafe fn main() { let A = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0]; for i in 0..100 { - core::intrinsics::offload::<_, _, ()>(foo, (A.as_ptr() as *const [f32; 6],)); + core::intrinsics::offload::<_, _, ()>( + foo, + [256, 1, 1], + [32, 1, 1], + (A.as_ptr() as *const [f32; 6],), + ); } } diff --git a/tests/codegen-llvm/gpu_offload/gpu_host.rs b/tests/codegen-llvm/gpu_offload/gpu_host.rs index ac179a65828d..b4d17143720a 100644 --- a/tests/codegen-llvm/gpu_offload/gpu_host.rs +++ b/tests/codegen-llvm/gpu_offload/gpu_host.rs @@ -82,14 +82,14 @@ fn main() { // CHECK-NEXT: %5 = getelementptr inbounds nuw i8, ptr %kernel_args, i64 40 // CHECK-NEXT: %6 = getelementptr inbounds nuw i8, ptr %kernel_args, i64 72 // CHECK-NEXT: call void @llvm.memset.p0.i64(ptr noundef nonnull align 8 dereferenceable(32) %5, i8 0, i64 32, i1 false) -// CHECK-NEXT: store <4 x i32> , ptr %6, align 8 -// CHECK-NEXT: %.fca.1.gep3 = getelementptr inbounds nuw i8, ptr %kernel_args, i64 88 -// CHECK-NEXT: store i32 0, ptr %.fca.1.gep3, align 8 -// CHECK-NEXT: %.fca.2.gep4 = getelementptr inbounds nuw i8, ptr %kernel_args, i64 92 -// CHECK-NEXT: store i32 0, ptr %.fca.2.gep4, align 4 +// CHECK-NEXT: store <4 x i32> , ptr %6, align 8 +// CHECK-NEXT: %.fca.1.gep5 = getelementptr inbounds nuw i8, ptr %kernel_args, i64 88 +// CHECK-NEXT: store i32 1, ptr %.fca.1.gep5, align 8 +// CHECK-NEXT: %.fca.2.gep7 = getelementptr inbounds nuw i8, ptr %kernel_args, i64 92 +// CHECK-NEXT: store i32 1, ptr %.fca.2.gep7, align 4 // CHECK-NEXT: %7 = getelementptr inbounds nuw i8, ptr %kernel_args, i64 96 // CHECK-NEXT: store i32 0, ptr %7, align 8 -// CHECK-NEXT: %8 = call i32 @__tgt_target_kernel(ptr nonnull @anon.{{.*}}.1, i64 -1, i32 2097152, i32 256, ptr nonnull @._kernel_1.region_id, ptr nonnull %kernel_args) +// CHECK-NEXT: %8 = call i32 @__tgt_target_kernel(ptr nonnull @anon.{{.*}}.1, i64 -1, i32 256, i32 32, ptr nonnull @._kernel_1.region_id, ptr nonnull %kernel_args) // CHECK-NEXT: call void @__tgt_target_data_end_mapper(ptr nonnull @anon.{{.*}}.1, i64 -1, i32 1, ptr nonnull %.offload_baseptrs, ptr nonnull %.offload_ptrs, ptr nonnull %.offload_sizes, ptr nonnull @.offload_maptypes._kernel_1, ptr null, ptr null) // CHECK-NEXT: call void @__tgt_unregister_lib(ptr nonnull %EmptyDesc) // CHECK-NEXT: ret void @@ -98,7 +98,7 @@ fn main() { #[unsafe(no_mangle)] #[inline(never)] pub fn kernel_1(x: &mut [f32; 256]) { - core::intrinsics::offload(_kernel_1, (x,)) + core::intrinsics::offload(_kernel_1, [256, 1, 1], [32, 1, 1], (x,)) } #[unsafe(no_mangle)] From 9f1066b1c1934c1ce76aececa7b0973776704281 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Thu, 27 Nov 2025 18:57:00 +0100 Subject: [PATCH 0171/1061] Basic support for FFI callbacks This commit adds basic support for FFI callbacks by registering a shim function via libffi. This shim function currently only exits with an error. The main motivation for this is to prevent miri segfaulting as described in [4639](https://github.com/rust-lang/miri/issues/4639). In the future miri could try to continue execution in the registered callback, although as far as I understand Ralf that is no easy problem. --- src/tools/miri/src/alloc_addresses/mod.rs | 35 ++++-- src/tools/miri/src/diagnostics.rs | 13 -- src/tools/miri/src/shims/mod.rs | 2 +- src/tools/miri/src/shims/native_lib/mod.rs | 112 +++++++++++++++--- .../fail/call_function_ptr.notrace.stderr | 31 +++++ .../native-lib/fail/call_function_ptr.rs | 21 ++++ .../fail/call_function_ptr.trace.stderr | 32 +++++ .../pass/ptr_read_access.notrace.stderr | 13 -- .../pass/ptr_read_access.trace.stderr | 13 -- .../miri/tests/native-lib/ptr_read_access.c | 7 ++ 10 files changed, 214 insertions(+), 65 deletions(-) create mode 100644 src/tools/miri/tests/native-lib/fail/call_function_ptr.notrace.stderr create mode 100644 src/tools/miri/tests/native-lib/fail/call_function_ptr.rs create mode 100644 src/tools/miri/tests/native-lib/fail/call_function_ptr.trace.stderr diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 05d3444a4eb1..24b1c5fc6635 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -12,6 +12,7 @@ use rustc_middle::ty::TyCtxt; pub use self::address_generator::AddressGenerator; use self::reuse_pool::ReusePool; +use crate::alloc::MiriAllocParams; use crate::concurrency::VClock; use crate::diagnostics::SpanDedupDiagnostic; use crate::*; @@ -162,18 +163,21 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.get_alloc_bytes_unchecked_raw(alloc_id)? } } - AllocKind::Function | AllocKind::VTable => { - // Allocate some dummy memory to get a unique address for this function/vtable. - let alloc_bytes = MiriAllocBytes::from_bytes( - &[0u8; 1], - Align::from_bytes(1).unwrap(), - params, - ); - let ptr = alloc_bytes.as_ptr(); - // Leak the underlying memory to ensure it remains unique. - std::mem::forget(alloc_bytes); - ptr + #[cfg(all(unix, feature = "native-lib"))] + AllocKind::Function => { + if let Some(GlobalAlloc::Function { instance, .. }) = + this.tcx.try_get_global_alloc(alloc_id) + { + let fn_sig = this.tcx.fn_sig(instance.def_id()).skip_binder().skip_binder(); + let ptr = crate::shims::native_lib::build_libffi_closure_ptr(this, fn_sig)?; + ptr.cast() + } else { + dummy_alloc(params) + } } + #[cfg(not(all(unix, feature = "native-lib")))] + AllocKind::Function => dummy_alloc(params), + AllocKind::VTable => dummy_alloc(params), AllocKind::TypeId | AllocKind::Dead => unreachable!(), }; // We don't have to expose this pointer yet, we do that in `prepare_for_native_call`. @@ -205,6 +209,15 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } } +fn dummy_alloc(params: MiriAllocParams) -> *const u8 { + // Allocate some dummy memory to get a unique address for this function/vtable. + let alloc_bytes = MiriAllocBytes::from_bytes(&[0u8; 1], Align::from_bytes(1).unwrap(), params); + let ptr = alloc_bytes.as_ptr(); + // Leak the underlying memory to ensure it remains unique. + std::mem::forget(alloc_bytes); + ptr +} + impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Returns the `AllocId` that corresponds to the specified addr, diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 1f87ac60c17a..64c7096fc5c2 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -138,7 +138,6 @@ pub enum NonHaltingDiagnostic { NativeCallSharedMem { tracing: bool, }, - NativeCallFnPtr, WeakMemoryOutdatedLoad { ptr: Pointer, }, @@ -643,11 +642,6 @@ impl<'tcx> MiriMachine<'tcx> { Int2Ptr { .. } => ("integer-to-pointer cast".to_string(), DiagLevel::Warning), NativeCallSharedMem { .. } => ("sharing memory with a native function".to_string(), DiagLevel::Warning), - NativeCallFnPtr => - ( - "sharing a function pointer with a native function".to_string(), - DiagLevel::Warning, - ), ExternTypeReborrow => ("reborrow of reference to `extern type`".to_string(), DiagLevel::Warning), GenmcCompareExchangeWeak | GenmcCompareExchangeOrderingMismatch { .. } => @@ -686,8 +680,6 @@ impl<'tcx> MiriMachine<'tcx> { Int2Ptr { .. } => format!("integer-to-pointer cast"), NativeCallSharedMem { .. } => format!("sharing memory with a native function called via FFI"), - NativeCallFnPtr => - format!("sharing a function pointer with a native function called via FFI"), WeakMemoryOutdatedLoad { ptr } => format!("weak memory emulation: outdated value returned from load at {ptr}"), ExternTypeReborrow => @@ -785,11 +777,6 @@ impl<'tcx> MiriMachine<'tcx> { ), ] }, - NativeCallFnPtr => { - vec![note!( - "calling Rust functions from C is not supported and will, in the best case, crash the program" - )] - } ExternTypeReborrow => { assert!(self.borrow_tracker.as_ref().is_some_and(|b| { matches!( diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs index e51ace2fd907..345e16b8da71 100644 --- a/src/tools/miri/src/shims/mod.rs +++ b/src/tools/miri/src/shims/mod.rs @@ -6,7 +6,7 @@ mod backtrace; mod files; mod math; #[cfg(all(unix, feature = "native-lib"))] -mod native_lib; +pub mod native_lib; mod unix; mod windows; mod x86; diff --git a/src/tools/miri/src/shims/native_lib/mod.rs b/src/tools/miri/src/shims/native_lib/mod.rs index 12abe841c052..719490c08e27 100644 --- a/src/tools/miri/src/shims/native_lib/mod.rs +++ b/src/tools/miri/src/shims/native_lib/mod.rs @@ -1,6 +1,7 @@ //! Implements calling functions from a native library. use std::ops::Deref; +use std::os::raw::c_void; use std::sync::atomic::AtomicBool; use libffi::low::CodePtr; @@ -74,6 +75,13 @@ impl AccessRange { } } +/// The data passed to the closure shim function used +/// to intercept function pointer calls from native +/// code +struct CallbackData<'tcx, 'this> { + ecx: &'this InterpCx<'tcx, MiriMachine<'tcx>>, +} + impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {} trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Call native host function and return the output as an immediate. @@ -330,7 +338,9 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Read the bytes that make up this argument. We cannot use the normal getter as // those would fail if any part of the argument is uninitialized. Native code // is kind of outside the interpreter, after all... - Box::from(alloc.inspect_with_uninit_and_ptr_outside_interpreter(range)) + let ret: Box<[u8]> = + Box::from(alloc.inspect_with_uninit_and_ptr_outside_interpreter(range)); + ret } either::Either::Right(imm) => { let mut bytes: Box<[u8]> = vec![0; imm.layout.size.bytes_usize()].into(); @@ -429,21 +439,102 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { Primitive::Float(Float::F32) => FfiType::f32(), Primitive::Float(Float::F64) => FfiType::f64(), Primitive::Pointer(AddressSpace::ZERO) => FfiType::pointer(), - _ => - throw_unsup_format!( - "unsupported scalar argument type for native call: {}", - layout.ty - ), + _ => throw_unsup_format!("unsupported scalar type for native call: {}", layout.ty), }); } interp_ok(match layout.ty.kind() { // Scalar types have already been handled above. ty::Adt(adt_def, args) => self.adt_to_ffitype(layout.ty, *adt_def, args)?, - _ => throw_unsup_format!("unsupported argument type for native call: {}", layout.ty), + // Rust uses `()` as return type for `void` function, which becomes `Tuple([])`. + ty::Tuple(t_list) if (*t_list).deref().is_empty() => FfiType::void(), + _ => { + throw_unsup_format!("unsupported type for native call: {}", layout.ty) + } }) } } +/// This function sets up a new libffi Closure to intercept +/// calls to rust code via function pointers passed to native code. +/// +/// It manages tho setup the underlying libffi datastructure by initializing the +/// right number of arguments with the right types, as well a setting +/// the right return type +/// +/// Calling this function leaks the data passed into the libffi closure as +/// these need to be available until the execution terminates as the native +/// code side could store a function pointer and only call it at a later point. +/// This is for example done by SQLite, which uses function pointers as destructors +/// which then only run at teardown time +fn build_libffi_closure<'tcx, 'this>( + this: &'this MiriInterpCx<'tcx>, + fn_sig: rustc_middle::ty::FnSig<'tcx>, +) -> InterpResult<'tcx, libffi::middle::Closure<'this>> { + let mut args = Vec::new(); + for input in fn_sig.inputs().iter() { + let layout = this.layout_of(*input)?; + let ty = this.ty_to_ffitype(layout)?; + args.push(ty); + } + let res_type = fn_sig.output(); + let res_type = { + let layout = this.layout_of(res_type)?; + this.ty_to_ffitype(layout)? + }; + let closure_builder = libffi::middle::Builder::new().args(args).res(res_type); + let data = CallbackData { ecx: this }; + let data = Box::leak(Box::new(data)); + let closure = closure_builder.into_closure(callback_callback, data); + interp_ok(closure) +} + +/// This function wraps build_libffi_closure +/// to return the correct pointer that is expected to be +/// passed into native code as function pointer. +/// +/// This function returns a `*const c_void` ptr to erase the +/// actual function type, that is only known at runtime. +pub fn build_libffi_closure_ptr<'tcx, 'this>( + this: &'this MiriInterpCx<'tcx>, + fn_sig: rustc_middle::ty::FnSig<'tcx>, +) -> InterpResult<'tcx, *const std::ffi::c_void> { + let closure = build_libffi_closure(this, fn_sig)?; + let closure = Box::leak(Box::new(closure)); + // Libffi returns a **reference** to a function ptr here. + // (The actual argument type doesn't matter) + let fn_ptr = + unsafe { closure.instantiate_code_ptr::() }; + // Therefore we need to dereference the reference to get the actual function pointer. + let fn_ptr = *fn_ptr; + #[expect(clippy::as_conversions, reason = "No better way to cast a function ptr to a ptr")] + { + // After that we need to cast the function pointer to the + // expected pointer type. At this point we don't actually care about the + // type of this pointer. + interp_ok(fn_ptr as *const std::ffi::c_void) + } +} + +/// A shim function to intercept calls back from native code into the interpreter +/// via function pointers passed to the native code. +/// +/// For now this shim only reports that such constructs are not supported by miri. +/// As future improvement we might continue execution in the interpreter here. +unsafe extern "C" fn callback_callback<'tcx, 'this>( + _cif: &libffi::low::ffi_cif, + _result: &mut c_void, + _args: *const *const c_void, + infos: &CallbackData<'tcx, 'this>, +) { + let ecx = infos.ecx; + let err = err_unsup_format!("calling a function pointer through the FFI boundary"); + + crate::diagnostics::report_result(ecx, err.into()); + // We abort the execution at this point as we cannot return the + // expected value here. + std::process::exit(1); +} + impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Call the native host function, with supplied arguments. @@ -477,13 +568,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // pointer was passed as argument). Uninitialised memory is left as-is, but any data // exposed this way is garbage anyway. this.visit_reachable_allocs(this.exposed_allocs(), |this, alloc_id, info| { - if matches!(info.kind, AllocKind::Function) { - static DEDUP: AtomicBool = AtomicBool::new(false); - if !DEDUP.swap(true, std::sync::atomic::Ordering::Relaxed) { - // Newly set, so first time we get here. - this.emit_diagnostic(NonHaltingDiagnostic::NativeCallFnPtr); - } - } // If there is no data behind this pointer, skip this. if !matches!(info.kind, AllocKind::LiveData) { return interp_ok(()); diff --git a/src/tools/miri/tests/native-lib/fail/call_function_ptr.notrace.stderr b/src/tools/miri/tests/native-lib/fail/call_function_ptr.notrace.stderr new file mode 100644 index 000000000000..faabba9ca725 --- /dev/null +++ b/src/tools/miri/tests/native-lib/fail/call_function_ptr.notrace.stderr @@ -0,0 +1,31 @@ +warning: sharing memory with a native function called via FFI + --> tests/native-lib/fail/call_function_ptr.rs:LL:CC + | +LL | call_fn_ptr(Some(nop)); + | ^^^^^^^^^^^^^^^^^^^^^^ sharing memory with a native function + | + = help: when memory is shared with a native function call, Miri stops tracking initialization and provenance for that memory + = help: in particular, Miri assumes that the native call initializes all memory it has access to + = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory + = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free + = note: stack backtrace: + 0: pass_fn_ptr + at tests/native-lib/fail/call_function_ptr.rs:LL:CC + 1: main + at tests/native-lib/fail/call_function_ptr.rs:LL:CC + +error: unsupported operation: calling a function pointer through the FFI boundary + --> tests/native-lib/fail/call_function_ptr.rs:LL:CC + | +LL | call_fn_ptr(Some(nop)); + | ^^^^^^^^^^^^^^^^^^^^^^ unsupported operation occurred here + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = note: stack backtrace: + 0: pass_fn_ptr + at tests/native-lib/fail/call_function_ptr.rs:LL:CC + 1: main + at tests/native-lib/fail/call_function_ptr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + diff --git a/src/tools/miri/tests/native-lib/fail/call_function_ptr.rs b/src/tools/miri/tests/native-lib/fail/call_function_ptr.rs new file mode 100644 index 000000000000..b68c4d4062b7 --- /dev/null +++ b/src/tools/miri/tests/native-lib/fail/call_function_ptr.rs @@ -0,0 +1,21 @@ +//@revisions: trace notrace +//@[trace] only-target: x86_64-unknown-linux-gnu i686-unknown-linux-gnu +//@[trace] compile-flags: -Zmiri-native-lib-enable-tracing +//@compile-flags: -Zmiri-permissive-provenance + +fn main() { + pass_fn_ptr() +} + +fn pass_fn_ptr() { + extern "C" { + fn call_fn_ptr(s: Option); + } + + extern "C" fn nop() {} + + unsafe { + call_fn_ptr(None); // this one is fine + call_fn_ptr(Some(nop)); //~ ERROR: unsupported operation: calling a function pointer through the FFI boundary + } +} diff --git a/src/tools/miri/tests/native-lib/fail/call_function_ptr.trace.stderr b/src/tools/miri/tests/native-lib/fail/call_function_ptr.trace.stderr new file mode 100644 index 000000000000..e56a5ece782b --- /dev/null +++ b/src/tools/miri/tests/native-lib/fail/call_function_ptr.trace.stderr @@ -0,0 +1,32 @@ +warning: sharing memory with a native function called via FFI + --> tests/native-lib/fail/call_function_ptr.rs:LL:CC + | +LL | call_fn_ptr(Some(nop)); + | ^^^^^^^^^^^^^^^^^^^^^^ sharing memory with a native function + | + = help: when memory is shared with a native function call, Miri can only track initialisation and provenance on a best-effort basis + = help: in particular, Miri assumes that the native call initializes all memory it has written to + = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory + = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free + = help: tracing memory accesses in native code is not yet fully implemented, so there can be further imprecisions beyond what is documented here + = note: stack backtrace: + 0: pass_fn_ptr + at tests/native-lib/fail/call_function_ptr.rs:LL:CC + 1: main + at tests/native-lib/fail/call_function_ptr.rs:LL:CC + +error: unsupported operation: calling a function pointer through the FFI boundary + --> tests/native-lib/fail/call_function_ptr.rs:LL:CC + | +LL | call_fn_ptr(Some(nop)); + | ^^^^^^^^^^^^^^^^^^^^^^ unsupported operation occurred here + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = note: stack backtrace: + 0: pass_fn_ptr + at tests/native-lib/fail/call_function_ptr.rs:LL:CC + 1: main + at tests/native-lib/fail/call_function_ptr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + diff --git a/src/tools/miri/tests/native-lib/pass/ptr_read_access.notrace.stderr b/src/tools/miri/tests/native-lib/pass/ptr_read_access.notrace.stderr index b6bbb4342b77..bc2fcac08f01 100644 --- a/src/tools/miri/tests/native-lib/pass/ptr_read_access.notrace.stderr +++ b/src/tools/miri/tests/native-lib/pass/ptr_read_access.notrace.stderr @@ -14,16 +14,3 @@ LL | unsafe { print_pointer(&x) }; 1: main at tests/native-lib/pass/ptr_read_access.rs:LL:CC -warning: sharing a function pointer with a native function called via FFI - --> tests/native-lib/pass/ptr_read_access.rs:LL:CC - | -LL | pass_fn_ptr(Some(nop)); // this one is not - | ^^^^^^^^^^^^^^^^^^^^^^ sharing a function pointer with a native function - | - = help: calling Rust functions from C is not supported and will, in the best case, crash the program - = note: stack backtrace: - 0: pass_fn_ptr - at tests/native-lib/pass/ptr_read_access.rs:LL:CC - 1: main - at tests/native-lib/pass/ptr_read_access.rs:LL:CC - diff --git a/src/tools/miri/tests/native-lib/pass/ptr_read_access.trace.stderr b/src/tools/miri/tests/native-lib/pass/ptr_read_access.trace.stderr index 0d86ea066099..c7f30c114f16 100644 --- a/src/tools/miri/tests/native-lib/pass/ptr_read_access.trace.stderr +++ b/src/tools/miri/tests/native-lib/pass/ptr_read_access.trace.stderr @@ -15,16 +15,3 @@ LL | unsafe { print_pointer(&x) }; 1: main at tests/native-lib/pass/ptr_read_access.rs:LL:CC -warning: sharing a function pointer with a native function called via FFI - --> tests/native-lib/pass/ptr_read_access.rs:LL:CC - | -LL | pass_fn_ptr(Some(nop)); // this one is not - | ^^^^^^^^^^^^^^^^^^^^^^ sharing a function pointer with a native function - | - = help: calling Rust functions from C is not supported and will, in the best case, crash the program - = note: stack backtrace: - 0: pass_fn_ptr - at tests/native-lib/pass/ptr_read_access.rs:LL:CC - 1: main - at tests/native-lib/pass/ptr_read_access.rs:LL:CC - diff --git a/src/tools/miri/tests/native-lib/ptr_read_access.c b/src/tools/miri/tests/native-lib/ptr_read_access.c index 5f071ca3d424..44ba13aa54a6 100644 --- a/src/tools/miri/tests/native-lib/ptr_read_access.c +++ b/src/tools/miri/tests/native-lib/ptr_read_access.c @@ -68,3 +68,10 @@ EXPORT uintptr_t do_one_deref(const int32_t ***ptr) { EXPORT void pass_fn_ptr(void f(void)) { (void)f; // suppress unused warning } + +/* Test: function_ptrs */ +EXPORT void call_fn_ptr(void f(void)) { + if (f != NULL) { + f(); + } +} From c7f6d7800da867ad3e384d65eff0d1fed2906036 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Jan 2026 11:50:17 +0100 Subject: [PATCH 0172/1061] minor cleanup --- src/tools/miri/src/alloc_addresses/mod.rs | 11 +++- src/tools/miri/src/shims/native_lib/mod.rs | 59 ++++++---------------- 2 files changed, 25 insertions(+), 45 deletions(-) diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 24b1c5fc6635..fed51ed86433 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -169,8 +169,15 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.tcx.try_get_global_alloc(alloc_id) { let fn_sig = this.tcx.fn_sig(instance.def_id()).skip_binder().skip_binder(); - let ptr = crate::shims::native_lib::build_libffi_closure_ptr(this, fn_sig)?; - ptr.cast() + let fn_ptr = crate::shims::native_lib::build_libffi_closure(this, fn_sig)?; + + #[expect( + clippy::as_conversions, + reason = "No better way to cast a function ptr to a ptr" + )] + { + fn_ptr as *const _ + } } else { dummy_alloc(params) } diff --git a/src/tools/miri/src/shims/native_lib/mod.rs b/src/tools/miri/src/shims/native_lib/mod.rs index 719490c08e27..9f997a82ee57 100644 --- a/src/tools/miri/src/shims/native_lib/mod.rs +++ b/src/tools/miri/src/shims/native_lib/mod.rs @@ -75,9 +75,8 @@ impl AccessRange { } } -/// The data passed to the closure shim function used -/// to intercept function pointer calls from native -/// code +/// The data passed to the closure shim function used to intercept function pointer calls from +/// native code. struct CallbackData<'tcx, 'this> { ecx: &'this InterpCx<'tcx, MiriMachine<'tcx>>, } @@ -338,9 +337,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Read the bytes that make up this argument. We cannot use the normal getter as // those would fail if any part of the argument is uninitialized. Native code // is kind of outside the interpreter, after all... - let ret: Box<[u8]> = - Box::from(alloc.inspect_with_uninit_and_ptr_outside_interpreter(range)); - ret + Box::from(alloc.inspect_with_uninit_and_ptr_outside_interpreter(range)) } either::Either::Right(imm) => { let mut bytes: Box<[u8]> = vec![0; imm.layout.size.bytes_usize()].into(); @@ -446,7 +443,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Scalar types have already been handled above. ty::Adt(adt_def, args) => self.adt_to_ffitype(layout.ty, *adt_def, args)?, // Rust uses `()` as return type for `void` function, which becomes `Tuple([])`. - ty::Tuple(t_list) if (*t_list).deref().is_empty() => FfiType::void(), + ty::Tuple(t_list) if t_list.len() == 0 => FfiType::void(), _ => { throw_unsup_format!("unsupported type for native call: {}", layout.ty) } @@ -454,22 +451,17 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } } -/// This function sets up a new libffi Closure to intercept +/// This function sets up a new libffi closure to intercept /// calls to rust code via function pointers passed to native code. /// -/// It manages tho setup the underlying libffi datastructure by initializing the -/// right number of arguments with the right types, as well a setting -/// the right return type -/// /// Calling this function leaks the data passed into the libffi closure as /// these need to be available until the execution terminates as the native /// code side could store a function pointer and only call it at a later point. -/// This is for example done by SQLite, which uses function pointers as destructors -/// which then only run at teardown time -fn build_libffi_closure<'tcx, 'this>( +pub fn build_libffi_closure<'tcx, 'this>( this: &'this MiriInterpCx<'tcx>, fn_sig: rustc_middle::ty::FnSig<'tcx>, -) -> InterpResult<'tcx, libffi::middle::Closure<'this>> { +) -> InterpResult<'tcx, unsafe extern "C" fn()> { + // Compute argument and return types in libffi representation. let mut args = Vec::new(); for input in fn_sig.inputs().iter() { let layout = this.layout_of(*input)?; @@ -481,38 +473,19 @@ fn build_libffi_closure<'tcx, 'this>( let layout = this.layout_of(res_type)?; this.ty_to_ffitype(layout)? }; + + // Build the actual closure. let closure_builder = libffi::middle::Builder::new().args(args).res(res_type); let data = CallbackData { ecx: this }; let data = Box::leak(Box::new(data)); - let closure = closure_builder.into_closure(callback_callback, data); - interp_ok(closure) -} - -/// This function wraps build_libffi_closure -/// to return the correct pointer that is expected to be -/// passed into native code as function pointer. -/// -/// This function returns a `*const c_void` ptr to erase the -/// actual function type, that is only known at runtime. -pub fn build_libffi_closure_ptr<'tcx, 'this>( - this: &'this MiriInterpCx<'tcx>, - fn_sig: rustc_middle::ty::FnSig<'tcx>, -) -> InterpResult<'tcx, *const std::ffi::c_void> { - let closure = build_libffi_closure(this, fn_sig)?; + let closure = closure_builder.into_closure(libffi_closure_callback, data); let closure = Box::leak(Box::new(closure)); + + // The actual argument/return type doesn't matter. + let fn_ptr = unsafe { closure.instantiate_code_ptr::() }; // Libffi returns a **reference** to a function ptr here. - // (The actual argument type doesn't matter) - let fn_ptr = - unsafe { closure.instantiate_code_ptr::() }; // Therefore we need to dereference the reference to get the actual function pointer. - let fn_ptr = *fn_ptr; - #[expect(clippy::as_conversions, reason = "No better way to cast a function ptr to a ptr")] - { - // After that we need to cast the function pointer to the - // expected pointer type. At this point we don't actually care about the - // type of this pointer. - interp_ok(fn_ptr as *const std::ffi::c_void) - } + interp_ok(*fn_ptr) } /// A shim function to intercept calls back from native code into the interpreter @@ -520,7 +493,7 @@ pub fn build_libffi_closure_ptr<'tcx, 'this>( /// /// For now this shim only reports that such constructs are not supported by miri. /// As future improvement we might continue execution in the interpreter here. -unsafe extern "C" fn callback_callback<'tcx, 'this>( +unsafe extern "C" fn libffi_closure_callback<'tcx, 'this>( _cif: &libffi::low::ffi_cif, _result: &mut c_void, _args: *const *const c_void, From bcdcabee75e5f0aad8811ce204f38e54174d26fd Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 3 Dec 2025 22:15:58 +0300 Subject: [PATCH 0173/1061] resolve: Do not break from the scope visiting loop if we already found the innermost binding. Previously we could lose the already found binding and break with an error, if some blocking error was found in the shadowed scopes. Also, avoid some impossible state in the return type of `fn resolve_ident_in_scope`. --- compiler/rustc_resolve/src/ident.rs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 669f045681b7..8e5c15e88ca5 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -429,10 +429,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { orig_ident.span.ctxt(), derive_fallback_lint_id, |this, scope, use_prelude, ctxt| { - // We can break with an error at this step, it means we cannot determine the - // resolution right now, but we must block and wait until we can instead of - // considering outer scopes. - match this.reborrow().resolve_ident_in_scope( + let res = match this.reborrow().resolve_ident_in_scope( orig_ident, ns, scope, @@ -445,7 +442,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { force, ignore_binding, ignore_import, - )? { + ) { + Ok(binding) => Ok(binding), + // We can break with an error at this step, it means we cannot determine the + // resolution right now, but we must block and wait until we can, instead of + // considering outer scopes. Although there's no need to do that if we already + // have a better solution. + Err(ControlFlow::Break(determinacy)) if innermost_results.is_empty() => { + return ControlFlow::Break(Err(determinacy)); + } + Err(determinacy) => Err(determinacy.into_value()), + }; + match res { Ok(binding) if sub_namespace_match(binding.macro_kinds(), macro_kind) => { // Below we report various ambiguity errors. // We do not need to report them if we are either in speculative resolution, @@ -504,8 +512,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { force: bool, ignore_binding: Option>, ignore_import: Option>, - ) -> ControlFlow, Determinacy>, Result, Determinacy>> - { + ) -> Result, ControlFlow> { let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt)); let ret = match scope { Scope::DeriveHelpers(expn_id) => { @@ -591,7 +598,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } Err(ControlFlow::Continue(determinacy)) => Err(determinacy), Err(ControlFlow::Break(Determinacy::Undetermined)) => { - return ControlFlow::Break(Err(Determinacy::determined(force))); + return Err(ControlFlow::Break(Determinacy::determined(force))); } // Privacy errors, do not happen during in scope resolution. Err(ControlFlow::Break(Determinacy::Determined)) => unreachable!(), @@ -680,7 +687,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }, }; - ControlFlow::Continue(ret) + ret.map_err(ControlFlow::Continue) } fn maybe_push_ambiguity( From 1f32c2a418eeabb57a643ae28817bfe00857766c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Jan 2026 12:06:19 +0100 Subject: [PATCH 0174/1061] bump libffi --- src/tools/miri/Cargo.lock | 8 ++++---- src/tools/miri/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock index 395c37e9ade8..220fad2a1c76 100644 --- a/src/tools/miri/Cargo.lock +++ b/src/tools/miri/Cargo.lock @@ -786,9 +786,9 @@ checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libffi" -version = "5.0.0" +version = "5.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0444124f3ffd67e1b0b0c661a7f81a278a135eb54aaad4078e79fbc8be50c8a5" +checksum = "0498fe5655f857803e156523e644dcdcdc3b3c7edda42ea2afdae2e09b2db87b" dependencies = [ "libc", "libffi-sys", @@ -796,9 +796,9 @@ dependencies = [ [[package]] name = "libffi-sys" -version = "4.0.0" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d722da8817ea580d0669da6babe2262d7b86a1af1103da24102b8bb9c101ce7" +checksum = "71d4f1d4ce15091955144350b75db16a96d4a63728500122706fb4d29a26afbb" dependencies = [ "cc", ] diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml index 4a54a7e0eb71..064706d7ed04 100644 --- a/src/tools/miri/Cargo.toml +++ b/src/tools/miri/Cargo.toml @@ -32,7 +32,7 @@ serde_json = { version = "1.0", optional = true } [target.'cfg(unix)'.dependencies] libc = "0.2" # native-lib dependencies -libffi = { version = "5.0.0", optional = true } +libffi = { version = "5.1.0", optional = true } libloading = { version = "0.9", optional = true } serde = { version = "1.0.219", features = ["derive"], optional = true } From 604cf92cd4518799b8613b3ad666cbe57178b6ec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Jan 2026 12:23:55 +0100 Subject: [PATCH 0175/1061] avoid aliasing trouble around libffi closures --- src/tools/miri/src/machine.rs | 7 ++++ src/tools/miri/src/shims/native_lib/mod.rs | 44 +++++++++++++++------- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 502cdbdc57b3..f17bd5ac4319 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -599,6 +599,9 @@ pub struct MiriMachine<'tcx> { pub native_lib: Vec<(libloading::Library, std::path::PathBuf)>, #[cfg(not(all(unix, feature = "native-lib")))] pub native_lib: Vec, + /// A memory location for exchanging the current `ecx` pointer with native code. + #[cfg(all(unix, feature = "native-lib"))] + pub native_lib_ecx_interchange: &'static Cell, /// Run a garbage collector for BorTags every N basic blocks. pub(crate) gc_interval: u32, @@ -790,6 +793,8 @@ impl<'tcx> MiriMachine<'tcx> { lib_file_path.clone(), ) }).collect(), + #[cfg(all(unix, feature = "native-lib"))] + native_lib_ecx_interchange: Box::leak(Box::new(Cell::new(0))), #[cfg(not(all(unix, feature = "native-lib")))] native_lib: config.native_lib.iter().map(|_| { panic!("calling functions from native libraries via FFI is not supported in this build of Miri") @@ -1026,6 +1031,8 @@ impl VisitProvenance for MiriMachine<'_> { report_progress: _, basic_block_count: _, native_lib: _, + #[cfg(all(unix, feature = "native-lib"))] + native_lib_ecx_interchange: _, gc_interval: _, since_gc: _, num_cpus: _, diff --git a/src/tools/miri/src/shims/native_lib/mod.rs b/src/tools/miri/src/shims/native_lib/mod.rs index 9f997a82ee57..c25c1841dd70 100644 --- a/src/tools/miri/src/shims/native_lib/mod.rs +++ b/src/tools/miri/src/shims/native_lib/mod.rs @@ -1,7 +1,10 @@ //! Implements calling functions from a native library. +use std::cell::Cell; +use std::marker::PhantomData; use std::ops::Deref; use std::os::raw::c_void; +use std::ptr; use std::sync::atomic::AtomicBool; use libffi::low::CodePtr; @@ -75,12 +78,6 @@ impl AccessRange { } } -/// The data passed to the closure shim function used to intercept function pointer calls from -/// native code. -struct CallbackData<'tcx, 'this> { - ecx: &'this InterpCx<'tcx, MiriMachine<'tcx>>, -} - impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {} trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Call native host function and return the output as an immediate. @@ -93,12 +90,15 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, (crate::ImmTy<'tcx>, Option)> { let this = self.eval_context_mut(); #[cfg(target_os = "linux")] - let alloc = this.machine.allocator.as_ref().unwrap(); + let alloc = this.machine.allocator.as_ref().unwrap().clone(); #[cfg(not(target_os = "linux"))] // Placeholder value. let alloc = (); - trace::Supervisor::do_ffi(alloc, || { + // Expose InterpCx for use by closure callbacks. + this.machine.native_lib_ecx_interchange.set(ptr::from_mut(this).expose_provenance()); + + let res = trace::Supervisor::do_ffi(&alloc, || { // Call the function (`ptr`) with arguments `libffi_args`, and obtain the return value // as the specified primitive integer type let scalar = match dest.layout.ty.kind() { @@ -174,7 +174,11 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { .into(), }; interp_ok(ImmTy::from_scalar(scalar, dest.layout)) - }) + }); + + this.machine.native_lib_ecx_interchange.set(0); + + res } /// Get the pointer to the function of the specified name in the shared object file, @@ -451,6 +455,13 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } } +/// The data passed to the closure shim function used to intercept function pointer calls from +/// native code. +struct LibffiClosureData<'tcx> { + ecx_interchange: &'static Cell, + marker: PhantomData>, +} + /// This function sets up a new libffi closure to intercept /// calls to rust code via function pointers passed to native code. /// @@ -476,7 +487,10 @@ pub fn build_libffi_closure<'tcx, 'this>( // Build the actual closure. let closure_builder = libffi::middle::Builder::new().args(args).res(res_type); - let data = CallbackData { ecx: this }; + let data = LibffiClosureData { + ecx_interchange: this.machine.native_lib_ecx_interchange, + marker: PhantomData, + }; let data = Box::leak(Box::new(data)); let closure = closure_builder.into_closure(libffi_closure_callback, data); let closure = Box::leak(Box::new(closure)); @@ -493,13 +507,17 @@ pub fn build_libffi_closure<'tcx, 'this>( /// /// For now this shim only reports that such constructs are not supported by miri. /// As future improvement we might continue execution in the interpreter here. -unsafe extern "C" fn libffi_closure_callback<'tcx, 'this>( +unsafe extern "C" fn libffi_closure_callback<'tcx>( _cif: &libffi::low::ffi_cif, _result: &mut c_void, _args: *const *const c_void, - infos: &CallbackData<'tcx, 'this>, + data: &LibffiClosureData<'tcx>, ) { - let ecx = infos.ecx; + let ecx = unsafe { + ptr::with_exposed_provenance_mut::>(data.ecx_interchange.get()) + .as_mut() + .expect("libffi closure called while no FFI call is active") + }; let err = err_unsup_format!("calling a function pointer through the FFI boundary"); crate::diagnostics::report_result(ecx, err.into()); From 75d90094e732948f4a45cb407f604239ae6a31ef Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 3 Dec 2025 22:24:59 +0300 Subject: [PATCH 0176/1061] resolve: Split `Scope::Module` into two scopes for non-glob and glob bindings --- compiler/rustc_resolve/src/diagnostics.rs | 7 +- compiler/rustc_resolve/src/ident.rs | 71 +++++++++++++++---- compiler/rustc_resolve/src/lib.rs | 17 +++-- tests/ui/imports/issue-114682-1.rs | 1 + tests/ui/imports/issue-114682-1.stderr | 28 +++++++- .../local-modularized-tricky-fail-1.rs | 1 + .../local-modularized-tricky-fail-1.stderr | 32 ++++++++- tests/ui/imports/macro-paths.rs | 1 + tests/ui/imports/macro-paths.stderr | 28 ++++++-- 9 files changed, 157 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 8f20b5fe5745..716e1d5a2e7f 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1206,9 +1206,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } } - Scope::Module(module, _) => { + Scope::ModuleNonGlobs(module, _) => { this.add_module_candidates(module, suggestions, filter_fn, None); } + Scope::ModuleGlobs(..) => { + // Already handled in `ModuleNonGlobs`. + } Scope::MacroUsePrelude => { suggestions.extend(this.macro_use_prelude.iter().filter_map( |(name, binding)| { @@ -2033,7 +2036,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { help_msgs.push(format!("use `::{ident}` to refer to this {thing} unambiguously")) } - if let Scope::Module(module, _) = scope { + if let Scope::ModuleNonGlobs(module, _) | Scope::ModuleGlobs(module, _) = scope { if module == self.graph_root { help_msgs.push(format!( "use `crate::{ident}` to refer to this {thing} unambiguously" diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 8e5c15e88ca5..fcd058c5ae6d 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -116,9 +116,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let module_and_extern_prelude = matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..)); let extern_prelude = matches!(scope_set, ScopeSet::ExternPrelude); let mut scope = match ns { - _ if module_and_extern_prelude => Scope::Module(module, None), + _ if module_and_extern_prelude => Scope::ModuleNonGlobs(module, None), _ if extern_prelude => Scope::ExternPreludeItems, - TypeNS | ValueNS => Scope::Module(module, None), + TypeNS | ValueNS => Scope::ModuleNonGlobs(module, None), MacroNS => Scope::DeriveHelpers(parent_scope.expansion), }; let mut ctxt = ctxt.normalize_to_macros_2_0(); @@ -145,7 +145,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } true } - Scope::Module(..) => true, + Scope::ModuleNonGlobs(..) | Scope::ModuleGlobs(..) => true, Scope::MacroUsePrelude => use_prelude || rust_2015, Scope::BuiltinAttrs => true, Scope::ExternPreludeItems | Scope::ExternPreludeFlags => { @@ -186,20 +186,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { MacroRulesScope::Invocation(invoc_id) => { Scope::MacroRules(self.invocation_parent_scopes[&invoc_id].macro_rules) } - MacroRulesScope::Empty => Scope::Module(module, None), + MacroRulesScope::Empty => Scope::ModuleNonGlobs(module, None), }, - Scope::Module(..) if module_and_extern_prelude => match ns { + Scope::ModuleNonGlobs(module, lint_id) => Scope::ModuleGlobs(module, lint_id), + Scope::ModuleGlobs(..) if module_and_extern_prelude => match ns { TypeNS => { ctxt.adjust(ExpnId::root()); Scope::ExternPreludeItems } ValueNS | MacroNS => break, }, - Scope::Module(module, prev_lint_id) => { + Scope::ModuleGlobs(module, prev_lint_id) => { use_prelude = !module.no_implicit_prelude; match self.hygienic_lexical_parent(module, &mut ctxt, derive_fallback_lint_id) { Some((parent_module, lint_id)) => { - Scope::Module(parent_module, lint_id.or(prev_lint_id)) + Scope::ModuleNonGlobs(parent_module, lint_id.or(prev_lint_id)) } None => { ctxt.adjust(ExpnId::root()); @@ -560,7 +561,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { MacroRulesScope::Invocation(_) => Err(Determinacy::Undetermined), _ => Err(Determinacy::Determined), }, - Scope::Module(module, derive_fallback_lint_id) => { + Scope::ModuleNonGlobs(module, derive_fallback_lint_id) => { let (adjusted_parent_scope, adjusted_finalize) = if matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..)) { (parent_scope, finalize) @@ -570,7 +571,51 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { finalize.map(|f| Finalize { used: Used::Scope, ..f }), ) }; - let binding = self.reborrow().resolve_ident_in_module_unadjusted( + let binding = self.reborrow().resolve_ident_in_module_non_globs_unadjusted( + module, + ident, + ns, + adjusted_parent_scope, + Shadowing::Restricted, + adjusted_finalize, + ignore_binding, + ignore_import, + ); + match binding { + Ok(binding) => { + if let Some(lint_id) = derive_fallback_lint_id { + self.get_mut().lint_buffer.buffer_lint( + PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, + lint_id, + orig_ident.span, + errors::ProcMacroDeriveResolutionFallback { + span: orig_ident.span, + ns_descr: ns.descr(), + ident, + }, + ); + } + Ok(binding) + } + Err(ControlFlow::Continue(determinacy)) => Err(determinacy), + Err(ControlFlow::Break(Determinacy::Undetermined)) => { + return Err(ControlFlow::Break(Determinacy::determined(force))); + } + // Privacy errors, do not happen during in scope resolution. + Err(ControlFlow::Break(Determinacy::Determined)) => unreachable!(), + } + } + Scope::ModuleGlobs(module, derive_fallback_lint_id) => { + let (adjusted_parent_scope, adjusted_finalize) = + if matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..)) { + (parent_scope, finalize) + } else { + ( + &ParentScope { module, ..*parent_scope }, + finalize.map(|f| Finalize { used: Used::Scope, ..f }), + ) + }; + let binding = self.reborrow().resolve_ident_in_module_globs_unadjusted( module, ident, ns, @@ -717,12 +762,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } else if res == derive_helper_compat && innermost_res != derive_helper { span_bug!(orig_ident.span, "impossible inner resolution kind") } else if matches!(innermost_scope, Scope::MacroRules(_)) - && matches!(scope, Scope::Module(..)) + && matches!(scope, Scope::ModuleNonGlobs(..) | Scope::ModuleGlobs(..)) && !self.disambiguate_macro_rules_vs_modularized(innermost_binding, binding) { Some(AmbiguityKind::MacroRulesVsModularized) } else if matches!(scope, Scope::MacroRules(_)) - && matches!(innermost_scope, Scope::Module(..)) + && matches!(innermost_scope, Scope::ModuleNonGlobs(..) | Scope::ModuleGlobs(..)) { // should be impossible because of visitation order in // visit_scopes @@ -1177,8 +1222,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, b1: binding, b2: shadowed_glob, - scope1: Scope::Module(self.empty_module, None), - scope2: Scope::Module(self.empty_module, None), + scope1: Scope::ModuleGlobs(self.empty_module, None), + scope2: Scope::ModuleGlobs(self.empty_module, None), warning: false, }); } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 7cbf2088efce..fa53d57d175e 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -123,10 +123,14 @@ enum Scope<'ra> { DeriveHelpersCompat, /// Textual `let`-like scopes introduced by `macro_rules!` items. MacroRules(MacroRulesScopeRef<'ra>), - /// Names declared in the given module. + /// Non-glob names declared in the given module. /// The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK` /// lint if it should be reported. - Module(Module<'ra>, Option), + ModuleNonGlobs(Module<'ra>, Option), + /// Glob names declared in the given module. + /// The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK` + /// lint if it should be reported. + ModuleGlobs(Module<'ra>, Option), /// Names introduced by `#[macro_use]` attributes on `extern crate` items. MacroUsePrelude, /// Built-in attributes. @@ -1926,9 +1930,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let scope_set = ScopeSet::All(TypeNS); self.cm().visit_scopes(scope_set, parent_scope, ctxt, None, |this, scope, _, _| { match scope { - Scope::Module(module, _) => { + Scope::ModuleNonGlobs(module, _) => { this.get_mut().traits_in_module(module, assoc_item, &mut found_traits); } + Scope::ModuleGlobs(..) => { + // Already handled in `ModuleNonGlobs` (but see #144993). + } Scope::StdLibPrelude => { if let Some(module) = this.prelude { this.get_mut().traits_in_module(module, assoc_item, &mut found_traits); @@ -2061,8 +2068,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, b1: used_binding, b2, - scope1: Scope::Module(self.empty_module, None), - scope2: Scope::Module(self.empty_module, None), + scope1: Scope::ModuleGlobs(self.empty_module, None), + scope2: Scope::ModuleGlobs(self.empty_module, None), warning: warn_ambiguity, }; if !self.matches_previous_ambiguity_error(&ambiguity_error) { diff --git a/tests/ui/imports/issue-114682-1.rs b/tests/ui/imports/issue-114682-1.rs index 88fe05e51444..58b78508026d 100644 --- a/tests/ui/imports/issue-114682-1.rs +++ b/tests/ui/imports/issue-114682-1.rs @@ -22,4 +22,5 @@ mac!(); fn main() { A!(); //~^ ERROR `A` is ambiguous + //~| ERROR `A` is ambiguous } diff --git a/tests/ui/imports/issue-114682-1.stderr b/tests/ui/imports/issue-114682-1.stderr index 85fb7f7919e4..de8dc6cfb9ff 100644 --- a/tests/ui/imports/issue-114682-1.stderr +++ b/tests/ui/imports/issue-114682-1.stderr @@ -23,6 +23,32 @@ LL | pub use m::*; = help: consider adding an explicit import of `A` to disambiguate = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 1 previous error +error[E0659]: `A` is ambiguous + --> $DIR/issue-114682-1.rs:23:5 + | +LL | A!(); + | ^ ambiguous name + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution +note: `A` could refer to the macro defined here + --> $DIR/issue-114682-1.rs:7:9 + | +LL | / pub macro A() { +LL | | println!("non import") +LL | | } + | |_________^ +... +LL | mac!(); + | ------ in this macro invocation + = help: use `crate::A` to refer to this macro unambiguously +note: `A` could also refer to the macro imported here + --> $DIR/issue-114682-1.rs:19:9 + | +LL | pub use m::*; + | ^^^^ + = help: use `crate::A` to refer to this macro unambiguously + = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/imports/local-modularized-tricky-fail-1.rs b/tests/ui/imports/local-modularized-tricky-fail-1.rs index ce700ae0de9b..bba26ee43a24 100644 --- a/tests/ui/imports/local-modularized-tricky-fail-1.rs +++ b/tests/ui/imports/local-modularized-tricky-fail-1.rs @@ -27,6 +27,7 @@ mod inner1 { } exported!(); //~ ERROR `exported` is ambiguous + //~| ERROR `exported` is ambiguous mod inner2 { define_exported!(); diff --git a/tests/ui/imports/local-modularized-tricky-fail-1.stderr b/tests/ui/imports/local-modularized-tricky-fail-1.stderr index 52a01e8bcdfe..54d928f7c812 100644 --- a/tests/ui/imports/local-modularized-tricky-fail-1.stderr +++ b/tests/ui/imports/local-modularized-tricky-fail-1.stderr @@ -23,8 +23,34 @@ LL | use inner1::*; = help: consider adding an explicit import of `exported` to disambiguate = note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0659]: `exported` is ambiguous + --> $DIR/local-modularized-tricky-fail-1.rs:29:1 + | +LL | exported!(); + | ^^^^^^^^ ambiguous name + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution +note: `exported` could refer to the macro defined here + --> $DIR/local-modularized-tricky-fail-1.rs:6:5 + | +LL | / macro_rules! exported { +LL | | () => () +LL | | } + | |_____^ +... +LL | define_exported!(); + | ------------------ in this macro invocation + = help: use `crate::exported` to refer to this macro unambiguously +note: `exported` could also refer to the macro imported here + --> $DIR/local-modularized-tricky-fail-1.rs:23:5 + | +LL | use inner1::*; + | ^^^^^^^^^ + = help: use `crate::exported` to refer to this macro unambiguously + = note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0659]: `panic` is ambiguous - --> $DIR/local-modularized-tricky-fail-1.rs:36:5 + --> $DIR/local-modularized-tricky-fail-1.rs:37:5 | LL | panic!(); | ^^^^^ ambiguous name @@ -45,7 +71,7 @@ LL | define_panic!(); = note: this error originates in the macro `define_panic` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `include` is ambiguous - --> $DIR/local-modularized-tricky-fail-1.rs:47:1 + --> $DIR/local-modularized-tricky-fail-1.rs:48:1 | LL | include!(); | ^^^^^^^ ambiguous name @@ -65,6 +91,6 @@ LL | define_include!(); = help: use `crate::include` to refer to this macro unambiguously = note: this error originates in the macro `define_include` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/imports/macro-paths.rs b/tests/ui/imports/macro-paths.rs index 916442a7c4ea..6fd426c34eff 100644 --- a/tests/ui/imports/macro-paths.rs +++ b/tests/ui/imports/macro-paths.rs @@ -11,6 +11,7 @@ mod foo { fn f() { use foo::*; bar::m! { //~ ERROR ambiguous + //~| ERROR `bar` is ambiguous mod bar { pub use two_macros::m; } } } diff --git a/tests/ui/imports/macro-paths.stderr b/tests/ui/imports/macro-paths.stderr index 5f113ce2bee5..5ba92072805e 100644 --- a/tests/ui/imports/macro-paths.stderr +++ b/tests/ui/imports/macro-paths.stderr @@ -6,7 +6,7 @@ LL | bar::m! { | = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution note: `bar` could refer to the module defined here - --> $DIR/macro-paths.rs:14:9 + --> $DIR/macro-paths.rs:15:9 | LL | mod bar { pub use two_macros::m; } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,20 +17,38 @@ LL | use foo::*; | ^^^^^^ = help: consider adding an explicit import of `bar` to disambiguate +error[E0659]: `bar` is ambiguous + --> $DIR/macro-paths.rs:13:5 + | +LL | bar::m! { + | ^^^ ambiguous name + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution +note: `bar` could refer to the module defined here + --> $DIR/macro-paths.rs:15:9 + | +LL | mod bar { pub use two_macros::m; } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: `bar` could also refer to the module imported here + --> $DIR/macro-paths.rs:12:9 + | +LL | use foo::*; + | ^^^^^^ + error[E0659]: `baz` is ambiguous - --> $DIR/macro-paths.rs:23:5 + --> $DIR/macro-paths.rs:24:5 | LL | baz::m! { | ^^^ ambiguous name | = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution note: `baz` could refer to the module defined here - --> $DIR/macro-paths.rs:24:9 + --> $DIR/macro-paths.rs:25:9 | LL | mod baz { pub use two_macros::m; } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `baz` could also refer to the module defined here - --> $DIR/macro-paths.rs:18:1 + --> $DIR/macro-paths.rs:19:1 | LL | / pub mod baz { LL | | pub use two_macros::m; @@ -38,6 +56,6 @@ LL | | } | |_^ = help: use `crate::baz` to refer to this module unambiguously -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0659`. From bcfbb5619c5f2f9d69d8b60b820a2b1db266d4af Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 3 Dec 2025 22:46:42 +0300 Subject: [PATCH 0177/1061] resolve: Migrate a special ambiguity for glob vs non-glob bindings in the same module to the usual ambiguity infra in `resolve_ident_in_scope_set` --- compiler/rustc_resolve/src/ident.rs | 30 +++++++++-------------------- tests/ui/imports/macro-paths.rs | 1 - tests/ui/imports/macro-paths.stderr | 29 +++++----------------------- 3 files changed, 14 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index fcd058c5ae6d..61e98c60a5c9 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -783,9 +783,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Some(AmbiguityKind::GlobVsOuter) } else if innermost_binding.may_appear_after(parent_scope.expansion, binding) { Some(AmbiguityKind::MoreExpandedVsOuter) + } else if innermost_binding.expansion != LocalExpnId::ROOT + && let Scope::ModuleGlobs(m1, _) = scope + && let Scope::ModuleNonGlobs(m2, _) = innermost_scope + && m1 == m2 + { + // FIXME: this error is too conservative and technically unnecessary now when module + // scope is split into two scopes, remove it with lang team approval. + Some(AmbiguityKind::GlobVsExpanded) } else { None }; + if let Some(kind) = ambiguity_error_kind { // Skip ambiguity errors for extern flag bindings "overridden" // by extern item bindings. @@ -1008,7 +1017,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return self.get_mut().finalize_module_binding( ident, binding, - if resolution.non_glob_binding.is_some() { resolution.glob_binding } else { None }, parent_scope, module, finalize, @@ -1070,7 +1078,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return self.get_mut().finalize_module_binding( ident, binding, - if resolution.non_glob_binding.is_some() { resolution.glob_binding } else { None }, parent_scope, module, finalize, @@ -1182,7 +1189,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { &mut self, ident: Ident, binding: Option>, - shadowed_glob: Option>, parent_scope: &ParentScope<'ra>, module: Module<'ra>, finalize: Finalize, @@ -1210,24 +1216,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - // Forbid expanded shadowing to avoid time travel. - if let Some(shadowed_glob) = shadowed_glob - && shadowing == Shadowing::Restricted - && finalize.stage == Stage::Early - && binding.expansion != LocalExpnId::ROOT - && binding.res() != shadowed_glob.res() - { - self.ambiguity_errors.push(AmbiguityError { - kind: AmbiguityKind::GlobVsExpanded, - ident, - b1: binding, - b2: shadowed_glob, - scope1: Scope::ModuleGlobs(self.empty_module, None), - scope2: Scope::ModuleGlobs(self.empty_module, None), - warning: false, - }); - } - if shadowing == Shadowing::Unrestricted && binding.expansion != LocalExpnId::ROOT && let NameBindingKind::Import { import, .. } = binding.kind diff --git a/tests/ui/imports/macro-paths.rs b/tests/ui/imports/macro-paths.rs index 6fd426c34eff..916442a7c4ea 100644 --- a/tests/ui/imports/macro-paths.rs +++ b/tests/ui/imports/macro-paths.rs @@ -11,7 +11,6 @@ mod foo { fn f() { use foo::*; bar::m! { //~ ERROR ambiguous - //~| ERROR `bar` is ambiguous mod bar { pub use two_macros::m; } } } diff --git a/tests/ui/imports/macro-paths.stderr b/tests/ui/imports/macro-paths.stderr index 5ba92072805e..56a40e908258 100644 --- a/tests/ui/imports/macro-paths.stderr +++ b/tests/ui/imports/macro-paths.stderr @@ -1,22 +1,3 @@ -error[E0659]: `bar` is ambiguous - --> $DIR/macro-paths.rs:13:5 - | -LL | bar::m! { - | ^^^ ambiguous name - | - = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution -note: `bar` could refer to the module defined here - --> $DIR/macro-paths.rs:15:9 - | -LL | mod bar { pub use two_macros::m; } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: `bar` could also refer to the module imported here - --> $DIR/macro-paths.rs:12:9 - | -LL | use foo::*; - | ^^^^^^ - = help: consider adding an explicit import of `bar` to disambiguate - error[E0659]: `bar` is ambiguous --> $DIR/macro-paths.rs:13:5 | @@ -25,7 +6,7 @@ LL | bar::m! { | = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution note: `bar` could refer to the module defined here - --> $DIR/macro-paths.rs:15:9 + --> $DIR/macro-paths.rs:14:9 | LL | mod bar { pub use two_macros::m; } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -36,19 +17,19 @@ LL | use foo::*; | ^^^^^^ error[E0659]: `baz` is ambiguous - --> $DIR/macro-paths.rs:24:5 + --> $DIR/macro-paths.rs:23:5 | LL | baz::m! { | ^^^ ambiguous name | = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution note: `baz` could refer to the module defined here - --> $DIR/macro-paths.rs:25:9 + --> $DIR/macro-paths.rs:24:9 | LL | mod baz { pub use two_macros::m; } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `baz` could also refer to the module defined here - --> $DIR/macro-paths.rs:19:1 + --> $DIR/macro-paths.rs:18:1 | LL | / pub mod baz { LL | | pub use two_macros::m; @@ -56,6 +37,6 @@ LL | | } | |_^ = help: use `crate::baz` to refer to this module unambiguously -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0659`. From cd7a58e4127a66f8a641c42c6a12c5419c8d5585 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 2 Jan 2026 13:01:07 +0100 Subject: [PATCH 0178/1061] Pre-allocate intern storages with 64kb of data To reduce the amount of re-allocating the hashtables which can be expensive given the need to re-hash --- src/tools/rust-analyzer/crates/hir-ty/src/lower.rs | 2 +- .../crates/hir-ty/src/method_resolution.rs | 8 ++++---- .../crates/hir-ty/src/next_solver/infer/mod.rs | 8 +++++--- .../src/next_solver/infer/opaque_types/table.rs | 2 +- .../crates/hir-ty/src/tests/incremental.rs | 3 --- .../rust-analyzer/crates/hir-ty/src/variance.rs | 13 +++++++------ src/tools/rust-analyzer/crates/intern/src/intern.rs | 2 +- .../rust-analyzer/crates/intern/src/intern_slice.rs | 7 ++++++- 8 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index 9307868f3982..e45ef113a086 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -1319,7 +1319,7 @@ fn type_for_struct_constructor( db: &dyn HirDatabase, def: StructId, ) -> Option> { - let struct_data = def.fields(db); + let struct_data = db.struct_signature(def); match struct_data.shape { FieldsShape::Record => None, FieldsShape::Unit => Some(type_for_adt(db, def.into())), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index 50dbd87d693e..3d7cc4ffbf8a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -731,6 +731,10 @@ impl TraitImpls { ) { for (_module_id, module_data) in def_map.modules() { for impl_id in module_data.scope.impls() { + let trait_ref = match db.impl_trait(impl_id) { + Some(tr) => tr.instantiate_identity(), + None => continue, + }; // Reservation impls should be ignored during trait resolution, so we never need // them during type analysis. See rust-lang/rust#64631 for details. // @@ -742,10 +746,6 @@ impl TraitImpls { { continue; } - let trait_ref = match db.impl_trait(impl_id) { - Some(tr) => tr.instantiate_identity(), - None => continue, - }; let self_ty = trait_ref.self_ty(); let interner = DbInterner::new_no_crate(db); let entry = map.entry(trait_ref.def_id.0).or_default(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs index 2926dc30def7..7d291f7ddbed 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs @@ -878,9 +878,11 @@ impl<'db> InferCtxt<'db> { self.tainted_by_errors.set(Some(e)); } - #[instrument(level = "debug", skip(self), ret)] - pub fn take_opaque_types(&self) -> Vec<(OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)> { - self.inner.borrow_mut().opaque_type_storage.take_opaque_types().collect() + #[instrument(level = "debug", skip(self))] + pub fn take_opaque_types( + &self, + ) -> impl IntoIterator, OpaqueHiddenType<'db>)> + use<'db> { + self.inner.borrow_mut().opaque_type_storage.take_opaque_types() } #[instrument(level = "debug", skip(self), ret)] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs index 00177d21ac76..894fe5eb7b87 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs @@ -61,7 +61,7 @@ impl<'db> OpaqueTypeStorage<'db> { pub(crate) fn take_opaque_types( &mut self, - ) -> impl Iterator, OpaqueHiddenType<'db>)> { + ) -> impl IntoIterator, OpaqueHiddenType<'db>)> + use<'db> { let OpaqueTypeStorage { opaque_types, duplicate_entries } = self; std::mem::take(opaque_types).into_iter().chain(std::mem::take(duplicate_entries)) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs index 1457bb2e1017..633ab43c4cec 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs @@ -632,8 +632,6 @@ fn main() { "struct_signature_with_source_map_shim", "GenericPredicates::query_with_diagnostics_", "value_ty_query", - "VariantFields::firewall_", - "VariantFields::query_", "InherentImpls::for_crate_", "impl_signature_shim", "impl_signature_with_source_map_shim", @@ -723,7 +721,6 @@ fn main() { "expr_scopes_shim", "struct_signature_with_source_map_shim", "GenericPredicates::query_with_diagnostics_", - "VariantFields::query_", "InherentImpls::for_crate_", "impl_signature_with_source_map_shim", "impl_signature_shim", diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs index e5cfe85573b8..6f415a5289c9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs @@ -41,7 +41,6 @@ pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> Variances )] fn variances_of_query(db: &dyn HirDatabase, def: GenericDefId) -> StoredVariancesOf { tracing::debug!("variances_of(def={:?})", def); - let interner = DbInterner::new_no_crate(db); match def { GenericDefId::FunctionId(_) => (), GenericDefId::AdtId(adt) => { @@ -55,15 +54,17 @@ fn variances_of_query(db: &dyn HirDatabase, def: GenericDefId) -> StoredVariance } } } - _ => return VariancesOf::empty(interner).store(), + _ => return VariancesOf::empty(DbInterner::new_no_crate(db)).store(), } let generics = generics(db, def); let count = generics.len(); if count == 0 { - return VariancesOf::empty(interner).store(); + return VariancesOf::empty(DbInterner::new_no_crate(db)).store(); } - let variances = Context { generics, variances: vec![Variance::Bivariant; count], db }.solve(); + let variances = + Context { generics, variances: vec![Variance::Bivariant; count].into_boxed_slice(), db } + .solve(); VariancesOf::new_from_slice(&variances).store() } @@ -113,11 +114,11 @@ pub(crate) fn variances_of_cycle_initial( struct Context<'db> { db: &'db dyn HirDatabase, generics: Generics, - variances: Vec, + variances: Box<[Variance]>, } impl<'db> Context<'db> { - fn solve(mut self) -> Vec { + fn solve(mut self) -> Box<[Variance]> { tracing::debug!("solve(generics={:?})", self.generics); match self.generics.def() { GenericDefId::AdtId(adt) => { diff --git a/src/tools/rust-analyzer/crates/intern/src/intern.rs b/src/tools/rust-analyzer/crates/intern/src/intern.rs index b7acd6624b99..a96dfcfa9fe3 100644 --- a/src/tools/rust-analyzer/crates/intern/src/intern.rs +++ b/src/tools/rust-analyzer/crates/intern/src/intern.rs @@ -334,7 +334,7 @@ impl InternStorage { impl InternStorage { pub(crate) fn get(&self) -> &InternMap { - self.map.get_or_init(DashMap::default) + self.map.get_or_init(|| DashMap::with_capacity_and_hasher(1024, Default::default())) } } diff --git a/src/tools/rust-analyzer/crates/intern/src/intern_slice.rs b/src/tools/rust-analyzer/crates/intern/src/intern_slice.rs index 58de6e17bdff..8857771d2e01 100644 --- a/src/tools/rust-analyzer/crates/intern/src/intern_slice.rs +++ b/src/tools/rust-analyzer/crates/intern/src/intern_slice.rs @@ -292,7 +292,12 @@ impl InternSliceStorage { impl InternSliceStorage { pub(crate) fn get(&self) -> &InternMap { - self.map.get_or_init(DashMap::default) + self.map.get_or_init(|| { + DashMap::with_capacity_and_hasher( + (64 * 1024) / std::mem::size_of::(), + Default::default(), + ) + }) } } From d7d49244ef9dafb7dff752b03561f369a9aab7e7 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 4 Dec 2025 22:03:42 +0300 Subject: [PATCH 0179/1061] resolve: Introduce `ScopeSet::Module` for looking up a name in two scopes inside a module - non-glob and glob bindings. --- compiler/rustc_resolve/src/ident.rs | 187 ++++++++++++---------------- compiler/rustc_resolve/src/late.rs | 6 +- compiler/rustc_resolve/src/lib.rs | 2 + 3 files changed, 87 insertions(+), 108 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 61e98c60a5c9..82a87b8a9ed6 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -103,20 +103,23 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let rust_2015 = ctxt.edition().is_rust_2015(); let (ns, macro_kind) = match scope_set { - ScopeSet::All(ns) | ScopeSet::ModuleAndExternPrelude(ns, _) => (ns, None), + ScopeSet::All(ns) + | ScopeSet::Module(ns, _) + | ScopeSet::ModuleAndExternPrelude(ns, _) => (ns, None), ScopeSet::ExternPrelude => (TypeNS, None), ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind)), }; let module = match scope_set { // Start with the specified module. - ScopeSet::ModuleAndExternPrelude(_, module) => module, + ScopeSet::Module(_, module) | ScopeSet::ModuleAndExternPrelude(_, module) => module, // Jump out of trait or enum modules, they do not act as scopes. _ => parent_scope.module.nearest_item_scope(), }; + let module_only = matches!(scope_set, ScopeSet::Module(..)); let module_and_extern_prelude = matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..)); let extern_prelude = matches!(scope_set, ScopeSet::ExternPrelude); let mut scope = match ns { - _ if module_and_extern_prelude => Scope::ModuleNonGlobs(module, None), + _ if module_only || module_and_extern_prelude => Scope::ModuleNonGlobs(module, None), _ if extern_prelude => Scope::ExternPreludeItems, TypeNS | ValueNS => Scope::ModuleNonGlobs(module, None), MacroNS => Scope::DeriveHelpers(parent_scope.expansion), @@ -189,6 +192,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { MacroRulesScope::Empty => Scope::ModuleNonGlobs(module, None), }, Scope::ModuleNonGlobs(module, lint_id) => Scope::ModuleGlobs(module, lint_id), + Scope::ModuleGlobs(..) if module_only => break, Scope::ModuleGlobs(..) if module_and_extern_prelude => match ns { TypeNS => { ctxt.adjust(ExpnId::root()); @@ -336,13 +340,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { diag_metadata, ))); } else if let RibKind::Block(Some(module)) = rib.kind - && let Ok(binding) = self.cm().resolve_ident_in_module_unadjusted( - module, + && let Ok(binding) = self.cm().resolve_ident_in_scope_set( ident, - ns, + ScopeSet::Module(ns, module), parent_scope, - Shadowing::Unrestricted, finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }), + finalize.is_some(), ignore_binding, None, ) @@ -395,12 +398,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { assert!(force || finalize.is_none()); // `finalize` implies `force` // Make sure `self`, `super` etc produce an error when passed to here. - if orig_ident.is_path_segment_keyword() { + if orig_ident.is_path_segment_keyword() && !matches!(scope_set, ScopeSet::Module(..)) { return Err(Determinacy::Determined); } let (ns, macro_kind) = match scope_set { - ScopeSet::All(ns) | ScopeSet::ModuleAndExternPrelude(ns, _) => (ns, None), + ScopeSet::All(ns) + | ScopeSet::Module(ns, _) + | ScopeSet::ModuleAndExternPrelude(ns, _) => (ns, None), ScopeSet::ExternPrelude => (TypeNS, None), ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind)), }; @@ -468,6 +473,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Found another solution, if the first one was "weak", report an error. if this.get_mut().maybe_push_ambiguity( orig_ident, + ns, + scope_set, parent_scope, binding, scope, @@ -562,21 +569,27 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _ => Err(Determinacy::Determined), }, Scope::ModuleNonGlobs(module, derive_fallback_lint_id) => { - let (adjusted_parent_scope, adjusted_finalize) = - if matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..)) { - (parent_scope, finalize) - } else { - ( - &ParentScope { module, ..*parent_scope }, - finalize.map(|f| Finalize { used: Used::Scope, ..f }), - ) - }; + let (adjusted_parent_scope, adjusted_finalize) = if matches!( + scope_set, + ScopeSet::Module(..) | ScopeSet::ModuleAndExternPrelude(..) + ) { + (parent_scope, finalize) + } else { + ( + &ParentScope { module, ..*parent_scope }, + finalize.map(|f| Finalize { used: Used::Scope, ..f }), + ) + }; let binding = self.reborrow().resolve_ident_in_module_non_globs_unadjusted( module, ident, ns, adjusted_parent_scope, - Shadowing::Restricted, + if matches!(scope_set, ScopeSet::Module(..)) { + Shadowing::Unrestricted + } else { + Shadowing::Restricted + }, adjusted_finalize, ignore_binding, ignore_import, @@ -598,29 +611,35 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Ok(binding) } Err(ControlFlow::Continue(determinacy)) => Err(determinacy), - Err(ControlFlow::Break(Determinacy::Undetermined)) => { - return Err(ControlFlow::Break(Determinacy::determined(force))); + Err(ControlFlow::Break(determinacy)) => { + return Err(ControlFlow::Break(Determinacy::determined( + determinacy == Determinacy::Determined || force, + ))); } - // Privacy errors, do not happen during in scope resolution. - Err(ControlFlow::Break(Determinacy::Determined)) => unreachable!(), } } Scope::ModuleGlobs(module, derive_fallback_lint_id) => { - let (adjusted_parent_scope, adjusted_finalize) = - if matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..)) { - (parent_scope, finalize) - } else { - ( - &ParentScope { module, ..*parent_scope }, - finalize.map(|f| Finalize { used: Used::Scope, ..f }), - ) - }; + let (adjusted_parent_scope, adjusted_finalize) = if matches!( + scope_set, + ScopeSet::Module(..) | ScopeSet::ModuleAndExternPrelude(..) + ) { + (parent_scope, finalize) + } else { + ( + &ParentScope { module, ..*parent_scope }, + finalize.map(|f| Finalize { used: Used::Scope, ..f }), + ) + }; let binding = self.reborrow().resolve_ident_in_module_globs_unadjusted( module, ident, ns, adjusted_parent_scope, - Shadowing::Restricted, + if matches!(scope_set, ScopeSet::Module(..)) { + Shadowing::Unrestricted + } else { + Shadowing::Restricted + }, adjusted_finalize, ignore_binding, ignore_import, @@ -642,11 +661,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Ok(binding) } Err(ControlFlow::Continue(determinacy)) => Err(determinacy), - Err(ControlFlow::Break(Determinacy::Undetermined)) => { - return Err(ControlFlow::Break(Determinacy::determined(force))); + Err(ControlFlow::Break(determinacy)) => { + return Err(ControlFlow::Break(Determinacy::determined( + determinacy == Determinacy::Determined || force, + ))); } - // Privacy errors, do not happen during in scope resolution. - Err(ControlFlow::Break(Determinacy::Determined)) => unreachable!(), } } Scope::MacroUsePrelude => match self.macro_use_prelude.get(&ident.name).cloned() { @@ -680,13 +699,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Scope::StdLibPrelude => { let mut result = Err(Determinacy::Determined); if let Some(prelude) = self.prelude - && let Ok(binding) = self.reborrow().resolve_ident_in_module_unadjusted( - prelude, + && let Ok(binding) = self.reborrow().resolve_ident_in_scope_set( ident, - ns, + ScopeSet::Module(ns, prelude), parent_scope, - Shadowing::Unrestricted, None, + false, ignore_binding, ignore_import, ) @@ -738,6 +756,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn maybe_push_ambiguity( &mut self, orig_ident: Ident, + ns: Namespace, + scope_set: ScopeSet<'ra>, parent_scope: &ParentScope<'ra>, binding: NameBinding<'ra>, scope: Scope<'ra>, @@ -751,6 +771,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // FIXME: Use `scope` instead of `res` to detect built-in attrs and derive helpers, // it will exclude imports, make slightly more code legal, and will require lang approval. + let module_only = matches!(scope_set, ScopeSet::Module(..)); let is_builtin = |res| matches!(res, Res::NonMacroAttr(NonMacroAttrKind::Builtin(..))); let derive_helper = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper); let derive_helper_compat = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat); @@ -781,9 +802,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) } else if innermost_binding.is_glob_import() { Some(AmbiguityKind::GlobVsOuter) - } else if innermost_binding.may_appear_after(parent_scope.expansion, binding) { + } else if !module_only + && innermost_binding.may_appear_after(parent_scope.expansion, binding) + { Some(AmbiguityKind::MoreExpandedVsOuter) } else if innermost_binding.expansion != LocalExpnId::ROOT + && (!module_only || ns == MacroNS) && let Scope::ModuleGlobs(m1, _) = scope && let Scope::ModuleNonGlobs(m2, _) = innermost_scope && m1 == m2 @@ -887,18 +911,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ignore_import: Option>, ) -> Result, Determinacy> { match module { - ModuleOrUniformRoot::Module(module) => self - .resolve_ident_in_module_unadjusted( - module, - ident, - ns, - parent_scope, - Shadowing::Unrestricted, - finalize, - ignore_binding, - ignore_import, - ) - .map_err(|determinacy| determinacy.into_value()), + ModuleOrUniformRoot::Module(module) => self.resolve_ident_in_scope_set( + ident, + ScopeSet::Module(ns, module), + parent_scope, + finalize, + finalize.is_some(), + ignore_binding, + ignore_import, + ), ModuleOrUniformRoot::ModuleAndExternPrelude(module) => self.resolve_ident_in_scope_set( ident, ScopeSet::ModuleAndExternPrelude(ns, module), @@ -948,48 +969,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - /// Attempts to resolve `ident` in namespace `ns` of `module`. - fn resolve_ident_in_module_unadjusted<'r>( - mut self: CmResolver<'r, 'ra, 'tcx>, - module: Module<'ra>, - ident: Ident, - ns: Namespace, - parent_scope: &ParentScope<'ra>, - shadowing: Shadowing, - finalize: Option, - // This binding should be ignored during in-module resolution, so that we don't get - // "self-confirming" import resolutions during import validation and checking. - ignore_binding: Option>, - ignore_import: Option>, - ) -> Result, ControlFlow> { - let res = self.reborrow().resolve_ident_in_module_non_globs_unadjusted( - module, - ident, - ns, - parent_scope, - shadowing, - finalize, - ignore_binding, - ignore_import, - ); - - match res { - Ok(_) | Err(ControlFlow::Break(_)) => return res, - Err(ControlFlow::Continue(_)) => {} - } - - self.resolve_ident_in_module_globs_unadjusted( - module, - ident, - ns, - parent_scope, - shadowing, - finalize, - ignore_binding, - ignore_import, - ) - } - /// Attempts to resolve `ident` in namespace `ns` of non-glob bindings in `module`. fn resolve_ident_in_module_non_globs_unadjusted<'r>( mut self: CmResolver<'r, 'ra, 'tcx>, @@ -999,6 +978,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, shadowing: Shadowing, finalize: Option, + // This binding should be ignored during in-module resolution, so that we don't get + // "self-confirming" import resolutions during import validation and checking. ignore_binding: Option>, ignore_import: Option>, ) -> Result, ControlFlow> { @@ -1156,28 +1137,24 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Some(None) => {} None => continue, }; - let result = self.reborrow().resolve_ident_in_module_unadjusted( - module, + let result = self.reborrow().resolve_ident_in_scope_set( ident, - ns, + ScopeSet::Module(ns, module), adjusted_parent_scope, - Shadowing::Unrestricted, None, + false, ignore_binding, ignore_import, ); match result { - Err(ControlFlow::Break(Determined) | ControlFlow::Continue(Determined)) => continue, + Err(Determined) => continue, Ok(binding) if !self.is_accessible_from(binding.vis, glob_import.parent_scope.module) => { continue; } - Ok(_) - | Err(ControlFlow::Break(Undetermined) | ControlFlow::Continue(Undetermined)) => { - return Err(ControlFlow::Continue(Undetermined)); - } + Ok(_) | Err(Undetermined) => return Err(ControlFlow::Continue(Undetermined)), } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index dd80f5da508c..290d21cad4b9 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -44,8 +44,8 @@ use tracing::{debug, instrument, trace}; use crate::{ BindingError, BindingKey, Finalize, LexicalScopeBinding, Module, ModuleOrUniformRoot, - NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, TyCtxt, UseError, - Used, errors, path_names_to_string, rustdoc, + NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, Stage, TyCtxt, + UseError, Used, errors, path_names_to_string, rustdoc, }; mod diagnostics; @@ -1514,7 +1514,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { opt_ns, &self.parent_scope, Some(source), - finalize, + finalize.map(|finalize| Finalize { stage: Stage::Late, ..finalize }), Some(&self.ribs), None, None, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index fa53d57d175e..1d462f173f4d 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -153,6 +153,8 @@ enum Scope<'ra> { enum ScopeSet<'ra> { /// All scopes with the given namespace. All(Namespace), + /// Two scopes inside a module, for non-glob and glob bindings. + Module(Namespace, Module<'ra>), /// A module, then extern prelude (used for mixed 2015-2018 mode in macros). ModuleAndExternPrelude(Namespace, Module<'ra>), /// Just two extern prelude scopes. From f841758cf5136bd982631e497df35ddc5f80521a Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 2 Jan 2026 11:04:27 +0100 Subject: [PATCH 0180/1061] Remove unnecessary `ConstLiteralRef` enum --- .../crates/hir-def/src/expr_store/lower.rs | 1 - .../crates/hir-def/src/hir/type_ref.rs | 58 +------- .../crates/hir-ty/src/consteval.rs | 131 ++++++++++++++---- .../rust-analyzer/crates/hir-ty/src/lower.rs | 24 +--- .../crates/hir-ty/src/next_solver/ty.rs | 18 +++ 5 files changed, 132 insertions(+), 100 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs index af274f1a485b..d3774ded39dc 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs @@ -2319,7 +2319,6 @@ impl<'db> ExprCollector<'db> { ast::Pat::SlicePat(p) => { let SlicePatComponents { prefix, slice, suffix } = p.components(); - // FIXME properly handle `RestPat` Pat::Slice { prefix: prefix.into_iter().map(|p| self.collect_pat(p, binding_list)).collect(), slice: slice.map(|p| self.collect_pat(p, binding_list)), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs index ad8535413d67..b64199fa2697 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs @@ -1,8 +1,6 @@ //! HIR for references to types. Paths in these are not yet resolved. They can //! be directly created from an ast::TypeRef, without further queries. -use std::fmt::Write; - use hir_expand::name::Name; use intern::Symbol; use la_arena::Idx; @@ -10,12 +8,11 @@ use thin_vec::ThinVec; use crate::{ LifetimeParamId, TypeParamId, - builtin_type::{BuiltinInt, BuiltinType, BuiltinUint}, expr_store::{ ExpressionStore, path::{GenericArg, Path}, }, - hir::{ExprId, Literal}, + hir::ExprId, }; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] @@ -275,56 +272,3 @@ impl TypeBound { pub struct ConstRef { pub expr: ExprId, } - -/// A literal constant value -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum LiteralConstRef { - Int(i128), - UInt(u128), - Bool(bool), - Char(char), - - /// Case of an unknown value that rustc might know but we don't - // FIXME: this is a hack to get around chalk not being able to represent unevaluatable - // constants - // https://github.com/rust-lang/rust-analyzer/pull/8813#issuecomment-840679177 - // https://rust-lang.zulipchat.com/#narrow/stream/144729-wg-traits/topic/Handling.20non.20evaluatable.20constants'.20equality/near/238386348 - Unknown, -} - -impl LiteralConstRef { - pub fn builtin_type(&self) -> BuiltinType { - match self { - LiteralConstRef::UInt(_) | LiteralConstRef::Unknown => { - BuiltinType::Uint(BuiltinUint::U128) - } - LiteralConstRef::Int(_) => BuiltinType::Int(BuiltinInt::I128), - LiteralConstRef::Char(_) => BuiltinType::Char, - LiteralConstRef::Bool(_) => BuiltinType::Bool, - } - } -} - -impl From for LiteralConstRef { - fn from(literal: Literal) -> Self { - match literal { - Literal::Char(c) => Self::Char(c), - Literal::Bool(flag) => Self::Bool(flag), - Literal::Int(num, _) => Self::Int(num), - Literal::Uint(num, _) => Self::UInt(num), - _ => Self::Unknown, - } - } -} - -impl std::fmt::Display for LiteralConstRef { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - match self { - LiteralConstRef::Int(num) => num.fmt(f), - LiteralConstRef::UInt(num) => num.fmt(f), - LiteralConstRef::Bool(flag) => flag.fmt(f), - LiteralConstRef::Char(c) => write!(f, "'{c}'"), - LiteralConstRef::Unknown => f.write_char('_'), - } - } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs index f11240e0f78c..5bc2446fdd2d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -7,9 +7,9 @@ use base_db::Crate; use hir_def::{ ConstId, EnumVariantId, GeneralConstId, HasModule, StaticId, attrs::AttrFlags, + builtin_type::{BuiltinInt, BuiltinType, BuiltinUint}, expr_store::Body, - hir::{Expr, ExprId}, - type_ref::LiteralConstRef, + hir::{Expr, ExprId, Literal}, }; use hir_expand::Lookup; use rustc_type_ir::inherent::IntoKind; @@ -23,7 +23,7 @@ use crate::{ mir::{MirEvalError, MirLowerError}, next_solver::{ Const, ConstBytes, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, - ParamEnv, StoredConst, StoredGenericArgs, Ty, ValueConst, + StoredConst, StoredGenericArgs, Ty, ValueConst, }, traits::StoredParamEnvAndCrate, }; @@ -81,47 +81,122 @@ impl From for ConstEvalError { /// Interns a constant scalar with the given type pub fn intern_const_ref<'a>( db: &'a dyn HirDatabase, - value: &LiteralConstRef, + value: &Literal, ty: Ty<'a>, - krate: Crate, + _krate: Crate, ) -> Const<'a> { let interner = DbInterner::new_no_crate(db); - let layout = db - .layout_of_ty(ty.store(), ParamEnvAndCrate { param_env: ParamEnv::empty(), krate }.store()); let kind = match value { - LiteralConstRef::Int(i) => { - // FIXME: We should handle failure of layout better. - let size = layout.map(|it| it.size.bytes_usize()).unwrap_or(16); + &Literal::Uint(i, builtin_ty) + if builtin_ty.is_none() || ty.as_builtin() == builtin_ty.map(BuiltinType::Uint) => + { + let memory = match ty.as_builtin() { + Some(BuiltinType::Uint(builtin_uint)) => match builtin_uint { + BuiltinUint::U8 => Box::new([i as u8]) as Box<[u8]>, + BuiltinUint::U16 => Box::new((i as u16).to_le_bytes()), + BuiltinUint::U32 => Box::new((i as u32).to_le_bytes()), + BuiltinUint::U64 => Box::new((i as u64).to_le_bytes()), + BuiltinUint::U128 => Box::new((i).to_le_bytes()), + BuiltinUint::Usize => Box::new((i as usize).to_le_bytes()), + }, + _ => return Const::new(interner, rustc_type_ir::ConstKind::Error(ErrorGuaranteed)), + }; rustc_type_ir::ConstKind::Value(ValueConst::new( ty, - ConstBytes { - memory: i.to_le_bytes()[0..size].into(), - memory_map: MemoryMap::default(), - }, + ConstBytes { memory, memory_map: MemoryMap::default() }, )) } - LiteralConstRef::UInt(i) => { - let size = layout.map(|it| it.size.bytes_usize()).unwrap_or(16); + &Literal::Int(i, None) + if ty + .as_builtin() + .is_some_and(|builtin_ty| matches!(builtin_ty, BuiltinType::Uint(_))) => + { + let memory = match ty.as_builtin() { + Some(BuiltinType::Uint(builtin_uint)) => match builtin_uint { + BuiltinUint::U8 => Box::new([i as u8]) as Box<[u8]>, + BuiltinUint::U16 => Box::new((i as u16).to_le_bytes()), + BuiltinUint::U32 => Box::new((i as u32).to_le_bytes()), + BuiltinUint::U64 => Box::new((i as u64).to_le_bytes()), + BuiltinUint::U128 => Box::new((i as u128).to_le_bytes()), + BuiltinUint::Usize => Box::new((i as usize).to_le_bytes()), + }, + _ => return Const::new(interner, rustc_type_ir::ConstKind::Error(ErrorGuaranteed)), + }; rustc_type_ir::ConstKind::Value(ValueConst::new( ty, - ConstBytes { - memory: i.to_le_bytes()[0..size].into(), - memory_map: MemoryMap::default(), - }, + ConstBytes { memory, memory_map: MemoryMap::default() }, )) } - LiteralConstRef::Bool(b) => rustc_type_ir::ConstKind::Value(ValueConst::new( + &Literal::Int(i, builtin_ty) + if builtin_ty.is_none() || ty.as_builtin() == builtin_ty.map(BuiltinType::Int) => + { + let memory = match ty.as_builtin() { + Some(BuiltinType::Int(builtin_int)) => match builtin_int { + BuiltinInt::I8 => Box::new([i as u8]) as Box<[u8]>, + BuiltinInt::I16 => Box::new((i as i16).to_le_bytes()), + BuiltinInt::I32 => Box::new((i as i32).to_le_bytes()), + BuiltinInt::I64 => Box::new((i as i64).to_le_bytes()), + BuiltinInt::I128 => Box::new((i).to_le_bytes()), + BuiltinInt::Isize => Box::new((i as isize).to_le_bytes()), + }, + _ => return Const::new(interner, rustc_type_ir::ConstKind::Error(ErrorGuaranteed)), + }; + rustc_type_ir::ConstKind::Value(ValueConst::new( + ty, + ConstBytes { memory, memory_map: MemoryMap::default() }, + )) + } + Literal::Float(float_type_wrapper, builtin_float) + if builtin_float.is_none() + || ty.as_builtin() == builtin_float.map(BuiltinType::Float) => + { + let memory = match ty.as_builtin().unwrap() { + BuiltinType::Float(builtin_float) => match builtin_float { + // FIXME: + hir_def::builtin_type::BuiltinFloat::F16 => Box::new([0u8; 2]) as Box<[u8]>, + hir_def::builtin_type::BuiltinFloat::F32 => { + Box::new(float_type_wrapper.to_f32().to_le_bytes()) + } + hir_def::builtin_type::BuiltinFloat::F64 => { + Box::new(float_type_wrapper.to_f64().to_le_bytes()) + } + // FIXME: + hir_def::builtin_type::BuiltinFloat::F128 => Box::new([0; 16]), + }, + _ => unreachable!(), + }; + rustc_type_ir::ConstKind::Value(ValueConst::new( + ty, + ConstBytes { memory, memory_map: MemoryMap::default() }, + )) + } + Literal::Bool(b) if ty.is_bool() => rustc_type_ir::ConstKind::Value(ValueConst::new( ty, ConstBytes { memory: Box::new([*b as u8]), memory_map: MemoryMap::default() }, )), - LiteralConstRef::Char(c) => rustc_type_ir::ConstKind::Value(ValueConst::new( + Literal::Char(c) if ty.is_char() => rustc_type_ir::ConstKind::Value(ValueConst::new( ty, ConstBytes { memory: (*c as u32).to_le_bytes().into(), memory_map: MemoryMap::default(), }, )), - LiteralConstRef::Unknown => rustc_type_ir::ConstKind::Error(ErrorGuaranteed), + Literal::String(symbol) if ty.is_str() => rustc_type_ir::ConstKind::Value(ValueConst::new( + ty, + ConstBytes { + memory: symbol.as_str().as_bytes().into(), + memory_map: MemoryMap::default(), + }, + )), + Literal::ByteString(items) if ty.as_slice().is_some_and(|ty| ty.is_u8()) => { + rustc_type_ir::ConstKind::Value(ValueConst::new( + ty, + ConstBytes { memory: items.clone(), memory_map: MemoryMap::default() }, + )) + } + // FIXME + Literal::CString(_items) => rustc_type_ir::ConstKind::Error(ErrorGuaranteed), + _ => rustc_type_ir::ConstKind::Error(ErrorGuaranteed), }; Const::new(interner, kind) } @@ -130,7 +205,15 @@ pub fn intern_const_ref<'a>( pub fn usize_const<'db>(db: &'db dyn HirDatabase, value: Option, krate: Crate) -> Const<'db> { intern_const_ref( db, - &value.map_or(LiteralConstRef::Unknown, LiteralConstRef::UInt), + &match value { + Some(value) => Literal::Uint(value, Some(BuiltinUint::Usize)), + None => { + return Const::new( + DbInterner::new_no_crate(db), + rustc_type_ir::ConstKind::Error(ErrorGuaranteed), + ); + } + }, Ty::new_uint(DbInterner::new_no_crate(db), rustc_type_ir::UintTy::Usize), krate, ) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index 9307868f3982..6688cf3d6025 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -27,8 +27,8 @@ use hir_def::{ resolver::{HasResolver, LifetimeNs, Resolver, TypeNs, ValueNs}, signatures::{FunctionSignature, TraitFlags, TypeAliasFlags}, type_ref::{ - ConstRef, LifetimeRefId, LiteralConstRef, PathId, TraitBoundModifier, - TraitRef as HirTraitRef, TypeBound, TypeRef, TypeRefId, + ConstRef, LifetimeRefId, PathId, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, + TypeRef, TypeRefId, }, }; use hir_expand::name::Name; @@ -281,21 +281,9 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { hir_def::hir::Expr::Path(path) => { self.path_to_const(path).unwrap_or_else(|| unknown_const(const_type)) } - hir_def::hir::Expr::Literal(literal) => intern_const_ref( - self.db, - &match *literal { - hir_def::hir::Literal::Float(_, _) - | hir_def::hir::Literal::String(_) - | hir_def::hir::Literal::ByteString(_) - | hir_def::hir::Literal::CString(_) => LiteralConstRef::Unknown, - hir_def::hir::Literal::Char(c) => LiteralConstRef::Char(c), - hir_def::hir::Literal::Bool(b) => LiteralConstRef::Bool(b), - hir_def::hir::Literal::Int(val, _) => LiteralConstRef::Int(val), - hir_def::hir::Literal::Uint(val, _) => LiteralConstRef::UInt(val), - }, - const_type, - self.resolver.krate(), - ), + hir_def::hir::Expr::Literal(literal) => { + intern_const_ref(self.db, literal, const_type, self.resolver.krate()) + } hir_def::hir::Expr::UnaryOp { expr: inner_expr, op: hir_def::hir::UnaryOp::Neg } => { if let hir_def::hir::Expr::Literal(literal) = &self.store[*inner_expr] { // Only handle negation for signed integers and floats @@ -304,7 +292,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { if let Some(negated_literal) = literal.clone().negate() { intern_const_ref( self.db, - &negated_literal.into(), + &negated_literal, const_type, self.resolver.krate(), ) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs index 030ba37015f2..66a24d394990 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs @@ -383,6 +383,11 @@ impl<'db> Ty<'db> { matches!(self.kind(), TyKind::Bool) } + #[inline] + pub fn is_char(self) -> bool { + matches!(self.kind(), TyKind::Char) + } + /// A scalar type is one that denotes an atomic datum, with no sub-components. /// (A RawPtr is scalar because it represents a non-managed pointer, so its /// contents are abstract to rustc.) @@ -422,6 +427,11 @@ impl<'db> Ty<'db> { matches!(self.kind(), TyKind::Tuple(tys) if tys.is_empty()) } + #[inline] + pub fn is_u8(self) -> bool { + matches!(self.kind(), TyKind::Uint(UintTy::U8)) + } + #[inline] pub fn is_raw_ptr(self) -> bool { matches!(self.kind(), TyKind::RawPtr(..)) @@ -456,6 +466,14 @@ impl<'db> Ty<'db> { } } + #[inline] + pub fn as_slice(self) -> Option> { + match self.kind() { + TyKind::Slice(ty) => Some(ty), + _ => None, + } + } + #[inline] pub fn ty_vid(self) -> Option { match self.kind() { From 0016a7174768082ea50187847e86b288ec28281a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 5 Dec 2025 16:31:04 +0300 Subject: [PATCH 0181/1061] resolve: Migrate one more special ambiguity for glob vs non-glob bindings in the same module to the usual ambiguity infra in `resolve_ident_in_scope_set` --- compiler/rustc_resolve/src/ident.rs | 3 +- compiler/rustc_resolve/src/imports.rs | 15 +----- .../ambiguous-glob-vs-expanded-extern.rs | 4 +- .../ambiguous-glob-vs-expanded-extern.stderr | 53 ------------------- tests/ui/imports/issue-114682-1.rs | 1 - tests/ui/imports/issue-114682-1.stderr | 27 +--------- .../local-modularized-tricky-fail-1.rs | 1 - .../local-modularized-tricky-fail-1.stderr | 31 ++--------- tests/ui/imports/macros.rs | 2 +- tests/ui/imports/macros.stderr | 21 +------- 10 files changed, 11 insertions(+), 147 deletions(-) delete mode 100644 tests/ui/imports/ambiguous-glob-vs-expanded-extern.stderr diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 82a87b8a9ed6..512b35310539 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -813,7 +813,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && m1 == m2 { // FIXME: this error is too conservative and technically unnecessary now when module - // scope is split into two scopes, remove it with lang team approval. + // scope is split into two scopes, at least when not resolving in `ScopeSet::Module`, + // remove it with lang team approval. Some(AmbiguityKind::GlobVsExpanded) } else { None diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 4e0f3db59821..a46ed5d8e69e 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -389,20 +389,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { (old_glob @ true, false) | (old_glob @ false, true) => { let (glob_binding, non_glob_binding) = if old_glob { (old_binding, binding) } else { (binding, old_binding) }; - if ns == MacroNS - && non_glob_binding.expansion != LocalExpnId::ROOT - && glob_binding.res() != non_glob_binding.res() - { - resolution.non_glob_binding = Some(this.new_ambiguity_binding( - AmbiguityKind::GlobVsExpanded, - non_glob_binding, - glob_binding, - false, - )); - } else { - resolution.non_glob_binding = Some(non_glob_binding); - } - + resolution.non_glob_binding = Some(non_glob_binding); if let Some(old_glob_binding) = resolution.glob_binding { assert!(old_glob_binding.is_glob_import()); if glob_binding.res() != old_glob_binding.res() { diff --git a/tests/ui/imports/ambiguous-glob-vs-expanded-extern.rs b/tests/ui/imports/ambiguous-glob-vs-expanded-extern.rs index de632119ecba..0277da46f750 100644 --- a/tests/ui/imports/ambiguous-glob-vs-expanded-extern.rs +++ b/tests/ui/imports/ambiguous-glob-vs-expanded-extern.rs @@ -1,6 +1,6 @@ +//@ check-pass //@ aux-crate: glob_vs_expanded=glob-vs-expanded.rs fn main() { - glob_vs_expanded::mac!(); //~ ERROR `mac` is ambiguous - //~| WARN this was previously accepted + glob_vs_expanded::mac!(); // OK } diff --git a/tests/ui/imports/ambiguous-glob-vs-expanded-extern.stderr b/tests/ui/imports/ambiguous-glob-vs-expanded-extern.stderr deleted file mode 100644 index 4a9a6c99819b..000000000000 --- a/tests/ui/imports/ambiguous-glob-vs-expanded-extern.stderr +++ /dev/null @@ -1,53 +0,0 @@ -error: `mac` is ambiguous - --> $DIR/ambiguous-glob-vs-expanded-extern.rs:4:23 - | -LL | glob_vs_expanded::mac!(); - | ^^^ ambiguous name - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #114095 - = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution -note: `mac` could refer to the macro defined here - --> $DIR/auxiliary/glob-vs-expanded.rs:9:13 - | -LL | () => { pub macro mac() {} } - | ^^^^^^^^^^^^^ -LL | } -LL | define_mac!(); - | ------------- in this macro invocation -note: `mac` could also refer to the macro defined here - --> $DIR/auxiliary/glob-vs-expanded.rs:5:9 - | -LL | pub use inner::*; - | ^^^^^ - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default - = note: this error originates in the macro `define_mac` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 1 previous error - -Future incompatibility report: Future breakage diagnostic: -error: `mac` is ambiguous - --> $DIR/ambiguous-glob-vs-expanded-extern.rs:4:23 - | -LL | glob_vs_expanded::mac!(); - | ^^^ ambiguous name - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #114095 - = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution -note: `mac` could refer to the macro defined here - --> $DIR/auxiliary/glob-vs-expanded.rs:9:13 - | -LL | () => { pub macro mac() {} } - | ^^^^^^^^^^^^^ -LL | } -LL | define_mac!(); - | ------------- in this macro invocation -note: `mac` could also refer to the macro defined here - --> $DIR/auxiliary/glob-vs-expanded.rs:5:9 - | -LL | pub use inner::*; - | ^^^^^ - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default - = note: this error originates in the macro `define_mac` (in Nightly builds, run with -Z macro-backtrace for more info) - diff --git a/tests/ui/imports/issue-114682-1.rs b/tests/ui/imports/issue-114682-1.rs index 58b78508026d..88fe05e51444 100644 --- a/tests/ui/imports/issue-114682-1.rs +++ b/tests/ui/imports/issue-114682-1.rs @@ -22,5 +22,4 @@ mac!(); fn main() { A!(); //~^ ERROR `A` is ambiguous - //~| ERROR `A` is ambiguous } diff --git a/tests/ui/imports/issue-114682-1.stderr b/tests/ui/imports/issue-114682-1.stderr index de8dc6cfb9ff..fd2776f50ad7 100644 --- a/tests/ui/imports/issue-114682-1.stderr +++ b/tests/ui/imports/issue-114682-1.stderr @@ -1,28 +1,3 @@ -error[E0659]: `A` is ambiguous - --> $DIR/issue-114682-1.rs:23:5 - | -LL | A!(); - | ^ ambiguous name - | - = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution -note: `A` could refer to the macro defined here - --> $DIR/issue-114682-1.rs:7:9 - | -LL | / pub macro A() { -LL | | println!("non import") -LL | | } - | |_________^ -... -LL | mac!(); - | ------ in this macro invocation -note: `A` could also refer to the macro imported here - --> $DIR/issue-114682-1.rs:19:9 - | -LL | pub use m::*; - | ^^^^ - = help: consider adding an explicit import of `A` to disambiguate - = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0659]: `A` is ambiguous --> $DIR/issue-114682-1.rs:23:5 | @@ -49,6 +24,6 @@ LL | pub use m::*; = help: use `crate::A` to refer to this macro unambiguously = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/imports/local-modularized-tricky-fail-1.rs b/tests/ui/imports/local-modularized-tricky-fail-1.rs index bba26ee43a24..ce700ae0de9b 100644 --- a/tests/ui/imports/local-modularized-tricky-fail-1.rs +++ b/tests/ui/imports/local-modularized-tricky-fail-1.rs @@ -27,7 +27,6 @@ mod inner1 { } exported!(); //~ ERROR `exported` is ambiguous - //~| ERROR `exported` is ambiguous mod inner2 { define_exported!(); diff --git a/tests/ui/imports/local-modularized-tricky-fail-1.stderr b/tests/ui/imports/local-modularized-tricky-fail-1.stderr index 54d928f7c812..b5b3be5953f9 100644 --- a/tests/ui/imports/local-modularized-tricky-fail-1.stderr +++ b/tests/ui/imports/local-modularized-tricky-fail-1.stderr @@ -1,28 +1,3 @@ -error[E0659]: `exported` is ambiguous - --> $DIR/local-modularized-tricky-fail-1.rs:29:1 - | -LL | exported!(); - | ^^^^^^^^ ambiguous name - | - = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution -note: `exported` could refer to the macro defined here - --> $DIR/local-modularized-tricky-fail-1.rs:6:5 - | -LL | / macro_rules! exported { -LL | | () => () -LL | | } - | |_____^ -... -LL | define_exported!(); - | ------------------ in this macro invocation -note: `exported` could also refer to the macro imported here - --> $DIR/local-modularized-tricky-fail-1.rs:23:5 - | -LL | use inner1::*; - | ^^^^^^^^^ - = help: consider adding an explicit import of `exported` to disambiguate - = note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0659]: `exported` is ambiguous --> $DIR/local-modularized-tricky-fail-1.rs:29:1 | @@ -50,7 +25,7 @@ LL | use inner1::*; = note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `panic` is ambiguous - --> $DIR/local-modularized-tricky-fail-1.rs:37:5 + --> $DIR/local-modularized-tricky-fail-1.rs:36:5 | LL | panic!(); | ^^^^^ ambiguous name @@ -71,7 +46,7 @@ LL | define_panic!(); = note: this error originates in the macro `define_panic` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `include` is ambiguous - --> $DIR/local-modularized-tricky-fail-1.rs:48:1 + --> $DIR/local-modularized-tricky-fail-1.rs:47:1 | LL | include!(); | ^^^^^^^ ambiguous name @@ -91,6 +66,6 @@ LL | define_include!(); = help: use `crate::include` to refer to this macro unambiguously = note: this error originates in the macro `define_include` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/imports/macros.rs b/tests/ui/imports/macros.rs index cf67e08c87a3..e1db42abd28f 100644 --- a/tests/ui/imports/macros.rs +++ b/tests/ui/imports/macros.rs @@ -13,7 +13,7 @@ mod m1 { mod m2 { use two_macros::*; - m! { //~ ERROR ambiguous + m! { use crate::foo::m; } } diff --git a/tests/ui/imports/macros.stderr b/tests/ui/imports/macros.stderr index 25a678c6b375..08ebfa5b8151 100644 --- a/tests/ui/imports/macros.stderr +++ b/tests/ui/imports/macros.stderr @@ -1,22 +1,3 @@ -error[E0659]: `m` is ambiguous - --> $DIR/macros.rs:16:5 - | -LL | m! { - | ^ ambiguous name - | - = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution -note: `m` could refer to the macro imported here - --> $DIR/macros.rs:17:13 - | -LL | use crate::foo::m; - | ^^^^^^^^^^^^^ -note: `m` could also refer to the macro imported here - --> $DIR/macros.rs:15:9 - | -LL | use two_macros::*; - | ^^^^^^^^^^^^^ - = help: consider adding an explicit import of `m` to disambiguate - error[E0659]: `m` is ambiguous --> $DIR/macros.rs:29:9 | @@ -36,6 +17,6 @@ LL | use two_macros::m; | ^^^^^^^^^^^^^ = help: use `self::m` to refer to this macro unambiguously -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0659`. From 78c61beb4816a9f103429da9a5cf49eeb6610ec9 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 5 Dec 2025 17:47:02 +0300 Subject: [PATCH 0182/1061] resolve: Patch up an inconsistent resolution ICE revealed by the previous commit --- compiler/rustc_resolve/src/ident.rs | 8 ++++++++ tests/ui/imports/macros.rs | 2 +- tests/ui/imports/macros.stderr | 22 +++++++++++++++++++++- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 512b35310539..f400ae8f6439 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1249,6 +1249,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, ) -> bool { for single_import in &resolution.single_imports { + if let Some(binding) = resolution.non_glob_binding + && let NameBindingKind::Import { import, .. } = binding.kind + && import == *single_import + { + // Single import has already defined the name and we are aware of it, + // no need to block the globs. + continue; + } if ignore_import == Some(*single_import) { continue; } diff --git a/tests/ui/imports/macros.rs b/tests/ui/imports/macros.rs index e1db42abd28f..121f1f7ae043 100644 --- a/tests/ui/imports/macros.rs +++ b/tests/ui/imports/macros.rs @@ -13,7 +13,7 @@ mod m1 { mod m2 { use two_macros::*; - m! { + m! { //~ ERROR `m` is ambiguous use crate::foo::m; } } diff --git a/tests/ui/imports/macros.stderr b/tests/ui/imports/macros.stderr index 08ebfa5b8151..9c081cc7af8b 100644 --- a/tests/ui/imports/macros.stderr +++ b/tests/ui/imports/macros.stderr @@ -1,3 +1,23 @@ +error[E0659]: `m` is ambiguous + --> $DIR/macros.rs:16:5 + | +LL | m! { + | ^ ambiguous name + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution +note: `m` could refer to the macro imported here + --> $DIR/macros.rs:17:13 + | +LL | use crate::foo::m; + | ^^^^^^^^^^^^^ + = help: use `self::m` to refer to this macro unambiguously +note: `m` could also refer to the macro imported here + --> $DIR/macros.rs:15:9 + | +LL | use two_macros::*; + | ^^^^^^^^^^^^^ + = help: use `self::m` to refer to this macro unambiguously + error[E0659]: `m` is ambiguous --> $DIR/macros.rs:29:9 | @@ -17,6 +37,6 @@ LL | use two_macros::m; | ^^^^^^^^^^^^^ = help: use `self::m` to refer to this macro unambiguously -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0659`. From 2e123aef706ac12e1277b90c933055d0b4b79d9b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 2 Jan 2026 14:29:23 +0300 Subject: [PATCH 0183/1061] resolve: Avoid additional ambiguities from splitting modules into two scopes --- compiler/rustc_resolve/src/ident.rs | 15 ++++++++++++- tests/ui/imports/overwritten-glob-ambig.rs | 26 ++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 tests/ui/imports/overwritten-glob-ambig.rs diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index f400ae8f6439..c9f560d2a6fa 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -828,8 +828,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && innermost_results[1..].iter().any(|(b, s)| { matches!(s, Scope::ExternPreludeItems) && *b != innermost_binding }); + // Skip ambiguity errors for nonglob module bindings "overridden" + // by glob module bindings in the same module. + // FIXME: Remove with lang team approval. + let issue_149681_hack = match scope { + Scope::ModuleGlobs(m1, _) + if innermost_results[1..] + .iter() + .any(|(_, s)| matches!(*s, Scope::ModuleNonGlobs(m2, _) if m1 == m2)) => + { + true + } + _ => false, + }; - if issue_145575_hack { + if issue_145575_hack || issue_149681_hack { self.issue_145575_hack_applied = true; } else { self.ambiguity_errors.push(AmbiguityError { diff --git a/tests/ui/imports/overwritten-glob-ambig.rs b/tests/ui/imports/overwritten-glob-ambig.rs new file mode 100644 index 000000000000..a5918568c62a --- /dev/null +++ b/tests/ui/imports/overwritten-glob-ambig.rs @@ -0,0 +1,26 @@ +// Test for a regression introduced by splitting module scope into two scopes +// (similar to issue #145575). + +//@ check-pass +//@ edition: 2018.. + +#[macro_use] +mod one { + // Macro that is in a different module, but still in scope due to `macro_use` + macro_rules! mac { () => {} } + pub(crate) use mac; +} + +mod other { + macro_rules! mac { () => {} } + pub(crate) use mac; +} + +// Single import of the same in the current module. +use one::mac; +// Glob import of a different macro in the current module (should be an ambiguity). +use other::*; + +fn main() { + mac!(); // OK for now, the ambiguity is not reported +} From 3f3db936514dca81c1e6ca6d004da9921450d981 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 2 Jan 2026 15:40:21 +0300 Subject: [PATCH 0184/1061] metadata: Stop keeping `AmbiguityKind` in name bindings It can only be `GlobVsGlob` now. --- compiler/rustc_middle/src/metadata.rs | 7 ----- .../rustc_resolve/src/build_reduced_graph.rs | 22 ++++++--------- compiler/rustc_resolve/src/imports.rs | 28 ++++++------------- compiler/rustc_resolve/src/lib.rs | 10 +++---- 4 files changed, 22 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_middle/src/metadata.rs b/compiler/rustc_middle/src/metadata.rs index 2b0be9865799..b7848bc261d8 100644 --- a/compiler/rustc_middle/src/metadata.rs +++ b/compiler/rustc_middle/src/metadata.rs @@ -45,16 +45,9 @@ pub struct ModChild { pub reexport_chain: SmallVec<[Reexport; 2]>, } -#[derive(Debug, TyEncodable, TyDecodable, HashStable)] -pub enum AmbigModChildKind { - GlobVsGlob, - GlobVsExpanded, -} - /// Same as `ModChild`, however, it includes ambiguity error. #[derive(Debug, TyEncodable, TyDecodable, HashStable)] pub struct AmbigModChild { pub main: ModChild, pub second: ModChild, - pub kind: AmbigModChildKind, } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index b9c945a440f8..241c13663ae5 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -22,7 +22,7 @@ use rustc_hir::def::{self, *}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_index::bit_set::DenseBitSet; use rustc_metadata::creader::LoadedMacro; -use rustc_middle::metadata::{AmbigModChildKind, ModChild, Reexport}; +use rustc_middle::metadata::{ModChild, Reexport}; use rustc_middle::ty::{Feed, Visibility}; use rustc_middle::{bug, span_bug}; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind}; @@ -36,9 +36,9 @@ use crate::imports::{ImportData, ImportKind}; use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; use crate::ref_mut::CmCell; use crate::{ - AmbiguityKind, BindingKey, ExternPreludeEntry, Finalize, MacroData, Module, ModuleKind, - ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind, ParentScope, PathResult, - ResolutionError, Resolver, Segment, Used, VisResolutionError, errors, + BindingKey, ExternPreludeEntry, Finalize, MacroData, Module, ModuleKind, ModuleOrUniformRoot, + NameBinding, NameBindingData, NameBindingKind, ParentScope, PathResult, ResolutionError, + Resolver, Segment, Used, VisResolutionError, errors, }; type Res = def::Res; @@ -82,7 +82,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { vis: Visibility, span: Span, expansion: LocalExpnId, - ambiguity: Option<(NameBinding<'ra>, AmbiguityKind)>, + ambiguity: Option>, ) { let binding = self.arenas.alloc_name_binding(NameBindingData { kind: NameBindingKind::Res(res), @@ -254,7 +254,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { &child.main, parent_scope, children.len() + i, - Some((&child.second, child.kind)), + Some(&child.second), ) } } @@ -265,7 +265,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { child: &ModChild, parent_scope: ParentScope<'ra>, child_index: usize, - ambig_child: Option<(&ModChild, AmbigModChildKind)>, + ambig_child: Option<&ModChild>, ) { let parent = parent_scope.module; let child_span = |this: &Self, reexport_chain: &[Reexport], res: def::Res<_>| { @@ -280,15 +280,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let span = child_span(self, reexport_chain, res); let res = res.expect_non_local(); let expansion = parent_scope.expansion; - let ambig = ambig_child.map(|(ambig_child, ambig_kind)| { + let ambig = ambig_child.map(|ambig_child| { let ModChild { ident: _, res, vis, ref reexport_chain } = *ambig_child; let span = child_span(self, reexport_chain, res); let res = res.expect_non_local(); - let ambig_kind = match ambig_kind { - AmbigModChildKind::GlobVsGlob => AmbiguityKind::GlobVsGlob, - AmbigModChildKind::GlobVsExpanded => AmbiguityKind::GlobVsExpanded, - }; - (self.arenas.new_res_binding(res, vis, span, expansion), ambig_kind) + self.arenas.new_res_binding(res, vis, span, expansion) }); // Record primary definitions. diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index a46ed5d8e69e..558f769eda19 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -9,7 +9,7 @@ use rustc_errors::codes::*; use rustc_errors::{Applicability, MultiSpan, pluralize, struct_span_code_err}; use rustc_hir::def::{self, DefKind, PartialRes}; use rustc_hir::def_id::{DefId, LocalDefIdMap}; -use rustc_middle::metadata::{AmbigModChild, AmbigModChildKind, ModChild, Reexport}; +use rustc_middle::metadata::{AmbigModChild, ModChild, Reexport}; use rustc_middle::span_bug; use rustc_middle::ty::Visibility; use rustc_session::lint::BuiltinLintDiag; @@ -32,10 +32,9 @@ use crate::errors::{ }; use crate::ref_mut::CmCell; use crate::{ - AmbiguityError, AmbiguityKind, BindingKey, CmResolver, Determinacy, Finalize, ImportSuggestion, - Module, ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind, ParentScope, - PathResult, PerNS, ResolutionError, Resolver, ScopeSet, Segment, Used, module_to_string, - names_to_string, + AmbiguityError, BindingKey, CmResolver, Determinacy, Finalize, ImportSuggestion, Module, + ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind, ParentScope, PathResult, + PerNS, ResolutionError, Resolver, ScopeSet, Segment, Used, module_to_string, names_to_string, }; type Res = def::Res; @@ -373,7 +372,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { resolution.glob_binding = Some(glob_binding); } else if res != old_glob_binding.res() { resolution.glob_binding = Some(this.new_ambiguity_binding( - AmbiguityKind::GlobVsGlob, old_glob_binding, glob_binding, warn_ambiguity, @@ -394,7 +392,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { assert!(old_glob_binding.is_glob_import()); if glob_binding.res() != old_glob_binding.res() { resolution.glob_binding = Some(this.new_ambiguity_binding( - AmbiguityKind::GlobVsGlob, old_glob_binding, glob_binding, false, @@ -424,12 +421,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn new_ambiguity_binding( &self, - ambiguity_kind: AmbiguityKind, primary_binding: NameBinding<'ra>, secondary_binding: NameBinding<'ra>, warn_ambiguity: bool, ) -> NameBinding<'ra> { - let ambiguity = Some((secondary_binding, ambiguity_kind)); + let ambiguity = Some(secondary_binding); let data = NameBindingData { ambiguity, warn_ambiguity, ..*primary_binding }; self.arenas.alloc_name_binding(data) } @@ -645,7 +641,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let Some(binding) = resolution.best_binding() else { continue }; if let NameBindingKind::Import { import, .. } = binding.kind - && let Some((amb_binding, _)) = binding.ambiguity + && let Some(amb_binding) = binding.ambiguity && binding.res() != Res::Err && exported_ambiguities.contains(&binding) { @@ -1553,9 +1549,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { vis: binding.vis, reexport_chain, }; - if let Some((ambig_binding1, ambig_binding2, ambig_kind)) = - binding.descent_to_ambiguity() - { + if let Some((ambig_binding1, ambig_binding2)) = binding.descent_to_ambiguity() { let main = child(ambig_binding1.reexport_chain(this)); let second = ModChild { ident: ident.0, @@ -1563,13 +1557,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { vis: ambig_binding2.vis, reexport_chain: ambig_binding2.reexport_chain(this), }; - let kind = match ambig_kind { - AmbiguityKind::GlobVsGlob => AmbigModChildKind::GlobVsGlob, - AmbiguityKind::GlobVsExpanded => AmbigModChildKind::GlobVsExpanded, - _ => unreachable!(), - }; - - ambig_children.push(AmbigModChild { main, second, kind }) + ambig_children.push(AmbigModChild { main, second }) } else { children.push(child(binding.reexport_chain(this))); } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 1d462f173f4d..fbd16072c2c0 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -807,7 +807,7 @@ impl<'ra> fmt::Debug for Module<'ra> { #[derive(Clone, Copy, Debug)] struct NameBindingData<'ra> { kind: NameBindingKind<'ra>, - ambiguity: Option<(NameBinding<'ra>, AmbiguityKind)>, + ambiguity: Option>, /// Produce a warning instead of an error when reporting ambiguities inside this binding. /// May apply to indirect ambiguities under imports, so `ambiguity.is_some()` is not required. warn_ambiguity: bool, @@ -937,9 +937,9 @@ impl<'ra> NameBindingData<'ra> { fn descent_to_ambiguity( self: NameBinding<'ra>, - ) -> Option<(NameBinding<'ra>, NameBinding<'ra>, AmbiguityKind)> { + ) -> Option<(NameBinding<'ra>, NameBinding<'ra>)> { match self.ambiguity { - Some((ambig_binding, ambig_kind)) => Some((self, ambig_binding, ambig_kind)), + Some(ambig_binding) => Some((self, ambig_binding)), None => match self.kind { NameBindingKind::Import { binding, .. } => binding.descent_to_ambiguity(), _ => None, @@ -2064,9 +2064,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { used: Used, warn_ambiguity: bool, ) { - if let Some((b2, kind)) = used_binding.ambiguity { + if let Some(b2) = used_binding.ambiguity { let ambiguity_error = AmbiguityError { - kind, + kind: AmbiguityKind::GlobVsGlob, ident, b1: used_binding, b2, From bfe591aac4c83c4e542a0fa3b00a88d7d6f242ca Mon Sep 17 00:00:00 2001 From: Alessio Date: Fri, 2 Jan 2026 14:54:36 +0100 Subject: [PATCH 0185/1061] library: Fix typo in the documentatio of `Cstring::from_vec_with_nul` Fixes the sentence "Attempts to converts a Vec to a CString.", where "converts" should be in the base form as it is part of the to-infinitive form. --- library/alloc/src/ffi/c_str.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index 59f5857b97aa..d6dcba7107a9 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -636,7 +636,7 @@ impl CString { Self { inner: v.into_boxed_slice() } } - /// Attempts to converts a [Vec]<[u8]> to a [`CString`]. + /// Attempts to convert a [Vec]<[u8]> to a [`CString`]. /// /// Runtime checks are present to ensure there is only one nul byte in the /// [`Vec`], its last element. From 8d5a7b685e63fe8e313da974b7e5b70117db1680 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 2 Jan 2026 13:16:21 +0100 Subject: [PATCH 0186/1061] Reduce `impl_signature` query dependencies in method resolution --- .../crates/hir-def/src/item_scope.rs | 16 ++++++++++++---- .../crates/hir-def/src/item_tree.rs | 4 +++- .../crates/hir-def/src/item_tree/lower.rs | 2 +- .../crates/hir-def/src/item_tree/pretty.rs | 2 +- .../crates/hir-def/src/lang_item.rs | 2 +- .../crates/hir-def/src/nameres/collector.rs | 4 +++- .../crates/hir-ty/src/method_resolution.rs | 9 ++------- .../crates/hir-ty/src/tests/incremental.rs | 18 ++++++------------ src/tools/rust-analyzer/crates/hir/src/lib.rs | 11 +++++------ .../ide-completion/src/tests/flyimport.rs | 4 ++-- 10 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs index 9e7868b273ef..a3278dd76c86 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs @@ -158,7 +158,7 @@ pub struct ItemScope { /// declared. declarations: ThinVec, - impls: ThinVec, + impls: ThinVec<(ImplId, /* trait impl */ bool)>, builtin_derive_impls: ThinVec, extern_blocks: ThinVec, unnamed_consts: ThinVec, @@ -327,7 +327,15 @@ impl ItemScope { } pub fn impls(&self) -> impl ExactSizeIterator + '_ { - self.impls.iter().copied() + self.impls.iter().map(|&(id, _)| id) + } + + pub fn trait_impls(&self) -> impl Iterator + '_ { + self.impls.iter().filter(|&&(_, is_trait_impl)| is_trait_impl).map(|&(id, _)| id) + } + + pub fn inherent_impls(&self) -> impl Iterator + '_ { + self.impls.iter().filter(|&&(_, is_trait_impl)| !is_trait_impl).map(|&(id, _)| id) } pub fn builtin_derive_impls(&self) -> impl ExactSizeIterator + '_ { @@ -472,8 +480,8 @@ impl ItemScope { self.legacy_macros.get(name).map(|it| &**it) } - pub(crate) fn define_impl(&mut self, imp: ImplId) { - self.impls.push(imp); + pub(crate) fn define_impl(&mut self, imp: ImplId, is_trait_impl: bool) { + self.impls.push((imp, is_trait_impl)); } pub(crate) fn define_builtin_derive_impl(&mut self, imp: BuiltinDeriveImplId) { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs index 2e838fad2e9f..a1707f17beb0 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs @@ -614,7 +614,9 @@ pub struct Trait { } #[derive(Debug, Clone, Eq, PartialEq)] -pub struct Impl {} +pub struct Impl { + pub is_trait_impl: bool, +} #[derive(Debug, Clone, PartialEq, Eq)] pub struct TypeAlias { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs index d8519f7393df..3f19e001548e 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs @@ -271,7 +271,7 @@ impl<'a> Ctx<'a> { let ast_id = self.source_ast_id_map.ast_id(impl_def); // Note that trait impls don't get implicit `Self` unlike traits, because here they are a // type alias rather than a type parameter, so this is handled by the resolver. - let res = Impl {}; + let res = Impl { is_trait_impl: impl_def.trait_().is_some() }; self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Impl(res)); ast_id } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs index c89299e6d863..4113a778eaaf 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs @@ -258,7 +258,7 @@ impl Printer<'_> { w!(self, "trait {} {{ ... }}", name.display(self.db, self.edition)); } ModItemId::Impl(ast_id) => { - let Impl {} = &self.tree[ast_id]; + let Impl { is_trait_impl: _ } = &self.tree[ast_id]; self.print_ast_id(ast_id.erase()); w!(self, "impl {{ ... }}"); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index 41d69c1fd624..d3f4480b207e 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -41,7 +41,7 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option { let impl_id = ImplLoc { container: module_id, id: InFile::new(self.file_id(), imp) } .intern(db); - self.def_collector.def_map.modules[self.module_id].scope.define_impl(impl_id) + self.def_collector.def_map.modules[self.module_id] + .scope + .define_impl(impl_id, self.item_tree[imp].is_trait_impl) } ModItemId::Function(id) => { let it = &self.item_tree[id]; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index 3d7cc4ffbf8a..e4681b464fec 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -609,12 +609,7 @@ impl InherentImpls { map: &mut FxHashMap>, ) { for (_module_id, module_data) in def_map.modules() { - for impl_id in module_data.scope.impls() { - let data = db.impl_signature(impl_id); - if data.target_trait.is_some() { - continue; - } - + for impl_id in module_data.scope.inherent_impls() { let interner = DbInterner::new_no_crate(db); let self_ty = db.impl_self_ty(impl_id); let self_ty = self_ty.instantiate_identity(); @@ -730,7 +725,7 @@ impl TraitImpls { map: &mut FxHashMap, ) { for (_module_id, module_data) in def_map.modules() { - for impl_id in module_data.scope.impls() { + for impl_id in module_data.scope.trait_impls() { let trait_ref = match db.impl_trait(impl_id) { Some(tr) => tr.instantiate_identity(), None => continue, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs index 633ab43c4cec..118f433a24e6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs @@ -539,12 +539,6 @@ impl SomeStruct { "AttrFlags::query_", "AttrFlags::query_", "AttrFlags::query_", - "impl_trait_with_diagnostics_query", - "impl_signature_shim", - "impl_signature_with_source_map_shim", - "impl_self_ty_with_diagnostics_query", - "struct_signature_shim", - "struct_signature_with_source_map_shim", ] "#]], ); @@ -617,7 +611,6 @@ fn main() { "lang_items", "crate_lang_items", "AttrFlags::query_", - "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", @@ -633,13 +626,14 @@ fn main() { "GenericPredicates::query_with_diagnostics_", "value_ty_query", "InherentImpls::for_crate_", - "impl_signature_shim", - "impl_signature_with_source_map_shim", "callable_item_signature_query", "TraitImpls::for_crate_and_deps_", "TraitImpls::for_crate_", "impl_trait_with_diagnostics_query", + "impl_signature_shim", + "impl_signature_with_source_map_shim", "impl_self_ty_with_diagnostics_query", + "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", ] "#]], @@ -710,7 +704,6 @@ fn main() { "crate_lang_items", "AttrFlags::query_", "AttrFlags::query_", - "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", @@ -722,12 +715,13 @@ fn main() { "struct_signature_with_source_map_shim", "GenericPredicates::query_with_diagnostics_", "InherentImpls::for_crate_", - "impl_signature_with_source_map_shim", - "impl_signature_shim", "callable_item_signature_query", "TraitImpls::for_crate_", + "impl_signature_with_source_map_shim", + "impl_signature_shim", "impl_trait_with_diagnostics_query", "impl_self_ty_with_diagnostics_query", + "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", ] "#]], diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 1ab57c4489cf..527614d56a01 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -803,22 +803,21 @@ impl Module { emit_def_diagnostic(db, acc, diag, edition, loc.container.krate(db)); } - if impl_signature.target_trait.is_none() - && !is_inherent_impl_coherent(db, def_map, impl_id) - { + let trait_impl = impl_signature.target_trait.is_some(); + if !trait_impl && !is_inherent_impl_coherent(db, def_map, impl_id) { acc.push(IncoherentImpl { impl_: ast_id_map.get(loc.id.value), file_id }.into()) } - if !impl_def.check_orphan_rules(db) { + if trait_impl && !impl_def.check_orphan_rules(db) { acc.push(TraitImplOrphan { impl_: ast_id_map.get(loc.id.value), file_id }.into()) } - let trait_ = impl_def.trait_(db); + let trait_ = trait_impl.then(|| impl_def.trait_(db)).flatten(); let mut trait_is_unsafe = trait_.is_some_and(|t| t.is_unsafe(db)); let impl_is_negative = impl_def.is_negative(db); let impl_is_unsafe = impl_def.is_unsafe(db); - let trait_is_unresolved = trait_.is_none() && impl_signature.target_trait.is_some(); + let trait_is_unresolved = trait_.is_none() && trait_impl; if trait_is_unresolved { // Ignore trait safety errors when the trait is unresolved, as otherwise we'll treat it as safe, // which may not be correct. diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs index aad881f8ce4f..2912457da1f7 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs @@ -781,9 +781,9 @@ fn main() { } "#, expect![[r#" - fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED - ct SPECIAL_CONST (use dep::test_mod::TestTrait) u8 DEPRECATED me random_method(…) (use dep::test_mod::TestTrait) fn(&self) DEPRECATED + ct SPECIAL_CONST (use dep::test_mod::TestTrait) u8 DEPRECATED + fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED "#]], ); } From 7e425b898540c51f73f152a353e5a138ae8602eb Mon Sep 17 00:00:00 2001 From: Antoni Spaanderman <56turtle56@gmail.com> Date: Fri, 2 Jan 2026 16:05:42 +0100 Subject: [PATCH 0187/1061] Add specialization for `deque1.prepend(deque2.drain(range))` This is used when moving elements between `VecDeque`s This pattern is also used in examples of `VecDeque::prepend`. (see its docs) --- .../alloc/src/collections/vec_deque/drain.rs | 6 +- .../src/collections/vec_deque/spec_extend.rs | 78 +++++++++++-- library/alloctests/tests/vec_deque.rs | 110 ++++++++++++++++++ 3 files changed, 180 insertions(+), 14 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/drain.rs b/library/alloc/src/collections/vec_deque/drain.rs index eee7be674c95..a43853604a2d 100644 --- a/library/alloc/src/collections/vec_deque/drain.rs +++ b/library/alloc/src/collections/vec_deque/drain.rs @@ -25,10 +25,10 @@ pub struct Drain< // drain_start is stored in deque.len pub(super) drain_len: usize, // index into the logical array, not the physical one (always lies in [0..deque.len)) - idx: usize, + pub(super) idx: usize, // number of elements after the drained range pub(super) tail_len: usize, - remaining: usize, + pub(super) remaining: usize, // Needed to make Drain covariant over T _marker: PhantomData<&'a T>, } @@ -53,7 +53,7 @@ impl<'a, T, A: Allocator> Drain<'a, T, A> { // Only returns pointers to the slices, as that's all we need // to drop them. May only be called if `self.remaining != 0`. - unsafe fn as_slices(&self) -> (*mut [T], *mut [T]) { + pub(super) unsafe fn as_slices(&self) -> (*mut [T], *mut [T]) { unsafe { let deque = self.deque.as_ref(); diff --git a/library/alloc/src/collections/vec_deque/spec_extend.rs b/library/alloc/src/collections/vec_deque/spec_extend.rs index f73ba795cbea..4ef854e8b327 100644 --- a/library/alloc/src/collections/vec_deque/spec_extend.rs +++ b/library/alloc/src/collections/vec_deque/spec_extend.rs @@ -1,7 +1,7 @@ use core::iter::{Copied, Rev, TrustedLen}; use core::slice; -use super::VecDeque; +use super::{Drain, VecDeque}; use crate::alloc::Allocator; #[cfg(not(test))] use crate::vec; @@ -157,7 +157,8 @@ impl SpecExtendFront> for VecDeque { #[track_caller] fn spec_extend_front(&mut self, mut iterator: vec::IntoIter) { let slice = iterator.as_slice(); - // SAFETY: elements in the slice are forgotten after this call + self.reserve(slice.len()); + // SAFETY: `slice.len()` space was just reserved and elements in the slice are forgotten after this call unsafe { prepend_reversed(self, slice) }; iterator.forget_remaining_elements(); } @@ -169,7 +170,8 @@ impl SpecExtendFront>> for VecDeque>) { let mut iterator = iterator.into_inner(); let slice = iterator.as_slice(); - // SAFETY: elements in the slice are forgotten after this call + self.reserve(slice.len()); + // SAFETY: `slice.len()` space was just reserved and elements in the slice are forgotten after this call unsafe { prepend(self, slice) }; iterator.forget_remaining_elements(); } @@ -182,7 +184,8 @@ where #[track_caller] fn spec_extend_front(&mut self, iter: Copied>) { let slice = iter.into_inner().as_slice(); - // SAFETY: T is Copy because Copied> is Iterator + self.reserve(slice.len()); + // SAFETY: `slice.len()` space was just reserved and T is Copy because Copied> is Iterator unsafe { prepend_reversed(self, slice) }; } } @@ -194,17 +197,69 @@ where #[track_caller] fn spec_extend_front(&mut self, iter: Rev>>) { let slice = iter.into_inner().into_inner().as_slice(); - // SAFETY: T is Copy because Rev>> is Iterator + self.reserve(slice.len()); + // SAFETY: `slice.len()` space was just reserved and T is Copy because Rev>> is Iterator unsafe { prepend(self, slice) }; } } +impl<'a, T, A1: Allocator, A2: Allocator> SpecExtendFront> for VecDeque { + #[track_caller] + fn spec_extend_front(&mut self, mut iter: Drain<'a, T, A2>) { + if iter.remaining == 0 { + return; + } + + self.reserve(iter.remaining); + unsafe { + // SAFETY: iter.remaining != 0. + let (left, right) = iter.as_slices(); + // SAFETY: + // - `iter.remaining` space was reserved, `iter.remaining == left.len() + right.len()`. + // - The elements in `left` and `right` are forgotten after these calls. + prepend_reversed(self, &*left); + prepend_reversed(self, &*right); + } + + iter.idx += iter.remaining; + iter.remaining = 0; + } +} + +impl<'a, T, A1: Allocator, A2: Allocator> SpecExtendFront>> + for VecDeque +{ + #[track_caller] + fn spec_extend_front(&mut self, iter: Rev>) { + let mut iter = iter.into_inner(); + + if iter.remaining == 0 { + return; + } + + self.reserve(iter.remaining); + unsafe { + // SAFETY: iter.remaining != 0. + let (left, right) = iter.as_slices(); + // SAFETY: + // - `iter.remaining` space was reserved, `iter.remaining == left.len() + right.len()`. + // - The elements in `left` and `right` are forgotten after these calls. + prepend(self, &*right); + prepend(self, &*left); + } + + iter.idx += iter.remaining; + iter.remaining = 0; + } +} + +/// Prepends elements of `slice` to `deque` using a copy. +/// /// # Safety /// -/// Elements of `slice` will be copied into the deque, make sure to forget the items if `T` is not `Copy`. +/// - `deque` must have space for `slice.len()` new elements. +/// - Elements of `slice` will be copied into the deque, make sure to forget the elements if `T` is not `Copy`. unsafe fn prepend(deque: &mut VecDeque, slice: &[T]) { - deque.reserve(slice.len()); - unsafe { deque.head = deque.wrap_sub(deque.head, slice.len()); deque.copy_slice(deque.head, slice); @@ -212,12 +267,13 @@ unsafe fn prepend(deque: &mut VecDeque, slice: &[T]) { } } +/// Prepends elements of `slice` to `deque` in reverse order using a copy. +/// /// # Safety /// -/// Elements of `slice` will be copied into the deque, make sure to forget the items if `T` is not `Copy`. +/// - `deque` must have space for `slice.len()` new elements. +/// - Elements of `slice` will be copied into the deque, make sure to forget the elements if `T` is not `Copy`. unsafe fn prepend_reversed(deque: &mut VecDeque, slice: &[T]) { - deque.reserve(slice.len()); - unsafe { deque.head = deque.wrap_sub(deque.head, slice.len()); deque.copy_slice_reversed(deque.head, slice); diff --git a/library/alloctests/tests/vec_deque.rs b/library/alloctests/tests/vec_deque.rs index 82803c7a0dab..e9f860f8df9b 100644 --- a/library/alloctests/tests/vec_deque.rs +++ b/library/alloctests/tests/vec_deque.rs @@ -2156,6 +2156,116 @@ fn test_extend_front_specialization_copy_slice() { assert_eq!(v.as_slices(), ([5].as_slice(), [4, 3, 2].as_slice())); } +#[test] +fn test_extend_front_specialization_deque_drain() { + // trigger 8 code paths: all combinations of prepend and extend_front, wrap and no wrap (src deque), wrap and no wrap (dst deque) + + /// Get deque containing `[1, 2, 3, 4]`, possibly wrapping in the middle (between the 2 and 3). + fn test_deque(wrap: bool) -> VecDeque { + if wrap { + let mut v = VecDeque::with_capacity(4); + v.extend([3, 4]); + v.prepend([1, 2]); + assert_eq!(v.as_slices(), ([1, 2].as_slice(), [3, 4].as_slice())); + v + } else { + VecDeque::from([1, 2, 3, 4]) + } + } + + // prepend, v2.head == 0 + + let mut v1 = VecDeque::with_capacity(7); + + let mut v2 = test_deque(false); + v1.prepend(v2.drain(..)); + // drain removes all elements but keeps the buffer + assert_eq!(v2, []); + assert!(v2.capacity() >= 4); + + assert_eq!(v1, [1, 2, 3, 4]); + v1.pop_back(); + + let mut v2 = test_deque(false); + // this should wrap around the physical buffer + v1.prepend(v2.drain(..)); + // drain removes all elements but keeps the buffer + assert_eq!(v2, []); + assert!(v2.capacity() >= 4); + + // check it really wrapped + assert_eq!(v1.as_slices(), ([1].as_slice(), [2, 3, 4, 1, 2, 3].as_slice())); + + // extend_front, v2.head == 0 + + let mut v1 = VecDeque::with_capacity(7); + + let mut v2 = test_deque(false); + v1.extend_front(v2.drain(..)); + // drain removes all elements but keeps the buffer + assert_eq!(v2, []); + assert!(v2.capacity() >= 4); + + assert_eq!(v1, [4, 3, 2, 1]); + v1.pop_back(); + + let mut v2 = test_deque(false); + // this should wrap around the physical buffer + v1.extend_front(v2.drain(..)); + // drain removes all elements but keeps the buffer + assert_eq!(v2, []); + assert!(v2.capacity() >= 4); + + // check it really wrapped + assert_eq!(v1.as_slices(), ([4].as_slice(), [3, 2, 1, 4, 3, 2].as_slice())); + + // prepend, v2.head != 0 + + let mut v1 = VecDeque::with_capacity(7); + + let mut v2 = test_deque(true); + v1.prepend(v2.drain(..)); + // drain removes all elements but keeps the buffer + assert_eq!(v2, []); + assert!(v2.capacity() >= 4); + + assert_eq!(v1, [1, 2, 3, 4]); + v1.pop_back(); + + let mut v2 = test_deque(true); + // this should wrap around the physical buffer + v1.prepend(v2.drain(..)); + // drain removes all elements but keeps the buffer + assert_eq!(v2, []); + assert!(v2.capacity() >= 4); + + // check it really wrapped + assert_eq!(v1.as_slices(), ([1].as_slice(), [2, 3, 4, 1, 2, 3].as_slice())); + + // extend_front, v2.head != 0 + + let mut v1 = VecDeque::with_capacity(7); + + let mut v2 = test_deque(true); + v1.extend_front(v2.drain(..)); + // drain removes all elements but keeps the buffer + assert_eq!(v2, []); + assert!(v2.capacity() >= 4); + + assert_eq!(v1, [4, 3, 2, 1]); + v1.pop_back(); + + let mut v2 = test_deque(true); + // this should wrap around the physical buffer + v1.extend_front(v2.drain(..)); + // drain removes all elements but keeps the buffer + assert_eq!(v2, []); + assert!(v2.capacity() >= 4); + + // check it really wrapped + assert_eq!(v1.as_slices(), ([4].as_slice(), [3, 2, 1, 4, 3, 2].as_slice())); +} + #[test] fn test_splice() { let mut v = VecDeque::from(vec![1, 2, 3, 4, 5]); From 9a170fedd792b3373ddf7b512cff0b1463ee30e0 Mon Sep 17 00:00:00 2001 From: Antoni Spaanderman <56turtle56@gmail.com> Date: Fri, 2 Jan 2026 16:15:40 +0100 Subject: [PATCH 0188/1061] make specialization of Vec::extend and VecDeque::extend_front work for vec::IntoIter with any Allocator, not just Global --- .../alloc/src/collections/vec_deque/spec_extend.rs | 14 ++++++++------ library/alloc/src/vec/spec_extend.rs | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/spec_extend.rs b/library/alloc/src/collections/vec_deque/spec_extend.rs index f73ba795cbea..b65e229361f2 100644 --- a/library/alloc/src/collections/vec_deque/spec_extend.rs +++ b/library/alloc/src/collections/vec_deque/spec_extend.rs @@ -77,8 +77,8 @@ where } #[cfg(not(test))] -impl SpecExtend> for VecDeque { - fn spec_extend(&mut self, mut iterator: vec::IntoIter) { +impl SpecExtend> for VecDeque { + fn spec_extend(&mut self, mut iterator: vec::IntoIter) { let slice = iterator.as_slice(); self.reserve(slice.len()); @@ -153,9 +153,9 @@ where } #[cfg(not(test))] -impl SpecExtendFront> for VecDeque { +impl SpecExtendFront> for VecDeque { #[track_caller] - fn spec_extend_front(&mut self, mut iterator: vec::IntoIter) { + fn spec_extend_front(&mut self, mut iterator: vec::IntoIter) { let slice = iterator.as_slice(); // SAFETY: elements in the slice are forgotten after this call unsafe { prepend_reversed(self, slice) }; @@ -164,9 +164,11 @@ impl SpecExtendFront> for VecDeque { } #[cfg(not(test))] -impl SpecExtendFront>> for VecDeque { +impl SpecExtendFront>> + for VecDeque +{ #[track_caller] - fn spec_extend_front(&mut self, iterator: Rev>) { + fn spec_extend_front(&mut self, iterator: Rev>) { let mut iterator = iterator.into_inner(); let slice = iterator.as_slice(); // SAFETY: elements in the slice are forgotten after this call diff --git a/library/alloc/src/vec/spec_extend.rs b/library/alloc/src/vec/spec_extend.rs index f5bcd3ec9d82..7c908841c90e 100644 --- a/library/alloc/src/vec/spec_extend.rs +++ b/library/alloc/src/vec/spec_extend.rs @@ -28,8 +28,8 @@ where } } -impl SpecExtend> for Vec { - fn spec_extend(&mut self, mut iterator: IntoIter) { +impl SpecExtend> for Vec { + fn spec_extend(&mut self, mut iterator: IntoIter) { unsafe { self.append_elements(iterator.as_slice() as _); } From c7bb49458f284421012f7e4c575d2747b19075d9 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 2 Jan 2026 23:13:52 +0900 Subject: [PATCH 0189/1061] Add tracking issue for sized_hierarchy --- compiler/rustc_feature/src/unstable.rs | 4 ++-- library/core/src/marker.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index ca2ce2f18812..94e861787fc6 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -247,8 +247,6 @@ declare_features! ( (internal, profiler_runtime, "1.18.0", None), /// Allows using `rustc_*` attributes (RFC 572). (internal, rustc_attrs, "1.0.0", None), - /// Introduces a hierarchy of `Sized` traits (RFC 3729). - (unstable, sized_hierarchy, "1.89.0", None), /// Allows using the `#[stable]` and `#[unstable]` attributes. (internal, staged_api, "1.0.0", None), /// Added for testing unstable lints; perma-unstable. @@ -305,6 +303,8 @@ declare_features! ( (internal, rustdoc_internals, "1.58.0", Some(90418)), /// Allows using the `rustdoc::missing_doc_code_examples` lint (unstable, rustdoc_missing_doc_code_examples, "1.31.0", Some(101730)), + /// Introduces a hierarchy of `Sized` traits (RFC 3729). + (unstable, sized_hierarchy, "1.89.0", Some(144404)), /// Allows using `#[structural_match]` which indicates that a type is structurally matchable. /// FIXME: Subsumed by trait `StructuralPartialEq`, cannot move to removed until a library /// feature with the same name exists. diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 68f22767d6cf..5ecc2a63ea83 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -163,7 +163,7 @@ pub trait Sized: MetaSized { } /// Types with a size that can be determined from pointer metadata. -#[unstable(feature = "sized_hierarchy", issue = "none")] +#[unstable(feature = "sized_hierarchy", issue = "144404")] #[lang = "meta_sized"] #[diagnostic::on_unimplemented( message = "the size for values of type `{Self}` cannot be known", @@ -181,7 +181,7 @@ pub trait MetaSized: PointeeSized { } /// Types that may or may not have a size. -#[unstable(feature = "sized_hierarchy", issue = "none")] +#[unstable(feature = "sized_hierarchy", issue = "144404")] #[lang = "pointee_sized"] #[diagnostic::on_unimplemented( message = "values of type `{Self}` may or may not have a size", From da1ffbe181973aa47e384949a4498dd7fbd30721 Mon Sep 17 00:00:00 2001 From: alhubanov Date: Fri, 2 Jan 2026 18:02:52 +0200 Subject: [PATCH 0190/1061] fix: restrict match_bool to 2 arms --- clippy_lints/src/matches/match_bool.rs | 95 +++++++++++++------------- 1 file changed, 47 insertions(+), 48 deletions(-) diff --git a/clippy_lints/src/matches/match_bool.rs b/clippy_lints/src/matches/match_bool.rs index a2c8741f4f74..dc3457aa7a46 100644 --- a/clippy_lints/src/matches/match_bool.rs +++ b/clippy_lints/src/matches/match_bool.rs @@ -16,6 +16,7 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>] && arms .iter() .all(|arm| arm.pat.walk_short(|p| !matches!(p.kind, PatKind::Binding(..)))) + && arms.len() == 2 { span_lint_and_then( cx, @@ -23,59 +24,57 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>] expr.span, "`match` on a boolean expression", move |diag| { - if arms.len() == 2 { - let mut app = Applicability::MachineApplicable; - let test_sugg = if let PatKind::Expr(arm_bool) = arms[0].pat.kind { - let test = Sugg::hir_with_applicability(cx, scrutinee, "_", &mut app); - if let PatExprKind::Lit { lit, .. } = arm_bool.kind { - match &lit.node { - LitKind::Bool(true) => Some(test), - LitKind::Bool(false) => Some(!test), - _ => None, - } - .map(|test| { - if let Some(guard) = &arms[0] - .guard - .map(|g| Sugg::hir_with_applicability(cx, g, "_", &mut app)) - { - test.and(guard) - } else { - test - } - }) - } else { - None + let mut app = Applicability::MachineApplicable; + let test_sugg = if let PatKind::Expr(arm_bool) = arms[0].pat.kind { + let test = Sugg::hir_with_applicability(cx, scrutinee, "_", &mut app); + if let PatExprKind::Lit { lit, .. } = arm_bool.kind { + match &lit.node { + LitKind::Bool(true) => Some(test), + LitKind::Bool(false) => Some(!test), + _ => None, } + .map(|test| { + if let Some(guard) = &arms[0] + .guard + .map(|g| Sugg::hir_with_applicability(cx, g, "_", &mut app)) + { + test.and(guard) + } else { + test + } + }) } else { None + } + } else { + None + }; + + if let Some(test_sugg) = test_sugg { + let ctxt = expr.span.ctxt(); + let (true_expr, false_expr) = (arms[0].body, arms[1].body); + let sugg = match (is_unit_expr(true_expr), is_unit_expr(false_expr)) { + (false, false) => Some(format!( + "if {} {} else {}", + test_sugg, + expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app), + expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app) + )), + (false, true) => Some(format!( + "if {} {}", + test_sugg, + expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app) + )), + (true, false) => Some(format!( + "if {} {}", + !test_sugg, + expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app) + )), + (true, true) => None, }; - if let Some(test_sugg) = test_sugg { - let ctxt = expr.span.ctxt(); - let (true_expr, false_expr) = (arms[0].body, arms[1].body); - let sugg = match (is_unit_expr(true_expr), is_unit_expr(false_expr)) { - (false, false) => Some(format!( - "if {} {} else {}", - test_sugg, - expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app), - expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app) - )), - (false, true) => Some(format!( - "if {} {}", - test_sugg, - expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app) - )), - (true, false) => Some(format!( - "if {} {}", - !test_sugg, - expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app) - )), - (true, true) => None, - }; - - if let Some(sugg) = sugg { - diag.span_suggestion(expr.span, "consider using an `if`/`else` expression", sugg, app); - } + if let Some(sugg) = sugg { + diag.span_suggestion(expr.span, "consider using an `if`/`else` expression", sugg, app); } } }, From 4d2ce7d36b7c96f1778621a6b0865bcaa8872c54 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Jan 2026 18:09:01 +0100 Subject: [PATCH 0191/1061] use a single generic codepath for all return types --- src/tools/miri/src/shims/native_lib/ffi.rs | 32 ---- src/tools/miri/src/shims/native_lib/mod.rs | 157 +++++++----------- .../miri/src/shims/native_lib/trace/child.rs | 12 +- .../miri/src/shims/native_lib/trace/stub.rs | 10 +- .../tests/native-lib/aggregate_arguments.c | 8 + .../tests/native-lib/fail/invalid_retval.rs | 14 ++ .../native-lib/fail/invalid_retval.stderr | 13 ++ .../native-lib/pass/aggregate_arguments.rs | 18 ++ .../miri/tests/native-lib/scalar_arguments.c | 4 + 9 files changed, 131 insertions(+), 137 deletions(-) delete mode 100644 src/tools/miri/src/shims/native_lib/ffi.rs create mode 100644 src/tools/miri/tests/native-lib/fail/invalid_retval.rs create mode 100644 src/tools/miri/tests/native-lib/fail/invalid_retval.stderr diff --git a/src/tools/miri/src/shims/native_lib/ffi.rs b/src/tools/miri/src/shims/native_lib/ffi.rs deleted file mode 100644 index 196f43c6f6a6..000000000000 --- a/src/tools/miri/src/shims/native_lib/ffi.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! Support code for dealing with libffi. - -use libffi::low::CodePtr; -use libffi::middle::{Arg as ArgPtr, Cif, Type as FfiType}; - -/// Perform the actual FFI call. -/// -/// # Safety -/// -/// The safety invariants of the foreign function being called must be upheld (if any). -pub unsafe fn call(fun: CodePtr, args: &mut [OwnedArg]) -> R { - let cif = Cif::new(args.iter_mut().map(|arg| arg.ty.take().unwrap()), R::reify().into_middle()); - let arg_ptrs: Vec<_> = args.iter().map(|arg| ArgPtr::new(&*arg.bytes)).collect(); - // SAFETY: Caller upholds that the function is safe to call. - unsafe { cif.call(fun, &arg_ptrs) } -} - -/// An argument for an FFI call. -#[derive(Debug, Clone)] -pub struct OwnedArg { - /// The type descriptor for this argument. - ty: Option, - /// Corresponding bytes for the value. - bytes: Box<[u8]>, -} - -impl OwnedArg { - /// Instantiates an argument from a type descriptor and bytes. - pub fn new(ty: FfiType, bytes: Box<[u8]>) -> Self { - Self { ty: Some(ty), bytes } - } -} diff --git a/src/tools/miri/src/shims/native_lib/mod.rs b/src/tools/miri/src/shims/native_lib/mod.rs index c25c1841dd70..8a761855c432 100644 --- a/src/tools/miri/src/shims/native_lib/mod.rs +++ b/src/tools/miri/src/shims/native_lib/mod.rs @@ -11,14 +11,12 @@ use libffi::low::CodePtr; use libffi::middle::Type as FfiType; use rustc_abi::{HasDataLayout, Size}; use rustc_data_structures::either; -use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout}; -use rustc_middle::ty::{self, FloatTy, IntTy, Ty, UintTy}; +use rustc_middle::ty::layout::TyAndLayout; +use rustc_middle::ty::{self, Ty}; use rustc_span::Symbol; use serde::{Deserialize, Serialize}; -use self::helpers::ToSoft; - -mod ffi; +use crate::*; #[cfg_attr( not(all( @@ -30,8 +28,21 @@ mod ffi; )] pub mod trace; -use self::ffi::OwnedArg; -use crate::*; +/// An argument for an FFI call. +#[derive(Debug, Clone)] +pub struct OwnedArg { + /// The type descriptor for this argument. + ty: Option, + /// Corresponding bytes for the value. + bytes: Box<[u8]>, +} + +impl OwnedArg { + /// Instantiates an argument from a type descriptor and bytes. + pub fn new(ty: FfiType, bytes: Box<[u8]>) -> Self { + Self { ty: Some(ty), bytes } + } +} /// The final results of an FFI trace, containing every relevant event detected /// by the tracer. @@ -80,14 +91,14 @@ impl AccessRange { impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {} trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { - /// Call native host function and return the output as an immediate. - fn call_native_with_args( + /// Call native host function and return the output and the memory accesses + /// that occurred during the call. + fn call_native_raw( &mut self, - link_name: Symbol, - dest: &MPlaceTy<'tcx>, fun: CodePtr, - libffi_args: &mut [OwnedArg], - ) -> InterpResult<'tcx, (crate::ImmTy<'tcx>, Option)> { + args: &mut [OwnedArg], + ret: (FfiType, Size), + ) -> InterpResult<'tcx, (Box<[u8]>, Option)> { let this = self.eval_context_mut(); #[cfg(target_os = "linux")] let alloc = this.machine.allocator.as_ref().unwrap().clone(); @@ -99,81 +110,14 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.machine.native_lib_ecx_interchange.set(ptr::from_mut(this).expose_provenance()); let res = trace::Supervisor::do_ffi(&alloc, || { - // Call the function (`ptr`) with arguments `libffi_args`, and obtain the return value - // as the specified primitive integer type - let scalar = match dest.layout.ty.kind() { - // ints - ty::Int(IntTy::I8) => { - // Unsafe because of the call to native code. - // Because this is calling a C function it is not necessarily sound, - // but there is no way around this and we've checked as much as we can. - let x = unsafe { ffi::call::(fun, libffi_args) }; - Scalar::from_i8(x) - } - ty::Int(IntTy::I16) => { - let x = unsafe { ffi::call::(fun, libffi_args) }; - Scalar::from_i16(x) - } - ty::Int(IntTy::I32) => { - let x = unsafe { ffi::call::(fun, libffi_args) }; - Scalar::from_i32(x) - } - ty::Int(IntTy::I64) => { - let x = unsafe { ffi::call::(fun, libffi_args) }; - Scalar::from_i64(x) - } - ty::Int(IntTy::Isize) => { - let x = unsafe { ffi::call::(fun, libffi_args) }; - Scalar::from_target_isize(x.try_into().unwrap(), this) - } - // uints - ty::Uint(UintTy::U8) => { - let x = unsafe { ffi::call::(fun, libffi_args) }; - Scalar::from_u8(x) - } - ty::Uint(UintTy::U16) => { - let x = unsafe { ffi::call::(fun, libffi_args) }; - Scalar::from_u16(x) - } - ty::Uint(UintTy::U32) => { - let x = unsafe { ffi::call::(fun, libffi_args) }; - Scalar::from_u32(x) - } - ty::Uint(UintTy::U64) => { - let x = unsafe { ffi::call::(fun, libffi_args) }; - Scalar::from_u64(x) - } - ty::Uint(UintTy::Usize) => { - let x = unsafe { ffi::call::(fun, libffi_args) }; - Scalar::from_target_usize(x.try_into().unwrap(), this) - } - ty::Float(FloatTy::F32) => { - let x = unsafe { ffi::call::(fun, libffi_args) }; - Scalar::from_f32(x.to_soft()) - } - ty::Float(FloatTy::F64) => { - let x = unsafe { ffi::call::(fun, libffi_args) }; - Scalar::from_f64(x.to_soft()) - } - // Functions with no declared return type (i.e., the default return) - // have the output_type `Tuple([])`. - ty::Tuple(t_list) if (*t_list).deref().is_empty() => { - unsafe { ffi::call::<()>(fun, libffi_args) }; - return interp_ok(ImmTy::uninit(dest.layout)); - } - ty::RawPtr(ty, ..) if ty.is_sized(*this.tcx, this.typing_env()) => { - let x = unsafe { ffi::call::<*const ()>(fun, libffi_args) }; - let ptr = StrictPointer::new(Provenance::Wildcard, Size::from_bytes(x.addr())); - Scalar::from_pointer(ptr, this) - } - _ => - return Err(err_unsup_format!( - "unsupported return type for native call: {:?}", - link_name - )) - .into(), - }; - interp_ok(ImmTy::from_scalar(scalar, dest.layout)) + use libffi::middle::{Arg, Cif, Ret}; + + let cif = Cif::new(args.iter_mut().map(|arg| arg.ty.take().unwrap()), ret.0); + let arg_ptrs: Vec<_> = args.iter().map(|arg| Arg::new(&*arg.bytes)).collect(); + let mut ret = vec![0u8; ret.1.bytes_usize()]; + + unsafe { cif.call_return_into(fun, &arg_ptrs, Ret::new::<[u8]>(&mut *ret)) }; + ret.into() }); this.machine.native_lib_ecx_interchange.set(0); @@ -392,6 +336,30 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(OwnedArg::new(ty, bytes)) } + fn ffi_ret_to_mem(&mut self, v: Box<[u8]>, dest: &MPlaceTy<'tcx>) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let len = v.len(); + this.write_bytes_ptr(dest.ptr(), v)?; + if len == 0 { + return interp_ok(()); + } + // We have no idea which provenance these bytes have, so we reset it to wildcard. + let tcx = this.tcx; + let (alloc_id, offset, _) = this.ptr_try_get_alloc_id(dest.ptr(), 0).unwrap(); + let alloc = this.get_alloc_raw_mut(alloc_id)?.0; + alloc.process_native_write(&tcx, Some(alloc_range(offset, dest.layout.size))); + // Run the validation that would usually be part of `return`, also to reset + // any provenance and padding that would not survive the return. + if MiriMachine::enforce_validity(this, dest.layout) { + this.validate_operand( + &dest.clone().into(), + MiriMachine::enforce_validity_recursively(this, dest.layout), + /*reset_provenance_and_padding*/ true, + )?; + } + interp_ok(()) + } + /// Parses an ADT to construct the matching libffi type. fn adt_to_ffitype( &self, @@ -399,6 +367,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { adt_def: ty::AdtDef<'tcx>, args: &'tcx ty::List>, ) -> InterpResult<'tcx, FfiType> { + let this = self.eval_context_ref(); // TODO: unions, etc. if !adt_def.is_struct() { throw_unsup_format!("passing an enum or union over FFI: {orig_ty}"); @@ -408,7 +377,6 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { throw_unsup_format!("passing a non-#[repr(C)] {} over FFI: {orig_ty}", adt_def.descr()) } - let this = self.eval_context_ref(); let mut fields = vec![]; for field in &adt_def.non_enum_variant().fields { let layout = this.layout_of(field.ty(*this.tcx, args))?; @@ -533,6 +501,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// a native form (through `libffi` call). /// Then, convert the return value from the native form into something that /// can be stored in Miri's internal memory. + /// + /// Returns `true` if a call has been made, `false` if no functions of this name was found. fn call_native_fn( &mut self, link_name: Symbol, @@ -554,6 +524,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { for arg in args.iter() { libffi_args.push(this.op_to_ffi_arg(arg, tracing)?); } + let ret_ty = this.ty_to_ffitype(dest.layout)?; // Prepare all exposed memory (both previously exposed, and just newly exposed since a // pointer was passed as argument). Uninitialised memory is left as-is, but any data @@ -596,15 +567,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(()) })?; - // Call the function and store output, depending on return type in the function signature. + // Call the function and store its output. let (ret, maybe_memevents) = - this.call_native_with_args(link_name, dest, code_ptr, &mut libffi_args)?; - + this.call_native_raw(code_ptr, &mut libffi_args, (ret_ty, dest.layout.size))?; if tracing { this.tracing_apply_accesses(maybe_memevents.unwrap())?; } - - this.write_immediate(*ret, dest)?; + this.ffi_ret_to_mem(ret, dest)?; interp_ok(true) } } diff --git a/src/tools/miri/src/shims/native_lib/trace/child.rs b/src/tools/miri/src/shims/native_lib/trace/child.rs index 795ad4a32076..021ec2e9aeb3 100644 --- a/src/tools/miri/src/shims/native_lib/trace/child.rs +++ b/src/tools/miri/src/shims/native_lib/trace/child.rs @@ -5,7 +5,7 @@ use std::rc::Rc; use ipc_channel::ipc; use nix::sys::{mman, ptrace, signal}; use nix::unistd; -use rustc_const_eval::interpret::InterpResult; +use rustc_const_eval::interpret::{InterpResult, interp_ok}; use super::CALLBACK_STACK_SIZE; use super::messages::{Confirmation, StartFfiInfo, TraceRequest}; @@ -58,16 +58,16 @@ impl Supervisor { /// Performs an arbitrary FFI call, enabling tracing from the supervisor. /// As this locks the supervisor via a mutex, no other threads may enter FFI /// until this function returns. - pub fn do_ffi<'tcx>( + pub fn do_ffi<'tcx, T>( alloc: &Rc>, - f: impl FnOnce() -> InterpResult<'tcx, crate::ImmTy<'tcx>>, - ) -> InterpResult<'tcx, (crate::ImmTy<'tcx>, Option)> { + f: impl FnOnce() -> T, + ) -> InterpResult<'tcx, (T, Option)> { let mut sv_guard = SUPERVISOR.lock().unwrap(); // If the supervisor is not initialised for whatever reason, fast-return. // As a side-effect, even on platforms where ptracing // is not implemented, we enforce that only one FFI call // happens at a time. - let Some(sv) = sv_guard.as_mut() else { return f().map(|v| (v, None)) }; + let Some(sv) = sv_guard.as_mut() else { return interp_ok((f(), None)) }; // Get pointers to all the pages the supervisor must allow accesses in // and prepare the callback stack. @@ -147,7 +147,7 @@ impl Supervisor { }) .ok(); - res.map(|v| (v, events)) + interp_ok((res, events)) } } diff --git a/src/tools/miri/src/shims/native_lib/trace/stub.rs b/src/tools/miri/src/shims/native_lib/trace/stub.rs index 22787a6f6fa7..a3f6c616301c 100644 --- a/src/tools/miri/src/shims/native_lib/trace/stub.rs +++ b/src/tools/miri/src/shims/native_lib/trace/stub.rs @@ -1,4 +1,4 @@ -use rustc_const_eval::interpret::InterpResult; +use rustc_const_eval::interpret::{InterpResult, interp_ok}; static SUPERVISOR: std::sync::Mutex<()> = std::sync::Mutex::new(()); @@ -13,13 +13,13 @@ impl Supervisor { false } - pub fn do_ffi<'tcx, T>( + pub fn do_ffi<'tcx, T, U>( _: T, - f: impl FnOnce() -> InterpResult<'tcx, crate::ImmTy<'tcx>>, - ) -> InterpResult<'tcx, (crate::ImmTy<'tcx>, Option)> { + f: impl FnOnce() -> U, + ) -> InterpResult<'tcx, (U, Option)> { // We acquire the lock to ensure that no two FFI calls run concurrently. let _g = SUPERVISOR.lock().unwrap(); - f().map(|v| (v, None)) + interp_ok((f(), None)) } } diff --git a/src/tools/miri/tests/native-lib/aggregate_arguments.c b/src/tools/miri/tests/native-lib/aggregate_arguments.c index 8ad687f2aec9..e315642c13a9 100644 --- a/src/tools/miri/tests/native-lib/aggregate_arguments.c +++ b/src/tools/miri/tests/native-lib/aggregate_arguments.c @@ -24,6 +24,14 @@ EXPORT int64_t pass_struct(const PassMe pass_me) { return pass_me.value + pass_me.other_value; } +/* Test: test_return_struct */ +EXPORT PassMe return_struct(int32_t value, int64_t other_value) { + struct PassMe ret; + ret.value = value; + ret.other_value = other_value; + return ret; +} + /* Test: test_pass_struct_complex */ typedef struct Part1 { diff --git a/src/tools/miri/tests/native-lib/fail/invalid_retval.rs b/src/tools/miri/tests/native-lib/fail/invalid_retval.rs new file mode 100644 index 000000000000..4967866b7e7f --- /dev/null +++ b/src/tools/miri/tests/native-lib/fail/invalid_retval.rs @@ -0,0 +1,14 @@ +// Only works on Unix targets +//@ignore-target: windows wasm +//@only-on-host +//@normalize-stderr-test: "OS `.*`" -> "$$OS" + +extern "C" { + fn u8_id(x: u8) -> bool; +} + +fn main() { + unsafe { + u8_id(2); //~ ERROR: invalid value: encountered 0x02, but expected a boolean + } +} diff --git a/src/tools/miri/tests/native-lib/fail/invalid_retval.stderr b/src/tools/miri/tests/native-lib/fail/invalid_retval.stderr new file mode 100644 index 000000000000..9db29822d4f5 --- /dev/null +++ b/src/tools/miri/tests/native-lib/fail/invalid_retval.stderr @@ -0,0 +1,13 @@ +error: Undefined Behavior: constructing invalid value: encountered 0x02, but expected a boolean + --> tests/native-lib/fail/invalid_retval.rs:LL:CC + | +LL | u8_id(2); + | ^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/native-lib/pass/aggregate_arguments.rs b/src/tools/miri/tests/native-lib/pass/aggregate_arguments.rs index 55acb240612f..730e9d89441a 100644 --- a/src/tools/miri/tests/native-lib/pass/aggregate_arguments.rs +++ b/src/tools/miri/tests/native-lib/pass/aggregate_arguments.rs @@ -1,6 +1,7 @@ fn main() { test_pass_struct(); test_pass_struct_complex(); + test_return_struct(); } /// Test passing a basic struct as an argument. @@ -20,6 +21,23 @@ fn test_pass_struct() { assert_eq!(unsafe { pass_struct(pass_me) }, 42 + 1337); } +fn test_return_struct() { + // Exactly two fields, so that we hit the ScalarPair case. + #[repr(C)] + struct PassMe { + value: i32, + other_value: i64, + } + + extern "C" { + fn return_struct(v: i32, ov: i64) -> PassMe; + } + + let pass_me = unsafe { return_struct(1, 2) }; + assert_eq!(pass_me.value, 1); + assert_eq!(pass_me.other_value, 2); +} + /// Test passing a more complex struct as an argument. fn test_pass_struct_complex() { #[repr(C)] diff --git a/src/tools/miri/tests/native-lib/scalar_arguments.c b/src/tools/miri/tests/native-lib/scalar_arguments.c index 10b6244bdeb4..720f1982178c 100644 --- a/src/tools/miri/tests/native-lib/scalar_arguments.c +++ b/src/tools/miri/tests/native-lib/scalar_arguments.c @@ -34,6 +34,10 @@ EXPORT float add_float(float x) { return x + 1.5f; } +EXPORT uint8_t u8_id(uint8_t x) { + return x; +} + // To test that functions not marked with EXPORT cannot be called by Miri. int32_t not_exported(void) { return 0; From ae09be596846d60d14f50399da91ffcb70bfd12e Mon Sep 17 00:00:00 2001 From: joboet Date: Fri, 12 Dec 2025 20:56:06 +0100 Subject: [PATCH 0192/1061] std: unify `sys::pal::common` and `sys_common` into `sys::helpers` --- library/std/src/lib.rs | 2 - library/std/src/sys/helpers/mod.rs | 38 ++++++++++++++++ .../{pal/common => helpers}/small_c_string.rs | 0 .../src/sys/{pal/common => helpers}/tests.rs | 8 +++- .../src/{sys_common => sys/helpers}/wstr.rs | 1 - library/std/src/sys/mod.rs | 1 + library/std/src/sys/pal/common/mod.rs | 16 ------- library/std/src/sys/pal/mod.rs | 2 - library/std/src/sys_common/mod.rs | 44 ------------------- library/std/src/sys_common/tests.rs | 6 --- 10 files changed, 46 insertions(+), 72 deletions(-) create mode 100644 library/std/src/sys/helpers/mod.rs rename library/std/src/sys/{pal/common => helpers}/small_c_string.rs (100%) rename library/std/src/sys/{pal/common => helpers}/tests.rs (89%) rename library/std/src/{sys_common => sys/helpers}/wstr.rs (98%) delete mode 100644 library/std/src/sys/pal/common/mod.rs delete mode 100644 library/std/src/sys_common/mod.rs delete mode 100644 library/std/src/sys_common/tests.rs diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 0dab29712f4f..f5b9f69a5f9f 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -681,9 +681,7 @@ pub mod arch { #[stable(feature = "simd_x86", since = "1.27.0")] pub use std_detect::is_x86_feature_detected; -// Platform-abstraction modules mod sys; -mod sys_common; pub mod alloc; diff --git a/library/std/src/sys/helpers/mod.rs b/library/std/src/sys/helpers/mod.rs new file mode 100644 index 000000000000..c29d9d2ce2d1 --- /dev/null +++ b/library/std/src/sys/helpers/mod.rs @@ -0,0 +1,38 @@ +//! Small helper functions used inside `sys`. +//! +//! If any of these have uses outside of `sys`, please move them to a different +//! module. + +#[cfg_attr(not(target_os = "linux"), allow(unused))] // Not used on all platforms. +mod small_c_string; +#[cfg_attr(not(target_os = "windows"), allow(unused))] // Not used on all platforms. +mod wstr; + +#[cfg(test)] +mod tests; + +#[cfg_attr(not(target_os = "linux"), allow(unused))] // Not used on all platforms. +pub use small_c_string::{run_path_with_cstr, run_with_cstr}; +#[cfg_attr(not(target_os = "windows"), allow(unused))] // Not used on all platforms. +pub use wstr::WStrUnits; + +// Computes (value*numerator)/denom without overflow, as long as both (numerator*denom) and the +// overall result fit into i64 (which is the case for our time conversions). +#[cfg_attr(not(target_os = "windows"), allow(unused))] // Not used on all platforms. +pub fn mul_div_u64(value: u64, numerator: u64, denom: u64) -> u64 { + let q = value / denom; + let r = value % denom; + // Decompose value as (value/denom*denom + value%denom), + // substitute into (value*numerator)/denom and simplify. + // r < denom, so (denom*numerator) is the upper bound of (r*numerator) + q * numerator + r * numerator / denom +} + +#[cfg_attr(not(target_os = "linux"), allow(unused))] // Not used on all platforms. +pub fn ignore_notfound(result: crate::io::Result) -> crate::io::Result<()> { + match result { + Err(err) if err.kind() == crate::io::ErrorKind::NotFound => Ok(()), + Ok(_) => Ok(()), + Err(err) => Err(err), + } +} diff --git a/library/std/src/sys/pal/common/small_c_string.rs b/library/std/src/sys/helpers/small_c_string.rs similarity index 100% rename from library/std/src/sys/pal/common/small_c_string.rs rename to library/std/src/sys/helpers/small_c_string.rs diff --git a/library/std/src/sys/pal/common/tests.rs b/library/std/src/sys/helpers/tests.rs similarity index 89% rename from library/std/src/sys/pal/common/tests.rs rename to library/std/src/sys/helpers/tests.rs index b7698907070c..b67fdb9408d6 100644 --- a/library/std/src/sys/pal/common/tests.rs +++ b/library/std/src/sys/helpers/tests.rs @@ -1,9 +1,10 @@ use core::iter::repeat; +use super::mul_div_u64; +use super::small_c_string::run_path_with_cstr; use crate::ffi::CString; use crate::hint::black_box; use crate::path::Path; -use crate::sys::common::small_c_string::run_path_with_cstr; #[test] fn stack_allocation_works() { @@ -65,3 +66,8 @@ fn bench_heap_path_alloc(b: &mut test::Bencher) { .unwrap(); }); } + +#[test] +fn test_muldiv() { + assert_eq!(mul_div_u64(1_000_000_000_001, 1_000_000_000, 1_000_000), 1_000_000_000_001_000); +} diff --git a/library/std/src/sys_common/wstr.rs b/library/std/src/sys/helpers/wstr.rs similarity index 98% rename from library/std/src/sys_common/wstr.rs rename to library/std/src/sys/helpers/wstr.rs index f9a171fb7d8f..9c4b8e09e463 100644 --- a/library/std/src/sys_common/wstr.rs +++ b/library/std/src/sys/helpers/wstr.rs @@ -1,5 +1,4 @@ //! This module contains constructs to work with 16-bit characters (UCS-2 or UTF-16) -#![allow(dead_code)] use crate::marker::PhantomData; use crate::num::NonZero; diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index 0c72f6a57fe8..bfdbc6ee5d1e 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -11,6 +11,7 @@ mod configure_builtins; mod pal; mod alloc; +mod helpers; mod personality; pub mod args; diff --git a/library/std/src/sys/pal/common/mod.rs b/library/std/src/sys/pal/common/mod.rs deleted file mode 100644 index 9af4dee401cf..000000000000 --- a/library/std/src/sys/pal/common/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -// This module contains code that is shared between all platforms, mostly utility or fallback code. -// This explicitly does not include code that is shared between only a few platforms, -// such as when reusing an implementation from `unix` or `unsupported`. -// In those cases the desired code should be included directly using the #[path] attribute, -// not moved to this module. -// -// Currently `sys_common` contains a lot of code that should live in this module, -// ideally `sys_common` would only contain platform-independent abstractions on top of `sys`. -// Progress on this is tracked in #84187. - -#![allow(dead_code)] - -pub mod small_c_string; - -#[cfg(test)] -mod tests; diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs index 93ad4536e18f..c039c2894877 100644 --- a/library/std/src/sys/pal/mod.rs +++ b/library/std/src/sys/pal/mod.rs @@ -22,8 +22,6 @@ #![allow(missing_debug_implementations)] -pub mod common; - cfg_select! { unix => { mod unix; diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs deleted file mode 100644 index 015042440b5a..000000000000 --- a/library/std/src/sys_common/mod.rs +++ /dev/null @@ -1,44 +0,0 @@ -//! Platform-independent platform abstraction -//! -//! This is the platform-independent portion of the standard library's -//! platform abstraction layer, whereas `std::sys` is the -//! platform-specific portion. -//! -//! The relationship between `std::sys_common`, `std::sys` and the -//! rest of `std` is complex, with dependencies going in all -//! directions: `std` depending on `sys_common`, `sys_common` -//! depending on `sys`, and `sys` depending on `sys_common` and `std`. -//! This is because `sys_common` not only contains platform-independent code, -//! but also code that is shared between the different platforms in `sys`. -//! Ideally all that shared code should be moved to `sys::common`, -//! and the dependencies between `std`, `sys_common` and `sys` all would form a DAG. -//! Progress on this is tracked in #84187. - -#![allow(missing_docs)] - -#[cfg(test)] -mod tests; - -pub mod wstr; - -// common error constructors - -// Computes (value*numerator)/denom without overflow, as long as both (numerator*denom) and the -// overall result fit into i64 (which is the case for our time conversions). -#[allow(dead_code)] // not used on all platforms -pub fn mul_div_u64(value: u64, numerator: u64, denom: u64) -> u64 { - let q = value / denom; - let r = value % denom; - // Decompose value as (value/denom*denom + value%denom), - // substitute into (value*numerator)/denom and simplify. - // r < denom, so (denom*numerator) is the upper bound of (r*numerator) - q * numerator + r * numerator / denom -} - -pub fn ignore_notfound(result: crate::io::Result) -> crate::io::Result<()> { - match result { - Err(err) if err.kind() == crate::io::ErrorKind::NotFound => Ok(()), - Ok(_) => Ok(()), - Err(err) => Err(err), - } -} diff --git a/library/std/src/sys_common/tests.rs b/library/std/src/sys_common/tests.rs deleted file mode 100644 index 1b6446db52d4..000000000000 --- a/library/std/src/sys_common/tests.rs +++ /dev/null @@ -1,6 +0,0 @@ -use super::mul_div_u64; - -#[test] -fn test_muldiv() { - assert_eq!(mul_div_u64(1_000_000_000_001, 1_000_000_000, 1_000_000), 1_000_000_000_001_000); -} From f4fe287d877d372c948730ad6720e74d818a2292 Mon Sep 17 00:00:00 2001 From: joboet Date: Fri, 12 Dec 2025 21:09:11 +0100 Subject: [PATCH 0193/1061] std: update imports of `sys::helpers` --- library/std/src/sys/args/windows.rs | 2 +- library/std/src/sys/env/solid.rs | 2 +- library/std/src/sys/env/uefi.rs | 2 +- library/std/src/sys/env/unix.rs | 2 +- library/std/src/sys/env/wasi.rs | 2 +- library/std/src/sys/fs/common.rs | 2 +- library/std/src/sys/fs/hermit.rs | 2 +- library/std/src/sys/fs/mod.rs | 2 +- library/std/src/sys/fs/solid.rs | 2 +- library/std/src/sys/fs/uefi.rs | 4 ++-- library/std/src/sys/fs/unix.rs | 5 ++--- library/std/src/sys/fs/vexos.rs | 2 +- library/std/src/sys/net/connection/socket/mod.rs | 2 +- library/std/src/sys/net/connection/uefi/tcp.rs | 2 +- library/std/src/sys/pal/uefi/helpers.rs | 2 +- library/std/src/sys/pal/uefi/time.rs | 2 +- library/std/src/sys/pal/unix/os.rs | 2 +- library/std/src/sys/pal/wasi/os.rs | 2 +- library/std/src/sys/pal/windows/time.rs | 2 +- library/std/src/sys/path/cygwin.rs | 2 +- library/std/src/sys/path/uefi.rs | 3 ++- .../std/src/sys/platform_version/darwin/core_foundation.rs | 2 +- library/std/src/sys/process/uefi.rs | 2 +- 23 files changed, 26 insertions(+), 26 deletions(-) diff --git a/library/std/src/sys/args/windows.rs b/library/std/src/sys/args/windows.rs index b4de759e1a4c..c1988657ff1b 100644 --- a/library/std/src/sys/args/windows.rs +++ b/library/std/src/sys/args/windows.rs @@ -11,11 +11,11 @@ use crate::ffi::{OsStr, OsString}; use crate::num::NonZero; use crate::os::windows::prelude::*; use crate::path::{Path, PathBuf}; +use crate::sys::helpers::WStrUnits; use crate::sys::pal::os::current_exe; use crate::sys::pal::{ensure_no_nuls, fill_utf16_buf}; use crate::sys::path::get_long_path; use crate::sys::{AsInner, c, to_u16s}; -use crate::sys_common::wstr::WStrUnits; use crate::{io, iter, ptr}; pub fn args() -> Args { diff --git a/library/std/src/sys/env/solid.rs b/library/std/src/sys/env/solid.rs index ea77fc3c1193..0ce5a22b4256 100644 --- a/library/std/src/sys/env/solid.rs +++ b/library/std/src/sys/env/solid.rs @@ -6,7 +6,7 @@ use crate::io; use crate::os::raw::{c_char, c_int}; use crate::os::solid::ffi::{OsStrExt, OsStringExt}; use crate::sync::{PoisonError, RwLock}; -use crate::sys::common::small_c_string::run_with_cstr; +use crate::sys::helpers::run_with_cstr; static ENV_LOCK: RwLock<()> = RwLock::new(()); diff --git a/library/std/src/sys/env/uefi.rs b/library/std/src/sys/env/uefi.rs index 1561df41cac3..5fe29a47a2ea 100644 --- a/library/std/src/sys/env/uefi.rs +++ b/library/std/src/sys/env/uefi.rs @@ -24,7 +24,7 @@ mod uefi_env { use crate::io; use crate::os::uefi::ffi::OsStringExt; use crate::ptr::NonNull; - use crate::sys::{helpers, unsupported_err}; + use crate::sys::pal::{helpers, unsupported_err}; pub(crate) fn get(key: &OsStr) -> Option { let shell = helpers::open_shell()?; diff --git a/library/std/src/sys/env/unix.rs b/library/std/src/sys/env/unix.rs index 78c7af65f9e3..66805ce3fa71 100644 --- a/library/std/src/sys/env/unix.rs +++ b/library/std/src/sys/env/unix.rs @@ -7,8 +7,8 @@ use crate::ffi::{CStr, OsStr, OsString}; use crate::io; use crate::os::unix::prelude::*; use crate::sync::{PoisonError, RwLock}; -use crate::sys::common::small_c_string::run_with_cstr; use crate::sys::cvt; +use crate::sys::helpers::run_with_cstr; // Use `_NSGetEnviron` on Apple platforms. // diff --git a/library/std/src/sys/env/wasi.rs b/library/std/src/sys/env/wasi.rs index 1327cbc3263b..c970aac18260 100644 --- a/library/std/src/sys/env/wasi.rs +++ b/library/std/src/sys/env/wasi.rs @@ -4,7 +4,7 @@ pub use super::common::Env; use crate::ffi::{CStr, OsStr, OsString}; use crate::io; use crate::os::wasi::prelude::*; -use crate::sys::common::small_c_string::run_with_cstr; +use crate::sys::helpers::run_with_cstr; use crate::sys::pal::os::{cvt, libc}; cfg_select! { diff --git a/library/std/src/sys/fs/common.rs b/library/std/src/sys/fs/common.rs index bfd684d295b8..fbd075d57d61 100644 --- a/library/std/src/sys/fs/common.rs +++ b/library/std/src/sys/fs/common.rs @@ -3,7 +3,7 @@ use crate::fs; use crate::io::{self, Error, ErrorKind}; use crate::path::Path; -use crate::sys_common::ignore_notfound; +use crate::sys::helpers::ignore_notfound; pub(crate) const NOT_FILE_ERROR: Error = io::const_error!( ErrorKind::InvalidInput, diff --git a/library/std/src/sys/fs/hermit.rs b/library/std/src/sys/fs/hermit.rs index 0914e4b6c907..bb0c44d7e9a1 100644 --- a/library/std/src/sys/fs/hermit.rs +++ b/library/std/src/sys/fs/hermit.rs @@ -9,9 +9,9 @@ use crate::os::hermit::hermit_abi::{ use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::path::{Path, PathBuf}; use crate::sync::Arc; -use crate::sys::common::small_c_string::run_path_with_cstr; use crate::sys::fd::FileDesc; pub use crate::sys::fs::common::{copy, exists}; +use crate::sys::helpers::run_path_with_cstr; use crate::sys::time::SystemTime; use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner, cvt, unsupported, unsupported_err}; use crate::{fmt, mem}; diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index 4a66227ce5f4..fa046cb8e7da 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -17,7 +17,7 @@ cfg_select! { pub(crate) use unix::debug_assert_fd_is_open; #[cfg(any(target_os = "linux", target_os = "android"))] pub(super) use unix::CachedFileMetadata; - use crate::sys::common::small_c_string::run_path_with_cstr as with_native_path; + use crate::sys::helpers::run_path_with_cstr as with_native_path; } target_os = "windows" => { mod windows; diff --git a/library/std/src/sys/fs/solid.rs b/library/std/src/sys/fs/solid.rs index f6d5d3b784d3..b6d41cc4bc84 100644 --- a/library/std/src/sys/fs/solid.rs +++ b/library/std/src/sys/fs/solid.rs @@ -10,10 +10,10 @@ use crate::os::solid::ffi::OsStrExt; use crate::path::{Path, PathBuf}; use crate::sync::Arc; pub use crate::sys::fs::common::exists; +use crate::sys::helpers::ignore_notfound; use crate::sys::pal::{abi, error}; use crate::sys::time::SystemTime; use crate::sys::{unsupported, unsupported_err}; -use crate::sys_common::ignore_notfound; type CIntNotMinusOne = core::num::niche_types::NotAllOnes; diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index 8339d835dd1c..f5530962c570 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -6,8 +6,8 @@ use crate::fs::TryLockError; use crate::hash::Hash; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::path::{Path, PathBuf}; +use crate::sys::pal::{helpers, unsupported}; use crate::sys::time::SystemTime; -use crate::sys::{helpers, unsupported}; const FILE_PERMISSIONS_MASK: u64 = r_efi::protocols::file::READ_ONLY; @@ -497,7 +497,7 @@ mod uefi_fs { use crate::os::uefi::ffi::OsStringExt; use crate::path::Path; use crate::ptr::NonNull; - use crate::sys::helpers::{self, UefiBox}; + use crate::sys::pal::helpers::{self, UefiBox}; use crate::sys::time::{self, SystemTime}; pub(crate) struct File { diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 7ac09cbea3da..1cc2edd0cf47 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -89,9 +89,9 @@ use crate::os::unix::prelude::*; use crate::os::wasi::prelude::*; use crate::path::{Path, PathBuf}; use crate::sync::Arc; -use crate::sys::common::small_c_string::run_path_with_cstr; use crate::sys::fd::FileDesc; pub use crate::sys::fs::common::exists; +use crate::sys::helpers::run_path_with_cstr; use crate::sys::time::SystemTime; #[cfg(all(target_os = "linux", target_env = "gnu"))] use crate::sys::weak::syscall; @@ -2498,9 +2498,8 @@ mod remove_dir_impl { use crate::ffi::CStr; use crate::io; use crate::path::{Path, PathBuf}; - use crate::sys::common::small_c_string::run_path_with_cstr; + use crate::sys::helpers::{ignore_notfound, run_path_with_cstr}; use crate::sys::{cvt, cvt_r}; - use crate::sys_common::ignore_notfound; pub fn openat_nofollow_dironly(parent_fd: Option, p: &CStr) -> io::Result { let fd = cvt_r(|| unsafe { diff --git a/library/std/src/sys/fs/vexos.rs b/library/std/src/sys/fs/vexos.rs index 381c87c62c68..81083a4fa81d 100644 --- a/library/std/src/sys/fs/vexos.rs +++ b/library/std/src/sys/fs/vexos.rs @@ -4,7 +4,7 @@ use crate::fs::TryLockError; use crate::hash::Hash; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::path::{Path, PathBuf}; -use crate::sys::common::small_c_string::run_path_with_cstr; +use crate::sys::helpers::run_path_with_cstr; use crate::sys::time::SystemTime; use crate::sys::{unsupported, unsupported_err}; diff --git a/library/std/src/sys/net/connection/socket/mod.rs b/library/std/src/sys/net/connection/socket/mod.rs index c6df9c6b8ae1..256b99dfa987 100644 --- a/library/std/src/sys/net/connection/socket/mod.rs +++ b/library/std/src/sys/net/connection/socket/mod.rs @@ -7,7 +7,7 @@ use crate::mem::MaybeUninit; use crate::net::{ Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs, }; -use crate::sys::common::small_c_string::run_with_cstr; +use crate::sys::helpers::run_with_cstr; use crate::sys::net::connection::each_addr; use crate::sys::{AsInner, FromInner}; use crate::time::Duration; diff --git a/library/std/src/sys/net/connection/uefi/tcp.rs b/library/std/src/sys/net/connection/uefi/tcp.rs index 1e7e829c85f3..0c8ba08d8149 100644 --- a/library/std/src/sys/net/connection/uefi/tcp.rs +++ b/library/std/src/sys/net/connection/uefi/tcp.rs @@ -2,7 +2,7 @@ use super::tcp4; use crate::io::{self, IoSlice, IoSliceMut}; use crate::net::SocketAddr; use crate::ptr::NonNull; -use crate::sys::{helpers, unsupported}; +use crate::sys::pal::{helpers, unsupported}; use crate::time::Duration; pub(crate) enum Tcp { diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs index d059be010e98..353702447813 100644 --- a/library/std/src/sys/pal/uefi/helpers.rs +++ b/library/std/src/sys/pal/uefi/helpers.rs @@ -24,7 +24,7 @@ use crate::path::Path; use crate::ptr::NonNull; use crate::slice; use crate::sync::atomic::{Atomic, AtomicPtr, Ordering}; -use crate::sys_common::wstr::WStrUnits; +use crate::sys::helpers::WStrUnits; type BootInstallMultipleProtocolInterfaces = unsafe extern "efiapi" fn(_: *mut r_efi::efi::Handle, _: ...) -> r_efi::efi::Status; diff --git a/library/std/src/sys/pal/uefi/time.rs b/library/std/src/sys/pal/uefi/time.rs index c0f13de252ed..3dccd03ff3fc 100644 --- a/library/std/src/sys/pal/uefi/time.rs +++ b/library/std/src/sys/pal/uefi/time.rs @@ -300,7 +300,7 @@ pub(crate) mod instant_internal { use crate::mem::MaybeUninit; use crate::ptr::NonNull; use crate::sync::atomic::{Atomic, AtomicPtr, Ordering}; - use crate::sys_common::mul_div_u64; + use crate::sys::helpers::mul_div_u64; const NS_PER_SEC: u64 = 1_000_000_000; diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index edb7b604415b..ef3b4a02f8ae 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -10,8 +10,8 @@ use libc::{c_char, c_int, c_void}; use crate::ffi::{CStr, OsStr, OsString}; use crate::os::unix::prelude::*; use crate::path::{self, PathBuf}; -use crate::sys::common::small_c_string::run_path_with_cstr; use crate::sys::cvt; +use crate::sys::helpers::run_path_with_cstr; use crate::{fmt, io, iter, mem, ptr, slice, str}; const TMPBUF_SZ: usize = 128; diff --git a/library/std/src/sys/pal/wasi/os.rs b/library/std/src/sys/pal/wasi/os.rs index a3bb329c2c4f..fee187a8adf3 100644 --- a/library/std/src/sys/pal/wasi/os.rs +++ b/library/std/src/sys/pal/wasi/os.rs @@ -4,7 +4,7 @@ use crate::ffi::{CStr, OsStr, OsString}; use crate::marker::PhantomData; use crate::os::wasi::prelude::*; use crate::path::{self, PathBuf}; -use crate::sys::common::small_c_string::run_path_with_cstr; +use crate::sys::helpers::run_path_with_cstr; use crate::sys::unsupported; use crate::{fmt, io, str}; diff --git a/library/std/src/sys/pal/windows/time.rs b/library/std/src/sys/pal/windows/time.rs index ecd46c950b5e..a555b2b54623 100644 --- a/library/std/src/sys/pal/windows/time.rs +++ b/library/std/src/sys/pal/windows/time.rs @@ -179,8 +179,8 @@ fn intervals2dur(intervals: u64) -> Duration { mod perf_counter { use super::NANOS_PER_SEC; use crate::sync::atomic::{Atomic, AtomicU64, Ordering}; + use crate::sys::helpers::mul_div_u64; use crate::sys::{c, cvt}; - use crate::sys_common::mul_div_u64; use crate::time::Duration; pub struct PerformanceCounterInstant { diff --git a/library/std/src/sys/path/cygwin.rs b/library/std/src/sys/path/cygwin.rs index 416877a7280d..75f0de6beaeb 100644 --- a/library/std/src/sys/path/cygwin.rs +++ b/library/std/src/sys/path/cygwin.rs @@ -1,8 +1,8 @@ use crate::ffi::OsString; use crate::os::unix::ffi::OsStringExt; use crate::path::{Path, PathBuf}; -use crate::sys::common::small_c_string::run_path_with_cstr; use crate::sys::cvt; +use crate::sys::helpers::run_path_with_cstr; use crate::{io, ptr}; #[inline] diff --git a/library/std/src/sys/path/uefi.rs b/library/std/src/sys/path/uefi.rs index 6b8258685aa0..84d634af93cf 100644 --- a/library/std/src/sys/path/uefi.rs +++ b/library/std/src/sys/path/uefi.rs @@ -2,7 +2,8 @@ use crate::ffi::OsStr; use crate::io; use crate::path::{Path, PathBuf, Prefix}; -use crate::sys::{helpers, unsupported_err}; +use crate::sys::pal::helpers; +use crate::sys::unsupported_err; const FORWARD_SLASH: u8 = b'/'; const COLON: u8 = b':'; diff --git a/library/std/src/sys/platform_version/darwin/core_foundation.rs b/library/std/src/sys/platform_version/darwin/core_foundation.rs index 1e0d15fcf661..de2b57ea755b 100644 --- a/library/std/src/sys/platform_version/darwin/core_foundation.rs +++ b/library/std/src/sys/platform_version/darwin/core_foundation.rs @@ -3,7 +3,7 @@ use super::root_relative; use crate::ffi::{CStr, c_char, c_void}; use crate::ptr::null_mut; -use crate::sys::common::small_c_string::run_path_with_cstr; +use crate::sys::helpers::run_path_with_cstr; // MacTypes.h pub(super) type Boolean = u8; diff --git a/library/std/src/sys/process/uefi.rs b/library/std/src/sys/process/uefi.rs index 0e10bc02a0b9..d627a477dc1a 100644 --- a/library/std/src/sys/process/uefi.rs +++ b/library/std/src/sys/process/uefi.rs @@ -377,8 +377,8 @@ mod uefi_command_internal { use crate::os::uefi::ffi::{OsStrExt, OsStringExt}; use crate::ptr::NonNull; use crate::slice; + use crate::sys::helpers::WStrUnits; use crate::sys::pal::helpers::{self, OwnedTable}; - use crate::sys_common::wstr::WStrUnits; pub struct Image { handle: NonNull, From d8489c1ea02d9af8035d8aca5d4ee16056051eeb Mon Sep 17 00:00:00 2001 From: joboet Date: Fri, 12 Dec 2025 21:19:40 +0100 Subject: [PATCH 0194/1061] std: remove outdated documentation in `sys` --- library/std/src/sys/configure_builtins.rs | 4 ++++ library/std/src/sys/mod.rs | 12 ++-------- .../src/sys/net/connection/socket/hermit.rs | 1 - .../src/sys/net/connection/socket/solid.rs | 1 - .../std/src/sys/net/connection/socket/unix.rs | 1 - .../src/sys/net/connection/socket/windows.rs | 1 - library/std/src/sys/pal/mod.rs | 23 ++----------------- src/tools/tidy/src/pal.rs | 1 - 8 files changed, 8 insertions(+), 36 deletions(-) diff --git a/library/std/src/sys/configure_builtins.rs b/library/std/src/sys/configure_builtins.rs index f569ec0f5129..7cdf04ebb889 100644 --- a/library/std/src/sys/configure_builtins.rs +++ b/library/std/src/sys/configure_builtins.rs @@ -1,3 +1,7 @@ +//! The configure builtins provides runtime support compiler-builtin features +//! which require dynamic initialization to work as expected, e.g. aarch64 +//! outline-atomics. + /// Enable LSE atomic operations at startup, if supported. /// /// Linker sections are based on what [`ctor`] does, with priorities to run slightly before user diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index bfdbc6ee5d1e..c9035938cfdd 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -1,17 +1,9 @@ #![allow(unsafe_op_in_unsafe_fn)] -/// The configure builtins provides runtime support compiler-builtin features -/// which require dynamic initialization to work as expected, e.g. aarch64 -/// outline-atomics. -mod configure_builtins; - -/// The PAL (platform abstraction layer) contains platform-specific abstractions -/// for implementing the features in the other submodules, e.g. UNIX file -/// descriptors. -mod pal; - mod alloc; +mod configure_builtins; mod helpers; +mod pal; mod personality; pub mod args; diff --git a/library/std/src/sys/net/connection/socket/hermit.rs b/library/std/src/sys/net/connection/socket/hermit.rs index c32f8dcc8de8..d57a075eb42d 100644 --- a/library/std/src/sys/net/connection/socket/hermit.rs +++ b/library/std/src/sys/net/connection/socket/hermit.rs @@ -300,7 +300,6 @@ impl Socket { if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } } - // This is used by sys_common code to abstract over Windows and Unix. pub fn as_raw(&self) -> RawFd { self.0.as_raw_fd() } diff --git a/library/std/src/sys/net/connection/socket/solid.rs b/library/std/src/sys/net/connection/socket/solid.rs index 673d75046d3f..e20a3fbb76b7 100644 --- a/library/std/src/sys/net/connection/socket/solid.rs +++ b/library/std/src/sys/net/connection/socket/solid.rs @@ -353,7 +353,6 @@ impl Socket { if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } } - // This method is used by sys_common code to abstract over targets. pub fn as_raw(&self) -> c_int { self.as_raw_fd() } diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs index 6d06a8d86bf1..d09ba97cfe01 100644 --- a/library/std/src/sys/net/connection/socket/unix.rs +++ b/library/std/src/sys/net/connection/socket/unix.rs @@ -614,7 +614,6 @@ impl Socket { if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } } - // This is used by sys_common code to abstract over Windows and Unix. pub fn as_raw(&self) -> RawFd { self.as_raw_fd() } diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs index 7355f0ce6bf5..3f99249efc47 100644 --- a/library/std/src/sys/net/connection/socket/windows.rs +++ b/library/std/src/sys/net/connection/socket/windows.rs @@ -439,7 +439,6 @@ impl Socket { if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } } - // This is used by sys_common code to abstract over Windows and Unix. pub fn as_raw(&self) -> c::SOCKET { debug_assert_eq!(size_of::(), size_of::()); debug_assert_eq!(align_of::(), align_of::()); diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs index c039c2894877..88d9d4205990 100644 --- a/library/std/src/sys/pal/mod.rs +++ b/library/std/src/sys/pal/mod.rs @@ -1,24 +1,5 @@ -//! Platform-dependent platform abstraction. -//! -//! The `std::sys` module is the abstracted interface through which -//! `std` talks to the underlying operating system. It has different -//! implementations for different operating system families, today -//! just Unix and Windows, and initial support for Redox. -//! -//! The centralization of platform-specific code in this module is -//! enforced by the "platform abstraction layer" tidy script in -//! `tools/tidy/src/pal.rs`. -//! -//! This module is closely related to the platform-independent system -//! integration code in `std::sys_common`. See that module's -//! documentation for details. -//! -//! In the future it would be desirable for the independent -//! implementations of this module to be extracted to their own crates -//! that `std` can link to, thus enabling their implementation -//! out-of-tree via crate replacement. Though due to the complex -//! inter-dependencies within `std` that will be a challenging goal to -//! achieve. +//! The PAL (platform abstraction layer) contains platform-specific abstractions +//! for implementing the features in the other submodules, such as e.g. bindings. #![allow(missing_debug_implementations)] diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index e5945a72d32a..e6423aeeba99 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -24,7 +24,6 @@ //! - `sys/` //! - `os/` //! -//! `std/sys_common` should _not_ contain platform-specific code. //! Finally, because std contains tests with platform-specific //! `ignore` attributes, once the parser encounters `mod tests`, //! platform-specific cfgs are allowed. Not sure yet how to deal with From fc9f0fbf565eb8ff20a67870b6be41919251f53c Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 29 Dec 2025 10:07:16 +0100 Subject: [PATCH 0195/1061] bless UI test referencing outdated paths --- .../miri/tests/fail/shims/fs/isolated_file.stderr | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr b/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr index af55ccfe5e67..09501f98a9aa 100644 --- a/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr +++ b/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr @@ -15,12 +15,12 @@ LL | let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode a at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC 3: std::sys::fs::PLATFORM::File::open::{closure#0} at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC - 4: std::sys::pal::PLATFORM::small_c_string::run_with_cstr_stack - at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC - 5: std::sys::pal::PLATFORM::small_c_string::run_with_cstr - at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC - 6: std::sys::pal::PLATFORM::small_c_string::run_path_with_cstr - at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC + 4: std::sys::helpers::small_c_string::run_with_cstr_stack + at RUSTLIB/std/src/sys/helpers/small_c_string.rs:LL:CC + 5: std::sys::helpers::small_c_string::run_with_cstr + at RUSTLIB/std/src/sys/helpers/small_c_string.rs:LL:CC + 6: std::sys::helpers::small_c_string::run_path_with_cstr + at RUSTLIB/std/src/sys/helpers/small_c_string.rs:LL:CC 7: std::sys::fs::PLATFORM::File::open at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC 8: std::fs::OpenOptions::_open From 7834c43ea6913f2ccf28373fffa321a495ab2f7c Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 29 Dec 2025 10:09:57 +0100 Subject: [PATCH 0196/1061] beautify comment in `sys::helpers` --- library/std/src/sys/helpers/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/helpers/mod.rs b/library/std/src/sys/helpers/mod.rs index c29d9d2ce2d1..a6236799caea 100644 --- a/library/std/src/sys/helpers/mod.rs +++ b/library/std/src/sys/helpers/mod.rs @@ -16,8 +16,9 @@ pub use small_c_string::{run_path_with_cstr, run_with_cstr}; #[cfg_attr(not(target_os = "windows"), allow(unused))] // Not used on all platforms. pub use wstr::WStrUnits; -// Computes (value*numerator)/denom without overflow, as long as both (numerator*denom) and the -// overall result fit into i64 (which is the case for our time conversions). +/// Computes `(value*numerator)/denom` without overflow, as long as both +/// `numerator*denom` and the overall result fit into `u64` (which is the case +/// for our time conversions). #[cfg_attr(not(target_os = "windows"), allow(unused))] // Not used on all platforms. pub fn mul_div_u64(value: u64, numerator: u64, denom: u64) -> u64 { let q = value / denom; From 296ab7c15c0a8d7af7a66057213835244e7c3b15 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Jan 2026 19:19:38 +0100 Subject: [PATCH 0197/1061] android: get the entire test suite to pass --- src/tools/miri/README.md | 2 +- src/tools/miri/ci/ci.sh | 3 +- src/tools/miri/src/shims/env.rs | 5 +- .../src/shims/unix/android/foreign_items.rs | 69 +++++++++++++++++++ .../miri/src/shims/unix/foreign_items.rs | 2 +- .../src/shims/unix/freebsd/foreign_items.rs | 4 +- src/tools/miri/src/shims/unix/fs.rs | 34 +++++---- .../src/shims/unix/macos/foreign_items.rs | 4 +- .../src/shims/unix/solarish/foreign_items.rs | 4 +- .../miri/src/shims/unix/unnamed_socket.rs | 2 +- .../miri/tests/pass-dep/libc/libc-fs-flock.rs | 1 + .../miri/tests/pass-dep/libc/libc-pipe.rs | 2 + src/tools/miri/tests/pass-dep/shims/gettid.rs | 6 +- src/tools/miri/tests/pass-dep/tempfile.rs | 11 +-- src/tools/miri/tests/pass/shims/fs.rs | 6 +- 15 files changed, 109 insertions(+), 46 deletions(-) diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 2832ef50adef..d5ef9c767414 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -219,7 +219,7 @@ degree documented below): - We have unofficial support (not maintained by the Miri team itself) for some further operating systems. - `solaris` / `illumos`: maintained by @devnexen. Supports the entire test suite. - `freebsd`: maintained by @YohDeadfall and @LorrensP-2158466. Supports the entire test suite. - - `android`: **maintainer wanted**. Basic OS APIs and concurrency work, but file system access is not supported. + - `android`: **maintainer wanted**. Supports the entire test suite. - For targets on other operating systems, Miri might fail before even reaching the `main` function. However, even for targets that we do support, the degree of support for accessing platform APIs diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 2dd8fc77459a..82007a8c1c1a 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -149,10 +149,11 @@ case $HOST_TARGET in i686-unknown-linux-gnu) # Host MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests + # Fully, but not officially, supported tier 2 + MANY_SEEDS=16 TEST_TARGET=aarch64-linux-android run_tests # Partially supported targets (tier 2) BASIC="empty_main integer heap_alloc libc-mem vec string btreemap" # ensures we have the basics: pre-main code, system allocator UNIX="hello panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there - TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency epoll eventfd prctl TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std ;; diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs index 6915924f2a48..7c463983320b 100644 --- a/src/tools/miri/src/shims/env.rs +++ b/src/tools/miri/src/shims/env.rs @@ -119,9 +119,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_ref(); let index = thread.to_u32(); let target_os = &this.tcx.sess.target.os; - if matches!(target_os, Os::Linux | Os::NetBsd) { - // On Linux, the main thread has PID == TID so we uphold this. NetBSD also appears - // to exhibit the same behavior, though I can't find a citation. + if matches!(target_os, Os::Linux | Os::Android) { + // On Linux, the main thread has PID == TID so we uphold this. this.get_pid().strict_add(index) } else { // Other platforms do not display any relationship between PID and TID. diff --git a/src/tools/miri/src/shims/unix/android/foreign_items.rs b/src/tools/miri/src/shims/unix/android/foreign_items.rs index 6cb0d221fc03..2b290b68c78c 100644 --- a/src/tools/miri/src/shims/unix/android/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/android/foreign_items.rs @@ -8,6 +8,7 @@ use crate::shims::unix::env::EvalContextExt as _; use crate::shims::unix::linux_like::epoll::EvalContextExt as _; use crate::shims::unix::linux_like::eventfd::EvalContextExt as _; use crate::shims::unix::linux_like::syscall::syscall; +use crate::shims::unix::*; use crate::*; pub fn is_dyn_sym(name: &str) -> bool { @@ -25,6 +26,74 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); match link_name.as_str() { + // File related shims + "stat" => { + let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let result = this.stat(path, buf)?; + this.write_scalar(result, dest)?; + } + "lstat" => { + let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let result = this.lstat(path, buf)?; + this.write_scalar(result, dest)?; + } + "readdir" => { + let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let result = this.readdir64("dirent", dirp)?; + this.write_scalar(result, dest)?; + } + "pread64" => { + let [fd, buf, count, offset] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, *mut _, usize, libc::off64_t) -> isize), + link_name, + abi, + args, + )?; + let fd = this.read_scalar(fd)?.to_i32()?; + let buf = this.read_pointer(buf)?; + let count = this.read_target_usize(count)?; + let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?; + this.read(fd, buf, count, Some(offset), dest)?; + } + "pwrite64" => { + let [fd, buf, n, offset] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, *const _, usize, libc::off64_t) -> isize), + link_name, + abi, + args, + )?; + let fd = this.read_scalar(fd)?.to_i32()?; + let buf = this.read_pointer(buf)?; + let count = this.read_target_usize(n)?; + let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?; + trace!("Called pwrite64({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset); + this.write(fd, buf, count, Some(offset), dest)?; + } + "lseek64" => { + let [fd, offset, whence] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, libc::off64_t, i32) -> libc::off64_t), + link_name, + abi, + args, + )?; + let fd = this.read_scalar(fd)?.to_i32()?; + let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?; + let whence = this.read_scalar(whence)?.to_i32()?; + this.lseek64(fd, offset, whence, dest)?; + } + "ftruncate64" => { + let [fd, length] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, libc::off64_t) -> i32), + link_name, + abi, + args, + )?; + let fd = this.read_scalar(fd)?.to_i32()?; + let length = this.read_scalar(length)?.to_int(length.layout.size)?; + let result = this.ftruncate64(fd, length)?; + this.write_scalar(result, dest)?; + } + // epoll, eventfd "epoll_create1" => { let [flag] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 64b8376ff4aa..8eacdc3583d4 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -510,7 +510,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "pipe2" => { // Currently this function does not exist on all Unixes, e.g. on macOS. this.check_target_os( - &[Os::Linux, Os::FreeBsd, Os::Solaris, Os::Illumos], + &[Os::Linux, Os::Android, Os::FreeBsd, Os::Solaris, Os::Illumos], link_name, )?; let [pipefd, flags] = this.check_shim_sig( diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs index c48301c72416..fb2d3f758420 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -140,12 +140,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // since freebsd 12 the former form can be expected. "stat" | "stat@FBSD_1.0" => { let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let result = this.macos_fbsd_solarish_stat(path, buf)?; + let result = this.stat(path, buf)?; this.write_scalar(result, dest)?; } "lstat" | "lstat@FBSD_1.0" => { let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let result = this.macos_fbsd_solarish_lstat(path, buf)?; + let result = this.lstat(path, buf)?; this.write_scalar(result, dest)?; } "fstat@FBSD_1.0" => { diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index e17456c3bc0e..f43fd3fe2d18 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -527,15 +527,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) } - fn macos_fbsd_solarish_stat( - &mut self, - path_op: &OpTy<'tcx>, - buf_op: &OpTy<'tcx>, - ) -> InterpResult<'tcx, Scalar> { + fn stat(&mut self, path_op: &OpTy<'tcx>, buf_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - if !matches!(&this.tcx.sess.target.os, Os::MacOs | Os::FreeBsd | Os::Solaris | Os::Illumos) - { + if !matches!( + &this.tcx.sess.target.os, + Os::MacOs | Os::FreeBsd | Os::Solaris | Os::Illumos | Os::Android + ) { panic!("`macos_fbsd_solaris_stat` should not be called on {}", this.tcx.sess.target.os); } @@ -558,15 +556,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } // `lstat` is used to get symlink metadata. - fn macos_fbsd_solarish_lstat( - &mut self, - path_op: &OpTy<'tcx>, - buf_op: &OpTy<'tcx>, - ) -> InterpResult<'tcx, Scalar> { + fn lstat(&mut self, path_op: &OpTy<'tcx>, buf_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - if !matches!(&this.tcx.sess.target.os, Os::MacOs | Os::FreeBsd | Os::Solaris | Os::Illumos) - { + if !matches!( + &this.tcx.sess.target.os, + Os::MacOs | Os::FreeBsd | Os::Solaris | Os::Illumos | Os::Android + ) { panic!( "`macos_fbsd_solaris_lstat` should not be called on {}", this.tcx.sess.target.os @@ -595,7 +591,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if !matches!( &this.tcx.sess.target.os, - Os::MacOs | Os::FreeBsd | Os::Solaris | Os::Illumos | Os::Linux + Os::MacOs | Os::FreeBsd | Os::Solaris | Os::Illumos | Os::Linux | Os::Android ) { panic!("`fstat` should not be called on {}", this.tcx.sess.target.os); } @@ -906,9 +902,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn readdir64(&mut self, dirent_type: &str, dirp_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - if !matches!(&this.tcx.sess.target.os, Os::Linux | Os::Solaris | Os::Illumos | Os::FreeBsd) - { - panic!("`linux_solaris_readdir64` should not be called on {}", this.tcx.sess.target.os); + if !matches!( + &this.tcx.sess.target.os, + Os::Linux | Os::Android | Os::Solaris | Os::Illumos | Os::FreeBsd + ) { + panic!("`readdir64` should not be called on {}", this.tcx.sess.target.os); } let dirp = this.read_target_usize(dirp_op)?; diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index dd7b95bdc82b..f798f64441b1 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -48,12 +48,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "stat" | "stat$INODE64" => { let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let result = this.macos_fbsd_solarish_stat(path, buf)?; + let result = this.stat(path, buf)?; this.write_scalar(result, dest)?; } "lstat" | "lstat$INODE64" => { let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let result = this.macos_fbsd_solarish_lstat(path, buf)?; + let result = this.lstat(path, buf)?; this.write_scalar(result, dest)?; } "fstat$INODE64" => { diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs index ae7230877a71..fa8c86b025a7 100644 --- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs @@ -92,12 +92,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // File related shims "stat" => { let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let result = this.macos_fbsd_solarish_stat(path, buf)?; + let result = this.stat(path, buf)?; this.write_scalar(result, dest)?; } "lstat" => { let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let result = this.macos_fbsd_solarish_lstat(path, buf)?; + let result = this.lstat(path, buf)?; this.write_scalar(result, dest)?; } "readdir" => { diff --git a/src/tools/miri/src/shims/unix/unnamed_socket.rs b/src/tools/miri/src/shims/unix/unnamed_socket.rs index a320ac131689..cc371b43a681 100644 --- a/src/tools/miri/src/shims/unix/unnamed_socket.rs +++ b/src/tools/miri/src/shims/unix/unnamed_socket.rs @@ -459,7 +459,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Interpret the flag. Every flag we recognize is "subtracted" from `flags`, so // if there is anything left at the end, that's an unsupported flag. - if this.tcx.sess.target.os == Os::Linux { + if matches!(this.tcx.sess.target.os, Os::Linux | Os::Android) { // SOCK_NONBLOCK only exists on Linux. let sock_nonblock = this.eval_libc_i32("SOCK_NONBLOCK"); let sock_cloexec = this.eval_libc_i32("SOCK_CLOEXEC"); diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs index 0500ba05046c..52de8c7104c2 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs @@ -1,5 +1,6 @@ //@ignore-target: windows # File handling is not implemented yet //@ignore-target: solaris # Does not have flock +//@ignore-target: android # Does not (always?) have flock //@compile-flags: -Zmiri-disable-isolation use std::fs::File; diff --git a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs index ffbcf633b987..63e330fed636 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs @@ -13,6 +13,7 @@ fn main() { test_pipe_array(); #[cfg(any( target_os = "linux", + target_os = "android", target_os = "illumos", target_os = "freebsd", target_os = "solaris" @@ -133,6 +134,7 @@ fn test_pipe_array() { /// Test if pipe2 (including the O_NONBLOCK flag) is supported. #[cfg(any( target_os = "linux", + target_os = "android", target_os = "illumos", target_os = "freebsd", target_os = "solaris" diff --git a/src/tools/miri/tests/pass-dep/shims/gettid.rs b/src/tools/miri/tests/pass-dep/shims/gettid.rs index b7a2fa49ef86..9d5ff0dc5dae 100644 --- a/src/tools/miri/tests/pass-dep/shims/gettid.rs +++ b/src/tools/miri/tests/pass-dep/shims/gettid.rs @@ -165,7 +165,7 @@ fn main() { // The value is not important, we only care that whatever the value is, // won't change from execution to execution. if cfg!(with_isolation) { - if cfg!(target_os = "linux") { + if cfg!(any(target_os = "linux", target_os = "android")) { // Linux starts the TID at the PID, which is 1000. assert_eq!(tid, 1000); } else { @@ -174,8 +174,8 @@ fn main() { } } - // On Linux and NetBSD, the first TID is the PID. - #[cfg(any(target_os = "linux", target_os = "netbsd"))] + // On Linux, the first TID is the PID. + #[cfg(any(target_os = "linux", target_os = "android"))] assert_eq!(tid, unsafe { libc::getpid() } as u64); #[cfg(any(target_vendor = "apple", windows))] diff --git a/src/tools/miri/tests/pass-dep/tempfile.rs b/src/tools/miri/tests/pass-dep/tempfile.rs index a44a7e7d9244..885190bd776a 100644 --- a/src/tools/miri/tests/pass-dep/tempfile.rs +++ b/src/tools/miri/tests/pass-dep/tempfile.rs @@ -7,15 +7,8 @@ mod utils; /// Test that the [`tempfile`] crate is compatible with miri for UNIX hosts and targets fn main() { - test_tempfile(); - test_tempfile_in(); -} - -fn test_tempfile() { - tempfile::tempfile().unwrap(); -} - -fn test_tempfile_in() { + // Only create a file in our own tmp folder; the "host" temp folder + // can be nonsensical for cross-tests. let dir_path = utils::tmp(); tempfile::tempfile_in(dir_path).unwrap(); } diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs index 648c90b5dd97..50b5dbfba1cd 100644 --- a/src/tools/miri/tests/pass/shims/fs.rs +++ b/src/tools/miri/tests/pass/shims/fs.rs @@ -37,7 +37,7 @@ fn main() { test_canonicalize(); #[cfg(unix)] test_pread_pwrite(); - #[cfg(not(any(target_os = "solaris", target_os = "illumos")))] + #[cfg(not(any(target_os = "solaris", target_os = "android")))] test_flock(); } } @@ -399,8 +399,8 @@ fn test_pread_pwrite() { assert_eq!(&buf1, b" m"); } -// This function does seem to exist on Illumos but std does not expose it there. -#[cfg(not(any(target_os = "solaris", target_os = "illumos")))] +// The standard library does not support this operation on Solaris, Android +#[cfg(not(any(target_os = "solaris", target_os = "android")))] fn test_flock() { let bytes = b"Hello, World!\n"; let path = utils::prepare_with_content("miri_test_fs_flock.txt", bytes); From ac453d34d21bc4817dd41df0a4eeac88a541b9ba Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 2 Jan 2026 20:21:00 +0100 Subject: [PATCH 0198/1061] Update `browser-ui-test` version to `0.23.0` --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 007e2c116321..ef74853b77a5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "dependencies": { - "browser-ui-test": "^0.22.2", + "browser-ui-test": "^0.23.0", "es-check": "^9.4.4", "eslint": "^8.57.1", "typescript": "^5.8.3" From 665781513e6a8d6a63ed9fab5b98f919ad3f627c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 2 Jan 2026 20:21:44 +0100 Subject: [PATCH 0199/1061] Fix changes coming from `browser-ui-test` version update --- tests/rustdoc-gui/anchors.goml | 8 ++++---- tests/rustdoc-gui/links-color.goml | 2 +- tests/rustdoc-gui/sidebar-mobile.goml | 2 +- tests/rustdoc-gui/sidebar-source-code-display.goml | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/rustdoc-gui/anchors.goml b/tests/rustdoc-gui/anchors.goml index 3168c8e17c52..0e8c834a7a77 100644 --- a/tests/rustdoc-gui/anchors.goml +++ b/tests/rustdoc-gui/anchors.goml @@ -15,7 +15,7 @@ define-function: ( assert-css: (".main-heading h1 span", {"color": |main_heading_type_color|}) assert-css: ( ".rightside a.src", - {"color": |src_link_color|, "text-decoration": "none solid " + |src_link_color|}, + {"color": |src_link_color|, "text-decoration": "none"}, ALL, ) compare-elements-css: ( @@ -32,17 +32,17 @@ define-function: ( move-cursor-to: ".main-heading a.src" assert-css: ( ".main-heading a.src", - {"color": |src_link_color|, "text-decoration": "underline solid " + |src_link_color|}, + {"color": |src_link_color|, "text-decoration": "underline"}, ) move-cursor-to: ".impl-items .rightside a.src" assert-css: ( ".impl-items .rightside a.src", - {"color": |src_link_color|, "text-decoration": "none solid " + |src_link_color|}, + {"color": |src_link_color|, "text-decoration": "none"}, ) move-cursor-to: ".impl-items a.rightside.src" assert-css: ( ".impl-items a.rightside.src", - {"color": |src_link_color|, "text-decoration": "none solid " + |src_link_color|}, + {"color": |src_link_color|, "text-decoration": "none"}, ) go-to: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html" diff --git a/tests/rustdoc-gui/links-color.goml b/tests/rustdoc-gui/links-color.goml index a363175c1ddb..ae1509c6fa4f 100644 --- a/tests/rustdoc-gui/links-color.goml +++ b/tests/rustdoc-gui/links-color.goml @@ -41,7 +41,7 @@ define-function: ( move-cursor-to: "dd a[href='long_code_block_link/index.html']" assert-css: ( "dd a[href='long_code_block_link/index.html']", - {"text-decoration": "underline solid " + |mod|}, + {"text-decoration": "underline"}, ) }, ) diff --git a/tests/rustdoc-gui/sidebar-mobile.goml b/tests/rustdoc-gui/sidebar-mobile.goml index f828516d7624..1fa5521baac9 100644 --- a/tests/rustdoc-gui/sidebar-mobile.goml +++ b/tests/rustdoc-gui/sidebar-mobile.goml @@ -49,7 +49,7 @@ assert-property: ("rustdoc-topbar", {"clientHeight": "45"}) // so the target is not obscured by the topbar. click: ".sidebar-menu-toggle" click: ".sidebar-elems section .block li > a" -assert-position: ("#method\.must_use", {"y": 46}) +assert-position: ("#method\.must_use", {"y": 45}) // Check that the bottom-most item on the sidebar menu can be scrolled fully into view. click: ".sidebar-menu-toggle" diff --git a/tests/rustdoc-gui/sidebar-source-code-display.goml b/tests/rustdoc-gui/sidebar-source-code-display.goml index 99810cd78633..d2b667b498bc 100644 --- a/tests/rustdoc-gui/sidebar-source-code-display.goml +++ b/tests/rustdoc-gui/sidebar-source-code-display.goml @@ -141,7 +141,7 @@ click: "#sidebar-button" wait-for-css: (".src .sidebar > *", {"visibility": "hidden"}) // We scroll to line 117 to change the scroll position. scroll-to: '//*[@id="117"]' -store-value: (y_offset, "2567") +store-value: (y_offset, "2568") assert-window-property: {"pageYOffset": |y_offset|} // Expanding the sidebar... click: "#sidebar-button" From 0451cc012a4890abcbc217d4105b8ecf3daecf43 Mon Sep 17 00:00:00 2001 From: benodiwal Date: Sat, 3 Jan 2026 00:52:19 +0530 Subject: [PATCH 0200/1061] fix: add location links for generic type parameters in inlay hints --- .../crates/hir-ty/src/display.rs | 14 ++++++++++++-- src/tools/rust-analyzer/crates/hir/src/lib.rs | 8 ++++---- .../crates/ide/src/inlay_hints.rs | 19 +++++++++++++++++-- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 44bbd84003da..4f9406908ffd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -10,7 +10,8 @@ use std::{ use base_db::{Crate, FxIndexMap}; use either::Either; use hir_def::{ - FindPathConfig, GenericDefId, HasModule, LocalFieldId, Lookup, ModuleDefId, ModuleId, TraitId, + FindPathConfig, GenericDefId, GenericParamId, HasModule, LocalFieldId, Lookup, ModuleDefId, + ModuleId, TraitId, db::DefDatabase, expr_store::{ExpressionStore, path::Path}, find_path::{self, PrefixKind}, @@ -66,6 +67,7 @@ pub type Result = std::result::Result; pub trait HirWrite: fmt::Write { fn start_location_link(&mut self, _location: ModuleDefId) {} + fn start_location_link_generic(&mut self, _location: GenericParamId) {} fn end_location_link(&mut self) {} } @@ -147,6 +149,10 @@ impl<'db> HirFormatter<'_, 'db> { self.fmt.start_location_link(location); } + pub fn start_location_link_generic(&mut self, location: GenericParamId) { + self.fmt.start_location_link_generic(location); + } + pub fn end_location_link(&mut self) { self.fmt.end_location_link(); } @@ -1489,6 +1495,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> { match param_data { TypeOrConstParamData::TypeParamData(p) => match p.provenance { TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => { + f.start_location_link_generic(param.id.into()); write!( f, "{}", @@ -1496,7 +1503,8 @@ impl<'db> HirDisplay<'db> for Ty<'db> { .clone() .unwrap_or_else(Name::missing) .display(f.db, f.edition()) - )? + )?; + f.end_location_link(); } TypeParamProvenance::ArgumentImplTrait => { let bounds = GenericPredicates::query_all(f.db, param.id.parent()) @@ -1519,7 +1527,9 @@ impl<'db> HirDisplay<'db> for Ty<'db> { } }, TypeOrConstParamData::ConstParamData(p) => { + f.start_location_link_generic(param.id.into()); write!(f, "{}", p.name.display(f.db, f.edition()))?; + f.end_location_link(); } } } diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 1ab57c4489cf..65de6c0a554a 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -50,9 +50,9 @@ use either::Either; use hir_def::{ AdtId, AssocItemId, AssocItemLoc, BuiltinDeriveImplId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, GenericDefId, - GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, - MacroExpander, MacroId, StaticId, StructId, SyntheticSyntax, TupleId, TypeAliasId, - TypeOrConstParamId, TypeParamId, UnionId, + HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, MacroExpander, + MacroId, StaticId, StructId, SyntheticSyntax, TupleId, TypeAliasId, TypeOrConstParamId, + TypeParamId, UnionId, attrs::AttrFlags, builtin_derive::BuiltinDeriveImplMethod, expr_store::{ExpressionStoreDiagnostics, ExpressionStoreSourceMap}, @@ -150,7 +150,7 @@ pub use { visibility::Visibility, // FIXME: This is here since some queries take it as input that are used // outside of hir. - {ModuleDefId, TraitId}, + {GenericParamId, ModuleDefId, TraitId}, }, hir_expand::{ EditionedFileId, ExpandResult, HirFileId, MacroCallId, MacroKind, diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs index 06ae0b1d73d1..a58dc6f03055 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -5,8 +5,8 @@ use std::{ use either::Either; use hir::{ - ClosureStyle, DisplayTarget, EditionedFileId, HasVisibility, HirDisplay, HirDisplayError, - HirWrite, InRealFile, ModuleDef, ModuleDefId, Semantics, sym, + ClosureStyle, DisplayTarget, EditionedFileId, GenericParam, GenericParamId, HasVisibility, + HirDisplay, HirDisplayError, HirWrite, InRealFile, ModuleDef, ModuleDefId, Semantics, sym, }; use ide_db::{ FileRange, MiniCore, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder, @@ -709,6 +709,21 @@ impl HirWrite for InlayHintLabelBuilder<'_> { }); } + fn start_location_link_generic(&mut self, def: GenericParamId) { + never!(self.location.is_some(), "location link is already started"); + self.make_new_part(); + + self.location = Some(if self.resolve { + LazyProperty::Lazy + } else { + LazyProperty::Computed({ + let Some(location) = GenericParam::from(def).try_to_nav(self.sema) else { return }; + let location = location.call_site(); + FileRange { file_id: location.file_id, range: location.focus_or_full_range() } + }) + }); + } + fn end_location_link(&mut self) { self.make_new_part(); } From 1222bbf29c7a0484c322006d8771dadcd47447c0 Mon Sep 17 00:00:00 2001 From: benodiwal Date: Sat, 3 Jan 2026 00:59:03 +0530 Subject: [PATCH 0201/1061] feat: added tests --- .../crates/ide/src/inlay_hints/bind_pat.rs | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs index 547004687c73..79cc2bdf8f7b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs @@ -183,7 +183,8 @@ mod tests { use crate::{ClosureReturnTypeHints, fixture, inlay_hints::InlayHintsConfig}; use crate::inlay_hints::tests::{ - DISABLED_CONFIG, TEST_CONFIG, check, check_edit, check_no_edit, check_with_config, + DISABLED_CONFIG, TEST_CONFIG, check, check_edit, check_expect, check_no_edit, + check_with_config, }; #[track_caller] @@ -1255,4 +1256,40 @@ where "#, ); } + + #[test] + fn generic_param_inlay_hint_has_location_link() { + check_expect( + InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, + r#" +fn identity(t: T) -> T { + let x = t; + x +} +"#, + expect![[r#" + [ + ( + 36..37, + [ + InlayHintLabelPart { + text: "T", + linked_location: Some( + Computed( + FileRangeWrapper { + file_id: FileId( + 0, + ), + range: 12..13, + }, + ), + ), + tooltip: "", + }, + ], + ), + ] + "#]], + ); + } } From 9a675c09cf65539e39e90d2adb6046870ec6a745 Mon Sep 17 00:00:00 2001 From: Clara Engler Date: Fri, 2 Jan 2026 20:40:04 +0100 Subject: [PATCH 0202/1061] alloc: Move Cow impl to existing ones Right now, the `borrow.rs` module starts with a `Cow` impl, although most of them can be found below. This hurts code readability because there is `ToOwned` alongside its impl directly below it. Moving it to the others down below makes sense here, given that the entire enum depends on `ToOwned` anyways. --- library/alloc/src/borrow.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs index aa973e0bb024..d1c7cd47da0f 100644 --- a/library/alloc/src/borrow.rs +++ b/library/alloc/src/borrow.rs @@ -16,19 +16,6 @@ use crate::fmt; #[cfg(not(no_global_oom_handling))] use crate::string::String; -// FIXME(inference): const bounds removed due to inference regressions found by crater; -// see https://github.com/rust-lang/rust/issues/147964 -// #[rustc_const_unstable(feature = "const_convert", issue = "143773")] -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, B: ?Sized + ToOwned> Borrow for Cow<'a, B> -// where -// B::Owned: [const] Borrow, -{ - fn borrow(&self) -> &B { - &**self - } -} - /// A generalization of `Clone` to borrowed data. /// /// Some types make it possible to go from borrowed to owned, usually by @@ -192,6 +179,19 @@ where Owned(#[stable(feature = "rust1", since = "1.0.0")] ::Owned), } +// FIXME(inference): const bounds removed due to inference regressions found by crater; +// see https://github.com/rust-lang/rust/issues/147964 +// #[rustc_const_unstable(feature = "const_convert", issue = "143773")] +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, B: ?Sized + ToOwned> Borrow for Cow<'a, B> +// where +// B::Owned: [const] Borrow, +{ + fn borrow(&self) -> &B { + &**self + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Cow<'_, B> { fn clone(&self) -> Self { From dd97e41d47b1bec301db3c334f4c378c946d9224 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sat, 3 Jan 2026 01:24:03 +0530 Subject: [PATCH 0203/1061] for filename, use localfilename first and then resort to other construction --- .../crates/load-cargo/src/lib.rs | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index 5aa96582e9f3..023253f23f42 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -563,14 +563,23 @@ impl ProcMacroExpander for Expander { let source_root_id = db.file_source_root(file).source_root_id(db); let source_root = db.source_root(source_root_id).source_root(db); - let name = source_root.path_for_file(&file).and_then(|path| { - path.name_and_extension().map(|(name, ext)| match ext { - Some(ext) => format!("{name}.{ext}"), - None => name.to_owned(), - }) - }); + let path = source_root.path_for_file(&file); - Ok(SubResponse::FileNameResult { name: name.unwrap_or_default() }) + let name = path + .and_then(|p| p.as_path()) + .and_then(|p| p.file_name()) + .map(|n| n.to_owned()) + .or_else(|| { + path.and_then(|p| { + p.name_and_extension().map(|(name, ext)| match ext { + Some(ext) => format!("{name}.{ext}"), + None => name.into(), + }) + }) + }) + .unwrap_or_default(); + + Ok(SubResponse::FileNameResult { name }) } }; match self.0.expand( From 3114decb04b1f4d8edb46a513df2f948ded778d2 Mon Sep 17 00:00:00 2001 From: benodiwal Date: Sat, 3 Jan 2026 01:58:48 +0530 Subject: [PATCH 0204/1061] fix: add location links for type, const, and lifetime parameters in inlay hints --- .../crates/hir-ty/src/display.rs | 4 + .../crates/ide/src/inlay_hints/bind_pat.rs | 92 ++++++++++++++++++- 2 files changed, 95 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 4f9406908ffd..43b428c3fa51 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -692,7 +692,9 @@ impl<'db> HirDisplay<'db> for Const<'db> { ConstKind::Param(param) => { let generics = generics(f.db, param.id.parent()); let param_data = &generics[param.id.local_id()]; + f.start_location_link_generic(param.id.into()); write!(f, "{}", param_data.name().unwrap().display(f.db, f.edition()))?; + f.end_location_link(); Ok(()) } ConstKind::Value(const_bytes) => render_const_scalar( @@ -2041,7 +2043,9 @@ impl<'db> HirDisplay<'db> for Region<'db> { RegionKind::ReEarlyParam(param) => { let generics = generics(f.db, param.id.parent); let param_data = &generics[param.id.local_id]; + f.start_location_link_generic(param.id.into()); write!(f, "{}", param_data.name.display(f.db, f.edition()))?; + f.end_location_link(); Ok(()) } RegionKind::ReBound(BoundVarIndexKind::Bound(db), idx) => { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs index 79cc2bdf8f7b..c74e3104c14e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs @@ -1258,7 +1258,7 @@ where } #[test] - fn generic_param_inlay_hint_has_location_link() { + fn type_param_inlay_hint_has_location_link() { check_expect( InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, r#" @@ -1292,4 +1292,94 @@ fn identity(t: T) -> T { "#]], ); } + + #[test] + fn const_param_inlay_hint_has_location_link() { + check_expect( + InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, + r#" +fn f() { + let x = [0; N]; +} +"#, + expect![[r#" + [ + ( + 33..34, + [ + "[i32; ", + InlayHintLabelPart { + text: "N", + linked_location: Some( + Computed( + FileRangeWrapper { + file_id: FileId( + 0, + ), + range: 11..12, + }, + ), + ), + tooltip: "", + }, + "]", + ], + ), + ] + "#]], + ); + } + + #[test] + fn lifetime_param_inlay_hint_has_location_link() { + check_expect( + InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, + r#" +struct S<'lt>(*mut &'lt ()); + +fn f<'a>() { + let x = S::<'a>(loop {}); +} +"#, + expect![[r#" + [ + ( + 51..52, + [ + InlayHintLabelPart { + text: "S", + linked_location: Some( + Computed( + FileRangeWrapper { + file_id: FileId( + 0, + ), + range: 7..8, + }, + ), + ), + tooltip: "", + }, + "<", + InlayHintLabelPart { + text: "'a", + linked_location: Some( + Computed( + FileRangeWrapper { + file_id: FileId( + 0, + ), + range: 35..37, + }, + ), + ), + tooltip: "", + }, + ">", + ], + ), + ] + "#]], + ); + } } From cecc26bf3efb41f27140bdd74f58e71a87a24ec6 Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 2 Jan 2026 22:55:05 +0200 Subject: [PATCH 0205/1061] Refactor libc-fs-symlink tests to use errno_result --- .../tests/pass-dep/libc/libc-fs-symlink.rs | 39 +++++++++++-------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs-symlink.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs-symlink.rs index fd7fc801dc28..52a0d978963e 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-fs-symlink.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs-symlink.rs @@ -4,11 +4,14 @@ //@compile-flags: -Zmiri-disable-isolation use std::ffi::CString; -use std::io::{Error, ErrorKind}; +use std::io::ErrorKind; use std::os::unix::ffi::OsStrExt; +#[path = "../../utils/libc.rs"] +mod libc_utils; #[path = "../../utils/mod.rs"] mod utils; +use libc_utils::errno_result; fn main() { test_readlink(); @@ -31,44 +34,48 @@ fn test_readlink() { // Make the buf one byte larger than it needs to be, // and check that the last byte is not overwritten. let mut large_buf = vec![0xFF; expected_path.len() + 1]; - let res = - unsafe { libc::readlink(symlink_c_ptr, large_buf.as_mut_ptr().cast(), large_buf.len()) }; + let res = errno_result(unsafe { + libc::readlink(symlink_c_ptr, large_buf.as_mut_ptr().cast(), large_buf.len()) + }) + .unwrap(); // Check that the resolved path was properly written into the buf. assert_eq!(&large_buf[..(large_buf.len() - 1)], expected_path); assert_eq!(large_buf.last(), Some(&0xFF)); - assert_eq!(res, large_buf.len() as isize - 1); + assert_eq!(res, (large_buf.len() - 1) as isize); // Test that the resolved path is truncated if the provided buffer // is too small. let mut small_buf = [0u8; 2]; - let res = - unsafe { libc::readlink(symlink_c_ptr, small_buf.as_mut_ptr().cast(), small_buf.len()) }; + let res = errno_result(unsafe { + libc::readlink(symlink_c_ptr, small_buf.as_mut_ptr().cast(), small_buf.len()) + }) + .unwrap(); assert_eq!(small_buf, &expected_path[..small_buf.len()]); assert_eq!(res, small_buf.len() as isize); // Test that we report a proper error for a missing path. - let res = unsafe { + let err = errno_result(unsafe { libc::readlink( c"MIRI_MISSING_FILE_NAME".as_ptr(), small_buf.as_mut_ptr().cast(), small_buf.len(), ) - }; - assert_eq!(res, -1); - assert_eq!(Error::last_os_error().kind(), ErrorKind::NotFound); + }) + .unwrap_err(); + assert_eq!(err.kind(), ErrorKind::NotFound); } fn test_nofollow_symlink() { - let bytes = b"Hello, World!\n"; - let path = utils::prepare_with_content("test_nofollow_symlink_target.txt", bytes); + let path = utils::prepare_with_content("test_nofollow_symlink_target.txt", b"Hello, World!\n"); let symlink_path = utils::prepare("test_nofollow_symlink.txt"); std::os::unix::fs::symlink(&path, &symlink_path).unwrap(); let symlink_cpath = CString::new(symlink_path.as_os_str().as_bytes()).unwrap(); - let ret = unsafe { libc::open(symlink_cpath.as_ptr(), libc::O_NOFOLLOW | libc::O_CLOEXEC) }; - assert_eq!(ret, -1); - let err = Error::last_os_error().raw_os_error().unwrap(); - assert_eq!(err, libc::ELOOP); + let err = errno_result(unsafe { + libc::open(symlink_cpath.as_ptr(), libc::O_NOFOLLOW | libc::O_CLOEXEC) + }) + .unwrap_err(); + assert_eq!(err.raw_os_error(), Some(libc::ELOOP)); } From 0d366e098c2b389a2e573056f02b07bd92b7bca4 Mon Sep 17 00:00:00 2001 From: SSD <96286755+the-ssd@users.noreply.github.com> Date: Fri, 2 Jan 2026 22:30:25 +0100 Subject: [PATCH 0206/1061] Fix a typo in `libm::Libm::roundeven` --- library/compiler-builtins/libm/src/libm_helper.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/libm_helper.rs b/library/compiler-builtins/libm/src/libm_helper.rs index dfa1ff77bf2e..0bb669398657 100644 --- a/library/compiler-builtins/libm/src/libm_helper.rs +++ b/library/compiler-builtins/libm/src/libm_helper.rs @@ -168,7 +168,7 @@ libm_helper! { (fn remquo(x: f64, y: f64) -> (f64, i32); => remquo); (fn rint(x: f64) -> (f64); => rint); (fn round(x: f64) -> (f64); => round); - (fn roundevem(x: f64) -> (f64); => roundeven); + (fn roundeven(x: f64) -> (f64); => roundeven); (fn scalbn(x: f64, n: i32) -> (f64); => scalbn); (fn sin(x: f64) -> (f64); => sin); (fn sincos(x: f64) -> (f64, f64); => sincos); From 7061adc5a40947521158bb848525717c632ef6b5 Mon Sep 17 00:00:00 2001 From: Coca Date: Fri, 2 Jan 2026 21:26:16 +0000 Subject: [PATCH 0207/1061] Add diagnostic items for `without_provenance` and `without_provenance_mut` Adds diagnostic items for `core::ptr::without_provenance` and `core::ptr::without_provenance_mut`. Will be used to enhance clippy lint `transmuting_null`, see https://github.com/rust-lang/rust-clippy/pull/16336. --- compiler/rustc_span/src/symbol.rs | 2 ++ library/core/src/ptr/mod.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 72709753b1df..c7ff28ccaffb 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1788,6 +1788,8 @@ symbols! { ptr_slice_from_raw_parts_mut, ptr_swap, ptr_swap_nonoverlapping, + ptr_without_provenance, + ptr_without_provenance_mut, ptr_write, ptr_write_bytes, ptr_write_unaligned, diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 29fe77390a16..335c5c6ee944 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -880,6 +880,7 @@ pub const fn null_mut() -> *mut T { #[must_use] #[stable(feature = "strict_provenance", since = "1.84.0")] #[rustc_const_stable(feature = "strict_provenance", since = "1.84.0")] +#[rustc_diagnostic_item = "ptr_without_provenance"] pub const fn without_provenance(addr: usize) -> *const T { without_provenance_mut(addr) } @@ -918,6 +919,7 @@ pub const fn dangling() -> *const T { #[must_use] #[stable(feature = "strict_provenance", since = "1.84.0")] #[rustc_const_stable(feature = "strict_provenance", since = "1.84.0")] +#[rustc_diagnostic_item = "ptr_without_provenance_mut"] #[allow(integer_to_ptr_transmutes)] // Expected semantics here. pub const fn without_provenance_mut(addr: usize) -> *mut T { // An int-to-pointer transmute currently has exactly the intended semantics: it creates a From c27addbc2b4e7db0b37f7bf6d4ffd7e633f8bfe4 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Fri, 2 Jan 2026 23:35:36 +0000 Subject: [PATCH 0208/1061] Prepare for merging from rust-lang/rust This updates the rust-version file to 85c8ff69cb3efd950395cc444a54bbbdad668865. --- src/doc/rustc-dev-guide/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index d32b6d0d2fc7..7b444a9ef5f1 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -7fefa09b90ca57b8a0e0e4717d672d38a0ae58b5 +85c8ff69cb3efd950395cc444a54bbbdad668865 From 3df06f5083ef6c44e7f49f6520d62adc1f05aa58 Mon Sep 17 00:00:00 2001 From: Ryan <63398895+rwardd@users.noreply.github.com> Date: Sat, 3 Jan 2026 10:53:54 +1030 Subject: [PATCH 0209/1061] fix: use `std::num::NonZero` instead of `extern crate` and extend information in `CHECK-` directives Co-authored-by: scottmcm --- .../issues/multiple-option-or-permutations.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/codegen-llvm/issues/multiple-option-or-permutations.rs b/tests/codegen-llvm/issues/multiple-option-or-permutations.rs index b45402f28a3a..0ea7ef9a0f7e 100644 --- a/tests/codegen-llvm/issues/multiple-option-or-permutations.rs +++ b/tests/codegen-llvm/issues/multiple-option-or-permutations.rs @@ -3,16 +3,15 @@ #![crate_type = "lib"] -extern crate core; -use core::num::NonZero; +use std::num::NonZero; // CHECK-LABEL: @or_match_u8 // CHECK-SAME: (i1{{.+}}%0, i8 %1, i1{{.+}}%optb.0, i8 %optb.1) #[no_mangle] pub fn or_match_u8(opta: Option, optb: Option) -> Option { // CHECK: start: - // CHECK-DAG: or i1 %0 // CHECK-DAG: select i1 %0 + // CHECK-DAG: or i1 %0 // CHECK-NEXT: insertvalue { i1, i8 } // CHECK-NEXT: insertvalue { i1, i8 } // ret { i1, i8 } @@ -27,8 +26,8 @@ pub fn or_match_u8(opta: Option, optb: Option) -> Option { #[no_mangle] pub fn or_match_alt_u8(opta: Option, optb: Option) -> Option { // CHECK: start: - // CHECK-DAG: select i1 - // CHECK-DAG: or i1 + // CHECK-DAG: select i1 %opta.0, i8 %opta.1, i8 %optb.1 + // CHECK-DAG: or i1 {{%opta.0, %optb.0|%optb.0, %opta.0}} // CHECK-NEXT: insertvalue { i1, i8 } // CHECK-NEXT: insertvalue { i1, i8 } // ret { i1, i8 } From cc563d531503b15576b147182f6880e75271195a Mon Sep 17 00:00:00 2001 From: AprilNEA Date: Fri, 2 Jan 2026 16:57:07 +0800 Subject: [PATCH 0210/1061] Remove unneeded `forbid_generic` field from `Res::SelfTyAlias` The `forbid_generic` field in `Res::SelfTyAlias` is no longer needed. The check for generic `Self` types in anonymous constants is now handled by `check_param_uses_if_mcg` in HIR type lowering, making this field redundant. This removes: - The `forbid_generic` field from `Res::SelfTyAlias` - The hack in `rustc_resolve` that set `forbid_generic: true` when encountering `Self` in constant items - Related pattern matching and field propagation code --- compiler/rustc_hir/src/def.rs | 31 ++-------- .../src/hir_ty_lowering/mod.rs | 2 +- compiler/rustc_resolve/src/ident.rs | 56 +++++++------------ compiler/rustc_resolve/src/late.rs | 9 +-- 4 files changed, 27 insertions(+), 71 deletions(-) diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 95abe5c40dd4..e93deaa84944 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -563,29 +563,6 @@ pub enum Res { /// to get the underlying type. alias_to: DefId, - /// Whether the `Self` type is disallowed from mentioning generics (i.e. when used in an - /// anonymous constant). - /// - /// HACK(min_const_generics): self types also have an optional requirement to **not** - /// mention any generic parameters to allow the following with `min_const_generics`: - /// ``` - /// # struct Foo; - /// impl Foo { fn test() -> [u8; size_of::()] { todo!() } } - /// - /// struct Bar([u8; baz::()]); - /// const fn baz() -> usize { 10 } - /// ``` - /// We do however allow `Self` in repeat expression even if it is generic to not break code - /// which already works on stable while causing the `const_evaluatable_unchecked` future - /// compat lint: - /// ``` - /// fn foo() { - /// let _bar = [1_u8; size_of::<*mut T>()]; - /// } - /// ``` - // FIXME(generic_const_exprs): Remove this bodge once that feature is stable. - forbid_generic: bool, - /// Is this within an `impl Foo for bar`? is_trait_impl: bool, }, @@ -910,8 +887,8 @@ impl Res { Res::PrimTy(id) => Res::PrimTy(id), Res::Local(id) => Res::Local(map(id)), Res::SelfTyParam { trait_ } => Res::SelfTyParam { trait_ }, - Res::SelfTyAlias { alias_to, forbid_generic, is_trait_impl } => { - Res::SelfTyAlias { alias_to, forbid_generic, is_trait_impl } + Res::SelfTyAlias { alias_to, is_trait_impl } => { + Res::SelfTyAlias { alias_to, is_trait_impl } } Res::ToolMod => Res::ToolMod, Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind), @@ -926,8 +903,8 @@ impl Res { Res::PrimTy(id) => Res::PrimTy(id), Res::Local(id) => Res::Local(map(id)?), Res::SelfTyParam { trait_ } => Res::SelfTyParam { trait_ }, - Res::SelfTyAlias { alias_to, forbid_generic, is_trait_impl } => { - Res::SelfTyAlias { alias_to, forbid_generic, is_trait_impl } + Res::SelfTyAlias { alias_to, is_trait_impl } => { + Res::SelfTyAlias { alias_to, is_trait_impl } } Res::ToolMod => Res::ToolMod, Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind), diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 48b2b80c8af3..7a11a808f83e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2149,7 +2149,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); self.check_param_uses_if_mcg(tcx.types.self_param, span, false) } - Res::SelfTyAlias { alias_to: def_id, forbid_generic: _, .. } => { + Res::SelfTyAlias { alias_to: def_id, .. } => { // `Self` in impl (we know the concrete type). assert_eq!(opt_self_ty, None); // Try to evaluate any array length constants. diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index f4a594a4731d..4d9702d9e0d5 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1332,7 +1332,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { &mut self, rib_index: usize, rib_ident: Ident, - mut res: Res, + res: Res, finalize: Option, original_rib_ident_def: Ident, all_ribs: &[Rib<'ra>], @@ -1485,44 +1485,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } RibKind::ConstantItem(trivial, _) => { - if let ConstantHasGenerics::No(cause) = trivial { - // HACK(min_const_generics): If we encounter `Self` in an anonymous - // constant we can't easily tell if it's generic at this stage, so - // we instead remember this and then enforce the self type to be - // concrete later on. - if let Res::SelfTyAlias { - alias_to: def, - forbid_generic: _, - is_trait_impl, - } = res - { - res = Res::SelfTyAlias { - alias_to: def, - forbid_generic: true, - is_trait_impl, - } - } else { - if let Some(span) = finalize { - let error = match cause { - NoConstantGenericsReason::IsEnumDiscriminant => { - ResolutionError::ParamInEnumDiscriminant { - name: rib_ident.name, - param_kind: ParamKindInEnumDiscriminant::Type, - } + if let ConstantHasGenerics::No(cause) = trivial + && !matches!(res, Res::SelfTyAlias { .. }) + { + if let Some(span) = finalize { + let error = match cause { + NoConstantGenericsReason::IsEnumDiscriminant => { + ResolutionError::ParamInEnumDiscriminant { + name: rib_ident.name, + param_kind: ParamKindInEnumDiscriminant::Type, } - NoConstantGenericsReason::NonTrivialConstArg => { - ResolutionError::ParamInNonTrivialAnonConst { - name: rib_ident.name, - param_kind: - ParamKindInNonTrivialAnonConst::Type, - } + } + NoConstantGenericsReason::NonTrivialConstArg => { + ResolutionError::ParamInNonTrivialAnonConst { + name: rib_ident.name, + param_kind: ParamKindInNonTrivialAnonConst::Type, } - }; - let _: ErrorGuaranteed = self.report_error(span, error); - } - - return Res::Err; + } + }; + let _: ErrorGuaranteed = self.report_error(span, error); } + + return Res::Err; } continue; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index dd80f5da508c..2630e2c811f7 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2655,11 +2655,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { |this| { let item_def_id = this.r.local_def_id(item.id).to_def_id(); this.with_self_rib( - Res::SelfTyAlias { - alias_to: item_def_id, - forbid_generic: false, - is_trait_impl: false, - }, + Res::SelfTyAlias { alias_to: item_def_id, is_trait_impl: false }, |this| { visit::walk_item(this, item); }, @@ -3368,8 +3364,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { let item_def_id = item_def_id.to_def_id(); let res = Res::SelfTyAlias { alias_to: item_def_id, - forbid_generic: false, - is_trait_impl: trait_id.is_some() + is_trait_impl: trait_id.is_some(), }; this.with_self_rib(res, |this| { if let Some(of_trait) = of_trait { From 3fc32260694a0e71484ba5251bc4e9c22f74bac7 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Sat, 3 Jan 2026 10:24:02 +0900 Subject: [PATCH 0211/1061] Move `pattern_types` and `unqualified_local_imports` to the tracking issue group --- compiler/rustc_feature/src/unstable.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 94e861787fc6..f64702fc44b0 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -239,8 +239,6 @@ declare_features! ( (internal, negative_bounds, "1.71.0", None), /// Set the maximum pattern complexity allowed (not limited by default). (internal, pattern_complexity_limit, "1.78.0", None), - /// Allows using pattern types. - (internal, pattern_types, "1.79.0", Some(123646)), /// Allows using `#[prelude_import]` on glob `use` items. (internal, prelude_import, "1.2.0", None), /// Used to identify crates that contain the profiler runtime. @@ -251,8 +249,6 @@ declare_features! ( (internal, staged_api, "1.0.0", None), /// Added for testing unstable lints; perma-unstable. (internal, test_unstable_lint, "1.60.0", None), - /// Helps with formatting for `group_imports = "StdExternalCrate"`. - (unstable, unqualified_local_imports, "1.83.0", Some(138299)), /// Use for stable + negative coherence and strict coherence depending on trait's /// rustc_strict_coherence value. (unstable, with_negative_coherence, "1.60.0", None), @@ -293,6 +289,8 @@ declare_features! ( (internal, needs_panic_runtime, "1.10.0", Some(32837)), /// Allows using the `#![panic_runtime]` attribute. (internal, panic_runtime, "1.10.0", Some(32837)), + /// Allows using pattern types. + (internal, pattern_types, "1.79.0", Some(123646)), /// Allows using `#[rustc_allow_const_fn_unstable]`. /// This is an attribute on `const fn` for the same /// purpose as `#[allow_internal_unstable]`. @@ -311,6 +309,8 @@ declare_features! ( (unstable, structural_match, "1.8.0", Some(31434)), /// Allows using the `rust-call` ABI. (unstable, unboxed_closures, "1.0.0", Some(29625)), + /// Helps with formatting for `group_imports = "StdExternalCrate"`. + (unstable, unqualified_local_imports, "1.83.0", Some(138299)), // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way. // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! From a2fcb0de187664d27aa6c312585bcf64ff1c909a Mon Sep 17 00:00:00 2001 From: Ryan Ward Date: Sat, 3 Jan 2026 12:50:38 +1030 Subject: [PATCH 0212/1061] fix: add `CHECK` directives to `ret` comments and be more pervasive with directive contents --- .../issues/multiple-option-or-permutations.rs | 88 +++++++++---------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/tests/codegen-llvm/issues/multiple-option-or-permutations.rs b/tests/codegen-llvm/issues/multiple-option-or-permutations.rs index 0ea7ef9a0f7e..9ec4ec8eeb15 100644 --- a/tests/codegen-llvm/issues/multiple-option-or-permutations.rs +++ b/tests/codegen-llvm/issues/multiple-option-or-permutations.rs @@ -10,11 +10,11 @@ use std::num::NonZero; #[no_mangle] pub fn or_match_u8(opta: Option, optb: Option) -> Option { // CHECK: start: - // CHECK-DAG: select i1 %0 - // CHECK-DAG: or i1 %0 - // CHECK-NEXT: insertvalue { i1, i8 } - // CHECK-NEXT: insertvalue { i1, i8 } - // ret { i1, i8 } + // CHECK-DAG: [[A_OR_B:%.+]] = select i1 %0, i8 %1, i8 %optb.1 + // CHECK-DAG: [[IS_SOME:%.+]] = or i1 {{%0, %optb.0|%optb.0, %0}} + // CHECK-NEXT: [[FLAG:%.+]] = insertvalue { i1, i8 } poison, i1 [[IS_SOME]], 0 + // CHECK-NEXT: [[R:%.+]] = insertvalue { i1, i8 } [[FLAG]], i8 [[A_OR_B]], 1 + // CHECK: ret { i1, i8 } [[R]] match opta { Some(x) => Some(x), None => optb, @@ -26,11 +26,11 @@ pub fn or_match_u8(opta: Option, optb: Option) -> Option { #[no_mangle] pub fn or_match_alt_u8(opta: Option, optb: Option) -> Option { // CHECK: start: - // CHECK-DAG: select i1 %opta.0, i8 %opta.1, i8 %optb.1 - // CHECK-DAG: or i1 {{%opta.0, %optb.0|%optb.0, %opta.0}} - // CHECK-NEXT: insertvalue { i1, i8 } - // CHECK-NEXT: insertvalue { i1, i8 } - // ret { i1, i8 } + // CHECK-DAG: [[A_OR_B:%.+]] = select i1 %opta.0, i8 %opta.1, i8 %optb.1 + // CHECK-DAG: [[IS_SOME:%.+]] = or i1 {{%opta.0, %optb.0|%optb.0, %opta.0}} + // CHECK-NEXT: [[FLAG:%.+]] = insertvalue { i1, i8 } poison, i1 [[IS_SOME]], 0 + // CHECK-NEXT: [[R:%.+]] = insertvalue { i1, i8 } [[FLAG]], i8 [[A_OR_B]], 1 + // CHECK: ret { i1, i8 } [[R]] match opta { Some(_) => opta, None => optb, @@ -42,11 +42,11 @@ pub fn or_match_alt_u8(opta: Option, optb: Option) -> Option { #[no_mangle] pub fn option_or_u8(opta: Option, optb: Option) -> Option { // CHECK: start: - // CHECK-DAG: select i1 - // CHECK-DAG: or i1 - // CHECK-NEXT: insertvalue { i1, i8 } - // CHECK-NEXT: insertvalue { i1, i8 } - // ret { i1, i8 } + // CHECK-DAG: [[A_OR_B:%.+]] = select i1 %opta.0, i8 %opta.1, i8 %optb.1 + // CHECK-DAG: [[IS_SOME:%.+]] = or i1 {{%opta.0, %optb.0|%optb.0, %opta.0}} + // CHECK-NEXT: [[FLAG:%.+]] = insertvalue { i1, i8 } poison, i1 [[IS_SOME]], 0 + // CHECK-NEXT: [[R:%.+]] = insertvalue { i1, i8 } [[FLAG]], i8 [[A_OR_B]], 1 + // CHECK: ret { i1, i8 } [[R]] opta.or(optb) } @@ -55,11 +55,11 @@ pub fn option_or_u8(opta: Option, optb: Option) -> Option { #[no_mangle] pub fn if_some_u8(opta: Option, optb: Option) -> Option { // CHECK: start: - // CHECK-DAG: select i1 - // CHECK-DAG: or i1 - // CHECK-NEXT: insertvalue { i1, i8 } - // CHECK-NEXT: insertvalue { i1, i8 } - // ret { i1, i8 } + // CHECK-DAG: [[A_OR_B:%.+]] = select i1 %opta.0, i8 %opta.1, i8 %optb.1 + // CHECK-DAG: [[IS_SOME:%.+]] = or i1 {{%opta.0, %optb.0|%optb.0, %opta.0}} + // CHECK-NEXT: [[FLAG:%.+]] = insertvalue { i1, i8 } poison, i1 [[IS_SOME]], 0 + // CHECK-NEXT: [[R:%.+]] = insertvalue { i1, i8 } [[FLAG]], i8 [[A_OR_B]], 1 + // CHECK: ret { i1, i8 } [[R]] if opta.is_some() { opta } else { optb } } @@ -70,9 +70,9 @@ pub fn if_some_u8(opta: Option, optb: Option) -> Option { #[no_mangle] pub fn or_match_slice_u8(opta: Option<[u8; 1]>, optb: Option<[u8; 1]>) -> Option<[u8; 1]> { // CHECK: start: - // CHECK-NEXT: trunc i16 %0 to i1 - // CHECK-NEXT: select i1 %2, i16 %0, i16 %1 - // ret i16 + // CHECK-NEXT: [[SOME_A:%.+]] = trunc i16 %0 to i1 + // CHECK-NEXT: [[R:%.+]] = select i1 [[SOME_A]], i16 %0, i16 %1 + // CHECK: ret i16 [[R]] match opta { Some(x) => Some(x), None => optb, @@ -84,9 +84,9 @@ pub fn or_match_slice_u8(opta: Option<[u8; 1]>, optb: Option<[u8; 1]>) -> Option #[no_mangle] pub fn or_match_slice_alt_u8(opta: Option<[u8; 1]>, optb: Option<[u8; 1]>) -> Option<[u8; 1]> { // CHECK: start: - // CHECK-NEXT: trunc i16 %0 to i1 - // CHECK-NEXT: select i1 %2, i16 %0, i16 %1 - // ret i16 + // CHECK-NEXT: [[SOME_A:%.+]] = trunc i16 %0 to i1 + // CHECK-NEXT: [[R:%.+]] = select i1 [[SOME_A]], i16 %0, i16 %1 + // CHECK: ret i16 [[R]] match opta { Some(_) => opta, None => optb, @@ -98,9 +98,9 @@ pub fn or_match_slice_alt_u8(opta: Option<[u8; 1]>, optb: Option<[u8; 1]>) -> Op #[no_mangle] pub fn option_or_slice_u8(opta: Option<[u8; 1]>, optb: Option<[u8; 1]>) -> Option<[u8; 1]> { // CHECK: start: - // CHECK-NEXT: trunc i16 %0 to i1 - // CHECK-NEXT: select i1 %2, i16 %0, i16 %1 - // ret i16 + // CHECK-NEXT: [[SOME_A:%.+]] = trunc i16 %0 to i1 + // CHECK-NEXT: [[R:%.+]] = select i1 [[SOME_A]], i16 %0, i16 %1 + // CHECK: ret i16 [[R]] opta.or(optb) } @@ -109,9 +109,9 @@ pub fn option_or_slice_u8(opta: Option<[u8; 1]>, optb: Option<[u8; 1]>) -> Optio #[no_mangle] pub fn if_some_slice_u8(opta: Option<[u8; 1]>, optb: Option<[u8; 1]>) -> Option<[u8; 1]> { // CHECK: start: - // CHECK-NEXT: trunc i16 %0 to i1 - // CHECK-NEXT: select i1 %2, i16 %0, i16 %1 - // ret i16 + // CHECK-NEXT: [[SOME_A:%.+]] = trunc i16 %0 to i1 + // CHECK-NEXT: [[R:%.+]] = select i1 [[SOME_A]], i16 %0, i16 %1 + // CHECK: ret i16 [[R]] if opta.is_some() { opta } else { optb } } @@ -122,9 +122,9 @@ pub fn if_some_slice_u8(opta: Option<[u8; 1]>, optb: Option<[u8; 1]>) -> Option< #[no_mangle] pub fn or_match_nz_u8(opta: Option>, optb: Option>) -> Option> { // CHECK: start: - // CHECK-NEXT: [[NOT_A:%.*]] = icmp eq i8 %0, 0 - // CHECK-NEXT: select i1 [[NOT_A]], i8 %optb, i8 %0 - // ret i8 + // CHECK-NEXT: [[NOT_A:%.+]] = icmp eq i8 %0, 0 + // CHECK-NEXT: [[R:%.+]] = select i1 [[NOT_A]], i8 %optb, i8 %0 + // CHECK: ret i8 [[R]] match opta { Some(x) => Some(x), None => optb, @@ -139,9 +139,9 @@ pub fn or_match_alt_nz_u8( optb: Option>, ) -> Option> { // CHECK: start: - // CHECK-NEXT: [[NOT_A:%.*]] = icmp eq i8 %opta, 0 - // CHECK-NEXT: select i1 [[NOT_A]], i8 %optb, i8 %opta - // ret i8 + // CHECK-NEXT: [[NOT_A:%.+]] = icmp eq i8 %opta, 0 + // CHECK-NEXT: [[R:%.+]] = select i1 [[NOT_A]], i8 %optb, i8 %opta + // CHECK: ret i8 [[R]] match opta { Some(_) => opta, None => optb, @@ -156,9 +156,9 @@ pub fn option_or_nz_u8( optb: Option>, ) -> Option> { // CHECK: start: - // CHECK-NEXT: [[NOT_A:%.*]] = icmp eq i8 %opta, 0 - // CHECK-NEXT: select i1 [[NOT_A]], i8 %optb, i8 %opta - // ret i8 + // CHECK-NEXT: [[NOT_A:%.+]] = icmp eq i8 %opta, 0 + // CHECK-NEXT: [[R:%.+]] = select i1 [[NOT_A]], i8 %optb, i8 %opta + // CHECK: ret i8 [[R]] opta.or(optb) } @@ -167,8 +167,8 @@ pub fn option_or_nz_u8( #[no_mangle] pub fn if_some_nz_u8(opta: Option>, optb: Option>) -> Option> { // CHECK: start: - // CHECK-NEXT: [[NOT_A:%.*]] = icmp eq i8 %opta, 0 - // CHECK-NEXT: select i1 [[NOT_A]], i8 %optb, i8 %opta - // ret i8 + // CHECK-NEXT: [[NOT_A:%.+]] = icmp eq i8 %opta, 0 + // CHECK-NEXT: [[R:%.+]] = select i1 [[NOT_A]], i8 %optb, i8 %opta + // CHECK: ret i8 [[R]] if opta.is_some() { opta } else { optb } } From 6326896b0c42eea27125b78fbed455a035e5e064 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sat, 3 Jan 2026 09:12:32 +0530 Subject: [PATCH 0213/1061] emit same info via localfilename and filename --- .../rust-analyzer/crates/load-cargo/src/lib.rs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index 023253f23f42..4ffc8383b620 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -563,20 +563,10 @@ impl ProcMacroExpander for Expander { let source_root_id = db.file_source_root(file).source_root_id(db); let source_root = db.source_root(source_root_id).source_root(db); - let path = source_root.path_for_file(&file); - - let name = path - .and_then(|p| p.as_path()) - .and_then(|p| p.file_name()) - .map(|n| n.to_owned()) - .or_else(|| { - path.and_then(|p| { - p.name_and_extension().map(|(name, ext)| match ext { - Some(ext) => format!("{name}.{ext}"), - None => name.into(), - }) - }) - }) + let name = source_root + .path_for_file(&file) + .and_then(|path| path.as_path()) + .and_then(|path| path.file_name().map(|filename| filename.to_owned())) .unwrap_or_default(); Ok(SubResponse::FileNameResult { name }) From b80a3ea6d689e4cd6b619c67cfac1c630de67e2f Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sat, 3 Jan 2026 04:57:40 +0000 Subject: [PATCH 0214/1061] Prepare for merging from rust-lang/rust This updates the rust-version file to e8f3cfc0de70bf82583591f6656e1fba3140253e. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index d32b6d0d2fc7..f22aff761e8d 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -7fefa09b90ca57b8a0e0e4717d672d38a0ae58b5 +e8f3cfc0de70bf82583591f6656e1fba3140253e From a8c23c86f01b0f8f9408ffed8ca0688453223f92 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 2 Jan 2026 23:03:51 -0500 Subject: [PATCH 0215/1061] triagebot: Add a mention for `dec2flt`, `flt2dec`, and `fmt/num` --- triagebot.toml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index fb6660b9dd03..fbb2bac2267b 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1059,6 +1059,18 @@ gets adapted for the changes, if necessary. """ cc = ["@rust-lang/miri", "@RalfJung", "@oli-obk", "@lcnr"] +[mentions."library/core/src/num/dec2flt"] +message = "Some changes occurred in float parsing" +cc = ["@tgross35"] + +[mentions."library/core/src/num/flt2dec"] +message = "Some changes occurred in float printing" +cc = ["@tgross35"] + +[mentions."library/core/src/fmt/num.rs"] +message = "Some changes occurred in integer formatting" +cc = ["@tgross35"] + [mentions."library/portable-simd"] message = """ Portable SIMD is developed in its own repository. If possible, consider \ From d79fa3ca3d8768077766bf9109225a65cb01e600 Mon Sep 17 00:00:00 2001 From: vsriram Date: Sat, 3 Jan 2026 12:58:36 +0530 Subject: [PATCH 0216/1061] Fixed edit-url-template by pointing to main instead of HEAD in both unstable book and the rustc book --- src/doc/rustc/book.toml | 2 +- src/doc/unstable-book/book.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc/book.toml b/src/doc/rustc/book.toml index 9a7c28525f0e..565f6247dcb2 100644 --- a/src/doc/rustc/book.toml +++ b/src/doc/rustc/book.toml @@ -3,7 +3,7 @@ title = "The rustc book" [output.html] git-repository-url = "https://github.com/rust-lang/rust/tree/HEAD/src/doc/rustc" -edit-url-template = "https://github.com/rust-lang/rust/edit/HEAD/src/doc/rustc/{path}" +edit-url-template = "https://github.com/rust-lang/rust/edit/main/src/doc/rustc/{path}" [output.html.search] use-boolean-and = true diff --git a/src/doc/unstable-book/book.toml b/src/doc/unstable-book/book.toml index c357949f6c2e..8a3d11499cdd 100644 --- a/src/doc/unstable-book/book.toml +++ b/src/doc/unstable-book/book.toml @@ -3,4 +3,4 @@ title = "The Rust Unstable Book" [output.html] git-repository-url = "https://github.com/rust-lang/rust/tree/HEAD/src/doc/unstable-book" -edit-url-template = "https://github.com/rust-lang/rust/edit/HEAD/src/doc/unstable-book/{path}" +edit-url-template = "https://github.com/rust-lang/rust/edit/main/src/doc/unstable-book/{path}" From c56c36ea7d1e0f15c41bfaf0dfe62b8e7954758e Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sat, 3 Jan 2026 14:58:47 +0530 Subject: [PATCH 0217/1061] use fullpath instead of filename --- src/tools/rust-analyzer/crates/load-cargo/src/lib.rs | 12 ++++++------ .../proc-macro-api/src/bidirectional_protocol/msg.rs | 8 ++++---- .../crates/proc-macro-srv-cli/src/main_loop.rs | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index 4ffc8383b620..e01ce0b129da 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -540,7 +540,7 @@ impl ProcMacroExpander for Expander { current_dir: String, ) -> Result { let mut cb = |req| match req { - SubRequest::LocalFileName { file_id } => { + SubRequest::LocalFilePath { file_id } => { let file = FileId::from_raw(file_id); let source_root_id = db.file_source_root(file).source_root_id(db); let source_root = db.source_root(source_root_id).source_root(db); @@ -548,9 +548,9 @@ impl ProcMacroExpander for Expander { let name = source_root .path_for_file(&file) .and_then(|path| path.as_path()) - .and_then(|path| path.file_name().map(|filename| filename.to_owned())); + .map(|path| path.to_string()); - Ok(SubResponse::LocalFileNameResult { name }) + Ok(SubResponse::LocalFilePathResult { name }) } SubRequest::SourceText { file_id, start, end } => { let file = FileId::from_raw(file_id); @@ -558,7 +558,7 @@ impl ProcMacroExpander for Expander { let slice = text.get(start as usize..end as usize).map(ToOwned::to_owned); Ok(SubResponse::SourceTextResult { text: slice }) } - SubRequest::FileName { file_id } => { + SubRequest::FilePath { file_id } => { let file = FileId::from_raw(file_id); let source_root_id = db.file_source_root(file).source_root_id(db); let source_root = db.source_root(source_root_id).source_root(db); @@ -566,10 +566,10 @@ impl ProcMacroExpander for Expander { let name = source_root .path_for_file(&file) .and_then(|path| path.as_path()) - .and_then(|path| path.file_name().map(|filename| filename.to_owned())) + .map(|path| path.to_string()) .unwrap_or_default(); - Ok(SubResponse::FileNameResult { name }) + Ok(SubResponse::FilePathResult { name }) } }; match self.0.expand( diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs index 2819a92fe33a..558954f7619d 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs @@ -10,16 +10,16 @@ use crate::{ #[derive(Debug, Serialize, Deserialize)] pub enum SubRequest { - FileName { file_id: u32 }, + FilePath { file_id: u32 }, SourceText { file_id: u32, start: u32, end: u32 }, - LocalFileName { file_id: u32 }, + LocalFilePath { file_id: u32 }, } #[derive(Debug, Serialize, Deserialize)] pub enum SubResponse { - FileNameResult { name: String }, + FilePathResult { name: String }, SourceTextResult { text: Option }, - LocalFileNameResult { name: Option }, + LocalFilePathResult { name: Option }, } #[derive(Debug, Serialize, Deserialize)] diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs index 77cb8760a100..8fe3e93e4702 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs @@ -186,9 +186,9 @@ impl<'a, C: Codec> ProcMacroClientHandle<'a, C> { impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandle<'_, C> { fn file(&mut self, file_id: u32) -> String { - match self.roundtrip(bidirectional::SubRequest::FileName { file_id }) { + match self.roundtrip(bidirectional::SubRequest::FilePath { file_id }) { Some(bidirectional::BidirectionalMessage::SubResponse( - bidirectional::SubResponse::FileNameResult { name }, + bidirectional::SubResponse::FilePathResult { name }, )) => name, _ => String::new(), } @@ -204,9 +204,9 @@ impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandl } fn local_file(&mut self, file_id: u32) -> Option { - match self.roundtrip(bidirectional::SubRequest::LocalFileName { file_id }) { + match self.roundtrip(bidirectional::SubRequest::LocalFilePath { file_id }) { Some(bidirectional::BidirectionalMessage::SubResponse( - bidirectional::SubResponse::LocalFileNameResult { name }, + bidirectional::SubResponse::LocalFilePathResult { name }, )) => name, _ => None, } From 7af3130d257bf06c4cb4ff4e160d69d8180b9c60 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 3 Jan 2026 10:47:41 +0100 Subject: [PATCH 0218/1061] perf: Only compute lang items for `#![feature(lang_items)]` crates --- .../crates/hir-def/src/lang_item.rs | 4 ++ .../crates/hir-ty/src/consteval/tests.rs | 3 ++ .../crates/hir-ty/src/tests/incremental.rs | 37 +++---------------- .../crates/hir-ty/src/tests/patterns.rs | 19 ++++++---- .../crates/hir-ty/src/tests/regression.rs | 1 + .../hir-ty/src/tests/regression/new_solver.rs | 1 + .../crates/hir-ty/src/tests/simple.rs | 36 ++++++++++-------- .../ide-completion/src/tests/flyimport.rs | 2 +- .../handlers/trait_impl_incorrect_safety.rs | 1 + .../crates/ide/src/hover/tests.rs | 1 + .../crates/ide/src/inlay_hints/bounds.rs | 2 +- .../crates/intern/src/symbol/symbols.rs | 1 + .../crates/test-utils/src/minicore.rs | 1 + 13 files changed, 51 insertions(+), 58 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index d3f4480b207e..eba4d87ec9f8 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -40,6 +40,10 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option i32 { "trait_environment_query", "lang_items", "crate_lang_items", - "AttrFlags::query_", - "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", "expr_scopes_shim", "InferenceResult::for_body_", "function_signature_shim", "function_signature_with_source_map_shim", + "AttrFlags::query_", "body_shim", "body_with_source_map_shim", "trait_environment_query", @@ -149,6 +148,7 @@ fn baz() -> i32 { "InferenceResult::for_body_", "function_signature_shim", "function_signature_with_source_map_shim", + "AttrFlags::query_", "body_shim", "body_with_source_map_shim", "trait_environment_query", @@ -197,13 +197,13 @@ fn baz() -> i32 { "body_with_source_map_shim", "body_shim", "AttrFlags::query_", - "AttrFlags::query_", "function_signature_with_source_map_shim", "function_signature_shim", "body_with_source_map_shim", "body_shim", "InferenceResult::for_body_", "expr_scopes_shim", + "AttrFlags::query_", "function_signature_with_source_map_shim", "function_signature_shim", "body_with_source_map_shim", @@ -245,8 +245,6 @@ $0", "TraitImpls::for_crate_", "lang_items", "crate_lang_items", - "AttrFlags::query_", - "AttrFlags::query_", ] "#]], ); @@ -284,9 +282,6 @@ pub struct NewStruct { "crate_local_def_map", "TraitImpls::for_crate_", "crate_lang_items", - "AttrFlags::query_", - "AttrFlags::query_", - "AttrFlags::query_", ] "#]], ); @@ -324,8 +319,6 @@ $0", "TraitImpls::for_crate_", "lang_items", "crate_lang_items", - "AttrFlags::query_", - "AttrFlags::query_", ] "#]], ); @@ -364,12 +357,6 @@ pub enum SomeEnum { "crate_local_def_map", "TraitImpls::for_crate_", "crate_lang_items", - "AttrFlags::query_", - "AttrFlags::query_", - "AttrFlags::query_", - "EnumVariants::of_", - "AttrFlags::query_", - "AttrFlags::query_", ] "#]], ); @@ -407,8 +394,6 @@ $0", "TraitImpls::for_crate_", "lang_items", "crate_lang_items", - "AttrFlags::query_", - "AttrFlags::query_", ] "#]], ); @@ -444,8 +429,6 @@ fn bar() -> f32 { "crate_local_def_map", "TraitImpls::for_crate_", "crate_lang_items", - "AttrFlags::query_", - "AttrFlags::query_", ] "#]], ); @@ -487,9 +470,6 @@ $0", "TraitImpls::for_crate_", "lang_items", "crate_lang_items", - "AttrFlags::query_", - "AttrFlags::query_", - "AttrFlags::query_", ] "#]], ); @@ -533,12 +513,6 @@ impl SomeStruct { "crate_local_def_map", "TraitImpls::for_crate_", "crate_lang_items", - "AttrFlags::query_", - "ImplItems::of_", - "AttrFlags::query_", - "AttrFlags::query_", - "AttrFlags::query_", - "AttrFlags::query_", ] "#]], ); @@ -610,7 +584,6 @@ fn main() { "trait_environment_query", "lang_items", "crate_lang_items", - "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", @@ -623,6 +596,7 @@ fn main() { "expr_scopes_shim", "struct_signature_shim", "struct_signature_with_source_map_shim", + "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", "value_ty_query", "InherentImpls::for_crate_", @@ -702,8 +676,6 @@ fn main() { "body_with_source_map_shim", "body_shim", "crate_lang_items", - "AttrFlags::query_", - "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", @@ -713,6 +685,7 @@ fn main() { "ImplTraits::return_type_impl_traits_", "expr_scopes_shim", "struct_signature_with_source_map_shim", + "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", "InherentImpls::for_crate_", "callable_item_signature_query", diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs index c312b167596f..0b776938c5b3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs @@ -794,6 +794,8 @@ fn slice_tail_pattern() { fn box_pattern() { check_infer( r#" + #![feature(lang_items)] + pub struct Global; #[lang = "owned_box"] pub struct Box(T); @@ -805,13 +807,13 @@ fn box_pattern() { } "#, expect![[r#" - 83..89 'params': Box - 101..155 '{ ... } }': () - 107..153 'match ... }': () - 113..119 'params': Box - 130..141 'box integer': Box - 134..141 'integer': i32 - 145..147 '{}': () + 108..114 'params': Box + 126..180 '{ ... } }': () + 132..178 'match ... }': () + 138..144 'params': Box + 155..166 'box integer': Box + 159..166 'integer': i32 + 170..172 '{}': () "#]], ); check_infer( @@ -831,7 +833,6 @@ fn box_pattern() { 76..122 'match ... }': () 82..88 'params': Box 99..110 'box integer': Box - 103..110 'integer': i32 114..116 '{}': () "#]], ); @@ -1142,6 +1143,7 @@ fn my_fn(#[cfg(feature = "feature")] u8: u8, u32: u32) {} fn var_args() { check_types( r#" +#![feature(lang_items)] #[lang = "va_list"] pub struct VaListImpl<'f>; fn my_fn(foo: ...) {} @@ -1156,6 +1158,7 @@ fn my_fn2(bar: u32, foo: ...) {} fn var_args_cond() { check_types( r#" +#![feature(lang_items)] #[lang = "va_list"] pub struct VaListImpl<'f>; fn my_fn(bar: u32, #[cfg(FALSE)] foo: ..., #[cfg(not(FALSE))] foo: u32) { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index f03f8d754f2a..c805f030446c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -2374,6 +2374,7 @@ fn rust_destruct_option_clone() { check_types( r#" //- minicore: option, drop +#![feature(lang_items)] fn test(o: &Option) { o.my_clone(); //^^^^^^^^^^^^ Option diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs index e11cc85e7ff1..a4554673cdd5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs @@ -234,6 +234,7 @@ fn main() { // toolchains <= 1.88.0, before sized-hierarchy. check_no_mismatches( r#" +#![feature(lang_items)] #[lang = "sized"] pub trait Sized {} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs index db557b75071f..6367521841ab 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs @@ -2702,6 +2702,8 @@ fn box_into_vec() { check_infer( r#" //- /core.rs crate:core +#![feature(lang_items)] + #[lang = "sized"] pub trait Sized {} @@ -2745,22 +2747,22 @@ struct Astruct; impl B for Astruct {} "#, expect![[r#" - 614..618 'self': Box<[T], A> - 647..679 '{ ... }': Vec - 693..863 '{ ...])); }': () - 703..706 'vec': Vec - 709..724 '<[_]>::into_vec': fn into_vec(Box<[i32], Global>) -> Vec - 709..755 '<[_]>:...i32]))': Vec - 725..754 '#[rust...1i32])': Box<[i32; 1], Global> - 747..753 '[1i32]': [i32; 1] - 748..752 '1i32': i32 - 765..766 'v': Vec, Global> - 786..803 '<[_]> ...to_vec': fn into_vec, Global>(Box<[Box], Global>) -> Vec, Global> - 786..860 '<[_]> ...ct)]))': Vec, Global> - 804..859 '#[rust...uct)])': Box<[Box; 1], Global> - 826..858 '[#[rus...ruct)]': [Box; 1] - 827..857 '#[rust...truct)': Box - 849..856 'Astruct': Astruct + 639..643 'self': Box<[T], A> + 672..704 '{ ... }': Vec + 718..888 '{ ...])); }': () + 728..731 'vec': Vec + 734..749 '<[_]>::into_vec': fn into_vec(Box<[i32], Global>) -> Vec + 734..780 '<[_]>:...i32]))': Vec + 750..779 '#[rust...1i32])': Box<[i32; 1], Global> + 772..778 '[1i32]': [i32; 1] + 773..777 '1i32': i32 + 790..791 'v': Vec, Global> + 811..828 '<[_]> ...to_vec': fn into_vec, Global>(Box<[Box], Global>) -> Vec, Global> + 811..885 '<[_]> ...ct)]))': Vec, Global> + 829..884 '#[rust...uct)])': Box<[Box; 1], Global> + 851..883 '[#[rus...ruct)]': [Box; 1] + 852..882 '#[rust...truct)': Box + 874..881 'Astruct': Astruct "#]], ) } @@ -3647,6 +3649,8 @@ fn main() { fn cstring_literals() { check_types( r#" +#![feature(lang_items)] + #[lang = "CStr"] pub struct CStr; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs index 2912457da1f7..797df3f163da 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs @@ -781,9 +781,9 @@ fn main() { } "#, expect![[r#" - me random_method(…) (use dep::test_mod::TestTrait) fn(&self) DEPRECATED ct SPECIAL_CONST (use dep::test_mod::TestTrait) u8 DEPRECATED fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED + me random_method(…) (use dep::test_mod::TestTrait) fn(&self) DEPRECATED "#]], ); } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs index 3414e972d5c9..c5b2f499d306 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs @@ -64,6 +64,7 @@ unsafe trait Unsafe {} fn drop_may_dangle() { check_diagnostics( r#" +#![feature(lang_items)] #[lang = "drop"] trait Drop {} struct S; diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index f42d3cf0dc41..0b518021e39e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -4089,6 +4089,7 @@ fn foo() { let fo$0o = async { S }; } //- /core.rs crate:core +#![feature(lang_items)] pub mod future { #[lang = "future_trait"] pub trait Future {} diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs index c9fbdf3ae754..045559fd7f46 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs @@ -143,7 +143,7 @@ fn foo() {} file_id: FileId( 1, ), - range: 446..451, + range: 470..475, }, ), ), diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index 3e325b2f990d..b6efc599f181 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -297,6 +297,7 @@ define_symbols! { iterator, keyword, lang, + lang_items, le, Left, len, diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index b7c09391ec37..01274a9835f4 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -80,6 +80,7 @@ //! offset_of: #![rustc_coherence_is_core] +#![feature(lang_items)] pub mod marker { // region:sized From 0e5a4fb302aafc1b1a0677b7ffb7eb57d8cea9ab Mon Sep 17 00:00:00 2001 From: joboet Date: Sat, 3 Jan 2026 11:46:06 +0100 Subject: [PATCH 0219/1061] std: remove manual bindings on NetBSD --- .../std/src/sys/pal/unix/thread_parking.rs | 21 ++++--------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/library/std/src/sys/pal/unix/thread_parking.rs b/library/std/src/sys/pal/unix/thread_parking.rs index bef8b4fb3639..6c3d04ceab21 100644 --- a/library/std/src/sys/pal/unix/thread_parking.rs +++ b/library/std/src/sys/pal/unix/thread_parking.rs @@ -2,24 +2,11 @@ // separate modules for each platform. #![cfg(target_os = "netbsd")] -use libc::{_lwp_self, CLOCK_MONOTONIC, c_long, clockid_t, lwpid_t, time_t, timespec}; +use libc::{_lwp_park, _lwp_self, _lwp_unpark, CLOCK_MONOTONIC, c_long, lwpid_t, time_t, timespec}; -use crate::ffi::{c_int, c_void}; use crate::ptr; use crate::time::Duration; -unsafe extern "C" { - fn ___lwp_park60( - clock_id: clockid_t, - flags: c_int, - ts: *mut timespec, - unpark: lwpid_t, - hint: *const c_void, - unparkhint: *const c_void, - ) -> c_int; - fn _lwp_unpark(lwp: lwpid_t, hint: *const c_void) -> c_int; -} - pub type ThreadId = lwpid_t; #[inline] @@ -30,7 +17,7 @@ pub fn current() -> ThreadId { #[inline] pub fn park(hint: usize) { unsafe { - ___lwp_park60(0, 0, ptr::null_mut(), 0, ptr::without_provenance(hint), ptr::null()); + _lwp_park(0, 0, ptr::null_mut(), 0, ptr::without_provenance(hint), ptr::null_mut()); } } @@ -45,13 +32,13 @@ pub fn park_timeout(dur: Duration, hint: usize) { // Timeout needs to be mutable since it is modified on NetBSD 9.0 and // above. unsafe { - ___lwp_park60( + _lwp_park( CLOCK_MONOTONIC, 0, &mut timeout, 0, ptr::without_provenance(hint), - ptr::null(), + ptr::null_mut(), ); } } From b2e6e0374def640e09393a93b8a555925a7b8fe3 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Sat, 3 Jan 2026 11:17:29 +0000 Subject: [PATCH 0220/1061] mutex.rs: remove needless-maybe-unsized bounds --- library/std/src/sync/nonpoison/mutex.rs | 2 +- library/std/src/sync/poison/mutex.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sync/nonpoison/mutex.rs b/library/std/src/sync/nonpoison/mutex.rs index ed3f8cfed821..307bf8eaf512 100644 --- a/library/std/src/sync/nonpoison/mutex.rs +++ b/library/std/src/sync/nonpoison/mutex.rs @@ -422,7 +422,7 @@ impl From for Mutex { } #[unstable(feature = "nonpoison_mutex", issue = "134645")] -impl Default for Mutex { +impl Default for Mutex { /// Creates a `Mutex`, with the `Default` value for T. fn default() -> Mutex { Mutex::new(Default::default()) diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs index 7f9e5fe62516..6eccd8a875ed 100644 --- a/library/std/src/sync/poison/mutex.rs +++ b/library/std/src/sync/poison/mutex.rs @@ -688,7 +688,7 @@ impl From for Mutex { } #[stable(feature = "mutex_default", since = "1.10.0")] -impl Default for Mutex { +impl Default for Mutex { /// Creates a `Mutex`, with the `Default` value for T. fn default() -> Mutex { Mutex::new(Default::default()) From 47798e261e13a905c6acae122a6111c8f1fd5eae Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Sat, 3 Jan 2026 11:36:25 +0000 Subject: [PATCH 0221/1061] vec in-place-drop: avoid creating an intermediate slice --- library/alloc/src/vec/in_place_drop.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/alloc/src/vec/in_place_drop.rs b/library/alloc/src/vec/in_place_drop.rs index 997c4c7525b5..c8cc758ac15c 100644 --- a/library/alloc/src/vec/in_place_drop.rs +++ b/library/alloc/src/vec/in_place_drop.rs @@ -1,6 +1,5 @@ use core::marker::PhantomData; use core::ptr::{self, NonNull, drop_in_place}; -use core::slice::{self}; use crate::alloc::Global; use crate::raw_vec::RawVec; @@ -22,7 +21,7 @@ impl Drop for InPlaceDrop { #[inline] fn drop(&mut self) { unsafe { - ptr::drop_in_place(slice::from_raw_parts_mut(self.inner, self.len())); + ptr::drop_in_place(ptr::slice_from_raw_parts_mut(self.inner, self.len())); } } } From c99f9c249b017c6909ea44bba6fe3efcd56208ed Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sat, 3 Jan 2026 19:04:35 +0530 Subject: [PATCH 0222/1061] Replace sourcedb with expanddb --- .../hir-def/src/macro_expansion_tests/mod.rs | 4 ++-- .../crates/hir-expand/src/proc_macro.rs | 4 ++-- .../crates/load-cargo/src/lib.rs | 19 +++++++++--------- .../crates/test-fixture/src/lib.rs | 20 +++++++++---------- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs index 3f136bc59172..c63f2c1d786b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -16,7 +16,7 @@ mod proc_macros; use std::{any::TypeId, iter, ops::Range, sync}; -use base_db::{RootQueryDb, SourceDatabase}; +use base_db::RootQueryDb; use expect_test::Expect; use hir_expand::{ AstId, ExpansionInfo, InFile, MacroCallId, MacroCallKind, MacroKind, @@ -387,7 +387,7 @@ struct IdentityWhenValidProcMacroExpander; impl ProcMacroExpander for IdentityWhenValidProcMacroExpander { fn expand( &self, - _: &dyn SourceDatabase, + _: &dyn ExpandDatabase, subtree: &TopSubtree, _: Option<&TopSubtree>, _: &base_db::Env, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs index d2614aa5f149..467eae3122df 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs @@ -4,7 +4,7 @@ use core::fmt; use std::any::Any; use std::{panic::RefUnwindSafe, sync}; -use base_db::{Crate, CrateBuilderId, CratesIdMap, Env, ProcMacroLoadingError, SourceDatabase}; +use base_db::{Crate, CrateBuilderId, CratesIdMap, Env, ProcMacroLoadingError}; use intern::Symbol; use rustc_hash::FxHashMap; use span::Span; @@ -25,7 +25,7 @@ pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe + Any { /// [`ProcMacroKind::Attr`]), environment variables, and span information. fn expand( &self, - db: &dyn SourceDatabase, + db: &dyn ExpandDatabase, subtree: &tt::TopSubtree, attrs: Option<&tt::TopSubtree>, env: &Env, diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index e01ce0b129da..94fac0bd33f7 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -11,15 +11,16 @@ extern crate rustc_driver as _; use std::{any::Any, collections::hash_map::Entry, mem, path::Path, sync}; use crossbeam_channel::{Receiver, unbounded}; -use hir_expand::proc_macro::{ - ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind, ProcMacroLoadResult, - ProcMacrosBuilder, +use hir_expand::{ + db::ExpandDatabase, + proc_macro::{ + ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind, ProcMacroLoadResult, + ProcMacrosBuilder, + }, }; use ide_db::{ - ChangeWithProcMacros, FxHashMap, RootDatabase, - base_db::{ - CrateGraphBuilder, Env, ProcMacroLoadingError, SourceDatabase, SourceRoot, SourceRootId, - }, + ChangeWithProcMacros, EditionedFileId, FxHashMap, RootDatabase, + base_db::{CrateGraphBuilder, Env, ProcMacroLoadingError, SourceRoot, SourceRootId}, prime_caches, }; use itertools::Itertools; @@ -33,7 +34,7 @@ use proc_macro_api::{ use project_model::{CargoConfig, PackageRoot, ProjectManifest, ProjectWorkspace}; use span::Span; use vfs::{ - AbsPath, AbsPathBuf, FileId, VfsPath, + AbsPath, AbsPathBuf, VfsPath, file_set::FileSetConfig, loader::{Handle, LoadingProgress}, }; @@ -530,7 +531,7 @@ struct Expander(proc_macro_api::ProcMacro); impl ProcMacroExpander for Expander { fn expand( &self, - db: &dyn SourceDatabase, + db: &dyn ExpandDatabase, subtree: &tt::TopSubtree, attrs: Option<&tt::TopSubtree>, env: &Env, diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs index b9c389c7694e..d81f27d7c3b1 100644 --- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs +++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs @@ -738,7 +738,7 @@ struct IdentityProcMacroExpander; impl ProcMacroExpander for IdentityProcMacroExpander { fn expand( &self, - _: &dyn SourceDatabase, + _: &dyn ExpandDatabase, subtree: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -761,7 +761,7 @@ struct Issue18089ProcMacroExpander; impl ProcMacroExpander for Issue18089ProcMacroExpander { fn expand( &self, - _: &dyn SourceDatabase, + _: &dyn ExpandDatabase, subtree: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -797,7 +797,7 @@ struct AttributeInputReplaceProcMacroExpander; impl ProcMacroExpander for AttributeInputReplaceProcMacroExpander { fn expand( &self, - _: &dyn SourceDatabase, + _: &dyn ExpandDatabase, _: &TopSubtree, attrs: Option<&TopSubtree>, _: &Env, @@ -821,7 +821,7 @@ struct Issue18840ProcMacroExpander; impl ProcMacroExpander for Issue18840ProcMacroExpander { fn expand( &self, - _: &dyn SourceDatabase, + _: &dyn ExpandDatabase, fn_: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -858,7 +858,7 @@ struct MirrorProcMacroExpander; impl ProcMacroExpander for MirrorProcMacroExpander { fn expand( &self, - _: &dyn SourceDatabase, + _: &dyn ExpandDatabase, input: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -897,7 +897,7 @@ struct ShortenProcMacroExpander; impl ProcMacroExpander for ShortenProcMacroExpander { fn expand( &self, - _: &dyn SourceDatabase, + _: &dyn ExpandDatabase, input: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -942,7 +942,7 @@ struct Issue17479ProcMacroExpander; impl ProcMacroExpander for Issue17479ProcMacroExpander { fn expand( &self, - _: &dyn SourceDatabase, + _: &dyn ExpandDatabase, subtree: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -973,7 +973,7 @@ struct Issue18898ProcMacroExpander; impl ProcMacroExpander for Issue18898ProcMacroExpander { fn expand( &self, - _: &dyn SourceDatabase, + _: &dyn ExpandDatabase, subtree: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -1027,7 +1027,7 @@ struct DisallowCfgProcMacroExpander; impl ProcMacroExpander for DisallowCfgProcMacroExpander { fn expand( &self, - _: &dyn SourceDatabase, + _: &dyn ExpandDatabase, subtree: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -1059,7 +1059,7 @@ struct GenerateSuffixedTypeProcMacroExpander; impl ProcMacroExpander for GenerateSuffixedTypeProcMacroExpander { fn expand( &self, - _: &dyn SourceDatabase, + _: &dyn ExpandDatabase, subtree: &TopSubtree, _attrs: Option<&TopSubtree>, _env: &Env, From 38b2e9262075debeb7dfb125d9ef78268e0a069d Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sat, 3 Jan 2026 19:06:26 +0530 Subject: [PATCH 0223/1061] added serde to span --- src/tools/rust-analyzer/Cargo.lock | 2 ++ .../rust-analyzer/crates/span/Cargo.toml | 1 + .../rust-analyzer/crates/span/src/ast_id.rs | 3 ++- .../rust-analyzer/crates/span/src/hygiene.rs | 5 +++- .../rust-analyzer/crates/span/src/lib.rs | 23 ++++++++++++++++--- 5 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 42eaeb01f1f2..453c35a574d7 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1881,6 +1881,7 @@ dependencies = [ "postcard", "proc-macro-api", "proc-macro-srv", + "span", ] [[package]] @@ -2648,6 +2649,7 @@ dependencies = [ "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hash 2.1.1", "salsa", + "serde", "stdx", "syntax", "text-size 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/src/tools/rust-analyzer/crates/span/Cargo.toml b/src/tools/rust-analyzer/crates/span/Cargo.toml index cfb319d688b6..d331f63d0c53 100644 --- a/src/tools/rust-analyzer/crates/span/Cargo.toml +++ b/src/tools/rust-analyzer/crates/span/Cargo.toml @@ -21,6 +21,7 @@ text-size.workspace = true vfs.workspace = true syntax.workspace = true stdx.workspace = true +serde.workspace = true [dev-dependencies] syntax.workspace = true diff --git a/src/tools/rust-analyzer/crates/span/src/ast_id.rs b/src/tools/rust-analyzer/crates/span/src/ast_id.rs index 599b3c717522..37954ca0b062 100644 --- a/src/tools/rust-analyzer/crates/span/src/ast_id.rs +++ b/src/tools/rust-analyzer/crates/span/src/ast_id.rs @@ -29,6 +29,7 @@ use std::{ use la_arena::{Arena, Idx, RawIdx}; use rustc_hash::{FxBuildHasher, FxHashMap}; +use serde::{Deserialize, Serialize}; use syntax::{ AstNode, AstPtr, SyntaxKind, SyntaxNode, SyntaxNodePtr, ast::{self, HasName}, @@ -54,7 +55,7 @@ pub const NO_DOWNMAP_ERASED_FILE_AST_ID_MARKER: ErasedFileAstId = ErasedFileAstId(pack_hash_index_and_kind(0, 0, ErasedFileAstIdKind::NoDownmap as u32)); /// This is a type erased FileAstId. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct ErasedFileAstId(u32); impl fmt::Debug for ErasedFileAstId { diff --git a/src/tools/rust-analyzer/crates/span/src/hygiene.rs b/src/tools/rust-analyzer/crates/span/src/hygiene.rs index 6805417177cd..1a82f221c6e4 100644 --- a/src/tools/rust-analyzer/crates/span/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/span/src/hygiene.rs @@ -21,11 +21,14 @@ //! `ExpnData::call_site` in rustc, [`MacroCallLoc::call_site`] in rust-analyzer. use std::fmt; +#[cfg(feature = "salsa")] +use serde::{Deserialize, Serialize}; + use crate::Edition; /// A syntax context describes a hierarchy tracking order of macro definitions. #[cfg(feature = "salsa")] -#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)] pub struct SyntaxContext( /// # Invariant /// diff --git a/src/tools/rust-analyzer/crates/span/src/lib.rs b/src/tools/rust-analyzer/crates/span/src/lib.rs index bfe7b2620d56..f6581de38ce2 100644 --- a/src/tools/rust-analyzer/crates/span/src/lib.rs +++ b/src/tools/rust-analyzer/crates/span/src/lib.rs @@ -20,6 +20,7 @@ pub use self::{ map::{RealSpanMap, SpanMap}, }; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; pub use syntax::Edition; pub use text_size::{TextRange, TextSize}; pub use vfs::FileId; @@ -68,11 +69,12 @@ impl Span { /// Spans represent a region of code, used by the IDE to be able link macro inputs and outputs /// together. Positions in spans are relative to some [`SpanAnchor`] to make them more incremental /// friendly. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Span { /// The text range of this span, relative to the anchor. /// We need the anchor for incrementality, as storing absolute ranges will require /// recomputation on every change in a file at all times. + #[serde(serialize_with = "serialize_text_range", deserialize_with = "deserialize_text_range")] pub range: TextRange, /// The anchor this span is relative to. pub anchor: SpanAnchor, @@ -80,6 +82,21 @@ pub struct Span { pub ctx: SyntaxContext, } +fn serialize_text_range(range: &TextRange, serializer: S) -> Result +where + S: Serializer, +{ + (u32::from(range.start()), u32::from(range.end())).serialize(serializer) +} + +fn deserialize_text_range<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let (start, end) = <(u32, u32)>::deserialize(deserializer)?; + Ok(TextRange::new(TextSize::from(start), TextSize::from(end))) +} + impl fmt::Debug for Span { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if f.alternate() { @@ -112,7 +129,7 @@ impl fmt::Display for Span { } } -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct SpanAnchor { pub file_id: EditionedFileId, pub ast_id: ErasedFileAstId, @@ -126,7 +143,7 @@ impl fmt::Debug for SpanAnchor { /// A [`FileId`] and [`Edition`] bundled up together. /// The MSB is reserved for `HirFileId` encoding, more upper bits are used to then encode the edition. -#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] pub struct EditionedFileId(u32); impl fmt::Debug for EditionedFileId { From 3941fed5017b6dce330fb14972fca968f80b3303 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sat, 3 Jan 2026 19:13:06 +0530 Subject: [PATCH 0224/1061] add span to proc-macro-srv-cliy --- src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml index 2c6e5a16ee06..875d9f6801a3 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml @@ -14,6 +14,7 @@ publish = false proc-macro-srv.workspace = true proc-macro-api.workspace = true postcard.workspace = true +span.workspace = true clap = {version = "4.5.42", default-features = false, features = ["std"]} [features] From be566f4e6b0f3d160d060d0b0508256d549e24bb Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sat, 3 Jan 2026 19:15:42 +0530 Subject: [PATCH 0225/1061] refactor subreq/resp variants to carry span --- .../src/bidirectional_protocol/msg.rs | 7 ++++--- .../crates/proc-macro-srv-cli/src/main_loop.rs | 13 +++++++------ .../rust-analyzer/crates/proc-macro-srv/src/lib.rs | 6 +++--- .../src/server_impl/rust_analyzer_span.rs | 13 +++---------- 4 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs index 558954f7619d..73cf58bd9ec7 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs @@ -2,6 +2,7 @@ use paths::Utf8PathBuf; use serde::{Deserialize, Serialize}; +use tt::Span; use crate::{ ProcMacroKind, @@ -10,9 +11,9 @@ use crate::{ #[derive(Debug, Serialize, Deserialize)] pub enum SubRequest { - FilePath { file_id: u32 }, - SourceText { file_id: u32, start: u32, end: u32 }, - LocalFilePath { file_id: u32 }, + FilePath { span: Span }, + SourceText { span: Span }, + LocalFilePath { span: Span }, } #[derive(Debug, Serialize, Deserialize)] diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs index 8fe3e93e4702..a5bf84df04de 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs @@ -6,6 +6,7 @@ use proc_macro_api::{ transport::codec::{json::JsonProtocol, postcard::PostcardProtocol}, version::CURRENT_API_VERSION, }; +use span::Span; use std::io; use legacy::Message; @@ -185,8 +186,8 @@ impl<'a, C: Codec> ProcMacroClientHandle<'a, C> { } impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandle<'_, C> { - fn file(&mut self, file_id: u32) -> String { - match self.roundtrip(bidirectional::SubRequest::FilePath { file_id }) { + fn file(&mut self, span: Span) -> String { + match self.roundtrip(bidirectional::SubRequest::FilePath { span }) { Some(bidirectional::BidirectionalMessage::SubResponse( bidirectional::SubResponse::FilePathResult { name }, )) => name, @@ -194,8 +195,8 @@ impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandl } } - fn source_text(&mut self, file_id: u32, start: u32, end: u32) -> Option { - match self.roundtrip(bidirectional::SubRequest::SourceText { file_id, start, end }) { + fn source_text(&mut self, span: Span) -> Option { + match self.roundtrip(bidirectional::SubRequest::SourceText { span }) { Some(bidirectional::BidirectionalMessage::SubResponse( bidirectional::SubResponse::SourceTextResult { text }, )) => text, @@ -203,8 +204,8 @@ impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandl } } - fn local_file(&mut self, file_id: u32) -> Option { - match self.roundtrip(bidirectional::SubRequest::LocalFilePath { file_id }) { + fn local_file(&mut self, span: Span) -> Option { + match self.roundtrip(bidirectional::SubRequest::LocalFilePath { span }) { Some(bidirectional::BidirectionalMessage::SubResponse( bidirectional::SubResponse::LocalFilePathResult { name }, )) => name, diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs index 8de712dbd386..6620800779bd 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs @@ -94,9 +94,9 @@ impl<'env> ProcMacroSrv<'env> { pub type ProcMacroClientHandle<'a> = &'a mut (dyn ProcMacroClientInterface + Sync + Send); pub trait ProcMacroClientInterface { - fn file(&mut self, file_id: u32) -> String; - fn source_text(&mut self, file_id: u32, start: u32, end: u32) -> Option; - fn local_file(&mut self, file_id: u32) -> Option; + fn file(&mut self, span: Span) -> String; + fn source_text(&mut self, span: Span) -> Option; + fn local_file(&mut self, span: Span) -> Option; } const EXPANDER_STACK_SIZE: usize = 8 * 1024 * 1024; diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index 7a9d655431f5..c4392a9ae110 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -128,13 +128,10 @@ impl server::Span for RaSpanServer<'_> { format!("{:?}", span) } fn file(&mut self, span: Self::Span) -> String { - self.callback - .as_mut() - .map(|cb| cb.file(span.anchor.file_id.file_id().index())) - .unwrap_or_default() + self.callback.as_mut().map(|cb| cb.file(span)).unwrap_or_default() } fn local_file(&mut self, span: Self::Span) -> Option { - self.callback.as_mut().and_then(|cb| cb.local_file(span.anchor.file_id.file_id().index())) + self.callback.as_mut().and_then(|cb| cb.local_file(span)) } fn save_span(&mut self, _span: Self::Span) -> usize { // FIXME, quote is incompatible with third-party tools @@ -153,11 +150,7 @@ impl server::Span for RaSpanServer<'_> { /// See PR: /// https://github.com/rust-lang/rust/pull/55780 fn source_text(&mut self, span: Self::Span) -> Option { - let file_id = span.anchor.file_id; - let start: u32 = span.range.start().into(); - let end: u32 = span.range.end().into(); - - self.callback.as_mut()?.source_text(file_id.file_id().index(), start, end) + self.callback.as_mut()?.source_text(span) } fn parent(&mut self, _span: Self::Span) -> Option { From 4f5502e8fb2679b76390bc7bebf4b457e853176d Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sat, 3 Jan 2026 19:18:36 +0530 Subject: [PATCH 0226/1061] Add span to callbacks and correct the source_text implementation --- .../crates/load-cargo/src/lib.rs | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index 94fac0bd33f7..474046ee2fa7 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -541,31 +541,37 @@ impl ProcMacroExpander for Expander { current_dir: String, ) -> Result { let mut cb = |req| match req { - SubRequest::LocalFilePath { file_id } => { - let file = FileId::from_raw(file_id); - let source_root_id = db.file_source_root(file).source_root_id(db); + SubRequest::LocalFilePath { span } => { + let file_id = span.anchor.file_id.file_id(); + let source_root_id = db.file_source_root(file_id).source_root_id(db); let source_root = db.source_root(source_root_id).source_root(db); - let name = source_root - .path_for_file(&file) + .path_for_file(&file_id) .and_then(|path| path.as_path()) .map(|path| path.to_string()); Ok(SubResponse::LocalFilePathResult { name }) } - SubRequest::SourceText { file_id, start, end } => { - let file = FileId::from_raw(file_id); - let text = db.file_text(file).text(db); - let slice = text.get(start as usize..end as usize).map(ToOwned::to_owned); - Ok(SubResponse::SourceTextResult { text: slice }) - } - SubRequest::FilePath { file_id } => { - let file = FileId::from_raw(file_id); - let source_root_id = db.file_source_root(file).source_root_id(db); - let source_root = db.source_root(source_root_id).source_root(db); + SubRequest::SourceText { span } => { + let anchor = span.anchor; + let file_id = EditionedFileId::from_span_guess_origin(db, anchor.file_id); + let range = db + .ast_id_map(hir_expand::HirFileId::FileId(file_id)) + .get_erased(anchor.ast_id) + .text_range(); + let source = db.file_text(anchor.file_id.file_id()).text(db); + let text = source + .get(usize::from(range.start())..usize::from(range.end())) + .map(ToOwned::to_owned); + Ok(SubResponse::SourceTextResult { text }) + } + SubRequest::FilePath { span } => { + let file_id = span.anchor.file_id.file_id(); + let source_root_id = db.file_source_root(file_id).source_root_id(db); + let source_root = db.source_root(source_root_id).source_root(db); let name = source_root - .path_for_file(&file) + .path_for_file(&file_id) .and_then(|path| path.as_path()) .map(|path| path.to_string()) .unwrap_or_default(); From ce19860f800c974dd1eb66a3aa9c2a6716d90bb7 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sat, 3 Jan 2026 20:10:00 +0530 Subject: [PATCH 0227/1061] remove span related API from proc-macro-srv/cli/api and remove span from procmacrosrvcli --- src/tools/rust-analyzer/Cargo.lock | 1 - .../crates/load-cargo/src/lib.rs | 36 ++++++++++--------- .../src/bidirectional_protocol/msg.rs | 7 ++-- .../crates/proc-macro-srv-cli/Cargo.toml | 1 - .../proc-macro-srv-cli/src/main_loop.rs | 14 ++++---- .../crates/proc-macro-srv/src/lib.rs | 6 ++-- .../src/server_impl/rust_analyzer_span.rs | 19 ++++++++-- 7 files changed, 49 insertions(+), 35 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 453c35a574d7..fbaeff1eb560 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1881,7 +1881,6 @@ dependencies = [ "postcard", "proc-macro-api", "proc-macro-srv", - "span", ] [[package]] diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index 474046ee2fa7..c302e266febd 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -34,7 +34,7 @@ use proc_macro_api::{ use project_model::{CargoConfig, PackageRoot, ProjectManifest, ProjectWorkspace}; use span::Span; use vfs::{ - AbsPath, AbsPathBuf, VfsPath, + AbsPath, AbsPathBuf, FileId, VfsPath, file_set::FileSetConfig, loader::{Handle, LoadingProgress}, }; @@ -541,8 +541,8 @@ impl ProcMacroExpander for Expander { current_dir: String, ) -> Result { let mut cb = |req| match req { - SubRequest::LocalFilePath { span } => { - let file_id = span.anchor.file_id.file_id(); + SubRequest::LocalFilePath { file_id } => { + let file_id = FileId::from_raw(file_id); let source_root_id = db.file_source_root(file_id).source_root_id(db); let source_root = db.source_root(source_root_id).source_root(db); let name = source_root @@ -552,22 +552,26 @@ impl ProcMacroExpander for Expander { Ok(SubResponse::LocalFilePathResult { name }) } - SubRequest::SourceText { span } => { - let anchor = span.anchor; - let file_id = EditionedFileId::from_span_guess_origin(db, anchor.file_id); - let range = db - .ast_id_map(hir_expand::HirFileId::FileId(file_id)) - .get_erased(anchor.ast_id) - .text_range(); - let source = db.file_text(anchor.file_id.file_id()).text(db); - let text = source - .get(usize::from(range.start())..usize::from(range.end())) - .map(ToOwned::to_owned); + SubRequest::SourceText { file_id, ast_id, start, end } => { + let raw_file_id = FileId::from_raw(file_id); + let editioned_file_id = span::EditionedFileId::from_raw(file_id); + let ast_id = span::ErasedFileAstId::from_raw(ast_id); + let hir_file_id = EditionedFileId::from_span_guess_origin(db, editioned_file_id); + let anchor_offset = db + .ast_id_map(hir_expand::HirFileId::FileId(hir_file_id)) + .get_erased(ast_id) + .text_range() + .start(); + let anchor_offset = u32::from(anchor_offset); + let abs_start = start + anchor_offset; + let abs_end = end + anchor_offset; + let source = db.file_text(raw_file_id).text(db); + let text = source.get(abs_start as usize..abs_end as usize).map(ToOwned::to_owned); Ok(SubResponse::SourceTextResult { text }) } - SubRequest::FilePath { span } => { - let file_id = span.anchor.file_id.file_id(); + SubRequest::FilePath { file_id } => { + let file_id = FileId::from_raw(file_id); let source_root_id = db.file_source_root(file_id).source_root_id(db); let source_root = db.source_root(source_root_id).source_root(db); let name = source_root diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs index 73cf58bd9ec7..e41f8a5d7da7 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs @@ -2,7 +2,6 @@ use paths::Utf8PathBuf; use serde::{Deserialize, Serialize}; -use tt::Span; use crate::{ ProcMacroKind, @@ -11,9 +10,9 @@ use crate::{ #[derive(Debug, Serialize, Deserialize)] pub enum SubRequest { - FilePath { span: Span }, - SourceText { span: Span }, - LocalFilePath { span: Span }, + FilePath { file_id: u32 }, + SourceText { file_id: u32, ast_id: u32, start: u32, end: u32 }, + LocalFilePath { file_id: u32 }, } #[derive(Debug, Serialize, Deserialize)] diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml index 875d9f6801a3..2c6e5a16ee06 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml @@ -14,7 +14,6 @@ publish = false proc-macro-srv.workspace = true proc-macro-api.workspace = true postcard.workspace = true -span.workspace = true clap = {version = "4.5.42", default-features = false, features = ["std"]} [features] diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs index a5bf84df04de..4891e073142d 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs @@ -6,7 +6,6 @@ use proc_macro_api::{ transport::codec::{json::JsonProtocol, postcard::PostcardProtocol}, version::CURRENT_API_VERSION, }; -use span::Span; use std::io; use legacy::Message; @@ -186,8 +185,8 @@ impl<'a, C: Codec> ProcMacroClientHandle<'a, C> { } impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandle<'_, C> { - fn file(&mut self, span: Span) -> String { - match self.roundtrip(bidirectional::SubRequest::FilePath { span }) { + fn file(&mut self, file_id: u32) -> String { + match self.roundtrip(bidirectional::SubRequest::FilePath { file_id }) { Some(bidirectional::BidirectionalMessage::SubResponse( bidirectional::SubResponse::FilePathResult { name }, )) => name, @@ -195,8 +194,9 @@ impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandl } } - fn source_text(&mut self, span: Span) -> Option { - match self.roundtrip(bidirectional::SubRequest::SourceText { span }) { + fn source_text(&mut self, file_id: u32, ast_id: u32, start: u32, end: u32) -> Option { + match self.roundtrip(bidirectional::SubRequest::SourceText { file_id, ast_id, start, end }) + { Some(bidirectional::BidirectionalMessage::SubResponse( bidirectional::SubResponse::SourceTextResult { text }, )) => text, @@ -204,8 +204,8 @@ impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandl } } - fn local_file(&mut self, span: Span) -> Option { - match self.roundtrip(bidirectional::SubRequest::LocalFilePath { span }) { + fn local_file(&mut self, file_id: u32) -> Option { + match self.roundtrip(bidirectional::SubRequest::LocalFilePath { file_id }) { Some(bidirectional::BidirectionalMessage::SubResponse( bidirectional::SubResponse::LocalFilePathResult { name }, )) => name, diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs index 6620800779bd..d63aea947c1d 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs @@ -94,9 +94,9 @@ impl<'env> ProcMacroSrv<'env> { pub type ProcMacroClientHandle<'a> = &'a mut (dyn ProcMacroClientInterface + Sync + Send); pub trait ProcMacroClientInterface { - fn file(&mut self, span: Span) -> String; - fn source_text(&mut self, span: Span) -> Option; - fn local_file(&mut self, span: Span) -> Option; + fn file(&mut self, file_id: u32) -> String; + fn source_text(&mut self, file_id: u32, ast_id: u32, start: u32, end: u32) -> Option; + fn local_file(&mut self, file_id: u32) -> Option; } const EXPANDER_STACK_SIZE: usize = 8 * 1024 * 1024; diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index c4392a9ae110..2ce3b717cb0d 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -128,10 +128,13 @@ impl server::Span for RaSpanServer<'_> { format!("{:?}", span) } fn file(&mut self, span: Self::Span) -> String { - self.callback.as_mut().map(|cb| cb.file(span)).unwrap_or_default() + self.callback + .as_mut() + .map(|cb| cb.file(span.anchor.file_id.file_id().index())) + .unwrap_or_default() } fn local_file(&mut self, span: Self::Span) -> Option { - self.callback.as_mut().and_then(|cb| cb.local_file(span)) + self.callback.as_mut().and_then(|cb| cb.local_file(span.anchor.file_id.file_id().index())) } fn save_span(&mut self, _span: Self::Span) -> usize { // FIXME, quote is incompatible with third-party tools @@ -150,7 +153,17 @@ impl server::Span for RaSpanServer<'_> { /// See PR: /// https://github.com/rust-lang/rust/pull/55780 fn source_text(&mut self, span: Self::Span) -> Option { - self.callback.as_mut()?.source_text(span) + let file_id = span.anchor.file_id; + let ast_id = span.anchor.ast_id; + let start: u32 = span.range.start().into(); + let end: u32 = span.range.end().into(); + + self.callback.as_mut()?.source_text( + file_id.file_id().index(), + ast_id.into_raw(), + start, + end, + ) } fn parent(&mut self, _span: Self::Span) -> Option { From f3b06a10f259fffd2ae92334f91fd0365e33f66a Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sat, 3 Jan 2026 20:13:41 +0530 Subject: [PATCH 0228/1061] remove serde from span --- src/tools/rust-analyzer/Cargo.lock | 1 - .../rust-analyzer/crates/span/Cargo.toml | 1 - .../rust-analyzer/crates/span/src/ast_id.rs | 3 +-- .../rust-analyzer/crates/span/src/hygiene.rs | 8 ++----- .../rust-analyzer/crates/span/src/lib.rs | 23 +++---------------- 5 files changed, 6 insertions(+), 30 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index fbaeff1eb560..42eaeb01f1f2 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -2648,7 +2648,6 @@ dependencies = [ "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hash 2.1.1", "salsa", - "serde", "stdx", "syntax", "text-size 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/src/tools/rust-analyzer/crates/span/Cargo.toml b/src/tools/rust-analyzer/crates/span/Cargo.toml index d331f63d0c53..cfb319d688b6 100644 --- a/src/tools/rust-analyzer/crates/span/Cargo.toml +++ b/src/tools/rust-analyzer/crates/span/Cargo.toml @@ -21,7 +21,6 @@ text-size.workspace = true vfs.workspace = true syntax.workspace = true stdx.workspace = true -serde.workspace = true [dev-dependencies] syntax.workspace = true diff --git a/src/tools/rust-analyzer/crates/span/src/ast_id.rs b/src/tools/rust-analyzer/crates/span/src/ast_id.rs index 37954ca0b062..599b3c717522 100644 --- a/src/tools/rust-analyzer/crates/span/src/ast_id.rs +++ b/src/tools/rust-analyzer/crates/span/src/ast_id.rs @@ -29,7 +29,6 @@ use std::{ use la_arena::{Arena, Idx, RawIdx}; use rustc_hash::{FxBuildHasher, FxHashMap}; -use serde::{Deserialize, Serialize}; use syntax::{ AstNode, AstPtr, SyntaxKind, SyntaxNode, SyntaxNodePtr, ast::{self, HasName}, @@ -55,7 +54,7 @@ pub const NO_DOWNMAP_ERASED_FILE_AST_ID_MARKER: ErasedFileAstId = ErasedFileAstId(pack_hash_index_and_kind(0, 0, ErasedFileAstIdKind::NoDownmap as u32)); /// This is a type erased FileAstId. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct ErasedFileAstId(u32); impl fmt::Debug for ErasedFileAstId { diff --git a/src/tools/rust-analyzer/crates/span/src/hygiene.rs b/src/tools/rust-analyzer/crates/span/src/hygiene.rs index 1a82f221c6e4..ea4f4c5efb42 100644 --- a/src/tools/rust-analyzer/crates/span/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/span/src/hygiene.rs @@ -19,16 +19,12 @@ //! # The Call-site Hierarchy //! //! `ExpnData::call_site` in rustc, [`MacroCallLoc::call_site`] in rust-analyzer. -use std::fmt; - -#[cfg(feature = "salsa")] -use serde::{Deserialize, Serialize}; - use crate::Edition; +use std::fmt; /// A syntax context describes a hierarchy tracking order of macro definitions. #[cfg(feature = "salsa")] -#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)] +#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] pub struct SyntaxContext( /// # Invariant /// diff --git a/src/tools/rust-analyzer/crates/span/src/lib.rs b/src/tools/rust-analyzer/crates/span/src/lib.rs index f6581de38ce2..bfe7b2620d56 100644 --- a/src/tools/rust-analyzer/crates/span/src/lib.rs +++ b/src/tools/rust-analyzer/crates/span/src/lib.rs @@ -20,7 +20,6 @@ pub use self::{ map::{RealSpanMap, SpanMap}, }; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; pub use syntax::Edition; pub use text_size::{TextRange, TextSize}; pub use vfs::FileId; @@ -69,12 +68,11 @@ impl Span { /// Spans represent a region of code, used by the IDE to be able link macro inputs and outputs /// together. Positions in spans are relative to some [`SpanAnchor`] to make them more incremental /// friendly. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct Span { /// The text range of this span, relative to the anchor. /// We need the anchor for incrementality, as storing absolute ranges will require /// recomputation on every change in a file at all times. - #[serde(serialize_with = "serialize_text_range", deserialize_with = "deserialize_text_range")] pub range: TextRange, /// The anchor this span is relative to. pub anchor: SpanAnchor, @@ -82,21 +80,6 @@ pub struct Span { pub ctx: SyntaxContext, } -fn serialize_text_range(range: &TextRange, serializer: S) -> Result -where - S: Serializer, -{ - (u32::from(range.start()), u32::from(range.end())).serialize(serializer) -} - -fn deserialize_text_range<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - let (start, end) = <(u32, u32)>::deserialize(deserializer)?; - Ok(TextRange::new(TextSize::from(start), TextSize::from(end))) -} - impl fmt::Debug for Span { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if f.alternate() { @@ -129,7 +112,7 @@ impl fmt::Display for Span { } } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct SpanAnchor { pub file_id: EditionedFileId, pub ast_id: ErasedFileAstId, @@ -143,7 +126,7 @@ impl fmt::Debug for SpanAnchor { /// A [`FileId`] and [`Edition`] bundled up together. /// The MSB is reserved for `HirFileId` encoding, more upper bits are used to then encode the edition. -#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct EditionedFileId(u32); impl fmt::Debug for EditionedFileId { From aec6b9b7bf541d386e5ef21a49f4ecfee17769ed Mon Sep 17 00:00:00 2001 From: hulxv Date: Wed, 17 Dec 2025 22:56:28 +0200 Subject: [PATCH 0229/1061] Refactor libc pipe tests to use utility functions for error handling and data operations --- .../miri/tests/pass-dep/libc/libc-pipe.rs | 137 +++++++----------- src/tools/miri/tests/utils/libc.rs | 18 +++ 2 files changed, 72 insertions(+), 83 deletions(-) diff --git a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs index ffbcf633b987..102bcbb34a26 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs @@ -5,6 +5,7 @@ use std::thread; #[path = "../../utils/libc.rs"] mod libc_utils; +use libc_utils::*; fn main() { test_pipe(); @@ -25,69 +26,46 @@ fn main() { fn test_pipe() { let mut fds = [-1, -1]; - let res = unsafe { libc::pipe(fds.as_mut_ptr()) }; - assert_eq!(res, 0); + errno_check(unsafe { libc::pipe(fds.as_mut_ptr()) }); // Read size == data available in buffer. - let data = "12345".as_bytes().as_ptr(); - let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) }; - assert_eq!(res, 5); - let mut buf3: [u8; 5] = [0; 5]; - let res = unsafe { - libc_utils::read_all(fds[0], buf3.as_mut_ptr().cast(), buf3.len() as libc::size_t) - }; - assert_eq!(res, 5); - assert_eq!(buf3, "12345".as_bytes()); + let data = b"12345"; + write_all_from_slice(fds[1], data).unwrap(); + let buf3 = read_all_into_array::<5>(fds[0]).unwrap(); + assert_eq!(&buf3, data); // Read size > data available in buffer. - let data = "123".as_bytes(); - let res = unsafe { libc_utils::write_all(fds[1], data.as_ptr() as *const libc::c_void, 3) }; - assert_eq!(res, 3); + let data = b"123"; + write_all_from_slice(fds[1], data).unwrap(); let mut buf4: [u8; 5] = [0; 5]; - let res = unsafe { libc::read(fds[0], buf4.as_mut_ptr().cast(), buf4.len() as libc::size_t) }; - assert!(res > 0 && res <= 3); - let res = res as usize; + let res = read_into_slice(fds[0], &mut buf4).unwrap().0.len(); assert_eq!(buf4[..res], data[..res]); if res < 3 { // Drain the rest from the read end. - let res = unsafe { libc_utils::read_all(fds[0], buf4[res..].as_mut_ptr().cast(), 3 - res) }; + let res = read_into_slice(fds[0], &mut buf4[res..]).unwrap().0.len(); assert!(res > 0); } } fn test_pipe_threaded() { let mut fds = [-1, -1]; - let res = unsafe { libc::pipe(fds.as_mut_ptr()) }; - assert_eq!(res, 0); + errno_check(unsafe { libc::pipe(fds.as_mut_ptr()) }); let thread1 = thread::spawn(move || { - let mut buf: [u8; 5] = [0; 5]; - let res: i64 = unsafe { - libc_utils::read_all(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) - .try_into() - .unwrap() - }; - assert_eq!(res, 5); - assert_eq!(buf, "abcde".as_bytes()); + let buf = read_all_into_array::<5>(fds[0]).unwrap(); + assert_eq!(&buf, b"abcde"); }); thread::yield_now(); - let data = "abcde".as_bytes().as_ptr(); - let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) }; - assert_eq!(res, 5); + write_all_from_slice(fds[1], b"abcde").unwrap(); thread1.join().unwrap(); // Read and write from different direction let thread2 = thread::spawn(move || { thread::yield_now(); - let data = "12345".as_bytes().as_ptr(); - let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) }; - assert_eq!(res, 5); + write_all_from_slice(fds[1], b"12345").unwrap(); }); - let mut buf: [u8; 5] = [0; 5]; - let res = - unsafe { libc_utils::read_all(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) }; - assert_eq!(res, 5); - assert_eq!(buf, "12345".as_bytes()); + let buf = read_all_into_array::<5>(fds[0]).unwrap(); + assert_eq!(&buf, b"12345"); thread2.join().unwrap(); } @@ -96,26 +74,17 @@ fn test_pipe_threaded() { fn test_race() { static mut VAL: u8 = 0; let mut fds = [-1, -1]; - let res = unsafe { libc::pipe(fds.as_mut_ptr()) }; - assert_eq!(res, 0); + errno_check(unsafe { libc::pipe(fds.as_mut_ptr()) }); let thread1 = thread::spawn(move || { - let mut buf: [u8; 1] = [0; 1]; // write() from the main thread will occur before the read() here // because preemption is disabled and the main thread yields after write(). - let res: i32 = unsafe { - libc_utils::read_all(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) - .try_into() - .unwrap() - }; - assert_eq!(res, 1); - assert_eq!(buf, "a".as_bytes()); + let buf = read_all_into_array::<1>(fds[0]).unwrap(); + assert_eq!(&buf, b"a"); // The read above establishes a happens-before so it is now safe to access this global variable. unsafe { assert_eq!(VAL, 1) }; }); unsafe { VAL = 1 }; - let data = "a".as_bytes().as_ptr(); - let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 1) }; - assert_eq!(res, 1); + write_all_from_slice(fds[1], b"a").unwrap(); thread::yield_now(); thread1.join().unwrap(); } @@ -139,40 +108,46 @@ fn test_pipe_array() { ))] fn test_pipe2() { let mut fds = [-1, -1]; - let res = unsafe { libc::pipe2(fds.as_mut_ptr(), libc::O_NONBLOCK) }; - assert_eq!(res, 0); + errno_check(unsafe { libc::pipe2(fds.as_mut_ptr(), libc::O_NONBLOCK) }); } /// Basic test for pipe fcntl's F_SETFL and F_GETFL flag. fn test_pipe_setfl_getfl() { // Initialise pipe fds. let mut fds = [-1, -1]; - let res = unsafe { libc::pipe(fds.as_mut_ptr()) }; - assert_eq!(res, 0); + errno_check(unsafe { libc::pipe(fds.as_mut_ptr()) }); // Both sides should either have O_RONLY or O_WRONLY. - let res = unsafe { libc::fcntl(fds[0], libc::F_GETFL) }; - assert_eq!(res, libc::O_RDONLY); - let res = unsafe { libc::fcntl(fds[1], libc::F_GETFL) }; - assert_eq!(res, libc::O_WRONLY); + assert_eq!( + errno_result(unsafe { libc::fcntl(fds[0], libc::F_GETFL) }).unwrap(), + libc::O_RDONLY + ); + assert_eq!( + errno_result(unsafe { libc::fcntl(fds[1], libc::F_GETFL) }).unwrap(), + libc::O_WRONLY + ); // Add the O_NONBLOCK flag with F_SETFL. - let res = unsafe { libc::fcntl(fds[0], libc::F_SETFL, libc::O_NONBLOCK) }; - assert_eq!(res, 0); + errno_check(unsafe { libc::fcntl(fds[0], libc::F_SETFL, libc::O_NONBLOCK) }); // Test if the O_NONBLOCK flag is successfully added. - let res = unsafe { libc::fcntl(fds[0], libc::F_GETFL) }; - assert_eq!(res, libc::O_RDONLY | libc::O_NONBLOCK); + assert_eq!( + errno_result(unsafe { libc::fcntl(fds[0], libc::F_GETFL) }).unwrap(), + libc::O_RDONLY | libc::O_NONBLOCK + ); // The other side remains unchanged. - let res = unsafe { libc::fcntl(fds[1], libc::F_GETFL) }; - assert_eq!(res, libc::O_WRONLY); + assert_eq!( + errno_result(unsafe { libc::fcntl(fds[1], libc::F_GETFL) }).unwrap(), + libc::O_WRONLY + ); // Test if O_NONBLOCK flag can be unset. - let res = unsafe { libc::fcntl(fds[0], libc::F_SETFL, 0) }; - assert_eq!(res, 0); - let res = unsafe { libc::fcntl(fds[0], libc::F_GETFL) }; - assert_eq!(res, libc::O_RDONLY); + errno_check(unsafe { libc::fcntl(fds[0], libc::F_SETFL, 0) }); + assert_eq!( + errno_result(unsafe { libc::fcntl(fds[0], libc::F_GETFL) }).unwrap(), + libc::O_RDONLY + ); } /// Test the behaviour of F_SETFL/F_GETFL when a fd is blocking. @@ -183,28 +158,24 @@ fn test_pipe_setfl_getfl() { /// then writes to fds[1] to unblock main thread's `read`. fn test_pipe_fcntl_threaded() { let mut fds = [-1, -1]; - let res = unsafe { libc::pipe(fds.as_mut_ptr()) }; - assert_eq!(res, 0); - let mut buf: [u8; 5] = [0; 5]; + errno_check(unsafe { libc::pipe(fds.as_mut_ptr()) }); let thread1 = thread::spawn(move || { // Add O_NONBLOCK flag while pipe is still blocked on read. - let res = unsafe { libc::fcntl(fds[0], libc::F_SETFL, libc::O_NONBLOCK) }; - assert_eq!(res, 0); + errno_check(unsafe { libc::fcntl(fds[0], libc::F_SETFL, libc::O_NONBLOCK) }); // Check the new flag value while the main thread is still blocked on fds[0]. - let res = unsafe { libc::fcntl(fds[0], libc::F_GETFL) }; - assert_eq!(res, libc::O_NONBLOCK); + assert_eq!( + errno_result(unsafe { libc::fcntl(fds[0], libc::F_GETFL) }).unwrap(), + libc::O_NONBLOCK + ); // The write below will unblock the `read` in main thread: even though // the socket is now "non-blocking", the shim needs to deal correctly // with threads that were blocked before the socket was made non-blocking. - let data = "abcde".as_bytes().as_ptr(); - let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) }; - assert_eq!(res, 5); + write_all_from_slice(fds[1], b"abcde").unwrap(); }); // The `read` below will block. - let res = - unsafe { libc_utils::read_all(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) }; + let buf = read_all_into_array::<5>(fds[0]).unwrap(); thread1.join().unwrap(); - assert_eq!(res, 5); + assert_eq!(&buf, b"abcde"); } diff --git a/src/tools/miri/tests/utils/libc.rs b/src/tools/miri/tests/utils/libc.rs index e42f39c64eb6..114aade7d31d 100644 --- a/src/tools/miri/tests/utils/libc.rs +++ b/src/tools/miri/tests/utils/libc.rs @@ -53,6 +53,24 @@ pub fn read_all_into_array(fd: libc::c_int) -> Result<[u8; N], l } } +pub fn read_all_into_slice(fd: libc::c_int, buf: &mut [u8]) -> Result<(), libc::ssize_t> { + let res = unsafe { read_all(fd, buf.as_mut_ptr().cast(), buf.len()) }; + if res >= 0 { + assert_eq!(res as usize, buf.len()); + Ok(()) + } else { + Err(res) + } +} + +pub fn read_into_slice( + fd: libc::c_int, + buf: &mut [u8], +) -> Result<(&mut [u8], &mut [u8]), libc::ssize_t> { + let res = unsafe { libc::read(fd, buf.as_mut_ptr().cast(), buf.len()) }; + if res >= 0 { Ok(buf.split_at_mut(res as usize)) } else { Err(res) } +} + pub unsafe fn write_all( fd: libc::c_int, buf: *const libc::c_void, From b692fcbb4bd60691af415d42b3e58fe5d469a619 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Jan 2026 16:23:55 +0100 Subject: [PATCH 0230/1061] minor tweaks --- .../miri/tests/pass-dep/libc/libc-pipe.rs | 12 ++++------ src/tools/miri/tests/utils/libc.rs | 24 +++++++++---------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs index 102bcbb34a26..1eef8eaf4452 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs @@ -38,13 +38,11 @@ fn test_pipe() { let data = b"123"; write_all_from_slice(fds[1], data).unwrap(); let mut buf4: [u8; 5] = [0; 5]; - let res = read_into_slice(fds[0], &mut buf4).unwrap().0.len(); - assert_eq!(buf4[..res], data[..res]); - if res < 3 { - // Drain the rest from the read end. - let res = read_into_slice(fds[0], &mut buf4[res..]).unwrap().0.len(); - assert!(res > 0); - } + let (part1, rest) = read_into_slice(fds[0], &mut buf4).unwrap(); + assert_eq!(part1[..], data[..part1.len()]); + // Write 2 more bytes so we can exactly fill the `rest`. + write_all_from_slice(fds[1], b"34").unwrap(); + read_all_into_slice(fds[0], rest).unwrap(); } fn test_pipe_threaded() { diff --git a/src/tools/miri/tests/utils/libc.rs b/src/tools/miri/tests/utils/libc.rs index 114aade7d31d..0765bacb6bd8 100644 --- a/src/tools/miri/tests/utils/libc.rs +++ b/src/tools/miri/tests/utils/libc.rs @@ -40,19 +40,8 @@ pub unsafe fn read_all( return read_so_far as libc::ssize_t; } -/// Read exactly `N` bytes from `fd`. Error if that many bytes could not be read. +/// Try to fill the given slice by reading from `fd`. Error if that many bytes could not be read. #[track_caller] -pub fn read_all_into_array(fd: libc::c_int) -> Result<[u8; N], libc::ssize_t> { - let mut buf = [0; N]; - let res = unsafe { read_all(fd, buf.as_mut_ptr().cast(), buf.len()) }; - if res >= 0 { - assert_eq!(res as usize, buf.len()); - Ok(buf) - } else { - Err(res) - } -} - pub fn read_all_into_slice(fd: libc::c_int, buf: &mut [u8]) -> Result<(), libc::ssize_t> { let res = unsafe { read_all(fd, buf.as_mut_ptr().cast(), buf.len()) }; if res >= 0 { @@ -63,6 +52,17 @@ pub fn read_all_into_slice(fd: libc::c_int, buf: &mut [u8]) -> Result<(), libc:: } } +/// Read exactly `N` bytes from `fd`. Error if that many bytes could not be read. +#[track_caller] +pub fn read_all_into_array(fd: libc::c_int) -> Result<[u8; N], libc::ssize_t> { + let mut buf = [0; N]; + read_all_into_slice(fd, &mut buf)?; + Ok(buf) +} + +/// Do a single read from `fd` and return the part of the buffer that was written into, +/// and the rest. +#[track_caller] pub fn read_into_slice( fd: libc::c_int, buf: &mut [u8], From 65c10702bdbbaa733858fa890a41d1f5892ab0de Mon Sep 17 00:00:00 2001 From: Sekar-C-Mca Date: Sat, 3 Jan 2026 22:41:01 +0530 Subject: [PATCH 0231/1061] Fix typo in pattern usefulness documentation Line 171 introduced `pt_1, .., pt_n` and `qt` as variable names, but line 172 incorrectly used `tp_1, .., tp_n, tq`. This commit fixes the inconsistency to use the correct variable names throughout. --- compiler/rustc_pattern_analysis/src/usefulness.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 971616b18914..bf236b7737d9 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -169,7 +169,7 @@ //! on pattern-tuples. //! //! Let `pt_1, .., pt_n` and `qt` be length-m tuples of patterns for the same type `(T_1, .., T_m)`. -//! We compute `usefulness(tp_1, .., tp_n, tq)` as follows: +//! We compute `usefulness(pt_1, .., pt_n, qt)` as follows: //! //! - Base case: `m == 0`. //! The pattern-tuples are all empty, i.e. they're all `()`. Thus `tq` is useful iff there are From d236b8a4f19b5c09f5cba0f5d69ac13c2c303d48 Mon Sep 17 00:00:00 2001 From: Jeremy Smart Date: Mon, 8 Sep 2025 13:24:24 -0400 Subject: [PATCH 0232/1061] Add Dir::open(_file) and some trait impls --- library/std/src/fs.rs | 118 +++++++++++++ library/std/src/fs/tests.rs | 31 ++++ library/std/src/sys/fs/common.rs | 25 ++- library/std/src/sys/fs/hermit.rs | 3 +- library/std/src/sys/fs/mod.rs | 2 +- library/std/src/sys/fs/solid.rs | 2 +- library/std/src/sys/fs/uefi.rs | 1 + library/std/src/sys/fs/unix.rs | 242 +++++++++++++++----------- library/std/src/sys/fs/unix/dir.rs | 114 ++++++++++++ library/std/src/sys/fs/unsupported.rs | 1 + library/std/src/sys/fs/windows.rs | 51 ++++-- library/std/src/sys/fs/windows/dir.rs | 153 ++++++++++++++++ 12 files changed, 619 insertions(+), 124 deletions(-) create mode 100644 library/std/src/sys/fs/unix/dir.rs create mode 100644 library/std/src/sys/fs/windows/dir.rs diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index f078dec21d0a..4edd35b310bd 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -152,6 +152,43 @@ pub enum TryLockError { WouldBlock, } +/// An object providing access to a directory on the filesystem. +/// +/// Directories are automatically closed when they go out of scope. Errors detected +/// on closing are ignored by the implementation of `Drop`. +/// +/// # Platform-specific behavior +/// +/// On supported systems (including Windows and some UNIX-based OSes), this function acquires a +/// handle/file descriptor for the directory. This allows functions like [`Dir::open_file`] to +/// avoid [TOCTOU] errors when the directory itself is being moved. +/// +/// On other systems, it stores an absolute path (see [`canonicalize()`]). In the latter case, no +/// [TOCTOU] guarantees are made. +/// +/// # Examples +/// +/// Opens a directory and then a file inside it. +/// +/// ```no_run +/// #![feature(dirfd)] +/// use std::{fs::Dir, io}; +/// +/// fn main() -> std::io::Result<()> { +/// let dir = Dir::open("foo")?; +/// let mut file = dir.open_file("bar.txt")?; +/// let contents = io::read_to_string(file)?; +/// assert_eq!(contents, "Hello, world!"); +/// Ok(()) +/// } +/// ``` +/// +/// [TOCTOU]: self#time-of-check-to-time-of-use-toctou +#[unstable(feature = "dirfd", issue = "120426")] +pub struct Dir { + inner: fs_imp::Dir, +} + /// Metadata information about a file. /// /// This structure is returned from the [`metadata`] or @@ -1554,6 +1591,87 @@ impl Seek for Arc { } } +impl Dir { + /// Attempts to open a directory at `path` in read-only mode. + /// + /// # Errors + /// + /// This function will return an error if `path` does not point to an existing directory. + /// Other errors may also be returned according to [`OpenOptions::open`]. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(dirfd)] + /// use std::{fs::Dir, io}; + /// + /// fn main() -> std::io::Result<()> { + /// let dir = Dir::open("foo")?; + /// let mut f = dir.open_file("bar.txt")?; + /// let contents = io::read_to_string(f)?; + /// assert_eq!(contents, "Hello, world!"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "dirfd", issue = "120426")] + pub fn open>(path: P) -> io::Result { + fs_imp::Dir::open(path.as_ref(), &OpenOptions::new().read(true).0) + .map(|inner| Self { inner }) + } + + /// Attempts to open a file in read-only mode relative to this directory. + /// + /// # Errors + /// + /// This function will return an error if `path` does not point to an existing file. + /// Other errors may also be returned according to [`OpenOptions::open`]. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(dirfd)] + /// use std::{fs::Dir, io}; + /// + /// fn main() -> std::io::Result<()> { + /// let dir = Dir::open("foo")?; + /// let mut f = dir.open_file("bar.txt")?; + /// let contents = io::read_to_string(f)?; + /// assert_eq!(contents, "Hello, world!"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "dirfd", issue = "120426")] + pub fn open_file>(&self, path: P) -> io::Result { + self.inner + .open_file(path.as_ref(), &OpenOptions::new().read(true).0) + .map(|f| File { inner: f }) + } +} + +impl AsInner for Dir { + #[inline] + fn as_inner(&self) -> &fs_imp::Dir { + &self.inner + } +} +impl FromInner for Dir { + fn from_inner(f: fs_imp::Dir) -> Dir { + Dir { inner: f } + } +} +impl IntoInner for Dir { + fn into_inner(self) -> fs_imp::Dir { + self.inner + } +} + +#[unstable(feature = "dirfd", issue = "120426")] +impl fmt::Debug for Dir { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.inner.fmt(f) + } +} + impl OpenOptions { /// Creates a blank new set of options ready for configuration. /// diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index f15efc7b2f0b..6a86705f2fad 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1,7 +1,11 @@ use rand::RngCore; +#[cfg(not(miri))] +use super::Dir; use crate::assert_matches::assert_matches; use crate::fs::{self, File, FileTimes, OpenOptions, TryLockError}; +#[cfg(not(miri))] +use crate::io; use crate::io::prelude::*; use crate::io::{BorrowedBuf, ErrorKind, SeekFrom}; use crate::mem::MaybeUninit; @@ -2465,3 +2469,30 @@ fn test_fs_set_times_nofollow() { assert_ne!(target_metadata.accessed().unwrap(), accessed); assert_ne!(target_metadata.modified().unwrap(), modified); } + +#[test] +// FIXME: libc calls fail on miri +#[cfg(not(miri))] +fn test_dir_smoke_test() { + let tmpdir = tmpdir(); + let dir = Dir::open(tmpdir.path()); + check!(dir); +} + +#[test] +// FIXME: libc calls fail on miri +#[cfg(not(miri))] +fn test_dir_read_file() { + let tmpdir = tmpdir(); + let mut f = check!(File::create(tmpdir.join("foo.txt"))); + check!(f.write(b"bar")); + check!(f.flush()); + drop(f); + let dir = check!(Dir::open(tmpdir.path())); + let f = check!(dir.open_file("foo.txt")); + let buf = check!(io::read_to_string(f)); + assert_eq!("bar", &buf); + let f = check!(dir.open_file(tmpdir.join("foo.txt"))); + let buf = check!(io::read_to_string(f)); + assert_eq!("bar", &buf); +} diff --git a/library/std/src/sys/fs/common.rs b/library/std/src/sys/fs/common.rs index fbd075d57d61..4d47d392a826 100644 --- a/library/std/src/sys/fs/common.rs +++ b/library/std/src/sys/fs/common.rs @@ -1,9 +1,10 @@ #![allow(dead_code)] // not used on all platforms -use crate::fs; use crate::io::{self, Error, ErrorKind}; -use crate::path::Path; +use crate::path::{Path, PathBuf}; +use crate::sys::fs::{File, OpenOptions}; use crate::sys::helpers::ignore_notfound; +use crate::{fmt, fs}; pub(crate) const NOT_FILE_ERROR: Error = io::const_error!( ErrorKind::InvalidInput, @@ -58,3 +59,23 @@ pub fn exists(path: &Path) -> io::Result { Err(error) => Err(error), } } + +pub struct Dir { + path: PathBuf, +} + +impl Dir { + pub fn open(path: &Path, _opts: &OpenOptions) -> io::Result { + path.canonicalize().map(|path| Self { path }) + } + + pub fn open_file(&self, path: &Path, opts: &OpenOptions) -> io::Result { + File::open(&self.path.join(path), &opts) + } +} + +impl fmt::Debug for Dir { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Dir").field("path", &self.path).finish() + } +} diff --git a/library/std/src/sys/fs/hermit.rs b/library/std/src/sys/fs/hermit.rs index bb0c44d7e9a1..1e281eb0d9d1 100644 --- a/library/std/src/sys/fs/hermit.rs +++ b/library/std/src/sys/fs/hermit.rs @@ -10,7 +10,7 @@ use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, Raw use crate::path::{Path, PathBuf}; use crate::sync::Arc; use crate::sys::fd::FileDesc; -pub use crate::sys::fs::common::{copy, exists}; +pub use crate::sys::fs::common::{Dir, copy, exists}; use crate::sys::helpers::run_path_with_cstr; use crate::sys::time::SystemTime; use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner, cvt, unsupported, unsupported_err}; @@ -18,6 +18,7 @@ use crate::{fmt, mem}; #[derive(Debug)] pub struct File(FileDesc); + #[derive(Clone)] pub struct FileAttr { stat_val: stat_struct, diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index fa046cb8e7da..0c297c5766b8 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -59,7 +59,7 @@ pub fn with_native_path(path: &Path, f: &dyn Fn(&Path) -> io::Result) -> i } pub use imp::{ - DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions, + Dir, DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions, ReadDir, }; diff --git a/library/std/src/sys/fs/solid.rs b/library/std/src/sys/fs/solid.rs index b6d41cc4bc84..114ffda57bc5 100644 --- a/library/std/src/sys/fs/solid.rs +++ b/library/std/src/sys/fs/solid.rs @@ -9,7 +9,7 @@ use crate::os::raw::{c_int, c_short}; use crate::os::solid::ffi::OsStrExt; use crate::path::{Path, PathBuf}; use crate::sync::Arc; -pub use crate::sys::fs::common::exists; +pub use crate::sys::fs::common::{Dir, exists}; use crate::sys::helpers::ignore_notfound; use crate::sys::pal::{abi, error}; use crate::sys::time::SystemTime; diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index f5530962c570..14ee49e071c1 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -6,6 +6,7 @@ use crate::fs::TryLockError; use crate::hash::Hash; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::path::{Path, PathBuf}; +pub use crate::sys::fs::common::Dir; use crate::sys::pal::{helpers, unsupported}; use crate::sys::time::SystemTime; diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 1cc2edd0cf47..327b0eb7468a 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -257,7 +257,7 @@ cfg_has_statx! {{ // all DirEntry's will have a reference to this struct struct InnerReadDir { - dirp: Dir, + dirp: DirStream, root: PathBuf, } @@ -272,10 +272,134 @@ impl ReadDir { } } -struct Dir(*mut libc::DIR); +struct DirStream(*mut libc::DIR); -unsafe impl Send for Dir {} -unsafe impl Sync for Dir {} +// dir::Dir requires openat support +cfg_select! { + any( + target_os = "redox", + target_os = "espidf", + target_os = "horizon", + target_os = "vita", + target_os = "nto", + target_os = "vxworks", + ) => { + pub use crate::sys::fs::common::Dir; + } + _ => { + mod dir; + pub use dir::Dir; + } +} + +fn debug_path_fd<'a, 'b>( + fd: c_int, + f: &'a mut fmt::Formatter<'b>, + name: &str, +) -> fmt::DebugStruct<'a, 'b> { + let mut b = f.debug_struct(name); + + fn get_mode(fd: c_int) -> Option<(bool, bool)> { + let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) }; + if mode == -1 { + return None; + } + match mode & libc::O_ACCMODE { + libc::O_RDONLY => Some((true, false)), + libc::O_RDWR => Some((true, true)), + libc::O_WRONLY => Some((false, true)), + _ => None, + } + } + + b.field("fd", &fd); + if let Some(path) = get_path_from_fd(fd) { + b.field("path", &path); + } + if let Some((read, write)) = get_mode(fd) { + b.field("read", &read).field("write", &write); + } + + b +} + +fn get_path_from_fd(fd: c_int) -> Option { + #[cfg(any(target_os = "linux", target_os = "illumos", target_os = "solaris"))] + fn get_path(fd: c_int) -> Option { + let mut p = PathBuf::from("/proc/self/fd"); + p.push(&fd.to_string()); + run_path_with_cstr(&p, &readlink).ok() + } + + #[cfg(any(target_vendor = "apple", target_os = "netbsd"))] + fn get_path(fd: c_int) -> Option { + // FIXME: The use of PATH_MAX is generally not encouraged, but it + // is inevitable in this case because Apple targets and NetBSD define `fcntl` + // with `F_GETPATH` in terms of `MAXPATHLEN`, and there are no + // alternatives. If a better method is invented, it should be used + // instead. + let mut buf = vec![0; libc::PATH_MAX as usize]; + let n = unsafe { libc::fcntl(fd, libc::F_GETPATH, buf.as_ptr()) }; + if n == -1 { + cfg_select! { + target_os = "netbsd" => { + // fallback to procfs as last resort + let mut p = PathBuf::from("/proc/self/fd"); + p.push(&fd.to_string()); + return run_path_with_cstr(&p, &readlink).ok() + } + _ => { + return None; + } + } + } + let l = buf.iter().position(|&c| c == 0).unwrap(); + buf.truncate(l as usize); + buf.shrink_to_fit(); + Some(PathBuf::from(OsString::from_vec(buf))) + } + + #[cfg(target_os = "freebsd")] + fn get_path(fd: c_int) -> Option { + let info = Box::::new_zeroed(); + let mut info = unsafe { info.assume_init() }; + info.kf_structsize = size_of::() as libc::c_int; + let n = unsafe { libc::fcntl(fd, libc::F_KINFO, &mut *info) }; + if n == -1 { + return None; + } + let buf = unsafe { CStr::from_ptr(info.kf_path.as_mut_ptr()).to_bytes().to_vec() }; + Some(PathBuf::from(OsString::from_vec(buf))) + } + + #[cfg(target_os = "vxworks")] + fn get_path(fd: c_int) -> Option { + let mut buf = vec![0; libc::PATH_MAX as usize]; + let n = unsafe { libc::ioctl(fd, libc::FIOGETNAME, buf.as_ptr()) }; + if n == -1 { + return None; + } + let l = buf.iter().position(|&c| c == 0).unwrap(); + buf.truncate(l as usize); + Some(PathBuf::from(OsString::from_vec(buf))) + } + + #[cfg(not(any( + target_os = "linux", + target_os = "vxworks", + target_os = "freebsd", + target_os = "netbsd", + target_os = "illumos", + target_os = "solaris", + target_vendor = "apple", + )))] + fn get_path(_fd: c_int) -> Option { + // FIXME(#24570): implement this for other Unix platforms + None + } + + get_path(fd) +} #[cfg(any( target_os = "aix", @@ -874,7 +998,7 @@ pub(crate) fn debug_assert_fd_is_open(fd: RawFd) { } } -impl Drop for Dir { +impl Drop for DirStream { fn drop(&mut self) { // dirfd isn't supported everywhere #[cfg(not(any( @@ -902,6 +1026,11 @@ impl Drop for Dir { } } +// SAFETY: `int dirfd (DIR *dirstream)` is MT-safe, implying that the pointer +// may be safely sent among threads. +unsafe impl Send for DirStream {} +unsafe impl Sync for DirStream {} + impl DirEntry { pub fn path(&self) -> PathBuf { self.dir.root.join(self.file_name_os_str()) @@ -1860,102 +1989,8 @@ impl FromRawFd for File { impl fmt::Debug for File { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - #[cfg(any(target_os = "linux", target_os = "illumos", target_os = "solaris"))] - fn get_path(fd: c_int) -> Option { - let mut p = PathBuf::from("/proc/self/fd"); - p.push(&fd.to_string()); - run_path_with_cstr(&p, &readlink).ok() - } - - #[cfg(any(target_vendor = "apple", target_os = "netbsd"))] - fn get_path(fd: c_int) -> Option { - // FIXME: The use of PATH_MAX is generally not encouraged, but it - // is inevitable in this case because Apple targets and NetBSD define `fcntl` - // with `F_GETPATH` in terms of `MAXPATHLEN`, and there are no - // alternatives. If a better method is invented, it should be used - // instead. - let mut buf = vec![0; libc::PATH_MAX as usize]; - let n = unsafe { libc::fcntl(fd, libc::F_GETPATH, buf.as_ptr()) }; - if n == -1 { - cfg_select! { - target_os = "netbsd" => { - // fallback to procfs as last resort - let mut p = PathBuf::from("/proc/self/fd"); - p.push(&fd.to_string()); - return run_path_with_cstr(&p, &readlink).ok() - } - _ => { - return None; - } - } - } - let l = buf.iter().position(|&c| c == 0).unwrap(); - buf.truncate(l as usize); - buf.shrink_to_fit(); - Some(PathBuf::from(OsString::from_vec(buf))) - } - - #[cfg(target_os = "freebsd")] - fn get_path(fd: c_int) -> Option { - let info = Box::::new_zeroed(); - let mut info = unsafe { info.assume_init() }; - info.kf_structsize = size_of::() as libc::c_int; - let n = unsafe { libc::fcntl(fd, libc::F_KINFO, &mut *info) }; - if n == -1 { - return None; - } - let buf = unsafe { CStr::from_ptr(info.kf_path.as_mut_ptr()).to_bytes().to_vec() }; - Some(PathBuf::from(OsString::from_vec(buf))) - } - - #[cfg(target_os = "vxworks")] - fn get_path(fd: c_int) -> Option { - let mut buf = vec![0; libc::PATH_MAX as usize]; - let n = unsafe { libc::ioctl(fd, libc::FIOGETNAME, buf.as_ptr()) }; - if n == -1 { - return None; - } - let l = buf.iter().position(|&c| c == 0).unwrap(); - buf.truncate(l as usize); - Some(PathBuf::from(OsString::from_vec(buf))) - } - - #[cfg(not(any( - target_os = "linux", - target_os = "vxworks", - target_os = "freebsd", - target_os = "netbsd", - target_os = "illumos", - target_os = "solaris", - target_vendor = "apple", - )))] - fn get_path(_fd: c_int) -> Option { - // FIXME(#24570): implement this for other Unix platforms - None - } - - fn get_mode(fd: c_int) -> Option<(bool, bool)> { - let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) }; - if mode == -1 { - return None; - } - match mode & libc::O_ACCMODE { - libc::O_RDONLY => Some((true, false)), - libc::O_RDWR => Some((true, true)), - libc::O_WRONLY => Some((false, true)), - _ => None, - } - } - let fd = self.as_raw_fd(); - let mut b = f.debug_struct("File"); - b.field("fd", &fd); - if let Some(path) = get_path(fd) { - b.field("path", &path); - } - if let Some((read, write)) = get_mode(fd) { - b.field("read", &read).field("write", &write); - } + let mut b = debug_path_fd(fd, f, "File"); b.finish() } } @@ -2033,7 +2068,7 @@ pub fn readdir(path: &Path) -> io::Result { Err(Error::last_os_error()) } else { let root = path.to_path_buf(); - let inner = InnerReadDir { dirp: Dir(ptr), root }; + let inner = InnerReadDir { dirp: DirStream(ptr), root }; Ok(ReadDir::new(inner)) } } @@ -2493,7 +2528,8 @@ mod remove_dir_impl { use libc::{fdopendir, openat64 as openat, unlinkat}; use super::{ - AsRawFd, Dir, DirEntry, FromRawFd, InnerReadDir, IntoRawFd, OwnedFd, RawFd, ReadDir, lstat, + AsRawFd, DirEntry, DirStream, FromRawFd, InnerReadDir, IntoRawFd, OwnedFd, RawFd, ReadDir, + lstat, }; use crate::ffi::CStr; use crate::io; @@ -2517,7 +2553,7 @@ mod remove_dir_impl { if ptr.is_null() { return Err(io::Error::last_os_error()); } - let dirp = Dir(ptr); + let dirp = DirStream(ptr); // file descriptor is automatically closed by libc::closedir() now, so give up ownership let new_parent_fd = dir_fd.into_raw_fd(); // a valid root is not needed because we do not call any functions involving the full path diff --git a/library/std/src/sys/fs/unix/dir.rs b/library/std/src/sys/fs/unix/dir.rs new file mode 100644 index 000000000000..094d1bfd3168 --- /dev/null +++ b/library/std/src/sys/fs/unix/dir.rs @@ -0,0 +1,114 @@ +use libc::c_int; + +cfg_select! { + not( + any( + all(target_os = "linux", not(target_env = "musl")), + target_os = "l4re", + target_os = "android", + target_os = "hurd", + ) + ) => { + use libc::{open as open64, openat as openat64}; + } + _ => { + use libc::{open64, openat64}; + } +} + +use crate::ffi::CStr; +use crate::os::fd::{AsFd, BorrowedFd, IntoRawFd, OwnedFd, RawFd}; +#[cfg(target_family = "unix")] +use crate::os::unix::io::{AsRawFd, FromRawFd}; +#[cfg(target_os = "wasi")] +use crate::os::wasi::io::{AsRawFd, FromRawFd}; +use crate::path::Path; +use crate::sys::fd::FileDesc; +use crate::sys::fs::OpenOptions; +use crate::sys::fs::unix::{File, debug_path_fd}; +use crate::sys::helpers::run_path_with_cstr; +use crate::sys::{AsInner, FromInner, IntoInner, cvt_r}; +use crate::{fmt, fs, io}; + +pub struct Dir(OwnedFd); + +impl Dir { + pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { + run_path_with_cstr(path, &|path| Self::open_with_c(path, opts)) + } + + pub fn open_file(&self, path: &Path, opts: &OpenOptions) -> io::Result { + run_path_with_cstr(path.as_ref(), &|path| self.open_file_c(path, &opts)) + } + + pub fn open_with_c(path: &CStr, opts: &OpenOptions) -> io::Result { + let flags = libc::O_CLOEXEC + | libc::O_DIRECTORY + | opts.get_access_mode()? + | opts.get_creation_mode()? + | (opts.custom_flags as c_int & !libc::O_ACCMODE); + let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode as c_int) })?; + Ok(Self(unsafe { OwnedFd::from_raw_fd(fd) })) + } + + fn open_file_c(&self, path: &CStr, opts: &OpenOptions) -> io::Result { + let flags = libc::O_CLOEXEC + | opts.get_access_mode()? + | opts.get_creation_mode()? + | (opts.custom_flags as c_int & !libc::O_ACCMODE); + let fd = cvt_r(|| unsafe { + openat64(self.0.as_raw_fd(), path.as_ptr(), flags, opts.mode as c_int) + })?; + Ok(File(unsafe { FileDesc::from_raw_fd(fd) })) + } +} + +impl fmt::Debug for Dir { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fd = self.0.as_raw_fd(); + let mut b = debug_path_fd(fd, f, "Dir"); + b.finish() + } +} + +#[unstable(feature = "dirfd", issue = "120426")] +impl AsRawFd for fs::Dir { + fn as_raw_fd(&self) -> RawFd { + self.as_inner().0.as_raw_fd() + } +} + +#[unstable(feature = "dirfd", issue = "120426")] +impl IntoRawFd for fs::Dir { + fn into_raw_fd(self) -> RawFd { + self.into_inner().0.into_raw_fd() + } +} + +#[unstable(feature = "dirfd", issue = "120426")] +impl FromRawFd for fs::Dir { + unsafe fn from_raw_fd(fd: RawFd) -> Self { + Self::from_inner(Dir(unsafe { FromRawFd::from_raw_fd(fd) })) + } +} + +#[unstable(feature = "dirfd", issue = "120426")] +impl AsFd for fs::Dir { + fn as_fd(&self) -> BorrowedFd<'_> { + self.as_inner().0.as_fd() + } +} + +#[unstable(feature = "dirfd", issue = "120426")] +impl From for OwnedFd { + fn from(value: fs::Dir) -> Self { + value.into_inner().0 + } +} + +#[unstable(feature = "dirfd", issue = "120426")] +impl From for fs::Dir { + fn from(value: OwnedFd) -> Self { + Self::from_inner(Dir(value)) + } +} diff --git a/library/std/src/sys/fs/unsupported.rs b/library/std/src/sys/fs/unsupported.rs index f222151d18e2..069b4fb8a29c 100644 --- a/library/std/src/sys/fs/unsupported.rs +++ b/library/std/src/sys/fs/unsupported.rs @@ -4,6 +4,7 @@ use crate::fs::TryLockError; use crate::hash::{Hash, Hasher}; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::path::{Path, PathBuf}; +pub use crate::sys::fs::common::Dir; use crate::sys::time::SystemTime; use crate::sys::unsupported; diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index b588b91c753b..2e3d50aa0e08 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -18,6 +18,8 @@ use crate::sys::time::SystemTime; use crate::sys::{Align8, AsInner, FromInner, IntoInner, c, cvt}; use crate::{fmt, ptr, slice}; +mod dir; +pub use dir::Dir; mod remove_dir_all; use remove_dir_all::remove_dir_all_iterative; @@ -274,7 +276,7 @@ impl OpenOptions { } } - fn get_creation_mode(&self) -> io::Result { + fn get_cmode_disposition(&self) -> io::Result<(u32, u32)> { match (self.write, self.append) { (true, false) => {} (false, false) => { @@ -296,16 +298,24 @@ impl OpenOptions { } Ok(match (self.create, self.truncate, self.create_new) { - (false, false, false) => c::OPEN_EXISTING, - (true, false, false) => c::OPEN_ALWAYS, - (false, true, false) => c::TRUNCATE_EXISTING, + (false, false, false) => (c::OPEN_EXISTING, c::FILE_OPEN), + (true, false, false) => (c::OPEN_ALWAYS, c::FILE_OPEN_IF), + (false, true, false) => (c::TRUNCATE_EXISTING, c::FILE_OVERWRITE), // `CREATE_ALWAYS` has weird semantics so we emulate it using // `OPEN_ALWAYS` and a manual truncation step. See #115745. - (true, true, false) => c::OPEN_ALWAYS, - (_, _, true) => c::CREATE_NEW, + (true, true, false) => (c::OPEN_ALWAYS, c::FILE_OVERWRITE_IF), + (_, _, true) => (c::CREATE_NEW, c::FILE_CREATE), }) } + fn get_creation_mode(&self) -> io::Result { + self.get_cmode_disposition().map(|(mode, _)| mode) + } + + fn get_disposition(&self) -> io::Result { + self.get_cmode_disposition().map(|(_, mode)| mode) + } + fn get_flags_and_attributes(&self) -> u32 { self.custom_flags | self.attributes @@ -1019,14 +1029,23 @@ impl FromRawHandle for File { } } +fn debug_path_handle<'a, 'b>( + handle: BorrowedHandle<'a>, + f: &'a mut fmt::Formatter<'b>, + name: &str, +) -> fmt::DebugStruct<'a, 'b> { + // FIXME(#24570): add more info here (e.g., mode) + let mut b = f.debug_struct(name); + b.field("handle", &handle.as_raw_handle()); + if let Ok(path) = get_path(handle) { + b.field("path", &path); + } + b +} + impl fmt::Debug for File { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // FIXME(#24570): add more info here (e.g., mode) - let mut b = f.debug_struct("File"); - b.field("handle", &self.handle.as_raw_handle()); - if let Ok(path) = get_path(self) { - b.field("path", &path); - } + let mut b = debug_path_handle(self.handle.as_handle(), f, "File"); b.finish() } } @@ -1292,8 +1311,8 @@ pub fn rename(old: &WCStr, new: &WCStr) -> io::Result<()> { Layout::from_size_align(struct_size as usize, align_of::()) .unwrap(); - // SAFETY: We allocate enough memory for a full FILE_RENAME_INFO struct and a filename. let file_rename_info; + // SAFETY: We allocate enough memory for a full FILE_RENAME_INFO struct and a filename. unsafe { file_rename_info = alloc(layout).cast::(); if file_rename_info.is_null() { @@ -1530,10 +1549,10 @@ pub fn set_times_nofollow(p: &WCStr, times: FileTimes) -> io::Result<()> { file.set_times(times) } -fn get_path(f: &File) -> io::Result { +fn get_path(f: impl AsRawHandle) -> io::Result { fill_utf16_buf( |buf, sz| unsafe { - c::GetFinalPathNameByHandleW(f.handle.as_raw_handle(), buf, sz, c::VOLUME_NAME_DOS) + c::GetFinalPathNameByHandleW(f.as_raw_handle(), buf, sz, c::VOLUME_NAME_DOS) }, |buf| PathBuf::from(OsString::from_wide(buf)), ) @@ -1546,7 +1565,7 @@ pub fn canonicalize(p: &WCStr) -> io::Result { // This flag is so we can open directories too opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS); let f = File::open_native(p, &opts)?; - get_path(&f) + get_path(f.handle) } pub fn copy(from: &WCStr, to: &WCStr) -> io::Result { diff --git a/library/std/src/sys/fs/windows/dir.rs b/library/std/src/sys/fs/windows/dir.rs new file mode 100644 index 000000000000..3f617806c6c3 --- /dev/null +++ b/library/std/src/sys/fs/windows/dir.rs @@ -0,0 +1,153 @@ +use crate::os::windows::io::{ + AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, HandleOrInvalid, IntoRawHandle, + OwnedHandle, RawHandle, +}; +use crate::path::Path; +use crate::sys::api::{UnicodeStrRef, WinError}; +use crate::sys::fs::windows::debug_path_handle; +use crate::sys::fs::{File, OpenOptions}; +use crate::sys::handle::Handle; +use crate::sys::path::{WCStr, with_native_path}; +use crate::sys::{AsInner, FromInner, IntoInner, IoResult, c, to_u16s}; +use crate::{fmt, fs, io, ptr}; + +pub struct Dir { + handle: Handle, +} + +/// A wrapper around a raw NtCreateFile call. +/// +/// This isn't completely safe because `OBJECT_ATTRIBUTES` contains raw pointers. +unsafe fn nt_create_file( + opts: &OpenOptions, + object_attributes: &c::OBJECT_ATTRIBUTES, + create_options: c::NTCREATEFILE_CREATE_OPTIONS, +) -> io::Result { + let mut handle = ptr::null_mut(); + let mut io_status = c::IO_STATUS_BLOCK::PENDING; + // SYNCHRONIZE is included in FILE_GENERIC_READ, but not GENERIC_READ, so we add it manually + let access = opts.get_access_mode()? | c::SYNCHRONIZE; + // one of FILE_SYNCHRONOUS_IO_{,NON}ALERT is required for later operations to succeed. + let options = create_options | c::FILE_SYNCHRONOUS_IO_NONALERT; + let status = unsafe { + c::NtCreateFile( + &mut handle, + access, + object_attributes, + &mut io_status, + ptr::null(), + c::FILE_ATTRIBUTE_NORMAL, + opts.share_mode, + opts.get_disposition()?, + options, + ptr::null(), + 0, + ) + }; + if c::nt_success(status) { + // SAFETY: nt_success guarantees that handle is no longer null + unsafe { Ok(Handle::from_raw_handle(handle)) } + } else { + Err(WinError::new(unsafe { c::RtlNtStatusToDosError(status) })).io_result() + } +} + +impl Dir { + pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { + with_native_path(path, &|path| Self::open_with_native(path, opts)) + } + + pub fn open_file(&self, path: &Path, opts: &OpenOptions) -> io::Result { + // NtCreateFile will fail if given an absolute path and a non-null RootDirectory + if path.is_absolute() { + return File::open(path, opts); + } + let path = to_u16s(path)?; + let path = &path[..path.len() - 1]; // trim 0 byte + self.open_file_native(&path, opts).map(|handle| File { handle }) + } + + fn open_with_native(path: &WCStr, opts: &OpenOptions) -> io::Result { + let creation = opts.get_creation_mode()?; + let sa = c::SECURITY_ATTRIBUTES { + nLength: size_of::() as u32, + lpSecurityDescriptor: ptr::null_mut(), + bInheritHandle: opts.inherit_handle as c::BOOL, + }; + let handle = unsafe { + c::CreateFileW( + path.as_ptr(), + opts.get_access_mode()?, + opts.share_mode, + &raw const sa, + creation, + // FILE_FLAG_BACKUP_SEMANTICS is required to open a directory + opts.get_flags_and_attributes() | c::FILE_FLAG_BACKUP_SEMANTICS, + ptr::null_mut(), + ) + }; + match OwnedHandle::try_from(unsafe { HandleOrInvalid::from_raw_handle(handle) }) { + Ok(handle) => Ok(Self { handle: Handle::from_inner(handle) }), + Err(_) => Err(io::Error::last_os_error()), + } + } + + fn open_file_native(&self, path: &[u16], opts: &OpenOptions) -> io::Result { + let name = UnicodeStrRef::from_slice(path); + let object_attributes = c::OBJECT_ATTRIBUTES { + RootDirectory: self.handle.as_raw_handle(), + ObjectName: name.as_ptr(), + ..c::OBJECT_ATTRIBUTES::with_length() + }; + unsafe { nt_create_file(opts, &object_attributes, c::FILE_NON_DIRECTORY_FILE) } + } +} + +impl fmt::Debug for Dir { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut b = debug_path_handle(self.handle.as_handle(), f, "Dir"); + b.finish() + } +} + +#[unstable(feature = "dirfd", issue = "120426")] +impl AsRawHandle for fs::Dir { + fn as_raw_handle(&self) -> RawHandle { + self.as_inner().handle.as_raw_handle() + } +} + +#[unstable(feature = "dirhandle", issue = "120426")] +impl IntoRawHandle for fs::Dir { + fn into_raw_handle(self) -> RawHandle { + self.into_inner().handle.into_raw_handle() + } +} + +#[unstable(feature = "dirhandle", issue = "120426")] +impl FromRawHandle for fs::Dir { + unsafe fn from_raw_handle(handle: RawHandle) -> Self { + Self::from_inner(Dir { handle: unsafe { FromRawHandle::from_raw_handle(handle) } }) + } +} + +#[unstable(feature = "dirhandle", issue = "120426")] +impl AsHandle for fs::Dir { + fn as_handle(&self) -> BorrowedHandle<'_> { + self.as_inner().handle.as_handle() + } +} + +#[unstable(feature = "dirhandle", issue = "120426")] +impl From for OwnedHandle { + fn from(value: fs::Dir) -> Self { + value.into_inner().handle.into_inner() + } +} + +#[unstable(feature = "dirhandle", issue = "120426")] +impl From for fs::Dir { + fn from(value: OwnedHandle) -> Self { + Self::from_inner(Dir { handle: Handle::from_inner(value) }) + } +} From 52d65b8a626ae074f45e19c8d8cfe41a5f5e444b Mon Sep 17 00:00:00 2001 From: Alessio Date: Sun, 4 Jan 2026 03:53:26 +0100 Subject: [PATCH 0233/1061] library: clarify panic conditions in `Iterator::last` Now `Iterator::last`'s docs specify that it might panic only if the iterator is infinite, rather than if it has more than `usize::MAX` elements. --- library/core/src/iter/traits/iterator.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 84da778c3b91..f106900a3983 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -238,8 +238,7 @@ pub trait Iterator { /// /// # Panics /// - /// This function might panic if the iterator has more than [`usize::MAX`] - /// elements. + /// This function might panic if the iterator is infinite. /// /// # Examples /// From 759857cce3f0b4cb72de251595ecf8c28408cead Mon Sep 17 00:00:00 2001 From: mu001999 Date: Sun, 4 Jan 2026 11:53:31 +0800 Subject: [PATCH 0234/1061] Add missing translator resources for interface parse_cfg and parse_check_cfg --- compiler/rustc_interface/src/interface.rs | 12 ++++++++++-- tests/ui/cfg/invalid-cli-cfg-pred.rs | 5 +++++ tests/ui/cfg/invalid-cli-cfg-pred.stderr | 7 +++++++ tests/ui/cfg/invalid-cli-check-cfg-pred.rs | 5 +++++ tests/ui/cfg/invalid-cli-check-cfg-pred.stderr | 10 ++++++++++ 5 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 tests/ui/cfg/invalid-cli-cfg-pred.rs create mode 100644 tests/ui/cfg/invalid-cli-cfg-pred.stderr create mode 100644 tests/ui/cfg/invalid-cli-check-cfg-pred.rs create mode 100644 tests/ui/cfg/invalid-cli-check-cfg-pred.stderr diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index c0f8f33692e8..b2c4a9158197 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -55,7 +55,11 @@ pub(crate) fn parse_cfg(dcx: DiagCtxtHandle<'_>, cfgs: Vec) -> Cfg { cfgs.into_iter() .map(|s| { let psess = ParseSess::emitter_with_note( - vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE], + vec![ + crate::DEFAULT_LOCALE_RESOURCE, + rustc_parse::DEFAULT_LOCALE_RESOURCE, + rustc_session::DEFAULT_LOCALE_RESOURCE, + ], format!("this occurred on the command line: `--cfg={s}`"), ); let filename = FileName::cfg_spec_source_code(&s); @@ -129,7 +133,11 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec) -> Ch for s in specs { let psess = ParseSess::emitter_with_note( - vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE], + vec![ + crate::DEFAULT_LOCALE_RESOURCE, + rustc_parse::DEFAULT_LOCALE_RESOURCE, + rustc_session::DEFAULT_LOCALE_RESOURCE, + ], format!("this occurred on the command line: `--check-cfg={s}`"), ); let filename = FileName::cfg_spec_source_code(&s); diff --git a/tests/ui/cfg/invalid-cli-cfg-pred.rs b/tests/ui/cfg/invalid-cli-cfg-pred.rs new file mode 100644 index 000000000000..fdfb6b18d96b --- /dev/null +++ b/tests/ui/cfg/invalid-cli-cfg-pred.rs @@ -0,0 +1,5 @@ +//@ compile-flags: --cfg foo=1x + +fn main() {} + +//~? ERROR invalid `--cfg` argument diff --git a/tests/ui/cfg/invalid-cli-cfg-pred.stderr b/tests/ui/cfg/invalid-cli-cfg-pred.stderr new file mode 100644 index 000000000000..2f5ed55a6423 --- /dev/null +++ b/tests/ui/cfg/invalid-cli-cfg-pred.stderr @@ -0,0 +1,7 @@ +error: invalid suffix `x` for number literal + | + = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) + = note: this occurred on the command line: `--cfg=foo=1x` + +error: invalid `--cfg` argument: `foo=1x` (expected `key` or `key="value"`, ensure escaping is appropriate for your shell, try 'key="value"' or key=\"value\") + diff --git a/tests/ui/cfg/invalid-cli-check-cfg-pred.rs b/tests/ui/cfg/invalid-cli-check-cfg-pred.rs new file mode 100644 index 000000000000..30417a912bfc --- /dev/null +++ b/tests/ui/cfg/invalid-cli-check-cfg-pred.rs @@ -0,0 +1,5 @@ +//@ compile-flags: --check-cfg 'foo=1x' + +fn main() {} + +//~? ERROR invalid `--check-cfg` argument diff --git a/tests/ui/cfg/invalid-cli-check-cfg-pred.stderr b/tests/ui/cfg/invalid-cli-check-cfg-pred.stderr new file mode 100644 index 000000000000..be8299aa9edf --- /dev/null +++ b/tests/ui/cfg/invalid-cli-check-cfg-pred.stderr @@ -0,0 +1,10 @@ +error: invalid suffix `x` for number literal + | + = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) + = note: this occurred on the command line: `--check-cfg=foo=1x` + +error: invalid `--check-cfg` argument: `foo=1x` + | + = note: expected `cfg(name, values("value1", "value2", ... "valueN"))` + = note: visit for more details + From 46bb414d69749ad7afe3ea8e0e4fd09ae7fe3d6b Mon Sep 17 00:00:00 2001 From: enthropy7 <221884178+enthropy7@users.noreply.github.com> Date: Sat, 3 Jan 2026 16:22:29 +0300 Subject: [PATCH 0235/1061] Forbid generic parameters in types of #[type_const] items --- compiler/rustc_resolve/src/late.rs | 58 ++++++++++++++++++- .../assoc-const-eq-bound-var-in-ty-not-wf.rs | 1 + ...soc-const-eq-bound-var-in-ty-not-wf.stderr | 4 +- .../assoc-const-eq-bound-var-in-ty.rs | 1 + .../assoc-const-eq-esc-bound-var-in-ty.rs | 7 ++- .../assoc-const-eq-esc-bound-var-in-ty.stderr | 2 +- .../assoc-const-eq-param-in-ty.rs | 1 + .../assoc-const-eq-param-in-ty.stderr | 22 +++---- .../assoc-const-eq-supertraits.rs | 1 + ...pe_const-generic-param-in-type.gate.stderr | 38 ++++++++++++ ..._const-generic-param-in-type.nogate.stderr | 57 ++++++++++++++++++ .../mgca/type_const-generic-param-in-type.rs | 54 +++++++++++++++++ 12 files changed, 228 insertions(+), 18 deletions(-) create mode 100644 tests/ui/const-generics/mgca/type_const-generic-param-in-type.gate.stderr create mode 100644 tests/ui/const-generics/mgca/type_const-generic-param-in-type.nogate.stderr create mode 100644 tests/ui/const-generics/mgca/type_const-generic-param-in-type.rs diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index dd80f5da508c..2bbaacce53f8 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2855,6 +2855,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ref define_opaque, .. }) => { + let is_type_const = attr::contains_name(&item.attrs, sym::type_const); self.with_generic_param_rib( &generics.params, RibKind::Item( @@ -2873,7 +2874,22 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { this.with_lifetime_rib( LifetimeRibKind::Elided(LifetimeRes::Static), - |this| this.visit_ty(ty), + |this| { + if is_type_const + && !this.r.tcx.features().generic_const_parameter_types() + { + this.with_rib(TypeNS, RibKind::ConstParamTy, |this| { + this.with_rib(ValueNS, RibKind::ConstParamTy, |this| { + this.with_lifetime_rib( + LifetimeRibKind::ConstParamTy, + |this| this.visit_ty(ty), + ) + }) + }); + } else { + this.visit_ty(ty); + } + }, ); if let Some(rhs) = rhs { @@ -3213,6 +3229,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { define_opaque, .. }) => { + let is_type_const = attr::contains_name(&item.attrs, sym::type_const); self.with_generic_param_rib( &generics.params, RibKind::AssocItem, @@ -3227,7 +3244,20 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }, |this| { this.visit_generics(generics); - this.visit_ty(ty); + if is_type_const + && !this.r.tcx.features().generic_const_parameter_types() + { + this.with_rib(TypeNS, RibKind::ConstParamTy, |this| { + this.with_rib(ValueNS, RibKind::ConstParamTy, |this| { + this.with_lifetime_rib( + LifetimeRibKind::ConstParamTy, + |this| this.visit_ty(ty), + ) + }) + }); + } else { + this.visit_ty(ty); + } // Only impose the restrictions of `ConstRibKind` for an // actual constant expression in a provided default. @@ -3422,6 +3452,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { .. }) => { debug!("resolve_implementation AssocItemKind::Const"); + let is_type_const = attr::contains_name(&item.attrs, sym::type_const); self.with_generic_param_rib( &generics.params, RibKind::AssocItem, @@ -3458,7 +3489,28 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ); this.visit_generics(generics); - this.visit_ty(ty); + if is_type_const + && !this + .r + .tcx + .features() + .generic_const_parameter_types() + { + this.with_rib(TypeNS, RibKind::ConstParamTy, |this| { + this.with_rib( + ValueNS, + RibKind::ConstParamTy, + |this| { + this.with_lifetime_rib( + LifetimeRibKind::ConstParamTy, + |this| this.visit_ty(ty), + ) + }, + ) + }); + } else { + this.visit_ty(ty); + } if let Some(rhs) = rhs { // We allow arbitrary const expressions inside of associated consts, // even if they are potentially not const evaluatable. diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs index 7f8b3036c3e8..50914fb192ff 100644 --- a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs +++ b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs @@ -5,6 +5,7 @@ min_generic_const_args, adt_const_params, unsized_const_params, + generic_const_parameter_types, )] #![allow(incomplete_features)] diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr index 76868715b861..fd49e151b8e6 100644 --- a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr @@ -1,11 +1,11 @@ error: higher-ranked subtype error - --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:13 + --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:22:13 | LL | K = const { () } | ^^^^^^^^^^^^ error: higher-ranked subtype error - --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:13 + --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:22:13 | LL | K = const { () } | ^^^^^^^^^^^^ diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty.rs b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty.rs index d3975bc19ad3..54e199d702c9 100644 --- a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty.rs +++ b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty.rs @@ -8,6 +8,7 @@ min_generic_const_args, adt_const_params, unsized_const_params, + generic_const_parameter_types, )] #![allow(incomplete_features)] diff --git a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs b/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs index 2571af57e66b..7f9a04bbf0fc 100644 --- a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs +++ b/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs @@ -1,6 +1,11 @@ // Detect and reject escaping late-bound generic params in // the type of assoc consts used in an equality bound. -#![feature(associated_const_equality, min_generic_const_args, unsized_const_params)] +#![feature( + associated_const_equality, + min_generic_const_args, + unsized_const_params, + generic_const_parameter_types, +)] #![allow(incomplete_features)] trait Trait<'a> { diff --git a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr b/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr index 44304443ac54..e22d9bfed7ef 100644 --- a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr @@ -1,5 +1,5 @@ error: the type of the associated constant `K` cannot capture late-bound generic parameters - --> $DIR/assoc-const-eq-esc-bound-var-in-ty.rs:11:35 + --> $DIR/assoc-const-eq-esc-bound-var-in-ty.rs:16:35 | LL | fn take(_: impl for<'r> Trait<'r, K = const { &() }>) {} | -- ^ its type cannot capture the late-bound lifetime parameter `'r` diff --git a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs index 242ad385947a..ea2f60cd6187 100644 --- a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs +++ b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs @@ -5,6 +5,7 @@ min_generic_const_args, adt_const_params, unsized_const_params, + generic_const_parameter_types, )] #![allow(incomplete_features)] diff --git a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr index b742e68044b0..ae6a35b4b9f2 100644 --- a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr @@ -1,5 +1,5 @@ error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:22:29 + --> $DIR/assoc-const-eq-param-in-ty.rs:23:29 | LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( | -- the lifetime parameter `'r` is defined here @@ -10,7 +10,7 @@ LL | _: impl Trait<'r, A, Q, K = const { loop {} }> = note: `K` has type `&'r [A; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:22:29 + --> $DIR/assoc-const-eq-param-in-ty.rs:23:29 | LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( | - the type parameter `A` is defined here @@ -21,7 +21,7 @@ LL | _: impl Trait<'r, A, Q, K = const { loop {} }> = note: `K` has type `&'r [A; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:22:29 + --> $DIR/assoc-const-eq-param-in-ty.rs:23:29 | LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( | - the const parameter `Q` is defined here @@ -32,7 +32,7 @@ LL | _: impl Trait<'r, A, Q, K = const { loop {} }> = note: `K` has type `&'r [A; Q]` error: the type of the associated constant `SELF` must not depend on `impl Trait` - --> $DIR/assoc-const-eq-param-in-ty.rs:39:26 + --> $DIR/assoc-const-eq-param-in-ty.rs:40:26 | LL | fn take1(_: impl Project) {} | -------------^^^^------------ @@ -41,7 +41,7 @@ LL | fn take1(_: impl Project) {} | the `impl Trait` is specified here error: the type of the associated constant `SELF` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:44:21 + --> $DIR/assoc-const-eq-param-in-ty.rs:45:21 | LL | fn take2>(_: P) {} | - ^^^^ its type must not depend on the type parameter `P` @@ -51,7 +51,7 @@ LL | fn take2>(_: P) {} = note: `SELF` has type `P` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:54:52 | LL | trait Iface<'r>: ConstParamTy_ { | -- the lifetime parameter `'r` is defined here @@ -62,7 +62,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> = note: `K` has type `&'r [Self; Q]` error: the type of the associated constant `K` must not depend on `Self` - --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:54:52 | LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | ^ its type must not depend on `Self` @@ -70,7 +70,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> = note: `K` has type `&'r [Self; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:54:52 | LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | - ^ its type must not depend on the const parameter `Q` @@ -80,7 +80,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> = note: `K` has type `&'r [Self; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:54:52 | LL | trait Iface<'r>: ConstParamTy_ { | -- the lifetime parameter `'r` is defined here @@ -92,7 +92,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: the type of the associated constant `K` must not depend on `Self` - --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:54:52 | LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | ^ its type must not depend on `Self` @@ -101,7 +101,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:54:52 | LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | - ^ its type must not depend on the const parameter `Q` diff --git a/tests/ui/associated-consts/assoc-const-eq-supertraits.rs b/tests/ui/associated-consts/assoc-const-eq-supertraits.rs index d9b8a8cd43d7..c092285dfcd4 100644 --- a/tests/ui/associated-consts/assoc-const-eq-supertraits.rs +++ b/tests/ui/associated-consts/assoc-const-eq-supertraits.rs @@ -8,6 +8,7 @@ min_generic_const_args, adt_const_params, unsized_const_params, + generic_const_parameter_types, )] #![allow(incomplete_features)] diff --git a/tests/ui/const-generics/mgca/type_const-generic-param-in-type.gate.stderr b/tests/ui/const-generics/mgca/type_const-generic-param-in-type.gate.stderr new file mode 100644 index 000000000000..8a64af285da5 --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-generic-param-in-type.gate.stderr @@ -0,0 +1,38 @@ +error: anonymous constants referencing generics are not yet supported + --> $DIR/type_const-generic-param-in-type.rs:9:53 + | +LL | const FOO: [T; 0] = const { [] }; + | ^^^^^^^^^^^^ + +error: anonymous constants referencing generics are not yet supported + --> $DIR/type_const-generic-param-in-type.rs:14:38 + | +LL | const BAR: [(); N] = const { [] }; + | ^^^^^^^^^^^^ + +error: anonymous constants with lifetimes in their type are not yet supported + --> $DIR/type_const-generic-param-in-type.rs:19:30 + | +LL | const BAZ<'a>: [&'a (); 0] = const { [] }; + | ^^^^^^^^^^^^ + +error: anonymous constants referencing generics are not yet supported + --> $DIR/type_const-generic-param-in-type.rs:39:59 + | +LL | const ASSOC: [T; 0] = const { [] }; + | ^^^^^^^^^^^^ + +error: anonymous constants referencing generics are not yet supported + --> $DIR/type_const-generic-param-in-type.rs:44:50 + | +LL | const ASSOC_CONST: [(); N] = const { [] }; + | ^^^^^^^^^^^^ + +error: anonymous constants with lifetimes in their type are not yet supported + --> $DIR/type_const-generic-param-in-type.rs:49:39 + | +LL | const ASSOC_LT<'a>: [&'a (); 0] = const { [] }; + | ^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/const-generics/mgca/type_const-generic-param-in-type.nogate.stderr b/tests/ui/const-generics/mgca/type_const-generic-param-in-type.nogate.stderr new file mode 100644 index 000000000000..14ae276324ad --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-generic-param-in-type.nogate.stderr @@ -0,0 +1,57 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/type_const-generic-param-in-type.rs:9:45 + | +LL | const FOO: [T; 0] = const { [] }; + | ^ the type must not depend on the parameter `T` + +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/type_const-generic-param-in-type.rs:14:33 + | +LL | const BAR: [(); N] = const { [] }; + | ^ the type must not depend on the parameter `N` + +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/type_const-generic-param-in-type.rs:19:18 + | +LL | const BAZ<'a>: [&'a (); 0] = const { [] }; + | ^^ the type must not depend on the parameter `'a` + +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/type_const-generic-param-in-type.rs:25:51 + | +LL | const ASSOC: [T; 0]; + | ^ the type must not depend on the parameter `T` + +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/type_const-generic-param-in-type.rs:29:45 + | +LL | const ASSOC_CONST: [(); N]; + | ^ the type must not depend on the parameter `N` + +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/type_const-generic-param-in-type.rs:33:27 + | +LL | const ASSOC_LT<'a>: [&'a (); 0]; + | ^^ the type must not depend on the parameter `'a` + +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/type_const-generic-param-in-type.rs:39:51 + | +LL | const ASSOC: [T; 0] = const { [] }; + | ^ the type must not depend on the parameter `T` + +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/type_const-generic-param-in-type.rs:44:45 + | +LL | const ASSOC_CONST: [(); N] = const { [] }; + | ^ the type must not depend on the parameter `N` + +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/type_const-generic-param-in-type.rs:49:27 + | +LL | const ASSOC_LT<'a>: [&'a (); 0] = const { [] }; + | ^^ the type must not depend on the parameter `'a` + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0770`. diff --git a/tests/ui/const-generics/mgca/type_const-generic-param-in-type.rs b/tests/ui/const-generics/mgca/type_const-generic-param-in-type.rs new file mode 100644 index 000000000000..f1a4aba9bcee --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-generic-param-in-type.rs @@ -0,0 +1,54 @@ +//@ revisions: nogate gate +//@ [gate] check-fail +// FIXME(generic_const_parameter_types): this should pass +#![expect(incomplete_features)] +#![feature(adt_const_params, unsized_const_params, min_generic_const_args, generic_const_items)] +#![cfg_attr(gate, feature(generic_const_parameter_types))] + +#[type_const] +const FOO: [T; 0] = const { [] }; +//[nogate]~^ ERROR the type of const parameters must not depend on other generic parameters +//[gate]~^^ ERROR anonymous constants referencing generics are not yet supported + +#[type_const] +const BAR: [(); N] = const { [] }; +//[nogate]~^ ERROR the type of const parameters must not depend on other generic parameters +//[gate]~^^ ERROR anonymous constants referencing generics are not yet supported + +#[type_const] +const BAZ<'a>: [&'a (); 0] = const { [] }; +//[nogate]~^ ERROR the type of const parameters must not depend on other generic parameters +//[gate]~^^ ERROR anonymous constants with lifetimes in their type are not yet supported + +trait Tr { + #[type_const] + const ASSOC: [T; 0]; + //[nogate]~^ ERROR the type of const parameters must not depend on other generic parameters + + #[type_const] + const ASSOC_CONST: [(); N]; + //[nogate]~^ ERROR the type of const parameters must not depend on other generic parameters + + #[type_const] + const ASSOC_LT<'a>: [&'a (); 0]; + //[nogate]~^ ERROR the type of const parameters must not depend on other generic parameters +} + +impl Tr for () { + #[type_const] + const ASSOC: [T; 0] = const { [] }; + //[nogate]~^ ERROR the type of const parameters must not depend on other generic parameters + //[gate]~^^ ERROR anonymous constants referencing generics are not yet supported + + #[type_const] + const ASSOC_CONST: [(); N] = const { [] }; + //[nogate]~^ ERROR the type of const parameters must not depend on other generic parameters + //[gate]~^^ ERROR anonymous constants referencing generics are not yet supported + + #[type_const] + const ASSOC_LT<'a>: [&'a (); 0] = const { [] }; + //[nogate]~^ ERROR the type of const parameters must not depend on other generic parameters + //[gate]~^^ ERROR anonymous constants with lifetimes in their type are not yet supported +} + +fn main() {} From de377241fb6490ed92fc8c9b6d9d2a0428da26f8 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 4 Jan 2026 14:12:40 +1100 Subject: [PATCH 0236/1061] Prefer to pass HIR nodes instead of loose types/spans This should make it easier to keep track of where the types/spans came from. --- .../rustc_mir_build/src/thir/pattern/mod.rs | 91 +++++++++++++------ 1 file changed, 62 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 0310003e7d58..988baae49141 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -4,6 +4,7 @@ mod check_match; mod const_to_pat; mod migration; +use std::assert_matches::assert_matches; use std::cmp::Ordering; use std::sync::Arc; @@ -21,7 +22,7 @@ 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::{ErrorGuaranteed, Span}; +use rustc_span::ErrorGuaranteed; use tracing::{debug, instrument}; pub(crate) use self::check_match::check_match; @@ -129,15 +130,20 @@ impl<'tcx> PatCtxt<'tcx> { fn lower_pattern_range_endpoint( &mut self, + pat: &'tcx hir::Pat<'tcx>, // Range pattern containing the endpoint expr: Option<&'tcx hir::PatExpr<'tcx>>, // Out-parameter collecting extra data to be reapplied by the caller ascriptions: &mut Vec>, ) -> Result>, ErrorGuaranteed> { + assert_matches!(pat.kind, hir::PatKind::Range(..)); + + // For partly-bounded ranges like `X..` or `..X`, an endpoint will be absent. + // Return None in that case; the caller will use NegInfinity or PosInfinity instead. let Some(expr) = expr else { return Ok(None) }; // Lower the endpoint into a temporary `PatKind` that will then be // deconstructed to obtain the constant value and other data. - let mut kind: PatKind<'tcx> = self.lower_pat_expr(expr, None); + let mut kind: PatKind<'tcx> = self.lower_pat_expr(pat, expr); // Unpeel any ascription or inline-const wrapper nodes. loop { @@ -214,12 +220,14 @@ impl<'tcx> PatCtxt<'tcx> { fn lower_pattern_range( &mut self, + pat: &'tcx hir::Pat<'tcx>, lo_expr: Option<&'tcx hir::PatExpr<'tcx>>, hi_expr: Option<&'tcx hir::PatExpr<'tcx>>, end: RangeEnd, - ty: Ty<'tcx>, - span: Span, ) -> Result, ErrorGuaranteed> { + let ty = self.typeck_results.node_type(pat.hir_id); + let span = pat.span; + if lo_expr.is_none() && hi_expr.is_none() { let msg = "found twice-open range pattern (`..`) outside of error recovery"; self.tcx.dcx().span_bug(span, msg); @@ -227,7 +235,8 @@ impl<'tcx> PatCtxt<'tcx> { // Collect extra data while lowering the endpoints, to be reapplied later. let mut ascriptions = vec![]; - let mut lower_endpoint = |expr| self.lower_pattern_range_endpoint(expr, &mut ascriptions); + let mut lower_endpoint = + |expr| self.lower_pattern_range_endpoint(pat, expr, &mut ascriptions); let lo = lower_endpoint(lo_expr)?.unwrap_or(PatRangeBoundary::NegInfinity); let hi = lower_endpoint(hi_expr)?.unwrap_or(PatRangeBoundary::PosInfinity); @@ -299,12 +308,10 @@ impl<'tcx> PatCtxt<'tcx> { hir::PatKind::Never => PatKind::Never, - hir::PatKind::Expr(value) => self.lower_pat_expr(value, Some(ty)), + hir::PatKind::Expr(value) => self.lower_pat_expr(pat, value), - hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => { - let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref()); - self.lower_pattern_range(lo_expr, hi_expr, end, ty, span) - .unwrap_or_else(PatKind::Error) + hir::PatKind::Range(lo_expr, hi_expr, end) => { + self.lower_pattern_range(pat, lo_expr, hi_expr, end).unwrap_or_else(PatKind::Error) } hir::PatKind::Deref(subpattern) => { @@ -327,7 +334,7 @@ impl<'tcx> PatCtxt<'tcx> { }, hir::PatKind::Slice(prefix, slice, suffix) => { - self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix) + self.slice_or_array_pattern(pat, prefix, slice, suffix) } hir::PatKind::Tuple(pats, ddpos) => { @@ -389,7 +396,7 @@ impl<'tcx> PatCtxt<'tcx> { }; let variant_def = adt_def.variant_of_res(res); let subpatterns = self.lower_tuple_subpats(pats, variant_def.fields.len(), ddpos); - self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns) + self.lower_variant_or_leaf(pat, None, res, subpatterns) } hir::PatKind::Struct(ref qpath, fields, _) => { @@ -406,7 +413,7 @@ impl<'tcx> PatCtxt<'tcx> { }) .collect(); - self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns) + self.lower_variant_or_leaf(pat, None, res, subpatterns) } hir::PatKind::Or(pats) => PatKind::Or { pats: self.lower_patterns(pats) }, @@ -445,12 +452,13 @@ impl<'tcx> PatCtxt<'tcx> { fn slice_or_array_pattern( &mut self, - span: Span, - ty: Ty<'tcx>, + pat: &'tcx hir::Pat<'tcx>, prefix: &'tcx [hir::Pat<'tcx>], slice: Option<&'tcx hir::Pat<'tcx>>, suffix: &'tcx [hir::Pat<'tcx>], ) -> PatKind<'tcx> { + let ty = self.typeck_results.node_type(pat.hir_id); + let prefix = self.lower_patterns(prefix); let slice = self.lower_opt_pattern(slice); let suffix = self.lower_patterns(suffix); @@ -465,18 +473,32 @@ impl<'tcx> PatCtxt<'tcx> { assert!(len >= prefix.len() as u64 + suffix.len() as u64); PatKind::Array { prefix, slice, suffix } } - _ => span_bug!(span, "bad slice pattern type {:?}", ty), + _ => span_bug!(pat.span, "bad slice pattern type {ty:?}"), } } fn lower_variant_or_leaf( &mut self, + pat: &'tcx hir::Pat<'tcx>, + expr: Option<&'tcx hir::PatExpr<'tcx>>, res: Res, - hir_id: hir::HirId, - span: Span, - ty: Ty<'tcx>, subpatterns: Vec>, ) -> PatKind<'tcx> { + // Check whether the caller should have provided an `expr` for this pattern kind. + assert_matches!( + (pat.kind, expr), + (hir::PatKind::Expr(..) | hir::PatKind::Range(..), Some(_)) + | (hir::PatKind::Struct(..) | hir::PatKind::TupleStruct(..), None) + ); + + // Use the id/span of the `hir::PatExpr`, if provided. + // Otherwise, use the id/span of the `hir::Pat`. + let (hir_id, span) = match expr { + Some(expr) => (expr.hir_id, expr.span), + None => (pat.hir_id, pat.span), + }; + let ty = self.typeck_results.node_type(hir_id); + let res = match res { Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => { let variant_id = self.tcx.parent(variant_ctor_id); @@ -563,7 +585,16 @@ impl<'tcx> PatCtxt<'tcx> { /// it to `const_to_pat`. Any other path (like enum variants without fields) /// is converted to the corresponding pattern via `lower_variant_or_leaf`. #[instrument(skip(self), level = "debug")] - fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) -> Box> { + fn lower_path( + &mut self, + pat: &'tcx hir::Pat<'tcx>, // Pattern that directly contains `expr` + expr: &'tcx hir::PatExpr<'tcx>, + qpath: &hir::QPath<'_>, + ) -> Box> { + assert_matches!(pat.kind, hir::PatKind::Expr(..) | hir::PatKind::Range(..)); + + let id = expr.hir_id; + let span = expr.span; let ty = self.typeck_results.node_type(id); let res = self.typeck_results.qpath_res(qpath, id); @@ -575,7 +606,7 @@ impl<'tcx> PatCtxt<'tcx> { _ => { // The path isn't the name of a constant, so it must actually // be a unit struct or unit variant (e.g. `Option::None`). - let kind = self.lower_variant_or_leaf(res, id, span, ty, vec![]); + let kind = self.lower_variant_or_leaf(pat, Some(expr), res, vec![]); return Box::new(Pat { span, ty, kind }); } }; @@ -615,24 +646,26 @@ impl<'tcx> PatCtxt<'tcx> { /// - Literals, possibly negated (e.g. `-128u8`, `"hello"`) fn lower_pat_expr( &mut self, + pat: &'tcx hir::Pat<'tcx>, // Pattern that directly contains `expr` expr: &'tcx hir::PatExpr<'tcx>, - pat_ty: Option>, ) -> PatKind<'tcx> { + assert_matches!(pat.kind, hir::PatKind::Expr(..) | hir::PatKind::Range(..)); match &expr.kind { - hir::PatExprKind::Path(qpath) => self.lower_path(qpath, expr.hir_id, expr.span).kind, + hir::PatExprKind::Path(qpath) => self.lower_path(pat, expr, qpath).kind, hir::PatExprKind::Lit { lit, negated } => { // We handle byte string literal patterns by using the pattern's type instead of the // literal's type in `const_to_pat`: if the literal `b"..."` matches on a slice reference, // the pattern's type will be `&[u8]` whereas the literal's type is `&[u8; 3]`; using the // pattern's type means we'll properly translate it to a slice reference pattern. This works // because slices and arrays have the same valtree representation. - let ct_ty = match pat_ty { - Some(pat_ty) => pat_ty, - None => self.typeck_results.node_type(expr.hir_id), - }; - let lit_input = LitToConstInput { lit: lit.node, ty: ct_ty, neg: *negated }; + // + // Under `feature(deref_patterns)`, this adjustment can also convert string literal + // patterns to `str`, and byte-string literal patterns to `[u8; N]` or `[u8]`. + + let pat_ty = self.typeck_results.node_type(pat.hir_id); + let lit_input = LitToConstInput { lit: lit.node, ty: pat_ty, neg: *negated }; let constant = self.tcx.at(expr.span).lit_to_const(lit_input); - self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind + self.const_to_pat(constant, pat_ty, expr.hir_id, lit.span).kind } } } From 9302232addcd9443e52452845d24eaf709427f82 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sun, 4 Jan 2026 05:03:43 +0000 Subject: [PATCH 0237/1061] Prepare for merging from rust-lang/rust This updates the rust-version file to f57b9e6f565a1847e83a63f3e90faa3870536c1f. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index f22aff761e8d..c44422d758c5 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -e8f3cfc0de70bf82583591f6656e1fba3140253e +f57b9e6f565a1847e83a63f3e90faa3870536c1f From 7c02e3c6ebfaa9d70d7a358dfe3209d110b2c618 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Sun, 4 Jan 2026 17:44:15 +0900 Subject: [PATCH 0238/1061] Fix ambig-unambig-ty-and-consts link --- compiler/rustc_hir/src/hir.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index da3e79efd6df..817eddefe5e8 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -440,7 +440,7 @@ impl<'hir> ConstItemRhs<'hir> { /// versus const args that are literals or have arbitrary computations (e.g., `{ 1 + 3 }`). /// /// For an explanation of the `Unambig` generic parameter see the dev-guide: -/// +/// #[derive(Clone, Copy, Debug, HashStable_Generic)] #[repr(C)] pub struct ConstArg<'hir, Unambig = ()> { @@ -3374,7 +3374,7 @@ pub enum AmbigArg {} /// Represents a type in the `HIR`. /// /// For an explanation of the `Unambig` generic parameter see the dev-guide: -/// +/// #[derive(Debug, Clone, Copy, HashStable_Generic)] #[repr(C)] pub struct Ty<'hir, Unambig = ()> { @@ -3713,7 +3713,7 @@ pub enum InferDelegationKind { /// The various kinds of types recognized by the compiler. /// /// For an explanation of the `Unambig` generic parameter see the dev-guide: -/// +/// // SAFETY: `repr(u8)` is required so that `TyKind<()>` and `TyKind` are layout compatible #[repr(u8, C)] #[derive(Debug, Clone, Copy, HashStable_Generic)] From f4112ee9b655027dc9526c529f074e6f15fe044a Mon Sep 17 00:00:00 2001 From: Mattias Petersson Date: Sun, 28 Dec 2025 16:56:17 +0100 Subject: [PATCH 0239/1061] Fix commit according to PR review Changed so cargo specifies the binary collector, removing the need to link to its local binary. Clarified that the SHAs should be from the rustc-repo, but the command should be ran in the rustc-perf repo. --- src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md b/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md index 19935d3d262f..7c7639a1ac3d 100644 --- a/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md +++ b/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md @@ -34,15 +34,16 @@ To start, in the `rustc-perf` repo, build the collector, which runs the Rust com ``` cargo build --release -p collector ``` -After this the collector can be located in `.\target\release\collector`, can be run locally with `bench_local` and expects the following arguments: +The collector can then be run using cargo, specifying the collector binary. It expects the following arguments: - ``: Profiler selection for how performance should be measured. For this example we will use Cachegrind. - ``: The Rust compiler revision to benchmark, specified as a commit SHA from `rust-lang/rust`. -Optional arguments allow running profiles and scenarios as described above. `--include` in `x perf` is instead `--exact-match`. More information regarding the mandatory and +Optional arguments allow running profiles and scenarios as described above. More information regarding the mandatory and optional arguments can be found in the [rustc-perf-readme-profilers]. -Then, for the case of generating a profile diff for the crate `serve_derive-1.0.136`, for two commits `` and `` in the `rust-lang/rust` repository, run the following +Then, for the case of generating a profile diff for the crate `serve_derive-1.0.136`, for two commits `` and `` from the `rust-lang/rust` repository, +run the following in the `rustc-perf` repo: ``` -./target/release/collector profile_local cachegrind + --rustc2 + --exact-match serde_derive-1.0.136 --profiles Check --scenarios IncrUnchanged +cargo run --release --bin collector profile_local cachegrind + --rustc2 + --exact-match serde_derive-1.0.136 --profiles Check --scenarios IncrUnchanged ``` From 65639fe0dcca82defbcc3dac91a33c94ccddf303 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 4 Jan 2026 04:15:05 -0500 Subject: [PATCH 0240/1061] ci: Move the dependency installs and wall time benchmarks to scripts Make it easier to run the same steps outside of GitHub Actions. --- .../.github/workflows/main.yaml | 21 +++---------------- library/compiler-builtins/ci/bench-runtime.sh | 9 ++++++++ .../ci/install-bench-deps.sh | 11 ++++++++++ 3 files changed, 23 insertions(+), 18 deletions(-) create mode 100755 library/compiler-builtins/ci/bench-runtime.sh create mode 100755 library/compiler-builtins/ci/install-bench-deps.sh diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 38995cf0f0ff..699a9c417dde 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -203,7 +203,7 @@ jobs: # Unlike rustfmt, stable clippy does not work on code with nightly features. - name: Install nightly `clippy` run: | - rustup set profile minimal + rustup update nightly --no-self-update rustup default nightly rustup component add clippy - uses: Swatinem/rust-cache@v2 @@ -247,16 +247,7 @@ jobs: - uses: taiki-e/install-action@cargo-binstall - name: Set up dependencies - run: | - sudo apt-get update - sudo apt-get install -y valgrind gdb libc6-dbg # Needed for gungraun - rustup update "$BENCHMARK_RUSTC" --no-self-update - rustup default "$BENCHMARK_RUSTC" - # Install the version of gungraun-runner that is specified in Cargo.toml - gungraun_version="$(cargo metadata --format-version=1 --features icount | - jq -r '.packages[] | select(.name == "gungraun").version')" - cargo binstall -y gungraun-runner --version "$gungraun_version" - sudo apt-get install valgrind + run: ./ci/install-bench-deps.sh - uses: Swatinem/rust-cache@v2 with: key: ${{ matrix.target }} @@ -276,13 +267,7 @@ jobs: path: ${{ env.BASELINE_NAME }}.tar.xz - name: Run wall time benchmarks - run: | - # Always use the same seed for benchmarks. Ideally we should switch to a - # non-random generator. - export LIBM_SEED=benchesbenchesbenchesbencheswoo! - cargo bench --package libm-test \ - --no-default-features \ - --features short-benchmarks,build-musl,libm/force-soft-floats + run: ./ci/bench-runtime.sh - name: Print test logs if available if: always() diff --git a/library/compiler-builtins/ci/bench-runtime.sh b/library/compiler-builtins/ci/bench-runtime.sh new file mode 100755 index 000000000000..d272cf33463e --- /dev/null +++ b/library/compiler-builtins/ci/bench-runtime.sh @@ -0,0 +1,9 @@ +#!/bin/sh +# Run wall time benchmarks as we do on CI. + +# Always use the same seed for benchmarks. Ideally we should switch to a +# non-random generator. +export LIBM_SEED=benchesbenchesbenchesbencheswoo! +cargo bench --package libm-test \ + --no-default-features \ + --features short-benchmarks,build-musl,libm/force-soft-floats diff --git a/library/compiler-builtins/ci/install-bench-deps.sh b/library/compiler-builtins/ci/install-bench-deps.sh new file mode 100755 index 000000000000..61f4723c0358 --- /dev/null +++ b/library/compiler-builtins/ci/install-bench-deps.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# Install needed dependencies for gungraun. + +sudo apt-get update +sudo apt-get install -y valgrind gdb libc6-dbg # Needed for gungraun +rustup update "$BENCHMARK_RUSTC" --no-self-update +rustup default "$BENCHMARK_RUSTC" +# Install the version of gungraun-runner that is specified in Cargo.toml +gungraun_version="$(cargo metadata --format-version=1 --features icount | + jq -r '.packages[] | select(.name == "gungraun").version')" +cargo binstall -y gungraun-runner --version "$gungraun_version" From 0557c759a9b7ef0f9fd8dbfef2469439289a311f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Jan 2026 11:26:05 +0100 Subject: [PATCH 0241/1061] add check_only feature for faster check builds --- src/tools/miri/Cargo.lock | 17 +++++++++++------ src/tools/miri/Cargo.toml | 3 ++- src/tools/miri/ci/ci.sh | 17 +++++++++-------- src/tools/miri/etc/rust_analyzer_helix.toml | 1 - src/tools/miri/etc/rust_analyzer_vscode.json | 1 - src/tools/miri/etc/rust_analyzer_zed.json | 1 - src/tools/miri/genmc-sys/Cargo.toml | 3 +++ src/tools/miri/genmc-sys/build.rs | 5 +++++ src/tools/miri/miri-script/src/commands.rs | 6 ++++-- 9 files changed, 34 insertions(+), 20 deletions(-) diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock index 220fad2a1c76..b314aaafbdf0 100644 --- a/src/tools/miri/Cargo.lock +++ b/src/tools/miri/Cargo.lock @@ -123,22 +123,21 @@ dependencies = [ [[package]] name = "capstone" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "015ef5d5ca1743e3f94af9509ba6bd2886523cfee46e48d15c2ef5216fd4ac9a" +checksum = "f442ae0f2f3f1b923334b4a5386c95c69c1cfa072bafa23d6fae6d9682eb1dd4" dependencies = [ "capstone-sys", - "libc", + "static_assertions", ] [[package]] name = "capstone-sys" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2267cb8d16a1e4197863ec4284ffd1aec26fe7e57c58af46b02590a0235809a0" +checksum = "a4e8087cab6731295f5a2a2bd82989ba4f41d3a428aab2e7c98d8f4db38aac05" dependencies = [ "cc", - "libc", ] [[package]] @@ -1404,6 +1403,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" version = "0.11.1" diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml index 064706d7ed04..e7c90e45eba5 100644 --- a/src/tools/miri/Cargo.toml +++ b/src/tools/miri/Cargo.toml @@ -39,7 +39,7 @@ serde = { version = "1.0.219", features = ["derive"], optional = true } [target.'cfg(target_os = "linux")'.dependencies] nix = { version = "0.30.1", features = ["mman", "ptrace", "signal"], optional = true } ipc-channel = { version = "0.20.0", optional = true } -capstone = { version = "0.13", optional = true } +capstone = { version = "0.14", optional = true } [target.'cfg(all(target_os = "linux", target_pointer_width = "64", target_endian = "little"))'.dependencies] genmc-sys = { path = "./genmc-sys/", version = "0.1.0", optional = true } @@ -68,6 +68,7 @@ expensive-consistency-checks = ["stack-cache"] tracing = ["serde_json"] native-lib = ["dep:libffi", "dep:libloading", "dep:capstone", "dep:ipc-channel", "dep:nix", "dep:serde"] jemalloc = [] +check_only = ["libffi?/check_only", "capstone?/check_only", "genmc-sys?/check_only"] [lints.rust.unexpected_cfgs] level = "warn" diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 82007a8c1c1a..c8e359cf2385 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -30,14 +30,15 @@ export CARGO_INCREMENTAL=0 export CARGO_EXTRA_FLAGS="--locked" # Determine configuration for installed build (used by test-cargo-miri and `./miri bench`). +# We use the default set of features for this. echo "Installing release version of Miri" time ./miri install # Prepare debug build for direct `./miri` invocations. -# We enable all features to make sure the Stacked Borrows consistency check runs. +# Here we enable some more features and checks. echo "Building debug version of Miri" -export CARGO_EXTRA_FLAGS="$CARGO_EXTRA_FLAGS --all-features" -time ./miri build # the build that all the `./miri test` below will use +export FEATURES="--features=expensive-consistency-checks,genmc" +time ./miri build $FEATURES # the build that all the `./miri test` below will use endgroup @@ -63,7 +64,7 @@ function run_tests { if [ -n "${GC_STRESS-}" ]; then time MIRIFLAGS="${MIRIFLAGS-} -Zmiri-provenance-gc=1" ./miri test $TARGET_FLAG else - time ./miri test $TARGET_FLAG + time ./miri test $FEATURES $TARGET_FLAG fi ## advanced tests @@ -74,20 +75,20 @@ function run_tests { # them. Also error locations change so we don't run the failing tests. # We explicitly enable debug-assertions here, they are disabled by -O but we have tests # which exist to check that we panic on debug assertion failures. - time MIRIFLAGS="${MIRIFLAGS-} -O -Zmir-opt-level=4 -Cdebug-assertions=yes" MIRI_SKIP_UI_CHECKS=1 ./miri test $TARGET_FLAG tests/{pass,panic} + time MIRIFLAGS="${MIRIFLAGS-} -O -Zmir-opt-level=4 -Cdebug-assertions=yes" MIRI_SKIP_UI_CHECKS=1 ./miri test $FEATURES $TARGET_FLAG tests/{pass,panic} fi if [ -n "${MANY_SEEDS-}" ]; then # Run many-seeds tests. (Also tests `./miri run`.) time for FILE in tests/many-seeds/*.rs; do - ./miri run "-Zmiri-many-seeds=0..$MANY_SEEDS" $TARGET_FLAG "$FILE" + ./miri run $FEATURES "-Zmiri-many-seeds=0..$MANY_SEEDS" $TARGET_FLAG "$FILE" done + # Smoke-test `./miri run --dep`. + ./miri run $FEATURES $TARGET_FLAG --dep tests/pass-dep/getrandom.rs fi if [ -n "${TEST_BENCH-}" ]; then # Check that the benchmarks build and run, but only once. time HYPERFINE="hyperfine -w0 -r1 --show-output" ./miri bench $TARGET_FLAG --no-install fi - # Smoke-test `./miri run --dep`. - ./miri run $TARGET_FLAG --dep tests/pass-dep/getrandom.rs ## test-cargo-miri # On Windows, there is always "python", not "python3" or "python2". diff --git a/src/tools/miri/etc/rust_analyzer_helix.toml b/src/tools/miri/etc/rust_analyzer_helix.toml index dd222c50431a..1015b4baa6b0 100644 --- a/src/tools/miri/etc/rust_analyzer_helix.toml +++ b/src/tools/miri/etc/rust_analyzer_helix.toml @@ -27,7 +27,6 @@ invocationStrategy = "once" overrideCommand = [ "./miri", "check", - "--no-default-features", "-Zunstable-options", "--compile-time-deps", "--message-format=json", diff --git a/src/tools/miri/etc/rust_analyzer_vscode.json b/src/tools/miri/etc/rust_analyzer_vscode.json index 97ba212f8ef9..e82c648f59ab 100644 --- a/src/tools/miri/etc/rust_analyzer_vscode.json +++ b/src/tools/miri/etc/rust_analyzer_vscode.json @@ -21,7 +21,6 @@ "rust-analyzer.cargo.buildScripts.overrideCommand": [ "./miri", "check", - "--no-default-features", "-Zunstable-options", "--compile-time-deps", "--message-format=json", diff --git a/src/tools/miri/etc/rust_analyzer_zed.json b/src/tools/miri/etc/rust_analyzer_zed.json index 7f60a931c46f..e5ff400e989e 100644 --- a/src/tools/miri/etc/rust_analyzer_zed.json +++ b/src/tools/miri/etc/rust_analyzer_zed.json @@ -30,7 +30,6 @@ "overrideCommand": [ "./miri", "check", - "--no-default-features", "-Zunstable-options", "--compile-time-deps", "--message-format=json" diff --git a/src/tools/miri/genmc-sys/Cargo.toml b/src/tools/miri/genmc-sys/Cargo.toml index 6443ecd969df..37fcc58070a3 100644 --- a/src/tools/miri/genmc-sys/Cargo.toml +++ b/src/tools/miri/genmc-sys/Cargo.toml @@ -13,3 +13,6 @@ cc = "1.2.16" cmake = "0.1.54" git2 = { version = "0.20.2", default-features = false, features = ["https"] } cxx-build = { version = "1.0.173", features = ["parallel"] } + +[features] +check_only = [] diff --git a/src/tools/miri/genmc-sys/build.rs b/src/tools/miri/genmc-sys/build.rs index a22e3341d67a..4fc3ce94fb8b 100644 --- a/src/tools/miri/genmc-sys/build.rs +++ b/src/tools/miri/genmc-sys/build.rs @@ -202,6 +202,11 @@ fn compile_cpp_dependencies(genmc_path: &Path, always_configure: bool) { } fn main() { + // For check-only builds, we don't need to do anything. + if cfg!(feature = "check_only") { + return; + } + // Select which path to use for the GenMC repo: let (genmc_path, always_configure) = if let Some(genmc_src_path) = option_env!("GENMC_SRC_PATH") { diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs index 5a8bf76befd6..86f6253d4558 100644 --- a/src/tools/miri/miri-script/src/commands.rs +++ b/src/tools/miri/miri-script/src/commands.rs @@ -391,7 +391,8 @@ impl Command { Ok(()) } - fn check(features: Vec, flags: Vec) -> Result<()> { + fn check(mut features: Vec, flags: Vec) -> Result<()> { + features.push("check_only".into()); let e = MiriEnv::new()?; e.check(".", &features, &flags)?; e.check("cargo-miri", &[], &flags)?; @@ -405,7 +406,8 @@ impl Command { Ok(()) } - fn clippy(features: Vec, flags: Vec) -> Result<()> { + fn clippy(mut features: Vec, flags: Vec) -> Result<()> { + features.push("check_only".into()); let e = MiriEnv::new()?; e.clippy(".", &features, &flags)?; e.clippy("cargo-miri", &[], &flags)?; From d4b9ea2e865f8de6fe994f1e9a7c0fa80b83dcbf Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 4 Jan 2026 11:44:42 +0100 Subject: [PATCH 0242/1061] internal: Clean up proc-macro-srv callback trait --- .../crates/base-db/src/editioned_file_id.rs | 3 ++ .../rust-analyzer/crates/hir-expand/src/db.rs | 14 +++++++-- .../crates/hir-expand/src/lib.rs | 24 ++++----------- .../crates/load-cargo/src/lib.rs | 29 +++++++++---------- .../crates/proc-macro-srv-cli/Cargo.toml | 1 + .../proc-macro-srv-cli/src/main_loop.rs | 22 +++++++++----- .../crates/proc-macro-srv/src/lib.rs | 7 +++-- .../src/server_impl/rust_analyzer_span.rs | 19 ++---------- 8 files changed, 58 insertions(+), 61 deletions(-) diff --git a/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs b/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs index e2791ffe6f0a..13fb05d56547 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs @@ -26,6 +26,9 @@ const _: () = { krate: Crate, } + // FIXME: This poses an invalidation problem, if one constructs an `EditionedFileId` with a + // different crate then whatever the input of a memo used, it will invalidate the memo causing + // it to recompute even if the crate is not really used. /// We like to include the origin crate in an `EditionedFileId` (for use in the item tree), /// but this poses us a problem. /// diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs index 40d44cd1dba2..51767f87ffb9 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs @@ -9,8 +9,8 @@ use triomphe::Arc; use crate::{ AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallInfo, - EagerExpander, EditionedFileId, ExpandError, ExpandResult, ExpandTo, HirFileId, MacroCallId, - MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind, + EagerExpander, EditionedFileId, ExpandError, ExpandResult, ExpandTo, FileRange, HirFileId, + MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind, attrs::Meta, builtin::pseudo_derive_attr_expansion, cfg_process::attr_macro_input_to_token_tree, @@ -61,6 +61,9 @@ pub trait ExpandDatabase: RootQueryDb { #[salsa::lru(1024)] fn ast_id_map(&self, file_id: HirFileId) -> Arc; + #[salsa::transparent] + fn resolve_span(&self, span: Span) -> FileRange; + #[salsa::transparent] fn parse_or_expand(&self, file_id: HirFileId) -> SyntaxNode; @@ -158,6 +161,13 @@ fn syntax_context(db: &dyn ExpandDatabase, file: HirFileId, edition: Edition) -> } } +fn resolve_span(db: &dyn ExpandDatabase, Span { range, anchor, ctx: _ }: Span) -> FileRange { + let file_id = EditionedFileId::from_span_guess_origin(db, anchor.file_id); + let anchor_offset = + db.ast_id_map(file_id.into()).get_erased(anchor.ast_id).text_range().start(); + FileRange { file_id, range: range + anchor_offset } +} + /// This expands the given macro call, but with different arguments. This is /// used for completion, where we want to see what 'would happen' if we insert a /// token. The `token_to_map` mapped down into the expansion, with the mapped diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index 7b6a6135b350..05541e782efd 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -901,11 +901,8 @@ impl ExpansionInfo { let span = self.exp_map.span_at(token.start()); match &self.arg_map { SpanMap::RealSpanMap(_) => { - let file_id = - EditionedFileId::from_span_guess_origin(db, span.anchor.file_id).into(); - let anchor_offset = - db.ast_id_map(file_id).get_erased(span.anchor.ast_id).text_range().start(); - InFile { file_id, value: smallvec::smallvec![span.range + anchor_offset] } + let range = db.resolve_span(span); + InFile { file_id: range.file_id.into(), value: smallvec::smallvec![range.range] } } SpanMap::ExpansionSpanMap(arg_map) => { let Some(arg_node) = &self.arg.value else { @@ -947,7 +944,7 @@ pub fn map_node_range_up_rooted( range: TextRange, ) -> Option { let mut spans = exp_map.spans_for_range(range).filter(|span| span.ctx.is_root()); - let Span { range, anchor, ctx: _ } = spans.next()?; + let Span { range, anchor, ctx } = spans.next()?; let mut start = range.start(); let mut end = range.end(); @@ -958,10 +955,7 @@ pub fn map_node_range_up_rooted( start = start.min(span.range.start()); end = end.max(span.range.end()); } - let file_id = EditionedFileId::from_span_guess_origin(db, anchor.file_id); - let anchor_offset = - db.ast_id_map(file_id.into()).get_erased(anchor.ast_id).text_range().start(); - Some(FileRange { file_id, range: TextRange::new(start, end) + anchor_offset }) + Some(db.resolve_span(Span { range: TextRange::new(start, end), anchor, ctx })) } /// Maps up the text range out of the expansion hierarchy back into the original file its from. @@ -984,10 +978,7 @@ pub fn map_node_range_up( start = start.min(span.range.start()); end = end.max(span.range.end()); } - let file_id = EditionedFileId::from_span_guess_origin(db, anchor.file_id); - let anchor_offset = - db.ast_id_map(file_id.into()).get_erased(anchor.ast_id).text_range().start(); - Some((FileRange { file_id, range: TextRange::new(start, end) + anchor_offset }, ctx)) + Some((db.resolve_span(Span { range: TextRange::new(start, end), anchor, ctx }), ctx)) } /// Looks up the span at the given offset. @@ -997,10 +988,7 @@ pub fn span_for_offset( offset: TextSize, ) -> (FileRange, SyntaxContext) { let span = exp_map.span_at(offset); - let file_id = EditionedFileId::from_span_guess_origin(db, span.anchor.file_id); - let anchor_offset = - db.ast_id_map(file_id.into()).get_erased(span.anchor.ast_id).text_range().start(); - (FileRange { file_id, range: span.range + anchor_offset }, span.ctx) + (db.resolve_span(span), span.ctx) } /// In Rust, macros expand token trees to token trees. When we want to turn a diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index c302e266febd..e8d98b1ce661 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -19,7 +19,7 @@ use hir_expand::{ }, }; use ide_db::{ - ChangeWithProcMacros, EditionedFileId, FxHashMap, RootDatabase, + ChangeWithProcMacros, FxHashMap, RootDatabase, base_db::{CrateGraphBuilder, Env, ProcMacroLoadingError, SourceRoot, SourceRootId}, prime_caches, }; @@ -32,7 +32,8 @@ use proc_macro_api::{ }, }; use project_model::{CargoConfig, PackageRoot, ProjectManifest, ProjectWorkspace}; -use span::Span; +use span::{Span, SpanAnchor, SyntaxContext}; +use tt::{TextRange, TextSize}; use vfs::{ AbsPath, AbsPathBuf, FileId, VfsPath, file_set::FileSetConfig, @@ -553,20 +554,18 @@ impl ProcMacroExpander for Expander { Ok(SubResponse::LocalFilePathResult { name }) } SubRequest::SourceText { file_id, ast_id, start, end } => { - let raw_file_id = FileId::from_raw(file_id); - let editioned_file_id = span::EditionedFileId::from_raw(file_id); let ast_id = span::ErasedFileAstId::from_raw(ast_id); - let hir_file_id = EditionedFileId::from_span_guess_origin(db, editioned_file_id); - let anchor_offset = db - .ast_id_map(hir_expand::HirFileId::FileId(hir_file_id)) - .get_erased(ast_id) - .text_range() - .start(); - let anchor_offset = u32::from(anchor_offset); - let abs_start = start + anchor_offset; - let abs_end = end + anchor_offset; - let source = db.file_text(raw_file_id).text(db); - let text = source.get(abs_start as usize..abs_end as usize).map(ToOwned::to_owned); + let editioned_file_id = span::EditionedFileId::from_raw(file_id); + let span = Span { + range: TextRange::new(TextSize::from(start), TextSize::from(end)), + anchor: SpanAnchor { file_id: editioned_file_id, ast_id }, + ctx: SyntaxContext::root(editioned_file_id.edition()), + }; + let range = db.resolve_span(span); + let source = db.file_text(range.file_id.file_id(db)).text(db); + let text = source + .get(usize::from(range.range.start())..usize::from(range.range.end())) + .map(ToOwned::to_owned); Ok(SubResponse::SourceTextResult { text }) } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml index 2c6e5a16ee06..6b2db0b269d5 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml @@ -18,6 +18,7 @@ clap = {version = "4.5.42", default-features = false, features = ["std"]} [features] default = [] +# default = ["sysroot-abi"] sysroot-abi = ["proc-macro-srv/sysroot-abi", "proc-macro-api/sysroot-abi"] in-rust-tree = ["proc-macro-srv/in-rust-tree", "sysroot-abi"] diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs index 4891e073142d..b2f4b96bd255 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs @@ -185,8 +185,8 @@ impl<'a, C: Codec> ProcMacroClientHandle<'a, C> { } impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandle<'_, C> { - fn file(&mut self, file_id: u32) -> String { - match self.roundtrip(bidirectional::SubRequest::FilePath { file_id }) { + fn file(&mut self, file_id: proc_macro_srv::span::FileId) -> String { + match self.roundtrip(bidirectional::SubRequest::FilePath { file_id: file_id.index() }) { Some(bidirectional::BidirectionalMessage::SubResponse( bidirectional::SubResponse::FilePathResult { name }, )) => name, @@ -194,9 +194,16 @@ impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandl } } - fn source_text(&mut self, file_id: u32, ast_id: u32, start: u32, end: u32) -> Option { - match self.roundtrip(bidirectional::SubRequest::SourceText { file_id, ast_id, start, end }) - { + fn source_text( + &mut self, + proc_macro_srv::span::Span { range, anchor, ctx: _ }: proc_macro_srv::span::Span, + ) -> Option { + match self.roundtrip(bidirectional::SubRequest::SourceText { + file_id: anchor.file_id.as_u32(), + ast_id: anchor.ast_id.into_raw(), + start: range.start().into(), + end: range.end().into(), + }) { Some(bidirectional::BidirectionalMessage::SubResponse( bidirectional::SubResponse::SourceTextResult { text }, )) => text, @@ -204,8 +211,9 @@ impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandl } } - fn local_file(&mut self, file_id: u32) -> Option { - match self.roundtrip(bidirectional::SubRequest::LocalFilePath { file_id }) { + fn local_file(&mut self, file_id: proc_macro_srv::span::FileId) -> Option { + match self.roundtrip(bidirectional::SubRequest::LocalFilePath { file_id: file_id.index() }) + { Some(bidirectional::BidirectionalMessage::SubResponse( bidirectional::SubResponse::LocalFilePathResult { name }, )) => name, diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs index d63aea947c1d..f2d1dfbba4cc 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs @@ -53,6 +53,7 @@ use temp_dir::TempDir; pub use crate::server_impl::token_id::SpanId; pub use proc_macro::Delimiter; +pub use span; pub use crate::bridge::*; pub use crate::server_impl::literal_from_str; @@ -94,9 +95,9 @@ impl<'env> ProcMacroSrv<'env> { pub type ProcMacroClientHandle<'a> = &'a mut (dyn ProcMacroClientInterface + Sync + Send); pub trait ProcMacroClientInterface { - fn file(&mut self, file_id: u32) -> String; - fn source_text(&mut self, file_id: u32, ast_id: u32, start: u32, end: u32) -> Option; - fn local_file(&mut self, file_id: u32) -> Option; + fn file(&mut self, file_id: span::FileId) -> String; + fn source_text(&mut self, span: Span) -> Option; + fn local_file(&mut self, file_id: span::FileId) -> Option; } const EXPANDER_STACK_SIZE: usize = 8 * 1024 * 1024; diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index 2ce3b717cb0d..32725afc5527 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -128,13 +128,10 @@ impl server::Span for RaSpanServer<'_> { format!("{:?}", span) } fn file(&mut self, span: Self::Span) -> String { - self.callback - .as_mut() - .map(|cb| cb.file(span.anchor.file_id.file_id().index())) - .unwrap_or_default() + self.callback.as_mut().map(|cb| cb.file(span.anchor.file_id.file_id())).unwrap_or_default() } fn local_file(&mut self, span: Self::Span) -> Option { - self.callback.as_mut().and_then(|cb| cb.local_file(span.anchor.file_id.file_id().index())) + self.callback.as_mut().and_then(|cb| cb.local_file(span.anchor.file_id.file_id())) } fn save_span(&mut self, _span: Self::Span) -> usize { // FIXME, quote is incompatible with third-party tools @@ -153,17 +150,7 @@ impl server::Span for RaSpanServer<'_> { /// See PR: /// https://github.com/rust-lang/rust/pull/55780 fn source_text(&mut self, span: Self::Span) -> Option { - let file_id = span.anchor.file_id; - let ast_id = span.anchor.ast_id; - let start: u32 = span.range.start().into(); - let end: u32 = span.range.end().into(); - - self.callback.as_mut()?.source_text( - file_id.file_id().index(), - ast_id.into_raw(), - start, - end, - ) + self.callback.as_mut()?.source_text(span) } fn parent(&mut self, _span: Self::Span) -> Option { From 50b78f1bb4c8bd3a0c2d5cb5b4323be16121354d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 4 Jan 2026 12:08:50 +0100 Subject: [PATCH 0243/1061] Add a README.md to proc-macro-srv-cli --- .../crates/proc-macro-srv-cli/README.md | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv-cli/README.md diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/README.md b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/README.md new file mode 100644 index 000000000000..02a67ac3ecc1 --- /dev/null +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/README.md @@ -0,0 +1,65 @@ +# proc-macro-srv-cli + +A standalone binary for the `proc-macro-srv` crate that provides procedural macro expansion for rust-analyzer. + +## Overview + +rust-analyzer uses a RPC (via stdio) client-server architecture for procedural macro expansion. This is necessary because: + +1. Proc macros are dynamic libraries that can segfault, bringing down the entire process, so running them out of process allows rust-analyzer to recover from fatal errors. +2. Proc macro dylibs are compiled against a specific rustc version and require matching internal APIs to load and execute, as such having this binary shipped as a rustup component allows us to always match the rustc version irrespective of the rust-analyzer version used. + +## The `sysroot-abi` Feature + +**The `sysroot-abi` feature is required for the binary to actually function.** Without it, the binary will return an error: + +``` +proc-macro-srv-cli needs to be compiled with the `sysroot-abi` feature to function +``` + +This feature is necessary because the proc-macro server needs access to unstable rustc internals (`proc_macro_internals`, `proc_macro_diagnostic`, `proc_macro_span`) which are only available on nightly or with `RUSTC_BOOTSTRAP=1`. +rust-analyzer is a stable toolchain project though, so the feature flag is used to have it remain compilable on stable by default. + +### Building + +```bash +# Using nightly toolchain +cargo build -p proc-macro-srv-cli --features sysroot-abi + +# Or with RUSTC_BOOTSTRAP on stable +RUSTC_BOOTSTRAP=1 cargo build -p proc-macro-srv-cli --features sysroot-abi +``` + +### Installing the proc-macro server + +For local testing purposes, you can install the proc-macro server using the xtask command: + +```bash +# Recommended: use the xtask command +cargo xtask install --proc-macro-server +``` + +## Testing + +```bash +cargo test --features sysroot-abi -p proc-macro-srv -p proc-macro-srv-cli -p proc-macro-api +``` + +The tests use a test proc macro dylib built by the `proc-macro-test` crate, which compiles a small proc macro implementation during build time. + +**Note**: Tests only compile on nightly toolchains (or with `RUSTC_BOOTSTRAP=1`). + +## Usage + +The binary requires the `RUST_ANALYZER_INTERNALS_DO_NOT_USE` environment variable to be set. This is intentional—the binary is an implementation detail of rust-analyzer and its API is still unstable: + +```bash +RUST_ANALYZER_INTERNALS_DO_NOT_USE=1 rust-analyzer-proc-macro-srv --version +``` + +## Related Crates + +- `proc-macro-srv`: The core server library that handles loading dylibs and expanding macros, but not the RPC protocol. +- `proc-macro-api`: The client library used by rust-analyzer to communicate with this server as well as the protocol definitions. +- `proc-macro-test`: Test harness with sample proc macros for testing +- `proc-macro-srv-cli`: The actual server binary that handles the RPC protocol. From ff2acf0eca6e45fa5828f4d0e5e5891b4c789517 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Jan 2026 12:44:38 +0100 Subject: [PATCH 0244/1061] update lockfile --- Cargo.lock | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d3637d1f4b3e..816bb1a37859 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -445,22 +445,21 @@ dependencies = [ [[package]] name = "capstone" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "015ef5d5ca1743e3f94af9509ba6bd2886523cfee46e48d15c2ef5216fd4ac9a" +checksum = "f442ae0f2f3f1b923334b4a5386c95c69c1cfa072bafa23d6fae6d9682eb1dd4" dependencies = [ "capstone-sys", - "libc", + "static_assertions", ] [[package]] name = "capstone-sys" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2267cb8d16a1e4197863ec4284ffd1aec26fe7e57c58af46b02590a0235809a0" +checksum = "a4e8087cab6731295f5a2a2bd82989ba4f41d3a428aab2e7c98d8f4db38aac05" dependencies = [ "cc", - "libc", ] [[package]] @@ -2232,9 +2231,9 @@ dependencies = [ [[package]] name = "libffi" -version = "5.0.0" +version = "5.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0444124f3ffd67e1b0b0c661a7f81a278a135eb54aaad4078e79fbc8be50c8a5" +checksum = "0498fe5655f857803e156523e644dcdcdc3b3c7edda42ea2afdae2e09b2db87b" dependencies = [ "libc", "libffi-sys", @@ -2242,9 +2241,9 @@ dependencies = [ [[package]] name = "libffi-sys" -version = "4.0.0" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d722da8817ea580d0669da6babe2262d7b86a1af1103da24102b8bb9c101ce7" +checksum = "71d4f1d4ce15091955144350b75db16a96d4a63728500122706fb4d29a26afbb" dependencies = [ "cc", ] From d7fa6e527fef7337dc25b1e824664dd5847ba4a2 Mon Sep 17 00:00:00 2001 From: sgasho Date: Sun, 4 Jan 2026 22:56:17 +0900 Subject: [PATCH 0245/1061] enrich error info when tries to dlopen Enzyme --- compiler/rustc_codegen_llvm/messages.ftl | 3 ++- compiler/rustc_codegen_llvm/src/errors.rs | 5 ++++- compiler/rustc_codegen_llvm/src/lib.rs | 6 ++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl index a637ae8184b4..018d240b2ae5 100644 --- a/compiler/rustc_codegen_llvm/messages.ftl +++ b/compiler/rustc_codegen_llvm/messages.ftl @@ -1,4 +1,5 @@ -codegen_llvm_autodiff_component_unavailable = failed to load our autodiff backend. Did you install it via rustup? +codegen_llvm_autodiff_component_unavailable = failed to load our autodiff backend. + .note = load error: {$err} codegen_llvm_autodiff_without_enable = using the autodiff feature requires -Z autodiff=Enable codegen_llvm_autodiff_without_lto = using the autodiff feature requires setting `lto="fat"` in your Cargo.toml diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index c73140e041b6..439664b8b9a2 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -34,7 +34,10 @@ impl Diagnostic<'_, G> for ParseTargetMachineConfig<'_> { #[derive(Diagnostic)] #[diag(codegen_llvm_autodiff_component_unavailable)] -pub(crate) struct AutoDiffComponentUnavailable; +#[note] +pub(crate) struct AutoDiffComponentUnavailable { + pub err: String, +} #[derive(Diagnostic)] #[diag(codegen_llvm_autodiff_without_lto)] diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 095274744993..801d23342973 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -249,8 +249,10 @@ impl CodegenBackend for LlvmCodegenBackend { use crate::back::lto::enable_autodiff_settings; if sess.opts.unstable_opts.autodiff.contains(&AutoDiff::Enable) { - if let Err(_) = llvm::EnzymeWrapper::get_or_init(&sess.opts.sysroot) { - sess.dcx().emit_fatal(crate::errors::AutoDiffComponentUnavailable); + if let Err(err) = llvm::EnzymeWrapper::get_or_init(&sess.opts.sysroot) { + sess.dcx().emit_fatal(crate::errors::AutoDiffComponentUnavailable { + err: format!("{err:?}"), + }); } enable_autodiff_settings(&sess.opts.unstable_opts.autodiff); } From fa584faca5387010e37bc8172529be3b3776e0cc Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Sun, 4 Jan 2026 06:56:48 -0800 Subject: [PATCH 0246/1061] Update test and verify that tgt_(un)register_lib have the right type --- compiler/rustc_codegen_llvm/src/base.rs | 9 +++- .../src/builder/gpu_offload.rs | 5 ++- compiler/rustc_session/src/config.rs | 2 + compiler/rustc_session/src/options.rs | 10 ++++- tests/codegen-llvm/gpu_offload/gpu_host.rs | 42 +++++++++---------- 5 files changed, 40 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index 388118f9b4f1..d00e70638b45 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -93,8 +93,13 @@ pub(crate) fn compile_codegen_unit( // They are necessary for correct offload execution. We do this here to simplify the // `offload` intrinsic, avoiding the need for tracking whether it's the first // intrinsic call or not. - let has_host_offload = - cx.sess().opts.unstable_opts.offload.iter().any(|o| matches!(o, Offload::Host(_))); + let has_host_offload = cx + .sess() + .opts + .unstable_opts + .offload + .iter() + .any(|o| matches!(o, Offload::Host(_) | Offload::Test)); if has_host_offload && !cx.sess().target.is_like_gpu { cx.offload_globals.replace(Some(OffloadGlobals::declare(&cx))); } diff --git a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs index fba92f996aa6..b8eb4f038216 100644 --- a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs +++ b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs @@ -49,8 +49,9 @@ impl<'ll> OffloadGlobals<'ll> { let bin_desc = cx.type_named_struct("struct.__tgt_bin_desc"); cx.set_struct_body(bin_desc, &tgt_bin_desc_ty, false); - let register_lib = declare_offload_fn(&cx, "__tgt_register_lib", mapper_fn_ty); - let unregister_lib = declare_offload_fn(&cx, "__tgt_unregister_lib", mapper_fn_ty); + let reg_lib_decl = cx.type_func(&[cx.type_ptr()], cx.type_void()); + let register_lib = declare_offload_fn(&cx, "__tgt_register_lib", reg_lib_decl); + let unregister_lib = declare_offload_fn(&cx, "__tgt_unregister_lib", reg_lib_decl); let init_ty = cx.type_func(&[], cx.type_void()); let init_rtls = declare_offload_fn(cx, "__tgt_init_all_rtls", init_ty); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index fe96dabf6330..8c492fcf8f15 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -196,6 +196,8 @@ pub enum Offload { Device, /// Second step in the offload pipeline, generates the host code to call kernels. Host(String), + /// Test is similar to Host, but allows testing without a device artifact. + Test, } /// The different settings that the `-Z autodiff` flag can have. diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index f11ad12fb9dd..21fa3321a30a 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -794,7 +794,8 @@ mod desc { pub(crate) const parse_list_with_polarity: &str = "a comma-separated list of strings, with elements beginning with + or -"; pub(crate) const parse_autodiff: &str = "a comma separated list of settings: `Enable`, `PrintSteps`, `PrintTA`, `PrintTAFn`, `PrintAA`, `PrintPerf`, `PrintModBefore`, `PrintModAfter`, `PrintModFinal`, `PrintPasses`, `NoPostopt`, `LooseTypes`, `Inline`, `NoTT`"; - pub(crate) const parse_offload: &str = "a comma separated list of settings: `Enable`"; + pub(crate) const parse_offload: &str = + "a comma separated list of settings: `Host=`, `Device`, `Test`"; pub(crate) const parse_comma_list: &str = "a comma-separated list of strings"; pub(crate) const parse_opt_comma_list: &str = parse_comma_list; pub(crate) const parse_number: &str = "a number"; @@ -1471,6 +1472,13 @@ pub mod parse { } Offload::Device } + "Test" => { + if let Some(_) = arg { + // Test does not accept a value + return false; + } + Offload::Test + } _ => { // FIXME(ZuseZ4): print an error saying which value is not recognized return false; diff --git a/tests/codegen-llvm/gpu_offload/gpu_host.rs b/tests/codegen-llvm/gpu_offload/gpu_host.rs index b4d17143720a..dcbd65b14427 100644 --- a/tests/codegen-llvm/gpu_offload/gpu_host.rs +++ b/tests/codegen-llvm/gpu_offload/gpu_host.rs @@ -1,15 +1,10 @@ -//@ compile-flags: -Zoffload=Enable -Zunstable-options -C opt-level=3 -Clto=fat +//@ compile-flags: -Zoffload=Test -Zunstable-options -C opt-level=3 -Clto=fat //@ no-prefer-dynamic -//@ needs-enzyme +//@ needs-offload // This test is verifying that we generate __tgt_target_data_*_mapper before and after a call to the // kernel_1. Better documentation to what each global or variable means is available in the gpu -// offlaod code, or the LLVM offload documentation. This code does not launch any GPU kernels yet, -// and will be rewritten once a proper offload frontend has landed. -// -// We currently only handle memory transfer for specific calls to functions named `kernel_{num}`, -// when inside of a function called main. This, too, is a temporary workaround for not having a -// frontend. +// offload code, or the LLVM offload documentation. #![feature(rustc_attrs)] #![feature(core_intrinsics)] @@ -22,6 +17,20 @@ fn main() { core::hint::black_box(&x); } +#[unsafe(no_mangle)] +#[inline(never)] +pub fn kernel_1(x: &mut [f32; 256]) { + core::intrinsics::offload(_kernel_1, [256, 1, 1], [32, 1, 1], (x,)) +} + +#[unsafe(no_mangle)] +#[inline(never)] +pub fn _kernel_1(x: &mut [f32; 256]) { + for i in 0..256 { + x[i] = 21.0; + } +} + // CHECK: %struct.ident_t = type { i32, i32, i32, i32, ptr } // CHECK: %struct.__tgt_offload_entry = type { i64, i16, i16, i32, ptr, ptr, i64, i64, ptr } // CHECK: %struct.__tgt_bin_desc = type { i32, ptr, ptr, ptr } @@ -36,8 +45,9 @@ fn main() { // CHECK: @.offloading.entry_name._kernel_1 = internal unnamed_addr constant [10 x i8] c"_kernel_1\00", section ".llvm.rodata.offloading", align 1 // CHECK: @.offloading.entry._kernel_1 = internal constant %struct.__tgt_offload_entry { i64 0, i16 1, i16 1, i32 0, ptr @._kernel_1.region_id, ptr @.offloading.entry_name._kernel_1, i64 0, i64 0, ptr null }, section "llvm_offload_entries", align 8 -// CHECK: Function Attrs: nounwind // CHECK: declare i32 @__tgt_target_kernel(ptr, i64, i32, i32, ptr, ptr) +// CHECK: declare void @__tgt_register_lib(ptr) local_unnamed_addr +// CHECK: declare void @__tgt_unregister_lib(ptr) local_unnamed_addr // CHECK: define{{( dso_local)?}} void @main() // CHECK-NEXT: start: @@ -94,17 +104,3 @@ fn main() { // CHECK-NEXT: call void @__tgt_unregister_lib(ptr nonnull %EmptyDesc) // CHECK-NEXT: ret void // CHECK-NEXT: } - -#[unsafe(no_mangle)] -#[inline(never)] -pub fn kernel_1(x: &mut [f32; 256]) { - core::intrinsics::offload(_kernel_1, [256, 1, 1], [32, 1, 1], (x,)) -} - -#[unsafe(no_mangle)] -#[inline(never)] -pub fn _kernel_1(x: &mut [f32; 256]) { - for i in 0..256 { - x[i] = 21.0; - } -} From a767bf74624b000064b08993148a78f1e06090a4 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Thu, 1 Jan 2026 02:16:49 +0000 Subject: [PATCH 0247/1061] init impl --- clippy_lints/src/utils/author.rs | 1 + clippy_utils/src/consts.rs | 2 +- clippy_utils/src/hir_utils.rs | 16 +++++++++++++++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 90fa976fda38..f515f9987a80 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -320,6 +320,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { self.body(field!(anon_const.body)); }, ConstArgKind::Struct(..) => chain!(self, "let ConstArgKind::Struct(..) = {const_arg}.kind"), + ConstArgKind::TupleCall(..) => chain!(self, "let ConstArgKind::TupleCall(..) = {const_arg}.kind"), ConstArgKind::Infer(..) => chain!(self, "let ConstArgKind::Infer(..) = {const_arg}.kind"), ConstArgKind::Error(..) => chain!(self, "let ConstArgKind::Error(..) = {const_arg}.kind"), } diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 78e3d6d192a0..a44cd31dc123 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -1140,7 +1140,7 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx ConstItemRhs::Body(body_id) => Some(tcx.hir_body(body_id).value), ConstItemRhs::TypeConst(const_arg) => match const_arg.kind { ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value), - ConstArgKind::Struct(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => { + ConstArgKind::Struct(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => { None }, }, diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 03853b5b4af5..f1ee534c500d 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -671,11 +671,19 @@ impl HirEqInterExpr<'_, '_, '_> { .iter() .zip(*inits_b) .all(|(init_a, init_b)| self.eq_const_arg(init_a.expr, init_b.expr)) - }, + } + (ConstArgKind::TupleCall(path_a, args_a), ConstArgKind::TupleCall(path_b, args_b)) => { + self.eq_qpath(path_a, path_b) + && args_a + .iter() + .zip(*args_b) + .all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b)) + } // Use explicit match for now since ConstArg is undergoing flux. ( ConstArgKind::Path(..) | ConstArgKind::Anon(..) + | ConstArgKind::TupleCall(..) | ConstArgKind::Infer(..) | ConstArgKind::Struct(..) | ConstArgKind::Error(..), @@ -1546,6 +1554,12 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_const_arg(init.expr); } }, + ConstArgKind::TupleCall(path, args) => { + self.hash_qpath(path); + for arg in *args { + self.hash_const_arg(arg); + } + }, ConstArgKind::Infer(..) | ConstArgKind::Error(..) => {}, } } From 05afcb6d26567d481119c8f6f4a58ccce225f224 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Thu, 1 Jan 2026 02:16:49 +0000 Subject: [PATCH 0248/1061] init impl --- compiler/rustc_ast_lowering/src/lib.rs | 34 ++++- compiler/rustc_hir/src/hir.rs | 3 + compiler/rustc_hir/src/intravisit.rs | 7 + .../src/hir_ty_lowering/mod.rs | 135 +++++++++++++++++- compiler/rustc_hir_pretty/src/lib.rs | 1 + compiler/rustc_metadata/src/rmeta/encoder.rs | 1 + compiler/rustc_resolve/src/def_collector.rs | 2 +- src/librustdoc/clean/mod.rs | 7 +- .../clippy/clippy_lints/src/utils/author.rs | 1 + src/tools/clippy/clippy_utils/src/consts.rs | 2 +- .../clippy/clippy_utils/src/hir_utils.rs | 16 ++- tests/crashes/136379.rs | 11 -- tests/crashes/138132.rs | 10 -- .../mgca/tuple_ctor_arg_simple.rs | 52 +++++++ .../mgca/tuple_ctor_complex_args.rs | 19 +++ .../mgca/tuple_ctor_complex_args.stderr | 14 ++ .../mgca/tuple_ctor_erroneous.rs | 46 ++++++ .../mgca/tuple_ctor_erroneous.stderr | 68 +++++++++ .../mgca/tuple_ctor_in_array_len.rs | 16 +++ .../mgca/tuple_ctor_in_array_len.stderr | 23 +++ .../const-generics/mgca/tuple_ctor_nested.rs | 38 +++++ .../mgca/tuple_ctor_type_relative.rs | 26 ++++ .../mgca/type_as_const_in_array_len.rs | 14 ++ .../mgca/type_as_const_in_array_len.stderr | 19 +++ 24 files changed, 537 insertions(+), 28 deletions(-) delete mode 100644 tests/crashes/136379.rs delete mode 100644 tests/crashes/138132.rs create mode 100644 tests/ui/const-generics/mgca/tuple_ctor_arg_simple.rs create mode 100644 tests/ui/const-generics/mgca/tuple_ctor_complex_args.rs create mode 100644 tests/ui/const-generics/mgca/tuple_ctor_complex_args.stderr create mode 100644 tests/ui/const-generics/mgca/tuple_ctor_erroneous.rs create mode 100644 tests/ui/const-generics/mgca/tuple_ctor_erroneous.stderr create mode 100644 tests/ui/const-generics/mgca/tuple_ctor_in_array_len.rs create mode 100644 tests/ui/const-generics/mgca/tuple_ctor_in_array_len.stderr create mode 100644 tests/ui/const-generics/mgca/tuple_ctor_nested.rs create mode 100644 tests/ui/const-generics/mgca/tuple_ctor_type_relative.rs create mode 100644 tests/ui/const-generics/mgca/type_as_const_in_array_len.rs create mode 100644 tests/ui/const-generics/mgca/type_as_const_in_array_len.stderr diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 416fef8e3af3..9a459156aba1 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2396,6 +2396,35 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; match &expr.kind { + ExprKind::Call(func, args) if let ExprKind::Path(qself, path) = &func.kind => { + let qpath = self.lower_qpath( + func.id, + qself, + path, + ParamMode::Explicit, + AllowReturnTypeNotation::No, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + ); + + let lowered_args = self.arena.alloc_from_iter(args.iter().map(|arg| { + let const_arg = if let ExprKind::ConstBlock(anon_const) = &arg.kind { + let def_id = self.local_def_id(anon_const.id); + let def_kind = self.tcx.def_kind(def_id); + assert_eq!(DefKind::AnonConst, def_kind); + self.lower_anon_const_to_const_arg_direct(anon_const) + } else { + self.lower_expr_to_const_arg_direct(arg) + }; + + &*self.arena.alloc(const_arg) + })); + + ConstArg { + hir_id: self.next_id(), + kind: hir::ConstArgKind::TupleCall(qpath, lowered_args), + } + } ExprKind::Path(qself, path) => { let qpath = self.lower_qpath( expr.id, @@ -2460,7 +2489,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { && let StmtKind::Expr(expr) = &stmt.kind && matches!( expr.kind, - ExprKind::Block(..) | ExprKind::Path(..) | ExprKind::Struct(..) + ExprKind::Block(..) + | ExprKind::Path(..) + | ExprKind::Struct(..) + | ExprKind::Call(..) ) { return self.lower_expr_to_const_arg_direct(expr); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index da3e79efd6df..252d32fa3365 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -499,6 +499,7 @@ impl<'hir, Unambig> ConstArg<'hir, Unambig> { match self.kind { ConstArgKind::Struct(path, _) => path.span(), ConstArgKind::Path(path) => path.span(), + ConstArgKind::TupleCall(path, _) => path.span(), ConstArgKind::Anon(anon) => anon.span, ConstArgKind::Error(span, _) => span, ConstArgKind::Infer(span, _) => span, @@ -519,6 +520,8 @@ pub enum ConstArgKind<'hir, Unambig = ()> { Anon(&'hir AnonConst), /// Represents construction of struct/struct variants Struct(QPath<'hir>, &'hir [&'hir ConstArgExprField<'hir>]), + /// Tuple constructor variant + TupleCall(QPath<'hir>, &'hir [&'hir ConstArg<'hir>]), /// Error const Error(Span, ErrorGuaranteed), /// This variant is not always used to represent inference consts, sometimes diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index e636b3fff654..853e7db0757a 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1090,6 +1090,13 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>( V::Result::output() } + ConstArgKind::TupleCall(qpath, args) => { + try_visit!(visitor.visit_qpath(qpath, *hir_id, qpath.span())); + for arg in *args { + try_visit!(visitor.visit_const_arg_unambig(*arg)); + } + V::Result::output() + } ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, qpath.span()), ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon), ConstArgKind::Error(_, _) => V::Result::output(), // errors and spans are not important diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 23110d2c5c87..680c44e80480 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -314,6 +314,7 @@ pub enum PermitVariants { enum TypeRelativePath<'tcx> { AssocItem(DefId, GenericArgsRef<'tcx>), Variant { adt: Ty<'tcx>, variant_did: DefId }, + Ctor { ctor_def_id: DefId, args: GenericArgsRef<'tcx> }, } /// New-typed boolean indicating whether explicit late-bound lifetimes @@ -1261,6 +1262,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { TypeRelativePath::Variant { adt, variant_did } => { Ok((adt, DefKind::Variant, variant_did)) } + TypeRelativePath::Ctor { .. } => { + let e = tcx.dcx().span_err(span, "expected type, found tuple constructor"); + Err(e) + } } } @@ -1294,6 +1299,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } (def_id, args) } + TypeRelativePath::Ctor { ctor_def_id, args } => { + return Ok(ty::Const::zero_sized(tcx, Ty::new_fn_def(tcx, ctor_def_id, args))); + } // FIXME(mgca): implement support for this once ready to support all adt ctor expressions, // not just const ctors TypeRelativePath::Variant { .. } => { @@ -1326,6 +1334,23 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .iter() .find(|vd| tcx.hygienic_eq(segment.ident, vd.ident(tcx), adt_def.did())); if let Some(variant_def) = variant_def { + // FIXME(mgca): do we want constructor resolutions to take priority over + // other possible resolutions? + if matches!(mode, LowerTypeRelativePathMode::Const) + && let Some((CtorKind::Fn, ctor_def_id)) = variant_def.ctor + { + tcx.check_stability(variant_def.def_id, Some(qpath_hir_id), span, None); + let _ = self.prohibit_generic_args( + slice::from_ref(segment).iter(), + GenericsArgsErrExtend::EnumVariant { + qself: hir_self_ty, + assoc_segment: segment, + adt_def, + }, + ); + let ty::Adt(_, enum_args) = self_ty.kind() else { unreachable!() }; + return Ok(TypeRelativePath::Ctor { ctor_def_id, args: enum_args }); + } if let PermitVariants::Yes = mode.permit_variants() { tcx.check_stability(variant_def.def_id, Some(qpath_hir_id), span, None); let _ = self.prohibit_generic_args( @@ -2266,12 +2291,106 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::ConstArgKind::Struct(qpath, inits) => { self.lower_const_arg_struct(hir_id, qpath, inits, const_arg.span()) } + hir::ConstArgKind::TupleCall(qpath, args) => { + self.lower_const_arg_tuple_call(hir_id, qpath, args, const_arg.span()) + } hir::ConstArgKind::Anon(anon) => self.lower_const_arg_anon(anon), hir::ConstArgKind::Infer(span, ()) => self.ct_infer(None, span), hir::ConstArgKind::Error(_, e) => ty::Const::new_error(tcx, e), } } + fn lower_const_arg_tuple_call( + &self, + hir_id: HirId, + qpath: hir::QPath<'tcx>, + args: &'tcx [&'tcx hir::ConstArg<'tcx>], + span: Span, + ) -> Const<'tcx> { + let tcx = self.tcx(); + + let non_adt_or_variant_res = || { + let e = tcx.dcx().span_err(span, "tuple constructor with invalid base path"); + ty::Const::new_error(tcx, e) + }; + + let ctor_const = match qpath { + hir::QPath::Resolved(maybe_qself, path) => { + let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); + self.lower_resolved_const_path(opt_self_ty, path, hir_id) + } + hir::QPath::TypeRelative(hir_self_ty, segment) => { + let self_ty = self.lower_ty(hir_self_ty); + match self.lower_type_relative_const_path( + self_ty, + hir_self_ty, + segment, + hir_id, + span, + ) { + Ok(c) => c, + Err(_) => return non_adt_or_variant_res(), + } + } + }; + + let Some(value) = ctor_const.try_to_value() else { + return non_adt_or_variant_res(); + }; + + let (adt_def, adt_args, variant_did) = match value.ty.kind() { + ty::FnDef(def_id, fn_args) + if let DefKind::Ctor(CtorOf::Variant, _) = tcx.def_kind(*def_id) => + { + let parent_did = tcx.parent(*def_id); + let enum_did = tcx.parent(parent_did); + (tcx.adt_def(enum_did), fn_args, parent_did) + } + ty::FnDef(def_id, fn_args) + if let DefKind::Ctor(CtorOf::Struct, _) = tcx.def_kind(*def_id) => + { + let parent_did = tcx.parent(*def_id); + (tcx.adt_def(parent_did), fn_args, parent_did) + } + _ => return non_adt_or_variant_res(), + }; + + let variant_def = adt_def.variant_with_id(variant_did); + let variant_idx = adt_def.variant_index_with_id(variant_did).as_u32(); + + if args.len() != variant_def.fields.len() { + let e = tcx.dcx().span_err( + span, + format!( + "tuple constructor has {} arguments but {} were provided", + variant_def.fields.len(), + args.len() + ), + ); + return ty::Const::new_error(tcx, e); + } + + let fields = variant_def + .fields + .iter() + .zip(args) + .map(|(field_def, arg)| { + self.lower_const_arg(arg, FeedConstTy::Param(field_def.did, adt_args)) + }) + .collect::>(); + + let opt_discr_const = if adt_def.is_enum() { + let valtree = ty::ValTree::from_scalar_int(tcx, variant_idx.into()); + Some(ty::Const::new_value(tcx, valtree, tcx.types.u32)) + } else { + None + }; + + let valtree = ty::ValTree::from_branches(tcx, opt_discr_const.into_iter().chain(fields)); + let adt_ty = Ty::new_adt(tcx, adt_def, adt_args); + ty::Const::new_value(tcx, valtree, adt_ty) + } + fn lower_const_arg_struct( &self, hir_id: HirId, @@ -2403,6 +2522,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let args = self.lower_generic_args_of_path_segment(span, did, segment); ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(did, args)) } + Res::Def(DefKind::Ctor(_, CtorKind::Fn), did) => { + assert_eq!(opt_self_ty, None); + let [leading_segments @ .., segment] = path.segments else { bug!() }; + let _ = self + .prohibit_generic_args(leading_segments.iter(), GenericsArgsErrExtend::None); + let parent_did = tcx.parent(did); + let generics_did = if let DefKind::Ctor(CtorOf::Variant, _) = tcx.def_kind(did) { + tcx.parent(parent_did) + } else { + parent_did + }; + let args = self.lower_generic_args_of_path_segment(span, generics_did, segment); + ty::Const::zero_sized(tcx, Ty::new_fn_def(tcx, did, args)) + } Res::Def(DefKind::AssocConst, did) => { let trait_segment = if let [modules @ .., trait_, _item] = path.segments { let _ = self.prohibit_generic_args(modules.iter(), GenericsArgsErrExtend::None); @@ -2438,9 +2571,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { DefKind::Mod | DefKind::Enum | DefKind::Variant - | DefKind::Ctor(CtorOf::Variant, CtorKind::Fn) | DefKind::Struct - | DefKind::Ctor(CtorOf::Struct, CtorKind::Fn) | DefKind::OpaqueTy | DefKind::TyAlias | DefKind::TraitAlias diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 5c03135ee1bf..533afc372063 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1139,6 +1139,7 @@ impl<'a> State<'a> { match &const_arg.kind { // FIXME(mgca): proper printing for struct exprs ConstArgKind::Struct(..) => self.word("/* STRUCT EXPR */"), + ConstArgKind::TupleCall(..) => self.word("/* TUPLE CALL */"), ConstArgKind::Path(qpath) => self.print_qpath(qpath, true), ConstArgKind::Anon(anon) => self.print_anon_const(anon), ConstArgKind::Error(_, _) => self.word("/*ERROR*/"), diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 920c896d5a47..d79ab9eaf759 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1441,6 +1441,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // Skip encoding defs for these as they should not have had a `DefId` created hir::ConstArgKind::Error(..) | hir::ConstArgKind::Struct(..) + | hir::ConstArgKind::TupleCall(..) | hir::ConstArgKind::Path(..) | hir::ConstArgKind::Infer(..) => true, hir::ConstArgKind::Anon(..) => false, diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index b50fc201bdb8..f7b85453448c 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -419,7 +419,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { // Avoid overwriting `const_arg_context` as we may want to treat const blocks // as being anon consts if we are inside a const argument. - ExprKind::Struct(_) => return visit::walk_expr(self, expr), + ExprKind::Struct(_) | ExprKind::Call(..) => return visit::walk_expr(self, expr), // FIXME(mgca): we may want to handle block labels in some manner ExprKind::Block(block, _) if let [stmt] = block.stmts.as_slice() => match stmt.kind { // FIXME(mgca): this probably means that mac calls that expand diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 707b48b355ba..d75a93606ea2 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -323,6 +323,9 @@ pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg<'tcx>) -> ConstantKind // FIXME(mgca): proper printing :3 ConstantKind::Path { path: "/* STRUCT EXPR */".to_string().into() } } + hir::ConstArgKind::TupleCall(..) => { + ConstantKind::Path { path: "/* TUPLE CALL */".to_string().into() } + } hir::ConstArgKind::Anon(anon) => ConstantKind::Anonymous { body: anon.body }, hir::ConstArgKind::Infer(..) | hir::ConstArgKind::Error(..) => ConstantKind::Infer, } @@ -1804,7 +1807,9 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T let ct = cx.tcx.normalize_erasing_regions(typing_env, ct); print_const(cx, ct) } - hir::ConstArgKind::Struct(..) | hir::ConstArgKind::Path(..) => { + hir::ConstArgKind::Struct(..) + | hir::ConstArgKind::Path(..) + | hir::ConstArgKind::TupleCall(..) => { let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, FeedConstTy::No); print_const(cx, ct) } diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 90fa976fda38..f515f9987a80 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -320,6 +320,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { self.body(field!(anon_const.body)); }, ConstArgKind::Struct(..) => chain!(self, "let ConstArgKind::Struct(..) = {const_arg}.kind"), + ConstArgKind::TupleCall(..) => chain!(self, "let ConstArgKind::TupleCall(..) = {const_arg}.kind"), ConstArgKind::Infer(..) => chain!(self, "let ConstArgKind::Infer(..) = {const_arg}.kind"), ConstArgKind::Error(..) => chain!(self, "let ConstArgKind::Error(..) = {const_arg}.kind"), } diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 78e3d6d192a0..a44cd31dc123 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -1140,7 +1140,7 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx ConstItemRhs::Body(body_id) => Some(tcx.hir_body(body_id).value), ConstItemRhs::TypeConst(const_arg) => match const_arg.kind { ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value), - ConstArgKind::Struct(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => { + ConstArgKind::Struct(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => { None }, }, diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 03853b5b4af5..f1ee534c500d 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -671,11 +671,19 @@ impl HirEqInterExpr<'_, '_, '_> { .iter() .zip(*inits_b) .all(|(init_a, init_b)| self.eq_const_arg(init_a.expr, init_b.expr)) - }, + } + (ConstArgKind::TupleCall(path_a, args_a), ConstArgKind::TupleCall(path_b, args_b)) => { + self.eq_qpath(path_a, path_b) + && args_a + .iter() + .zip(*args_b) + .all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b)) + } // Use explicit match for now since ConstArg is undergoing flux. ( ConstArgKind::Path(..) | ConstArgKind::Anon(..) + | ConstArgKind::TupleCall(..) | ConstArgKind::Infer(..) | ConstArgKind::Struct(..) | ConstArgKind::Error(..), @@ -1546,6 +1554,12 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_const_arg(init.expr); } }, + ConstArgKind::TupleCall(path, args) => { + self.hash_qpath(path); + for arg in *args { + self.hash_const_arg(arg); + } + }, ConstArgKind::Infer(..) | ConstArgKind::Error(..) => {}, } } diff --git a/tests/crashes/136379.rs b/tests/crashes/136379.rs deleted file mode 100644 index 077b373e3b5d..000000000000 --- a/tests/crashes/136379.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: #136379 -#![feature(min_generic_const_args)] -pub struct S(); - -impl S { - pub fn f() -> [u8; S] { - [] - } -} - -pub fn main() {} diff --git a/tests/crashes/138132.rs b/tests/crashes/138132.rs deleted file mode 100644 index 3e31117c526a..000000000000 --- a/tests/crashes/138132.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ known-bug: #138132 -#![feature(min_generic_const_args)] -struct b(Box<[u8; c]>); -impl b { - fn d(self) { - self.0.e() - } -} -struct c<'a>(&'a u8); -fn main() {} diff --git a/tests/ui/const-generics/mgca/tuple_ctor_arg_simple.rs b/tests/ui/const-generics/mgca/tuple_ctor_arg_simple.rs new file mode 100644 index 000000000000..a5b3d3d0d5b6 --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_ctor_arg_simple.rs @@ -0,0 +1,52 @@ +//@ run-pass +#![feature(min_generic_const_args, adt_const_params)] +#![expect(incomplete_features)] +#![allow(dead_code)] + +use std::marker::ConstParamTy; + +#[derive(Debug, Eq, PartialEq, ConstParamTy)] +struct Point(u32, u32); + +#[derive(Debug, Eq, PartialEq, ConstParamTy)] +enum MyEnum { + Variant(T), + Other, +} + +trait Trait { + #[type_const] + const ASSOC: u32; +} + +fn with_point() -> Point { + P +} + +fn with_enum>() -> MyEnum { + E +} + +fn test() { + with_point::<{ Point(::ASSOC, N) }>(); +} + +fn test_basic() { + with_point::<{ Point(N, N) }>(); + with_point::<{ Point(const { 5 }, const { 10 }) }>(); + + with_enum::<{ MyEnum::Variant::(N) }>(); + with_enum::<{ MyEnum::Variant::(const { 42 }) }>(); + + with_enum::<{ >::Variant(N) }>(); +} + +fn main() { + test_basic::<5>(); + + let p = with_point::<{ Point(const { 1 }, const { 2 }) }>(); + assert_eq!(p, Point(1, 2)); + + let e = with_enum::<{ MyEnum::Variant::(const { 10 }) }>(); + assert_eq!(e, MyEnum::Variant(10)); +} diff --git a/tests/ui/const-generics/mgca/tuple_ctor_complex_args.rs b/tests/ui/const-generics/mgca/tuple_ctor_complex_args.rs new file mode 100644 index 000000000000..2e39f8952b11 --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_ctor_complex_args.rs @@ -0,0 +1,19 @@ +#![feature(min_generic_const_args, adt_const_params)] +#![expect(incomplete_features)] + +use std::marker::ConstParamTy; + +#[derive(Eq, PartialEq, ConstParamTy)] +struct Point(u32, u32); + +fn with_point() {} + +fn test() { + with_point::<{ Point(N + 1, N) }>(); + //~^ ERROR complex const arguments must be placed inside of a `const` block + + with_point::<{ Point(const { N + 1 }, N) }>(); + //~^ ERROR generic parameters may not be used in const operations +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/tuple_ctor_complex_args.stderr b/tests/ui/const-generics/mgca/tuple_ctor_complex_args.stderr new file mode 100644 index 000000000000..e0ea3fd5560c --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_ctor_complex_args.stderr @@ -0,0 +1,14 @@ +error: complex const arguments must be placed inside of a `const` block + --> $DIR/tuple_ctor_complex_args.rs:12:26 + | +LL | with_point::<{ Point(N + 1, N) }>(); + | ^^^^^ + +error: generic parameters may not be used in const operations + --> $DIR/tuple_ctor_complex_args.rs:15:34 + | +LL | with_point::<{ Point(const { N + 1 }, N) }>(); + | ^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/const-generics/mgca/tuple_ctor_erroneous.rs b/tests/ui/const-generics/mgca/tuple_ctor_erroneous.rs new file mode 100644 index 000000000000..84ded05fdd0e --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_ctor_erroneous.rs @@ -0,0 +1,46 @@ +#![feature(min_generic_const_args, adt_const_params)] +#![expect(incomplete_features)] + +use std::marker::ConstParamTy; + +#[derive(Eq, PartialEq, ConstParamTy)] +struct Point(u32, u32); + +#[derive(Eq, PartialEq, ConstParamTy)] +enum MyEnum { + Variant(T), + Unit, +} + +const CONST_ITEM: u32 = 42; + +fn accepts_point() {} +fn accepts_enum>() {} + +fn non_ctor() {} + +fn test_errors() { + accepts_point::<{ Point(N) }>(); + //~^ ERROR tuple constructor has 2 arguments but 1 were provided + + accepts_point::<{ Point(N, N, N) }>(); + //~^ ERROR tuple constructor has 2 arguments but 3 were provided + + accepts_point::<{ UnresolvedIdent(N, N) }>(); + //~^ ERROR cannot find function, tuple struct or tuple variant `UnresolvedIdent` in this scope + //~| ERROR tuple constructor with invalid base path + + accepts_point::<{ non_ctor(N, N) }>(); + //~^ ERROR tuple constructor with invalid base path + + accepts_point::<{ CONST_ITEM(N, N) }>(); + //~^ ERROR tuple constructor with invalid base path + + accepts_point::<{ Point }>(); + //~^ ERROR the constant `Point` is not of type `Point` + + accepts_enum::<{ MyEnum::Variant:: }>(); + //~^ ERROR the constant `MyEnum::::Variant` is not of type `MyEnum` +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/tuple_ctor_erroneous.stderr b/tests/ui/const-generics/mgca/tuple_ctor_erroneous.stderr new file mode 100644 index 000000000000..fbcdf35461ec --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_ctor_erroneous.stderr @@ -0,0 +1,68 @@ +error[E0425]: cannot find function, tuple struct or tuple variant `UnresolvedIdent` in this scope + --> $DIR/tuple_ctor_erroneous.rs:29:23 + | +LL | accepts_point::<{ UnresolvedIdent(N, N) }>(); + | ^^^^^^^^^^^^^^^ not found in this scope + | +help: you might be missing a const parameter + | +LL | fn test_errors() { + | +++++++++++++++++++++++++++++++++++ + +error: tuple constructor has 2 arguments but 1 were provided + --> $DIR/tuple_ctor_erroneous.rs:23:23 + | +LL | accepts_point::<{ Point(N) }>(); + | ^^^^^ + +error: tuple constructor has 2 arguments but 3 were provided + --> $DIR/tuple_ctor_erroneous.rs:26:23 + | +LL | accepts_point::<{ Point(N, N, N) }>(); + | ^^^^^ + +error: tuple constructor with invalid base path + --> $DIR/tuple_ctor_erroneous.rs:29:23 + | +LL | accepts_point::<{ UnresolvedIdent(N, N) }>(); + | ^^^^^^^^^^^^^^^ + +error: tuple constructor with invalid base path + --> $DIR/tuple_ctor_erroneous.rs:33:23 + | +LL | accepts_point::<{ non_ctor(N, N) }>(); + | ^^^^^^^^ + +error: tuple constructor with invalid base path + --> $DIR/tuple_ctor_erroneous.rs:36:23 + | +LL | accepts_point::<{ CONST_ITEM(N, N) }>(); + | ^^^^^^^^^^ + +error: the constant `Point` is not of type `Point` + --> $DIR/tuple_ctor_erroneous.rs:39:23 + | +LL | accepts_point::<{ Point }>(); + | ^^^^^ expected `Point`, found struct constructor + | +note: required by a const generic parameter in `accepts_point` + --> $DIR/tuple_ctor_erroneous.rs:17:18 + | +LL | fn accepts_point() {} + | ^^^^^^^^^^^^^^ required by this const generic parameter in `accepts_point` + +error: the constant `MyEnum::::Variant` is not of type `MyEnum` + --> $DIR/tuple_ctor_erroneous.rs:42:22 + | +LL | accepts_enum::<{ MyEnum::Variant:: }>(); + | ^^^^^^^^^^^^^^^^^^^^^^ expected `MyEnum`, found enum constructor + | +note: required by a const generic parameter in `accepts_enum` + --> $DIR/tuple_ctor_erroneous.rs:18:17 + | +LL | fn accepts_enum>() {} + | ^^^^^^^^^^^^^^^^^^^^ required by this const generic parameter in `accepts_enum` + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/const-generics/mgca/tuple_ctor_in_array_len.rs b/tests/ui/const-generics/mgca/tuple_ctor_in_array_len.rs new file mode 100644 index 000000000000..5c7290b40be2 --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_ctor_in_array_len.rs @@ -0,0 +1,16 @@ +//! Regression test for + +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +pub struct S(); + +impl S { + pub fn f() -> [u8; S] { + //~^ ERROR the constant `S` is not of type `usize` + [] + //~^ ERROR mismatched types [E0308] + } +} + +pub fn main() {} diff --git a/tests/ui/const-generics/mgca/tuple_ctor_in_array_len.stderr b/tests/ui/const-generics/mgca/tuple_ctor_in_array_len.stderr new file mode 100644 index 000000000000..64c3cecd4fb5 --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_ctor_in_array_len.stderr @@ -0,0 +1,23 @@ +error: the constant `S` is not of type `usize` + --> $DIR/tuple_ctor_in_array_len.rs:9:19 + | +LL | pub fn f() -> [u8; S] { + | ^^^^^^^ expected `usize`, found struct constructor + | + = note: the length of array `[u8; S]` must be type `usize` + +error[E0308]: mismatched types + --> $DIR/tuple_ctor_in_array_len.rs:11:9 + | +LL | pub fn f() -> [u8; S] { + | ------- expected `[u8; S]` because of return type +LL | +LL | [] + | ^^ expected an array with a size of S, found one with a size of 0 + | + = note: expected array `[u8; S]` + found array `[_; 0]` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/mgca/tuple_ctor_nested.rs b/tests/ui/const-generics/mgca/tuple_ctor_nested.rs new file mode 100644 index 000000000000..49a31ea3e527 --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_ctor_nested.rs @@ -0,0 +1,38 @@ +//@ run-pass +#![feature(min_generic_const_args, adt_const_params)] +#![expect(incomplete_features)] + +use std::marker::ConstParamTy; + +#[derive(Debug, Eq, PartialEq, ConstParamTy)] +struct Inner(u32); + +#[derive(Debug, Eq, PartialEq, ConstParamTy)] +struct Outer(Inner); + +#[derive(Debug, Eq, PartialEq, ConstParamTy)] +enum Container { + Wrap(T), +} + +fn with_outer() -> Outer { + O +} + +fn with_container>() -> Container { + C +} + +fn test() { + with_outer::<{ Outer(Inner(N)) }>(); + with_outer::<{ Outer(Inner(const { 42 })) }>(); + + with_container::<{ Container::Wrap::(Inner(N)) }>(); +} + +fn main() { + test::<5>(); + + let o = with_outer::<{ Outer(Inner(const { 10 })) }>(); + assert_eq!(o, Outer(Inner(10))); +} diff --git a/tests/ui/const-generics/mgca/tuple_ctor_type_relative.rs b/tests/ui/const-generics/mgca/tuple_ctor_type_relative.rs new file mode 100644 index 000000000000..d5a07cbb7d70 --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_ctor_type_relative.rs @@ -0,0 +1,26 @@ +//@ run-pass +#![feature(min_generic_const_args, adt_const_params)] +#![expect(incomplete_features)] + +use std::marker::ConstParamTy; + +#[derive(Debug, Eq, PartialEq, ConstParamTy)] +enum Option { + Some(T), +} + +fn with_option>() -> Option { + O +} + +fn test() { + with_option::<{ >::Some(N) }>(); + with_option::<{ >::Some(const { 42 }) }>(); +} + +fn main() { + test::<5>(); + + let o = with_option::<{ >::Some(const { 10 }) }>(); + assert_eq!(o, Option::Some(10)); +} diff --git a/tests/ui/const-generics/mgca/type_as_const_in_array_len.rs b/tests/ui/const-generics/mgca/type_as_const_in_array_len.rs new file mode 100644 index 000000000000..b6b76fe3fc91 --- /dev/null +++ b/tests/ui/const-generics/mgca/type_as_const_in_array_len.rs @@ -0,0 +1,14 @@ +//! Regression test for + +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +struct B(Box<[u8; C]>); +//~^ ERROR missing generics for struct `C` +impl B { + fn d(self) { + self.0.e() + } +} +struct C<'a>(&'a u8); +fn main() {} diff --git a/tests/ui/const-generics/mgca/type_as_const_in_array_len.stderr b/tests/ui/const-generics/mgca/type_as_const_in_array_len.stderr new file mode 100644 index 000000000000..482fd730a71c --- /dev/null +++ b/tests/ui/const-generics/mgca/type_as_const_in_array_len.stderr @@ -0,0 +1,19 @@ +error[E0107]: missing generics for struct `C` + --> $DIR/type_as_const_in_array_len.rs:6:19 + | +LL | struct B(Box<[u8; C]>); + | ^ expected 1 lifetime argument + | +note: struct defined here, with 1 lifetime parameter: `'a` + --> $DIR/type_as_const_in_array_len.rs:13:8 + | +LL | struct C<'a>(&'a u8); + | ^ -- +help: add missing lifetime argument + | +LL | struct B(Box<[u8; C<'a>]>); + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0107`. From 08e0400116f8fd5ccb84ac7c0839ae4afc465449 Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Sun, 4 Jan 2026 12:50:21 +0000 Subject: [PATCH 0249/1061] add unit test for ExtraCheckArg::from_str --- src/tools/tidy/src/extra_checks/mod.rs | 50 ++++++++------ src/tools/tidy/src/extra_checks/tests.rs | 86 ++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 22 deletions(-) create mode 100644 src/tools/tidy/src/extra_checks/tests.rs diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index 2d654339e883..fd3dfbcf19b8 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -28,6 +28,9 @@ use crate::{CiInfo, ensure_version}; mod rustdoc_js; +#[cfg(test)] +mod tests; + const MIN_PY_REV: (u32, u32) = (3, 9); const MIN_PY_REV_STR: &str = "≥3.9"; @@ -735,7 +738,7 @@ impl From for Error { } } -#[derive(Debug)] +#[derive(Debug, PartialEq)] enum ExtraCheckParseError { #[allow(dead_code, reason = "shown through Debug")] UnknownKind(String), @@ -752,6 +755,7 @@ enum ExtraCheckParseError { IfInstalledRequiresLang, } +#[derive(PartialEq, Debug)] struct ExtraCheckArg { /// Only run the check if files to check have been modified. auto: bool, @@ -854,30 +858,32 @@ impl FromStr for ExtraCheckArg { let mut auto = false; let mut if_installed = false; let mut parts = s.split(':'); - let Some(mut first) = parts.next() else { - return Err(ExtraCheckParseError::Empty); + let mut first = match parts.next() { + Some("") | None => return Err(ExtraCheckParseError::Empty), + Some(part) => part, }; + // The loop allows users to specify `auto` and `if-installed` in any order. // Both auto:if-installed: and if-installed:auto: are valid. loop { - if !auto && first == "auto" { - let Some(part) = parts.next() else { - return Err(ExtraCheckParseError::AutoRequiresLang); - }; - auto = true; - first = part; - continue; + match (first, auto, if_installed) { + ("auto", false, _) => { + let Some(part) = parts.next() else { + return Err(ExtraCheckParseError::AutoRequiresLang); + }; + auto = true; + first = part; + } + ("if-installed", _, false) => { + let Some(part) = parts.next() else { + return Err(ExtraCheckParseError::IfInstalledRequiresLang); + }; + if_installed = true; + first = part; + continue; + } + _ => break, } - - if !if_installed && first == "if-installed" { - let Some(part) = parts.next() else { - return Err(ExtraCheckParseError::IfInstalledRequiresLang); - }; - if_installed = true; - first = part; - continue; - } - break; } let second = parts.next(); if parts.next().is_some() { @@ -897,7 +903,7 @@ impl FromStr for ExtraCheckArg { } } -#[derive(PartialEq, Copy, Clone)] +#[derive(PartialEq, Copy, Clone, Debug)] enum ExtraCheckLang { Py, Shell, @@ -921,7 +927,7 @@ impl FromStr for ExtraCheckLang { } } -#[derive(PartialEq, Copy, Clone)] +#[derive(PartialEq, Copy, Clone, Debug)] enum ExtraCheckKind { Lint, Fmt, diff --git a/src/tools/tidy/src/extra_checks/tests.rs b/src/tools/tidy/src/extra_checks/tests.rs new file mode 100644 index 000000000000..62501803b255 --- /dev/null +++ b/src/tools/tidy/src/extra_checks/tests.rs @@ -0,0 +1,86 @@ +use std::str::FromStr; + +use crate::extra_checks::{ExtraCheckArg, ExtraCheckKind, ExtraCheckLang, ExtraCheckParseError}; + +#[test] +fn test_extra_check_arg_from_str_ok() { + let test_cases = [ + ( + "auto:if-installed:spellcheck", + Ok(ExtraCheckArg { + auto: true, + if_installed: true, + lang: ExtraCheckLang::Spellcheck, + kind: None, + }), + ), + ( + "if-installed:auto:spellcheck", + Ok(ExtraCheckArg { + auto: true, + if_installed: true, + lang: ExtraCheckLang::Spellcheck, + kind: None, + }), + ), + ( + "auto:spellcheck", + Ok(ExtraCheckArg { + auto: true, + if_installed: false, + lang: ExtraCheckLang::Spellcheck, + kind: None, + }), + ), + ( + "if-installed:spellcheck", + Ok(ExtraCheckArg { + auto: false, + if_installed: true, + lang: ExtraCheckLang::Spellcheck, + kind: None, + }), + ), + ( + "spellcheck", + Ok(ExtraCheckArg { + auto: false, + if_installed: false, + lang: ExtraCheckLang::Spellcheck, + kind: None, + }), + ), + ( + "js:lint", + Ok(ExtraCheckArg { + auto: false, + if_installed: false, + lang: ExtraCheckLang::Js, + kind: Some(ExtraCheckKind::Lint), + }), + ), + ]; + + for (s, expected) in test_cases { + assert_eq!(ExtraCheckArg::from_str(s), expected); + } +} + +#[test] +fn test_extra_check_arg_from_str_err() { + let test_cases = [ + ("some:spellcheck", Err(ExtraCheckParseError::UnknownLang("some".to_string()))), + ("spellcheck:some", Err(ExtraCheckParseError::UnknownKind("some".to_string()))), + ("spellcheck:lint", Err(ExtraCheckParseError::UnsupportedKindForLang)), + ("auto:spellcheck:some", Err(ExtraCheckParseError::UnknownKind("some".to_string()))), + ("auto:js:lint:some", Err(ExtraCheckParseError::TooManyParts)), + ("some", Err(ExtraCheckParseError::UnknownLang("some".to_string()))), + ("auto", Err(ExtraCheckParseError::AutoRequiresLang)), + ("if-installed", Err(ExtraCheckParseError::IfInstalledRequiresLang)), + ("", Err(ExtraCheckParseError::Empty)), + ]; + + for (s, expected) in test_cases { + assert_eq!(ExtraCheckArg::from_str(s), expected); + } +} From 359f060175a99e73d576c08aa9f6140a13df0f4a Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Sun, 4 Jan 2026 17:06:39 +0000 Subject: [PATCH 0250/1061] relate.rs: tiny cleanup: eliminate temp vars --- compiler/rustc_type_ir/src/relate.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index 4954ebc51cfc..9e14bf6b60ad 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -155,11 +155,10 @@ impl Relate for ty::FnSig { let cx = relation.cx(); if a.c_variadic != b.c_variadic { - return Err(TypeError::VariadicMismatch({ - let a = a.c_variadic; - let b = b.c_variadic; - ExpectedFound::new(a, b) - })); + return Err(TypeError::VariadicMismatch(ExpectedFound::new( + a.c_variadic, + b.c_variadic, + ))); } if a.safety != b.safety { From dfe7d8a9b647d1e6b9bd51bc81bdbba067a69e13 Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Sun, 4 Jan 2026 16:24:00 +0000 Subject: [PATCH 0251/1061] move ensure_version/ensure_version_or_cargo_install to extra_checks --- src/tools/tidy/src/extra_checks/mod.rs | 103 ++++++++++++++++++++++--- src/tools/tidy/src/lib.rs | 81 ------------------- 2 files changed, 93 insertions(+), 91 deletions(-) diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index fd3dfbcf19b8..a1d9ad436885 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -21,10 +21,12 @@ use std::ffi::OsStr; use std::path::{Path, PathBuf}; use std::process::Command; use std::str::FromStr; -use std::{fmt, fs, io}; +use std::{env, fmt, fs, io}; +use build_helper::ci::CiEnv; + +use crate::CiInfo; use crate::diagnostics::TidyCtx; -use crate::{CiInfo, ensure_version}; mod rustdoc_js; @@ -630,13 +632,8 @@ fn spellcheck_runner( cargo: &Path, args: &[&str], ) -> Result<(), Error> { - let bin_path = crate::ensure_version_or_cargo_install( - outdir, - cargo, - "typos-cli", - "typos", - SPELLCHECK_VER, - )?; + let bin_path = + ensure_version_or_cargo_install(outdir, cargo, "typos-cli", "typos", SPELLCHECK_VER)?; match Command::new(bin_path).current_dir(src_root).args(args).status() { Ok(status) => { if status.success() { @@ -690,6 +687,83 @@ fn find_with_extension( Ok(output) } +/// Check if the given executable is installed and the version is expected. +fn ensure_version(build_dir: &Path, bin_name: &str, version: &str) -> Result { + let bin_path = build_dir.join("misc-tools").join("bin").join(bin_name); + + match Command::new(&bin_path).arg("--version").output() { + Ok(output) => { + let Some(v) = str::from_utf8(&output.stdout).unwrap().trim().split_whitespace().last() + else { + return Err(Error::Generic("version check failed".to_string())); + }; + + if v != version { + return Err(Error::Version { program: "", required: "", installed: v.to_string() }); + } + Ok(bin_path) + } + Err(e) => Err(Error::Io(e)), + } +} + +/// If the given executable is installed with the given version, use that, +/// otherwise install via cargo. +fn ensure_version_or_cargo_install( + build_dir: &Path, + cargo: &Path, + pkg_name: &str, + bin_name: &str, + version: &str, +) -> Result { + if let Ok(bin_path) = ensure_version(build_dir, bin_name, version) { + return Ok(bin_path); + } + + eprintln!("building external tool {bin_name} from package {pkg_name}@{version}"); + + let tool_root_dir = build_dir.join("misc-tools"); + let tool_bin_dir = tool_root_dir.join("bin"); + let bin_path = tool_bin_dir.join(bin_name).with_extension(env::consts::EXE_EXTENSION); + + // use --force to ensure that if the required version is bumped, we update it. + // use --target-dir to ensure we have a build cache so repeated invocations aren't slow. + // modify PATH so that cargo doesn't print a warning telling the user to modify the path. + let mut cmd = Command::new(cargo); + cmd.args(["install", "--locked", "--force", "--quiet"]) + .arg("--root") + .arg(&tool_root_dir) + .arg("--target-dir") + .arg(tool_root_dir.join("target")) + .arg(format!("{pkg_name}@{version}")) + .env( + "PATH", + env::join_paths( + env::split_paths(&env::var("PATH").unwrap()) + .chain(std::iter::once(tool_bin_dir.clone())), + ) + .expect("build dir contains invalid char"), + ); + + // On CI, we set opt-level flag for quicker installation. + // Since lower opt-level decreases the tool's performance, + // we don't set this option on local. + if CiEnv::is_ci() { + cmd.env("RUSTFLAGS", "-Copt-level=0"); + } + + let cargo_exit_code = cmd.spawn()?.wait()?; + if !cargo_exit_code.success() { + return Err(Error::Generic("cargo install failed".to_string())); + } + assert!( + matches!(bin_path.try_exists(), Ok(true)), + "cargo install did not produce the expected binary" + ); + eprintln!("finished building tool {bin_name}"); + Ok(bin_path) +} + #[derive(Debug)] enum Error { Io(io::Error), @@ -778,7 +852,16 @@ impl ExtraCheckArg { match self.lang { ExtraCheckLang::Spellcheck => { - ensure_version(build_dir, "typos", SPELLCHECK_VER).is_ok() + match ensure_version(build_dir, "typos", SPELLCHECK_VER) { + Ok(_) => true, + Err(Error::Version { installed, .. }) => { + eprintln!( + "warning: the tool `typos` is detected, but version {installed} doesn't match with the expected version {SPELLCHECK_VER}" + ); + false + } + _ => false, + } } ExtraCheckLang::Shell => has_shellcheck().is_ok(), ExtraCheckLang::Js => { diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 62da0191da9e..425f43e42b7f 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -4,9 +4,7 @@ //! to be used by tools. use std::ffi::OsStr; -use std::path::{Path, PathBuf}; use std::process::Command; -use std::{env, io}; use build_helper::ci::CiEnv; use build_helper::git::{GitConfig, get_closest_upstream_commit}; @@ -158,85 +156,6 @@ pub fn files_modified(ci_info: &CiInfo, pred: impl Fn(&str) -> bool) -> bool { !v.is_empty() } -/// Check if the given executable is installed and the version is expected. -pub fn ensure_version(build_dir: &Path, bin_name: &str, version: &str) -> io::Result { - let bin_path = build_dir.join("misc-tools").join("bin").join(bin_name); - - match Command::new(&bin_path).arg("--version").output() { - Ok(output) => { - let Some(v) = str::from_utf8(&output.stdout).unwrap().trim().split_whitespace().last() - else { - return Err(io::Error::other("version check failed")); - }; - - if v != version { - eprintln!( - "warning: the tool `{bin_name}` is detected, but version {v} doesn't match with the expected version {version}" - ); - } - Ok(bin_path) - } - Err(e) => Err(e), - } -} - -/// If the given executable is installed with the given version, use that, -/// otherwise install via cargo. -pub fn ensure_version_or_cargo_install( - build_dir: &Path, - cargo: &Path, - pkg_name: &str, - bin_name: &str, - version: &str, -) -> io::Result { - if let Ok(bin_path) = ensure_version(build_dir, bin_name, version) { - return Ok(bin_path); - } - - eprintln!("building external tool {bin_name} from package {pkg_name}@{version}"); - - let tool_root_dir = build_dir.join("misc-tools"); - let tool_bin_dir = tool_root_dir.join("bin"); - let bin_path = tool_bin_dir.join(bin_name).with_extension(env::consts::EXE_EXTENSION); - - // use --force to ensure that if the required version is bumped, we update it. - // use --target-dir to ensure we have a build cache so repeated invocations aren't slow. - // modify PATH so that cargo doesn't print a warning telling the user to modify the path. - let mut cmd = Command::new(cargo); - cmd.args(["install", "--locked", "--force", "--quiet"]) - .arg("--root") - .arg(&tool_root_dir) - .arg("--target-dir") - .arg(tool_root_dir.join("target")) - .arg(format!("{pkg_name}@{version}")) - .env( - "PATH", - env::join_paths( - env::split_paths(&env::var("PATH").unwrap()) - .chain(std::iter::once(tool_bin_dir.clone())), - ) - .expect("build dir contains invalid char"), - ); - - // On CI, we set opt-level flag for quicker installation. - // Since lower opt-level decreases the tool's performance, - // we don't set this option on local. - if CiEnv::is_ci() { - cmd.env("RUSTFLAGS", "-Copt-level=0"); - } - - let cargo_exit_code = cmd.spawn()?.wait()?; - if !cargo_exit_code.success() { - return Err(io::Error::other("cargo install failed")); - } - assert!( - matches!(bin_path.try_exists(), Ok(true)), - "cargo install did not produce the expected binary" - ); - eprintln!("finished building tool {bin_name}"); - Ok(bin_path) -} - pub mod alphabetical; pub mod bins; pub mod debug_artifacts; From 7dbe12ec729ed3ce6d7b228cbb213d8e73df30b4 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Mon, 5 Jan 2026 00:37:40 +0900 Subject: [PATCH 0252/1061] fix: Suppress false positive missing assoc item diag on specialization --- src/tools/rust-analyzer/crates/hir/src/lib.rs | 42 +++++++++++++++++++ .../handlers/trait_impl_missing_assoc_item.rs | 18 ++++++++ 2 files changed, 60 insertions(+) diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index ef35694774e0..78be5a7e8fa9 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -920,6 +920,48 @@ impl Module { } } + // HACK: When specialization is enabled in the current crate, and there exists + // *any* blanket impl that provides a default implementation for the missing item, + // suppress the missing associated item diagnostic. + // This can lead to false negatives when the impl in question does not actually + // specialize that blanket impl, but determining the exact specialization + // relationship here would be significantly more expensive. + if !missing.is_empty() { + let krate = self.krate(db).id; + let def_map = crate_def_map(db, krate); + if def_map.is_unstable_feature_enabled(&sym::specialization) + || def_map.is_unstable_feature_enabled(&sym::min_specialization) + { + missing.retain(|(assoc_name, assoc_item)| { + let AssocItem::Function(_) = assoc_item else { + return true; + }; + + for &impl_ in TraitImpls::for_crate(db, krate).blanket_impls(trait_.id) + { + if impl_ == impl_id { + continue; + } + + for (name, item) in &impl_.impl_items(db).items { + let AssocItemId::FunctionId(fn_) = item else { + continue; + }; + if name != assoc_name { + continue; + } + + if db.function_signature(*fn_).is_default() { + return false; + } + } + } + + true + }); + } + } + if !missing.is_empty() { acc.push( TraitImplMissingAssocItems { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs index 0e18ce967404..2c0554470187 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs @@ -156,4 +156,22 @@ impl Trait for dyn OtherTrait {} "#, ) } + + #[test] + fn no_false_positive_on_specialization() { + check_diagnostics( + r#" +#![feature(specialization)] + +pub trait Foo { + fn foo(); +} + +impl Foo for T { + default fn foo() {} +} +impl Foo for bool {} +"#, + ); + } } From 65c17223c1fa4792be28f533c17f680d9eef0e66 Mon Sep 17 00:00:00 2001 From: is57primenumber <58158444+is57primenumber@users.noreply.github.com> Date: Wed, 17 Dec 2025 02:30:19 +0900 Subject: [PATCH 0253/1061] add CSE optimization tests for iterating over slice --- tests/codegen-llvm/slice_cse_optimization.rs | 46 ++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 tests/codegen-llvm/slice_cse_optimization.rs diff --git a/tests/codegen-llvm/slice_cse_optimization.rs b/tests/codegen-llvm/slice_cse_optimization.rs new file mode 100644 index 000000000000..2b1851d8ae44 --- /dev/null +++ b/tests/codegen-llvm/slice_cse_optimization.rs @@ -0,0 +1,46 @@ +//! Various iterating method over slice correctly optimized using common subexpression elimination. +//! Checks function has memory(argmem: read) attribute. +//! Regression test for . +//@ compile-flags: -O + +#![crate_type = "lib"] +// CHECK-LABEL: @has_zero_iter +// CHECK-SAME: #[[ATTR:[0-9]+]] +#[inline(never)] +#[unsafe(no_mangle)] +pub fn has_zero_iter(xs: &[u8]) -> bool { + xs.iter().any(|&x| x == 0) +} + +// CHECK-LABEL: @has_zero_ptr +// CHECK-SAME: #[[ATTR]] +#[inline(never)] +#[unsafe(no_mangle)] +fn has_zero_ptr(xs: &[u8]) -> bool { + let range = xs.as_ptr_range(); + let mut start = range.start; + let end = range.end; + while start < end { + unsafe { + if *start == 0 { + return true; + } + start = start.add(1); + } + } + false +} +// CHECK-LABEL: @has_zero_for +// CHECK-SAME: #[[ATTR]] +#[inline(never)] +#[unsafe(no_mangle)] +fn has_zero_for(xs: &[u8]) -> bool { + for x in xs { + if *x == 0 { + return true; + } + } + false +} + +// CHECK: attributes #[[ATTR]] = { {{.*}}memory(argmem: read){{.*}} } From 814ee134f7ffb50369e46e94bf2829108cff0baf Mon Sep 17 00:00:00 2001 From: clubby789 Date: Sun, 4 Jan 2026 22:07:40 +0000 Subject: [PATCH 0254/1061] Bump `askama` to 0.15 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 67078adea2b4..7379dcbb7b37 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ walkdir = "2.3" filetime = "0.2.9" itertools = "0.12" pulldown-cmark = { version = "0.11", default-features = false, features = ["html"] } -askama = { version = "0.14", default-features = false, features = ["alloc", "config", "derive"] } +askama = { version = "0.15", default-features = false, features = ["alloc", "config", "derive"] } [dev-dependencies.toml] version = "0.9.7" From 9ba5b5e7f7b99bc9579d4893b5dd7582924ac68c Mon Sep 17 00:00:00 2001 From: Connor Tsui Date: Tue, 29 Jul 2025 11:10:17 +0200 Subject: [PATCH 0255/1061] add experimental `oneshot` channel The `oneshot` channel is gated under the `oneshot_channel` feature. Signed-off-by: Connor Tsui --- library/std/src/sync/mod.rs | 2 + library/std/src/sync/mpmc/mod.rs | 4 +- library/std/src/sync/mpsc.rs | 6 +- library/std/src/sync/oneshot.rs | 466 +++++++++++++++++++++++++++++++ 4 files changed, 474 insertions(+), 4 deletions(-) create mode 100644 library/std/src/sync/oneshot.rs diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs index 19b3040dcb27..5da50480c723 100644 --- a/library/std/src/sync/mod.rs +++ b/library/std/src/sync/mod.rs @@ -184,6 +184,8 @@ pub use alloc_crate::sync::{Arc, Weak}; #[unstable(feature = "mpmc_channel", issue = "126840")] pub mod mpmc; pub mod mpsc; +#[unstable(feature = "oneshot_channel", issue = "143674")] +pub mod oneshot; pub(crate) mod once; // `pub(crate)` for the `sys::sync::once` implementations and `LazyLock`. diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs index ee9795a52812..8df81a580f7b 100644 --- a/library/std/src/sync/mpmc/mod.rs +++ b/library/std/src/sync/mpmc/mod.rs @@ -654,7 +654,7 @@ impl Clone for Sender { #[unstable(feature = "mpmc_channel", issue = "126840")] impl fmt::Debug for Sender { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Sender { .. }") + f.debug_struct("Sender").finish_non_exhaustive() } } @@ -1380,7 +1380,7 @@ impl Clone for Receiver { #[unstable(feature = "mpmc_channel", issue = "126840")] impl fmt::Debug for Receiver { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Receiver { .. }") + f.debug_struct("Receiver").finish_non_exhaustive() } } diff --git a/library/std/src/sync/mpsc.rs b/library/std/src/sync/mpsc.rs index f91c26aa22cf..0ae23f6e13bf 100644 --- a/library/std/src/sync/mpsc.rs +++ b/library/std/src/sync/mpsc.rs @@ -1114,8 +1114,10 @@ impl error::Error for SendError {} impl fmt::Debug for TrySendError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - TrySendError::Full(..) => "Full(..)".fmt(f), - TrySendError::Disconnected(..) => "Disconnected(..)".fmt(f), + TrySendError::Full(..) => f.debug_tuple("TrySendError::Full").finish_non_exhaustive(), + TrySendError::Disconnected(..) => { + f.debug_tuple("TrySendError::Disconnected").finish_non_exhaustive() + } } } } diff --git a/library/std/src/sync/oneshot.rs b/library/std/src/sync/oneshot.rs new file mode 100644 index 000000000000..b2c9ba34c0ff --- /dev/null +++ b/library/std/src/sync/oneshot.rs @@ -0,0 +1,466 @@ +//! A single-producer, single-consumer (oneshot) channel. +//! +//! This is an experimental module, so the API will likely change. + +use crate::sync::mpmc; +use crate::sync::mpsc::{RecvError, SendError}; +use crate::time::{Duration, Instant}; +use crate::{error, fmt}; + +/// Creates a new oneshot channel, returning the sender/receiver halves. +/// +/// # Examples +/// +/// ``` +/// #![feature(oneshot_channel)] +/// use std::sync::oneshot; +/// use std::thread; +/// +/// let (sender, receiver) = oneshot::channel(); +/// +/// // Spawn off an expensive computation. +/// thread::spawn(move || { +/// # fn expensive_computation() -> i32 { 42 } +/// sender.send(expensive_computation()).unwrap(); +/// // `sender` is consumed by `send`, so we cannot use it anymore. +/// }); +/// +/// # fn do_other_work() -> i32 { 42 } +/// do_other_work(); +/// +/// // Let's see what that answer was... +/// println!("{:?}", receiver.recv().unwrap()); +/// // `receiver` is consumed by `recv`, so we cannot use it anymore. +/// ``` +#[must_use] +#[unstable(feature = "oneshot_channel", issue = "143674")] +pub fn channel() -> (Sender, Receiver) { + // Using a `sync_channel` with capacity 1 means that the internal implementation will use the + // `Array`-flavored channel implementation. + let (sender, receiver) = mpmc::sync_channel(1); + (Sender { inner: sender }, Receiver { inner: receiver }) +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Sender +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// The sending half of a oneshot channel. +/// +/// # Examples +/// +/// ``` +/// #![feature(oneshot_channel)] +/// use std::sync::oneshot; +/// use std::thread; +/// +/// let (sender, receiver) = oneshot::channel(); +/// +/// thread::spawn(move || { +/// sender.send("Hello from thread!").unwrap(); +/// }); +/// +/// assert_eq!(receiver.recv().unwrap(), "Hello from thread!"); +/// ``` +/// +/// `Sender` cannot be sent between threads if it is sending non-`Send` types. +/// +/// ```compile_fail +/// #![feature(oneshot_channel)] +/// use std::sync::oneshot; +/// use std::thread; +/// use std::ptr; +/// +/// let (sender, receiver) = oneshot::channel(); +/// +/// struct NotSend(*mut ()); +/// thread::spawn(move || { +/// sender.send(NotSend(ptr::null_mut())); +/// }); +/// +/// let reply = receiver.try_recv().unwrap(); +/// ``` +#[unstable(feature = "oneshot_channel", issue = "143674")] +pub struct Sender { + /// The `oneshot` channel is simply a wrapper around a `mpmc` channel. + inner: mpmc::Sender, +} + +// SAFETY: Since the only methods in which synchronization must occur take full ownership of the +// [`Sender`], it is perfectly safe to share a `&Sender` between threads (as it is effectively +// useless without ownership). +#[unstable(feature = "oneshot_channel", issue = "143674")] +unsafe impl Sync for Sender {} + +impl Sender { + /// Attempts to send a value through this channel. This can only fail if the corresponding + /// [`Receiver`] has been dropped. + /// + /// This method is non-blocking (wait-free). + /// + /// # Examples + /// + /// ``` + /// #![feature(oneshot_channel)] + /// use std::sync::oneshot; + /// use std::thread; + /// + /// let (tx, rx) = oneshot::channel(); + /// + /// thread::spawn(move || { + /// // Perform some computation. + /// let result = 2 + 2; + /// tx.send(result).unwrap(); + /// }); + /// + /// assert_eq!(rx.recv().unwrap(), 4); + /// ``` + #[unstable(feature = "oneshot_channel", issue = "143674")] + pub fn send(self, t: T) -> Result<(), SendError> { + self.inner.send(t) + } +} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl fmt::Debug for Sender { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Sender").finish_non_exhaustive() + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Receiver +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// The receiving half of a oneshot channel. +/// +/// # Examples +/// +/// ``` +/// #![feature(oneshot_channel)] +/// use std::sync::oneshot; +/// use std::thread; +/// use std::time::Duration; +/// +/// let (sender, receiver) = oneshot::channel(); +/// +/// thread::spawn(move || { +/// thread::sleep(Duration::from_millis(100)); +/// sender.send("Hello after delay!").unwrap(); +/// }); +/// +/// println!("Waiting for message..."); +/// println!("{}", receiver.recv().unwrap()); +/// ``` +/// +/// `Receiver` cannot be sent between threads if it is receiving non-`Send` types. +/// +/// ```compile_fail +/// # #![feature(oneshot_channel)] +/// # use std::sync::oneshot; +/// # use std::thread; +/// # use std::ptr; +/// # +/// let (sender, receiver) = oneshot::channel(); +/// +/// struct NotSend(*mut ()); +/// sender.send(NotSend(ptr::null_mut())); +/// +/// thread::spawn(move || { +/// let reply = receiver.try_recv().unwrap(); +/// }); +/// ``` +#[unstable(feature = "oneshot_channel", issue = "143674")] +pub struct Receiver { + /// The `oneshot` channel is simply a wrapper around a `mpmc` channel. + inner: mpmc::Receiver, +} + +// SAFETY: Since the only methods in which synchronization must occur take full ownership of the +// [`Receiver`], it is perfectly safe to share a `&Receiver` between threads (as it is unable to +// receive any values without ownership). +#[unstable(feature = "oneshot_channel", issue = "143674")] +unsafe impl Sync for Receiver {} + +impl Receiver { + /// Receives the value from the sending end, blocking the calling thread until it gets it. + /// + /// Can only fail if the corresponding [`Sender`] has been dropped. + /// + /// # Examples + /// + /// ``` + /// #![feature(oneshot_channel)] + /// use std::sync::oneshot; + /// use std::thread; + /// use std::time::Duration; + /// + /// let (tx, rx) = oneshot::channel(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_millis(500)); + /// tx.send("Done!").unwrap(); + /// }); + /// + /// // This will block until the message arrives. + /// println!("{}", rx.recv().unwrap()); + /// ``` + #[unstable(feature = "oneshot_channel", issue = "143674")] + pub fn recv(self) -> Result { + self.inner.recv() + } + + // Fallible methods. + + /// Attempts to return a pending value on this receiver without blocking. + /// + /// # Examples + /// + /// ``` + /// #![feature(oneshot_channel)] + /// use std::sync::oneshot; + /// use std::thread; + /// use std::time::Duration; + /// + /// let (sender, mut receiver) = oneshot::channel(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_millis(100)); + /// sender.send(42).unwrap(); + /// }); + /// + /// // Keep trying until we get the message, doing other work in the process. + /// loop { + /// match receiver.try_recv() { + /// Ok(value) => { + /// assert_eq!(value, 42); + /// break; + /// } + /// Err(oneshot::TryRecvError::Empty(rx)) => { + /// // Retake ownership of the receiver. + /// receiver = rx; + /// # fn do_other_work() { thread::sleep(Duration::from_millis(25)); } + /// do_other_work(); + /// } + /// Err(oneshot::TryRecvError::Disconnected) => panic!("Sender disconnected"), + /// } + /// } + /// ``` + #[unstable(feature = "oneshot_channel", issue = "143674")] + pub fn try_recv(self) -> Result> { + self.inner.try_recv().map_err(|err| match err { + mpmc::TryRecvError::Empty => TryRecvError::Empty(self), + mpmc::TryRecvError::Disconnected => TryRecvError::Disconnected, + }) + } + + /// Attempts to wait for a value on this receiver, returning an error if the corresponding + /// [`Sender`] half of this channel has been dropped, or if it waits more than `timeout`. + /// + /// # Examples + /// + /// ``` + /// #![feature(oneshot_channel)] + /// use std::sync::oneshot; + /// use std::thread; + /// use std::time::Duration; + /// + /// let (sender, receiver) = oneshot::channel(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_millis(500)); + /// sender.send("Success!").unwrap(); + /// }); + /// + /// // Wait up to 1 second for the message + /// match receiver.recv_timeout(Duration::from_secs(1)) { + /// Ok(msg) => println!("Received: {}", msg), + /// Err(oneshot::RecvTimeoutError::Timeout(_)) => println!("Timed out!"), + /// Err(oneshot::RecvTimeoutError::Disconnected) => println!("Sender dropped!"), + /// } + /// ``` + #[unstable(feature = "oneshot_channel", issue = "143674")] + pub fn recv_timeout(self, timeout: Duration) -> Result> { + self.inner.recv_timeout(timeout).map_err(|err| match err { + mpmc::RecvTimeoutError::Timeout => RecvTimeoutError::Timeout(self), + mpmc::RecvTimeoutError::Disconnected => RecvTimeoutError::Disconnected, + }) + } + + /// Attempts to wait for a value on this receiver, returning an error if the corresponding + /// [`Sender`] half of this channel has been dropped, or if `deadline` is reached. + /// + /// # Examples + /// + /// ``` + /// #![feature(oneshot_channel)] + /// use std::sync::oneshot; + /// use std::thread; + /// use std::time::{Duration, Instant}; + /// + /// let (sender, receiver) = oneshot::channel(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_millis(100)); + /// sender.send("Just in time!").unwrap(); + /// }); + /// + /// let deadline = Instant::now() + Duration::from_millis(500); + /// match receiver.recv_deadline(deadline) { + /// Ok(msg) => println!("Received: {}", msg), + /// Err(oneshot::RecvTimeoutError::Timeout(_)) => println!("Missed deadline!"), + /// Err(oneshot::RecvTimeoutError::Disconnected) => println!("Sender dropped!"), + /// } + /// ``` + #[unstable(feature = "oneshot_channel", issue = "143674")] + pub fn recv_deadline(self, deadline: Instant) -> Result> { + self.inner.recv_deadline(deadline).map_err(|err| match err { + mpmc::RecvTimeoutError::Timeout => RecvTimeoutError::Timeout(self), + mpmc::RecvTimeoutError::Disconnected => RecvTimeoutError::Disconnected, + }) + } +} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl fmt::Debug for Receiver { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Receiver").finish_non_exhaustive() + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Receiver Errors +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// An error returned from the [`try_recv`](Receiver::try_recv) method. +/// +/// See the documentation for [`try_recv`] for more information on how to use this error. +/// +/// [`try_recv`]: Receiver::try_recv +#[unstable(feature = "oneshot_channel", issue = "143674")] +pub enum TryRecvError { + /// The [`Sender`] has not sent a message yet, but it might in the future (as it has not yet + /// disconnected). This variant contains the [`Receiver`] that [`try_recv`](Receiver::try_recv) + /// took ownership over. + Empty(Receiver), + /// The corresponding [`Sender`] half of this channel has become disconnected, and there will + /// never be any more data sent over the channel. + Disconnected, +} + +/// An error returned from the [`recv_timeout`](Receiver::recv_timeout) or +/// [`recv_deadline`](Receiver::recv_deadline) methods. +/// +/// # Examples +/// +/// Usage of this error is similar to [`TryRecvError`]. +/// +/// ``` +/// #![feature(oneshot_channel)] +/// use std::sync::oneshot::{self, RecvTimeoutError}; +/// use std::thread; +/// use std::time::Duration; +/// +/// let (sender, receiver) = oneshot::channel(); +/// +/// let send_failure = thread::spawn(move || { +/// // Simulate a long computation that takes longer than our timeout. +/// thread::sleep(Duration::from_millis(250)); +/// +/// // This will likely fail to send because we drop the receiver in the main thread. +/// sender.send("Goodbye!".to_string()).unwrap(); +/// }); +/// +/// // Try to receive the message with a short timeout. +/// match receiver.recv_timeout(Duration::from_millis(10)) { +/// Ok(msg) => println!("Received: {}", msg), +/// Err(RecvTimeoutError::Timeout(rx)) => { +/// println!("Timed out waiting for message!"); +/// +/// // Note that you can reuse the receiver without dropping it. +/// drop(rx); +/// }, +/// Err(RecvTimeoutError::Disconnected) => println!("Sender dropped!"), +/// } +/// +/// send_failure.join().unwrap_err(); +/// ``` +#[unstable(feature = "oneshot_channel", issue = "143674")] +pub enum RecvTimeoutError { + /// The [`Sender`] has not sent a message yet, but it might in the future (as it has not yet + /// disconnected). This variant contains the [`Receiver`] that either + /// [`recv_timeout`](Receiver::recv_timeout) or [`recv_deadline`](Receiver::recv_deadline) took + /// ownership over. + Timeout(Receiver), + /// The corresponding [`Sender`] half of this channel has become disconnected, and there will + /// never be any more data sent over the channel. + Disconnected, +} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl fmt::Debug for TryRecvError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("TryRecvError").finish_non_exhaustive() + } +} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl fmt::Display for TryRecvError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + TryRecvError::Empty(..) => "receiving on an empty oneshot channel".fmt(f), + TryRecvError::Disconnected => "receiving on a closed oneshot channel".fmt(f), + } + } +} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl error::Error for TryRecvError {} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl From for TryRecvError { + /// Converts a `RecvError` into a `TryRecvError`. + /// + /// This conversion always returns `TryRecvError::Disconnected`. + /// + /// No data is allocated on the heap. + fn from(err: RecvError) -> TryRecvError { + match err { + RecvError => TryRecvError::Disconnected, + } + } +} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl fmt::Debug for RecvTimeoutError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("RecvTimeoutError").finish_non_exhaustive() + } +} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl fmt::Display for RecvTimeoutError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + RecvTimeoutError::Timeout(..) => "timed out waiting on oneshot channel".fmt(f), + RecvTimeoutError::Disconnected => "receiving on a closed oneshot channel".fmt(f), + } + } +} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl error::Error for RecvTimeoutError {} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl From for RecvTimeoutError { + /// Converts a `RecvError` into a `RecvTimeoutError`. + /// + /// This conversion always returns `RecvTimeoutError::Disconnected`. + /// + /// No data is allocated on the heap. + fn from(err: RecvError) -> RecvTimeoutError { + match err { + RecvError => RecvTimeoutError::Disconnected, + } + } +} From b481ecd8b51eba60c7223cef2453a0a9d4c554c0 Mon Sep 17 00:00:00 2001 From: Connor Tsui Date: Tue, 29 Jul 2025 11:11:18 +0200 Subject: [PATCH 0256/1061] add `oneshot` tests Tests inspired by tests in the `oneshot` third-party crate. --- library/std/tests/sync/lib.rs | 3 + library/std/tests/sync/oneshot.rs | 342 ++++++++++++++++++++++++++++++ 2 files changed, 345 insertions(+) create mode 100644 library/std/tests/sync/oneshot.rs diff --git a/library/std/tests/sync/lib.rs b/library/std/tests/sync/lib.rs index 7ade9f623147..32a7efde2a25 100644 --- a/library/std/tests/sync/lib.rs +++ b/library/std/tests/sync/lib.rs @@ -1,5 +1,6 @@ #![feature(mapped_lock_guards)] #![feature(mpmc_channel)] +#![feature(oneshot_channel)] #![feature(once_cell_try)] #![feature(lock_value_accessors)] #![feature(reentrant_lock)] @@ -26,6 +27,8 @@ mod mutex; mod once; mod once_lock; #[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] +mod oneshot; +#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] mod reentrant_lock; #[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] mod rwlock; diff --git a/library/std/tests/sync/oneshot.rs b/library/std/tests/sync/oneshot.rs new file mode 100644 index 000000000000..6a87c72b9cb5 --- /dev/null +++ b/library/std/tests/sync/oneshot.rs @@ -0,0 +1,342 @@ +//! Inspired by tests from + +use std::sync::mpsc::RecvError; +use std::sync::oneshot; +use std::sync::oneshot::{RecvTimeoutError, TryRecvError}; +use std::time::{Duration, Instant}; +use std::{mem, thread}; + +#[test] +fn send_before_try_recv() { + let (sender, receiver) = oneshot::channel(); + + assert!(sender.send(19i128).is_ok()); + + match receiver.try_recv() { + Ok(19) => {} + _ => panic!("expected Ok(19)"), + } +} + +#[test] +fn send_before_recv() { + let (sender, receiver) = oneshot::channel::<()>(); + + assert!(sender.send(()).is_ok()); + assert_eq!(receiver.recv(), Ok(())); + + let (sender, receiver) = oneshot::channel::(); + + assert!(sender.send(42).is_ok()); + assert_eq!(receiver.recv(), Ok(42)); + + let (sender, receiver) = oneshot::channel::<[u8; 4096]>(); + + assert!(sender.send([0b10101010; 4096]).is_ok()); + assert!(receiver.recv().unwrap()[..] == [0b10101010; 4096][..]); +} + +#[test] +fn sender_drop() { + { + let (sender, receiver) = oneshot::channel::(); + + mem::drop(sender); + + match receiver.recv() { + Err(RecvError) => {} + _ => panic!("expected recv error"), + } + } + + { + let (sender, receiver) = oneshot::channel::(); + + mem::drop(sender); + + match receiver.try_recv() { + Err(TryRecvError::Disconnected) => {} + _ => panic!("expected disconnected error"), + } + } + { + let (sender, receiver) = oneshot::channel::(); + + mem::drop(sender); + + match receiver.recv_timeout(Duration::from_secs(1)) { + Err(RecvTimeoutError::Disconnected) => {} + _ => panic!("expected disconnected error"), + } + } +} + +#[test] +fn send_never_deadline() { + let (sender, receiver) = oneshot::channel::(); + + mem::drop(sender); + + match receiver.recv_deadline(Instant::now()) { + Err(RecvTimeoutError::Disconnected) => {} + _ => panic!("expected disconnected error"), + } +} + +#[test] +fn send_before_recv_timeout() { + let (sender, receiver) = oneshot::channel(); + + assert!(sender.send(22i128).is_ok()); + + let start = Instant::now(); + + let timeout = Duration::from_secs(1); + match receiver.recv_timeout(timeout) { + Ok(22) => {} + _ => panic!("expected Ok(22)"), + } + + assert!(start.elapsed() < timeout); +} + +#[test] +fn send_error() { + let (sender, receiver) = oneshot::channel(); + + mem::drop(receiver); + + let send_error = sender.send(32u128).unwrap_err(); + assert_eq!(send_error.0, 32); +} + +#[test] +fn recv_before_send() { + let (sender, receiver) = oneshot::channel(); + + let t1 = thread::spawn(move || { + thread::sleep(Duration::from_millis(10)); + sender.send(9u128).unwrap(); + }); + let t2 = thread::spawn(move || { + assert_eq!(receiver.recv(), Ok(9)); + }); + + t1.join().unwrap(); + t2.join().unwrap(); +} + +#[test] +fn recv_timeout_before_send() { + let (sender, receiver) = oneshot::channel(); + + let t = thread::spawn(move || { + thread::sleep(Duration::from_millis(100)); + sender.send(99u128).unwrap(); + }); + + match receiver.recv_timeout(Duration::from_secs(1)) { + Ok(99) => {} + _ => panic!("expected Ok(99)"), + } + + t.join().unwrap(); +} + +#[test] +fn recv_then_drop_sender() { + let (sender, receiver) = oneshot::channel::(); + + let t1 = thread::spawn(move || match receiver.recv() { + Err(RecvError) => {} + _ => panic!("expected recv error"), + }); + + let t2 = thread::spawn(move || { + thread::sleep(Duration::from_millis(10)); + mem::drop(sender); + }); + + t1.join().unwrap(); + t2.join().unwrap(); +} + +#[test] +fn drop_sender_then_recv() { + let (sender, receiver) = oneshot::channel::(); + + let t1 = thread::spawn(move || { + thread::sleep(Duration::from_millis(10)); + mem::drop(sender); + }); + + let t2 = thread::spawn(move || match receiver.recv() { + Err(RecvError) => {} + _ => panic!("expected disconnected error"), + }); + + t1.join().unwrap(); + t2.join().unwrap(); +} + +#[test] +fn try_recv_empty() { + let (sender, receiver) = oneshot::channel::(); + match receiver.try_recv() { + Err(TryRecvError::Empty(_)) => {} + _ => panic!("expected empty error"), + } + mem::drop(sender); +} + +#[test] +fn try_recv_then_drop_receiver() { + let (sender, receiver) = oneshot::channel::(); + + let t1 = thread::spawn(move || { + thread::sleep(Duration::from_millis(100)); + let _ = sender.send(42); + }); + + let t2 = thread::spawn(move || match receiver.try_recv() { + Ok(_) => {} + Err(TryRecvError::Empty(r)) => { + mem::drop(r); + } + Err(TryRecvError::Disconnected) => {} + }); + + t2.join().unwrap(); + t1.join().unwrap(); +} + +#[test] +fn recv_no_time() { + let (_sender, receiver) = oneshot::channel::(); + + let start = Instant::now(); + match receiver.recv_deadline(start) { + Err(RecvTimeoutError::Timeout(_)) => {} + _ => panic!("expected timeout error"), + } + + let (_sender, receiver) = oneshot::channel::(); + match receiver.recv_timeout(Duration::from_millis(0)) { + Err(RecvTimeoutError::Timeout(_)) => {} + _ => panic!("expected timeout error"), + } +} + +#[test] +fn recv_deadline_passed() { + let (_sender, receiver) = oneshot::channel::(); + + let start = Instant::now(); + let timeout = Duration::from_millis(100); + + match receiver.recv_deadline(start + timeout) { + Err(RecvTimeoutError::Timeout(_)) => {} + _ => panic!("expected timeout error"), + } + + assert!(start.elapsed() >= timeout); + assert!(start.elapsed() < timeout * 3); +} + +#[test] +fn recv_time_passed() { + let (_sender, receiver) = oneshot::channel::(); + + let start = Instant::now(); + let timeout = Duration::from_millis(100); + match receiver.recv_timeout(timeout) { + Err(RecvTimeoutError::Timeout(_)) => {} + _ => panic!("expected timeout error"), + } + assert!(start.elapsed() >= timeout); + assert!(start.elapsed() < timeout * 3); +} + +#[test] +fn non_send_type_can_be_used_on_same_thread() { + use std::ptr; + + #[derive(Debug, Eq, PartialEq)] + struct NotSend(*mut ()); + + let (sender, receiver) = oneshot::channel(); + sender.send(NotSend(ptr::null_mut())).unwrap(); + let reply = receiver.try_recv().unwrap(); + assert_eq!(reply, NotSend(ptr::null_mut())); +} + +/// Helper for testing drop behavior (taken directly from the `oneshot` crate). +struct DropCounter { + count: std::rc::Rc>, +} + +impl DropCounter { + fn new() -> (DropTracker, DropCounter) { + let count = std::rc::Rc::new(std::cell::RefCell::new(0)); + (DropTracker { count: count.clone() }, DropCounter { count }) + } + + fn count(&self) -> usize { + *self.count.borrow() + } +} + +struct DropTracker { + count: std::rc::Rc>, +} + +impl Drop for DropTracker { + fn drop(&mut self) { + *self.count.borrow_mut() += 1; + } +} + +#[test] +fn message_in_channel_dropped_on_receiver_drop() { + let (sender, receiver) = oneshot::channel(); + + let (message, counter) = DropCounter::new(); + assert_eq!(counter.count(), 0); + + sender.send(message).unwrap(); + assert_eq!(counter.count(), 0); + + mem::drop(receiver); + assert_eq!(counter.count(), 1); +} + +#[test] +fn send_error_drops_message_correctly() { + let (sender, receiver) = oneshot::channel(); + mem::drop(receiver); + + let (message, counter) = DropCounter::new(); + + let send_error = sender.send(message).unwrap_err(); + assert_eq!(counter.count(), 0); + + mem::drop(send_error); + assert_eq!(counter.count(), 1); +} + +#[test] +fn send_error_drops_message_correctly_on_extract() { + let (sender, receiver) = oneshot::channel(); + mem::drop(receiver); + + let (message, counter) = DropCounter::new(); + + let send_error = sender.send(message).unwrap_err(); + assert_eq!(counter.count(), 0); + + let message = send_error.0; // Access the inner value directly + assert_eq!(counter.count(), 0); + + mem::drop(message); + assert_eq!(counter.count(), 1); +} From 3f1dd92cc7e5c97b54b58e70ad9d904ce08e372c Mon Sep 17 00:00:00 2001 From: "U. Lasiotus" Date: Sun, 4 Jan 2026 16:55:57 -0800 Subject: [PATCH 0257/1061] Motor OS: fix compile error PR https://github.com/rust-lang/rust/pull/146341 introduced a compilation error. This fixes it. --- library/std/src/sys/fs/motor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/fs/motor.rs b/library/std/src/sys/fs/motor.rs index 8f3336e2fa96..2ae01db24be5 100644 --- a/library/std/src/sys/fs/motor.rs +++ b/library/std/src/sys/fs/motor.rs @@ -4,7 +4,7 @@ use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::path::{Path, PathBuf}; use crate::sys::fd::FileDesc; -pub use crate::sys::fs::common::exists; +pub use crate::sys::fs::common::{Dir, exists}; use crate::sys::time::SystemTime; use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner, map_motor_error, unsupported}; From 5c5c1ff6dbe84e1d9eddd158116f6e40b941ed03 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 25 Dec 2025 23:29:35 +0900 Subject: [PATCH 0258/1061] moved some test delete tests/ui/issues/issue-22426.rs duplicated of tests/ui/match/guards.rs --- .../associated-type-const-nomalization.rs} | 0 .../ui/{issues/issue-2428.rs => cast/cast-enum-const.rs} | 0 .../ui/{issues/issue-22403.rs => cast/cast-to-box-arr.rs} | 0 .../issue-41998.rs => cast/cast-to-char-compare.rs} | 0 .../const-static-ref-to-closure.rs} | 0 .../derive-debug-generic-with-lifetime.rs} | 0 .../derive-debug-newtype-unsized-slice.rs} | 0 .../call-unit-struct-impl-fn-once.rs} | 0 .../fn-trait-explicit-call.rs} | 0 tests/ui/issues/issue-22426.rs | 8 -------- tests/ui/{issues => resolve}/auxiliary/i8.rs | 0 .../const-iter-no-conflict-for-loop.rs} | 0 .../issue-20427.rs => resolve/shadow-primitives.rs} | 0 .../self-in-method-body-resolves.rs} | 0 .../bound/recursive-trait-bound-on-type-param.rs} | 0 .../tuple-ref-order-distinct-impls.rs} | 0 .../issue-20676.rs => ufcs/ufcs-trait-object-format.rs} | 0 17 files changed, 8 deletions(-) rename tests/ui/{issues/issue-26614.rs => associated-types/associated-type-const-nomalization.rs} (100%) rename tests/ui/{issues/issue-2428.rs => cast/cast-enum-const.rs} (100%) rename tests/ui/{issues/issue-22403.rs => cast/cast-to-box-arr.rs} (100%) rename tests/ui/{issues/issue-41998.rs => cast/cast-to-char-compare.rs} (100%) rename tests/ui/{issues/issue-25180.rs => consts/const-static-ref-to-closure.rs} (100%) rename tests/ui/{issues/issue-29030.rs => derives/derive-debug-generic-with-lifetime.rs} (100%) rename tests/ui/{issues/issue-25394.rs => derives/derive-debug-newtype-unsized-slice.rs} (100%) rename tests/ui/{issues/issue-33687.rs => fn_traits/call-unit-struct-impl-fn-once.rs} (100%) rename tests/ui/{issues/issue-20847.rs => fn_traits/fn-trait-explicit-call.rs} (100%) delete mode 100644 tests/ui/issues/issue-22426.rs rename tests/ui/{issues => resolve}/auxiliary/i8.rs (100%) rename tests/ui/{issues/issue-27639.rs => resolve/const-iter-no-conflict-for-loop.rs} (100%) rename tests/ui/{issues/issue-20427.rs => resolve/shadow-primitives.rs} (100%) rename tests/ui/{issues/issue-24389.rs => self/self-in-method-body-resolves.rs} (100%) rename tests/ui/{issues/issue-19601.rs => traits/bound/recursive-trait-bound-on-type-param.rs} (100%) rename tests/ui/{issues/issue-11384.rs => typeck/tuple-ref-order-distinct-impls.rs} (100%) rename tests/ui/{issues/issue-20676.rs => ufcs/ufcs-trait-object-format.rs} (100%) diff --git a/tests/ui/issues/issue-26614.rs b/tests/ui/associated-types/associated-type-const-nomalization.rs similarity index 100% rename from tests/ui/issues/issue-26614.rs rename to tests/ui/associated-types/associated-type-const-nomalization.rs diff --git a/tests/ui/issues/issue-2428.rs b/tests/ui/cast/cast-enum-const.rs similarity index 100% rename from tests/ui/issues/issue-2428.rs rename to tests/ui/cast/cast-enum-const.rs diff --git a/tests/ui/issues/issue-22403.rs b/tests/ui/cast/cast-to-box-arr.rs similarity index 100% rename from tests/ui/issues/issue-22403.rs rename to tests/ui/cast/cast-to-box-arr.rs diff --git a/tests/ui/issues/issue-41998.rs b/tests/ui/cast/cast-to-char-compare.rs similarity index 100% rename from tests/ui/issues/issue-41998.rs rename to tests/ui/cast/cast-to-char-compare.rs diff --git a/tests/ui/issues/issue-25180.rs b/tests/ui/consts/const-static-ref-to-closure.rs similarity index 100% rename from tests/ui/issues/issue-25180.rs rename to tests/ui/consts/const-static-ref-to-closure.rs diff --git a/tests/ui/issues/issue-29030.rs b/tests/ui/derives/derive-debug-generic-with-lifetime.rs similarity index 100% rename from tests/ui/issues/issue-29030.rs rename to tests/ui/derives/derive-debug-generic-with-lifetime.rs diff --git a/tests/ui/issues/issue-25394.rs b/tests/ui/derives/derive-debug-newtype-unsized-slice.rs similarity index 100% rename from tests/ui/issues/issue-25394.rs rename to tests/ui/derives/derive-debug-newtype-unsized-slice.rs diff --git a/tests/ui/issues/issue-33687.rs b/tests/ui/fn_traits/call-unit-struct-impl-fn-once.rs similarity index 100% rename from tests/ui/issues/issue-33687.rs rename to tests/ui/fn_traits/call-unit-struct-impl-fn-once.rs diff --git a/tests/ui/issues/issue-20847.rs b/tests/ui/fn_traits/fn-trait-explicit-call.rs similarity index 100% rename from tests/ui/issues/issue-20847.rs rename to tests/ui/fn_traits/fn-trait-explicit-call.rs diff --git a/tests/ui/issues/issue-22426.rs b/tests/ui/issues/issue-22426.rs deleted file mode 100644 index 0857ac9dfb4d..000000000000 --- a/tests/ui/issues/issue-22426.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ run-pass - -fn main() { - match 42 { - x if x < 7 => (), - _ => () - } -} diff --git a/tests/ui/issues/auxiliary/i8.rs b/tests/ui/resolve/auxiliary/i8.rs similarity index 100% rename from tests/ui/issues/auxiliary/i8.rs rename to tests/ui/resolve/auxiliary/i8.rs diff --git a/tests/ui/issues/issue-27639.rs b/tests/ui/resolve/const-iter-no-conflict-for-loop.rs similarity index 100% rename from tests/ui/issues/issue-27639.rs rename to tests/ui/resolve/const-iter-no-conflict-for-loop.rs diff --git a/tests/ui/issues/issue-20427.rs b/tests/ui/resolve/shadow-primitives.rs similarity index 100% rename from tests/ui/issues/issue-20427.rs rename to tests/ui/resolve/shadow-primitives.rs diff --git a/tests/ui/issues/issue-24389.rs b/tests/ui/self/self-in-method-body-resolves.rs similarity index 100% rename from tests/ui/issues/issue-24389.rs rename to tests/ui/self/self-in-method-body-resolves.rs diff --git a/tests/ui/issues/issue-19601.rs b/tests/ui/traits/bound/recursive-trait-bound-on-type-param.rs similarity index 100% rename from tests/ui/issues/issue-19601.rs rename to tests/ui/traits/bound/recursive-trait-bound-on-type-param.rs diff --git a/tests/ui/issues/issue-11384.rs b/tests/ui/typeck/tuple-ref-order-distinct-impls.rs similarity index 100% rename from tests/ui/issues/issue-11384.rs rename to tests/ui/typeck/tuple-ref-order-distinct-impls.rs diff --git a/tests/ui/issues/issue-20676.rs b/tests/ui/ufcs/ufcs-trait-object-format.rs similarity index 100% rename from tests/ui/issues/issue-20676.rs rename to tests/ui/ufcs/ufcs-trait-object-format.rs From 442127051669be574107571773c669006413dedf Mon Sep 17 00:00:00 2001 From: AprilNEA Date: Sat, 3 Jan 2026 16:24:56 +0800 Subject: [PATCH 0259/1061] Merge `associated_const_equality` feature gate into MGCA This removes `associated_const_equality` as a separate feature gate and makes it part of `min_generic_const_args` (mgca). Key changes: - Remove `associated_const_equality` from unstable features, add to removed - Update all test files to use `min_generic_const_args` instead - Preserve the original "associated const equality is incomplete" error message by specially handling `sym::associated_const_equality` spans in `feature_gate.rs` - Rename FIXME(associated_const_equality) to FIXME(mgca) --- compiler/rustc_ast_passes/src/feature_gate.rs | 18 +++++- .../src/debuginfo/type_names.rs | 2 +- compiler/rustc_feature/src/removed.rs | 3 + compiler/rustc_feature/src/unstable.rs | 2 - .../src/hir_ty_lowering/bounds.rs | 4 +- .../src/hir_ty_lowering/dyn_trait.rs | 2 +- .../src/hir_ty_lowering/errors.rs | 4 +- compiler/rustc_middle/src/ty/context.rs | 4 -- .../src/solve/assembly/structural_traits.rs | 2 +- compiler/rustc_type_ir/src/inherent.rs | 2 - ...duplication_in_bounds_assoc_const_eq.fixed | 2 +- ...it_duplication_in_bounds_assoc_const_eq.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/lower.rs | 2 +- tests/crashes/mgca/ace-with-const-ctor.rs | 2 +- .../associated-constant-not-allowed-102467.rs | 2 +- .../auxiliary/assoc-const-equality.rs | 2 +- .../assoc-const-eq-ambiguity.rs | 2 +- .../assoc-const-eq-bound-var-in-ty-not-wf.rs | 1 - ...soc-const-eq-bound-var-in-ty-not-wf.stderr | 4 +- .../assoc-const-eq-bound-var-in-ty.rs | 1 - ...oc-const-eq-const_evaluatable_unchecked.rs | 2 +- .../assoc-const-eq-esc-bound-var-in-ty.rs | 1 - .../assoc-const-eq-esc-bound-var-in-ty.stderr | 2 +- .../assoc-const-eq-missing.rs | 4 +- .../assoc-const-eq-param-in-ty.rs | 1 - .../assoc-const-eq-param-in-ty.stderr | 22 +++---- .../assoc-const-eq-supertraits.rs | 1 - .../assoc-const-eq-ty-alias-noninteracting.rs | 2 +- .../assoc-const-ty-mismatch.rs | 4 +- tests/ui/associated-consts/assoc-const.rs | 2 +- .../equality-unused-issue-126729.rs | 2 +- .../associated-consts/issue-102335-const.rs | 2 +- .../ui/associated-consts/issue-105330.stderr | 8 +-- tests/ui/associated-consts/issue-110933.rs | 2 +- tests/ui/associated-consts/issue-93835.rs | 4 +- tests/ui/associated-consts/issue-93835.stderr | 8 +-- .../projection-unspecified-but-bounded.rs | 2 +- .../const-projection-err.rs | 2 +- .../duplicate-bound-err.rs | 1 - .../duplicate-bound-err.stderr | 64 +++++++++---------- .../associated-type-bounds/duplicate-bound.rs | 2 +- .../associated-type-bounds/issue-99828.stderr | 4 +- .../associated-types-eq-2.stderr | 16 ++--- .../assoc_const_eq_diagnostic.rs | 3 +- .../assoc_const_eq_diagnostic.stderr | 16 ++--- .../associated_const_equality/coherence.rs | 2 +- .../equality_bound_with_infer.rs | 2 +- ...with-generic-in-ace-no-feature-gate.stderr | 20 +++--- .../mismatched-types-with-generic-in-ace.rs | 2 +- .../unconstrained_impl_param.stderr | 4 +- .../mgca/explicit_anon_consts.rs | 2 +- .../explicit_anon_consts_literals_hack.rs | 2 +- .../mgca/type_const-only-in-impl.rs | 2 +- .../mgca/type_const-only-in-trait.rs | 2 +- .../mgca/using-fnptr-as-type_const.rs | 2 +- .../issue-89013-no-kw.stderr | 4 +- .../parser-error-recovery/issue-89013.stderr | 4 +- .../feature-gate-associated_const_equality.rs | 2 +- ...ture-gate-associated_const_equality.stderr | 4 +- .../assoc-const-no-infer-ice-115806.rs | 2 +- .../associated-const-equality.rs | 2 +- .../no-name-for-DefPath-issue-133426.stderr | 4 +- .../recover-assoc-const-constraint.stderr | 8 +-- .../overlap-due-to-unsatisfied-const-bound.rs | 2 +- ...rlap-due-to-unsatisfied-const-bound.stderr | 12 ++-- .../dont-ice-on-assoc-projection.stderr | 4 +- 66 files changed, 166 insertions(+), 162 deletions(-) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index dbbd3906b525..f2fdd1b0eb8b 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -505,7 +505,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { half_open_range_patterns_in_slices, "half-open range patterns in slices are unstable" ); - gate_all!(associated_const_equality, "associated const equality is incomplete"); gate_all!(yeet_expr, "`do yeet` expression is experimental"); gate_all!(const_closures, "const closures are experimental"); gate_all!(builtin_syntax, "`builtin #` syntax is unstable"); @@ -518,6 +517,23 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(postfix_match, "postfix match is experimental"); gate_all!(mut_ref, "mutable by-reference bindings are experimental"); gate_all!(min_generic_const_args, "unbraced const blocks as const args are experimental"); + // associated_const_equality is stabilized as part of min_generic_const_args + if let Some(spans) = spans.get(&sym::associated_const_equality) { + for span in spans { + if !visitor.features.min_generic_const_args() + && !span.allows_unstable(sym::min_generic_const_args) + { + #[allow(rustc::untranslatable_diagnostic)] + feature_err( + &visitor.sess, + sym::min_generic_const_args, + *span, + "associated const equality is incomplete", + ) + .emit(); + } + } + } gate_all!(global_registration, "global registration is experimental"); gate_all!(return_type_notation, "return type notation is experimental"); gate_all!(pin_ergonomics, "pinned reference syntax is experimental"); diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 18279a4d05fe..02476a332252 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -260,7 +260,7 @@ fn push_debuginfo_type_name<'tcx>( .map(|bound| { let ExistentialProjection { def_id: item_def_id, term, .. } = tcx.instantiate_bound_regions_with_erased(bound); - // FIXME(associated_const_equality): allow for consts here + // FIXME(mgca): allow for consts here (item_def_id, term.expect_type()) }) .collect(); diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 9d8a84c52e98..6aaf4542260c 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -60,6 +60,9 @@ declare_features! ( (removed, allocator, "1.0.0", None, None), /// Allows a test to fail without failing the whole suite. (removed, allow_fail, "1.60.0", Some(46488), Some("removed due to no clear use cases"), 93416), + /// Allows users to enforce equality of associated constants `TraitImpl`. + (removed, associated_const_equality, "CURRENT_RUSTC_VERSION", Some(92827), + Some("merged into `min_generic_const_args`")), (removed, await_macro, "1.38.0", Some(50547), Some("subsumed by `.await` syntax"), 62293), /// Allows using the `box $expr` syntax. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index f64702fc44b0..387a01967ae5 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -363,8 +363,6 @@ declare_features! ( (unstable, asm_goto_with_outputs, "1.85.0", Some(119364)), /// Allows the `may_unwind` option in inline assembly. (unstable, asm_unwind, "1.58.0", Some(93334)), - /// Allows users to enforce equality of associated constants `TraitImpl`. - (unstable, associated_const_equality, "1.58.0", Some(92827)), /// Allows associated type defaults. (unstable, associated_type_defaults, "1.2.0", Some(29661)), /// Allows implementing `AsyncDrop`. diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 555ef5c45e12..9ae6a9fac504 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -610,9 +610,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { AttributeKind::TypeConst(_) ) { - if tcx.features().min_generic_const_args() - || tcx.features().associated_const_equality() - { + if tcx.features().min_generic_const_args() { let mut err = self.dcx().struct_span_err( constraint.span, "use of trait associated const without `#[type_const]`", diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index 15d7da3a0070..edb79592e6c5 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -239,7 +239,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // `trait_object_dummy_self`, so check for that. let references_self = match pred.skip_binder().term.kind() { ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()), - // FIXME(associated_const_equality): We should walk the const instead of not doing anything + // FIXME(mgca): We should walk the const instead of not doing anything ty::TermKind::Const(_) => false, }; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 5fc201db68e5..51c664921804 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -359,12 +359,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { None }; - // FIXME(associated_const_equality): This has quite a few false positives and negatives. + // FIXME(mgca): This has quite a few false positives and negatives. let wrap_in_braces_sugg = if let Some(constraint) = constraint && let Some(hir_ty) = constraint.ty() && let ty = self.lower_ty(hir_ty) && (ty.is_enum() || ty.references_error()) - && tcx.features().associated_const_equality() + && tcx.features().min_generic_const_args() { Some(errors::AssocKindMismatchWrapInBracesSugg { lo: hir_ty.span.shrink_to_lo(), diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 25cc739f5ff9..a2f4714d1b2c 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -907,10 +907,6 @@ impl<'tcx> rustc_type_ir::inherent::Features> for &'tcx rustc_featu self.coroutine_clone() } - fn associated_const_equality(self) -> bool { - self.associated_const_equality() - } - fn feature_bound_holds_in_crate(self, symbol: Symbol) -> bool { // We don't consider feature bounds to hold in the crate when `staged_api` feature is // enabled, even if it is enabled through `#[feature]`. diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 2f6ff12e1e8d..05ea217c1de0 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -868,7 +868,7 @@ where .map(|(pred, _)| pred), )); - // FIXME(associated_const_equality): Also add associated consts to + // FIXME(mgca): Also add associated consts to // the requirements here. for associated_type_def_id in cx.associated_type_def_ids(trait_ref.def_id) { // associated types that require `Self: Sized` do not show up in the built-in diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 16f837141e97..4323b1ca6469 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -646,8 +646,6 @@ pub trait Features: Copy { fn coroutine_clone(self) -> bool; - fn associated_const_equality(self) -> bool; - fn feature_bound_holds_in_crate(self, symbol: I::Symbol) -> bool; } diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds_assoc_const_eq.fixed b/src/tools/clippy/tests/ui/trait_duplication_in_bounds_assoc_const_eq.fixed index f2bd306a99e4..f8be3331317c 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds_assoc_const_eq.fixed +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds_assoc_const_eq.fixed @@ -1,6 +1,6 @@ #![deny(clippy::trait_duplication_in_bounds)] #![expect(incomplete_features)] -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] trait AssocConstTrait { #[type_const] diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds_assoc_const_eq.rs b/src/tools/clippy/tests/ui/trait_duplication_in_bounds_assoc_const_eq.rs index 8e7d843a44c0..a0d7a653993f 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds_assoc_const_eq.rs +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds_assoc_const_eq.rs @@ -1,6 +1,6 @@ #![deny(clippy::trait_duplication_in_bounds)] #![expect(incomplete_features)] -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] trait AssocConstTrait { #[type_const] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index 9307868f3982..6c224f875d3a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -862,7 +862,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { TermKind::Ty(ty) => { ty.walk().any(|arg| arg == dummy_self_ty.into()) } - // FIXME(associated_const_equality): We should walk the const instead of not doing anything + // FIXME(mgca): We should walk the const instead of not doing anything TermKind::Const(_) => false, }; diff --git a/tests/crashes/mgca/ace-with-const-ctor.rs b/tests/crashes/mgca/ace-with-const-ctor.rs index 9e49bca06d52..28e85f37de1f 100644 --- a/tests/crashes/mgca/ace-with-const-ctor.rs +++ b/tests/crashes/mgca/ace-with-const-ctor.rs @@ -3,7 +3,7 @@ // readded once fixed. // Previous issue (before mgca): https://github.com/rust-lang/rust/issues/105952 #![crate_name = "foo"] -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] pub enum ParseMode { Raw, } diff --git a/tests/rustdoc-ui/associated-constant-not-allowed-102467.rs b/tests/rustdoc-ui/associated-constant-not-allowed-102467.rs index c4bbcfc2b077..5b8a90d64121 100644 --- a/tests/rustdoc-ui/associated-constant-not-allowed-102467.rs +++ b/tests/rustdoc-ui/associated-constant-not-allowed-102467.rs @@ -2,7 +2,7 @@ // It ensures that the expected error is displayed. #![expect(incomplete_features)] -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] trait T { type A: S = 34>; diff --git a/tests/rustdoc/inline_cross/auxiliary/assoc-const-equality.rs b/tests/rustdoc/inline_cross/auxiliary/assoc-const-equality.rs index f6c03d189b5e..598d2b5bf29d 100644 --- a/tests/rustdoc/inline_cross/auxiliary/assoc-const-equality.rs +++ b/tests/rustdoc/inline_cross/auxiliary/assoc-const-equality.rs @@ -1,5 +1,5 @@ #![expect(incomplete_features)] -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] pub fn accept(_: impl Trait) {} diff --git a/tests/ui/associated-consts/assoc-const-eq-ambiguity.rs b/tests/ui/associated-consts/assoc-const-eq-ambiguity.rs index 27261a4806eb..6bc2a6d5d153 100644 --- a/tests/ui/associated-consts/assoc-const-eq-ambiguity.rs +++ b/tests/ui/associated-consts/assoc-const-eq-ambiguity.rs @@ -1,7 +1,7 @@ // We used to say "ambiguous associated type" on ambiguous associated consts. // Ensure that we now use the correct label. -#![feature(associated_const_equality, min_generic_const_args, unsized_const_params)] +#![feature(min_generic_const_args, unsized_const_params)] #![allow(incomplete_features)] trait Trait0: Parent0 + Parent0 {} diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs index 50914fb192ff..803cc59cc93d 100644 --- a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs +++ b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs @@ -1,7 +1,6 @@ // Check that we eventually catch types of assoc const bounds // (containing late-bound vars) that are ill-formed. #![feature( - associated_const_equality, min_generic_const_args, adt_const_params, unsized_const_params, diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr index fd49e151b8e6..76868715b861 100644 --- a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr @@ -1,11 +1,11 @@ error: higher-ranked subtype error - --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:22:13 + --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:13 | LL | K = const { () } | ^^^^^^^^^^^^ error: higher-ranked subtype error - --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:22:13 + --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:13 | LL | K = const { () } | ^^^^^^^^^^^^ diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty.rs b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty.rs index 54e199d702c9..e6fd5bdad002 100644 --- a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty.rs +++ b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty.rs @@ -4,7 +4,6 @@ //@ check-pass #![feature( - associated_const_equality, min_generic_const_args, adt_const_params, unsized_const_params, diff --git a/tests/ui/associated-consts/assoc-const-eq-const_evaluatable_unchecked.rs b/tests/ui/associated-consts/assoc-const-eq-const_evaluatable_unchecked.rs index 22a03e47b2f7..161eef63d36f 100644 --- a/tests/ui/associated-consts/assoc-const-eq-const_evaluatable_unchecked.rs +++ b/tests/ui/associated-consts/assoc-const-eq-const_evaluatable_unchecked.rs @@ -4,7 +4,7 @@ // // issue: //@ check-pass -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] #![allow(incomplete_features)] pub trait TraitA { diff --git a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs b/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs index 7f9a04bbf0fc..d32737fcb62f 100644 --- a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs +++ b/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs @@ -1,7 +1,6 @@ // Detect and reject escaping late-bound generic params in // the type of assoc consts used in an equality bound. #![feature( - associated_const_equality, min_generic_const_args, unsized_const_params, generic_const_parameter_types, diff --git a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr b/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr index e22d9bfed7ef..ef861cb7f49a 100644 --- a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr @@ -1,5 +1,5 @@ error: the type of the associated constant `K` cannot capture late-bound generic parameters - --> $DIR/assoc-const-eq-esc-bound-var-in-ty.rs:16:35 + --> $DIR/assoc-const-eq-esc-bound-var-in-ty.rs:15:35 | LL | fn take(_: impl for<'r> Trait<'r, K = const { &() }>) {} | -- ^ its type cannot capture the late-bound lifetime parameter `'r` diff --git a/tests/ui/associated-consts/assoc-const-eq-missing.rs b/tests/ui/associated-consts/assoc-const-eq-missing.rs index f384927e4a34..22b565cb27d2 100644 --- a/tests/ui/associated-consts/assoc-const-eq-missing.rs +++ b/tests/ui/associated-consts/assoc-const-eq-missing.rs @@ -1,5 +1,5 @@ -#![feature(associated_const_equality)] -#![allow(unused)] +#![feature(min_generic_const_args)] +#![allow(incomplete_features, unused)] pub trait Foo { const N: usize; diff --git a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs index ea2f60cd6187..44e7e3f19ef2 100644 --- a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs +++ b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs @@ -1,7 +1,6 @@ // Regression test for issue #108271. // Detect and reject generic params in the type of assoc consts used in an equality bound. #![feature( - associated_const_equality, min_generic_const_args, adt_const_params, unsized_const_params, diff --git a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr index ae6a35b4b9f2..b742e68044b0 100644 --- a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr @@ -1,5 +1,5 @@ error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:23:29 + --> $DIR/assoc-const-eq-param-in-ty.rs:22:29 | LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( | -- the lifetime parameter `'r` is defined here @@ -10,7 +10,7 @@ LL | _: impl Trait<'r, A, Q, K = const { loop {} }> = note: `K` has type `&'r [A; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:23:29 + --> $DIR/assoc-const-eq-param-in-ty.rs:22:29 | LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( | - the type parameter `A` is defined here @@ -21,7 +21,7 @@ LL | _: impl Trait<'r, A, Q, K = const { loop {} }> = note: `K` has type `&'r [A; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:23:29 + --> $DIR/assoc-const-eq-param-in-ty.rs:22:29 | LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( | - the const parameter `Q` is defined here @@ -32,7 +32,7 @@ LL | _: impl Trait<'r, A, Q, K = const { loop {} }> = note: `K` has type `&'r [A; Q]` error: the type of the associated constant `SELF` must not depend on `impl Trait` - --> $DIR/assoc-const-eq-param-in-ty.rs:40:26 + --> $DIR/assoc-const-eq-param-in-ty.rs:39:26 | LL | fn take1(_: impl Project) {} | -------------^^^^------------ @@ -41,7 +41,7 @@ LL | fn take1(_: impl Project) {} | the `impl Trait` is specified here error: the type of the associated constant `SELF` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:45:21 + --> $DIR/assoc-const-eq-param-in-ty.rs:44:21 | LL | fn take2>(_: P) {} | - ^^^^ its type must not depend on the type parameter `P` @@ -51,7 +51,7 @@ LL | fn take2>(_: P) {} = note: `SELF` has type `P` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:54:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | LL | trait Iface<'r>: ConstParamTy_ { | -- the lifetime parameter `'r` is defined here @@ -62,7 +62,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> = note: `K` has type `&'r [Self; Q]` error: the type of the associated constant `K` must not depend on `Self` - --> $DIR/assoc-const-eq-param-in-ty.rs:54:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | ^ its type must not depend on `Self` @@ -70,7 +70,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> = note: `K` has type `&'r [Self; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:54:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | - ^ its type must not depend on the const parameter `Q` @@ -80,7 +80,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> = note: `K` has type `&'r [Self; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:54:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | LL | trait Iface<'r>: ConstParamTy_ { | -- the lifetime parameter `'r` is defined here @@ -92,7 +92,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: the type of the associated constant `K` must not depend on `Self` - --> $DIR/assoc-const-eq-param-in-ty.rs:54:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | ^ its type must not depend on `Self` @@ -101,7 +101,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:54:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | - ^ its type must not depend on the const parameter `Q` diff --git a/tests/ui/associated-consts/assoc-const-eq-supertraits.rs b/tests/ui/associated-consts/assoc-const-eq-supertraits.rs index c092285dfcd4..a5f8859c92bd 100644 --- a/tests/ui/associated-consts/assoc-const-eq-supertraits.rs +++ b/tests/ui/associated-consts/assoc-const-eq-supertraits.rs @@ -4,7 +4,6 @@ //@ check-pass #![feature( - associated_const_equality, min_generic_const_args, adt_const_params, unsized_const_params, diff --git a/tests/ui/associated-consts/assoc-const-eq-ty-alias-noninteracting.rs b/tests/ui/associated-consts/assoc-const-eq-ty-alias-noninteracting.rs index 41857eca87de..004215986711 100644 --- a/tests/ui/associated-consts/assoc-const-eq-ty-alias-noninteracting.rs +++ b/tests/ui/associated-consts/assoc-const-eq-ty-alias-noninteracting.rs @@ -5,7 +5,7 @@ //@ check-pass -#![feature(associated_const_equality, min_generic_const_args, unsized_const_params)] +#![feature(min_generic_const_args, unsized_const_params)] #![allow(incomplete_features)] trait Trait: SuperTrait { diff --git a/tests/ui/associated-consts/assoc-const-ty-mismatch.rs b/tests/ui/associated-consts/assoc-const-ty-mismatch.rs index 7211637659bd..1092733a8e2e 100644 --- a/tests/ui/associated-consts/assoc-const-ty-mismatch.rs +++ b/tests/ui/associated-consts/assoc-const-ty-mismatch.rs @@ -1,5 +1,5 @@ -#![feature(associated_const_equality)] -#![allow(unused)] +#![feature(min_generic_const_args)] +#![allow(incomplete_features, unused)] pub trait Foo { const N: usize; diff --git a/tests/ui/associated-consts/assoc-const.rs b/tests/ui/associated-consts/assoc-const.rs index 6295fd50b8ff..ac9f7e53b3cb 100644 --- a/tests/ui/associated-consts/assoc-const.rs +++ b/tests/ui/associated-consts/assoc-const.rs @@ -1,5 +1,5 @@ //@ run-pass -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] #![allow(unused, incomplete_features)] pub trait Foo { diff --git a/tests/ui/associated-consts/equality-unused-issue-126729.rs b/tests/ui/associated-consts/equality-unused-issue-126729.rs index 35b49314b5f5..614ed8c803d4 100644 --- a/tests/ui/associated-consts/equality-unused-issue-126729.rs +++ b/tests/ui/associated-consts/equality-unused-issue-126729.rs @@ -1,6 +1,6 @@ //@ check-pass -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] #![allow(incomplete_features)] #![deny(dead_code)] diff --git a/tests/ui/associated-consts/issue-102335-const.rs b/tests/ui/associated-consts/issue-102335-const.rs index f9b816fd3bc9..a88a3abf0a12 100644 --- a/tests/ui/associated-consts/issue-102335-const.rs +++ b/tests/ui/associated-consts/issue-102335-const.rs @@ -1,4 +1,4 @@ -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] #![allow(incomplete_features)] trait T { diff --git a/tests/ui/associated-consts/issue-105330.stderr b/tests/ui/associated-consts/issue-105330.stderr index 5d6dc48e36c0..06900404ec34 100644 --- a/tests/ui/associated-consts/issue-105330.stderr +++ b/tests/ui/associated-consts/issue-105330.stderr @@ -21,8 +21,8 @@ error[E0658]: associated const equality is incomplete LL | fn foo>() { | ^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated const equality is incomplete @@ -31,8 +31,8 @@ error[E0658]: associated const equality is incomplete LL | fn main>() { | ^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0562]: `impl Trait` is not allowed in impl headers diff --git a/tests/ui/associated-consts/issue-110933.rs b/tests/ui/associated-consts/issue-110933.rs index 731ff1564ce2..9a013ee71274 100644 --- a/tests/ui/associated-consts/issue-110933.rs +++ b/tests/ui/associated-consts/issue-110933.rs @@ -1,6 +1,6 @@ //@ check-pass -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] #![allow(incomplete_features)] pub trait Trait { diff --git a/tests/ui/associated-consts/issue-93835.rs b/tests/ui/associated-consts/issue-93835.rs index d6c2acaa9edc..26d0bbe3a40f 100644 --- a/tests/ui/associated-consts/issue-93835.rs +++ b/tests/ui/associated-consts/issue-93835.rs @@ -4,9 +4,9 @@ fn e() { type_ascribe!(p, a>); //~^ ERROR cannot find type `a` in this scope //~| ERROR cannot find value - //~| ERROR associated const equality + //~| ERROR associated const equality is incomplete //~| ERROR cannot find trait `p` in this scope - //~| ERROR associated const equality + //~| ERROR associated const equality is incomplete } fn main() {} diff --git a/tests/ui/associated-consts/issue-93835.stderr b/tests/ui/associated-consts/issue-93835.stderr index 3f1679890130..990d22bba4de 100644 --- a/tests/ui/associated-consts/issue-93835.stderr +++ b/tests/ui/associated-consts/issue-93835.stderr @@ -22,8 +22,8 @@ error[E0658]: associated const equality is incomplete LL | type_ascribe!(p, a>); | ^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated const equality is incomplete @@ -32,8 +32,8 @@ error[E0658]: associated const equality is incomplete LL | type_ascribe!(p, a>); | ^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/associated-consts/projection-unspecified-but-bounded.rs b/tests/ui/associated-consts/projection-unspecified-but-bounded.rs index 7f3304f07656..8a78b26dbc5d 100644 --- a/tests/ui/associated-consts/projection-unspecified-but-bounded.rs +++ b/tests/ui/associated-consts/projection-unspecified-but-bounded.rs @@ -1,4 +1,4 @@ -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] #![allow(incomplete_features)] // Issue 110549 diff --git a/tests/ui/associated-type-bounds/const-projection-err.rs b/tests/ui/associated-type-bounds/const-projection-err.rs index b230ea77f5fe..d485316ce371 100644 --- a/tests/ui/associated-type-bounds/const-projection-err.rs +++ b/tests/ui/associated-type-bounds/const-projection-err.rs @@ -1,4 +1,4 @@ -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] #![allow(incomplete_features)] trait TraitWAssocConst { diff --git a/tests/ui/associated-type-bounds/duplicate-bound-err.rs b/tests/ui/associated-type-bounds/duplicate-bound-err.rs index 7e86148eb811..1587be7200e7 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound-err.rs +++ b/tests/ui/associated-type-bounds/duplicate-bound-err.rs @@ -1,7 +1,6 @@ //@ edition: 2024 #![feature( - associated_const_equality, min_generic_const_args, type_alias_impl_trait, return_type_notation diff --git a/tests/ui/associated-type-bounds/duplicate-bound-err.stderr b/tests/ui/associated-type-bounds/duplicate-bound-err.stderr index 6484880392d6..ec864c1dd96e 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound-err.stderr +++ b/tests/ui/associated-type-bounds/duplicate-bound-err.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/duplicate-bound-err.rs:15:5 + --> $DIR/duplicate-bound-err.rs:14:5 | LL | iter::empty() | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` @@ -10,7 +10,7 @@ LL | iter::empty::() | +++++ error[E0282]: type annotations needed - --> $DIR/duplicate-bound-err.rs:19:5 + --> $DIR/duplicate-bound-err.rs:18:5 | LL | iter::empty() | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` @@ -21,7 +21,7 @@ LL | iter::empty::() | +++++ error[E0282]: type annotations needed - --> $DIR/duplicate-bound-err.rs:23:5 + --> $DIR/duplicate-bound-err.rs:22:5 | LL | iter::empty() | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` @@ -32,7 +32,7 @@ LL | iter::empty::() | +++++ error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:27:51 + --> $DIR/duplicate-bound-err.rs:26:51 | LL | type Tait1> = impl Copy; | ^^^^^^^^^ @@ -40,7 +40,7 @@ LL | type Tait1> = impl Copy; = note: `Tait1` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:29:51 + --> $DIR/duplicate-bound-err.rs:28:51 | LL | type Tait2> = impl Copy; | ^^^^^^^^^ @@ -48,7 +48,7 @@ LL | type Tait2> = impl Copy; = note: `Tait2` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:31:57 + --> $DIR/duplicate-bound-err.rs:30:57 | LL | type Tait3> = impl Copy; | ^^^^^^^^^ @@ -56,7 +56,7 @@ LL | type Tait3> = impl Copy; = note: `Tait3` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:34:14 + --> $DIR/duplicate-bound-err.rs:33:14 | LL | type Tait4 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | type Tait4 = impl Iterator; = note: `Tait4` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:36:14 + --> $DIR/duplicate-bound-err.rs:35:14 | LL | type Tait5 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | type Tait5 = impl Iterator; = note: `Tait5` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:38:14 + --> $DIR/duplicate-bound-err.rs:37:14 | LL | type Tait6 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL | type Tait6 = impl Iterator; = note: `Tait6` must be used in combination with a concrete type within the same crate error[E0277]: `*const ()` cannot be sent between threads safely - --> $DIR/duplicate-bound-err.rs:41:18 + --> $DIR/duplicate-bound-err.rs:40:18 | LL | fn mismatch() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const ()` cannot be sent between threads safely @@ -91,7 +91,7 @@ LL | iter::empty::<*const ()>() = help: the trait `Send` is not implemented for `*const ()` error[E0277]: the trait bound `String: Copy` is not satisfied - --> $DIR/duplicate-bound-err.rs:46:20 + --> $DIR/duplicate-bound-err.rs:45:20 | LL | fn mismatch_2() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` @@ -100,7 +100,7 @@ LL | iter::empty::() | ----------------------- return type was inferred to be `std::iter::Empty` here error[E0271]: expected `IntoIter` to be an iterator that yields `i32`, but it yields `u32` - --> $DIR/duplicate-bound-err.rs:112:17 + --> $DIR/duplicate-bound-err.rs:111:17 | LL | fn foo() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` @@ -109,7 +109,7 @@ LL | [2u32].into_iter() | ------------------ return type was inferred to be `std::array::IntoIter` here error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate-bound-err.rs:88:42 + --> $DIR/duplicate-bound-err.rs:87:42 | LL | type MustFail = dyn Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -117,7 +117,7 @@ LL | type MustFail = dyn Iterator; | `Item` bound here first error: conflicting associated type bounds for `Item` - --> $DIR/duplicate-bound-err.rs:88:17 + --> $DIR/duplicate-bound-err.rs:87:17 | LL | type MustFail = dyn Iterator; | ^^^^^^^^^^^^^----------^^----------^ @@ -126,7 +126,7 @@ LL | type MustFail = dyn Iterator; | `Item` is specified to be `i32` here error[E0719]: the value of the associated type `ASSOC` in trait `Trait2` is already specified - --> $DIR/duplicate-bound-err.rs:97:43 + --> $DIR/duplicate-bound-err.rs:96:43 | LL | type MustFail2 = dyn Trait2; | ------------ ^^^^^^^^^^^^ re-bound here @@ -134,7 +134,7 @@ LL | type MustFail2 = dyn Trait2; | `ASSOC` bound here first error: conflicting associated type bounds for `ASSOC` - --> $DIR/duplicate-bound-err.rs:97:18 + --> $DIR/duplicate-bound-err.rs:96:18 | LL | type MustFail2 = dyn Trait2; | ^^^^^^^^^^^------------^^------------^ @@ -143,7 +143,7 @@ LL | type MustFail2 = dyn Trait2; | `ASSOC` is specified to be `3` here error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate-bound-err.rs:101:43 + --> $DIR/duplicate-bound-err.rs:100:43 | LL | type MustFail3 = dyn Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -151,7 +151,7 @@ LL | type MustFail3 = dyn Iterator; | `Item` bound here first error[E0719]: the value of the associated type `ASSOC` in trait `Trait2` is already specified - --> $DIR/duplicate-bound-err.rs:104:43 + --> $DIR/duplicate-bound-err.rs:103:43 | LL | type MustFail4 = dyn Trait2; | ------------ ^^^^^^^^^^^^ re-bound here @@ -159,19 +159,19 @@ LL | type MustFail4 = dyn Trait2; | `ASSOC` bound here first error[E0271]: expected `impl Iterator` to be an iterator that yields `i32`, but it yields `u32` - --> $DIR/duplicate-bound-err.rs:112:17 + --> $DIR/duplicate-bound-err.rs:111:17 | LL | fn foo() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` | note: required by a bound in `Trait3::foo::{anon_assoc#0}` - --> $DIR/duplicate-bound-err.rs:108:31 + --> $DIR/duplicate-bound-err.rs:107:31 | LL | fn foo() -> impl Iterator; | ^^^^^^^^^^ required by this bound in `Trait3::foo::{anon_assoc#0}` error[E0271]: expected `Empty` to be an iterator that yields `i32`, but it yields `u32` - --> $DIR/duplicate-bound-err.rs:120:16 + --> $DIR/duplicate-bound-err.rs:119:16 | LL | uncallable(iter::empty::()); | ---------- ^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` @@ -179,13 +179,13 @@ LL | uncallable(iter::empty::()); | required by a bound introduced by this call | note: required by a bound in `uncallable` - --> $DIR/duplicate-bound-err.rs:80:32 + --> $DIR/duplicate-bound-err.rs:79:32 | LL | fn uncallable(_: impl Iterator) {} | ^^^^^^^^^^ required by this bound in `uncallable` error[E0271]: expected `Empty` to be an iterator that yields `u32`, but it yields `i32` - --> $DIR/duplicate-bound-err.rs:121:16 + --> $DIR/duplicate-bound-err.rs:120:16 | LL | uncallable(iter::empty::()); | ---------- ^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `i32` @@ -193,13 +193,13 @@ LL | uncallable(iter::empty::()); | required by a bound introduced by this call | note: required by a bound in `uncallable` - --> $DIR/duplicate-bound-err.rs:80:44 + --> $DIR/duplicate-bound-err.rs:79:44 | LL | fn uncallable(_: impl Iterator) {} | ^^^^^^^^^^ required by this bound in `uncallable` error[E0271]: type mismatch resolving `<() as Trait>::ASSOC == 4` - --> $DIR/duplicate-bound-err.rs:122:22 + --> $DIR/duplicate-bound-err.rs:121:22 | LL | uncallable_const(()); | ---------------- ^^ expected `4`, found `3` @@ -209,13 +209,13 @@ LL | uncallable_const(()); = note: expected constant `4` found constant `3` note: required by a bound in `uncallable_const` - --> $DIR/duplicate-bound-err.rs:82:46 + --> $DIR/duplicate-bound-err.rs:81:46 | LL | fn uncallable_const(_: impl Trait) {} | ^^^^^^^^^ required by this bound in `uncallable_const` error[E0271]: type mismatch resolving `::ASSOC == 3` - --> $DIR/duplicate-bound-err.rs:123:22 + --> $DIR/duplicate-bound-err.rs:122:22 | LL | uncallable_const(4u32); | ---------------- ^^^^ expected `3`, found `4` @@ -225,13 +225,13 @@ LL | uncallable_const(4u32); = note: expected constant `3` found constant `4` note: required by a bound in `uncallable_const` - --> $DIR/duplicate-bound-err.rs:82:35 + --> $DIR/duplicate-bound-err.rs:81:35 | LL | fn uncallable_const(_: impl Trait) {} | ^^^^^^^^^ required by this bound in `uncallable_const` error[E0271]: type mismatch resolving `<() as Trait>::ASSOC == 4` - --> $DIR/duplicate-bound-err.rs:124:20 + --> $DIR/duplicate-bound-err.rs:123:20 | LL | uncallable_rtn(()); | -------------- ^^ expected `4`, found `3` @@ -241,7 +241,7 @@ LL | uncallable_rtn(()); = note: expected constant `4` found constant `3` note: required by a bound in `uncallable_rtn` - --> $DIR/duplicate-bound-err.rs:85:61 + --> $DIR/duplicate-bound-err.rs:84:61 | LL | fn uncallable_rtn( | -------------- required by a bound in this function @@ -249,7 +249,7 @@ LL | _: impl Trait, foo(..): Trait> | ^^^^^^^^^ required by this bound in `uncallable_rtn` error[E0271]: type mismatch resolving `::ASSOC == 3` - --> $DIR/duplicate-bound-err.rs:125:20 + --> $DIR/duplicate-bound-err.rs:124:20 | LL | uncallable_rtn(17u32); | -------------- ^^^^^ expected `3`, found `4` @@ -259,7 +259,7 @@ LL | uncallable_rtn(17u32); = note: expected constant `3` found constant `4` note: required by a bound in `uncallable_rtn` - --> $DIR/duplicate-bound-err.rs:85:34 + --> $DIR/duplicate-bound-err.rs:84:34 | LL | fn uncallable_rtn( | -------------- required by a bound in this function diff --git a/tests/ui/associated-type-bounds/duplicate-bound.rs b/tests/ui/associated-type-bounds/duplicate-bound.rs index 6ea0daeca2c4..1aeb0022a04f 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound.rs +++ b/tests/ui/associated-type-bounds/duplicate-bound.rs @@ -1,7 +1,7 @@ //@ edition: 2024 //@ run-pass -#![feature(associated_const_equality, min_generic_const_args, return_type_notation)] +#![feature(min_generic_const_args, return_type_notation)] #![expect(incomplete_features)] #![allow(dead_code, refining_impl_trait_internal, type_alias_bounds)] diff --git a/tests/ui/associated-type-bounds/issue-99828.stderr b/tests/ui/associated-type-bounds/issue-99828.stderr index 132d5251987b..e1dc1f07d9cb 100644 --- a/tests/ui/associated-type-bounds/issue-99828.stderr +++ b/tests/ui/associated-type-bounds/issue-99828.stderr @@ -4,8 +4,8 @@ error[E0658]: associated const equality is incomplete LL | fn get_iter(vec: &[i32]) -> impl Iterator + '_ { | ^^^^^^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: expected type, found constant diff --git a/tests/ui/associated-types/associated-types-eq-2.stderr b/tests/ui/associated-types/associated-types-eq-2.stderr index 19c34241e5f2..9be346516c89 100644 --- a/tests/ui/associated-types/associated-types-eq-2.stderr +++ b/tests/ui/associated-types/associated-types-eq-2.stderr @@ -7,8 +7,8 @@ LL | impl Tr3 for Bar { | |____^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated const equality is incomplete @@ -17,8 +17,8 @@ error[E0658]: associated const equality is incomplete LL | impl Tr3 for Qux { | ^^^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated const equality is incomplete @@ -27,8 +27,8 @@ error[E0658]: associated const equality is incomplete LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar { | ^^^^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated const equality is incomplete @@ -37,8 +37,8 @@ error[E0658]: associated const equality is incomplete LL | impl Tr3 for Bar { | ^^^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0229]: associated item constraints are not allowed here diff --git a/tests/ui/const-generics/assoc_const_eq_diagnostic.rs b/tests/ui/const-generics/assoc_const_eq_diagnostic.rs index 6ab82f45e684..f2b581412a72 100644 --- a/tests/ui/const-generics/assoc_const_eq_diagnostic.rs +++ b/tests/ui/const-generics/assoc_const_eq_diagnostic.rs @@ -1,5 +1,6 @@ //@ edition:2015 -#![feature(associated_const_equality)] +#![feature(min_generic_const_args)] +#![allow(incomplete_features)] pub enum Mode { Cool, diff --git a/tests/ui/const-generics/assoc_const_eq_diagnostic.stderr b/tests/ui/const-generics/assoc_const_eq_diagnostic.stderr index bcfad9d1538c..05e0ec93d494 100644 --- a/tests/ui/const-generics/assoc_const_eq_diagnostic.stderr +++ b/tests/ui/const-generics/assoc_const_eq_diagnostic.stderr @@ -1,5 +1,5 @@ error[E0573]: expected type, found variant `Mode::Cool` - --> $DIR/assoc_const_eq_diagnostic.rs:12:35 + --> $DIR/assoc_const_eq_diagnostic.rs:13:35 | LL | pub trait CoolStuff: Parse {} | ^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | pub trait CoolStuff: Parse {} | help: try using the variant's enum: `Mode` error[E0573]: expected type, found variant `Mode::Cool` - --> $DIR/assoc_const_eq_diagnostic.rs:18:17 + --> $DIR/assoc_const_eq_diagnostic.rs:19:17 | LL | fn no_help() -> Mode::Cool {} | ^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | fn no_help() -> Mode::Cool {} | help: try using the variant's enum: `Mode` error: expected constant, found type - --> $DIR/assoc_const_eq_diagnostic.rs:12:35 + --> $DIR/assoc_const_eq_diagnostic.rs:13:35 | LL | pub trait CoolStuff: Parse {} | ---- ^^^^^^^^^^ unexpected type @@ -25,7 +25,7 @@ LL | pub trait CoolStuff: Parse {} | expected a constant because of this associated constant | note: the associated constant is defined here - --> $DIR/assoc_const_eq_diagnostic.rs:9:5 + --> $DIR/assoc_const_eq_diagnostic.rs:10:5 | LL | const MODE: Mode; | ^^^^^^^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | pub trait CoolStuff: Parse {} | + + error: expected constant, found type - --> $DIR/assoc_const_eq_diagnostic.rs:12:35 + --> $DIR/assoc_const_eq_diagnostic.rs:13:35 | LL | pub trait CoolStuff: Parse {} | ---- ^^^^^^^^^^ unexpected type @@ -43,7 +43,7 @@ LL | pub trait CoolStuff: Parse {} | expected a constant because of this associated constant | note: the associated constant is defined here - --> $DIR/assoc_const_eq_diagnostic.rs:9:5 + --> $DIR/assoc_const_eq_diagnostic.rs:10:5 | LL | const MODE: Mode; | ^^^^^^^^^^^^^^^^ @@ -54,7 +54,7 @@ LL | pub trait CoolStuff: Parse {} | + + error: expected constant, found type - --> $DIR/assoc_const_eq_diagnostic.rs:12:35 + --> $DIR/assoc_const_eq_diagnostic.rs:13:35 | LL | pub trait CoolStuff: Parse {} | ---- ^^^^^^^^^^ unexpected type @@ -62,7 +62,7 @@ LL | pub trait CoolStuff: Parse {} | expected a constant because of this associated constant | note: the associated constant is defined here - --> $DIR/assoc_const_eq_diagnostic.rs:9:5 + --> $DIR/assoc_const_eq_diagnostic.rs:10:5 | LL | const MODE: Mode; | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/const-generics/associated_const_equality/coherence.rs b/tests/ui/const-generics/associated_const_equality/coherence.rs index fb5f255c1dc4..f4081fae6144 100644 --- a/tests/ui/const-generics/associated_const_equality/coherence.rs +++ b/tests/ui/const-generics/associated_const_equality/coherence.rs @@ -1,4 +1,4 @@ -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] #![expect(incomplete_features)] pub trait IsVoid { diff --git a/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.rs b/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.rs index 3973c7af15b4..b7ed8ee39f87 100644 --- a/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.rs +++ b/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.rs @@ -1,6 +1,6 @@ //@ check-pass -#![feature(associated_const_equality, min_generic_const_args, generic_const_items)] +#![feature(min_generic_const_args, generic_const_items)] #![expect(incomplete_features)] // Regression test for #133066 where we would try to evaluate `<() as Foo>::ASSOC<_>` even diff --git a/tests/ui/const-generics/associated_const_equality/mismatched-types-with-generic-in-ace-no-feature-gate.stderr b/tests/ui/const-generics/associated_const_equality/mismatched-types-with-generic-in-ace-no-feature-gate.stderr index 0b487b6a7aa0..d2f28a62e04e 100644 --- a/tests/ui/const-generics/associated_const_equality/mismatched-types-with-generic-in-ace-no-feature-gate.stderr +++ b/tests/ui/const-generics/associated_const_equality/mismatched-types-with-generic-in-ace-no-feature-gate.stderr @@ -1,13 +1,3 @@ -error[E0658]: associated const equality is incomplete - --> $DIR/mismatched-types-with-generic-in-ace-no-feature-gate.rs:7:38 - | -LL | fn take0(_: impl Owner = { N }>) {} - | ^^^^^^^^^^^^ - | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0658]: generic const items are experimental --> $DIR/mismatched-types-with-generic-in-ace-no-feature-gate.rs:2:12 | @@ -18,6 +8,16 @@ LL | const C: u32 = N; = help: add `#![feature(generic_const_items)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: associated const equality is incomplete + --> $DIR/mismatched-types-with-generic-in-ace-no-feature-gate.rs:7:38 + | +LL | fn take0(_: impl Owner = { N }>) {} + | ^^^^^^^^^^^^ + | + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/const-generics/associated_const_equality/mismatched-types-with-generic-in-ace.rs b/tests/ui/const-generics/associated_const_equality/mismatched-types-with-generic-in-ace.rs index 33afa7e3228e..77f0f06f8040 100644 --- a/tests/ui/const-generics/associated_const_equality/mismatched-types-with-generic-in-ace.rs +++ b/tests/ui/const-generics/associated_const_equality/mismatched-types-with-generic-in-ace.rs @@ -1,4 +1,4 @@ -#![feature(generic_const_items, associated_const_equality, min_generic_const_args)] +#![feature(generic_const_items, min_generic_const_args)] #![expect(incomplete_features)] trait Foo { diff --git a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr index 092faff93511..c34674604b51 100644 --- a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr +++ b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr @@ -4,8 +4,8 @@ error[E0658]: associated const equality is incomplete LL | impl Trait for () where (U,): AssocConst {} | ^^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts.rs b/tests/ui/const-generics/mgca/explicit_anon_consts.rs index f3edc0b3fbf3..bf825a44b1c0 100644 --- a/tests/ui/const-generics/mgca/explicit_anon_consts.rs +++ b/tests/ui/const-generics/mgca/explicit_anon_consts.rs @@ -1,4 +1,4 @@ -#![feature(associated_const_equality, generic_const_items, min_generic_const_args)] +#![feature(generic_const_items, min_generic_const_args)] #![expect(incomplete_features)] // library crates exercise weirder code paths around // DefIds which were created for const args. diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs b/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs index 8c8c5c8e8f88..eb8f04b8b24b 100644 --- a/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs +++ b/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs @@ -4,7 +4,7 @@ // However, we don't allow so for const arguments in field init positions. // This is just harder to implement so we did not do so. -#![feature(min_generic_const_args, adt_const_params, associated_const_equality)] +#![feature(min_generic_const_args, adt_const_params)] #![expect(incomplete_features)] trait Trait { diff --git a/tests/ui/const-generics/mgca/type_const-only-in-impl.rs b/tests/ui/const-generics/mgca/type_const-only-in-impl.rs index ae4a0004232b..1887f511bd62 100644 --- a/tests/ui/const-generics/mgca/type_const-only-in-impl.rs +++ b/tests/ui/const-generics/mgca/type_const-only-in-impl.rs @@ -1,5 +1,5 @@ #![expect(incomplete_features)] -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] trait BadTr { const NUM: usize; diff --git a/tests/ui/const-generics/mgca/type_const-only-in-trait.rs b/tests/ui/const-generics/mgca/type_const-only-in-trait.rs index 8c8ff6259cae..2ff38648206a 100644 --- a/tests/ui/const-generics/mgca/type_const-only-in-trait.rs +++ b/tests/ui/const-generics/mgca/type_const-only-in-trait.rs @@ -1,5 +1,5 @@ #![expect(incomplete_features)] -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] trait GoodTr { #[type_const] diff --git a/tests/ui/const-generics/mgca/using-fnptr-as-type_const.rs b/tests/ui/const-generics/mgca/using-fnptr-as-type_const.rs index d97b3a9f0929..5c494031d4fa 100644 --- a/tests/ui/const-generics/mgca/using-fnptr-as-type_const.rs +++ b/tests/ui/const-generics/mgca/using-fnptr-as-type_const.rs @@ -1,7 +1,7 @@ // Regression test for #119783 #![expect(incomplete_features)] -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] trait Trait { #[type_const] diff --git a/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr b/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr index d435af07db2a..9c956d79a7bb 100644 --- a/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr +++ b/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr @@ -4,8 +4,8 @@ error[E0658]: associated const equality is incomplete LL | impl Foo for Bar { | ^^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0229]: associated item constraints are not allowed here diff --git a/tests/ui/const-generics/parser-error-recovery/issue-89013.stderr b/tests/ui/const-generics/parser-error-recovery/issue-89013.stderr index f852c14b1784..4a4ff098dc4b 100644 --- a/tests/ui/const-generics/parser-error-recovery/issue-89013.stderr +++ b/tests/ui/const-generics/parser-error-recovery/issue-89013.stderr @@ -16,8 +16,8 @@ error[E0658]: associated const equality is incomplete LL | impl Foo for Bar { | ^^^^^^^^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0229]: associated item constraints are not allowed here diff --git a/tests/ui/feature-gates/feature-gate-associated_const_equality.rs b/tests/ui/feature-gates/feature-gate-associated_const_equality.rs index 2534c527be46..6b643b629a29 100644 --- a/tests/ui/feature-gates/feature-gate-associated_const_equality.rs +++ b/tests/ui/feature-gates/feature-gate-associated_const_equality.rs @@ -8,7 +8,7 @@ impl TraitWAssocConst for Demo { } fn foo>() {} -//~^ ERROR associated const equality +//~^ ERROR associated const equality is incomplete fn main() { foo::(); diff --git a/tests/ui/feature-gates/feature-gate-associated_const_equality.stderr b/tests/ui/feature-gates/feature-gate-associated_const_equality.stderr index 5a0fb69b6ba7..096755701931 100644 --- a/tests/ui/feature-gates/feature-gate-associated_const_equality.stderr +++ b/tests/ui/feature-gates/feature-gate-associated_const_equality.stderr @@ -4,8 +4,8 @@ error[E0658]: associated const equality is incomplete LL | fn foo>() {} | ^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: aborting due to 1 previous error diff --git a/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs index a72aaedb980e..fb2506daf078 100644 --- a/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs +++ b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs @@ -1,6 +1,6 @@ // ICE: assertion failed: !value.has_infer() // issue: rust-lang/rust#115806 -#![feature(associated_const_equality, min_generic_const_args, unsized_const_params)] +#![feature(min_generic_const_args, unsized_const_params)] #![allow(incomplete_features)] pub struct NoPin; diff --git a/tests/ui/generic-const-items/associated-const-equality.rs b/tests/ui/generic-const-items/associated-const-equality.rs index 37cf381e6824..d0301b920e27 100644 --- a/tests/ui/generic-const-items/associated-const-equality.rs +++ b/tests/ui/generic-const-items/associated-const-equality.rs @@ -1,7 +1,7 @@ //@ check-pass #![feature(generic_const_items, min_generic_const_args)] -#![feature(associated_const_equality, adt_const_params)] +#![feature(adt_const_params)] #![allow(incomplete_features)] trait Owner { diff --git a/tests/ui/lowering/no-name-for-DefPath-issue-133426.stderr b/tests/ui/lowering/no-name-for-DefPath-issue-133426.stderr index 555d8eec6bab..3d1233cdd019 100644 --- a/tests/ui/lowering/no-name-for-DefPath-issue-133426.stderr +++ b/tests/ui/lowering/no-name-for-DefPath-issue-133426.stderr @@ -4,8 +4,8 @@ error[E0658]: associated const equality is incomplete LL | fn b(_: impl Iterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0614]: type `!` cannot be dereferenced diff --git a/tests/ui/parser/recover/recover-assoc-const-constraint.stderr b/tests/ui/parser/recover/recover-assoc-const-constraint.stderr index 02b1c3fe68a9..766acd0398d2 100644 --- a/tests/ui/parser/recover/recover-assoc-const-constraint.stderr +++ b/tests/ui/parser/recover/recover-assoc-const-constraint.stderr @@ -4,8 +4,8 @@ error[E0658]: associated const equality is incomplete LL | bar::(); | ^^^^^^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated const equality is incomplete @@ -14,8 +14,8 @@ error[E0658]: associated const equality is incomplete LL | bar::(); | ^^^^^^^^^^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: aborting due to 2 previous errors diff --git a/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.rs b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.rs index edea6f75444f..538b0c2b1d46 100644 --- a/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.rs +++ b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.rs @@ -1,6 +1,6 @@ // Regression test for #140571. The compiler used to ICE -#![feature(associated_const_equality, min_generic_const_args, specialization)] +#![feature(min_generic_const_args, specialization)] //~^ WARN the feature `specialization` is incomplete //~| WARN the feature `min_generic_const_args` is incomplete diff --git a/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr index bf15d0fae4e5..6159c2ed331a 100644 --- a/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr +++ b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr @@ -1,17 +1,17 @@ warning: the feature `min_generic_const_args` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/overlap-due-to-unsatisfied-const-bound.rs:3:39 + --> $DIR/overlap-due-to-unsatisfied-const-bound.rs:3:12 | -LL | #![feature(associated_const_equality, min_generic_const_args, specialization)] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![feature(min_generic_const_args, specialization)] + | ^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #132980 for more information = note: `#[warn(incomplete_features)]` on by default warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/overlap-due-to-unsatisfied-const-bound.rs:3:63 + --> $DIR/overlap-due-to-unsatisfied-const-bound.rs:3:36 | -LL | #![feature(associated_const_equality, min_generic_const_args, specialization)] - | ^^^^^^^^^^^^^^ +LL | #![feature(min_generic_const_args, specialization)] + | ^^^^^^^^^^^^^^ | = note: see issue #31844 for more information = help: consider using `min_specialization` instead, which is more stable and complete diff --git a/tests/ui/traits/next-solver/dont-ice-on-assoc-projection.stderr b/tests/ui/traits/next-solver/dont-ice-on-assoc-projection.stderr index db7d2dd3e3a3..8334fdae9485 100644 --- a/tests/ui/traits/next-solver/dont-ice-on-assoc-projection.stderr +++ b/tests/ui/traits/next-solver/dont-ice-on-assoc-projection.stderr @@ -4,8 +4,8 @@ error[E0658]: associated const equality is incomplete LL | impl Foo for T where T: Bar {} | ^^^^^^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0119]: conflicting implementations of trait `Foo` for type `()` From af5bebeae3d66b2b92bee4187108f64d931537f8 Mon Sep 17 00:00:00 2001 From: AprilNEA Date: Sat, 3 Jan 2026 16:24:56 +0800 Subject: [PATCH 0260/1061] Merge `associated_const_equality` feature gate into MGCA This removes `associated_const_equality` as a separate feature gate and makes it part of `min_generic_const_args` (mgca). Key changes: - Remove `associated_const_equality` from unstable features, add to removed - Update all test files to use `min_generic_const_args` instead - Preserve the original "associated const equality is incomplete" error message by specially handling `sym::associated_const_equality` spans in `feature_gate.rs` - Rename FIXME(associated_const_equality) to FIXME(mgca) --- tests/ui/trait_duplication_in_bounds_assoc_const_eq.fixed | 2 +- tests/ui/trait_duplication_in_bounds_assoc_const_eq.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui/trait_duplication_in_bounds_assoc_const_eq.fixed b/tests/ui/trait_duplication_in_bounds_assoc_const_eq.fixed index f2bd306a99e4..f8be3331317c 100644 --- a/tests/ui/trait_duplication_in_bounds_assoc_const_eq.fixed +++ b/tests/ui/trait_duplication_in_bounds_assoc_const_eq.fixed @@ -1,6 +1,6 @@ #![deny(clippy::trait_duplication_in_bounds)] #![expect(incomplete_features)] -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] trait AssocConstTrait { #[type_const] diff --git a/tests/ui/trait_duplication_in_bounds_assoc_const_eq.rs b/tests/ui/trait_duplication_in_bounds_assoc_const_eq.rs index 8e7d843a44c0..a0d7a653993f 100644 --- a/tests/ui/trait_duplication_in_bounds_assoc_const_eq.rs +++ b/tests/ui/trait_duplication_in_bounds_assoc_const_eq.rs @@ -1,6 +1,6 @@ #![deny(clippy::trait_duplication_in_bounds)] #![expect(incomplete_features)] -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] trait AssocConstTrait { #[type_const] From 3f773fac3b5a1ed57ffd9918789dab7ce0e7c0ac Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Wed, 31 Dec 2025 12:29:01 +0530 Subject: [PATCH 0261/1061] std: sys: fs: uefi: Implement remove_dir_all - Using the implementation from sys::fs::common since UEFI does not have a built-in for this functionality. Signed-off-by: Ayush Singh --- library/std/src/sys/fs/uefi.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index 14ee49e071c1..5a07e6332109 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -6,7 +6,7 @@ use crate::fs::TryLockError; use crate::hash::Hash; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::path::{Path, PathBuf}; -pub use crate::sys::fs::common::Dir; +pub use crate::sys::fs::common::{Dir, remove_dir_all}; use crate::sys::pal::{helpers, unsupported}; use crate::sys::time::SystemTime; @@ -446,10 +446,6 @@ pub fn rmdir(p: &Path) -> io::Result<()> { } } -pub fn remove_dir_all(_path: &Path) -> io::Result<()> { - unsupported() -} - pub fn exists(path: &Path) -> io::Result { let f = uefi_fs::File::from_path(path, r_efi::protocols::file::MODE_READ, 0); match f { From 93f8ad99507ecb851ace4b1d4e3e7c5cd67ed80c Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 26 Dec 2025 00:13:11 +0900 Subject: [PATCH 0262/1061] cleaned up some tests cleaned up cast-enum-const.rs cleaned up ufcs-trait-object-format.rs add comment to cast-to-box-arr.rs add comment to shadow-primitives.rs add comment to associated-type-const-nomalization.rs add comment to fn-trait-explicit-call.rs add comment to call-unit-struct-impl-fn-once.rs add comment to cast-to-char-compare.rs add comment to self-in-method-body-resolves.rs add comment to derive-debug-newtype-unsized-slice.rs add comment to tuple-ref-order-distinct-impls.rs add comment to derive-debug-generic-with-lifetime.rs add comment to recursive-trait-bound-on-type-param.rs cleaned up const-static-ref-to-closure.rs add comment to const-iter-no-conflict-for-loop.rs --- .../associated-type-const-nomalization.rs | 1 + tests/ui/cast/cast-enum-const.rs | 12 +++---- tests/ui/cast/cast-to-box-arr.rs | 1 + tests/ui/cast/cast-to-char-compare.rs | 2 +- .../ui/consts/const-static-ref-to-closure.rs | 4 +-- .../derive-debug-generic-with-lifetime.rs | 1 + .../derive-debug-newtype-unsized-slice.rs | 1 + .../call-unit-struct-impl-fn-once.rs | 1 + tests/ui/fn_traits/fn-trait-explicit-call.rs | 1 + .../const-iter-no-conflict-for-loop.rs | 4 +++ tests/ui/resolve/shadow-primitives.rs | 33 ++++++++++--------- tests/ui/self/self-in-method-body-resolves.rs | 9 +++-- .../recursive-trait-bound-on-type-param.rs | 8 ++++- .../typeck/tuple-ref-order-distinct-impls.rs | 5 ++- tests/ui/ufcs/ufcs-trait-object-format.rs | 9 ++--- 15 files changed, 59 insertions(+), 33 deletions(-) diff --git a/tests/ui/associated-types/associated-type-const-nomalization.rs b/tests/ui/associated-types/associated-type-const-nomalization.rs index 576c7545924b..b7951ba9a435 100644 --- a/tests/ui/associated-types/associated-type-const-nomalization.rs +++ b/tests/ui/associated-types/associated-type-const-nomalization.rs @@ -1,3 +1,4 @@ +//! regression test for //@ check-pass trait Mirror { diff --git a/tests/ui/cast/cast-enum-const.rs b/tests/ui/cast/cast-enum-const.rs index 9cb02460f35b..cfad40c07b0e 100644 --- a/tests/ui/cast/cast-enum-const.rs +++ b/tests/ui/cast/cast-enum-const.rs @@ -1,14 +1,12 @@ +//! regression test for //@ run-pass -#![allow(non_upper_case_globals)] - -pub fn main() { - let _foo = 100; - const quux: isize = 5; +fn main() { + const QUUX: isize = 5; enum Stuff { - Bar = quux + Bar = QUUX, } - assert_eq!(Stuff::Bar as isize, quux); + assert_eq!(Stuff::Bar as isize, QUUX); } diff --git a/tests/ui/cast/cast-to-box-arr.rs b/tests/ui/cast/cast-to-box-arr.rs index 89c956913f93..1a9004cd074e 100644 --- a/tests/ui/cast/cast-to-box-arr.rs +++ b/tests/ui/cast/cast-to-box-arr.rs @@ -1,3 +1,4 @@ +//! regression test for //@ run-pass fn main() { let x = Box::new([1, 2, 3]); diff --git a/tests/ui/cast/cast-to-char-compare.rs b/tests/ui/cast/cast-to-char-compare.rs index 303bf7a57513..159b8ee04e02 100644 --- a/tests/ui/cast/cast-to-char-compare.rs +++ b/tests/ui/cast/cast-to-char-compare.rs @@ -1,6 +1,6 @@ +//! regression test for //@ check-pass - fn main() { if ('x' as char) < ('y' as char) { print!("x"); diff --git a/tests/ui/consts/const-static-ref-to-closure.rs b/tests/ui/consts/const-static-ref-to-closure.rs index 339aca037546..06b5ca5a935c 100644 --- a/tests/ui/consts/const-static-ref-to-closure.rs +++ b/tests/ui/consts/const-static-ref-to-closure.rs @@ -1,7 +1,7 @@ +//! regression test for //@ check-pass #![allow(dead_code)] -#![allow(non_upper_case_globals)] -const x: &'static dyn Fn() = &|| println!("ICE here"); +const X: &'static dyn Fn() = &|| println!("ICE here"); fn main() {} diff --git a/tests/ui/derives/derive-debug-generic-with-lifetime.rs b/tests/ui/derives/derive-debug-generic-with-lifetime.rs index c92853fb5dc2..430ade071795 100644 --- a/tests/ui/derives/derive-debug-generic-with-lifetime.rs +++ b/tests/ui/derives/derive-debug-generic-with-lifetime.rs @@ -1,3 +1,4 @@ +//! regression test for //@ check-pass #![allow(dead_code)] #[derive(Debug)] diff --git a/tests/ui/derives/derive-debug-newtype-unsized-slice.rs b/tests/ui/derives/derive-debug-newtype-unsized-slice.rs index 689c9f33af02..c735d9f039d2 100644 --- a/tests/ui/derives/derive-debug-newtype-unsized-slice.rs +++ b/tests/ui/derives/derive-debug-newtype-unsized-slice.rs @@ -1,3 +1,4 @@ +//! regression test for //@ check-pass #![allow(dead_code)] #[derive(Debug)] diff --git a/tests/ui/fn_traits/call-unit-struct-impl-fn-once.rs b/tests/ui/fn_traits/call-unit-struct-impl-fn-once.rs index a5693b3aca8e..15554482931b 100644 --- a/tests/ui/fn_traits/call-unit-struct-impl-fn-once.rs +++ b/tests/ui/fn_traits/call-unit-struct-impl-fn-once.rs @@ -1,3 +1,4 @@ +//! regression test for //@ run-pass #![feature(unboxed_closures)] #![feature(fn_traits)] diff --git a/tests/ui/fn_traits/fn-trait-explicit-call.rs b/tests/ui/fn_traits/fn-trait-explicit-call.rs index 364b07bf6922..f37e0a558baa 100644 --- a/tests/ui/fn_traits/fn-trait-explicit-call.rs +++ b/tests/ui/fn_traits/fn-trait-explicit-call.rs @@ -1,3 +1,4 @@ +//! regression test for //@ run-pass #![feature(fn_traits)] diff --git a/tests/ui/resolve/const-iter-no-conflict-for-loop.rs b/tests/ui/resolve/const-iter-no-conflict-for-loop.rs index 95edcb8695e2..ddbba64e5a31 100644 --- a/tests/ui/resolve/const-iter-no-conflict-for-loop.rs +++ b/tests/ui/resolve/const-iter-no-conflict-for-loop.rs @@ -1,3 +1,7 @@ +//! regression test for +//! Ensure that a constant named `iter` does not +//! interfere with the name resolution of the `iter` methods used internally +//! by `for` loops //@ run-pass #![allow(dead_code)] #![allow(non_upper_case_globals)] diff --git a/tests/ui/resolve/shadow-primitives.rs b/tests/ui/resolve/shadow-primitives.rs index 4018043c371e..17da0cd0530c 100644 --- a/tests/ui/resolve/shadow-primitives.rs +++ b/tests/ui/resolve/shadow-primitives.rs @@ -1,3 +1,4 @@ +//! regression test for //@ run-pass #![allow(dead_code)] #![allow(unused_variables)] @@ -31,17 +32,10 @@ mod char { mod char_ {} mod str { - use super::i8 as i8; - use super::i32_ as i32; - use super::i64_ as i64; - use super::u8_ as u8; - use super::f_ as f64; - use super::u16_ as u16; - use super::u32_ as u32; - use super::u64_ as u64; - use super::bool_ as bool; - use super::{bool_ as str}; - use super::char_ as char; + use super::{ + bool_ as bool, bool_ as str, char_ as char, f_ as f64, i8, i32_ as i32, i64_ as i64, + u8_ as u8, u16_ as u16, u32_ as u32, u64_ as u64, + }; } } @@ -49,7 +43,9 @@ trait isize_ { type isize; } -fn usize<'usize>(usize: &'usize usize) -> &'usize usize { usize } +fn usize<'usize>(usize: &'usize usize) -> &'usize usize { + usize +} mod reuse { use std::mem::size_of; @@ -68,9 +64,10 @@ mod reuse { mod guard { pub fn check() { use std::u8; // bring module u8 in scope - fn f() -> u8 { // OK, resolves to primitive u8, not to std::u8 + fn f() -> u8 { + // OK, resolves to primitive u8, not to std::u8 u8::max_value() // OK, resolves to associated function ::max_value, - // not to non-existent std::u8::max_value + // not to non-existent std::u8::max_value } assert_eq!(f(), u8::MAX); // OK, resolves to std::u8::MAX } @@ -79,7 +76,13 @@ mod guard { fn main() { let bool = true; let _ = match bool { - str @ true => if str { i32 as i64 } else { i64 }, + str @ true => { + if str { + i32 as i64 + } else { + i64 + } + } false => i64, }; diff --git a/tests/ui/self/self-in-method-body-resolves.rs b/tests/ui/self/self-in-method-body-resolves.rs index 95bb2af9b25c..636922cd87ce 100644 --- a/tests/ui/self/self-in-method-body-resolves.rs +++ b/tests/ui/self/self-in-method-body-resolves.rs @@ -1,11 +1,16 @@ +//! regression test for //@ check-pass #![allow(dead_code)] struct Foo; impl Foo { - fn new() -> Self { Foo } - fn bar() { Self::new(); } + fn new() -> Self { + Foo + } + fn bar() { + Self::new(); + } } fn main() {} diff --git a/tests/ui/traits/bound/recursive-trait-bound-on-type-param.rs b/tests/ui/traits/bound/recursive-trait-bound-on-type-param.rs index e97819e4122d..41ae91afad49 100644 --- a/tests/ui/traits/bound/recursive-trait-bound-on-type-param.rs +++ b/tests/ui/traits/bound/recursive-trait-bound-on-type-param.rs @@ -1,6 +1,12 @@ +//! regression test for //@ check-pass trait A {} -struct B where B: A> { t: T } +struct B +where + B: A>, +{ + t: T, +} fn main() {} diff --git a/tests/ui/typeck/tuple-ref-order-distinct-impls.rs b/tests/ui/typeck/tuple-ref-order-distinct-impls.rs index ad0affa4b0d2..fdede8a1d9c4 100644 --- a/tests/ui/typeck/tuple-ref-order-distinct-impls.rs +++ b/tests/ui/typeck/tuple-ref-order-distinct-impls.rs @@ -1,6 +1,9 @@ +//! regression test for //@ check-pass -trait Common { fn dummy(&self) { } } +trait Common { + fn dummy(&self) {} +} impl<'t, T> Common for (T, &'t T) {} diff --git a/tests/ui/ufcs/ufcs-trait-object-format.rs b/tests/ui/ufcs/ufcs-trait-object-format.rs index 2059365c7d62..7d50a2444806 100644 --- a/tests/ui/ufcs/ufcs-trait-object-format.rs +++ b/tests/ui/ufcs/ufcs-trait-object-format.rs @@ -1,8 +1,9 @@ //@ run-pass -// Regression test for #20676. Error was that we didn't support -// UFCS-style calls to a method in `Trait` where `Self` was bound to a -// trait object of type `Trait`. See also `ufcs-trait-object.rs`. - +//! Regression test for . +//! Error was that we didn't support +//! UFCS-style calls to a method in `Trait` where `Self` was bound to a +//! trait object of type `Trait`. +//! See also . use std::fmt; From de505d24db776bf399b9932f673f3f3de8c591a0 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Mon, 5 Jan 2026 08:08:02 +0100 Subject: [PATCH 0263/1061] tests/debuginfo/basic-stepping.rs: Don't mix `compile-flags` with `ignore-*` We want directives nice and tidy. --- tests/debuginfo/basic-stepping.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/debuginfo/basic-stepping.rs b/tests/debuginfo/basic-stepping.rs index ffb5d87710dc..72d4e354a6f1 100644 --- a/tests/debuginfo/basic-stepping.rs +++ b/tests/debuginfo/basic-stepping.rs @@ -5,9 +5,11 @@ //@ ignore-aarch64: Doesn't work yet. //@ ignore-loongarch64: Doesn't work yet. //@ ignore-riscv64: Doesn't work yet. -//@ compile-flags: -g //@ ignore-backends: gcc +// Debugger tests need debuginfo +//@ compile-flags: -g + //@ gdb-command: run // FIXME(#97083): Should we be able to break on initialization of zero-sized types? // FIXME(#97083): Right now the first breakable line is: From 622572f6df87a8b374159a8ee95a1195a600754b Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Tue, 7 Oct 2025 06:41:09 +0200 Subject: [PATCH 0264/1061] tests/debuginfo/basic-stepping.rs: Add revisions `default-mir-passes`, `no-SingleUseConsts-mir-pass` To prevent regressions our test must cover the code both inside and outside of the `SingleUseConsts` MIR pass. Use revisions for that. --- tests/debuginfo/basic-stepping.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/debuginfo/basic-stepping.rs b/tests/debuginfo/basic-stepping.rs index 72d4e354a6f1..744f8f5dd654 100644 --- a/tests/debuginfo/basic-stepping.rs +++ b/tests/debuginfo/basic-stepping.rs @@ -10,6 +10,10 @@ // Debugger tests need debuginfo //@ compile-flags: -g +// FIXME(#128945): SingleUseConsts shouldn't need to be disabled. +//@ revisions: default-mir-passes no-SingleUseConsts-mir-pass +//@ [no-SingleUseConsts-mir-pass] compile-flags: -Zmir-enable-passes=-SingleUseConsts + //@ gdb-command: run // FIXME(#97083): Should we be able to break on initialization of zero-sized types? // FIXME(#97083): Right now the first breakable line is: @@ -17,12 +21,12 @@ //@ gdb-command: next //@ gdb-check: let d = c = 99; //@ gdb-command: next -// FIXME(#33013): gdb-check: let e = "hi bob"; -// FIXME(#33013): gdb-command: next -// FIXME(#33013): gdb-check: let f = b"hi bob"; -// FIXME(#33013): gdb-command: next -// FIXME(#33013): gdb-check: let g = b'9'; -// FIXME(#33013): gdb-command: next +//@ [no-SingleUseConsts-mir-pass] gdb-check: let e = "hi bob"; +//@ [no-SingleUseConsts-mir-pass] gdb-command: next +//@ [no-SingleUseConsts-mir-pass] gdb-check: let f = b"hi bob"; +//@ [no-SingleUseConsts-mir-pass] gdb-command: next +//@ [no-SingleUseConsts-mir-pass] gdb-check: let g = b'9'; +//@ [no-SingleUseConsts-mir-pass] gdb-command: next //@ gdb-check: let h = ["whatever"; 8]; //@ gdb-command: next //@ gdb-check: let i = [1,2,3,4]; From 38ab51943c5726ce71f5656e8345e0487f94e2ce Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Jan 2026 09:28:05 +0100 Subject: [PATCH 0265/1061] ./x check miri: enable check_only feature --- src/bootstrap/src/core/build_steps/check.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index df82b7baa9f9..7da2551c76fe 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -793,8 +793,7 @@ tool_check_step!(Clippy { path: "src/tools/clippy", mode: Mode::ToolRustcPrivate tool_check_step!(Miri { path: "src/tools/miri", mode: Mode::ToolRustcPrivate, - enable_features: ["stack-cache"], - default_features: false, + enable_features: ["check_only"], }); tool_check_step!(CargoMiri { path: "src/tools/miri/cargo-miri", mode: Mode::ToolRustcPrivate }); tool_check_step!(Rustfmt { path: "src/tools/rustfmt", mode: Mode::ToolRustcPrivate }); From 0330cc24468ac4a009df902a4313c472448658bf Mon Sep 17 00:00:00 2001 From: Khashayar Fereidani Date: Mon, 5 Jan 2026 13:14:11 +0330 Subject: [PATCH 0266/1061] Add feature flag `likely/unlikely` for alloc --- library/alloc/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index b659e904c8a0..595329c38fc2 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -126,6 +126,7 @@ #![feature(iter_next_chunk)] #![feature(layout_for_ptr)] #![feature(legacy_receiver_trait)] +#![feature(likely_unlikely)] #![feature(local_waker)] #![feature(maybe_uninit_uninit_array_transpose)] #![feature(panic_internals)] From bd79ea1b743cccde61ffda92ba4f41abdfab515c Mon Sep 17 00:00:00 2001 From: Khashayar Fereidani Date: Mon, 5 Jan 2026 13:18:41 +0330 Subject: [PATCH 0267/1061] Improve and optimize retain_mut implementation --- library/alloc/src/vec/mod.rs | 117 +++++++++++++++++------------------ 1 file changed, 56 insertions(+), 61 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index f8a96e358d6d..4e76a34a72c7 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -86,7 +86,7 @@ use core::mem::{self, Assume, ManuallyDrop, MaybeUninit, SizedTypeProperties, Tr use core::ops::{self, Index, IndexMut, Range, RangeBounds}; use core::ptr::{self, NonNull}; use core::slice::{self, SliceIndex}; -use core::{fmt, intrinsics, ub_checks}; +use core::{fmt, hint, intrinsics, ub_checks}; #[stable(feature = "extract_if", since = "1.87.0")] pub use self::extract_if::ExtractIf; @@ -2292,13 +2292,8 @@ impl Vec { return; } - // Avoid double drop if the drop guard is not executed, - // since we may make some holes during the process. - unsafe { self.set_len(0) }; - // Vec: [Kept, Kept, Hole, Hole, Hole, Hole, Unchecked, Unchecked] - // |<- processed len ->| ^- next to check - // |<- deleted cnt ->| + // | ^- write ^- read | // |<- original_len ->| // Kept: Elements which predicate returns true on. // Hole: Moved or dropped element slot. @@ -2307,77 +2302,77 @@ impl Vec { // This drop guard will be invoked when predicate or `drop` of element panicked. // It shifts unchecked elements to cover holes and `set_len` to the correct length. // In cases when predicate and `drop` never panick, it will be optimized out. - struct BackshiftOnDrop<'a, T, A: Allocator> { + struct PanicGuard<'a, T, A: Allocator> { v: &'a mut Vec, - processed_len: usize, - deleted_cnt: usize, + read: usize, + write: usize, original_len: usize, } - impl Drop for BackshiftOnDrop<'_, T, A> { + impl Drop for PanicGuard<'_, T, A> { + #[cold] fn drop(&mut self) { - if self.deleted_cnt > 0 { - // SAFETY: Trailing unchecked items must be valid since we never touch them. - unsafe { - ptr::copy( - self.v.as_ptr().add(self.processed_len), - self.v.as_mut_ptr().add(self.processed_len - self.deleted_cnt), - self.original_len - self.processed_len, - ); - } + let remaining = self.original_len - self.read; + // SAFETY: Trailing unchecked items must be valid since we never touch them. + unsafe { + ptr::copy( + self.v.as_ptr().add(self.read), + self.v.as_mut_ptr().add(self.write), + remaining, + ); } // SAFETY: After filling holes, all items are in contiguous memory. unsafe { - self.v.set_len(self.original_len - self.deleted_cnt); + self.v.set_len(self.write + remaining); } } } - let mut g = BackshiftOnDrop { v: self, processed_len: 0, deleted_cnt: 0, original_len }; - - fn process_loop( - original_len: usize, - f: &mut F, - g: &mut BackshiftOnDrop<'_, T, A>, - ) where - F: FnMut(&mut T) -> bool, - { - while g.processed_len != original_len { - // SAFETY: Unchecked element must be valid. - let cur = unsafe { &mut *g.v.as_mut_ptr().add(g.processed_len) }; - if !f(cur) { - // Advance early to avoid double drop if `drop_in_place` panicked. - g.processed_len += 1; - g.deleted_cnt += 1; - // SAFETY: We never touch this element again after dropped. - unsafe { ptr::drop_in_place(cur) }; - // We already advanced the counter. - if DELETED { - continue; - } else { - break; - } - } - if DELETED { - // SAFETY: `deleted_cnt` > 0, so the hole slot must not overlap with current element. - // We use copy for move, and never touch this element again. - unsafe { - let hole_slot = g.v.as_mut_ptr().add(g.processed_len - g.deleted_cnt); - ptr::copy_nonoverlapping(cur, hole_slot, 1); - } - } - g.processed_len += 1; + let mut read = 0; + loop { + // SAFETY: read < original_len + let cur = unsafe { self.get_unchecked_mut(read) }; + if hint::unlikely(!f(cur)) { + break; + } + read += 1; + if read == original_len { + // All elements are kept, return early. + return; } } - // Stage 1: Nothing was deleted. - process_loop::(original_len, &mut f, &mut g); + // Critical section starts here and at least one element is going to be removed. + // Advance `g.read` early to avoid double drop if `drop_in_place` panicked. + let mut g = PanicGuard { v: self, read: read + 1, write: read, original_len }; + // SAFETY: previous `read` is always less than original_len. + unsafe { ptr::drop_in_place(&mut *g.v.as_mut_ptr().add(read)) }; - // Stage 2: Some elements were deleted. - process_loop::(original_len, &mut f, &mut g); + while g.read < g.original_len { + // SAFETY: `read` is always less than original_len. + let cur = unsafe { &mut *g.v.as_mut_ptr().add(g.read) }; + if !f(cur) { + // Advance `read` early to avoid double drop if `drop_in_place` panicked. + g.read += 1; + // SAFETY: We never touch this element again after dropped. + unsafe { ptr::drop_in_place(cur) }; + } else { + // SAFETY: `read` > `write`, so the slots don't overlap. + // We use copy for move, and never touch the source element again. + unsafe { + let hole = g.v.as_mut_ptr().add(g.write); + ptr::copy_nonoverlapping(cur, hole, 1); + } + g.write += 1; + g.read += 1; + } + } - // All item are processed. This can be optimized to `set_len` by LLVM. - drop(g); + // We are leaving the critical section and no panic happened, + // Commit the length change and forget the guard. + // SAFETY: `write` is always less than or equal to original_len. + unsafe { g.v.set_len(g.write) }; + mem::forget(g); } /// Removes all but the first of consecutive elements in the vector that resolve to the same From 75eaa452681e8008a24a7bd2ce8d44bad38d5a44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 31 Dec 2025 13:23:13 +0100 Subject: [PATCH 0268/1061] Allow building cg_gcc without building libgccjit --- src/bootstrap/src/core/build_steps/compile.rs | 106 ++++++++---------- 1 file changed, 47 insertions(+), 59 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 762aeea9f451..adfb3c21d38e 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -19,7 +19,7 @@ use serde_derive::Deserialize; #[cfg(feature = "tracing")] use tracing::span; -use crate::core::build_steps::gcc::{Gcc, GccOutput, GccTargetPair, add_cg_gcc_cargo_flags}; +use crate::core::build_steps::gcc::{Gcc, GccOutput, GccTargetPair}; use crate::core::build_steps::tool::{RustcPrivateCompilers, SourceType, copy_lld_artifacts}; use crate::core::build_steps::{dist, llvm}; use crate::core::builder; @@ -1569,21 +1569,29 @@ impl Step for RustcLink { } /// Set of `libgccjit` dylibs that can be used by `cg_gcc` to compile code for a set of targets. +/// `libgccjit` requires a separate build for each `(host, target)` pair. +/// So if you are on linux-x64 and build for linux-aarch64, you will need at least: +/// - linux-x64 -> linux-x64 libgccjit (for building host code like proc macros) +/// - linux-x64 -> linux-aarch64 libgccjit (for the aarch64 target code) #[derive(Clone)] pub struct GccDylibSet { dylibs: BTreeMap, - host_pair: GccTargetPair, } impl GccDylibSet { - /// Returns the libgccjit.so dylib that corresponds to a host target on which `cg_gcc` will be - /// executed, and which will target the host. So e.g. if `cg_gcc` will be executed on - /// x86_64-unknown-linux-gnu, the host dylib will be for compilation pair - /// `(x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu)`. - fn host_dylib(&self) -> &GccOutput { - self.dylibs.get(&self.host_pair).unwrap_or_else(|| { - panic!("libgccjit.so was not built for host target {}", self.host_pair) - }) + /// Build a set of libgccjit dylibs that will be executed on `host` and will generate code for + /// each specified target. + pub fn build( + builder: &Builder<'_>, + host: TargetSelection, + targets: Vec, + ) -> Self { + let dylibs = targets + .iter() + .map(|t| GccTargetPair::for_target_pair(host, *t)) + .map(|target_pair| (target_pair, builder.ensure(Gcc { target_pair }))) + .collect(); + Self { dylibs } } /// Install the libgccjit dylibs to the corresponding target directories of the given compiler. @@ -1626,39 +1634,28 @@ impl GccDylibSet { /// Output of the `compile::GccCodegenBackend` step. /// -/// It contains paths to all built libgccjit libraries on which this backend depends here. +/// It contains a build stamp with the path to the built cg_gcc dylib. #[derive(Clone)] pub struct GccCodegenBackendOutput { stamp: BuildStamp, - dylib_set: GccDylibSet, } /// Builds the GCC codegen backend (`cg_gcc`). -/// The `cg_gcc` backend uses `libgccjit`, which requires a separate build for each -/// `host -> target` pair. So if you are on linux-x64 and build for linux-aarch64, -/// you will need at least: -/// - linux-x64 -> linux-x64 libgccjit (for building host code like proc macros) -/// - linux-x64 -> linux-aarch64 libgccjit (for the aarch64 target code) -/// -/// We model this by having a single cg_gcc for a given host target, which contains one -/// libgccjit per (host, target) pair. -/// Note that the host target is taken from `self.compilers.target_compiler.host`. +/// Note that this **does not** build libgccjit, which is a dependency of cg_gcc. +/// That has to be built separately, because a separate copy of libgccjit is required +/// for each (host, target) compilation pair. +/// cg_gcc goes to great lengths to ensure that it does not *directly* link to libgccjit, +/// so we respect that here and allow building cg_gcc without building libgccjit itself. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct GccCodegenBackend { compilers: RustcPrivateCompilers, - targets: Vec, + target: TargetSelection, } impl GccCodegenBackend { - /// Build `cg_gcc` that will run on host `H` (`compilers.target_compiler.host`) and will be - /// able to produce code target pairs (`H`, `T`) for all `T` from `targets`. - pub fn for_targets( - compilers: RustcPrivateCompilers, - mut targets: Vec, - ) -> Self { - // Sort targets to improve step cache hits - targets.sort(); - Self { compilers, targets } + /// Build `cg_gcc` that will run on the given host target. + pub fn for_target(compilers: RustcPrivateCompilers, target: TargetSelection) -> Self { + Self { compilers, target } } } @@ -1672,10 +1669,8 @@ impl Step for GccCodegenBackend { } fn make_run(run: RunConfig<'_>) { - // By default, build cg_gcc that will only be able to compile native code for the given - // host target. let compilers = RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target); - run.builder.ensure(GccCodegenBackend { compilers, targets: vec![run.target] }); + run.builder.ensure(GccCodegenBackend::for_target(compilers, run.target)); } fn run(self, builder: &Builder<'_>) -> Self::Output { @@ -1689,18 +1684,6 @@ impl Step for GccCodegenBackend { &CodegenBackendKind::Gcc, ); - let dylib_set = GccDylibSet { - dylibs: self - .targets - .iter() - .map(|&target| { - let target_pair = GccTargetPair::for_target_pair(host, target); - (target_pair, builder.ensure(Gcc { target_pair })) - }) - .collect(), - host_pair: GccTargetPair::for_native_build(host), - }; - if builder.config.keep_stage.contains(&build_compiler.stage) { trace!("`keep-stage` requested"); builder.info( @@ -1709,7 +1692,7 @@ impl Step for GccCodegenBackend { ); // Codegen backends are linked separately from this step today, so we don't do // anything here. - return GccCodegenBackendOutput { stamp, dylib_set }; + return GccCodegenBackendOutput { stamp }; } let mut cargo = builder::Cargo::new( @@ -1723,15 +1706,12 @@ impl Step for GccCodegenBackend { cargo.arg("--manifest-path").arg(builder.src.join("compiler/rustc_codegen_gcc/Cargo.toml")); rustc_cargo_env(builder, &mut cargo, host); - add_cg_gcc_cargo_flags(&mut cargo, dylib_set.host_dylib()); - let _guard = builder.msg(Kind::Build, "codegen backend gcc", Mode::Codegen, build_compiler, host); let files = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false); GccCodegenBackendOutput { stamp: write_codegen_backend_stamp(stamp, files, builder.config.dry_run()), - dylib_set, } } @@ -2457,12 +2437,18 @@ impl Step for Assemble { // GCC dylibs built below by taking a look at the current stage and whether // cg_gcc is used as the default codegen backend. + // First, the easy part: build cg_gcc let compilers = prepare_compilers(); + let cg_gcc = builder + .ensure(GccCodegenBackend::for_target(compilers, target_compiler.host)); + copy_codegen_backends_to_sysroot(builder, cg_gcc.stamp, target_compiler); + + // Then, the hard part: prepare all required libgccjit dylibs. // The left side of the target pairs below is implied. It has to match the - // host target on which cg_gcc will run, which is the host target of + // host target on which libgccjit will be used, which is the host target of // `target_compiler`. We only pass the right side of the target pairs to - // the `GccCodegenBackend` constructor. + // the `GccDylibSet` constructor. let mut targets = HashSet::new(); // Add all host targets, so that we are able to build host code in this // bootstrap invocation using cg_gcc. @@ -2477,14 +2463,16 @@ impl Step for Assemble { // host code (e.g. proc macros) using cg_gcc. targets.insert(compilers.target_compiler().host); - let output = builder.ensure(GccCodegenBackend::for_targets( - compilers, + // Now build all the required libgccjit dylibs + let dylib_set = GccDylibSet::build( + builder, + compilers.target_compiler().host, targets.into_iter().collect(), - )); - copy_codegen_backends_to_sysroot(builder, output.stamp, target_compiler); - // Also copy all requires libgccjit dylibs to the corresponding - // library sysroots, so that they are available for the codegen backend. - output.dylib_set.install_to(builder, target_compiler); + ); + + // And then copy all the dylibs to the corresponding + // library sysroots, so that they are available for cg_gcc. + dylib_set.install_to(builder, target_compiler); } CodegenBackendKind::Llvm | CodegenBackendKind::Custom(_) => continue, } From 2b53ecaff4ab1a7c8279ca182c6433f488312b50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 31 Dec 2025 13:39:15 +0100 Subject: [PATCH 0269/1061] Add a dist step for the GCC codegen backend --- src/bootstrap/src/core/build_steps/compile.rs | 6 + src/bootstrap/src/core/build_steps/dist.rs | 125 +++++++++++++++--- src/bootstrap/src/core/builder/mod.rs | 1 + src/bootstrap/src/utils/tarball.rs | 7 + src/tools/opt-dist/src/main.rs | 1 + 5 files changed, 123 insertions(+), 17 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index adfb3c21d38e..a42d46a8c018 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1640,6 +1640,12 @@ pub struct GccCodegenBackendOutput { stamp: BuildStamp, } +impl GccCodegenBackendOutput { + pub fn stamp(&self) -> &BuildStamp { + &self.stamp + } +} + /// Builds the GCC codegen backend (`cg_gcc`). /// Note that this **does not** build libgccjit, which is a dependency of cg_gcc. /// That has to be built separately, because a separate copy of libgccjit is required diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 0e7051cc22df..f47b0c0b0072 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1652,23 +1652,7 @@ impl Step for CraneliftCodegenBackend { return None; } - // Get the relative path of where the codegen backend should be stored. - let backends_dst = builder.sysroot_codegen_backends(compilers.target_compiler()); - let backends_rel = backends_dst - .strip_prefix(builder.sysroot(compilers.target_compiler())) - .unwrap() - .strip_prefix(builder.sysroot_libdir_relative(compilers.target_compiler())) - .unwrap(); - // Don't use custom libdir here because ^lib/ will be resolved again with installer - let backends_dst = PathBuf::from("lib").join(backends_rel); - - let codegen_backend_dylib = get_codegen_backend_file(&stamp); - tarball.add_renamed_file( - &codegen_backend_dylib, - &backends_dst, - &normalize_codegen_backend_name(builder, &codegen_backend_dylib), - FileType::NativeLibrary, - ); + add_codegen_backend_to_tarball(builder, &tarball, compilers.target_compiler(), &stamp); Some(tarball.generate()) } @@ -1681,6 +1665,113 @@ impl Step for CraneliftCodegenBackend { } } +/// Builds a dist component containing the GCC codegen backend. +/// Note that for this backend to work, it must have a set of libgccjit dylibs available +/// at runtime. +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct GccCodegenBackend { + pub compilers: RustcPrivateCompilers, + pub target: TargetSelection, +} + +impl Step for GccCodegenBackend { + type Output = Option; + const IS_HOST: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.alias("rustc_codegen_gcc") + } + + fn is_default_step(builder: &Builder<'_>) -> bool { + // We only want to build the gcc backend in `x dist` if the backend was enabled + // in rust.codegen-backends. + // Sadly, we don't have access to the actual target for which we're disting clif here.. + // So we just use the host target. + builder + .config + .enabled_codegen_backends(builder.host_target) + .contains(&CodegenBackendKind::Gcc) + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(GccCodegenBackend { + compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target), + target: run.target, + }); + } + + fn run(self, builder: &Builder<'_>) -> Option { + // This prevents rustc_codegen_gcc from being built for "dist" + // or "install" on the stable/beta channels. It is not yet stable and + // should not be included. + if !builder.build.unstable_features() { + return None; + } + + let target = self.target; + if target != "x86_64-unknown-linux-gnu" { + builder + .info(&format!("target `{target}` not supported by rustc_codegen_gcc. skipping")); + return None; + } + + let mut tarball = Tarball::new(builder, "rustc-codegen-gcc", &target.triple); + tarball.set_overlay(OverlayKind::RustcCodegenGcc); + tarball.is_preview(true); + tarball.add_legal_and_readme_to("share/doc/rustc_codegen_gcc"); + + let compilers = self.compilers; + let backend = builder.ensure(compile::GccCodegenBackend::for_target(compilers, target)); + + if builder.config.dry_run() { + return None; + } + + add_codegen_backend_to_tarball( + builder, + &tarball, + compilers.target_compiler(), + backend.stamp(), + ); + + Some(tarball.generate()) + } + + fn metadata(&self) -> Option { + Some( + StepMetadata::dist("rustc_codegen_gcc", self.target) + .built_by(self.compilers.build_compiler()), + ) + } +} + +/// Add a codegen backend built for `compiler`, with its artifacts stored in `stamp`, to the given +/// `tarball` at the correct place. +fn add_codegen_backend_to_tarball( + builder: &Builder<'_>, + tarball: &Tarball<'_>, + compiler: Compiler, + stamp: &BuildStamp, +) { + // Get the relative path of where the codegen backend should be stored. + let backends_dst = builder.sysroot_codegen_backends(compiler); + let backends_rel = backends_dst + .strip_prefix(builder.sysroot(compiler)) + .unwrap() + .strip_prefix(builder.sysroot_libdir_relative(compiler)) + .unwrap(); + // Don't use custom libdir here because ^lib/ will be resolved again with installer + let backends_dst = PathBuf::from("lib").join(backends_rel); + + let codegen_backend_dylib = get_codegen_backend_file(stamp); + tarball.add_renamed_file( + &codegen_backend_dylib, + &backends_dst, + &normalize_codegen_backend_name(builder, &codegen_backend_dylib), + FileType::NativeLibrary, + ); +} + #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Rustfmt { pub compilers: RustcPrivateCompilers, diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 92a6eb8ce837..0164cc5310c2 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -967,6 +967,7 @@ impl<'a> Builder<'a> { dist::Mingw, dist::Rustc, dist::CraneliftCodegenBackend, + dist::GccCodegenBackend, dist::Std, dist::RustcDev, dist::Analysis, diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index 079afb7a0054..7db06dcc3e9a 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -25,6 +25,7 @@ pub(crate) enum OverlayKind { Rustfmt, RustAnalyzer, RustcCodegenCranelift, + RustcCodegenGcc, LlvmBitcodeLinker, } @@ -66,6 +67,11 @@ impl OverlayKind { "compiler/rustc_codegen_cranelift/LICENSE-APACHE", "compiler/rustc_codegen_cranelift/LICENSE-MIT", ], + OverlayKind::RustcCodegenGcc => &[ + "compiler/rustc_codegen_gcc/Readme.md", + "compiler/rustc_codegen_gcc/LICENSE-APACHE", + "compiler/rustc_codegen_gcc/LICENSE-MIT", + ], OverlayKind::LlvmBitcodeLinker => &[ "COPYRIGHT", "LICENSE-APACHE", @@ -93,6 +99,7 @@ impl OverlayKind { .rust_analyzer_info .version(builder, &builder.release_num("rust-analyzer/crates/rust-analyzer")), OverlayKind::RustcCodegenCranelift => builder.rust_version(), + OverlayKind::RustcCodegenGcc => builder.rust_version(), OverlayKind::LlvmBitcodeLinker => builder.rust_version(), } } diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs index 5515dbf1940e..b17cfb567e5b 100644 --- a/src/tools/opt-dist/src/main.rs +++ b/src/tools/opt-dist/src/main.rs @@ -456,6 +456,7 @@ fn main() -> anyhow::Result<()> { "rustfmt", "generate-copyright", "bootstrap", + "rustc_codegen_gcc", ] { build_args.extend(["--skip".to_string(), target.to_string()]); } From 9b789f0bd05477690eaf01dc8698f34678652f09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 31 Dec 2025 13:39:23 +0100 Subject: [PATCH 0270/1061] Dist cg_gcc on CI --- src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh index 9579e0d79cb0..f77a0d562f03 100755 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh @@ -7,7 +7,9 @@ python3 ../x.py build --set rust.debug=true opt-dist ./build/$HOSTS/stage1-tools-bin/opt-dist linux-ci -- python3 ../x.py dist \ --host $HOSTS --target $HOSTS \ --include-default-paths \ - build-manifest bootstrap + build-manifest \ + bootstrap \ + rustc_codegen_gcc # Use GCC for building GCC components, as it seems to behave badly when built with Clang # Only build GCC on full builds, not try builds From 04707f4f86ea0b484da9c368dcb81fdfb7939bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 2 Jan 2026 10:05:30 +0100 Subject: [PATCH 0271/1061] Only keep old cg_gcc if the stamp file actually exists --- src/bootstrap/src/core/build_steps/compile.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index a42d46a8c018..02be3f2cc735 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1690,7 +1690,7 @@ impl Step for GccCodegenBackend { &CodegenBackendKind::Gcc, ); - if builder.config.keep_stage.contains(&build_compiler.stage) { + if builder.config.keep_stage.contains(&build_compiler.stage) && stamp.path().exists() { trace!("`keep-stage` requested"); builder.info( "WARNING: Using a potentially old codegen backend. \ From 304101f21241f8ba3692b5c917e23252a37709b0 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 4 Jan 2026 18:39:59 +1100 Subject: [PATCH 0272/1061] Move all `thir::Pat` creation into `rustc_mir_build::thir::pattern` --- compiler/rustc_mir_build/src/thir/cx/block.rs | 24 +------------- compiler/rustc_mir_build/src/thir/cx/mod.rs | 22 +++++++++---- .../rustc_mir_build/src/thir/pattern/mod.rs | 32 +++++++++++++++++-- 3 files changed, 46 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs index 57ddb8eddb8e..7cdd70a7fc27 100644 --- a/compiler/rustc_mir_build/src/thir/cx/block.rs +++ b/compiler/rustc_mir_build/src/thir/cx/block.rs @@ -2,8 +2,6 @@ use rustc_hir as hir; use rustc_index::Idx; use rustc_middle::middle::region; use rustc_middle::thir::*; -use rustc_middle::ty; -use rustc_middle::ty::CanonicalUserTypeAnnotation; use tracing::debug; use crate::thir::cx::ThirBuildCx; @@ -73,29 +71,9 @@ impl<'tcx> ThirBuildCx<'tcx> { let else_block = local.els.map(|els| self.mirror_block(els)); - let mut pattern = self.pattern_from_hir(local.pat); + let pattern = self.pattern_from_hir_with_annotation(local.pat, local.ty); debug!(?pattern); - if let Some(ty) = &local.ty - && let Some(&user_ty) = - self.typeck_results.user_provided_types().get(ty.hir_id) - { - debug!("mirror_stmts: user_ty={:?}", user_ty); - let annotation = CanonicalUserTypeAnnotation { - user_ty: Box::new(user_ty), - span: ty.span, - inferred_ty: self.typeck_results.node_type(ty.hir_id), - }; - pattern = Box::new(Pat { - ty: pattern.ty, - span: pattern.span, - kind: PatKind::AscribeUserType { - ascription: Ascription { annotation, variance: ty::Covariant }, - subpattern: pattern, - }, - }); - } - let span = match local.init { Some(init) => local.span.with_hi(init.span.hi()), None => local.span, diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index d26dfac0c2ab..79e85a243f40 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -12,9 +12,6 @@ use rustc_hir::{self as hir, HirId, find_attr}; use rustc_middle::bug; use rustc_middle::thir::*; use rustc_middle::ty::{self, TyCtxt}; -use tracing::instrument; - -use crate::thir::pattern::pat_from_hir; /// Query implementation for [`TyCtxt::thir_body`]. pub(crate) fn thir_body( @@ -111,9 +108,22 @@ impl<'tcx> ThirBuildCx<'tcx> { } } - #[instrument(level = "debug", skip(self))] - fn pattern_from_hir(&mut self, p: &'tcx hir::Pat<'tcx>) -> Box> { - pat_from_hir(self.tcx, self.typing_env, self.typeck_results, p) + fn pattern_from_hir(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box> { + self.pattern_from_hir_with_annotation(pat, None) + } + + fn pattern_from_hir_with_annotation( + &mut self, + pat: &'tcx hir::Pat<'tcx>, + let_stmt_type: Option<&hir::Ty<'tcx>>, + ) -> Box> { + crate::thir::pattern::pat_from_hir( + self.tcx, + self.typing_env, + self.typeck_results, + pat, + let_stmt_type, + ) } fn closure_env_param(&self, owner_def: LocalDefId, expr_id: HirId) -> Option> { diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 0310003e7d58..76890316ba44 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -38,11 +38,14 @@ struct PatCtxt<'tcx> { rust_2024_migration: Option>, } +#[instrument(level = "debug", skip(tcx, typing_env, typeck_results), ret)] pub(super) fn pat_from_hir<'tcx>( tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, typeck_results: &'tcx ty::TypeckResults<'tcx>, pat: &'tcx hir::Pat<'tcx>, + // Present if `pat` came from a let statement with an explicit type annotation + let_stmt_type: Option<&hir::Ty<'tcx>>, ) -> Box> { let mut pcx = PatCtxt { tcx, @@ -53,12 +56,35 @@ pub(super) fn pat_from_hir<'tcx>( .get(pat.hir_id) .map(PatMigration::new), }; - let result = pcx.lower_pattern(pat); - debug!("pat_from_hir({:?}) = {:?}", pat, result); + + let mut thir_pat = pcx.lower_pattern(pat); + + // If this pattern came from a let statement with an explicit type annotation + // (e.g. `let x: Foo = ...`), retain that user type information in the THIR pattern. + if let Some(let_stmt_type) = let_stmt_type + && let Some(&user_ty) = typeck_results.user_provided_types().get(let_stmt_type.hir_id) + { + debug!(?user_ty); + let annotation = CanonicalUserTypeAnnotation { + user_ty: Box::new(user_ty), + span: let_stmt_type.span, + inferred_ty: typeck_results.node_type(let_stmt_type.hir_id), + }; + thir_pat = Box::new(Pat { + ty: thir_pat.ty, + span: thir_pat.span, + kind: PatKind::AscribeUserType { + ascription: Ascription { annotation, variance: ty::Covariant }, + subpattern: thir_pat, + }, + }); + } + if let Some(m) = pcx.rust_2024_migration { m.emit(tcx, pat.hir_id); } - result + + thir_pat } impl<'tcx> PatCtxt<'tcx> { From 3d6a2c5ae1685cda3a1ec8357a21fc7f76c7c6be Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Mon, 5 Jan 2026 12:05:23 +0000 Subject: [PATCH 0273/1061] relate.rs: tiny cleanup: eliminate temp vars 2 --- compiler/rustc_type_ir/src/relate.rs | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index 9e14bf6b60ad..3610605462ba 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -216,11 +216,7 @@ impl Relate for ty::AliasTy { b: ty::AliasTy, ) -> RelateResult> { if a.def_id != b.def_id { - Err(TypeError::ProjectionMismatched({ - let a = a.def_id; - let b = b.def_id; - ExpectedFound::new(a, b) - })) + Err(TypeError::ProjectionMismatched(ExpectedFound::new(a.def_id, b.def_id))) } else { let cx = relation.cx(); let args = if let Some(variances) = cx.opt_alias_variances(a.kind(cx), a.def_id) { @@ -240,11 +236,7 @@ impl Relate for ty::AliasTerm { b: ty::AliasTerm, ) -> RelateResult> { if a.def_id != b.def_id { - Err(TypeError::ProjectionMismatched({ - let a = a.def_id; - let b = b.def_id; - ExpectedFound::new(a, b) - })) + Err(TypeError::ProjectionMismatched(ExpectedFound::new(a.def_id, b.def_id))) } else { let args = match a.kind(relation.cx()) { ty::AliasTermKind::OpaqueTy => relate_args_with_variances( @@ -275,11 +267,7 @@ impl Relate for ty::ExistentialProjection { b: ty::ExistentialProjection, ) -> RelateResult> { if a.def_id != b.def_id { - Err(TypeError::ProjectionMismatched({ - let a = a.def_id; - let b = b.def_id; - ExpectedFound::new(a, b) - })) + Err(TypeError::ProjectionMismatched(ExpectedFound::new(a.def_id, b.def_id))) } else { let term = relation.relate_with_variance( ty::Invariant, From a956b56d6db0f9ad54b555b8ef52539c0c6b3bc2 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Mon, 5 Jan 2026 14:10:50 +0100 Subject: [PATCH 0274/1061] Improve comment clarity in candidate_may_shadow --- compiler/rustc_hir_typeck/src/method/probe.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 1a25f6a582f2..beb0337d8c59 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -190,8 +190,8 @@ impl PickConstraintsForShadowed { // An item never shadows itself candidate.item.def_id != self.def_id // and we're only concerned about inherent impls doing the shadowing. - // Shadowing can only occur if the shadowed is further along - // the Receiver dereferencing chain than the shadowed. + // Shadowing can only occur if the impl being shadowed is further along + // the Receiver dereferencing chain than the impl doing the shadowing. && match candidate.kind { CandidateKind::InherentImplCandidate { receiver_steps, .. } => match self.receiver_steps { Some(shadowed_receiver_steps) => receiver_steps > shadowed_receiver_steps, From c5f67830c2a1395da5589a87e84facbcfe30ea54 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Fri, 19 Dec 2025 10:27:38 -0800 Subject: [PATCH 0275/1061] Convert Windows to use check_shim_sig instead of check_shim_sig_lenient --- src/tools/miri/src/shims/sig.rs | 11 +- .../miri/src/shims/windows/foreign_items.rs | 605 ++++++++++++++---- src/tools/miri/tests/pass-dep/getrandom.rs | 2 + src/tools/miri/tests/pass/tls/windows-tls.rs | 8 +- 4 files changed, 497 insertions(+), 129 deletions(-) diff --git a/src/tools/miri/src/shims/sig.rs b/src/tools/miri/src/shims/sig.rs index bc5e7f584f50..a49689d11fd7 100644 --- a/src/tools/miri/src/shims/sig.rs +++ b/src/tools/miri/src/shims/sig.rs @@ -17,11 +17,14 @@ pub struct ShimSig<'tcx, const ARGS: usize> { /// Construct a `ShimSig` with convenient syntax: /// ```rust,ignore -/// shim_sig!(this, extern "C" fn (*const T, i32) -> usize) +/// shim_sig!(extern "C" fn (*const T, i32) -> usize) /// ``` +/// +/// In type position, `winapi::` can be used as a shorthand for the full path used by +/// `windows_ty_layout`. #[macro_export] macro_rules! shim_sig { - (extern $abi:literal fn($($arg:ty),*) -> $ret:ty) => { + (extern $abi:literal fn($($arg:ty),* $(,)?) -> $ret:ty) => { |this| $crate::shims::sig::ShimSig { abi: std::str::FromStr::from_str($abi).expect("incorrect abi specified"), args: [$(shim_sig_arg!(this, $arg)),*], @@ -53,7 +56,9 @@ macro_rules! shim_sig_arg { "*const _" => $this.machine.layouts.const_raw_ptr.ty, "*mut _" => $this.machine.layouts.mut_raw_ptr.ty, ty if let Some(libc_ty) = ty.strip_prefix("libc::") => $this.libc_ty_layout(libc_ty).ty, - ty => panic!("unsupported signature type {ty:?}"), + ty if let Some(win_ty) = ty.strip_prefix("winapi::") => + $this.windows_ty_layout(win_ty).ty, + ty => helpers::path_ty_layout($this, &ty.split("::").collect::>()).ty, } }}; } diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index 3bc52dddfe8b..1905fb22e26a 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -2,11 +2,11 @@ use std::ffi::OsStr; use std::path::{self, Path, PathBuf}; use std::{io, iter, str}; -use rustc_abi::{Align, CanonAbi, Size, X86Call}; +use rustc_abi::{Align, Size}; use rustc_middle::ty::Ty; use rustc_span::Symbol; use rustc_target::callconv::FnAbi; -use rustc_target::spec::{Arch, Env}; +use rustc_target::spec::Env; use self::shims::windows::handle::{Handle, PseudoHandle}; use crate::shims::os_str::bytes_to_os_str; @@ -137,65 +137,93 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); - // According to - // https://github.com/rust-lang/rust/blob/fb00adbdb69266f10df95a4527b767b0ad35ea48/compiler/rustc_target/src/spec/mod.rs#L2766-L2768, - // x86-32 Windows uses a different calling convention than other Windows targets - // for the "system" ABI. - let sys_conv = if this.tcx.sess.target.arch == Arch::X86 { - CanonAbi::X86(X86Call::Stdcall) - } else { - CanonAbi::C - }; - // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern. // Windows API stubs. - // HANDLE = isize - // NTSTATUS = LONH = i32 + // HANDLE = *mut c_void (formerly: isize) + // NTSTATUS = LONG = i32 // DWORD = ULONG = u32 // BOOL = i32 // BOOLEAN = u8 match link_name.as_str() { // Environment related shims "GetEnvironmentVariableW" => { - let [name, buf, size] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [name, buf, size] = this.check_shim_sig( + shim_sig!(extern "system" fn(*const _, *mut _, u32) -> u32), + link_name, + abi, + args, + )?; let result = this.GetEnvironmentVariableW(name, buf, size)?; this.write_scalar(result, dest)?; } "SetEnvironmentVariableW" => { - let [name, value] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [name, value] = this.check_shim_sig( + shim_sig!(extern "system" fn(*const _, *const _) -> winapi::BOOL), + link_name, + abi, + args, + )?; let result = this.SetEnvironmentVariableW(name, value)?; this.write_scalar(result, dest)?; } "GetEnvironmentStringsW" => { - let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [] = this.check_shim_sig( + shim_sig!(extern "system" fn() -> *mut _), + link_name, + abi, + args, + )?; let result = this.GetEnvironmentStringsW()?; this.write_pointer(result, dest)?; } "FreeEnvironmentStringsW" => { - let [env_block] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [env_block] = this.check_shim_sig( + shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL), + link_name, + abi, + args, + )?; let result = this.FreeEnvironmentStringsW(env_block)?; this.write_scalar(result, dest)?; } "GetCurrentDirectoryW" => { - let [size, buf] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [size, buf] = this.check_shim_sig( + shim_sig!(extern "system" fn(u32, *mut _) -> u32), + link_name, + abi, + args, + )?; let result = this.GetCurrentDirectoryW(size, buf)?; this.write_scalar(result, dest)?; } "SetCurrentDirectoryW" => { - let [path] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [path] = this.check_shim_sig( + shim_sig!(extern "system" fn(*const _) -> winapi::BOOL), + link_name, + abi, + args, + )?; let result = this.SetCurrentDirectoryW(path)?; this.write_scalar(result, dest)?; } "GetUserProfileDirectoryW" => { - let [token, buf, size] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [token, buf, size] = this.check_shim_sig( + shim_sig!(extern "system" fn(winapi::HANDLE, *mut _, *mut _) -> winapi::BOOL), + link_name, + abi, + args, + )?; let result = this.GetUserProfileDirectoryW(token, buf, size)?; this.write_scalar(result, dest)?; } "GetCurrentProcessId" => { - let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [] = this.check_shim_sig( + shim_sig!(extern "system" fn() -> u32), + link_name, + abi, + args, + )?; let result = this.GetCurrentProcessId()?; this.write_scalar(result, dest)?; } @@ -212,7 +240,24 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { n, byte_offset, key, - ] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + ] = this.check_shim_sig( + shim_sig!( + extern "system" fn( + winapi::HANDLE, + winapi::HANDLE, + *mut _, + *mut _, + *mut _, + *mut _, + u32, + *mut _, + *mut _, + ) -> i32 + ), + link_name, + abi, + args, + )?; this.NtWriteFile( handle, event, @@ -237,7 +282,24 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { n, byte_offset, key, - ] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + ] = this.check_shim_sig( + shim_sig!( + extern "system" fn( + winapi::HANDLE, + winapi::HANDLE, + *mut _, + *mut _, + *mut _, + *mut _, + u32, + *mut _, + *mut _, + ) -> i32 + ), + link_name, + abi, + args, + )?; this.NtReadFile( handle, event, @@ -252,8 +314,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { )?; } "GetFullPathNameW" => { - let [filename, size, buffer, filepart] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [filename, size, buffer, filepart] = this.check_shim_sig( + shim_sig!(extern "system" fn(*const _, u32, *mut _, *mut _) -> u32), + link_name, + abi, + args, + )?; this.check_no_isolation("`GetFullPathNameW`")?; let filename = this.read_pointer(filename)?; @@ -290,7 +356,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { creation_disposition, flags_and_attributes, template_file, - ] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + ] = this.check_shim_sig( + shim_sig!( + extern "system" fn( + *const _, + u32, + u32, + *mut _, + u32, + u32, + winapi::HANDLE, + ) -> winapi::HANDLE + ), + link_name, + abi, + args, + )?; let handle = this.CreateFileW( file_name, desired_access, @@ -303,29 +384,60 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(handle.to_scalar(this), dest)?; } "GetFileInformationByHandle" => { - let [handle, info] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [handle, info] = this.check_shim_sig( + shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> winapi::BOOL), + link_name, + abi, + args, + )?; let res = this.GetFileInformationByHandle(handle, info)?; this.write_scalar(res, dest)?; } "SetFileInformationByHandle" => { - let [handle, class, info, size] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [handle, class, info, size] = this.check_shim_sig( + shim_sig!( + extern "system" fn( + winapi::HANDLE, + winapi::FILE_INFO_BY_HANDLE_CLASS, + *mut _, + u32, + ) -> winapi::BOOL + ), + link_name, + abi, + args, + )?; let res = this.SetFileInformationByHandle(handle, class, info, size)?; this.write_scalar(res, dest)?; } "FlushFileBuffers" => { - let [handle] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [handle] = this.check_shim_sig( + shim_sig!(extern "system" fn(winapi::HANDLE) -> winapi::BOOL), + link_name, + abi, + args, + )?; let res = this.FlushFileBuffers(handle)?; this.write_scalar(res, dest)?; } "DeleteFileW" => { - let [file_name] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [file_name] = this.check_shim_sig( + shim_sig!(extern "system" fn(*const _) -> winapi::BOOL), + link_name, + abi, + args, + )?; let res = this.DeleteFileW(file_name)?; this.write_scalar(res, dest)?; } "SetFilePointerEx" => { - let [file, distance_to_move, new_file_pointer, move_method] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [file, distance_to_move, new_file_pointer, move_method] = this.check_shim_sig( + // i64 is actually a LARGE_INTEGER union of {u32, i32} and {i64} + shim_sig!(extern "system" fn(winapi::HANDLE, i64, *mut _, u32) -> winapi::BOOL), + link_name, + abi, + args, + )?; let res = this.SetFilePointerEx(file, distance_to_move, new_file_pointer, move_method)?; this.write_scalar(res, dest)?; @@ -333,8 +445,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Allocation "HeapAlloc" => { - let [handle, flags, size] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [handle, flags, size] = this.check_shim_sig( + shim_sig!(extern "system" fn(winapi::HANDLE, u32, usize) -> *mut _), + link_name, + abi, + args, + )?; this.read_target_isize(handle)?; let flags = this.read_scalar(flags)?.to_u32()?; let size = this.read_target_usize(size)?; @@ -356,8 +472,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_pointer(ptr, dest)?; } "HeapFree" => { - let [handle, flags, ptr] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [handle, flags, ptr] = this.check_shim_sig( + shim_sig!(extern "system" fn(winapi::HANDLE, u32, *mut _) -> winapi::BOOL), + link_name, + abi, + args, + )?; this.read_target_isize(handle)?; this.read_scalar(flags)?.to_u32()?; let ptr = this.read_pointer(ptr)?; @@ -369,8 +489,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_i32(1), dest)?; } "HeapReAlloc" => { - let [handle, flags, old_ptr, size] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [handle, flags, old_ptr, size] = this.check_shim_sig( + shim_sig!(extern "system" fn(winapi::HANDLE, u32, *mut _, usize) -> *mut _), + link_name, + abi, + args, + )?; this.read_target_isize(handle)?; this.read_scalar(flags)?.to_u32()?; let old_ptr = this.read_pointer(old_ptr)?; @@ -390,7 +514,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_pointer(new_ptr, dest)?; } "LocalFree" => { - let [ptr] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [ptr] = this.check_shim_sig( + shim_sig!(extern "system" fn(winapi::HLOCAL) -> winapi::HLOCAL), + link_name, + abi, + args, + )?; let ptr = this.read_pointer(ptr)?; // "If the hMem parameter is NULL, LocalFree ignores the parameter and returns NULL." // (https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-localfree) @@ -402,17 +531,32 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // errno "SetLastError" => { - let [error] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [error] = this.check_shim_sig( + shim_sig!(extern "system" fn(u32) -> ()), + link_name, + abi, + args, + )?; let error = this.read_scalar(error)?; this.set_last_error(error)?; } "GetLastError" => { - let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [] = this.check_shim_sig( + shim_sig!(extern "system" fn() -> u32), + link_name, + abi, + args, + )?; let last_error = this.get_last_error()?; this.write_scalar(last_error, dest)?; } "RtlNtStatusToDosError" => { - let [status] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [status] = this.check_shim_sig( + shim_sig!(extern "system" fn(i32) -> u32), + link_name, + abi, + args, + )?; let status = this.read_scalar(status)?.to_u32()?; let err = match status { // STATUS_MEDIA_WRITE_PROTECTED => ERROR_WRITE_PROTECT @@ -434,7 +578,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Querying system information "GetSystemInfo" => { // Also called from `page_size` crate. - let [system_info] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [system_info] = this.check_shim_sig( + shim_sig!(extern "system" fn(*mut _) -> ()), + link_name, + abi, + args, + )?; let system_info = this.deref_pointer_as(system_info, this.windows_ty_layout("SYSTEM_INFO"))?; // Initialize with `0`. @@ -457,19 +606,34 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // This just creates a key; Windows does not natively support TLS destructors. // Create key and return it. - let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [] = this.check_shim_sig( + shim_sig!(extern "system" fn() -> u32), + link_name, + abi, + args, + )?; let key = this.machine.tls.create_tls_key(None, dest.layout.size)?; this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - let [key] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [key] = this.check_shim_sig( + shim_sig!(extern "system" fn(u32) -> *mut _), + link_name, + abi, + args, + )?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "TlsSetValue" => { - let [key, new_ptr] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [key, new_ptr] = this.check_shim_sig( + shim_sig!(extern "system" fn(u32, *mut _) -> winapi::BOOL), + link_name, + abi, + args, + )?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.active_thread(); let new_data = this.read_scalar(new_ptr)?; @@ -479,7 +643,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_int(1, dest)?; } "TlsFree" => { - let [key] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [key] = this.check_shim_sig( + shim_sig!(extern "system" fn(u32) -> winapi::BOOL), + link_name, + abi, + args, + )?; let key = u128::from(this.read_scalar(key)?.to_u32()?); this.machine.tls.delete_tls_key(key)?; @@ -489,7 +658,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Access to command-line arguments "GetCommandLineW" => { - let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [] = this.check_shim_sig( + shim_sig!(extern "system" fn() -> *mut _), + link_name, + abi, + args, + )?; this.write_pointer( this.machine.cmd_line.expect("machine must be initialized"), dest, @@ -498,31 +672,51 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Time related shims "GetSystemTimeAsFileTime" | "GetSystemTimePreciseAsFileTime" => { - #[allow(non_snake_case)] - let [LPFILETIME] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; - this.GetSystemTimeAsFileTime(link_name.as_str(), LPFILETIME)?; + let [filetime] = this.check_shim_sig( + shim_sig!(extern "system" fn(*mut _) -> ()), + link_name, + abi, + args, + )?; + this.GetSystemTimeAsFileTime(link_name.as_str(), filetime)?; } "QueryPerformanceCounter" => { - #[allow(non_snake_case)] - let [lpPerformanceCount] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; - let result = this.QueryPerformanceCounter(lpPerformanceCount)?; + let [performance_count] = this.check_shim_sig( + shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL), + link_name, + abi, + args, + )?; + let result = this.QueryPerformanceCounter(performance_count)?; this.write_scalar(result, dest)?; } "QueryPerformanceFrequency" => { - #[allow(non_snake_case)] - let [lpFrequency] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; - let result = this.QueryPerformanceFrequency(lpFrequency)?; + let [frequency] = this.check_shim_sig( + shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL), + link_name, + abi, + args, + )?; + let result = this.QueryPerformanceFrequency(frequency)?; this.write_scalar(result, dest)?; } "Sleep" => { - let [timeout] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [timeout] = this.check_shim_sig( + shim_sig!(extern "system" fn(u32) -> ()), + link_name, + abi, + args, + )?; this.Sleep(timeout)?; } "CreateWaitableTimerExW" => { - let [attributes, name, flags, access] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [attributes, name, flags, access] = this.check_shim_sig( + shim_sig!(extern "system" fn(*mut _, *const _, u32, u32) -> winapi::HANDLE), + link_name, + abi, + args, + )?; this.read_pointer(attributes)?; this.read_pointer(name)?; this.read_scalar(flags)?.to_u32()?; @@ -535,40 +729,66 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Synchronization primitives "InitOnceBeginInitialize" => { - let [ptr, flags, pending, context] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [ptr, flags, pending, context] = this.check_shim_sig( + shim_sig!(extern "system" fn(*mut _, u32, *mut _, *mut _) -> winapi::BOOL), + link_name, + abi, + args, + )?; this.InitOnceBeginInitialize(ptr, flags, pending, context, dest)?; } "InitOnceComplete" => { - let [ptr, flags, context] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [ptr, flags, context] = this.check_shim_sig( + shim_sig!(extern "system" fn(*mut _, u32, *mut _) -> winapi::BOOL), + link_name, + abi, + args, + )?; let result = this.InitOnceComplete(ptr, flags, context)?; this.write_scalar(result, dest)?; } "WaitOnAddress" => { - let [ptr_op, compare_op, size_op, timeout_op] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [ptr_op, compare_op, size_op, timeout_op] = this.check_shim_sig( + // First pointer is volatile + shim_sig!(extern "system" fn(*mut _, *mut _, usize, u32) -> winapi::BOOL), + link_name, + abi, + args, + )?; this.WaitOnAddress(ptr_op, compare_op, size_op, timeout_op, dest)?; } "WakeByAddressSingle" => { - let [ptr_op] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [ptr_op] = this.check_shim_sig( + shim_sig!(extern "system" fn(*mut _) -> ()), + link_name, + abi, + args, + )?; this.WakeByAddressSingle(ptr_op)?; } "WakeByAddressAll" => { - let [ptr_op] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [ptr_op] = this.check_shim_sig( + shim_sig!(extern "system" fn(*mut _) -> ()), + link_name, + abi, + args, + )?; this.WakeByAddressAll(ptr_op)?; } // Dynamic symbol loading "GetProcAddress" => { - #[allow(non_snake_case)] - let [hModule, lpProcName] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; - this.read_target_isize(hModule)?; - let name = this.read_c_str(this.read_pointer(lpProcName)?)?; + let [module, proc_name] = this.check_shim_sig( + shim_sig!(extern "system" fn(winapi::HMODULE, *const _) -> winapi::FARPROC), + link_name, + abi, + args, + )?; + this.read_target_isize(module)?; + let name = this.read_c_str(this.read_pointer(proc_name)?)?; if let Ok(name) = str::from_utf8(name) && is_dyn_sym(name) { @@ -581,8 +801,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Threading "CreateThread" => { - let [security, stacksize, start, arg, flags, thread] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [security, stacksize, start, arg, flags, thread] = this.check_shim_sig( + shim_sig!( + extern "system" fn( + *mut _, + usize, + *mut _, + *mut _, + u32, + *mut _, + ) -> winapi::HANDLE + ), + link_name, + abi, + args, + )?; let thread_id = this.CreateThread(security, stacksize, start, arg, flags, thread)?; @@ -590,13 +823,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?; } "WaitForSingleObject" => { - let [handle, timeout] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [handle, timeout] = this.check_shim_sig( + shim_sig!(extern "system" fn(winapi::HANDLE, u32) -> u32), + link_name, + abi, + args, + )?; this.WaitForSingleObject(handle, timeout, dest)?; } "GetCurrentProcess" => { - let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [] = this.check_shim_sig( + shim_sig!(extern "system" fn() -> winapi::HANDLE), + link_name, + abi, + args, + )?; this.write_scalar( Handle::Pseudo(PseudoHandle::CurrentProcess).to_scalar(this), @@ -604,7 +846,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { )?; } "GetCurrentThread" => { - let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [] = this.check_shim_sig( + shim_sig!(extern "system" fn() -> winapi::HANDLE), + link_name, + abi, + args, + )?; this.write_scalar( Handle::Pseudo(PseudoHandle::CurrentThread).to_scalar(this), @@ -612,7 +859,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { )?; } "SetThreadDescription" => { - let [handle, name] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [handle, name] = this.check_shim_sig( + shim_sig!(extern "system" fn(winapi::HANDLE, *const _) -> i32), + link_name, + abi, + args, + )?; let handle = this.read_handle(handle, "SetThreadDescription")?; let name = this.read_wide_str(this.read_pointer(name)?)?; @@ -627,8 +879,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_u32(0), dest)?; } "GetThreadDescription" => { - let [handle, name_ptr] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [handle, name_ptr] = this.check_shim_sig( + shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> i32), + link_name, + abi, + args, + )?; let handle = this.read_handle(handle, "GetThreadDescription")?; let name_ptr = this.deref_pointer_as(name_ptr, this.machine.layouts.mut_raw_ptr)?; // the pointer where we should store the ptr to the name @@ -651,7 +907,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } "GetThreadId" => { - let [handle] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [handle] = this.check_shim_sig( + shim_sig!(extern "system" fn(winapi::HANDLE) -> u32), + link_name, + abi, + args, + )?; let handle = this.read_handle(handle, "GetThreadId")?; let thread = match handle { Handle::Thread(thread) => thread, @@ -662,7 +923,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_u32(tid), dest)?; } "GetCurrentThreadId" => { - let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [] = this.check_shim_sig( + shim_sig!(extern "system" fn() -> u32), + link_name, + abi, + args, + )?; let thread = this.active_thread(); let tid = this.get_tid(thread); this.write_scalar(Scalar::from_u32(tid), dest)?; @@ -670,7 +936,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Miscellaneous "ExitProcess" => { - let [code] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [code] = this.check_shim_sig( + shim_sig!(extern "system" fn(u32) -> ()), + link_name, + abi, + args, + )?; // Windows technically uses u32, but we unify everything to a Unix-style i32. let code = this.read_scalar(code)?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit { code, leak_check: false }); @@ -678,7 +949,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "SystemFunction036" => { // used by getrandom 0.1 // This is really 'RtlGenRandom'. - let [ptr, len] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [ptr, len] = this.check_shim_sig( + // Returns winapi::BOOLEAN, which is a byte + shim_sig!(extern "system" fn(*mut _, u32) -> u8), + link_name, + abi, + args, + )?; let ptr = this.read_pointer(ptr)?; let len = this.read_scalar(len)?.to_u32()?; this.gen_random(ptr, len.into())?; @@ -686,7 +963,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "ProcessPrng" => { // used by `std` - let [ptr, len] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [ptr, len] = this.check_shim_sig( + shim_sig!(extern "system" fn(*mut _, usize) -> winapi::BOOL), + link_name, + abi, + args, + )?; let ptr = this.read_pointer(ptr)?; let len = this.read_target_usize(len)?; this.gen_random(ptr, len)?; @@ -694,8 +976,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "BCryptGenRandom" => { // used by getrandom 0.2 - let [algorithm, ptr, len, flags] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [algorithm, ptr, len, flags] = this.check_shim_sig( + shim_sig!(extern "system" fn(*mut _, *mut _, u32, u32) -> i32), + link_name, + abi, + args, + )?; let algorithm = this.read_scalar(algorithm)?; let algorithm = algorithm.to_target_usize(this)?; let ptr = this.read_pointer(ptr)?; @@ -729,8 +1015,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "GetConsoleScreenBufferInfo" => { // `term` needs this, so we fake it. - let [console, buffer_info] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [console, buffer_info] = this.check_shim_sig( + shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> winapi::BOOL), + link_name, + abi, + args, + )?; this.read_target_isize(console)?; // FIXME: this should use deref_pointer_as, but CONSOLE_SCREEN_BUFFER_INFO is not in std this.deref_pointer(buffer_info)?; @@ -739,13 +1029,33 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } "GetStdHandle" => { - let [which] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [which] = this.check_shim_sig( + shim_sig!(extern "system" fn(u32) -> winapi::HANDLE), + link_name, + abi, + args, + )?; let res = this.GetStdHandle(which)?; this.write_scalar(res, dest)?; } "DuplicateHandle" => { let [src_proc, src_handle, target_proc, target_handle, access, inherit, options] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + this.check_shim_sig( + shim_sig!( + extern "system" fn( + winapi::HANDLE, + winapi::HANDLE, + winapi::HANDLE, + *mut _, + u32, + winapi::BOOL, + u32, + ) -> winapi::BOOL + ), + link_name, + abi, + args, + )?; let res = this.DuplicateHandle( src_proc, src_handle, @@ -758,15 +1068,24 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } "CloseHandle" => { - let [handle] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [handle] = this.check_shim_sig( + shim_sig!(extern "system" fn(winapi::HANDLE) -> winapi::BOOL), + link_name, + abi, + args, + )?; let ret = this.CloseHandle(handle)?; this.write_scalar(ret, dest)?; } "GetModuleFileNameW" => { - let [handle, filename, size] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [handle, filename, size] = this.check_shim_sig( + shim_sig!(extern "system" fn(winapi::HMODULE, *mut _, u32) -> u32), + link_name, + abi, + args, + )?; this.check_no_isolation("`GetModuleFileNameW`")?; let handle = this.read_handle(handle, "GetModuleFileNameW")?; @@ -799,8 +1118,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } "FormatMessageW" => { - let [flags, module, message_id, language_id, buffer, size, arguments] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [flags, module, message_id, language_id, buffer, size, arguments] = this + .check_shim_sig( + shim_sig!( + extern "system" fn(u32, *const _, u32, u32, *mut _, u32, *mut _) -> u32 + ), + link_name, + abi, + args, + )?; let flags = this.read_scalar(flags)?.to_u32()?; let _module = this.read_pointer(module)?; // seems to contain a module name @@ -843,7 +1169,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ); } // This function looks and behaves excatly like miri_start_unwind. - let [payload] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [payload] = this.check_shim_sig( + shim_sig!(extern "C" fn(*mut _) -> unwind::libunwind::_Unwind_Reason_Code), + link_name, + abi, + args, + )?; this.handle_miri_start_unwind(payload)?; return interp_ok(EmulateItemResult::NeedsUnwind); } @@ -851,56 +1182,86 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "GetProcessHeap" if this.frame_in_std() => { - let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [] = this.check_shim_sig( + shim_sig!(extern "system" fn() -> winapi::HANDLE), + link_name, + abi, + args, + )?; // Just fake a HANDLE // It's fine to not use the Handle type here because its a stub this.write_int(1, dest)?; } "GetModuleHandleA" if this.frame_in_std() => { - #[allow(non_snake_case)] - let [_lpModuleName] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [_module_name] = this.check_shim_sig( + shim_sig!(extern "system" fn(*const _) -> winapi::HMODULE), + link_name, + abi, + args, + )?; // We need to return something non-null here to make `compat_fn!` work. this.write_int(1, dest)?; } "SetConsoleTextAttribute" if this.frame_in_std() => { - #[allow(non_snake_case)] - let [_hConsoleOutput, _wAttribute] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [_console_output, _attribute] = this.check_shim_sig( + shim_sig!(extern "system" fn(winapi::HANDLE, u16) -> winapi::BOOL), + link_name, + abi, + args, + )?; // Pretend these does not exist / nothing happened, by returning zero. this.write_null(dest)?; } "GetConsoleMode" if this.frame_in_std() => { - let [console, mode] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [console, mode] = this.check_shim_sig( + shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> winapi::BOOL), + link_name, + abi, + args, + )?; this.read_target_isize(console)?; this.deref_pointer_as(mode, this.machine.layouts.u32)?; // Indicate an error. this.write_null(dest)?; } "GetFileType" if this.frame_in_std() => { - #[allow(non_snake_case)] - let [_hFile] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [_file] = this.check_shim_sig( + shim_sig!(extern "system" fn(winapi::HANDLE) -> u32), + link_name, + abi, + args, + )?; // Return unknown file type. this.write_null(dest)?; } "AddVectoredExceptionHandler" if this.frame_in_std() => { - #[allow(non_snake_case)] - let [_First, _Handler] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [_first, _handler] = this.check_shim_sig( + shim_sig!(extern "system" fn(u32, *mut _) -> *mut _), + link_name, + abi, + args, + )?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_int(1, dest)?; } "SetThreadStackGuarantee" if this.frame_in_std() => { - #[allow(non_snake_case)] - let [_StackSizeInBytes] = - this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [_stack_size_in_bytes] = this.check_shim_sig( + shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL), + link_name, + abi, + args, + )?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_int(1, dest)?; } // this is only callable from std because we know that std ignores the return value "SwitchToThread" if this.frame_in_std() => { - let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let [] = this.check_shim_sig( + shim_sig!(extern "system" fn() -> winapi::BOOL), + link_name, + abi, + args, + )?; this.yield_active_thread(); diff --git a/src/tools/miri/tests/pass-dep/getrandom.rs b/src/tools/miri/tests/pass-dep/getrandom.rs index d359730e7f97..9adb48fb1c3c 100644 --- a/src/tools/miri/tests/pass-dep/getrandom.rs +++ b/src/tools/miri/tests/pass-dep/getrandom.rs @@ -12,6 +12,8 @@ fn main() { #[cfg(not(target_os = "solaris"))] getrandom_01::getrandom(&mut data).unwrap(); + // On Windows, getrandom 0.2 uses the wrong return type for BCryptGenRandom + #[cfg(not(target_os = "windows"))] getrandom_02::getrandom(&mut data).unwrap(); getrandom_03::fill(&mut data).unwrap(); diff --git a/src/tools/miri/tests/pass/tls/windows-tls.rs b/src/tools/miri/tests/pass/tls/windows-tls.rs index 58131be19037..9c5e8eea4d3f 100644 --- a/src/tools/miri/tests/pass/tls/windows-tls.rs +++ b/src/tools/miri/tests/pass/tls/windows-tls.rs @@ -5,14 +5,14 @@ use std::ptr; extern "system" { fn TlsAlloc() -> u32; - fn TlsSetValue(key: u32, val: *mut c_void) -> bool; + fn TlsSetValue(key: u32, val: *mut c_void) -> i32; fn TlsGetValue(key: u32) -> *mut c_void; - fn TlsFree(key: u32) -> bool; + fn TlsFree(key: u32) -> i32; } fn main() { let key = unsafe { TlsAlloc() }; - assert!(unsafe { TlsSetValue(key, ptr::without_provenance_mut(1)) }); + assert!(unsafe { TlsSetValue(key, ptr::without_provenance_mut(1)) != 0 }); assert_eq!(unsafe { TlsGetValue(key).addr() }, 1); - assert!(unsafe { TlsFree(key) }); + assert!(unsafe { TlsFree(key) != 0 }); } From 00693a8b2523ff78fd8d0f62bad17ccaa5f7e422 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Jan 2026 15:10:44 +0100 Subject: [PATCH 0276/1061] tweak shim_sig --- src/tools/miri/src/shims/sig.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/tools/miri/src/shims/sig.rs b/src/tools/miri/src/shims/sig.rs index a49689d11fd7..e88cc66b6ea5 100644 --- a/src/tools/miri/src/shims/sig.rs +++ b/src/tools/miri/src/shims/sig.rs @@ -20,8 +20,12 @@ pub struct ShimSig<'tcx, const ARGS: usize> { /// shim_sig!(extern "C" fn (*const T, i32) -> usize) /// ``` /// -/// In type position, `winapi::` can be used as a shorthand for the full path used by -/// `windows_ty_layout`. +/// The following types are supported: +/// - primitive integer types +/// - `()` +/// - (thin) raw pointers, written `*const _` and `*mut _` since the pointee type is irrelevant +/// - `$crate::$mod::...::$ty` for a type from the given crate (most commonly that is `libc`) +/// - `winapi::$ty` for a type from `std::sys::pal::windows::c` #[macro_export] macro_rules! shim_sig { (extern $abi:literal fn($($arg:ty),* $(,)?) -> $ret:ty) => { @@ -55,10 +59,11 @@ macro_rules! shim_sig_arg { "()" => $this.tcx.types.unit, "*const _" => $this.machine.layouts.const_raw_ptr.ty, "*mut _" => $this.machine.layouts.mut_raw_ptr.ty, - ty if let Some(libc_ty) = ty.strip_prefix("libc::") => $this.libc_ty_layout(libc_ty).ty, ty if let Some(win_ty) = ty.strip_prefix("winapi::") => $this.windows_ty_layout(win_ty).ty, - ty => helpers::path_ty_layout($this, &ty.split("::").collect::>()).ty, + ty if ty.contains("::") => + helpers::path_ty_layout($this, &ty.split("::").collect::>()).ty, + ty => panic!("unsupported signature type {ty:?}"), } }}; } From ba13bb44edd8a96c6de25e98ac70d9b6eefc163e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 5 Jan 2026 08:05:20 -0800 Subject: [PATCH 0277/1061] Update wasm-component-ld Same as 147495, just keeping it up-to-date. --- Cargo.lock | 53 +++++++++++++------------- src/tools/wasm-component-ld/Cargo.toml | 2 +- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 816bb1a37859..470b38d5a91c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6221,9 +6221,9 @@ dependencies = [ [[package]] name = "wasi-preview1-component-adapter-provider" -version = "38.0.4" +version = "40.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ec3ef3783e18f2457796ed91b1e6c2adc46f2905f740d1527ab3053fe8e5682" +checksum = "bb5e2b9858989c3a257de4ca169977f4f79897b64e4f482f188f4fcf8ac557d1" [[package]] name = "wasm-bindgen" @@ -6272,17 +6272,18 @@ dependencies = [ [[package]] name = "wasm-component-ld" -version = "0.5.19" +version = "0.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bfc50dd0b883d841bc1dba5ff7020ca52fa7b2c3bb1266d8bf6a09dd032e115" +checksum = "846d20ed66ae37b7a237e36dfcd2fdc979eae82a46cdb0586f9bba80782fd789" dependencies = [ "anyhow", "clap", + "clap_lex", "lexopt", "libc", "tempfile", "wasi-preview1-component-adapter-provider", - "wasmparser 0.241.2", + "wasmparser 0.243.0", "wat", "windows-sys 0.61.2", "winsplit", @@ -6309,24 +6310,24 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.241.2" +version = "0.243.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01164c9dda68301e34fdae536c23ed6fe90ce6d97213ccc171eebbd3d02d6b8" +checksum = "c55db9c896d70bd9fa535ce83cd4e1f2ec3726b0edd2142079f594fc3be1cb35" dependencies = [ "leb128fmt", - "wasmparser 0.241.2", + "wasmparser 0.243.0", ] [[package]] name = "wasm-metadata" -version = "0.241.2" +version = "0.243.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876fe286f2fa416386deedebe8407e6f19e0b5aeaef3d03161e77a15fa80f167" +checksum = "eae05bf9579f45a62e8d0a4e3f52eaa8da518883ac5afa482ec8256c329ecd56" dependencies = [ "anyhow", "indexmap", - "wasm-encoder 0.241.2", - "wasmparser 0.241.2", + "wasm-encoder 0.243.0", + "wasmparser 0.243.0", ] [[package]] @@ -6351,9 +6352,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.241.2" +version = "0.243.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46d90019b1afd4b808c263e428de644f3003691f243387d30d673211ee0cb8e8" +checksum = "f6d8db401b0528ec316dfbe579e6ab4152d61739cfe076706d2009127970159d" dependencies = [ "bitflags", "hashbrown 0.15.5", @@ -6364,22 +6365,22 @@ dependencies = [ [[package]] name = "wast" -version = "241.0.2" +version = "243.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63f66e07e2ddf531fef6344dbf94d112df7c2f23ed6ffb10962e711500b8d816" +checksum = "df21d01c2d91e46cb7a221d79e58a2d210ea02020d57c092e79255cc2999ca7f" dependencies = [ "bumpalo", "leb128fmt", "memchr", "unicode-width 0.2.2", - "wasm-encoder 0.241.2", + "wasm-encoder 0.243.0", ] [[package]] name = "wat" -version = "1.241.2" +version = "1.243.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45f923705c40830af909c5dec2352ec2821202e4a66008194585e1917458a26d" +checksum = "226a9a91cd80a50449312fef0c75c23478fcecfcc4092bdebe1dc8e760ef521b" dependencies = [ "wast", ] @@ -6775,9 +6776,9 @@ dependencies = [ [[package]] name = "wit-component" -version = "0.241.2" +version = "0.243.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0c57df25e7ee612d946d3b7646c1ddb2310f8280aa2c17e543b66e0812241" +checksum = "36f9fc53513e461ce51dcf17a3e331752cb829f1d187069e54af5608fc998fe4" dependencies = [ "anyhow", "bitflags", @@ -6786,17 +6787,17 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "wasm-encoder 0.241.2", + "wasm-encoder 0.243.0", "wasm-metadata", - "wasmparser 0.241.2", + "wasmparser 0.243.0", "wit-parser", ] [[package]] name = "wit-parser" -version = "0.241.2" +version = "0.243.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ef1c6ad67f35c831abd4039c02894de97034100899614d1c44e2268ad01c91" +checksum = "df983a8608e513d8997f435bb74207bf0933d0e49ca97aa9d8a6157164b9b7fc" dependencies = [ "anyhow", "id-arena", @@ -6807,7 +6808,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.241.2", + "wasmparser 0.243.0", ] [[package]] diff --git a/src/tools/wasm-component-ld/Cargo.toml b/src/tools/wasm-component-ld/Cargo.toml index 744b67c17f65..2d44358c7433 100644 --- a/src/tools/wasm-component-ld/Cargo.toml +++ b/src/tools/wasm-component-ld/Cargo.toml @@ -10,4 +10,4 @@ name = "wasm-component-ld" path = "src/main.rs" [dependencies] -wasm-component-ld = "0.5.19" +wasm-component-ld = "0.5.20" From 1925afb7b08e3de09af0bb06fd60fbc3ce82b178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 5 Jan 2026 17:18:52 +0100 Subject: [PATCH 0278/1061] Enable merge queue in new bors --- rust-bors.toml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rust-bors.toml b/rust-bors.toml index 384343e431dc..0d59918e3f77 100644 --- a/rust-bors.toml +++ b/rust-bors.toml @@ -29,8 +29,7 @@ labels_blocking_approval = [ # If CI runs quicker than this duration, consider it to be a failure min_ci_time = 600 -# Flip this once new bors is used for actual merges on this repository -merge_queue_enabled = false +merge_queue_enabled = true report_merge_conflicts = true [labels] @@ -55,7 +54,9 @@ try_failed = [ "-S-waiting-on-review", "-S-waiting-on-crater" ] -auto_build_succeeded = ["+merged-by-bors"] +auto_build_succeeded = [ + "+merged-by-bors" +] auto_build_failed = [ "+S-waiting-on-review", "-S-blocked", From accfc34e43b0fb6ef9ac162ca256ae270b6d468e Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Thu, 11 Dec 2025 10:31:33 -0500 Subject: [PATCH 0279/1061] rustc_codegen_llvm: update alignment for double on AIX This was recently fixed upstream in LLVM, so we update our default layout to match. @rustbot label: +llvm-main --- compiler/rustc_codegen_llvm/src/context.rs | 4 ++++ compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 07b04863af6b..4b2544b7efdf 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -211,6 +211,10 @@ pub(crate) unsafe fn create_module<'ll>( // LLVM 22 updated the NVPTX layout to indicate 256-bit vector load/store: https://github.com/llvm/llvm-project/pull/155198 target_data_layout = target_data_layout.replace("-i256:256", ""); } + if sess.target.arch == Arch::PowerPC64 { + // LLVM 22 updated the ABI alignment for double on AIX: https://github.com/llvm/llvm-project/pull/144673 + target_data_layout = target_data_layout.replace("-f64:32:64", ""); + } } // Ensure the data-layout values hardcoded remain the defaults. diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs b/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs index b4f394643a9d..b83f5544a351 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs @@ -17,7 +17,8 @@ pub(crate) fn target() -> Target { std: None, // ? }, pointer_width: 64, - data_layout: "E-m:a-Fi64-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512".into(), + data_layout: "E-m:a-Fi64-i64:64-i128:128-n32:64-f64:32:64-S128-v256:256:256-v512:512:512" + .into(), arch: Arch::PowerPC64, options: base, } From 85c8e41f62f1c347f2b5c2f5f008a238ecff22e9 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Mon, 5 Jan 2026 09:01:23 +0000 Subject: [PATCH 0280/1061] add pretty printing --- compiler/rustc_hir_pretty/src/lib.rs | 36 ++++++++++++++--- ...struct-exprs-tuple-call-pretty-printing.rs | 33 ++++++++++++++++ ...ct-exprs-tuple-call-pretty-printing.stdout | 39 +++++++++++++++++++ 3 files changed, 102 insertions(+), 6 deletions(-) create mode 100644 tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.rs create mode 100644 tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 533afc372063..feaada638f07 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -17,9 +17,9 @@ use rustc_ast_pretty::pprust::state::MacHeader; use rustc_ast_pretty::pprust::{Comments, PrintState}; use rustc_hir::attrs::{AttributeKind, PrintAttribute}; use rustc_hir::{ - BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind, - HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, - TyPatKind, + BindingMode, ByRef, ConstArg, ConstArgExprField, ConstArgKind, GenericArg, GenericBound, + GenericParam, GenericParamKind, HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind, + PreciseCapturingArg, RangeEnd, Term, TyPatKind, }; use rustc_span::source_map::SourceMap; use rustc_span::{FileName, Ident, Span, Symbol, kw, sym}; @@ -1137,9 +1137,8 @@ impl<'a> State<'a> { fn print_const_arg(&mut self, const_arg: &hir::ConstArg<'_>) { match &const_arg.kind { - // FIXME(mgca): proper printing for struct exprs - ConstArgKind::Struct(..) => self.word("/* STRUCT EXPR */"), - ConstArgKind::TupleCall(..) => self.word("/* TUPLE CALL */"), + ConstArgKind::Struct(qpath, fields) => self.print_const_struct(qpath, fields), + ConstArgKind::TupleCall(qpath, args) => self.print_const_ctor(qpath, args), ConstArgKind::Path(qpath) => self.print_qpath(qpath, true), ConstArgKind::Anon(anon) => self.print_anon_const(anon), ConstArgKind::Error(_, _) => self.word("/*ERROR*/"), @@ -1147,6 +1146,31 @@ impl<'a> State<'a> { } } + fn print_const_struct(&mut self, qpath: &hir::QPath<'_>, fields: &&[&ConstArgExprField<'_>]) { + self.print_qpath(qpath, true); + self.word(" "); + self.word("{"); + if !fields.is_empty() { + self.nbsp(); + } + self.commasep(Inconsistent, *fields, |s, field| { + s.word(field.field.as_str().to_string()); + s.word(":"); + s.nbsp(); + s.print_const_arg(field.expr); + }); + self.word("}"); + } + + fn print_const_ctor(&mut self, qpath: &hir::QPath<'_>, args: &&[&ConstArg<'_, ()>]) { + self.print_qpath(qpath, true); + self.word("("); + self.commasep(Inconsistent, *args, |s, arg| { + s.print_const_arg(arg); + }); + self.word(")"); + } + fn print_call_post(&mut self, args: &[hir::Expr<'_>]) { self.popen(); self.commasep_exprs(Inconsistent, args); diff --git a/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.rs b/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.rs new file mode 100644 index 000000000000..5f2d6680efac --- /dev/null +++ b/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.rs @@ -0,0 +1,33 @@ +//@ compile-flags: -Zunpretty=hir +//@ check-pass + +#![feature(min_generic_const_args, adt_const_params)] +#![expect(incomplete_features)] +#![allow(dead_code)] + +use std::marker::ConstParamTy; + +struct Point(u32, u32); + +struct Point3(); + +struct Point1 { + a: u32, + b: u32, +} + +struct Point2 {} + +fn with_point() {} +fn with_point1() {} +fn with_point2() {} +fn with_point3() {} + +fn test() { + with_point::<{ Point(N, N) }>(); + with_point1::<{ Point1 { a: N, b: N } }>(); + with_point2::<{ Point2 {} }>(); + with_point3::<{ Point3() }>(); +} + +fn main() {} diff --git a/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout b/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout new file mode 100644 index 000000000000..fc0fbe8ef237 --- /dev/null +++ b/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout @@ -0,0 +1,39 @@ +//@ compile-flags: -Zunpretty=hir +//@ check-pass + +#![feature(min_generic_const_args, adt_const_params)] +#![expect(incomplete_features)] +#![allow(dead_code)] +#[attr = MacroUse {arguments: UseAll}] +extern crate std; +#[prelude_import] +use ::std::prelude::rust_2015::*; + +use std::marker::ConstParamTy; + +struct Point(u32, u32); + +struct Point3(); + +struct Point1 { + a: u32, + b: u32, +} + +struct Point2 { +} + +fn with_point() { } +fn with_point1() { } +fn with_point2() { } +fn with_point3() { } + +fn test() { + with_point::(); + with_point1::(); + with_point2::(); + with_point3::(); +} + +fn main() { } From 85d7fb0755432cdd65f88c3d9cb372fbc49c29fb Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Mon, 5 Jan 2026 23:28:24 +0000 Subject: [PATCH 0281/1061] Remove copyright year --- COPYRIGHT | 2 +- LICENSE-APACHE | 2 +- LICENSE-MIT | 2 +- README.md | 2 +- clippy_utils/README.md | 2 +- rustc_tools_util/README.md | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/COPYRIGHT b/COPYRIGHT index 5d3075903a01..d3b4c9e5fb2c 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,6 +1,6 @@ // REUSE-IgnoreStart -Copyright 2014-2026 The Rust Project Developers +Copyright (c) The Rust Project Contributors Licensed under the Apache License, Version 2.0 or the MIT license diff --git a/LICENSE-APACHE b/LICENSE-APACHE index 6f6e5844208d..773ae298cc19 100644 --- a/LICENSE-APACHE +++ b/LICENSE-APACHE @@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work. same "printed page" as the copyright notice for easier identification within third-party archives. -Copyright 2014-2026 The Rust Project Developers +Copyright (c) The Rust Project Contributors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/LICENSE-MIT b/LICENSE-MIT index a51639bc0f9b..9549420685cc 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2014-2026 The Rust Project Developers +Copyright (c) The Rust Project Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/README.md b/README.md index 287dee82daaa..8bccd040c1f9 100644 --- a/README.md +++ b/README.md @@ -277,7 +277,7 @@ If you want to contribute to Clippy, you can find more information in [CONTRIBUT -Copyright 2014-2026 The Rust Project Developers +Copyright (c) The Rust Project Contributors Licensed under the Apache License, Version 2.0 or the MIT license diff --git a/clippy_utils/README.md b/clippy_utils/README.md index e3ce95d30074..69bb6a2d6669 100644 --- a/clippy_utils/README.md +++ b/clippy_utils/README.md @@ -30,7 +30,7 @@ Function signatures can change or be removed without replacement without any pri -Copyright 2014-2026 The Rust Project Developers +Copyright (c) The Rust Project Contributors Licensed under the Apache License, Version 2.0 <[https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license diff --git a/rustc_tools_util/README.md b/rustc_tools_util/README.md index 083814e1e05d..45d2844ad00b 100644 --- a/rustc_tools_util/README.md +++ b/rustc_tools_util/README.md @@ -51,7 +51,7 @@ The changelog for `rustc_tools_util` is available under: -Copyright 2014-2026 The Rust Project Developers +Copyright (c) The Rust Project Contributors Licensed under the Apache License, Version 2.0 or the MIT license From fa4a62b06656b46afbd3398dc75b10997b3ab7db Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sat, 27 Dec 2025 00:26:21 +0100 Subject: [PATCH 0282/1061] use PIDFD_GET_INFO ioctl when available This way using pidfd_spawnp won't have to rely on procfs, avoiding an unpleasant edge-case where the child is spawned but we can't get the pid. And `pidfd.{try_}wait` will be able to return the exit status even after a process has been reaped. At least on newer kernels. --- library/std/src/os/linux/process.rs | 10 +- library/std/src/sys/pal/unix/linux/pidfd.rs | 101 ++++++++++++++---- .../std/src/sys/pal/unix/linux/pidfd/tests.rs | 38 ++++--- library/std/src/sys/process/unix/unix.rs | 40 +++---- 4 files changed, 132 insertions(+), 57 deletions(-) diff --git a/library/std/src/os/linux/process.rs b/library/std/src/os/linux/process.rs index fef321436f6a..60851db831bf 100644 --- a/library/std/src/os/linux/process.rs +++ b/library/std/src/os/linux/process.rs @@ -67,8 +67,10 @@ impl PidFd { /// Waits for the child to exit completely, returning the status that it exited with. /// /// Unlike [`Child::wait`] it does not ensure that the stdin handle is closed. - /// Additionally it will not return an `ExitStatus` if the child - /// has already been reaped. Instead an error will be returned. + /// + /// Additionally on kernels prior to 6.15 only the first attempt to + /// reap a child will return an ExitStatus, further attempts + /// will return an Error. /// /// [`Child::wait`]: process::Child::wait pub fn wait(&self) -> Result { @@ -77,8 +79,8 @@ impl PidFd { /// Attempts to collect the exit status of the child if it has already exited. /// - /// Unlike [`Child::try_wait`] this method will return an Error - /// if the child has already been reaped. + /// On kernels prior to 6.15, and unlike [`Child::try_wait`], only the first attempt + /// to reap a child will return an ExitStatus, further attempts will return an Error. /// /// [`Child::try_wait`]: process::Child::try_wait pub fn try_wait(&self) -> Result> { diff --git a/library/std/src/sys/pal/unix/linux/pidfd.rs b/library/std/src/sys/pal/unix/linux/pidfd.rs index 7859854e96b4..e9e4831fcc02 100644 --- a/library/std/src/sys/pal/unix/linux/pidfd.rs +++ b/library/std/src/sys/pal/unix/linux/pidfd.rs @@ -1,5 +1,5 @@ use crate::io; -use crate::os::fd::{AsRawFd, FromRawFd, RawFd}; +use crate::os::fd::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use crate::sys::fd::FileDesc; use crate::sys::process::ExitStatus; use crate::sys::{AsInner, FromInner, IntoInner, cvt}; @@ -15,6 +15,73 @@ impl PidFd { self.send_signal(libc::SIGKILL) } + #[cfg(any(test, target_env = "gnu", target_env = "musl"))] + pub(crate) fn current_process() -> io::Result { + let pid = crate::process::id(); + let pidfd = cvt(unsafe { libc::syscall(libc::SYS_pidfd_open, pid, 0) })?; + Ok(unsafe { PidFd::from_raw_fd(pidfd as RawFd) }) + } + + #[cfg(any(test, target_env = "gnu", target_env = "musl"))] + pub(crate) fn pid(&self) -> io::Result { + use crate::sys::weak::weak; + + // since kernel 6.13 + // https://lore.kernel.org/all/20241010155401.2268522-1-luca.boccassi@gmail.com/ + let mut pidfd_info: libc::pidfd_info = unsafe { crate::mem::zeroed() }; + pidfd_info.mask = libc::PIDFD_INFO_PID as u64; + match cvt(unsafe { libc::ioctl(self.0.as_raw_fd(), libc::PIDFD_GET_INFO, &mut pidfd_info) }) + { + Ok(_) => {} + Err(e) if e.raw_os_error() == Some(libc::EINVAL) => { + // kernel doesn't support that ioctl, try the glibc helper that looks at procfs + weak!( + fn pidfd_getpid(pidfd: RawFd) -> libc::pid_t; + ); + if let Some(pidfd_getpid) = pidfd_getpid.get() { + let pid: libc::c_int = cvt(unsafe { pidfd_getpid(self.0.as_raw_fd()) })?; + return Ok(pid as u32); + } + return Err(e); + } + Err(e) => return Err(e), + } + + Ok(pidfd_info.pid) + } + + fn exit_for_reaped_child(&self) -> io::Result { + // since kernel 6.15 + // https://lore.kernel.org/linux-fsdevel/20250305-work-pidfs-kill_on_last_close-v3-0-c8c3d8361705@kernel.org/T/ + let mut pidfd_info: libc::pidfd_info = unsafe { crate::mem::zeroed() }; + pidfd_info.mask = libc::PIDFD_INFO_EXIT as u64; + cvt(unsafe { libc::ioctl(self.0.as_raw_fd(), libc::PIDFD_GET_INFO, &mut pidfd_info) })?; + Ok(ExitStatus::new(pidfd_info.exit_code)) + } + + fn waitid(&self, options: libc::c_int) -> io::Result> { + let mut siginfo: libc::siginfo_t = unsafe { crate::mem::zeroed() }; + let r = cvt(unsafe { + libc::waitid(libc::P_PIDFD, self.0.as_raw_fd() as u32, &mut siginfo, options) + }); + match r { + Err(waitid_err) if waitid_err.raw_os_error() == Some(libc::ECHILD) => { + // already reaped + match self.exit_for_reaped_child() { + Ok(exit_status) => return Ok(Some(exit_status)), + Err(_) => return Err(waitid_err), + } + } + Err(e) => return Err(e), + Ok(_) => {} + } + if unsafe { siginfo.si_pid() } == 0 { + Ok(None) + } else { + Ok(Some(ExitStatus::from_waitid_siginfo(siginfo))) + } + } + pub(crate) fn send_signal(&self, signal: i32) -> io::Result<()> { cvt(unsafe { libc::syscall( @@ -29,29 +96,15 @@ impl PidFd { } pub fn wait(&self) -> io::Result { - let mut siginfo: libc::siginfo_t = unsafe { crate::mem::zeroed() }; - cvt(unsafe { - libc::waitid(libc::P_PIDFD, self.0.as_raw_fd() as u32, &mut siginfo, libc::WEXITED) - })?; - Ok(ExitStatus::from_waitid_siginfo(siginfo)) + let r = self.waitid(libc::WEXITED)?; + match r { + Some(exit_status) => Ok(exit_status), + None => unreachable!("waitid with WEXITED should not return None"), + } } pub fn try_wait(&self) -> io::Result> { - let mut siginfo: libc::siginfo_t = unsafe { crate::mem::zeroed() }; - - cvt(unsafe { - libc::waitid( - libc::P_PIDFD, - self.0.as_raw_fd() as u32, - &mut siginfo, - libc::WEXITED | libc::WNOHANG, - ) - })?; - if unsafe { siginfo.si_pid() } == 0 { - Ok(None) - } else { - Ok(Some(ExitStatus::from_waitid_siginfo(siginfo))) - } + self.waitid(libc::WEXITED | libc::WNOHANG) } } @@ -78,3 +131,9 @@ impl FromRawFd for PidFd { Self(FileDesc::from_raw_fd(fd)) } } + +impl IntoRawFd for PidFd { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw_fd() + } +} diff --git a/library/std/src/sys/pal/unix/linux/pidfd/tests.rs b/library/std/src/sys/pal/unix/linux/pidfd/tests.rs index 17b06bea9127..a3bb5d5d64ba 100644 --- a/library/std/src/sys/pal/unix/linux/pidfd/tests.rs +++ b/library/std/src/sys/pal/unix/linux/pidfd/tests.rs @@ -1,8 +1,11 @@ +use super::PidFd as InternalPidFd; use crate::assert_matches::assert_matches; -use crate::os::fd::{AsRawFd, RawFd}; +use crate::io::ErrorKind; +use crate::os::fd::AsRawFd; use crate::os::linux::process::{ChildExt, CommandExt as _}; use crate::os::unix::process::{CommandExt as _, ExitStatusExt}; use crate::process::Command; +use crate::sys::AsInner; #[test] fn test_command_pidfd() { @@ -48,11 +51,22 @@ fn test_command_pidfd() { let mut cmd = Command::new("false"); let mut child = unsafe { cmd.pre_exec(|| Ok(())) }.create_pidfd(true).spawn().unwrap(); - assert!(child.id() > 0 && child.id() < -1i32 as u32); + let id = child.id(); + + assert!(id > 0 && id < -1i32 as u32, "spawning with pidfd still returns a sane pid"); if pidfd_open_available { assert!(child.pidfd().is_ok()) } + + if let Ok(pidfd) = child.pidfd() { + match pidfd.as_inner().pid() { + Ok(pid) => assert_eq!(pid, id), + Err(e) if e.kind() == ErrorKind::InvalidInput => { /* older kernel */ } + Err(e) => panic!("unexpected error getting pid from pidfd: {}", e), + } + } + child.wait().expect("error waiting on child"); } @@ -77,9 +91,15 @@ fn test_pidfd() { assert_eq!(status.signal(), Some(libc::SIGKILL)); // Trying to wait again for a reaped child is safe since there's no pid-recycling race. - // But doing so will return an error. + // But doing so may return an error. let res = fd.wait(); - assert_matches!(res, Err(e) if e.raw_os_error() == Some(libc::ECHILD)); + match res { + // older kernels + Err(e) if e.raw_os_error() == Some(libc::ECHILD) => {} + // 6.15+ + Ok(exit) if exit.signal() == Some(libc::SIGKILL) => {} + other => panic!("expected ECHILD error, got {:?}", other), + } // Ditto for additional attempts to kill an already-dead child. let res = fd.kill(); @@ -87,13 +107,5 @@ fn test_pidfd() { } fn probe_pidfd_support() -> bool { - // pidfds require the pidfd_open syscall - let our_pid = crate::process::id(); - let pidfd = unsafe { libc::syscall(libc::SYS_pidfd_open, our_pid, 0) }; - if pidfd >= 0 { - unsafe { libc::close(pidfd as RawFd) }; - true - } else { - false - } + InternalPidFd::current_process().is_ok() } diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs index 5ba57e11679c..df64a1716d52 100644 --- a/library/std/src/sys/process/unix/unix.rs +++ b/library/std/src/sys/process/unix/unix.rs @@ -482,10 +482,6 @@ impl Command { ) -> libc::c_int; ); - weak!( - fn pidfd_getpid(pidfd: libc::c_int) -> libc::c_int; - ); - static PIDFD_SUPPORTED: Atomic = AtomicU8::new(0); const UNKNOWN: u8 = 0; const SPAWN: u8 = 1; @@ -502,24 +498,26 @@ impl Command { } if support == UNKNOWN { support = NO; - let our_pid = crate::process::id(); - let pidfd = cvt(unsafe { libc::syscall(libc::SYS_pidfd_open, our_pid, 0) } as c_int); - match pidfd { + + match PidFd::current_process() { Ok(pidfd) => { + // if pidfd_open works then we at least know the fork path is available. support = FORK_EXEC; - if let Some(Ok(pid)) = pidfd_getpid.get().map(|f| cvt(unsafe { f(pidfd) } as i32)) { - if pidfd_spawnp.get().is_some() && pid as u32 == our_pid { - support = SPAWN - } + // but for the fast path we need both spawnp and the + // pidfd -> pid conversion to work. + if pidfd_spawnp.get().is_some() && let Ok(pid) = pidfd.pid() { + assert_eq!(pid, crate::process::id(), "sanity check"); + support = SPAWN; } - unsafe { libc::close(pidfd) }; } Err(e) if e.raw_os_error() == Some(libc::EMFILE) => { - // We're temporarily(?) out of file descriptors. In this case obtaining a pidfd would also fail + // We're temporarily(?) out of file descriptors. In this case pidfd_spawnp would also fail // Don't update the support flag so we can probe again later. return Err(e) } - _ => {} + _ => { + // pidfd_open not available? likely an old kernel without pidfd support. + } } PIDFD_SUPPORTED.store(support, Ordering::Relaxed); if support == FORK_EXEC { @@ -791,13 +789,17 @@ impl Command { } spawn_res?; - let pid = match cvt(pidfd_getpid.get().unwrap()(pidfd)) { + use crate::os::fd::{FromRawFd, IntoRawFd}; + + let pidfd = PidFd::from_raw_fd(pidfd); + let pid = match pidfd.pid() { Ok(pid) => pid, Err(e) => { // The child has been spawned and we are holding its pidfd. - // But we cannot obtain its pid even though pidfd_getpid support was verified earlier. - // This might happen if libc can't open procfs because the file descriptor limit has been reached. - libc::close(pidfd); + // But we cannot obtain its pid even though pidfd_spawnp and getpid support + // was verified earlier. + // This is quite unlikely, but might happen if the ioctl is not supported, + // glibc tries to use procfs and we're out of file descriptors. return Err(Error::new( e.kind(), "pidfd_spawnp succeeded but the child's PID could not be obtained", @@ -805,7 +807,7 @@ impl Command { } }; - return Ok(Some(Process::new(pid, pidfd))); + return Ok(Some(Process::new(pid as i32, pidfd.into_raw_fd()))); } // Safety: -1 indicates we don't have a pidfd. From b0a581d51d7656379bd26c2e6c3c28db73ff97ce Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Tue, 6 Jan 2026 09:19:03 +0900 Subject: [PATCH 0283/1061] rename the `lower_ty` and `lower_ty_direct` to `lower_ty_and_alloc` and `lower_ty` --- compiler/rustc_ast_lowering/src/block.rs | 2 +- compiler/rustc_ast_lowering/src/expr.rs | 17 ++++---- compiler/rustc_ast_lowering/src/item.rs | 51 ++++++++++++++---------- compiler/rustc_ast_lowering/src/lib.rs | 38 +++++++++--------- compiler/rustc_ast_lowering/src/path.rs | 15 +++---- 5 files changed, 70 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 5bfe63008516..cf3f331a701b 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -98,7 +98,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Let statements are allowed to have impl trait in bindings. let super_ = l.super_.map(|span| self.lower_span(span)); let ty = l.ty.as_ref().map(|t| { - self.lower_ty(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable)) + self.lower_ty_alloc(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable)) }); let init = l.kind.init().map(|init| self.lower_expr(init)); let hir_id = self.lower_node_id(l.id); diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 0502fd2873e9..9fbfeb7a11e6 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -158,14 +158,14 @@ impl<'hir> LoweringContext<'_, 'hir> { } ExprKind::Cast(expr, ty) => { let expr = self.lower_expr(expr); - let ty = - self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast)); + let ty = self + .lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast)); hir::ExprKind::Cast(expr, ty) } ExprKind::Type(expr, ty) => { let expr = self.lower_expr(expr); - let ty = - self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast)); + let ty = self + .lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast)); hir::ExprKind::Type(expr, ty) } ExprKind::AddrOf(k, m, ohs) => { @@ -335,7 +335,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } ExprKind::FormatArgs(fmt) => self.lower_format_args(e.span, fmt), ExprKind::OffsetOf(container, fields) => hir::ExprKind::OffsetOf( - self.lower_ty( + self.lower_ty_alloc( container, ImplTraitContext::Disallowed(ImplTraitPosition::OffsetOf), ), @@ -371,7 +371,10 @@ impl<'hir> LoweringContext<'_, 'hir> { *kind, self.lower_expr(expr), ty.as_ref().map(|ty| { - self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast)) + self.lower_ty_alloc( + ty, + ImplTraitContext::Disallowed(ImplTraitPosition::Cast), + ) }), ), @@ -617,7 +620,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }); if let Some(ty) = opt_ty { - let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path)); + let ty = self.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path)); let block_expr = self.arena.alloc(self.expr_block(whole_block)); hir::ExprKind::Type(block_expr, ty) } else { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index bfce7c25b75d..f8b98a5ece40 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -264,8 +264,8 @@ impl<'hir> LoweringContext<'_, 'hir> { define_opaque, }) => { let ident = self.lower_ident(*ident); - let ty = - self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); + let ty = self + .lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); let body_id = self.lower_const_body(span, e.as_deref()); self.lower_define_opaque(hir_id, define_opaque); hir::ItemKind::Static(*m, ident, ty, body_id) @@ -279,8 +279,10 @@ impl<'hir> LoweringContext<'_, 'hir> { id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { - let ty = this - .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); + let ty = this.lower_ty_alloc( + ty, + ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy), + ); let rhs = this.lower_const_item_rhs(attrs, rhs.as_ref(), span); (ty, rhs) }, @@ -379,7 +381,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); this.arena.alloc(this.ty(span, hir::TyKind::Err(guar))) } - Some(ty) => this.lower_ty( + Some(ty) => this.lower_ty_alloc( ty, ImplTraitContext::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias { @@ -453,7 +455,7 @@ impl<'hir> LoweringContext<'_, 'hir> { .as_deref() .map(|of_trait| this.lower_trait_impl_header(of_trait)); - let lowered_ty = this.lower_ty( + let lowered_ty = this.lower_ty_alloc( ty, ImplTraitContext::Disallowed(ImplTraitPosition::ImplSelf), ); @@ -758,8 +760,8 @@ impl<'hir> LoweringContext<'_, 'hir> { safety, define_opaque, }) => { - let ty = - self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); + let ty = self + .lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); let safety = self.lower_safety(*safety, hir::Safety::Unsafe); if define_opaque.is_some() { self.dcx().span_err(i.span, "foreign statics cannot define opaque types"); @@ -870,7 +872,8 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, (index, f): (usize, &FieldDef), ) -> hir::FieldDef<'hir> { - let ty = self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy)); + let ty = + self.lower_ty_alloc(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy)); let hir_id = self.lower_node_id(f.id); self.lower_attrs(hir_id, &f.attrs, f.span, Target::Field); hir::FieldDef { @@ -908,8 +911,10 @@ impl<'hir> LoweringContext<'_, 'hir> { i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { - let ty = this - .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); + let ty = this.lower_ty_alloc( + ty, + ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy), + ); let rhs = rhs .as_ref() .map(|rhs| this.lower_const_item_rhs(attrs, Some(rhs), i.span)); @@ -1008,7 +1013,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { let ty = ty.as_ref().map(|x| { - this.lower_ty( + this.lower_ty_alloc( x, ImplTraitContext::Disallowed(ImplTraitPosition::AssocTy), ) @@ -1120,8 +1125,10 @@ impl<'hir> LoweringContext<'_, 'hir> { i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { - let ty = this - .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); + let ty = this.lower_ty_alloc( + ty, + ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy), + ); this.lower_define_opaque(hir_id, &define_opaque); let rhs = this.lower_const_item_rhs(attrs, rhs.as_ref(), i.span); hir::ImplItemKind::Const(ty, rhs) @@ -1180,7 +1187,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ImplItemKind::Type(ty) } Some(ty) => { - let ty = this.lower_ty( + let ty = this.lower_ty_alloc( ty, ImplTraitContext::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias { @@ -1916,7 +1923,7 @@ impl<'hir> LoweringContext<'_, 'hir> { bound_generic_params, hir::GenericParamSource::Binder, ), - bounded_ty: self.lower_ty( + bounded_ty: self.lower_ty_alloc( bounded_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound), ), @@ -1945,10 +1952,14 @@ impl<'hir> LoweringContext<'_, 'hir> { } WherePredicateKind::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty }) => { hir::WherePredicateKind::EqPredicate(hir::WhereEqPredicate { - lhs_ty: self - .lower_ty(lhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)), - rhs_ty: self - .lower_ty(rhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)), + lhs_ty: self.lower_ty_alloc( + lhs_ty, + ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + ), + rhs_ty: self.lower_ty_alloc( + rhs_ty, + ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + ), }) } }); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 9a459156aba1..0d1388a2441d 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1125,7 +1125,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let kind = match &constraint.kind { AssocItemConstraintKind::Equality { term } => { let term = match term { - Term::Ty(ty) => self.lower_ty(ty, itctx).into(), + Term::Ty(ty) => self.lower_ty_alloc(ty, itctx).into(), Term::Const(c) => self.lower_anon_const_to_const_arg(c).into(), }; hir::AssocItemConstraintKind::Equality { term } @@ -1250,7 +1250,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } _ => {} } - GenericArg::Type(self.lower_ty(ty, itctx).try_as_ambig_ty().unwrap()) + GenericArg::Type(self.lower_ty_alloc(ty, itctx).try_as_ambig_ty().unwrap()) } ast::GenericArg::Const(ct) => { GenericArg::Const(self.lower_anon_const_to_const_arg(ct).try_as_ambig_ct().unwrap()) @@ -1259,8 +1259,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } #[instrument(level = "debug", skip(self))] - fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> &'hir hir::Ty<'hir> { - self.arena.alloc(self.lower_ty_direct(t, itctx)) + fn lower_ty_alloc(&mut self, t: &Ty, itctx: ImplTraitContext) -> &'hir hir::Ty<'hir> { + self.arena.alloc(self.lower_ty(t, itctx)) } fn lower_path_ty( @@ -1324,11 +1324,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.ty(span, hir::TyKind::Tup(tys)) } - fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> { + fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> { let kind = match &t.kind { TyKind::Infer => hir::TyKind::Infer(()), TyKind::Err(guar) => hir::TyKind::Err(*guar), - TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)), + TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty_alloc(ty, itctx)), TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)), TyKind::Ref(region, mt) => { let lifetime = self.lower_ty_direct_lifetime(t, *region); @@ -1362,15 +1362,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params); hir::TyKind::UnsafeBinder(self.arena.alloc(hir::UnsafeBinderTy { generic_params, - inner_ty: self.lower_ty(&f.inner_ty, itctx), + inner_ty: self.lower_ty_alloc(&f.inner_ty, itctx), })) } TyKind::Never => hir::TyKind::Never, TyKind::Tup(tys) => hir::TyKind::Tup( - self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))), + self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty(ty, itctx))), ), TyKind::Paren(ty) => { - return self.lower_ty_direct(ty, itctx); + return self.lower_ty(ty, itctx); } TyKind::Path(qself, path) => { return self.lower_path_ty(t, qself, path, ParamMode::Explicit, itctx); @@ -1393,7 +1393,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { )) } TyKind::Array(ty, length) => hir::TyKind::Array( - self.lower_ty(ty, itctx), + self.lower_ty_alloc(ty, itctx), self.lower_array_length_to_const_arg(length), ), TyKind::TraitObject(bounds, kind) => { @@ -1493,7 +1493,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } TyKind::Pat(ty, pat) => { - hir::TyKind::Pat(self.lower_ty(ty, itctx), self.lower_ty_pat(pat, ty.span)) + hir::TyKind::Pat(self.lower_ty_alloc(ty, itctx), self.lower_ty_pat(pat, ty.span)) } TyKind::MacCall(_) => { span_bug!(t.span, "`TyKind::MacCall` should have been expanded by now") @@ -1693,7 +1693,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ImplTraitContext::Disallowed(ImplTraitPosition::PointerParam) } }; - self.lower_ty_direct(¶m.ty, itctx) + self.lower_ty(¶m.ty, itctx) })); let output = match coro { @@ -1732,7 +1732,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ImplTraitContext::Disallowed(ImplTraitPosition::PointerReturn) } }; - hir::FnRetTy::Return(self.lower_ty(ty, itctx)) + hir::FnRetTy::Return(self.lower_ty_alloc(ty, itctx)) } FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(self.lower_span(*span)), }, @@ -1843,7 +1843,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Not `OpaqueTyOrigin::AsyncFn`: that's only used for the // `impl Future` opaque type that `async fn` implicitly // generates. - self.lower_ty(ty, itctx) + self.lower_ty_alloc(ty, itctx) } FnRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])), }; @@ -2036,7 +2036,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } }) .map(|def| { - self.lower_ty( + self.lower_ty_alloc( def, ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault), ) @@ -2047,8 +2047,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { (hir::ParamName::Plain(self.lower_ident(param.ident)), kind) } GenericParamKind::Const { ty, span: _, default } => { - let ty = self - .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault)); + let ty = self.lower_ty_alloc( + ty, + ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault), + ); // Not only do we deny const param defaults in binders but we also map them to `None` // since later compiler stages cannot handle them (and shouldn't need to be able to). @@ -2198,7 +2200,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> { - hir::MutTy { ty: self.lower_ty(&mt.ty, itctx), mutbl: mt.mutbl } + hir::MutTy { ty: self.lower_ty_alloc(&mt.ty, itctx), mutbl: mt.mutbl } } #[instrument(level = "debug", skip(self), ret)] diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 3322e0fb66b4..bfb42efb684f 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -36,7 +36,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let qself = qself .as_ref() // Reject cases like `::Assoc` and `::Assoc`. - .map(|q| self.lower_ty(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path))); + .map(|q| { + self.lower_ty_alloc(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path)) + }); let partial_res = self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err)); @@ -510,7 +512,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // we generally don't permit such things (see #51008). let ParenthesizedArgs { span, inputs, inputs_span, output } = data; let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| { - self.lower_ty_direct(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam)) + self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam)) })); let output_ty = match output { // Only allow `impl Trait` in return position. i.e.: @@ -520,9 +522,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // ``` FnRetTy::Ty(ty) if matches!(itctx, ImplTraitContext::OpaqueTy { .. }) => { if self.tcx.features().impl_trait_in_fn_trait_return() { - self.lower_ty(ty, itctx) + self.lower_ty_alloc(ty, itctx) } else { - self.lower_ty( + self.lower_ty_alloc( ty, ImplTraitContext::FeatureGated( ImplTraitPosition::FnTraitReturn, @@ -531,9 +533,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) } } - FnRetTy::Ty(ty) => { - self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)) - } + FnRetTy::Ty(ty) => self + .lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)), FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])), }; let args = smallvec![GenericArg::Type( From 56cb5d598bc4b0e3b106752720feb3934316bfb5 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Tue, 6 Jan 2026 09:24:41 +0900 Subject: [PATCH 0284/1061] rename the `lower_anon_const_to_const_arg` and `lower_anon_const_to_const_arg_direct` to `lower_anon_const_to_const_arg_and_alloc` and `lower_anon_const_to_const_arg` --- compiler/rustc_ast_lowering/src/lib.rs | 27 ++++++++++++++------------ compiler/rustc_ast_lowering/src/pat.rs | 18 +++++++++-------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 0d1388a2441d..e11e24c0263f 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1126,7 +1126,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { AssocItemConstraintKind::Equality { term } => { let term = match term { Term::Ty(ty) => self.lower_ty_alloc(ty, itctx).into(), - Term::Const(c) => self.lower_anon_const_to_const_arg(c).into(), + Term::Const(c) => self.lower_anon_const_to_const_arg_and_alloc(c).into(), }; hir::AssocItemConstraintKind::Equality { term } } @@ -1252,9 +1252,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } GenericArg::Type(self.lower_ty_alloc(ty, itctx).try_as_ambig_ty().unwrap()) } - ast::GenericArg::Const(ct) => { - GenericArg::Const(self.lower_anon_const_to_const_arg(ct).try_as_ambig_ct().unwrap()) - } + ast::GenericArg::Const(ct) => GenericArg::Const( + self.lower_anon_const_to_const_arg_and_alloc(ct).try_as_ambig_ct().unwrap(), + ), } } @@ -2066,7 +2066,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { false } }) - .map(|def| self.lower_anon_const_to_const_arg(def)); + .map(|def| self.lower_anon_const_to_const_arg_and_alloc(def)); ( hir::ParamName::Plain(self.lower_ident(param.ident)), @@ -2288,7 +2288,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let ct_kind = hir::ConstArgKind::Infer(self.lower_span(c.value.span), ()); self.arena.alloc(hir::ConstArg { hir_id: self.lower_node_id(c.id), kind: ct_kind }) } - _ => self.lower_anon_const_to_const_arg(c), + _ => self.lower_anon_const_to_const_arg_and_alloc(c), } } @@ -2367,7 +2367,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) -> hir::ConstItemRhs<'hir> { match rhs { Some(ConstItemRhs::TypeConst(anon)) => { - hir::ConstItemRhs::TypeConst(self.lower_anon_const_to_const_arg(anon)) + hir::ConstItemRhs::TypeConst(self.lower_anon_const_to_const_arg_and_alloc(anon)) } None if attr::contains_name(attrs, sym::type_const) => { let const_arg = ConstArg { @@ -2414,7 +2414,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let def_id = self.local_def_id(anon_const.id); let def_kind = self.tcx.def_kind(def_id); assert_eq!(DefKind::AnonConst, def_kind); - self.lower_anon_const_to_const_arg_direct(anon_const) + self.lower_anon_const_to_const_arg(anon_const) } else { self.lower_expr_to_const_arg_direct(arg) }; @@ -2467,7 +2467,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let def_kind = self.tcx.def_kind(def_id); assert_eq!(DefKind::AnonConst, def_kind); - self.lower_anon_const_to_const_arg_direct(anon_const) + self.lower_anon_const_to_const_arg(anon_const) } else { self.lower_expr_to_const_arg_direct(&f.expr) }; @@ -2508,12 +2508,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// See [`hir::ConstArg`] for when to use this function vs /// [`Self::lower_anon_const_to_anon_const`]. - fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> &'hir hir::ConstArg<'hir> { - self.arena.alloc(self.lower_anon_const_to_const_arg_direct(anon)) + fn lower_anon_const_to_const_arg_and_alloc( + &mut self, + anon: &AnonConst, + ) -> &'hir hir::ConstArg<'hir> { + self.arena.alloc(self.lower_anon_const_to_const_arg(anon)) } #[instrument(level = "debug", skip(self))] - fn lower_anon_const_to_const_arg_direct(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> { + fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> { let tcx = self.tcx; // We cannot change parsing depending on feature gates available, diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 7a5d8d9847a1..f09bbb9c4972 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -444,16 +444,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let pat_hir_id = self.lower_node_id(pattern.id); let node = match &pattern.kind { TyPatKind::Range(e1, e2, Spanned { node: end, span }) => hir::TyPatKind::Range( - e1.as_deref().map(|e| self.lower_anon_const_to_const_arg(e)).unwrap_or_else(|| { - self.lower_ty_pat_range_end( - hir::LangItem::RangeMin, - span.shrink_to_lo(), - base_type, - ) - }), + e1.as_deref() + .map(|e| self.lower_anon_const_to_const_arg_and_alloc(e)) + .unwrap_or_else(|| { + self.lower_ty_pat_range_end( + hir::LangItem::RangeMin, + span.shrink_to_lo(), + base_type, + ) + }), e2.as_deref() .map(|e| match end { - RangeEnd::Included(..) => self.lower_anon_const_to_const_arg(e), + RangeEnd::Included(..) => self.lower_anon_const_to_const_arg_and_alloc(e), RangeEnd::Excluded => self.lower_excluded_range_end(e), }) .unwrap_or_else(|| { From e603055d89063ee3fea237f34deccbf333a6e91a Mon Sep 17 00:00:00 2001 From: delta17920 Date: Mon, 5 Jan 2026 16:20:36 +0000 Subject: [PATCH 0285/1061] Fix ICE when transmute Assume field is invalid --- compiler/rustc_transmute/src/lib.rs | 10 +++--- .../non_scalar_alignment_value.rs | 30 ++++++++++++++++ .../non_scalar_alignment_value.stderr | 35 +++++++++++++++++++ 3 files changed, 70 insertions(+), 5 deletions(-) create mode 100644 tests/ui/transmutability/non_scalar_alignment_value.rs create mode 100644 tests/ui/transmutability/non_scalar_alignment_value.stderr diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 58cb2eb6556e..08ae561c972c 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -155,14 +155,14 @@ mod rustc { .enumerate() .find(|(_, field_def)| name == field_def.name) .unwrap_or_else(|| panic!("There were no fields named `{name}`.")); - fields[field_idx].to_leaf() == ScalarInt::TRUE + fields[field_idx].try_to_leaf().map(|leaf| leaf == ScalarInt::TRUE) }; Some(Self { - alignment: get_field(sym::alignment), - lifetimes: get_field(sym::lifetimes), - safety: get_field(sym::safety), - validity: get_field(sym::validity), + alignment: get_field(sym::alignment)?, + lifetimes: get_field(sym::lifetimes)?, + safety: get_field(sym::safety)?, + validity: get_field(sym::validity)?, }) } } diff --git a/tests/ui/transmutability/non_scalar_alignment_value.rs b/tests/ui/transmutability/non_scalar_alignment_value.rs new file mode 100644 index 000000000000..45c9e61fcfe2 --- /dev/null +++ b/tests/ui/transmutability/non_scalar_alignment_value.rs @@ -0,0 +1,30 @@ +#![feature(min_generic_const_args)] +//~^ WARN the feature `min_generic_const_args` is incomplete + +#![feature(transmutability)] + +mod assert { + use std::mem::{Assume, TransmuteFrom}; + struct Dst {} + fn is_maybe_transmutable() + where + Dst: TransmuteFrom< + (), + { + Assume { + alignment: Assume {}, + //~^ ERROR struct expression with missing field initialiser for `alignment` + //~| ERROR struct expression with missing field initialiser for `lifetimes` + //~| ERROR struct expression with missing field initialiser for `safety` + //~| ERROR struct expression with missing field initialiser for `validity` + lifetimes: const { true }, + safety: const { true }, + validity: const { true }, + } + }, + >, + { + } +} + +fn main() {} diff --git a/tests/ui/transmutability/non_scalar_alignment_value.stderr b/tests/ui/transmutability/non_scalar_alignment_value.stderr new file mode 100644 index 000000000000..06487dea82e0 --- /dev/null +++ b/tests/ui/transmutability/non_scalar_alignment_value.stderr @@ -0,0 +1,35 @@ +warning: the feature `min_generic_const_args` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/non_scalar_alignment_value.rs:1:12 + | +LL | #![feature(min_generic_const_args)] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #132980 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: struct expression with missing field initialiser for `alignment` + --> $DIR/non_scalar_alignment_value.rs:15:32 + | +LL | alignment: Assume {}, + | ^^^^^^ + +error: struct expression with missing field initialiser for `lifetimes` + --> $DIR/non_scalar_alignment_value.rs:15:32 + | +LL | alignment: Assume {}, + | ^^^^^^ + +error: struct expression with missing field initialiser for `safety` + --> $DIR/non_scalar_alignment_value.rs:15:32 + | +LL | alignment: Assume {}, + | ^^^^^^ + +error: struct expression with missing field initialiser for `validity` + --> $DIR/non_scalar_alignment_value.rs:15:32 + | +LL | alignment: Assume {}, + | ^^^^^^ + +error: aborting due to 4 previous errors; 1 warning emitted + From 8233943e818eb570ba715ce935ad9764bba5af47 Mon Sep 17 00:00:00 2001 From: Redddy Date: Tue, 6 Jan 2026 14:11:22 +0900 Subject: [PATCH 0286/1061] Fix indent in rust code --- src/doc/rustc-dev-guide/src/ambig-unambig-ty-and-consts.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/ambig-unambig-ty-and-consts.md b/src/doc/rustc-dev-guide/src/ambig-unambig-ty-and-consts.md index 64a15b7f9aa8..33b685861df3 100644 --- a/src/doc/rustc-dev-guide/src/ambig-unambig-ty-and-consts.md +++ b/src/doc/rustc-dev-guide/src/ambig-unambig-ty-and-consts.md @@ -6,7 +6,7 @@ parse. ```rust fn func(arg: T) { - // ^ Unambig type position + // ^ Unambig type position let a: _ = arg; // ^ Unambig type position @@ -108,4 +108,4 @@ This has a number of benefits: [`ast::AnonConst`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/struct.AnonConst.html [`hir::GenericArg::Infer`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.GenericArg.html#variant.Infer [`ast::ExprKind::Underscore`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/enum.ExprKind.html#variant.Underscore -[`ast::Ty::Path(N)`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/enum.TyKind.html#variant.Path \ No newline at end of file +[`ast::Ty::Path(N)`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/enum.TyKind.html#variant.Path From dd948f96f30af19cf2cb7041de577ee1bf29bb9f Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Tue, 6 Jan 2026 09:42:42 +0800 Subject: [PATCH 0287/1061] Thread `--jobs` from `bootstrap` -> `compiletest` -> `run-make-support` --- src/bootstrap/src/core/build_steps/test.rs | 2 ++ src/tools/compiletest/src/common.rs | 5 +++++ src/tools/compiletest/src/directives/tests.rs | 1 + src/tools/compiletest/src/lib.rs | 10 +++++++++- src/tools/compiletest/src/runtest/run_make.rs | 3 +++ src/tools/compiletest/src/rustdoc_gui_test.rs | 1 + src/tools/run-make-support/src/env.rs | 14 ++++++++++++++ tests/run-make/compiletest-self-test/jobs/rmake.rs | 5 +++++ 8 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 tests/run-make/compiletest-self-test/jobs/rmake.rs diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index a3c13fc4b095..4008ede6c0d4 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2265,6 +2265,8 @@ Please disable assertions with `rust.debug-assertions = false`. cmd.arg("--with-std-remap-debuginfo"); } + cmd.arg("--jobs").arg(builder.jobs().to_string()); + let mut llvm_components_passed = false; let mut copts_passed = false; if builder.config.llvm_enabled(test_compiler.host) { diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 5563abe92a80..800ce4f3088e 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -715,6 +715,11 @@ pub struct Config { pub override_codegen_backend: Option, /// Whether to ignore `//@ ignore-backends`. pub bypass_ignore_backends: bool, + + /// Number of parallel jobs configured for the build. + /// + /// This is forwarded from bootstrap's `jobs` configuration. + pub jobs: u32, } impl Config { diff --git a/src/tools/compiletest/src/directives/tests.rs b/src/tools/compiletest/src/directives/tests.rs index 0d3777b8e60c..71343080cfa2 100644 --- a/src/tools/compiletest/src/directives/tests.rs +++ b/src/tools/compiletest/src/directives/tests.rs @@ -225,6 +225,7 @@ impl ConfigBuilder { "--nightly-branch=", "--git-merge-commit-email=", "--minicore-path=", + "--jobs=0", ]; let mut args: Vec = args.iter().map(ToString::to_string).collect(); diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index a64c7850aad4..997f570393f2 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -218,7 +218,8 @@ fn parse_config(args: Vec) -> Config { "the codegen backend to use instead of the default one", "CODEGEN BACKEND [NAME | PATH]", ) - .optflag("", "bypass-ignore-backends", "ignore `//@ ignore-backends` directives"); + .optflag("", "bypass-ignore-backends", "ignore `//@ ignore-backends` directives") + .reqopt("", "jobs", "number of parallel jobs bootstrap was configured with", "JOBS"); let (argv0, args_) = args.split_first().unwrap(); if args.len() == 1 || args[1] == "-h" || args[1] == "--help" { @@ -363,6 +364,11 @@ fn parse_config(args: Vec) -> Config { let build_test_suite_root = opt_path(matches, "build-test-suite-root"); assert!(build_test_suite_root.starts_with(&build_root)); + let jobs = match matches.opt_str("jobs") { + Some(jobs) => jobs.parse::().expect("expected `--jobs` to be an `u32`"), + None => panic!("`--jobs` is required"), + }; + Config { bless: matches.opt_present("bless"), fail_fast: matches.opt_present("fail-fast") @@ -481,6 +487,8 @@ fn parse_config(args: Vec) -> Config { default_codegen_backend, override_codegen_backend, bypass_ignore_backends: matches.opt_present("bypass-ignore-backends"), + + jobs, } } diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs index ba3a12347367..4eb8f91fe894 100644 --- a/src/tools/compiletest/src/runtest/run_make.rs +++ b/src/tools/compiletest/src/runtest/run_make.rs @@ -249,6 +249,9 @@ impl TestCx<'_> { cmd.env("__STD_REMAP_DEBUGINFO_ENABLED", "1"); } + // Used for `run_make_support::env::jobs`. + cmd.env("__BOOTSTRAP_JOBS", self.config.jobs.to_string()); + // We don't want RUSTFLAGS set from the outside to interfere with // compiler flags set in the test cases: cmd.env_remove("RUSTFLAGS"); diff --git a/src/tools/compiletest/src/rustdoc_gui_test.rs b/src/tools/compiletest/src/rustdoc_gui_test.rs index 4454ffb1f59e..06b66ef9fd0a 100644 --- a/src/tools/compiletest/src/rustdoc_gui_test.rs +++ b/src/tools/compiletest/src/rustdoc_gui_test.rs @@ -139,5 +139,6 @@ fn incomplete_config_for_rustdoc_gui_test() -> Config { default_codegen_backend: CodegenBackend::Llvm, override_codegen_backend: None, bypass_ignore_backends: Default::default(), + jobs: Default::default(), } } diff --git a/src/tools/run-make-support/src/env.rs b/src/tools/run-make-support/src/env.rs index 507d51471df0..65b6d3db85d5 100644 --- a/src/tools/run-make-support/src/env.rs +++ b/src/tools/run-make-support/src/env.rs @@ -49,3 +49,17 @@ pub fn set_current_dir>(dir: P) { std::env::set_current_dir(dir.as_ref()) .expect(&format!("could not set current directory to \"{}\"", dir.as_ref().display())); } + +/// Number of parallel jobs bootstrap was configured with. +/// +/// This may fallback to [`std::thread::available_parallelism`] when no explicit jobs count has been +/// configured. Refer to bootstrap's jobs fallback logic. +#[track_caller] +pub fn jobs() -> u32 { + std::env::var_os("__BOOTSTRAP_JOBS") + .expect("`__BOOTSTRAP_JOBS` must be set by `compiletest`") + .to_str() + .expect("`__BOOTSTRAP_JOBS` must be a valid string") + .parse::() + .expect("`__BOOTSTRAP_JOBS` must be a valid `u32`") +} diff --git a/tests/run-make/compiletest-self-test/jobs/rmake.rs b/tests/run-make/compiletest-self-test/jobs/rmake.rs new file mode 100644 index 000000000000..d21b44ada1c3 --- /dev/null +++ b/tests/run-make/compiletest-self-test/jobs/rmake.rs @@ -0,0 +1,5 @@ +//! Very basic smoke test to make sure `run_make_support::env::jobs` at least does not panic. + +fn main() { + println!("{}", run_make_support::env::jobs()); +} From 03fb7eecedf37b28a1feab1383c917d9e91dfaef Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 26 Dec 2025 20:54:15 +0100 Subject: [PATCH 0288/1061] Create a `rustc_ast` representation for parsed attributes --- compiler/rustc_ast/src/ast.rs | 45 ++++++++++++++++++- compiler/rustc_ast/src/attr/mod.rs | 33 +++++++++++--- compiler/rustc_ast/src/visit.rs | 2 + compiler/rustc_ast_pretty/src/pprust/state.rs | 2 +- .../rustc_attr_parsing/src/attributes/cfg.rs | 10 ++--- compiler/rustc_attr_parsing/src/parser.rs | 4 +- .../rustc_attr_parsing/src/validate_attr.rs | 4 +- compiler/rustc_builtin_macros/src/autodiff.rs | 14 +++--- .../src/deriving/generic/mod.rs | 41 +++++++++-------- compiler/rustc_expand/src/expand.rs | 4 +- compiler/rustc_parse/src/parser/attr.rs | 4 +- 11 files changed, 115 insertions(+), 48 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 7c922417ee29..571e840795b5 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -34,6 +34,7 @@ use rustc_span::source_map::{Spanned, respan}; use rustc_span::{ByteSymbol, DUMMY_SP, ErrorGuaranteed, Ident, Span, Symbol, kw, sym}; use thin_vec::{ThinVec, thin_vec}; +use crate::attr::data_structures::CfgEntry; pub use crate::format::*; use crate::token::{self, CommentKind, Delimiter}; use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream}; @@ -3390,7 +3391,7 @@ impl NormalAttr { item: AttrItem { unsafety: Safety::Default, path: Path::from_ident(ident), - args: AttrArgs::Empty, + args: AttrItemKind::Unparsed(AttrArgs::Empty), tokens: None, }, tokens: None, @@ -3402,11 +3403,51 @@ impl NormalAttr { pub struct AttrItem { pub unsafety: Safety, pub path: Path, - pub args: AttrArgs, + pub args: AttrItemKind, // Tokens for the meta item, e.g. just the `foo` within `#[foo]` or `#![foo]`. pub tokens: Option, } +/// Some attributes are stored in a parsed form, for performance reasons. +/// Their arguments don't have to be reparsed everytime they're used +#[derive(Clone, Encodable, Decodable, Debug, Walkable)] +pub enum AttrItemKind { + Parsed(EarlyParsedAttribute), + Unparsed(AttrArgs), +} + +impl AttrItemKind { + pub fn unparsed(self) -> Option { + match self { + AttrItemKind::Unparsed(args) => Some(args), + AttrItemKind::Parsed(_) => None, + } + } + + pub fn unparsed_ref(&self) -> Option<&AttrArgs> { + match self { + AttrItemKind::Unparsed(args) => Some(args), + AttrItemKind::Parsed(_) => None, + } + } + + pub fn span(&self) -> Option { + match self { + AttrItemKind::Unparsed(args) => args.span(), + AttrItemKind::Parsed(_) => None, + } + } +} + +/// Some attributes are stored in parsed form in the AST. +/// This is done for performance reasons, so the attributes don't need to be reparsed on every use. +/// +/// Currently all early parsed attributes are excluded from pretty printing at rustc_ast_pretty::pprust::state::print_attribute_inline. +/// When adding new early parsed attributes, consider whether they should be pretty printed. +#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] +pub enum EarlyParsedAttribute { +} + impl AttrItem { pub fn is_valid_for_outer_style(&self) -> bool { self.path == sym::cfg_attr diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index c0ed6e24e222..6ecba865c815 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -1,5 +1,8 @@ //! Functions dealing with attributes and meta items. +pub mod data_structures; +pub mod version; + use std::fmt::Debug; use std::sync::atomic::{AtomicU32, Ordering}; @@ -8,6 +11,7 @@ use rustc_span::{Ident, Span, Symbol, sym}; use smallvec::{SmallVec, smallvec}; use thin_vec::{ThinVec, thin_vec}; +use crate::AttrItemKind; use crate::ast::{ AttrArgs, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, DUMMY_NODE_ID, DelimArgs, Expr, ExprKind, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NormalAttr, Path, @@ -62,6 +66,15 @@ impl Attribute { } } + /// Replaces the arguments of this attribute with new arguments `AttrItemKind`. + /// This is useful for making this attribute into a trace attribute, and should otherwise be avoided. + pub fn replace_args(&mut self, new_args: AttrItemKind) { + match &mut self.kind { + AttrKind::Normal(normal) => normal.item.args = new_args, + AttrKind::DocComment(..) => panic!("unexpected doc comment"), + } + } + pub fn unwrap_normal_item(self) -> AttrItem { match self.kind { AttrKind::Normal(normal) => normal.item, @@ -77,7 +90,7 @@ impl AttributeExt for Attribute { fn value_span(&self) -> Option { match &self.kind { - AttrKind::Normal(normal) => match &normal.item.args { + AttrKind::Normal(normal) => match &normal.item.args.unparsed_ref()? { AttrArgs::Eq { expr, .. } => Some(expr.span), _ => None, }, @@ -147,7 +160,7 @@ impl AttributeExt for Attribute { fn is_word(&self) -> bool { if let AttrKind::Normal(normal) = &self.kind { - matches!(normal.item.args, AttrArgs::Empty) + matches!(normal.item.args, AttrItemKind::Unparsed(AttrArgs::Empty)) } else { false } @@ -303,7 +316,7 @@ impl AttrItem { } pub fn meta_item_list(&self) -> Option> { - match &self.args { + match &self.args.unparsed_ref()? { AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => { MetaItemKind::list_from_tokens(args.tokens.clone()) } @@ -324,7 +337,7 @@ impl AttrItem { /// #[attr("value")] /// ``` fn value_str(&self) -> Option { - match &self.args { + match &self.args.unparsed_ref()? { AttrArgs::Eq { expr, .. } => match expr.kind { ExprKind::Lit(token_lit) => { LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str()) @@ -348,7 +361,7 @@ impl AttrItem { /// #[attr("value")] /// ``` fn value_span(&self) -> Option { - match &self.args { + match &self.args.unparsed_ref()? { AttrArgs::Eq { expr, .. } => Some(expr.span), AttrArgs::Delimited(_) | AttrArgs::Empty => None, } @@ -364,7 +377,7 @@ impl AttrItem { } pub fn meta_kind(&self) -> Option { - MetaItemKind::from_attr_args(&self.args) + MetaItemKind::from_attr_args(self.args.unparsed_ref()?) } } @@ -699,7 +712,13 @@ fn mk_attr( args: AttrArgs, span: Span, ) -> Attribute { - mk_attr_from_item(g, AttrItem { unsafety, path, args, tokens: None }, None, style, span) + mk_attr_from_item( + g, + AttrItem { unsafety, path, args: AttrItemKind::Unparsed(args), tokens: None }, + None, + style, + span, + ) } pub fn mk_attr_from_item( diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index d122adfdf966..83b751fbde90 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -366,6 +366,7 @@ macro_rules! common_visitor_and_walkers { crate::token::LitKind, crate::tokenstream::LazyAttrTokenStream, crate::tokenstream::TokenStream, + EarlyParsedAttribute, Movability, Mutability, Pinnedness, @@ -457,6 +458,7 @@ macro_rules! common_visitor_and_walkers { ModSpans, MutTy, NormalAttr, + AttrItemKind, Parens, ParenthesizedArgs, PatFieldsRest, diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 1aa08dfd3d5e..0cf0eae821e9 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -694,7 +694,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere } ast::Safety::Default | ast::Safety::Safe(_) => {} } - match &item.args { + match &item.args.unparsed_ref().expect("Parsed attributes are never printed") { AttrArgs::Delimited(DelimArgs { dspan: _, delim, tokens }) => self.print_mac_common( Some(MacHeader::Path(&item.path)), false, diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 66f0f8d391f6..ccf0a394afd0 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -294,11 +294,9 @@ pub fn parse_cfg_attr( sess: &Session, features: Option<&Features>, ) -> Option<(CfgEntry, Vec<(AttrItem, Span)>)> { - match cfg_attr.get_normal_item().args { - ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens }) - if !tokens.is_empty() => - { - check_cfg_attr_bad_delim(&sess.psess, dspan, delim); + match cfg_attr.get_normal_item().args.unparsed_ref().unwrap() { + ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, tokens }) if !tokens.is_empty() => { + check_cfg_attr_bad_delim(&sess.psess, *dspan, *delim); match parse_in(&sess.psess, tokens.clone(), "`cfg_attr` input", |p| { parse_cfg_attr_internal(p, sess, features, cfg_attr) }) { @@ -322,7 +320,7 @@ pub fn parse_cfg_attr( } _ => { let (span, reason) = if let ast::AttrArgs::Delimited(ast::DelimArgs { dspan, .. }) = - cfg_attr.get_normal_item().args + cfg_attr.get_normal_item().args.unparsed_ref()? { (dspan.entire(), AttributeParseErrorReason::ExpectedAtLeastOneArgument) } else { diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 39419dfa4ed8..d79579fdf0b7 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -122,10 +122,10 @@ impl ArgParser { } if args.delim != Delimiter::Parenthesis { - psess.dcx().emit_err(MetaBadDelim { + should_emit.emit_err(psess.dcx().create_err(MetaBadDelim { span: args.dspan.entire(), sugg: MetaBadDelimSugg { open: args.dspan.open, close: args.dspan.close }, - }); + })); return None; } diff --git a/compiler/rustc_attr_parsing/src/validate_attr.rs b/compiler/rustc_attr_parsing/src/validate_attr.rs index 4879646a1107..f56e85b11061 100644 --- a/compiler/rustc_attr_parsing/src/validate_attr.rs +++ b/compiler/rustc_attr_parsing/src/validate_attr.rs @@ -48,7 +48,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) { } _ => { let attr_item = attr.get_normal_item(); - if let AttrArgs::Eq { .. } = attr_item.args { + if let AttrArgs::Eq { .. } = attr_item.args.unparsed_ref().unwrap() { // All key-value attributes are restricted to meta-item syntax. match parse_meta(psess, attr) { Ok(_) => {} @@ -67,7 +67,7 @@ pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Met unsafety: item.unsafety, span: attr.span, path: item.path.clone(), - kind: match &item.args { + kind: match &item.args.unparsed_ref().unwrap() { AttrArgs::Empty => MetaItemKind::Word, AttrArgs::Delimited(DelimArgs { dspan, delim, tokens }) => { check_meta_bad_delim(psess, *dspan, *delim); diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 39abb66df30c..95191b82ff3f 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -358,7 +358,7 @@ mod llvm_enzyme { let inline_item = ast::AttrItem { unsafety: ast::Safety::Default, path: ast::Path::from_ident(Ident::with_dummy_span(sym::inline)), - args: ast::AttrArgs::Delimited(never_arg), + args: rustc_ast::ast::AttrItemKind::Unparsed(ast::AttrArgs::Delimited(never_arg)), tokens: None, }; let inline_never_attr = Box::new(ast::NormalAttr { item: inline_item, tokens: None }); @@ -421,11 +421,13 @@ mod llvm_enzyme { } }; // Now update for d_fn - rustc_ad_attr.item.args = rustc_ast::AttrArgs::Delimited(rustc_ast::DelimArgs { - dspan: DelimSpan::dummy(), - delim: rustc_ast::token::Delimiter::Parenthesis, - tokens: ts, - }); + rustc_ad_attr.item.args = rustc_ast::ast::AttrItemKind::Unparsed( + rustc_ast::AttrArgs::Delimited(rustc_ast::DelimArgs { + dspan: DelimSpan::dummy(), + delim: rustc_ast::token::Delimiter::Parenthesis, + tokens: ts, + }), + ); let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id(); let d_attr = outer_normal_attr(&rustc_ad_attr, new_id, span); diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index bb6557802ece..7c84530abbee 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -807,24 +807,29 @@ impl<'a> TraitDef<'a> { rustc_ast::AttrItem { unsafety: Safety::Default, path: rustc_const_unstable, - args: AttrArgs::Delimited(DelimArgs { - dspan: DelimSpan::from_single(self.span), - delim: rustc_ast::token::Delimiter::Parenthesis, - tokens: [ - TokenKind::Ident(sym::feature, IdentIsRaw::No), - TokenKind::Eq, - TokenKind::lit(LitKind::Str, sym::derive_const, None), - TokenKind::Comma, - TokenKind::Ident(sym::issue, IdentIsRaw::No), - TokenKind::Eq, - TokenKind::lit(LitKind::Str, sym::derive_const_issue, None), - ] - .into_iter() - .map(|kind| { - TokenTree::Token(Token { kind, span: self.span }, Spacing::Alone) - }) - .collect(), - }), + args: rustc_ast::ast::AttrItemKind::Unparsed(AttrArgs::Delimited( + DelimArgs { + dspan: DelimSpan::from_single(self.span), + delim: rustc_ast::token::Delimiter::Parenthesis, + tokens: [ + TokenKind::Ident(sym::feature, IdentIsRaw::No), + TokenKind::Eq, + TokenKind::lit(LitKind::Str, sym::derive_const, None), + TokenKind::Comma, + TokenKind::Ident(sym::issue, IdentIsRaw::No), + TokenKind::Eq, + TokenKind::lit(LitKind::Str, sym::derive_const_issue, None), + ] + .into_iter() + .map(|kind| { + TokenTree::Token( + Token { kind, span: self.span }, + Spacing::Alone, + ) + }) + .collect(), + }, + )), tokens: None, }, self.span, diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 52b7339e0140..8102f8e6dac7 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -813,10 +813,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; let attr_item = attr.get_normal_item(); let safety = attr_item.unsafety; - if let AttrArgs::Eq { .. } = attr_item.args { + if let AttrArgs::Eq { .. } = attr_item.args.unparsed_ref().unwrap() { self.cx.dcx().emit_err(UnsupportedKeyValue { span }); } - let inner_tokens = attr_item.args.inner_tokens(); + let inner_tokens = attr_item.args.unparsed_ref().unwrap().inner_tokens(); match expander.expand_with_safety(self.cx, safety, span, inner_tokens, tokens) { Ok(tok_result) => { let fragment = self.parse_ast_fragment( diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 63109c7ba5cb..1cb9a1b65d65 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -1,7 +1,7 @@ use rustc_ast as ast; use rustc_ast::token::{self, MetaVarKind}; use rustc_ast::tokenstream::ParserRange; -use rustc_ast::{Attribute, attr}; +use rustc_ast::{AttrItemKind, Attribute, attr}; use rustc_errors::codes::*; use rustc_errors::{Diag, PResult}; use rustc_span::{BytePos, Span}; @@ -313,7 +313,7 @@ impl<'a> Parser<'a> { this.expect(exp!(CloseParen))?; } Ok(( - ast::AttrItem { unsafety, path, args, tokens: None }, + ast::AttrItem { unsafety, path, args: AttrItemKind::Unparsed(args), tokens: None }, Trailing::No, UsePreAttrPos::No, )) From 5590fc034c2c965f20844841e9e2a7382b25a0fb Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 26 Dec 2025 20:56:42 +0100 Subject: [PATCH 0289/1061] Make `cfg` and `cfg_attr` trace attributes into early parsed attributes --- compiler/rustc_ast/src/ast.rs | 2 + .../rustc_ast/src/attr/data_structures.rs | 101 ++++++++++++++++++ .../src => rustc_ast/src/attr}/version.rs | 16 +-- .../rustc_attr_parsing/src/early_parsed.rs | 53 +++++++++ compiler/rustc_attr_parsing/src/interface.rs | 44 +++++--- compiler/rustc_attr_parsing/src/lib.rs | 1 + compiler/rustc_attr_parsing/src/safety.rs | 7 +- compiler/rustc_expand/src/config.rs | 8 +- compiler/rustc_expand/src/expand.rs | 57 ++++++---- .../rustc_hir/src/attrs/data_structures.rs | 85 ++------------- .../rustc_hir/src/attrs/encode_cross_crate.rs | 2 + .../rustc_hir/src/attrs/pretty_printing.rs | 4 + compiler/rustc_hir/src/hir.rs | 1 + compiler/rustc_hir/src/lib.rs | 3 +- compiler/rustc_passes/src/check_attr.rs | 6 +- 15 files changed, 247 insertions(+), 143 deletions(-) create mode 100644 compiler/rustc_ast/src/attr/data_structures.rs rename compiler/{rustc_hir/src => rustc_ast/src/attr}/version.rs (75%) create mode 100644 compiler/rustc_attr_parsing/src/early_parsed.rs diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 571e840795b5..d4407dbf7be7 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3446,6 +3446,8 @@ impl AttrItemKind { /// When adding new early parsed attributes, consider whether they should be pretty printed. #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] pub enum EarlyParsedAttribute { + CfgTrace(CfgEntry), + CfgAttrTrace, } impl AttrItem { diff --git a/compiler/rustc_ast/src/attr/data_structures.rs b/compiler/rustc_ast/src/attr/data_structures.rs new file mode 100644 index 000000000000..2eab91801cd6 --- /dev/null +++ b/compiler/rustc_ast/src/attr/data_structures.rs @@ -0,0 +1,101 @@ +use std::fmt; + +use rustc_macros::{Decodable, Encodable, HashStable_Generic}; +use rustc_span::{Span, Symbol}; +use thin_vec::ThinVec; + +use crate::attr::version::RustcVersion; + +#[derive(Encodable, Decodable, Clone, Debug, PartialEq, Eq, Hash, HashStable_Generic)] +pub enum CfgEntry { + All(ThinVec, Span), + Any(ThinVec, Span), + Not(Box, Span), + Bool(bool, Span), + NameValue { name: Symbol, value: Option, span: Span }, + Version(Option, Span), +} + +impl CfgEntry { + pub fn lower_spans(&mut self, lower_span: impl Copy + Fn(Span) -> Span) { + match self { + CfgEntry::All(subs, span) | CfgEntry::Any(subs, span) => { + *span = lower_span(*span); + subs.iter_mut().for_each(|sub| sub.lower_spans(lower_span)); + } + CfgEntry::Not(sub, span) => { + *span = lower_span(*span); + sub.lower_spans(lower_span); + } + CfgEntry::Bool(_, span) + | CfgEntry::NameValue { span, .. } + | CfgEntry::Version(_, span) => { + *span = lower_span(*span); + } + } + } + + pub fn span(&self) -> Span { + let (Self::All(_, span) + | Self::Any(_, span) + | Self::Not(_, span) + | Self::Bool(_, span) + | Self::NameValue { span, .. } + | Self::Version(_, span)) = self; + *span + } + + /// Same as `PartialEq` but doesn't check spans and ignore order of cfgs. + pub fn is_equivalent_to(&self, other: &Self) -> bool { + match (self, other) { + (Self::All(a, _), Self::All(b, _)) | (Self::Any(a, _), Self::Any(b, _)) => { + a.len() == b.len() && a.iter().all(|a| b.iter().any(|b| a.is_equivalent_to(b))) + } + (Self::Not(a, _), Self::Not(b, _)) => a.is_equivalent_to(b), + (Self::Bool(a, _), Self::Bool(b, _)) => a == b, + ( + Self::NameValue { name: name1, value: value1, .. }, + Self::NameValue { name: name2, value: value2, .. }, + ) => name1 == name2 && value1 == value2, + (Self::Version(a, _), Self::Version(b, _)) => a == b, + _ => false, + } + } +} + +impl fmt::Display for CfgEntry { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn write_entries( + name: &str, + entries: &[CfgEntry], + f: &mut fmt::Formatter<'_>, + ) -> fmt::Result { + write!(f, "{name}(")?; + for (nb, entry) in entries.iter().enumerate() { + if nb != 0 { + f.write_str(", ")?; + } + entry.fmt(f)?; + } + f.write_str(")") + } + match self { + Self::All(entries, _) => write_entries("all", entries, f), + Self::Any(entries, _) => write_entries("any", entries, f), + Self::Not(entry, _) => write!(f, "not({entry})"), + Self::Bool(value, _) => write!(f, "{value}"), + Self::NameValue { name, value, .. } => { + match value { + // We use `as_str` and debug display to have characters escaped and `"` + // characters surrounding the string. + Some(value) => write!(f, "{name} = {:?}", value.as_str()), + None => write!(f, "{name}"), + } + } + Self::Version(version, _) => match version { + Some(version) => write!(f, "{version}"), + None => Ok(()), + }, + } + } +} diff --git a/compiler/rustc_hir/src/version.rs b/compiler/rustc_ast/src/attr/version.rs similarity index 75% rename from compiler/rustc_hir/src/version.rs rename to compiler/rustc_ast/src/attr/version.rs index 03182088d4c0..59deee40ae28 100644 --- a/compiler/rustc_hir/src/version.rs +++ b/compiler/rustc_ast/src/attr/version.rs @@ -1,16 +1,10 @@ -use std::borrow::Cow; use std::fmt::{self, Display}; use std::sync::OnceLock; -use rustc_error_messages::{DiagArgValue, IntoDiagArg}; -use rustc_macros::{ - BlobDecodable, Encodable, HashStable_Generic, PrintAttribute, current_rustc_version, -}; - -use crate::attrs::PrintAttribute; +use rustc_macros::{BlobDecodable, Encodable, HashStable_Generic, current_rustc_version}; #[derive(Encodable, BlobDecodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[derive(HashStable_Generic, PrintAttribute)] +#[derive(HashStable_Generic)] pub struct RustcVersion { pub major: u16, pub minor: u16, @@ -47,9 +41,3 @@ impl Display for RustcVersion { write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch) } } - -impl IntoDiagArg for RustcVersion { - fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { - DiagArgValue::Str(Cow::Owned(self.to_string())) - } -} diff --git a/compiler/rustc_attr_parsing/src/early_parsed.rs b/compiler/rustc_attr_parsing/src/early_parsed.rs new file mode 100644 index 000000000000..6a33cb38edf9 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/early_parsed.rs @@ -0,0 +1,53 @@ +use rustc_ast::EarlyParsedAttribute; +use rustc_ast::attr::data_structures::CfgEntry; +use rustc_hir::Attribute; +use rustc_hir::attrs::AttributeKind; +use rustc_span::{Span, Symbol, sym}; +use thin_vec::ThinVec; + +pub(crate) const EARLY_PARSED_ATTRIBUTES: &[&[Symbol]] = + &[&[sym::cfg_trace], &[sym::cfg_attr_trace]]; + +/// This struct contains the state necessary to convert early parsed attributes to hir attributes +/// The only conversion that really happens here is that multiple early parsed attributes are +/// merged into a single hir attribute, representing their combined state. +/// FIXME: We should make this a nice and extendable system if this is going to be used more often +#[derive(Default)] +pub(crate) struct EarlyParsedState { + /// Attribute state for `#[cfg]` trace attributes + cfg_trace: ThinVec<(CfgEntry, Span)>, + + /// Attribute state for `#[cfg_attr]` trace attributes + /// The arguments of these attributes is no longer relevant for any later passes, only their presence. + /// So we discard the arguments here. + cfg_attr_trace: bool, +} + +impl EarlyParsedState { + pub(crate) fn accept_early_parsed_attribute( + &mut self, + attr_span: Span, + lower_span: impl Copy + Fn(Span) -> Span, + parsed: &EarlyParsedAttribute, + ) { + match parsed { + EarlyParsedAttribute::CfgTrace(cfg) => { + let mut cfg = cfg.clone(); + cfg.lower_spans(lower_span); + self.cfg_trace.push((cfg, attr_span)); + } + EarlyParsedAttribute::CfgAttrTrace => { + self.cfg_attr_trace = true; + } + } + } + + pub(crate) fn finalize_early_parsed_attributes(self, attributes: &mut Vec) { + if !self.cfg_trace.is_empty() { + attributes.push(Attribute::Parsed(AttributeKind::CfgTrace(self.cfg_trace))); + } + if self.cfg_attr_trace { + attributes.push(Attribute::Parsed(AttributeKind::CfgAttrTrace)); + } + } +} diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 91596ff0de60..e38fffa6587c 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -2,7 +2,7 @@ use std::convert::identity; use rustc_ast as ast; use rustc_ast::token::DocFragmentKind; -use rustc_ast::{AttrStyle, NodeId, Safety}; +use rustc_ast::{AttrItemKind, AttrStyle, NodeId, Safety}; use rustc_errors::DiagCtxtHandle; use rustc_feature::{AttributeTemplate, Features}; use rustc_hir::attrs::AttributeKind; @@ -13,6 +13,7 @@ use rustc_session::lint::BuiltinLintDiag; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use crate::context::{AcceptContext, FinalizeContext, SharedContext, Stage}; +use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState}; use crate::parser::{ArgParser, PathParser, RefPathParser}; use crate::session_diagnostics::ParsedDescription; use crate::{Early, Late, OmitDoc, ShouldEmit}; @@ -146,8 +147,12 @@ impl<'sess> AttributeParser<'sess, Early> { normal_attr.item.path.segments.iter().map(|seg| seg.ident.name).collect::>(); let path = AttrPath::from_ast(&normal_attr.item.path, identity); - let args = - ArgParser::from_attr_args(&normal_attr.item.args, &parts, &sess.psess, emit_errors)?; + let args = ArgParser::from_attr_args( + &normal_attr.item.args.unparsed_ref().unwrap(), + &parts, + &sess.psess, + emit_errors, + )?; Self::parse_single_args( sess, attr.span, @@ -263,12 +268,12 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { target_id: S::Id, target: Target, omit_doc: OmitDoc, - lower_span: impl Copy + Fn(Span) -> Span, mut emit_lint: impl FnMut(AttributeLint), ) -> Vec { let mut attributes = Vec::new(); let mut attr_paths: Vec> = Vec::new(); + let mut early_parsed_state = EarlyParsedState::default(); for attr in attrs { // If we're only looking for a single attribute, skip all the ones we don't care about. @@ -288,6 +293,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { continue; } + let attr_span = lower_span(attr.span); match &attr.kind { ast::AttrKind::DocComment(comment_kind, symbol) => { if omit_doc == OmitDoc::Skip { @@ -297,7 +303,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { attributes.push(Attribute::Parsed(AttributeKind::DocComment { style: attr.style, kind: DocFragmentKind::Sugared(*comment_kind), - span: lower_span(attr.span), + span: attr_span, comment: *symbol, })) } @@ -305,6 +311,15 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { attr_paths.push(PathParser(&n.item.path)); let attr_path = AttrPath::from_ast(&n.item.path, lower_span); + let args = match &n.item.args { + AttrItemKind::Unparsed(args) => args, + AttrItemKind::Parsed(parsed) => { + early_parsed_state + .accept_early_parsed_attribute(attr_span, lower_span, parsed); + continue; + } + }; + self.check_attribute_safety( &attr_path, lower_span(n.item.span()), @@ -318,7 +333,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { if let Some(accepts) = S::parsers().accepters.get(parts.as_slice()) { let Some(args) = ArgParser::from_attr_args( - &n.item.args, + args, &parts, &self.sess.psess, self.stage.should_emit(), @@ -351,7 +366,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { attributes.push(Attribute::Parsed(AttributeKind::DocComment { style: attr.style, kind: DocFragmentKind::Raw(nv.value_span), - span: attr.span, + span: attr_span, comment, })); continue; @@ -365,7 +380,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { target_id, emit_lint: &mut emit_lint, }, - attr_span: lower_span(attr.span), + attr_span, inner_span: lower_span(n.item.span()), attr_style: attr.style, parsed_description: ParsedDescription::Attribute, @@ -396,17 +411,18 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { attributes.push(Attribute::Unparsed(Box::new(AttrItem { path: attr_path.clone(), - args: self.lower_attr_args(&n.item.args, lower_span), + args: self + .lower_attr_args(n.item.args.unparsed_ref().unwrap(), lower_span), id: HashIgnoredAttrId { attr_id: attr.id }, style: attr.style, - span: lower_span(attr.span), + span: attr_span, }))); } } } } - let mut parsed_attributes = Vec::new(); + early_parsed_state.finalize_early_parsed_attributes(&mut attributes); for f in &S::parsers().finalizers { if let Some(attr) = f(&mut FinalizeContext { shared: SharedContext { @@ -417,18 +433,16 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { }, all_attrs: &attr_paths, }) { - parsed_attributes.push(Attribute::Parsed(attr)); + attributes.push(Attribute::Parsed(attr)); } } - attributes.extend(parsed_attributes); - attributes } /// Returns whether there is a parser for an attribute with this name pub fn is_parsed_attribute(path: &[Symbol]) -> bool { - Late::parsers().accepters.contains_key(path) + Late::parsers().accepters.contains_key(path) || EARLY_PARSED_ATTRIBUTES.contains(&path) } fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs { diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 411b4dd75e66..349e6c234520 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -99,6 +99,7 @@ mod interface; /// like lists or name-value pairs. pub mod parser; +mod early_parsed; mod safety; mod session_diagnostics; mod target_checking; diff --git a/compiler/rustc_attr_parsing/src/safety.rs b/compiler/rustc_attr_parsing/src/safety.rs index 68aeca2bbda9..9fca57f88025 100644 --- a/compiler/rustc_attr_parsing/src/safety.rs +++ b/compiler/rustc_attr_parsing/src/safety.rs @@ -4,7 +4,7 @@ use rustc_hir::AttrPath; use rustc_hir::lints::{AttributeLint, AttributeLintKind}; use rustc_session::lint::LintId; use rustc_session::lint::builtin::UNSAFE_ATTR_OUTSIDE_UNSAFE; -use rustc_span::{Span, sym}; +use rustc_span::Span; use crate::context::Stage; use crate::{AttributeParser, ShouldEmit}; @@ -23,11 +23,6 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { } let name = (attr_path.segments.len() == 1).then_some(attr_path.segments[0]); - if let Some(name) = name - && [sym::cfg_trace, sym::cfg_attr_trace].contains(&name) - { - return; - } // FIXME: We should retrieve this information from the attribute parsers instead of from `BUILTIN_ATTRIBUTE_MAP` let builtin_attr_info = name.and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name)); diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 492c845df171..28f711f362bd 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -7,8 +7,8 @@ use rustc_ast::tokenstream::{ AttrTokenStream, AttrTokenTree, LazyAttrTokenStream, Spacing, TokenTree, }; use rustc_ast::{ - self as ast, AttrKind, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, MetaItemInner, - NodeId, NormalAttr, + self as ast, AttrItemKind, AttrKind, AttrStyle, Attribute, EarlyParsedAttribute, HasAttrs, + HasTokens, MetaItem, MetaItemInner, NodeId, NormalAttr, }; use rustc_attr_parsing as attr; use rustc_attr_parsing::{ @@ -288,7 +288,9 @@ impl<'a> StripUnconfigured<'a> { pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> Vec { // A trace attribute left in AST in place of the original `cfg_attr` attribute. // It can later be used by lints or other diagnostics. - let trace_attr = attr_into_trace(cfg_attr.clone(), sym::cfg_attr_trace); + let mut trace_attr = cfg_attr.clone(); + trace_attr.replace_args(AttrItemKind::Parsed(EarlyParsedAttribute::CfgAttrTrace)); + let trace_attr = attr_into_trace(trace_attr, sym::cfg_attr_trace); let Some((cfg_predicate, expanded_attrs)) = rustc_attr_parsing::parse_cfg_attr(cfg_attr, &self.sess, self.features) diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 8102f8e6dac7..c130d9f59940 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -7,12 +7,16 @@ use rustc_ast::mut_visit::*; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, AssocCtxt, Visitor, VisitorResult, try_visit, walk_list}; use rustc_ast::{ - self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, DUMMY_NODE_ID, - ExprKind, ForeignItemKind, HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemInner, - MetaItemKind, ModKind, NodeId, PatKind, StmtKind, TyKind, token, + self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrItemKind, AttrStyle, AttrVec, + DUMMY_NODE_ID, EarlyParsedAttribute, ExprKind, ForeignItemKind, HasAttrs, HasNodeId, Inline, + ItemKind, MacStmtStyle, MetaItemInner, MetaItemKind, ModKind, NodeId, PatKind, StmtKind, + TyKind, token, }; use rustc_ast_pretty::pprust; -use rustc_attr_parsing::{AttributeParser, Early, EvalConfigResult, ShouldEmit, validate_attr}; +use rustc_attr_parsing::{ + AttributeParser, CFG_TEMPLATE, Early, EvalConfigResult, ShouldEmit, eval_config_entry, + parse_cfg, validate_attr, +}; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::PResult; @@ -2188,21 +2192,17 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { && !AttributeParser::::is_parsed_attribute(&attr.path()) { let attr_name = attr.name().unwrap(); - // `#[cfg]` and `#[cfg_attr]` are special - they are - // eagerly evaluated. - if attr_name != sym::cfg_trace && attr_name != sym::cfg_attr_trace { - self.cx.sess.psess.buffer_lint( - UNUSED_ATTRIBUTES, - attr.span, - self.cx.current_expansion.lint_node_id, - crate::errors::UnusedBuiltinAttribute { - attr_name, - macro_name: pprust::path_to_string(&call.path), - invoc_span: call.path.span, - attr_span: attr.span, - }, - ); - } + self.cx.sess.psess.buffer_lint( + UNUSED_ATTRIBUTES, + attr.span, + self.cx.current_expansion.lint_node_id, + crate::errors::UnusedBuiltinAttribute { + attr_name, + macro_name: pprust::path_to_string(&call.path), + invoc_span: call.path.span, + attr_span: attr.span, + }, + ); } } } @@ -2213,11 +2213,26 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { attr: ast::Attribute, pos: usize, ) -> EvalConfigResult { - let res = self.cfg().cfg_true(&attr, ShouldEmit::ErrorsAndLints); + let Some(cfg) = AttributeParser::parse_single( + self.cfg().sess, + &attr, + attr.span, + self.cfg().lint_node_id, + self.cfg().features, + ShouldEmit::ErrorsAndLints, + parse_cfg, + &CFG_TEMPLATE, + ) else { + // Cfg attribute was not parsable, give up + return EvalConfigResult::True; + }; + + let res = eval_config_entry(self.cfg().sess, &cfg); if res.as_bool() { // A trace attribute left in AST in place of the original `cfg` attribute. // It can later be used by lints or other diagnostics. - let trace_attr = attr_into_trace(attr, sym::cfg_trace); + let mut trace_attr = attr_into_trace(attr, sym::cfg_trace); + trace_attr.replace_args(AttrItemKind::Parsed(EarlyParsedAttribute::CfgTrace(cfg))); node.visit_attrs(|attrs| attrs.insert(pos, trace_attr)); } diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index f418c391ece7..fa8998f0546d 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1,9 +1,9 @@ use std::borrow::Cow; -use std::fmt; use std::path::PathBuf; pub use ReprAttr::*; use rustc_abi::Align; +pub use rustc_ast::attr::data_structures::*; use rustc_ast::token::DocFragmentKind; use rustc_ast::{AttrStyle, ast}; use rustc_data_structures::fx::FxIndexMap; @@ -212,83 +212,6 @@ impl StrippedCfgItem { } } -#[derive(Encodable, Decodable, Clone, Debug, PartialEq, Eq, Hash)] -#[derive(HashStable_Generic, PrintAttribute)] -pub enum CfgEntry { - All(ThinVec, Span), - Any(ThinVec, Span), - Not(Box, Span), - Bool(bool, Span), - NameValue { name: Symbol, value: Option, span: Span }, - Version(Option, Span), -} - -impl CfgEntry { - pub fn span(&self) -> Span { - let (Self::All(_, span) - | Self::Any(_, span) - | Self::Not(_, span) - | Self::Bool(_, span) - | Self::NameValue { span, .. } - | Self::Version(_, span)) = self; - *span - } - - /// Same as `PartialEq` but doesn't check spans and ignore order of cfgs. - pub fn is_equivalent_to(&self, other: &Self) -> bool { - match (self, other) { - (Self::All(a, _), Self::All(b, _)) | (Self::Any(a, _), Self::Any(b, _)) => { - a.len() == b.len() && a.iter().all(|a| b.iter().any(|b| a.is_equivalent_to(b))) - } - (Self::Not(a, _), Self::Not(b, _)) => a.is_equivalent_to(b), - (Self::Bool(a, _), Self::Bool(b, _)) => a == b, - ( - Self::NameValue { name: name1, value: value1, .. }, - Self::NameValue { name: name2, value: value2, .. }, - ) => name1 == name2 && value1 == value2, - (Self::Version(a, _), Self::Version(b, _)) => a == b, - _ => false, - } - } -} - -impl fmt::Display for CfgEntry { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fn write_entries( - name: &str, - entries: &[CfgEntry], - f: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - write!(f, "{name}(")?; - for (nb, entry) in entries.iter().enumerate() { - if nb != 0 { - f.write_str(", ")?; - } - entry.fmt(f)?; - } - f.write_str(")") - } - match self { - Self::All(entries, _) => write_entries("all", entries, f), - Self::Any(entries, _) => write_entries("any", entries, f), - Self::Not(entry, _) => write!(f, "not({entry})"), - Self::Bool(value, _) => write!(f, "{value}"), - Self::NameValue { name, value, .. } => { - match value { - // We use `as_str` and debug display to have characters escaped and `"` - // characters surrounding the string. - Some(value) => write!(f, "{name} = {:?}", value.as_str()), - None => write!(f, "{name}"), - } - } - Self::Version(version, _) => match version { - Some(version) => write!(f, "{version}"), - None => Ok(()), - }, - } - } -} - /// Possible values for the `#[linkage]` attribute, allowing to specify the /// linkage type for a `MonoItem`. /// @@ -713,6 +636,12 @@ pub enum AttributeKind { span: Span, }, + /// Represents the trace attribute of `#[cfg_attr]` + CfgAttrTrace, + + /// Represents the trace attribute of `#[cfg]` + CfgTrace(ThinVec<(CfgEntry, Span)>), + /// Represents `#[cfi_encoding]` CfiEncoding { encoding: Symbol }, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 57d2d6c5875e..3efa876ed6a9 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -26,6 +26,8 @@ impl AttributeKind { AsPtr(..) => Yes, AutomaticallyDerived(..) => Yes, BodyStability { .. } => No, + CfgAttrTrace => Yes, + CfgTrace(..) => Yes, CfiEncoding { .. } => Yes, Coinductive(..) => No, Cold(..) => No, diff --git a/compiler/rustc_hir/src/attrs/pretty_printing.rs b/compiler/rustc_hir/src/attrs/pretty_printing.rs index f8ac2a547ca8..806f5c4d3ed9 100644 --- a/compiler/rustc_hir/src/attrs/pretty_printing.rs +++ b/compiler/rustc_hir/src/attrs/pretty_printing.rs @@ -2,6 +2,8 @@ use std::num::NonZero; use std::ops::Deref; use rustc_abi::Align; +use rustc_ast::attr::data_structures::CfgEntry; +use rustc_ast::attr::version::RustcVersion; use rustc_ast::token::{CommentKind, DocFragmentKind}; use rustc_ast::{AttrStyle, IntTy, UintTy}; use rustc_ast_pretty::pp::Printer; @@ -182,4 +184,6 @@ print_debug!( Transparency, SanitizerSet, DefId, + RustcVersion, + CfgEntry, ); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e13782282891..1a9bc8a2781b 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1371,6 +1371,7 @@ impl AttributeExt for Attribute { // FIXME: should not be needed anymore when all attrs are parsed Attribute::Parsed(AttributeKind::DocComment { span, .. }) => *span, Attribute::Parsed(AttributeKind::Deprecation { span, .. }) => *span, + Attribute::Parsed(AttributeKind::CfgTrace(cfgs)) => cfgs[0].1, a => panic!("can't get the span of an arbitrary parsed attribute: {a:?}"), } } diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 7c9c15c16df4..fa46c0f085a2 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -33,7 +33,6 @@ pub mod pat_util; mod stability; mod stable_hash_impls; mod target; -mod version; pub mod weak_lang_items; #[cfg(test)] @@ -42,9 +41,9 @@ mod tests; #[doc(no_inline)] pub use hir::*; pub use lang_items::{LangItem, LanguageItems}; +pub use rustc_ast::attr::version::*; pub use stability::*; pub use stable_hash_impls::HashStableContext; pub use target::{MethodKind, Target}; -pub use version::*; arena_types!(rustc_arena::declare_arena); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 7516460155e7..f1cbb72554d2 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -229,6 +229,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect | AttributeKind::MacroTransparency(_) + | AttributeKind::CfgTrace(..) | AttributeKind::Pointee(..) | AttributeKind::Dummy | AttributeKind::RustcBuiltinMacro { .. } @@ -302,6 +303,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcPassIndirectlyInNonRusticAbis(..) | AttributeKind::PinV2(..) | AttributeKind::WindowsSubsystem(..) + | AttributeKind::CfgAttrTrace | AttributeKind::ThreadLocal | AttributeKind::CfiEncoding { .. } ) => { /* do nothing */ } @@ -338,8 +340,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::forbid | sym::cfg | sym::cfg_attr - | sym::cfg_trace - | sym::cfg_attr_trace // need to be fixed | sym::patchable_function_entry // FIXME(patchable_function_entry) | sym::deprecated_safe // FIXME(deprecated_safe) @@ -1950,12 +1950,10 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { // only `#[cfg]` and `#[cfg_attr]` are allowed, but it should be removed // if we allow more attributes (e.g., tool attributes and `allow/deny/warn`) // in where clauses. After that, only `self.check_attributes` should be enough. - const ATTRS_ALLOWED: &[Symbol] = &[sym::cfg_trace, sym::cfg_attr_trace]; let spans = self .tcx .hir_attrs(where_predicate.hir_id) .iter() - .filter(|attr| !ATTRS_ALLOWED.iter().any(|&sym| attr.has_name(sym))) // FIXME: We shouldn't need to special-case `doc`! .filter(|attr| { matches!( From 442981441294894978b8a1ce9cefcf52e2755bcd Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 26 Dec 2025 20:57:26 +0100 Subject: [PATCH 0290/1061] Convert librustdoc to use the new parsed representation --- src/librustdoc/clean/cfg.rs | 129 +------------------- src/librustdoc/clean/cfg/tests.rs | 133 --------------------- src/librustdoc/clean/mod.rs | 16 +-- src/librustdoc/passes/propagate_doc_cfg.rs | 6 +- 4 files changed, 11 insertions(+), 273 deletions(-) diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 61ebc73182c0..485af5ab1d01 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -7,7 +7,6 @@ use std::sync::Arc; use std::{fmt, mem, ops}; use itertools::Either; -use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::thin_vec::{ThinVec, thin_vec}; use rustc_hir as hir; @@ -29,12 +28,6 @@ mod tests; #[cfg_attr(test, derive(PartialEq))] pub(crate) struct Cfg(CfgEntry); -#[derive(PartialEq, Debug)] -pub(crate) struct InvalidCfgError { - pub(crate) msg: &'static str, - pub(crate) span: Span, -} - /// Whether the configuration consists of just `Cfg` or `Not`. fn is_simple_cfg(cfg: &CfgEntry) -> bool { match cfg { @@ -105,106 +98,6 @@ fn should_capitalize_first_letter(cfg: &CfgEntry) -> bool { } impl Cfg { - /// Parses a `MetaItemInner` into a `Cfg`. - fn parse_nested( - nested_cfg: &MetaItemInner, - exclude: &FxHashSet, - ) -> Result, InvalidCfgError> { - match nested_cfg { - MetaItemInner::MetaItem(cfg) => Cfg::parse_without(cfg, exclude), - MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => { - Ok(Some(Cfg(CfgEntry::Bool(*b, DUMMY_SP)))) - } - MetaItemInner::Lit(lit) => { - Err(InvalidCfgError { msg: "unexpected literal", span: lit.span }) - } - } - } - - fn parse_without( - cfg: &MetaItem, - exclude: &FxHashSet, - ) -> Result, InvalidCfgError> { - let name = match cfg.ident() { - Some(ident) => ident.name, - None => { - return Err(InvalidCfgError { - msg: "expected a single identifier", - span: cfg.span, - }); - } - }; - match cfg.kind { - MetaItemKind::Word => { - if exclude.contains(&NameValueCfg::new(name)) { - Ok(None) - } else { - Ok(Some(Cfg(CfgEntry::NameValue { name, value: None, span: DUMMY_SP }))) - } - } - MetaItemKind::NameValue(ref lit) => match lit.kind { - LitKind::Str(value, _) => { - if exclude.contains(&NameValueCfg::new_value(name, value)) { - Ok(None) - } else { - Ok(Some(Cfg(CfgEntry::NameValue { - name, - value: Some(value), - span: DUMMY_SP, - }))) - } - } - _ => Err(InvalidCfgError { - // FIXME: if the main #[cfg] syntax decided to support non-string literals, - // this should be changed as well. - msg: "value of cfg option should be a string literal", - span: lit.span, - }), - }, - MetaItemKind::List(ref items) => { - let orig_len = items.len(); - let mut sub_cfgs = - items.iter().filter_map(|i| Cfg::parse_nested(i, exclude).transpose()); - let ret = match name { - sym::all => { - sub_cfgs.try_fold(Cfg(CfgEntry::Bool(true, DUMMY_SP)), |x, y| Ok(x & y?)) - } - sym::any => { - sub_cfgs.try_fold(Cfg(CfgEntry::Bool(false, DUMMY_SP)), |x, y| Ok(x | y?)) - } - sym::not => { - if orig_len == 1 { - let mut sub_cfgs = sub_cfgs.collect::>(); - if sub_cfgs.len() == 1 { - Ok(!sub_cfgs.pop().unwrap()?) - } else { - return Ok(None); - } - } else { - Err(InvalidCfgError { msg: "expected 1 cfg-pattern", span: cfg.span }) - } - } - _ => Err(InvalidCfgError { msg: "invalid predicate", span: cfg.span }), - }; - match ret { - Ok(c) => Ok(Some(c)), - Err(e) => Err(e), - } - } - } - } - - /// Parses a `MetaItem` into a `Cfg`. - /// - /// The `MetaItem` should be the content of the `#[cfg(...)]`, e.g., `unix` or - /// `target_os = "redox"`. - /// - /// If the content is not properly formatted, it will return an error indicating what and where - /// the error is. - pub(crate) fn parse(cfg: &MetaItemInner) -> Result { - Self::parse_nested(cfg, &FxHashSet::default()).map(|ret| ret.unwrap()) - } - /// Renders the configuration for human display, as a short HTML description. pub(crate) fn render_short_html(&self) -> String { let mut msg = Display(&self.0, Format::ShortHtml).to_string(); @@ -644,10 +537,6 @@ impl NameValueCfg { fn new(name: Symbol) -> Self { Self { name, value: None } } - - fn new_value(name: Symbol, value: Symbol) -> Self { - Self { name, value: Some(value) } - } } impl<'a> From<&'a CfgEntry> for NameValueCfg { @@ -751,15 +640,6 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator tcx: TyCtxt<'_>, cfg_info: &mut CfgInfo, ) -> Option> { - fn single(it: T) -> Option { - let mut iter = it.into_iter(); - let item = iter.next()?; - if iter.next().is_some() { - return None; - } - Some(item) - } - fn check_changed_auto_active_status( changed_auto_active_status: &mut Option, attr_span: Span, @@ -859,12 +739,11 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator } continue; } else if !cfg_info.parent_is_doc_cfg - && let Some(name) = attr.name() - && matches!(name, sym::cfg | sym::cfg_trace) - && let Some(attr) = single(attr.meta_item_list()?) - && let Ok(new_cfg) = Cfg::parse(&attr) + && let hir::Attribute::Parsed(AttributeKind::CfgTrace(cfgs)) = attr { - cfg_info.current_cfg &= new_cfg; + for (new_cfg, _) in cfgs { + cfg_info.current_cfg &= Cfg(new_cfg.clone()); + } } } diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs index 09316ead76ac..e0c21865d8df 100644 --- a/src/librustdoc/clean/cfg/tests.rs +++ b/src/librustdoc/clean/cfg/tests.rs @@ -1,8 +1,5 @@ -use rustc_ast::ast::LitIntType; -use rustc_ast::{MetaItemInner, MetaItemLit, Path, Safety, StrStyle}; use rustc_data_structures::thin_vec::thin_vec; use rustc_hir::attrs::CfgEntry; -use rustc_span::symbol::{Ident, kw}; use rustc_span::{DUMMY_SP, create_default_session_globals_then}; use super::*; @@ -28,10 +25,6 @@ fn name_value_cfg_e(name: &str, value: &str) -> CfgEntry { } } -fn dummy_lit(symbol: Symbol, kind: LitKind) -> MetaItemInner { - MetaItemInner::Lit(MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP }) -} - fn cfg_all(v: ThinVec) -> Cfg { Cfg(cfg_all_e(v)) } @@ -52,51 +45,6 @@ fn cfg_not(v: CfgEntry) -> Cfg { Cfg(CfgEntry::Not(Box::new(v), DUMMY_SP)) } -fn dummy_meta_item_word(name: &str) -> MetaItemInner { - MetaItemInner::MetaItem(MetaItem { - unsafety: Safety::Default, - path: Path::from_ident(Ident::from_str(name)), - kind: MetaItemKind::Word, - span: DUMMY_SP, - }) -} - -fn dummy_meta_item_name_value(name: &str, symbol: Symbol, kind: LitKind) -> MetaItemInner { - let lit = MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP }; - MetaItemInner::MetaItem(MetaItem { - unsafety: Safety::Default, - path: Path::from_ident(Ident::from_str(name)), - kind: MetaItemKind::NameValue(lit), - span: DUMMY_SP, - }) -} - -macro_rules! dummy_meta_item_list { - ($name:ident, [$($list:ident),* $(,)?]) => { - MetaItemInner::MetaItem(MetaItem { - unsafety: Safety::Default, - path: Path::from_ident(Ident::from_str(stringify!($name))), - kind: MetaItemKind::List(thin_vec![ - $( - dummy_meta_item_word(stringify!($list)), - )* - ]), - span: DUMMY_SP, - }) - }; - - ($name:ident, [$($list:expr),* $(,)?]) => { - MetaItemInner::MetaItem(MetaItem { - unsafety: Safety::Default, - path: Path::from_ident(Ident::from_str(stringify!($name))), - kind: MetaItemKind::List(thin_vec![ - $($list,)* - ]), - span: DUMMY_SP, - }) - }; -} - fn cfg_true() -> Cfg { Cfg(CfgEntry::Bool(true, DUMMY_SP)) } @@ -303,87 +251,6 @@ fn test_cfg_or() { }) } -#[test] -fn test_parse_ok() { - create_default_session_globals_then(|| { - let r#true = Symbol::intern("true"); - let mi = dummy_lit(r#true, LitKind::Bool(true)); - assert_eq!(Cfg::parse(&mi), Ok(cfg_true())); - - let r#false = Symbol::intern("false"); - let mi = dummy_lit(r#false, LitKind::Bool(false)); - assert_eq!(Cfg::parse(&mi), Ok(cfg_false())); - - let mi = dummy_meta_item_word("all"); - assert_eq!(Cfg::parse(&mi), Ok(word_cfg("all"))); - - let done = Symbol::intern("done"); - let mi = dummy_meta_item_name_value("all", done, LitKind::Str(done, StrStyle::Cooked)); - assert_eq!(Cfg::parse(&mi), Ok(name_value_cfg("all", "done"))); - - let mi = dummy_meta_item_list!(all, [a, b]); - assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") & word_cfg("b"))); - - let mi = dummy_meta_item_list!(any, [a, b]); - assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") | word_cfg("b"))); - - let mi = dummy_meta_item_list!(not, [a]); - assert_eq!(Cfg::parse(&mi), Ok(!word_cfg("a"))); - - let mi = dummy_meta_item_list!( - not, - [dummy_meta_item_list!( - any, - [dummy_meta_item_word("a"), dummy_meta_item_list!(all, [b, c]),] - ),] - ); - assert_eq!(Cfg::parse(&mi), Ok(!(word_cfg("a") | (word_cfg("b") & word_cfg("c"))))); - - let mi = dummy_meta_item_list!(all, [a, b, c]); - assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") & word_cfg("b") & word_cfg("c"))); - }) -} - -#[test] -fn test_parse_err() { - create_default_session_globals_then(|| { - let mi = dummy_meta_item_name_value("foo", kw::False, LitKind::Bool(false)); - assert!(Cfg::parse(&mi).is_err()); - - let mi = dummy_meta_item_list!(not, [a, b]); - assert!(Cfg::parse(&mi).is_err()); - - let mi = dummy_meta_item_list!(not, []); - assert!(Cfg::parse(&mi).is_err()); - - let mi = dummy_meta_item_list!(foo, []); - assert!(Cfg::parse(&mi).is_err()); - - let mi = dummy_meta_item_list!( - all, - [dummy_meta_item_list!(foo, []), dummy_meta_item_word("b"),] - ); - assert!(Cfg::parse(&mi).is_err()); - - let mi = dummy_meta_item_list!( - any, - [dummy_meta_item_word("a"), dummy_meta_item_list!(foo, []),] - ); - assert!(Cfg::parse(&mi).is_err()); - - let mi = dummy_meta_item_list!(not, [dummy_meta_item_list!(foo, []),]); - assert!(Cfg::parse(&mi).is_err()); - - let c = Symbol::intern("e"); - let mi = dummy_lit(c, LitKind::Char('e')); - assert!(Cfg::parse(&mi).is_err()); - - let five = Symbol::intern("5"); - let mi = dummy_lit(five, LitKind::Int(5.into(), LitIntType::Unsuffixed)); - assert!(Cfg::parse(&mi).is_err()); - }) -} - #[test] fn test_render_short_html() { create_default_session_globals_then(|| { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0768e6a56b3c..8de3722fa69d 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -51,7 +51,7 @@ use rustc_middle::ty::{self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeVisitableE use rustc_middle::{bug, span_bug}; use rustc_span::ExpnKind; use rustc_span::hygiene::{AstPass, MacroKind}; -use rustc_span::symbol::{Ident, Symbol, kw, sym}; +use rustc_span::symbol::{Ident, Symbol, kw}; use rustc_trait_selection::traits::wf::object_region_bounds; use tracing::{debug, instrument}; use utils::*; @@ -2682,17 +2682,13 @@ fn add_without_unwanted_attributes<'hir>( import_parent, )); } - hir::Attribute::Unparsed(normal) if let [name] = &*normal.path.segments => { - if is_inline || *name != sym::cfg_trace { - // If it's not a `cfg()` attribute, we keep it. - attrs.push((Cow::Borrowed(attr), import_parent)); - } - } - // FIXME: make sure to exclude `#[cfg_trace]` here when it is ported to the new parsers - hir::Attribute::Parsed(..) => { + + // We discard `#[cfg(...)]` attributes unless we're inlining + hir::Attribute::Parsed(AttributeKind::CfgTrace(..)) if !is_inline => {} + // We keep all other attributes + _ => { attrs.push((Cow::Borrowed(attr), import_parent)); } - _ => {} } } } diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index d4bf74c29514..54da158d4d39 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -2,7 +2,6 @@ use rustc_hir::Attribute; use rustc_hir::attrs::{AttributeKind, DocAttribute}; -use rustc_span::symbol::sym; use crate::clean::inline::{load_attrs, merge_attrs}; use crate::clean::{CfgInfo, Crate, Item, ItemKind}; @@ -39,10 +38,7 @@ fn add_only_cfg_attributes(attrs: &mut Vec, new_attrs: &[Attribute]) let mut new_attr = DocAttribute::default(); new_attr.cfg = d.cfg.clone(); attrs.push(Attribute::Parsed(AttributeKind::Doc(Box::new(new_attr)))); - } else if let Attribute::Unparsed(normal) = attr - && let [name] = &*normal.path.segments - && *name == sym::cfg_trace - { + } else if let Attribute::Parsed(AttributeKind::CfgTrace(..)) = attr { // If it's a `cfg()` attribute, we keep it. attrs.push(attr.clone()); } From e9fdf11c665f194bc269794e8523f61c7fb1591a Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 26 Dec 2025 20:57:35 +0100 Subject: [PATCH 0291/1061] Convert clippy to use the new parsed representation --- .../clippy/clippy_lints/src/attrs/mod.rs | 4 +- .../src/attrs/should_panic_without_expect.rs | 6 +-- .../clippy/clippy_lints/src/cfg_not_test.rs | 52 +++++++++++-------- .../src/doc/include_in_doc_without_cfg.rs | 4 +- .../clippy_lints/src/incompatible_msrv.rs | 9 ++-- .../clippy_lints/src/large_include_file.rs | 3 +- .../clippy_lints/src/methods/is_empty.rs | 5 +- .../clippy_lints/src/new_without_default.rs | 11 ++-- .../clippy/clippy_utils/src/ast_utils/mod.rs | 10 +++- src/tools/clippy/clippy_utils/src/lib.rs | 25 ++++----- 10 files changed, 72 insertions(+), 57 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs index 679ccfb8de3a..366f5873a1aa 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs @@ -16,7 +16,7 @@ mod utils; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::msrvs::{self, Msrv, MsrvStack}; -use rustc_ast::{self as ast, AttrArgs, AttrKind, Attribute, MetaItemInner, MetaItemKind}; +use rustc_ast::{self as ast, AttrArgs, AttrKind, Attribute, MetaItemInner, MetaItemKind, AttrItemKind}; use rustc_hir::{ImplItem, Item, ItemKind, TraitItem}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -604,7 +604,7 @@ impl EarlyLintPass for PostExpansionEarlyAttributes { if attr.has_name(sym::ignore) && match &attr.kind { - AttrKind::Normal(normal_attr) => !matches!(normal_attr.item.args, AttrArgs::Eq { .. }), + AttrKind::Normal(normal_attr) => !matches!(normal_attr.item.args, AttrItemKind::Unparsed(AttrArgs::Eq { .. })), AttrKind::DocComment(..) => true, } { diff --git a/src/tools/clippy/clippy_lints/src/attrs/should_panic_without_expect.rs b/src/tools/clippy/clippy_lints/src/attrs/should_panic_without_expect.rs index fd27e30a67f3..b854a3070bef 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/should_panic_without_expect.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/should_panic_without_expect.rs @@ -2,19 +2,19 @@ use super::{Attribute, SHOULD_PANIC_WITHOUT_EXPECT}; use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_ast::token::{Token, TokenKind}; use rustc_ast::tokenstream::TokenTree; -use rustc_ast::{AttrArgs, AttrKind}; +use rustc_ast::{AttrArgs, AttrKind, AttrItemKind}; use rustc_errors::Applicability; use rustc_lint::EarlyContext; use rustc_span::sym; pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute) { if let AttrKind::Normal(normal_attr) = &attr.kind { - if let AttrArgs::Eq { .. } = &normal_attr.item.args { + if let AttrItemKind::Unparsed(AttrArgs::Eq { .. }) = &normal_attr.item.args { // `#[should_panic = ".."]` found, good return; } - if let AttrArgs::Delimited(args) = &normal_attr.item.args + if let AttrItemKind::Unparsed(AttrArgs::Delimited(args)) = &normal_attr.item.args && let mut tt_iter = args.tokens.iter() && let Some(TokenTree::Token( Token { diff --git a/src/tools/clippy/clippy_lints/src/cfg_not_test.rs b/src/tools/clippy/clippy_lints/src/cfg_not_test.rs index 7590fe96fd21..ec543d02c9dd 100644 --- a/src/tools/clippy/clippy_lints/src/cfg_not_test.rs +++ b/src/tools/clippy/clippy_lints/src/cfg_not_test.rs @@ -1,7 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; -use rustc_ast::MetaItemInner; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; +use rustc_ast::AttrItemKind; +use rustc_ast::EarlyParsedAttribute; +use rustc_span::sym; +use rustc_ast::attr::data_structures::CfgEntry; declare_clippy_lint! { /// ### What it does @@ -32,29 +35,34 @@ declare_lint_pass!(CfgNotTest => [CFG_NOT_TEST]); impl EarlyLintPass for CfgNotTest { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &rustc_ast::Attribute) { - if attr.has_name(rustc_span::sym::cfg_trace) && contains_not_test(attr.meta_item_list().as_deref(), false) { - span_lint_and_then( - cx, - CFG_NOT_TEST, - attr.span, - "code is excluded from test builds", - |diag| { - diag.help("consider not excluding any code from test builds"); - diag.note_once("this could increase code coverage despite not actually being tested"); - }, - ); + if attr.has_name(sym::cfg_trace) { + let AttrItemKind::Parsed(EarlyParsedAttribute::CfgTrace(cfg)) = &attr.get_normal_item().args else { + unreachable!() + }; + + if contains_not_test(&cfg, false) { + span_lint_and_then( + cx, + CFG_NOT_TEST, + attr.span, + "code is excluded from test builds", + |diag| { + diag.help("consider not excluding any code from test builds"); + diag.note_once("this could increase code coverage despite not actually being tested"); + }, + ); + } } } } -fn contains_not_test(list: Option<&[MetaItemInner]>, not: bool) -> bool { - list.is_some_and(|list| { - list.iter().any(|item| { - item.ident().is_some_and(|ident| match ident.name { - rustc_span::sym::not => contains_not_test(item.meta_item_list(), !not), - rustc_span::sym::test => not, - _ => contains_not_test(item.meta_item_list(), not), - }) - }) - }) +fn contains_not_test(cfg: &CfgEntry, not: bool) -> bool { + match cfg { + CfgEntry::All(subs, _) | CfgEntry::Any(subs, _) => subs.iter().any(|item| { + contains_not_test(item, not) + }), + CfgEntry::Not(sub, _) => contains_not_test(sub, !not), + CfgEntry::NameValue { name: sym::test, .. } => not, + _ => false + } } diff --git a/src/tools/clippy/clippy_lints/src/doc/include_in_doc_without_cfg.rs b/src/tools/clippy/clippy_lints/src/doc/include_in_doc_without_cfg.rs index bca1cd03bb7e..f8e9e870f629 100644 --- a/src/tools/clippy/clippy_lints/src/doc/include_in_doc_without_cfg.rs +++ b/src/tools/clippy/clippy_lints/src/doc/include_in_doc_without_cfg.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; -use rustc_ast::{AttrArgs, AttrKind, AttrStyle, Attribute}; +use rustc_ast::{AttrArgs, AttrKind, AttrStyle, Attribute, AttrItemKind}; use rustc_errors::Applicability; use rustc_lint::EarlyContext; @@ -11,7 +11,7 @@ pub fn check(cx: &EarlyContext<'_>, attrs: &[Attribute]) { if !attr.span.from_expansion() && let AttrKind::Normal(ref item) = attr.kind && attr.doc_str().is_some() - && let AttrArgs::Eq { expr: meta, .. } = &item.item.args + && let AttrItemKind::Unparsed(AttrArgs::Eq { expr: meta, .. }) = &item.item.args && !attr.span.contains(meta.span) // Since the `include_str` is already expanded at this point, we can only take the // whole attribute snippet and then modify for our suggestion. diff --git a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs index 28ea2e4fa1f0..e0149a23fccf 100644 --- a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs +++ b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs @@ -9,6 +9,8 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_session::impl_lint_pass; use rustc_span::def_id::{CrateNum, DefId}; use rustc_span::{ExpnKind, Span}; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::find_attr; declare_clippy_lint! { /// ### What it does @@ -268,11 +270,6 @@ impl<'tcx> LateLintPass<'tcx> for IncompatibleMsrv { /// attribute. fn is_under_cfg_attribute(cx: &LateContext<'_>, hir_id: HirId) -> bool { cx.tcx.hir_parent_id_iter(hir_id).any(|id| { - cx.tcx.hir_attrs(id).iter().any(|attr| { - matches!( - attr.name(), - Some(sym::cfg_trace | sym::cfg_attr_trace) - ) - }) + find_attr!(cx.tcx.hir_attrs(id), AttributeKind::CfgTrace(..) | AttributeKind::CfgAttrTrace) }) } diff --git a/src/tools/clippy/clippy_lints/src/large_include_file.rs b/src/tools/clippy/clippy_lints/src/large_include_file.rs index 48ce1afc6e69..5c37747b8c9b 100644 --- a/src/tools/clippy/clippy_lints/src/large_include_file.rs +++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs @@ -1,3 +1,4 @@ +use rustc_ast::AttrItemKind; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::root_macro_call_first_node; @@ -92,7 +93,7 @@ impl EarlyLintPass for LargeIncludeFile { && let AttrKind::Normal(ref item) = attr.kind && let Some(doc) = attr.doc_str() && doc.as_str().len() as u64 > self.max_file_size - && let AttrArgs::Eq { expr: meta, .. } = &item.item.args + && let AttrItemKind::Unparsed(AttrArgs::Eq { expr: meta, .. }) = &item.item.args && !attr.span.contains(meta.span) // Since the `include_str` is already expanded at this point, we can only take the // whole attribute snippet and then modify for our suggestion. diff --git a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs index add01b6a0837..834456ff6668 100644 --- a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs +++ b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs @@ -5,7 +5,8 @@ use clippy_utils::res::MaybeResPath; use clippy_utils::{find_binding_init, get_parent_expr, is_inside_always_const_context}; use rustc_hir::{Expr, HirId}; use rustc_lint::{LateContext, LintContext}; -use rustc_span::sym; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::find_attr; use super::CONST_IS_EMPTY; @@ -40,7 +41,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, receiver: &Expr<'_ fn is_under_cfg(cx: &LateContext<'_>, id: HirId) -> bool { cx.tcx .hir_parent_id_iter(id) - .any(|id| cx.tcx.hir_attrs(id).iter().any(|attr| attr.has_name(sym::cfg_trace))) + .any(|id| find_attr!(cx.tcx.hir_attrs(id), AttributeKind::CfgTrace(..))) } /// Similar to [`clippy_utils::expr_or_init`], but does not go up the chain if the initialization diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs index 6fc034b6fc5d..67493d54b552 100644 --- a/src/tools/clippy/clippy_lints/src/new_without_default.rs +++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs @@ -9,6 +9,8 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::AssocKind; use rustc_session::impl_lint_pass; use rustc_span::sym; +use rustc_hir::Attribute; +use rustc_hir::attrs::AttributeKind; declare_clippy_lint! { /// ### What it does @@ -121,7 +123,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { let attrs_sugg = { let mut sugg = String::new(); for attr in cx.tcx.hir_attrs(assoc_item_hir_id) { - if !attr.has_name(sym::cfg_trace) { + let Attribute::Parsed(AttributeKind::CfgTrace(attrs)) = attr else { // This might be some other attribute that the `impl Default` ought to inherit. // But it could also be one of the many attributes that: // - can't be put on an impl block -- like `#[inline]` @@ -131,10 +133,13 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { // reduce the applicability app = Applicability::MaybeIncorrect; continue; + }; + + for (_, attr_span) in attrs { + sugg.push_str(&snippet_with_applicability(cx.sess(), *attr_span, "_", &mut app)); + sugg.push('\n'); } - sugg.push_str(&snippet_with_applicability(cx.sess(), attr.span(), "_", &mut app)); - sugg.push('\n'); } sugg }; diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 432d7a251a21..618719286e8f 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -976,11 +976,19 @@ pub fn eq_attr(l: &Attribute, r: &Attribute) -> bool { l.style == r.style && match (&l.kind, &r.kind) { (DocComment(l1, l2), DocComment(r1, r2)) => l1 == r1 && l2 == r2, - (Normal(l), Normal(r)) => eq_path(&l.item.path, &r.item.path) && eq_attr_args(&l.item.args, &r.item.args), + (Normal(l), Normal(r)) => eq_path(&l.item.path, &r.item.path) && eq_attr_item_kind(&l.item.args, &r.item.args), _ => false, } } +pub fn eq_attr_item_kind(l: &AttrItemKind, r: &AttrItemKind) -> bool { + match (l, r) { + (AttrItemKind::Unparsed(l), AttrItemKind::Unparsed(r)) => eq_attr_args(l, r), + (AttrItemKind::Parsed(_l), AttrItemKind::Parsed(_r)) => todo!(), + _ => false, + } +} + pub fn eq_attr_args(l: &AttrArgs, r: &AttrArgs) -> bool { use AttrArgs::*; match (l, r) { diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 954c32687af6..38e1542cd758 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -121,6 +121,7 @@ use rustc_middle::ty::{ self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, GenericArgKind, GenericArgsRef, IntTy, Ty, TyCtxt, TypeFlags, TypeVisitableExt, UintTy, UpvarCapture, }; +use rustc_hir::attrs::CfgEntry; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{Ident, Symbol, kw}; @@ -2401,17 +2402,12 @@ pub fn is_test_function(tcx: TyCtxt<'_>, fn_def_id: LocalDefId) -> bool { /// This only checks directly applied attributes, to see if a node is inside a `#[cfg(test)]` parent /// use [`is_in_cfg_test`] pub fn is_cfg_test(tcx: TyCtxt<'_>, id: HirId) -> bool { - tcx.hir_attrs(id).iter().any(|attr| { - if attr.has_name(sym::cfg_trace) - && let Some(items) = attr.meta_item_list() - && let [item] = &*items - && item.has_name(sym::test) - { - true - } else { - false - } - }) + if let Some(cfgs) = find_attr!(tcx.hir_attrs(id), AttributeKind::CfgTrace(cfgs) => cfgs) + && cfgs.iter().any(|(cfg, _)| { matches!(cfg, CfgEntry::NameValue { name: sym::test, ..})}) { + true + } else { + false + } } /// Checks if any parent node of `HirId` has `#[cfg(test)]` attribute applied @@ -2426,11 +2422,10 @@ pub fn is_in_test(tcx: TyCtxt<'_>, hir_id: HirId) -> bool { /// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied. pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - tcx.has_attr(def_id, sym::cfg_trace) - || tcx + find_attr!(tcx.get_all_attrs(def_id), AttributeKind::CfgTrace(..)) + || find_attr!(tcx .hir_parent_iter(tcx.local_def_id_to_hir_id(def_id)) - .flat_map(|(parent_id, _)| tcx.hir_attrs(parent_id)) - .any(|attr| attr.has_name(sym::cfg_trace)) + .flat_map(|(parent_id, _)| tcx.hir_attrs(parent_id)), AttributeKind::CfgTrace(..)) } /// Walks up the HIR tree from the given expression in an attempt to find where the value is From f1ce0dd4dece601b131e794854ef219f40a7a444 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 26 Dec 2025 20:57:35 +0100 Subject: [PATCH 0292/1061] Convert clippy to use the new parsed representation --- clippy_lints/src/attrs/mod.rs | 4 +- .../src/attrs/should_panic_without_expect.rs | 6 +-- clippy_lints/src/cfg_not_test.rs | 52 +++++++++++-------- .../src/doc/include_in_doc_without_cfg.rs | 4 +- clippy_lints/src/incompatible_msrv.rs | 9 ++-- clippy_lints/src/large_include_file.rs | 3 +- clippy_lints/src/methods/is_empty.rs | 5 +- clippy_lints/src/new_without_default.rs | 11 ++-- clippy_utils/src/ast_utils/mod.rs | 10 +++- clippy_utils/src/lib.rs | 25 ++++----- 10 files changed, 72 insertions(+), 57 deletions(-) diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index 679ccfb8de3a..366f5873a1aa 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -16,7 +16,7 @@ mod utils; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::msrvs::{self, Msrv, MsrvStack}; -use rustc_ast::{self as ast, AttrArgs, AttrKind, Attribute, MetaItemInner, MetaItemKind}; +use rustc_ast::{self as ast, AttrArgs, AttrKind, Attribute, MetaItemInner, MetaItemKind, AttrItemKind}; use rustc_hir::{ImplItem, Item, ItemKind, TraitItem}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -604,7 +604,7 @@ impl EarlyLintPass for PostExpansionEarlyAttributes { if attr.has_name(sym::ignore) && match &attr.kind { - AttrKind::Normal(normal_attr) => !matches!(normal_attr.item.args, AttrArgs::Eq { .. }), + AttrKind::Normal(normal_attr) => !matches!(normal_attr.item.args, AttrItemKind::Unparsed(AttrArgs::Eq { .. })), AttrKind::DocComment(..) => true, } { diff --git a/clippy_lints/src/attrs/should_panic_without_expect.rs b/clippy_lints/src/attrs/should_panic_without_expect.rs index fd27e30a67f3..b854a3070bef 100644 --- a/clippy_lints/src/attrs/should_panic_without_expect.rs +++ b/clippy_lints/src/attrs/should_panic_without_expect.rs @@ -2,19 +2,19 @@ use super::{Attribute, SHOULD_PANIC_WITHOUT_EXPECT}; use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_ast::token::{Token, TokenKind}; use rustc_ast::tokenstream::TokenTree; -use rustc_ast::{AttrArgs, AttrKind}; +use rustc_ast::{AttrArgs, AttrKind, AttrItemKind}; use rustc_errors::Applicability; use rustc_lint::EarlyContext; use rustc_span::sym; pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute) { if let AttrKind::Normal(normal_attr) = &attr.kind { - if let AttrArgs::Eq { .. } = &normal_attr.item.args { + if let AttrItemKind::Unparsed(AttrArgs::Eq { .. }) = &normal_attr.item.args { // `#[should_panic = ".."]` found, good return; } - if let AttrArgs::Delimited(args) = &normal_attr.item.args + if let AttrItemKind::Unparsed(AttrArgs::Delimited(args)) = &normal_attr.item.args && let mut tt_iter = args.tokens.iter() && let Some(TokenTree::Token( Token { diff --git a/clippy_lints/src/cfg_not_test.rs b/clippy_lints/src/cfg_not_test.rs index 7590fe96fd21..ec543d02c9dd 100644 --- a/clippy_lints/src/cfg_not_test.rs +++ b/clippy_lints/src/cfg_not_test.rs @@ -1,7 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; -use rustc_ast::MetaItemInner; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; +use rustc_ast::AttrItemKind; +use rustc_ast::EarlyParsedAttribute; +use rustc_span::sym; +use rustc_ast::attr::data_structures::CfgEntry; declare_clippy_lint! { /// ### What it does @@ -32,29 +35,34 @@ declare_lint_pass!(CfgNotTest => [CFG_NOT_TEST]); impl EarlyLintPass for CfgNotTest { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &rustc_ast::Attribute) { - if attr.has_name(rustc_span::sym::cfg_trace) && contains_not_test(attr.meta_item_list().as_deref(), false) { - span_lint_and_then( - cx, - CFG_NOT_TEST, - attr.span, - "code is excluded from test builds", - |diag| { - diag.help("consider not excluding any code from test builds"); - diag.note_once("this could increase code coverage despite not actually being tested"); - }, - ); + if attr.has_name(sym::cfg_trace) { + let AttrItemKind::Parsed(EarlyParsedAttribute::CfgTrace(cfg)) = &attr.get_normal_item().args else { + unreachable!() + }; + + if contains_not_test(&cfg, false) { + span_lint_and_then( + cx, + CFG_NOT_TEST, + attr.span, + "code is excluded from test builds", + |diag| { + diag.help("consider not excluding any code from test builds"); + diag.note_once("this could increase code coverage despite not actually being tested"); + }, + ); + } } } } -fn contains_not_test(list: Option<&[MetaItemInner]>, not: bool) -> bool { - list.is_some_and(|list| { - list.iter().any(|item| { - item.ident().is_some_and(|ident| match ident.name { - rustc_span::sym::not => contains_not_test(item.meta_item_list(), !not), - rustc_span::sym::test => not, - _ => contains_not_test(item.meta_item_list(), not), - }) - }) - }) +fn contains_not_test(cfg: &CfgEntry, not: bool) -> bool { + match cfg { + CfgEntry::All(subs, _) | CfgEntry::Any(subs, _) => subs.iter().any(|item| { + contains_not_test(item, not) + }), + CfgEntry::Not(sub, _) => contains_not_test(sub, !not), + CfgEntry::NameValue { name: sym::test, .. } => not, + _ => false + } } diff --git a/clippy_lints/src/doc/include_in_doc_without_cfg.rs b/clippy_lints/src/doc/include_in_doc_without_cfg.rs index bca1cd03bb7e..f8e9e870f629 100644 --- a/clippy_lints/src/doc/include_in_doc_without_cfg.rs +++ b/clippy_lints/src/doc/include_in_doc_without_cfg.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; -use rustc_ast::{AttrArgs, AttrKind, AttrStyle, Attribute}; +use rustc_ast::{AttrArgs, AttrKind, AttrStyle, Attribute, AttrItemKind}; use rustc_errors::Applicability; use rustc_lint::EarlyContext; @@ -11,7 +11,7 @@ pub fn check(cx: &EarlyContext<'_>, attrs: &[Attribute]) { if !attr.span.from_expansion() && let AttrKind::Normal(ref item) = attr.kind && attr.doc_str().is_some() - && let AttrArgs::Eq { expr: meta, .. } = &item.item.args + && let AttrItemKind::Unparsed(AttrArgs::Eq { expr: meta, .. }) = &item.item.args && !attr.span.contains(meta.span) // Since the `include_str` is already expanded at this point, we can only take the // whole attribute snippet and then modify for our suggestion. diff --git a/clippy_lints/src/incompatible_msrv.rs b/clippy_lints/src/incompatible_msrv.rs index 28ea2e4fa1f0..e0149a23fccf 100644 --- a/clippy_lints/src/incompatible_msrv.rs +++ b/clippy_lints/src/incompatible_msrv.rs @@ -9,6 +9,8 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_session::impl_lint_pass; use rustc_span::def_id::{CrateNum, DefId}; use rustc_span::{ExpnKind, Span}; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::find_attr; declare_clippy_lint! { /// ### What it does @@ -268,11 +270,6 @@ impl<'tcx> LateLintPass<'tcx> for IncompatibleMsrv { /// attribute. fn is_under_cfg_attribute(cx: &LateContext<'_>, hir_id: HirId) -> bool { cx.tcx.hir_parent_id_iter(hir_id).any(|id| { - cx.tcx.hir_attrs(id).iter().any(|attr| { - matches!( - attr.name(), - Some(sym::cfg_trace | sym::cfg_attr_trace) - ) - }) + find_attr!(cx.tcx.hir_attrs(id), AttributeKind::CfgTrace(..) | AttributeKind::CfgAttrTrace) }) } diff --git a/clippy_lints/src/large_include_file.rs b/clippy_lints/src/large_include_file.rs index 48ce1afc6e69..5c37747b8c9b 100644 --- a/clippy_lints/src/large_include_file.rs +++ b/clippy_lints/src/large_include_file.rs @@ -1,3 +1,4 @@ +use rustc_ast::AttrItemKind; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::root_macro_call_first_node; @@ -92,7 +93,7 @@ impl EarlyLintPass for LargeIncludeFile { && let AttrKind::Normal(ref item) = attr.kind && let Some(doc) = attr.doc_str() && doc.as_str().len() as u64 > self.max_file_size - && let AttrArgs::Eq { expr: meta, .. } = &item.item.args + && let AttrItemKind::Unparsed(AttrArgs::Eq { expr: meta, .. }) = &item.item.args && !attr.span.contains(meta.span) // Since the `include_str` is already expanded at this point, we can only take the // whole attribute snippet and then modify for our suggestion. diff --git a/clippy_lints/src/methods/is_empty.rs b/clippy_lints/src/methods/is_empty.rs index add01b6a0837..834456ff6668 100644 --- a/clippy_lints/src/methods/is_empty.rs +++ b/clippy_lints/src/methods/is_empty.rs @@ -5,7 +5,8 @@ use clippy_utils::res::MaybeResPath; use clippy_utils::{find_binding_init, get_parent_expr, is_inside_always_const_context}; use rustc_hir::{Expr, HirId}; use rustc_lint::{LateContext, LintContext}; -use rustc_span::sym; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::find_attr; use super::CONST_IS_EMPTY; @@ -40,7 +41,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, receiver: &Expr<'_ fn is_under_cfg(cx: &LateContext<'_>, id: HirId) -> bool { cx.tcx .hir_parent_id_iter(id) - .any(|id| cx.tcx.hir_attrs(id).iter().any(|attr| attr.has_name(sym::cfg_trace))) + .any(|id| find_attr!(cx.tcx.hir_attrs(id), AttributeKind::CfgTrace(..))) } /// Similar to [`clippy_utils::expr_or_init`], but does not go up the chain if the initialization diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 6fc034b6fc5d..67493d54b552 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -9,6 +9,8 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::AssocKind; use rustc_session::impl_lint_pass; use rustc_span::sym; +use rustc_hir::Attribute; +use rustc_hir::attrs::AttributeKind; declare_clippy_lint! { /// ### What it does @@ -121,7 +123,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { let attrs_sugg = { let mut sugg = String::new(); for attr in cx.tcx.hir_attrs(assoc_item_hir_id) { - if !attr.has_name(sym::cfg_trace) { + let Attribute::Parsed(AttributeKind::CfgTrace(attrs)) = attr else { // This might be some other attribute that the `impl Default` ought to inherit. // But it could also be one of the many attributes that: // - can't be put on an impl block -- like `#[inline]` @@ -131,10 +133,13 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { // reduce the applicability app = Applicability::MaybeIncorrect; continue; + }; + + for (_, attr_span) in attrs { + sugg.push_str(&snippet_with_applicability(cx.sess(), *attr_span, "_", &mut app)); + sugg.push('\n'); } - sugg.push_str(&snippet_with_applicability(cx.sess(), attr.span(), "_", &mut app)); - sugg.push('\n'); } sugg }; diff --git a/clippy_utils/src/ast_utils/mod.rs b/clippy_utils/src/ast_utils/mod.rs index 432d7a251a21..618719286e8f 100644 --- a/clippy_utils/src/ast_utils/mod.rs +++ b/clippy_utils/src/ast_utils/mod.rs @@ -976,11 +976,19 @@ pub fn eq_attr(l: &Attribute, r: &Attribute) -> bool { l.style == r.style && match (&l.kind, &r.kind) { (DocComment(l1, l2), DocComment(r1, r2)) => l1 == r1 && l2 == r2, - (Normal(l), Normal(r)) => eq_path(&l.item.path, &r.item.path) && eq_attr_args(&l.item.args, &r.item.args), + (Normal(l), Normal(r)) => eq_path(&l.item.path, &r.item.path) && eq_attr_item_kind(&l.item.args, &r.item.args), _ => false, } } +pub fn eq_attr_item_kind(l: &AttrItemKind, r: &AttrItemKind) -> bool { + match (l, r) { + (AttrItemKind::Unparsed(l), AttrItemKind::Unparsed(r)) => eq_attr_args(l, r), + (AttrItemKind::Parsed(_l), AttrItemKind::Parsed(_r)) => todo!(), + _ => false, + } +} + pub fn eq_attr_args(l: &AttrArgs, r: &AttrArgs) -> bool { use AttrArgs::*; match (l, r) { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 954c32687af6..38e1542cd758 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -121,6 +121,7 @@ use rustc_middle::ty::{ self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, GenericArgKind, GenericArgsRef, IntTy, Ty, TyCtxt, TypeFlags, TypeVisitableExt, UintTy, UpvarCapture, }; +use rustc_hir::attrs::CfgEntry; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{Ident, Symbol, kw}; @@ -2401,17 +2402,12 @@ pub fn is_test_function(tcx: TyCtxt<'_>, fn_def_id: LocalDefId) -> bool { /// This only checks directly applied attributes, to see if a node is inside a `#[cfg(test)]` parent /// use [`is_in_cfg_test`] pub fn is_cfg_test(tcx: TyCtxt<'_>, id: HirId) -> bool { - tcx.hir_attrs(id).iter().any(|attr| { - if attr.has_name(sym::cfg_trace) - && let Some(items) = attr.meta_item_list() - && let [item] = &*items - && item.has_name(sym::test) - { - true - } else { - false - } - }) + if let Some(cfgs) = find_attr!(tcx.hir_attrs(id), AttributeKind::CfgTrace(cfgs) => cfgs) + && cfgs.iter().any(|(cfg, _)| { matches!(cfg, CfgEntry::NameValue { name: sym::test, ..})}) { + true + } else { + false + } } /// Checks if any parent node of `HirId` has `#[cfg(test)]` attribute applied @@ -2426,11 +2422,10 @@ pub fn is_in_test(tcx: TyCtxt<'_>, hir_id: HirId) -> bool { /// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied. pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - tcx.has_attr(def_id, sym::cfg_trace) - || tcx + find_attr!(tcx.get_all_attrs(def_id), AttributeKind::CfgTrace(..)) + || find_attr!(tcx .hir_parent_iter(tcx.local_def_id_to_hir_id(def_id)) - .flat_map(|(parent_id, _)| tcx.hir_attrs(parent_id)) - .any(|attr| attr.has_name(sym::cfg_trace)) + .flat_map(|(parent_id, _)| tcx.hir_attrs(parent_id)), AttributeKind::CfgTrace(..)) } /// Walks up the HIR tree from the given expression in an attempt to find where the value is From bd5526c2cf7a040d96ef7c41fce8b9f0ca6b9374 Mon Sep 17 00:00:00 2001 From: andjsrk Date: Tue, 6 Jan 2026 20:14:52 +0900 Subject: [PATCH 0293/1061] accept test changes related to binary ops --- src/tools/clippy/tests/ui/manual_clamp.fixed | 3 +- src/tools/clippy/tests/ui/manual_clamp.rs | 3 +- src/tools/clippy/tests/ui/manual_clamp.stderr | 70 +++++++++---------- .../tests/ui/needless_bitwise_bool.fixed | 4 +- .../clippy/tests/ui/needless_bitwise_bool.rs | 2 + .../tests/ui/needless_bitwise_bool.stderr | 8 ++- 6 files changed, 51 insertions(+), 39 deletions(-) diff --git a/src/tools/clippy/tests/ui/manual_clamp.fixed b/src/tools/clippy/tests/ui/manual_clamp.fixed index 2450a4f4c611..b279a413bc17 100644 --- a/src/tools/clippy/tests/ui/manual_clamp.fixed +++ b/src/tools/clippy/tests/ui/manual_clamp.fixed @@ -4,7 +4,8 @@ dead_code, clippy::unnecessary_operation, clippy::no_effect, - clippy::if_same_then_else + clippy::if_same_then_else, + clippy::needless_match )] use std::cmp::{max as cmp_max, min as cmp_min}; diff --git a/src/tools/clippy/tests/ui/manual_clamp.rs b/src/tools/clippy/tests/ui/manual_clamp.rs index ee341d50768f..7fda41cd4c35 100644 --- a/src/tools/clippy/tests/ui/manual_clamp.rs +++ b/src/tools/clippy/tests/ui/manual_clamp.rs @@ -4,7 +4,8 @@ dead_code, clippy::unnecessary_operation, clippy::no_effect, - clippy::if_same_then_else + clippy::if_same_then_else, + clippy::needless_match )] use std::cmp::{max as cmp_max, min as cmp_min}; diff --git a/src/tools/clippy/tests/ui/manual_clamp.stderr b/src/tools/clippy/tests/ui/manual_clamp.stderr index 4a0e4fa51646..775a16418eba 100644 --- a/src/tools/clippy/tests/ui/manual_clamp.stderr +++ b/src/tools/clippy/tests/ui/manual_clamp.stderr @@ -1,5 +1,5 @@ error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:212:5 + --> tests/ui/manual_clamp.rs:213:5 | LL | / if x9 < CONST_MIN { LL | | @@ -15,7 +15,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::manual_clamp)]` error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:230:5 + --> tests/ui/manual_clamp.rs:231:5 | LL | / if x11 > CONST_MAX { LL | | @@ -29,7 +29,7 @@ LL | | } = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:240:5 + --> tests/ui/manual_clamp.rs:241:5 | LL | / if CONST_MIN > x12 { LL | | @@ -43,7 +43,7 @@ LL | | } = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:250:5 + --> tests/ui/manual_clamp.rs:251:5 | LL | / if CONST_MAX < x13 { LL | | @@ -57,7 +57,7 @@ LL | | } = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:363:5 + --> tests/ui/manual_clamp.rs:364:5 | LL | / if CONST_MAX < x35 { LL | | @@ -71,7 +71,7 @@ LL | | } = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:144:14 + --> tests/ui/manual_clamp.rs:145:14 | LL | let x0 = if CONST_MAX < input { | ______________^ @@ -86,7 +86,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:154:14 + --> tests/ui/manual_clamp.rs:155:14 | LL | let x1 = if input > CONST_MAX { | ______________^ @@ -101,7 +101,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:164:14 + --> tests/ui/manual_clamp.rs:165:14 | LL | let x2 = if input < CONST_MIN { | ______________^ @@ -116,7 +116,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:174:14 + --> tests/ui/manual_clamp.rs:175:14 | LL | let x3 = if CONST_MIN > input { | ______________^ @@ -131,7 +131,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:184:14 + --> tests/ui/manual_clamp.rs:185:14 | LL | let x4 = input.max(CONST_MIN).min(CONST_MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -139,7 +139,7 @@ LL | let x4 = input.max(CONST_MIN).min(CONST_MAX); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:187:14 + --> tests/ui/manual_clamp.rs:188:14 | LL | let x5 = input.min(CONST_MAX).max(CONST_MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -147,7 +147,7 @@ LL | let x5 = input.min(CONST_MAX).max(CONST_MIN); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:190:14 + --> tests/ui/manual_clamp.rs:191:14 | LL | let x6 = match input { | ______________^ @@ -161,7 +161,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:197:14 + --> tests/ui/manual_clamp.rs:198:14 | LL | let x7 = match input { | ______________^ @@ -175,7 +175,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:204:14 + --> tests/ui/manual_clamp.rs:205:14 | LL | let x8 = match input { | ______________^ @@ -189,7 +189,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:221:15 + --> tests/ui/manual_clamp.rs:222:15 | LL | let x10 = match input { | _______________^ @@ -203,7 +203,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:259:15 + --> tests/ui/manual_clamp.rs:260:15 | LL | let x14 = if input > CONST_MAX { | _______________^ @@ -218,7 +218,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:270:19 + --> tests/ui/manual_clamp.rs:271:19 | LL | let x15 = if input > CONST_F64_MAX { | ___________________^ @@ -234,7 +234,7 @@ LL | | }; = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:283:19 + --> tests/ui/manual_clamp.rs:284:19 | LL | let x16 = cmp_max(cmp_min(input, CONST_MAX), CONST_MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -242,7 +242,7 @@ LL | let x16 = cmp_max(cmp_min(input, CONST_MAX), CONST_MIN); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:286:19 + --> tests/ui/manual_clamp.rs:287:19 | LL | let x17 = cmp_min(cmp_max(input, CONST_MIN), CONST_MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -250,7 +250,7 @@ LL | let x17 = cmp_min(cmp_max(input, CONST_MIN), CONST_MAX); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:289:19 + --> tests/ui/manual_clamp.rs:290:19 | LL | let x18 = cmp_max(CONST_MIN, cmp_min(input, CONST_MAX)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -258,7 +258,7 @@ LL | let x18 = cmp_max(CONST_MIN, cmp_min(input, CONST_MAX)); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:292:19 + --> tests/ui/manual_clamp.rs:293:19 | LL | let x19 = cmp_min(CONST_MAX, cmp_max(input, CONST_MIN)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -266,7 +266,7 @@ LL | let x19 = cmp_min(CONST_MAX, cmp_max(input, CONST_MIN)); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:295:19 + --> tests/ui/manual_clamp.rs:296:19 | LL | let x20 = cmp_max(cmp_min(CONST_MAX, input), CONST_MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -274,7 +274,7 @@ LL | let x20 = cmp_max(cmp_min(CONST_MAX, input), CONST_MIN); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:298:19 + --> tests/ui/manual_clamp.rs:299:19 | LL | let x21 = cmp_min(cmp_max(CONST_MIN, input), CONST_MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -282,7 +282,7 @@ LL | let x21 = cmp_min(cmp_max(CONST_MIN, input), CONST_MAX); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:301:19 + --> tests/ui/manual_clamp.rs:302:19 | LL | let x22 = cmp_max(CONST_MIN, cmp_min(CONST_MAX, input)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -290,7 +290,7 @@ LL | let x22 = cmp_max(CONST_MIN, cmp_min(CONST_MAX, input)); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:304:19 + --> tests/ui/manual_clamp.rs:305:19 | LL | let x23 = cmp_min(CONST_MAX, cmp_max(CONST_MIN, input)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -298,7 +298,7 @@ LL | let x23 = cmp_min(CONST_MAX, cmp_max(CONST_MIN, input)); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:308:19 + --> tests/ui/manual_clamp.rs:309:19 | LL | let x24 = f64::max(f64::min(input, CONST_F64_MAX), CONST_F64_MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -307,7 +307,7 @@ LL | let x24 = f64::max(f64::min(input, CONST_F64_MAX), CONST_F64_MIN); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:311:19 + --> tests/ui/manual_clamp.rs:312:19 | LL | let x25 = f64::min(f64::max(input, CONST_F64_MIN), CONST_F64_MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -316,7 +316,7 @@ LL | let x25 = f64::min(f64::max(input, CONST_F64_MIN), CONST_F64_MAX); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:314:19 + --> tests/ui/manual_clamp.rs:315:19 | LL | let x26 = f64::max(CONST_F64_MIN, f64::min(input, CONST_F64_MAX)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -325,7 +325,7 @@ LL | let x26 = f64::max(CONST_F64_MIN, f64::min(input, CONST_F64_MAX)); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:317:19 + --> tests/ui/manual_clamp.rs:318:19 | LL | let x27 = f64::min(CONST_F64_MAX, f64::max(input, CONST_F64_MIN)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -334,7 +334,7 @@ LL | let x27 = f64::min(CONST_F64_MAX, f64::max(input, CONST_F64_MIN)); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:320:19 + --> tests/ui/manual_clamp.rs:321:19 | LL | let x28 = f64::max(f64::min(CONST_F64_MAX, input), CONST_F64_MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -343,7 +343,7 @@ LL | let x28 = f64::max(f64::min(CONST_F64_MAX, input), CONST_F64_MIN); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:323:19 + --> tests/ui/manual_clamp.rs:324:19 | LL | let x29 = f64::min(f64::max(CONST_F64_MIN, input), CONST_F64_MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -352,7 +352,7 @@ LL | let x29 = f64::min(f64::max(CONST_F64_MIN, input), CONST_F64_MAX); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:326:19 + --> tests/ui/manual_clamp.rs:327:19 | LL | let x30 = f64::max(CONST_F64_MIN, f64::min(CONST_F64_MAX, input)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -361,7 +361,7 @@ LL | let x30 = f64::max(CONST_F64_MIN, f64::min(CONST_F64_MAX, input)); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:329:19 + --> tests/ui/manual_clamp.rs:330:19 | LL | let x31 = f64::min(CONST_F64_MAX, f64::max(CONST_F64_MIN, input)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -370,7 +370,7 @@ LL | let x31 = f64::min(CONST_F64_MAX, f64::max(CONST_F64_MIN, input)); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:333:5 + --> tests/ui/manual_clamp.rs:334:5 | LL | / if x32 < CONST_MIN { LL | | @@ -384,7 +384,7 @@ LL | | } = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:525:13 + --> tests/ui/manual_clamp.rs:526:13 | LL | let _ = if input > CONST_MAX { | _____________^ diff --git a/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed b/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed index 89a3c1474f25..751d3d257000 100644 --- a/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed +++ b/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed @@ -34,7 +34,9 @@ fn main() { println!("true") // This is a const method call } - if y & (0 < 1) { + // Resolved + if y && (0 < 1) { + //~^ needless_bitwise_bool println!("true") // This is a BinOp with no side effects } } diff --git a/src/tools/clippy/tests/ui/needless_bitwise_bool.rs b/src/tools/clippy/tests/ui/needless_bitwise_bool.rs index f5aa7a9f3d9e..5d3ff3b2079c 100644 --- a/src/tools/clippy/tests/ui/needless_bitwise_bool.rs +++ b/src/tools/clippy/tests/ui/needless_bitwise_bool.rs @@ -34,7 +34,9 @@ fn main() { println!("true") // This is a const method call } + // Resolved if y & (0 < 1) { + //~^ needless_bitwise_bool println!("true") // This is a BinOp with no side effects } } diff --git a/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr b/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr index 9f14646c3e5a..4f64c7136916 100644 --- a/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr +++ b/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr @@ -7,5 +7,11 @@ LL | if y & !x { = note: `-D clippy::needless-bitwise-bool` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::needless_bitwise_bool)]` -error: aborting due to 1 previous error +error: use of bitwise operator instead of lazy operator between booleans + --> tests/ui/needless_bitwise_bool.rs:38:8 + | +LL | if y & (0 < 1) { + | ^^^^^^^^^^^ help: try: `y && (0 < 1)` + +error: aborting due to 2 previous errors From ce012da28e4d69cc24a4ecb6afb262564183f2bc Mon Sep 17 00:00:00 2001 From: andjsrk Date: Tue, 6 Jan 2026 20:14:52 +0900 Subject: [PATCH 0294/1061] accept test changes related to binary ops --- tests/ui/manual_clamp.fixed | 3 +- tests/ui/manual_clamp.rs | 3 +- tests/ui/manual_clamp.stderr | 70 +++++++++++++-------------- tests/ui/needless_bitwise_bool.fixed | 4 +- tests/ui/needless_bitwise_bool.rs | 2 + tests/ui/needless_bitwise_bool.stderr | 8 ++- 6 files changed, 51 insertions(+), 39 deletions(-) diff --git a/tests/ui/manual_clamp.fixed b/tests/ui/manual_clamp.fixed index 2450a4f4c611..b279a413bc17 100644 --- a/tests/ui/manual_clamp.fixed +++ b/tests/ui/manual_clamp.fixed @@ -4,7 +4,8 @@ dead_code, clippy::unnecessary_operation, clippy::no_effect, - clippy::if_same_then_else + clippy::if_same_then_else, + clippy::needless_match )] use std::cmp::{max as cmp_max, min as cmp_min}; diff --git a/tests/ui/manual_clamp.rs b/tests/ui/manual_clamp.rs index ee341d50768f..7fda41cd4c35 100644 --- a/tests/ui/manual_clamp.rs +++ b/tests/ui/manual_clamp.rs @@ -4,7 +4,8 @@ dead_code, clippy::unnecessary_operation, clippy::no_effect, - clippy::if_same_then_else + clippy::if_same_then_else, + clippy::needless_match )] use std::cmp::{max as cmp_max, min as cmp_min}; diff --git a/tests/ui/manual_clamp.stderr b/tests/ui/manual_clamp.stderr index 4a0e4fa51646..775a16418eba 100644 --- a/tests/ui/manual_clamp.stderr +++ b/tests/ui/manual_clamp.stderr @@ -1,5 +1,5 @@ error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:212:5 + --> tests/ui/manual_clamp.rs:213:5 | LL | / if x9 < CONST_MIN { LL | | @@ -15,7 +15,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::manual_clamp)]` error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:230:5 + --> tests/ui/manual_clamp.rs:231:5 | LL | / if x11 > CONST_MAX { LL | | @@ -29,7 +29,7 @@ LL | | } = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:240:5 + --> tests/ui/manual_clamp.rs:241:5 | LL | / if CONST_MIN > x12 { LL | | @@ -43,7 +43,7 @@ LL | | } = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:250:5 + --> tests/ui/manual_clamp.rs:251:5 | LL | / if CONST_MAX < x13 { LL | | @@ -57,7 +57,7 @@ LL | | } = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:363:5 + --> tests/ui/manual_clamp.rs:364:5 | LL | / if CONST_MAX < x35 { LL | | @@ -71,7 +71,7 @@ LL | | } = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:144:14 + --> tests/ui/manual_clamp.rs:145:14 | LL | let x0 = if CONST_MAX < input { | ______________^ @@ -86,7 +86,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:154:14 + --> tests/ui/manual_clamp.rs:155:14 | LL | let x1 = if input > CONST_MAX { | ______________^ @@ -101,7 +101,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:164:14 + --> tests/ui/manual_clamp.rs:165:14 | LL | let x2 = if input < CONST_MIN { | ______________^ @@ -116,7 +116,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:174:14 + --> tests/ui/manual_clamp.rs:175:14 | LL | let x3 = if CONST_MIN > input { | ______________^ @@ -131,7 +131,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:184:14 + --> tests/ui/manual_clamp.rs:185:14 | LL | let x4 = input.max(CONST_MIN).min(CONST_MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -139,7 +139,7 @@ LL | let x4 = input.max(CONST_MIN).min(CONST_MAX); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:187:14 + --> tests/ui/manual_clamp.rs:188:14 | LL | let x5 = input.min(CONST_MAX).max(CONST_MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -147,7 +147,7 @@ LL | let x5 = input.min(CONST_MAX).max(CONST_MIN); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:190:14 + --> tests/ui/manual_clamp.rs:191:14 | LL | let x6 = match input { | ______________^ @@ -161,7 +161,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:197:14 + --> tests/ui/manual_clamp.rs:198:14 | LL | let x7 = match input { | ______________^ @@ -175,7 +175,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:204:14 + --> tests/ui/manual_clamp.rs:205:14 | LL | let x8 = match input { | ______________^ @@ -189,7 +189,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:221:15 + --> tests/ui/manual_clamp.rs:222:15 | LL | let x10 = match input { | _______________^ @@ -203,7 +203,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:259:15 + --> tests/ui/manual_clamp.rs:260:15 | LL | let x14 = if input > CONST_MAX { | _______________^ @@ -218,7 +218,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:270:19 + --> tests/ui/manual_clamp.rs:271:19 | LL | let x15 = if input > CONST_F64_MAX { | ___________________^ @@ -234,7 +234,7 @@ LL | | }; = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:283:19 + --> tests/ui/manual_clamp.rs:284:19 | LL | let x16 = cmp_max(cmp_min(input, CONST_MAX), CONST_MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -242,7 +242,7 @@ LL | let x16 = cmp_max(cmp_min(input, CONST_MAX), CONST_MIN); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:286:19 + --> tests/ui/manual_clamp.rs:287:19 | LL | let x17 = cmp_min(cmp_max(input, CONST_MIN), CONST_MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -250,7 +250,7 @@ LL | let x17 = cmp_min(cmp_max(input, CONST_MIN), CONST_MAX); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:289:19 + --> tests/ui/manual_clamp.rs:290:19 | LL | let x18 = cmp_max(CONST_MIN, cmp_min(input, CONST_MAX)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -258,7 +258,7 @@ LL | let x18 = cmp_max(CONST_MIN, cmp_min(input, CONST_MAX)); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:292:19 + --> tests/ui/manual_clamp.rs:293:19 | LL | let x19 = cmp_min(CONST_MAX, cmp_max(input, CONST_MIN)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -266,7 +266,7 @@ LL | let x19 = cmp_min(CONST_MAX, cmp_max(input, CONST_MIN)); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:295:19 + --> tests/ui/manual_clamp.rs:296:19 | LL | let x20 = cmp_max(cmp_min(CONST_MAX, input), CONST_MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -274,7 +274,7 @@ LL | let x20 = cmp_max(cmp_min(CONST_MAX, input), CONST_MIN); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:298:19 + --> tests/ui/manual_clamp.rs:299:19 | LL | let x21 = cmp_min(cmp_max(CONST_MIN, input), CONST_MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -282,7 +282,7 @@ LL | let x21 = cmp_min(cmp_max(CONST_MIN, input), CONST_MAX); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:301:19 + --> tests/ui/manual_clamp.rs:302:19 | LL | let x22 = cmp_max(CONST_MIN, cmp_min(CONST_MAX, input)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -290,7 +290,7 @@ LL | let x22 = cmp_max(CONST_MIN, cmp_min(CONST_MAX, input)); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:304:19 + --> tests/ui/manual_clamp.rs:305:19 | LL | let x23 = cmp_min(CONST_MAX, cmp_max(CONST_MIN, input)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -298,7 +298,7 @@ LL | let x23 = cmp_min(CONST_MAX, cmp_max(CONST_MIN, input)); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:308:19 + --> tests/ui/manual_clamp.rs:309:19 | LL | let x24 = f64::max(f64::min(input, CONST_F64_MAX), CONST_F64_MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -307,7 +307,7 @@ LL | let x24 = f64::max(f64::min(input, CONST_F64_MAX), CONST_F64_MIN); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:311:19 + --> tests/ui/manual_clamp.rs:312:19 | LL | let x25 = f64::min(f64::max(input, CONST_F64_MIN), CONST_F64_MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -316,7 +316,7 @@ LL | let x25 = f64::min(f64::max(input, CONST_F64_MIN), CONST_F64_MAX); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:314:19 + --> tests/ui/manual_clamp.rs:315:19 | LL | let x26 = f64::max(CONST_F64_MIN, f64::min(input, CONST_F64_MAX)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -325,7 +325,7 @@ LL | let x26 = f64::max(CONST_F64_MIN, f64::min(input, CONST_F64_MAX)); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:317:19 + --> tests/ui/manual_clamp.rs:318:19 | LL | let x27 = f64::min(CONST_F64_MAX, f64::max(input, CONST_F64_MIN)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -334,7 +334,7 @@ LL | let x27 = f64::min(CONST_F64_MAX, f64::max(input, CONST_F64_MIN)); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:320:19 + --> tests/ui/manual_clamp.rs:321:19 | LL | let x28 = f64::max(f64::min(CONST_F64_MAX, input), CONST_F64_MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -343,7 +343,7 @@ LL | let x28 = f64::max(f64::min(CONST_F64_MAX, input), CONST_F64_MIN); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:323:19 + --> tests/ui/manual_clamp.rs:324:19 | LL | let x29 = f64::min(f64::max(CONST_F64_MIN, input), CONST_F64_MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -352,7 +352,7 @@ LL | let x29 = f64::min(f64::max(CONST_F64_MIN, input), CONST_F64_MAX); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:326:19 + --> tests/ui/manual_clamp.rs:327:19 | LL | let x30 = f64::max(CONST_F64_MIN, f64::min(CONST_F64_MAX, input)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -361,7 +361,7 @@ LL | let x30 = f64::max(CONST_F64_MIN, f64::min(CONST_F64_MAX, input)); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:329:19 + --> tests/ui/manual_clamp.rs:330:19 | LL | let x31 = f64::min(CONST_F64_MAX, f64::max(CONST_F64_MIN, input)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -370,7 +370,7 @@ LL | let x31 = f64::min(CONST_F64_MAX, f64::max(CONST_F64_MIN, input)); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:333:5 + --> tests/ui/manual_clamp.rs:334:5 | LL | / if x32 < CONST_MIN { LL | | @@ -384,7 +384,7 @@ LL | | } = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:525:13 + --> tests/ui/manual_clamp.rs:526:13 | LL | let _ = if input > CONST_MAX { | _____________^ diff --git a/tests/ui/needless_bitwise_bool.fixed b/tests/ui/needless_bitwise_bool.fixed index 89a3c1474f25..751d3d257000 100644 --- a/tests/ui/needless_bitwise_bool.fixed +++ b/tests/ui/needless_bitwise_bool.fixed @@ -34,7 +34,9 @@ fn main() { println!("true") // This is a const method call } - if y & (0 < 1) { + // Resolved + if y && (0 < 1) { + //~^ needless_bitwise_bool println!("true") // This is a BinOp with no side effects } } diff --git a/tests/ui/needless_bitwise_bool.rs b/tests/ui/needless_bitwise_bool.rs index f5aa7a9f3d9e..5d3ff3b2079c 100644 --- a/tests/ui/needless_bitwise_bool.rs +++ b/tests/ui/needless_bitwise_bool.rs @@ -34,7 +34,9 @@ fn main() { println!("true") // This is a const method call } + // Resolved if y & (0 < 1) { + //~^ needless_bitwise_bool println!("true") // This is a BinOp with no side effects } } diff --git a/tests/ui/needless_bitwise_bool.stderr b/tests/ui/needless_bitwise_bool.stderr index 9f14646c3e5a..4f64c7136916 100644 --- a/tests/ui/needless_bitwise_bool.stderr +++ b/tests/ui/needless_bitwise_bool.stderr @@ -7,5 +7,11 @@ LL | if y & !x { = note: `-D clippy::needless-bitwise-bool` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::needless_bitwise_bool)]` -error: aborting due to 1 previous error +error: use of bitwise operator instead of lazy operator between booleans + --> tests/ui/needless_bitwise_bool.rs:38:8 + | +LL | if y & (0 < 1) { + | ^^^^^^^^^^^ help: try: `y && (0 < 1)` + +error: aborting due to 2 previous errors From d32f1c695fb7a1082b710fd0ff7516a824bc2cff Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Mon, 5 Jan 2026 13:59:22 +0000 Subject: [PATCH 0295/1061] add const ctor support --- .../src/hir_ty_lowering/mod.rs | 58 ++++++++++++-- tests/crashes/132985.rs | 17 ---- tests/crashes/136138.rs | 7 -- tests/crashes/139596.rs | 10 --- tests/crashes/mgca/ace-with-const-ctor.rs | 16 ---- .../ice-associated-const-equality-105952.rs | 20 +++++ .../mgca/const-ctor-overflow-eval.rs | 19 +++++ .../mgca/const-ctor-overflow-eval.stderr | 80 +++++++++++++++++++ .../mgca/const-ctor-with-error.rs | 19 +++++ .../mgca/const-ctor-with-error.stderr | 14 ++++ tests/ui/const-generics/mgca/const-ctor.rs | 49 ++++++++++++ 11 files changed, 254 insertions(+), 55 deletions(-) delete mode 100644 tests/crashes/132985.rs delete mode 100644 tests/crashes/136138.rs delete mode 100644 tests/crashes/139596.rs delete mode 100644 tests/crashes/mgca/ace-with-const-ctor.rs create mode 100644 tests/rustdoc/constant/ice-associated-const-equality-105952.rs create mode 100644 tests/ui/const-generics/mgca/const-ctor-overflow-eval.rs create mode 100644 tests/ui/const-generics/mgca/const-ctor-overflow-eval.stderr create mode 100644 tests/ui/const-generics/mgca/const-ctor-with-error.rs create mode 100644 tests/ui/const-generics/mgca/const-ctor-with-error.stderr create mode 100644 tests/ui/const-generics/mgca/const-ctor.rs diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index d0f25e8fc321..a22729fd287e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1415,9 +1415,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let ct = self.check_param_uses_if_mcg(ct, span, false); Ok(ct) } - TypeRelativePath::Ctor { ctor_def_id, args } => { - return Ok(ty::Const::zero_sized(tcx, Ty::new_fn_def(tcx, ctor_def_id, args))); - } + TypeRelativePath::Ctor { ctor_def_id, args } => match tcx.def_kind(ctor_def_id) { + DefKind::Ctor(_, CtorKind::Fn) => { + Ok(ty::Const::zero_sized(tcx, Ty::new_fn_def(tcx, ctor_def_id, args))) + } + DefKind::Ctor(ctor_of, CtorKind::Const) => { + Ok(self.construct_const_ctor_value(ctor_def_id, ctor_of, args)) + } + _ => unreachable!(), + }, // FIXME(mgca): implement support for this once ready to support all adt ctor expressions, // not just const ctors TypeRelativePath::Variant { .. } => { @@ -1452,7 +1458,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // FIXME(mgca): do we want constructor resolutions to take priority over // other possible resolutions? if matches!(mode, LowerTypeRelativePathMode::Const) - && let Some((CtorKind::Fn, ctor_def_id)) = variant_def.ctor + && let Some((_, ctor_def_id)) = variant_def.ctor { tcx.check_stability(variant_def.def_id, Some(qpath_hir_id), span, None); let _ = self.prohibit_generic_args( @@ -2597,7 +2603,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); self.lower_const_param(def_id, hir_id) } - Res::Def(DefKind::Const | DefKind::Ctor(_, CtorKind::Const), did) => { + Res::Def(DefKind::Const, did) => { assert_eq!(opt_self_ty, None); let [leading_segments @ .., segment] = path.segments else { bug!() }; let _ = self @@ -2605,6 +2611,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let args = self.lower_generic_args_of_path_segment(span, did, segment); ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(did, args)) } + Res::Def(DefKind::Ctor(ctor_of, CtorKind::Const), did) => { + assert_eq!(opt_self_ty, None); + let [leading_segments @ .., segment] = path.segments else { bug!() }; + let _ = self + .prohibit_generic_args(leading_segments.iter(), GenericsArgsErrExtend::None); + + let parent_did = tcx.parent(did); + let generics_did = match ctor_of { + CtorOf::Variant => tcx.parent(parent_did), + CtorOf::Struct => parent_did, + }; + let args = self.lower_generic_args_of_path_segment(span, generics_did, segment); + + self.construct_const_ctor_value(did, ctor_of, args) + } Res::Def(DefKind::Ctor(_, CtorKind::Fn), did) => { assert_eq!(opt_self_ty, None); let [leading_segments @ .., segment] = path.segments else { bug!() }; @@ -3174,4 +3195,31 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } Some(r) } + + fn construct_const_ctor_value( + &self, + ctor_def_id: DefId, + ctor_of: CtorOf, + args: GenericArgsRef<'tcx>, + ) -> Const<'tcx> { + let tcx = self.tcx(); + let parent_did = tcx.parent(ctor_def_id); + + let adt_def = tcx.adt_def(match ctor_of { + CtorOf::Variant => tcx.parent(parent_did), + CtorOf::Struct => parent_did, + }); + + let variant_idx = adt_def.variant_index_with_id(parent_did); + + let valtree = if adt_def.is_enum() { + let discr = ty::ValTree::from_scalar_int(tcx, variant_idx.as_u32().into()); + ty::ValTree::from_branches(tcx, [ty::Const::new_value(tcx, discr, tcx.types.u32)]) + } else { + ty::ValTree::zst(tcx) + }; + + let adt_ty = Ty::new_adt(tcx, adt_def, args); + ty::Const::new_value(tcx, valtree, adt_ty) + } } diff --git a/tests/crashes/132985.rs b/tests/crashes/132985.rs deleted file mode 100644 index 2735074f44d1..000000000000 --- a/tests/crashes/132985.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ known-bug: #132985 -//@ aux-build:aux132985.rs - -#![allow(incomplete_features)] -#![feature(min_generic_const_args)] -#![feature(adt_const_params)] - -extern crate aux132985; -use aux132985::Foo; - -fn bar() {} - -fn baz() { - bar::<{ Foo }>(); -} - -fn main() {} diff --git a/tests/crashes/136138.rs b/tests/crashes/136138.rs deleted file mode 100644 index c3893dc9c8e6..000000000000 --- a/tests/crashes/136138.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ known-bug: #136138 -#![feature(min_generic_const_args)] -struct U; -struct S() -where - S<{ U }>:; -fn main() {} diff --git a/tests/crashes/139596.rs b/tests/crashes/139596.rs deleted file mode 100644 index 590cfddf83e2..000000000000 --- a/tests/crashes/139596.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ known-bug: #139596 - -#![feature(min_generic_const_args)] -struct Colour; - -struct Led; - -fn main() { - Led::<{ Colour}>; -} diff --git a/tests/crashes/mgca/ace-with-const-ctor.rs b/tests/crashes/mgca/ace-with-const-ctor.rs deleted file mode 100644 index 28e85f37de1f..000000000000 --- a/tests/crashes/mgca/ace-with-const-ctor.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ known-bug: #132980 -// Originally a rustdoc test. Should be moved back there with @has checks -// readded once fixed. -// Previous issue (before mgca): https://github.com/rust-lang/rust/issues/105952 -#![crate_name = "foo"] -#![feature(min_generic_const_args)] -pub enum ParseMode { - Raw, -} -pub trait Parse { - #[type_const] - const PARSE_MODE: ParseMode; -} -pub trait RenderRaw {} - -impl> RenderRaw for T {} diff --git a/tests/rustdoc/constant/ice-associated-const-equality-105952.rs b/tests/rustdoc/constant/ice-associated-const-equality-105952.rs new file mode 100644 index 000000000000..310e56b917fc --- /dev/null +++ b/tests/rustdoc/constant/ice-associated-const-equality-105952.rs @@ -0,0 +1,20 @@ +//! Regression test for + +#![crate_name = "foo"] +#![feature(min_generic_const_args, adt_const_params)] +#![expect(incomplete_features)] +use std::marker::ConstParamTy; + +#[derive(PartialEq, Eq, ConstParamTy)] +pub enum ParseMode { + Raw, +} +pub trait Parse { + #[type_const] + const PARSE_MODE: ParseMode; +} +pub trait RenderRaw {} + +//@ hasraw foo/trait.RenderRaw.html 'impl' +//@ hasraw foo/trait.RenderRaw.html 'ParseMode::Raw' +impl> RenderRaw for T {} diff --git a/tests/ui/const-generics/mgca/const-ctor-overflow-eval.rs b/tests/ui/const-generics/mgca/const-ctor-overflow-eval.rs new file mode 100644 index 000000000000..6a4ee3ed1772 --- /dev/null +++ b/tests/ui/const-generics/mgca/const-ctor-overflow-eval.rs @@ -0,0 +1,19 @@ +#![feature(min_generic_const_args, adt_const_params)] +#![expect(incomplete_features)] +use std::marker::ConstParamTy; + +#[derive(ConstParamTy, PartialEq, Eq)] +struct U; + +#[derive(ConstParamTy, PartialEq, Eq)] +//~^ ERROR overflow evaluating the requirement `S well-formed` +//~| ERROR overflow evaluating the requirement `S well-formed` + +struct S() +where + S<{ U }>:; +//~^ ERROR overflow evaluating the requirement `S well-formed` +//~| ERROR overflow evaluating the requirement `S well-formed` +//~| ERROR overflow evaluating the requirement `S well-formed` + +fn main() {} diff --git a/tests/ui/const-generics/mgca/const-ctor-overflow-eval.stderr b/tests/ui/const-generics/mgca/const-ctor-overflow-eval.stderr new file mode 100644 index 000000000000..4c5ad645bc45 --- /dev/null +++ b/tests/ui/const-generics/mgca/const-ctor-overflow-eval.stderr @@ -0,0 +1,80 @@ +error[E0275]: overflow evaluating the requirement `S well-formed` + --> $DIR/const-ctor-overflow-eval.rs:14:5 + | +LL | S<{ U }>:; + | ^^^^^^^^ + | +note: required by a bound in `S` + --> $DIR/const-ctor-overflow-eval.rs:14:5 + | +LL | struct S() + | - required by a bound in this struct +LL | where +LL | S<{ U }>:; + | ^^^^^^^^ required by this bound in `S` + +error[E0275]: overflow evaluating the requirement `S well-formed` + --> $DIR/const-ctor-overflow-eval.rs:14:5 + | +LL | S<{ U }>:; + | ^^^^^^^^ + | +note: required by a bound in `S` + --> $DIR/const-ctor-overflow-eval.rs:14:5 + | +LL | struct S() + | - required by a bound in this struct +LL | where +LL | S<{ U }>:; + | ^^^^^^^^ required by this bound in `S` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0275]: overflow evaluating the requirement `S well-formed` + --> $DIR/const-ctor-overflow-eval.rs:14:5 + | +LL | S<{ U }>:; + | ^^^^^^^^ + | +note: required by a bound in `S` + --> $DIR/const-ctor-overflow-eval.rs:14:5 + | +LL | struct S() + | - required by a bound in this struct +LL | where +LL | S<{ U }>:; + | ^^^^^^^^ required by this bound in `S` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0275]: overflow evaluating the requirement `S well-formed` + --> $DIR/const-ctor-overflow-eval.rs:8:24 + | +LL | #[derive(ConstParamTy, PartialEq, Eq)] + | ^^^^^^^^^ + | +note: required by a bound in `S` + --> $DIR/const-ctor-overflow-eval.rs:14:5 + | +LL | struct S() + | - required by a bound in this struct +LL | where +LL | S<{ U }>:; + | ^^^^^^^^ required by this bound in `S` + +error[E0275]: overflow evaluating the requirement `S well-formed` + --> $DIR/const-ctor-overflow-eval.rs:8:35 + | +LL | #[derive(ConstParamTy, PartialEq, Eq)] + | ^^ + | +note: required by a bound in `S` + --> $DIR/const-ctor-overflow-eval.rs:14:5 + | +LL | struct S() + | - required by a bound in this struct +LL | where +LL | S<{ U }>:; + | ^^^^^^^^ required by this bound in `S` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/const-generics/mgca/const-ctor-with-error.rs b/tests/ui/const-generics/mgca/const-ctor-with-error.rs new file mode 100644 index 000000000000..95a910e3dd2c --- /dev/null +++ b/tests/ui/const-generics/mgca/const-ctor-with-error.rs @@ -0,0 +1,19 @@ +// to ensure it does not ices like before + +#![feature(min_generic_const_args, adt_const_params)] +#![expect(incomplete_features)] +use std::marker::ConstParamTy; + +#[derive(ConstParamTy, PartialEq, Eq)] +enum Option { + #[allow(dead_code)] + Some(T), + None, +} + +fn pass_enum>() {} + +fn main() { + pass_enum::<{ None }>(); + //~^ ERROR missing generics for enum `std::option::Option` +} diff --git a/tests/ui/const-generics/mgca/const-ctor-with-error.stderr b/tests/ui/const-generics/mgca/const-ctor-with-error.stderr new file mode 100644 index 000000000000..8684457a978b --- /dev/null +++ b/tests/ui/const-generics/mgca/const-ctor-with-error.stderr @@ -0,0 +1,14 @@ +error[E0107]: missing generics for enum `std::option::Option` + --> $DIR/const-ctor-with-error.rs:17:19 + | +LL | pass_enum::<{ None }>(); + | ^^^^ expected 1 generic argument + | +help: add missing generic argument + | +LL | pass_enum::<{ None }>(); + | +++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/const-generics/mgca/const-ctor.rs b/tests/ui/const-generics/mgca/const-ctor.rs new file mode 100644 index 000000000000..19900b56a816 --- /dev/null +++ b/tests/ui/const-generics/mgca/const-ctor.rs @@ -0,0 +1,49 @@ +//! Regression test for +//! +//! + +//@ check-pass + +#![feature( + min_generic_const_args, + adt_const_params, + generic_const_parameter_types, + unsized_const_params +)] +#![expect(incomplete_features)] +use std::marker::{ConstParamTy, ConstParamTy_}; +#[derive(ConstParamTy, PartialEq, Eq)] +struct Colour; + +#[derive(ConstParamTy, PartialEq, Eq)] +enum A { + B, +} + +#[derive(ConstParamTy, PartialEq, Eq)] +enum MyOption { + #[allow(dead_code)] + Some(T), + None, +} + +#[derive(ConstParamTy, PartialEq, Eq)] +struct Led; + +#[derive(Eq, PartialEq, ConstParamTy)] +struct Foo; + +fn pass_enum>() {} + +fn accepts_foo>() {} + +fn accepts_bar>() {} + +fn test() { + accepts_foo:: }>(); + accepts_bar:: }>(); +} + +fn main() { + Led::<{ Colour }>; +} From 460f22c38823b3478ff5aa5f9083968974532177 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 30 Dec 2025 20:02:51 +0300 Subject: [PATCH 0296/1061] resolve: Rename `NameBinding(Data,Kind)` to `Decl(Data,Kind)` Also, rename `DeclKind::Res` to `DeclKind::Def`. --- compiler/rustc_middle/src/metadata.rs | 2 +- .../rustc_resolve/src/build_reduced_graph.rs | 16 +- compiler/rustc_resolve/src/check_unused.rs | 6 +- compiler/rustc_resolve/src/diagnostics.rs | 56 +++---- .../src/effective_visibilities.rs | 20 +-- compiler/rustc_resolve/src/ident.rs | 60 +++---- compiler/rustc_resolve/src/imports.rs | 76 ++++----- compiler/rustc_resolve/src/late.rs | 8 +- compiler/rustc_resolve/src/lib.rs | 153 +++++++++--------- compiler/rustc_resolve/src/macros.rs | 14 +- 10 files changed, 195 insertions(+), 216 deletions(-) diff --git a/compiler/rustc_middle/src/metadata.rs b/compiler/rustc_middle/src/metadata.rs index b7848bc261d8..9e5b3ef61905 100644 --- a/compiler/rustc_middle/src/metadata.rs +++ b/compiler/rustc_middle/src/metadata.rs @@ -26,7 +26,7 @@ impl Reexport { } } -/// This structure is supposed to keep enough data to re-create `NameBinding`s for other crates +/// This structure is supposed to keep enough data to re-create `Decl`s for other crates /// during name resolution. Right now the bindings are not recreated entirely precisely so we may /// need to add more data in the future to correctly support macros 2.0, for example. /// Module child can be either a proper item or a reexport (including private imports). diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 241c13663ae5..d31723844290 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -36,9 +36,9 @@ use crate::imports::{ImportData, ImportKind}; use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; use crate::ref_mut::CmCell; use crate::{ - BindingKey, ExternPreludeEntry, Finalize, MacroData, Module, ModuleKind, ModuleOrUniformRoot, - NameBinding, NameBindingData, NameBindingKind, ParentScope, PathResult, ResolutionError, - Resolver, Segment, Used, VisResolutionError, errors, + BindingKey, Decl, DeclData, DeclKind, ExternPreludeEntry, Finalize, MacroData, Module, + ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, ResolutionError, Resolver, Segment, + Used, VisResolutionError, errors, }; type Res = def::Res; @@ -51,7 +51,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent: Module<'ra>, ident: Ident, ns: Namespace, - binding: NameBinding<'ra>, + binding: Decl<'ra>, ) { if let Err(old_binding) = self.try_define_local(parent, ident, ns, binding, false) { self.report_conflict(parent, ident, ns, old_binding, binding); @@ -82,10 +82,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { vis: Visibility, span: Span, expansion: LocalExpnId, - ambiguity: Option>, + ambiguity: Option>, ) { - let binding = self.arenas.alloc_name_binding(NameBindingData { - kind: NameBindingKind::Res(res), + let binding = self.arenas.alloc_name_binding(DeclData { + kind: DeclKind::Def(res), ambiguity, // External ambiguities always report the `AMBIGUOUS_GLOB_IMPORTS` lint at the moment. warn_ambiguity: true, @@ -1092,7 +1092,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { fn add_macro_use_binding( &mut self, name: Symbol, - binding: NameBinding<'ra>, + binding: Decl<'ra>, span: Span, allow_shadowing: bool, ) { diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 5349cf6d7dbe..b7705773041f 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -36,7 +36,7 @@ use rustc_session::lint::builtin::{ use rustc_span::{DUMMY_SP, Ident, Macros20NormalizedIdent, Span, kw}; use crate::imports::{Import, ImportKind}; -use crate::{LexicalScopeBinding, NameBindingKind, Resolver, module_to_string}; +use crate::{DeclKind, LexicalScopeBinding, Resolver, module_to_string}; struct UnusedImport { use_tree: ast::UseTree, @@ -515,7 +515,7 @@ impl Resolver<'_, '_> { for module in &self.local_modules { for (_key, resolution) in self.resolutions(*module).borrow().iter() { if let Some(binding) = resolution.borrow().best_binding() - && let NameBindingKind::Import { import, .. } = binding.kind + && let DeclKind::Import { import, .. } = binding.kind && let ImportKind::Single { id, .. } = import.kind { if let Some(unused_import) = unused_imports.get(&import.root_id) @@ -543,7 +543,7 @@ impl Resolver<'_, '_> { // in the item not being found. for unn_qua in &self.potentially_unnecessary_qualifications { if let LexicalScopeBinding::Item(name_binding) = unn_qua.binding - && let NameBindingKind::Import { import, .. } = name_binding.kind + && let DeclKind::Import { import, .. } = name_binding.kind && (is_unused_import(import, &unused_imports) || is_redundant_import(import, &redundant_imports)) { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 716e1d5a2e7f..7e78f66574ed 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -44,11 +44,11 @@ use crate::errors::{ use crate::imports::{Import, ImportKind}; use crate::late::{DiagMetadata, PatternSource, Rib}; use crate::{ - AmbiguityError, AmbiguityKind, BindingError, BindingKey, Finalize, + AmbiguityError, AmbiguityKind, BindingError, BindingKey, Decl, DeclKind, Finalize, ForwardGenericParamBanReason, HasGenericParams, LexicalScopeBinding, MacroRulesScope, Module, - ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, - PrivacyError, ResolutionError, Resolver, Scope, ScopeSet, Segment, UseError, Used, - VisResolutionError, errors as errs, path_names_to_string, + ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, PrivacyError, ResolutionError, + Resolver, Scope, ScopeSet, Segment, UseError, Used, VisResolutionError, errors as errs, + path_names_to_string, }; type Res = def::Res; @@ -149,8 +149,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if ambiguity_error.warning { let node_id = match ambiguity_error.b1.0.kind { - NameBindingKind::Import { import, .. } => import.root_id, - NameBindingKind::Res(_) => CRATE_NODE_ID, + DeclKind::Import { import, .. } => import.root_id, + DeclKind::Def(_) => CRATE_NODE_ID, }; self.lint_buffer.buffer_lint( AMBIGUOUS_GLOB_IMPORTS, @@ -212,8 +212,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent: Module<'_>, ident: Ident, ns: Namespace, - new_binding: NameBinding<'ra>, - old_binding: NameBinding<'ra>, + new_binding: Decl<'ra>, + old_binding: Decl<'ra>, ) { // Error on the second of two conflicting names if old_binding.span.lo() > new_binding.span.lo() { @@ -288,8 +288,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .with_code(code); // See https://github.com/rust-lang/rust/issues/32354 - use NameBindingKind::Import; - let can_suggest = |binding: NameBinding<'_>, import: self::Import<'_>| { + use DeclKind::Import; + let can_suggest = |binding: Decl<'_>, import: self::Import<'_>| { !binding.span.is_dummy() && !matches!(import.kind, ImportKind::MacroUse { .. } | ImportKind::MacroExport) }; @@ -473,7 +473,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { &mut self, finalize: Finalize, path: &[Segment], - second_binding: Option>, + second_binding: Option>, ) { let Finalize { node_id, root_span, .. } = finalize; @@ -506,7 +506,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // `ExternCrate` (also used for `crate::...`) then no need to issue a // warning, this looks all good! if let Some(binding) = second_binding - && let NameBindingKind::Import { import, .. } = binding.kind + && let DeclKind::Import { import, .. } = binding.kind // Careful: we still want to rewrite paths from renamed extern crates. && let ImportKind::ExternCrate { source: None, .. } = import.kind { @@ -1360,7 +1360,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // #90113: Do not count an inaccessible reexported item as a candidate. - if let NameBindingKind::Import { binding, .. } = name_binding.kind + if let DeclKind::Import { binding, .. } = name_binding.kind && this.is_accessible_from(binding.vis, parent_scope.module) && !this.is_accessible_from(name_binding.vis, parent_scope.module) { @@ -1469,8 +1469,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut path_segments = path_segments.clone(); path_segments.push(ast::PathSegment::from_ident(ident.0)); - let alias_import = if let NameBindingKind::Import { import, .. } = - name_binding.kind + let alias_import = if let DeclKind::Import { import, .. } = name_binding.kind && let ImportKind::ExternCrate { source: Some(_), .. } = import.kind && import.parent_scope.expansion == parent_scope.expansion { @@ -1754,7 +1753,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { macro_kind.descr_expected(), ), }; - if let crate::NameBindingKind::Import { import, .. } = binding.kind + if let crate::DeclKind::Import { import, .. } = binding.kind && !import.span.is_dummy() { let note = errors::IdentImporterHereButItIsDesc { @@ -1971,7 +1970,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { true } - fn binding_description(&self, b: NameBinding<'_>, ident: Ident, scope: Scope<'_>) -> String { + fn binding_description(&self, b: Decl<'_>, ident: Ident, scope: Scope<'_>) -> String { let res = b.res(); if b.span.is_dummy() || !self.tcx.sess.source_map().is_span_accessible(b.span) { let (built_in, from) = match scope { @@ -2016,7 +2015,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { (b1, b2, scope1, scope2, false) }; - let could_refer_to = |b: NameBinding<'_>, scope: Scope<'ra>, also: &str| { + let could_refer_to = |b: Decl<'_>, scope: Scope<'ra>, also: &str| { let what = self.binding_description(b, ident, scope); let note_msg = format!("`{ident}` could{also} refer to {what}"); @@ -2075,11 +2074,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// If the binding refers to a tuple struct constructor with fields, /// returns the span of its fields. - fn ctor_fields_span(&self, binding: NameBinding<'_>) -> Option { - let NameBindingKind::Res(Res::Def( - DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), - ctor_def_id, - )) = binding.kind + fn ctor_fields_span(&self, binding: Decl<'_>) -> Option { + let DeclKind::Def(Res::Def(DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), ctor_def_id)) = + binding.kind else { return None; }; @@ -2105,8 +2102,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let nonimport_descr = if ctor_fields_span.is_some() { plain_descr + " constructor" } else { plain_descr }; let import_descr = nonimport_descr.clone() + " import"; - let get_descr = - |b: NameBinding<'_>| if b.is_import() { &import_descr } else { &nonimport_descr }; + let get_descr = |b: Decl<'_>| if b.is_import() { &import_descr } else { &nonimport_descr }; // Print the primary message. let ident_descr = get_descr(binding); @@ -2217,7 +2213,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let name = next_ident; next_binding = match binding.kind { _ if res == Res::Err => None, - NameBindingKind::Import { binding, import, .. } => match import.kind { + DeclKind::Import { binding, import, .. } => match import.kind { _ if binding.span.is_dummy() => None, ImportKind::Single { source, .. } => { next_ident = source; @@ -2232,7 +2228,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; match binding.kind { - NameBindingKind::Import { import, .. } => { + DeclKind::Import { import, .. } => { for segment in import.module_path.iter().skip(1) { // Don't include `{{root}}` in suggestions - it's an internal symbol // that should never be shown to users. @@ -2245,14 +2241,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { true, // re-export )); } - NameBindingKind::Res(_) => {} + DeclKind::Def(_) => {} } let first = binding == first_binding; let def_span = self.tcx.sess.source_map().guess_head_span(binding.span); let mut note_span = MultiSpan::from_span(def_span); if !first && binding.vis.is_public() { let desc = match binding.kind { - NameBindingKind::Import { .. } => "re-export", + DeclKind::Import { .. } => "re-export", _ => "directly", }; note_span.push_span_label(def_span, format!("you could import this {desc}")); @@ -2418,7 +2414,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { opt_ns: Option, // `None` indicates a module path in import parent_scope: &ParentScope<'ra>, ribs: Option<&PerNS>>>, - ignore_binding: Option>, + ignore_binding: Option>, ignore_import: Option>, module: Option>, failed_segment_idx: usize, diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index fe6e5b8e6eb6..5d78f3752439 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -8,12 +8,12 @@ use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, use rustc_middle::ty::Visibility; use tracing::info; -use crate::{NameBinding, NameBindingKind, Resolver}; +use crate::{Decl, DeclKind, Resolver}; #[derive(Clone, Copy)] enum ParentId<'ra> { Def(LocalDefId), - Import(NameBinding<'ra>), + Import(Decl<'ra>), } impl ParentId<'_> { @@ -31,7 +31,7 @@ pub(crate) struct EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { /// While walking import chains we need to track effective visibilities per-binding, and def id /// keys in `Resolver::effective_visibilities` are not enough for that, because multiple /// bindings can correspond to a single def id in imports. So we keep a separate table. - import_effective_visibilities: EffectiveVisibilities>, + import_effective_visibilities: EffectiveVisibilities>, // It's possible to recalculate this at any point, but it's relatively expensive. current_private_vis: Visibility, changed: bool, @@ -42,8 +42,8 @@ impl Resolver<'_, '_> { self.get_nearest_non_block_module(def_id.to_def_id()).nearest_parent_mod().expect_local() } - fn private_vis_import(&self, binding: NameBinding<'_>) -> Visibility { - let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() }; + fn private_vis_import(&self, binding: Decl<'_>) -> Visibility { + let DeclKind::Import { import, .. } = binding.kind else { unreachable!() }; Visibility::Restricted( import .id() @@ -70,7 +70,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { pub(crate) fn compute_effective_visibilities<'c>( r: &'a mut Resolver<'ra, 'tcx>, krate: &'c Crate, - ) -> FxHashSet> { + ) -> FxHashSet> { let mut visitor = EffectiveVisibilitiesVisitor { r, def_effective_visibilities: Default::default(), @@ -95,7 +95,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { // information, but are used by later passes. Effective visibility of an import def id // is the maximum value among visibilities of bindings corresponding to that def id. for (binding, eff_vis) in visitor.import_effective_visibilities.iter() { - let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() }; + let DeclKind::Import { import, .. } = binding.kind else { unreachable!() }; if !binding.is_ambiguity_recursive() { if let Some(node_id) = import.id() { r.effective_visibilities.update_eff_vis(r.local_def_id(node_id), eff_vis, r.tcx) @@ -126,10 +126,10 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { // leading to it into the table. They are used by the `ambiguous_glob_reexports` // lint. For all bindings added to the table this way `is_ambiguity` returns true. let is_ambiguity = - |binding: NameBinding<'ra>, warn: bool| binding.ambiguity.is_some() && !warn; + |binding: Decl<'ra>, warn: bool| binding.ambiguity.is_some() && !warn; let mut parent_id = ParentId::Def(module_id); let mut warn_ambiguity = binding.warn_ambiguity; - while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind { + while let DeclKind::Import { binding: nested_binding, .. } = binding.kind { self.update_import(binding, parent_id); if is_ambiguity(binding, warn_ambiguity) { @@ -188,7 +188,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { } } - fn update_import(&mut self, binding: NameBinding<'ra>, parent_id: ParentId<'ra>) { + fn update_import(&mut self, binding: Decl<'ra>, parent_id: ParentId<'ra>) { let nominal_vis = binding.vis.expect_local(); let Some(cheap_private_vis) = self.may_update(nominal_vis, parent_id) else { return }; let inherited_eff_vis = self.effective_vis_or_private(parent_id); diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index b6ec26be5ca1..7ebc75abca89 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -19,10 +19,10 @@ use crate::late::{ }; use crate::macros::{MacroRulesScope, sub_namespace_match}; use crate::{ - AmbiguityError, AmbiguityKind, BindingKey, CmResolver, Determinacy, Finalize, ImportKind, - LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, - ParentScope, PathResult, PrivacyError, Res, ResolutionError, Resolver, Scope, ScopeSet, - Segment, Stage, Used, errors, + AmbiguityError, AmbiguityKind, BindingKey, CmResolver, Decl, DeclKind, Determinacy, Finalize, + ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot, ParentScope, + PathResult, PrivacyError, Res, ResolutionError, Resolver, Scope, ScopeSet, Segment, Stage, + Used, errors, }; #[derive(Copy, Clone)] @@ -305,7 +305,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, finalize: Option, ribs: &[Rib<'ra>], - ignore_binding: Option>, + ignore_binding: Option>, diag_metadata: Option<&DiagMetadata<'_>>, ) -> Option> { let orig_ident = ident; @@ -392,9 +392,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, finalize: Option, force: bool, - ignore_binding: Option>, + ignore_binding: Option>, ignore_import: Option>, - ) -> Result, Determinacy> { + ) -> Result, Determinacy> { assert!(force || finalize.is_none()); // `finalize` implies `force` // Make sure `self`, `super` etc produce an error when passed to here. @@ -425,7 +425,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // } // So we have to save the innermost solution and continue searching in outer scopes // to detect potential ambiguities. - let mut innermost_results: Vec<(NameBinding<'_>, Scope<'_>)> = Vec::new(); + let mut innermost_results: Vec<(Decl<'_>, Scope<'_>)> = Vec::new(); let mut determinacy = Determinacy::Determined; // Go through all the scopes and try to resolve the name. @@ -518,9 +518,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, finalize: Option, force: bool, - ignore_binding: Option>, + ignore_binding: Option>, ignore_import: Option>, - ) -> Result, ControlFlow> { + ) -> Result, ControlFlow> { let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt)); let ret = match scope { Scope::DeriveHelpers(expn_id) => { @@ -759,9 +759,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns: Namespace, scope_set: ScopeSet<'ra>, parent_scope: &ParentScope<'ra>, - binding: NameBinding<'ra>, + binding: Decl<'ra>, scope: Scope<'ra>, - innermost_results: &[(NameBinding<'ra>, Scope<'ra>)], + innermost_results: &[(Decl<'ra>, Scope<'ra>)], ) -> bool { let (innermost_binding, innermost_scope) = *innermost_results.first().unwrap(); let (res, innermost_res) = (binding.res(), innermost_binding.res()); @@ -869,7 +869,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns: Namespace, parent_scope: &ParentScope<'ra>, ignore_import: Option>, - ) -> Result, Determinacy> { + ) -> Result, Determinacy> { self.resolve_ident_in_module(module, ident, ns, parent_scope, None, None, ignore_import) } @@ -881,9 +881,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns: Namespace, parent_scope: &ParentScope<'ra>, finalize: Option, - ignore_binding: Option>, + ignore_binding: Option>, ignore_import: Option>, - ) -> Result, Determinacy> { + ) -> Result, Determinacy> { let tmp_parent_scope; let mut adjusted_parent_scope = parent_scope; match module { @@ -921,9 +921,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns: Namespace, parent_scope: &ParentScope<'ra>, finalize: Option, - ignore_binding: Option>, + ignore_binding: Option>, ignore_import: Option>, - ) -> Result, Determinacy> { + ) -> Result, Determinacy> { match module { ModuleOrUniformRoot::Module(module) => self.resolve_ident_in_scope_set( ident, @@ -994,9 +994,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { finalize: Option, // This binding should be ignored during in-module resolution, so that we don't get // "self-confirming" import resolutions during import validation and checking. - ignore_binding: Option>, + ignore_binding: Option>, ignore_import: Option>, - ) -> Result, ControlFlow> { + ) -> Result, ControlFlow> { let key = BindingKey::new(ident, ns); // `try_borrow_mut` is required to ensure exclusive access, even if the resulting binding // doesn't need to be mutable. It will fail when there is a cycle of imports, and without @@ -1055,9 +1055,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, shadowing: Shadowing, finalize: Option, - ignore_binding: Option>, + ignore_binding: Option>, ignore_import: Option>, - ) -> Result, ControlFlow> { + ) -> Result, ControlFlow> { let key = BindingKey::new(ident, ns); // `try_borrow_mut` is required to ensure exclusive access, even if the resulting binding // doesn't need to be mutable. It will fail when there is a cycle of imports, and without @@ -1179,12 +1179,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn finalize_module_binding( &mut self, ident: Ident, - binding: Option>, + binding: Option>, parent_scope: &ParentScope<'ra>, module: Module<'ra>, finalize: Finalize, shadowing: Shadowing, - ) -> Result, ControlFlow> { + ) -> Result, ControlFlow> { let Finalize { path_span, report_private, used, root_span, .. } = finalize; let Some(binding) = binding else { @@ -1209,7 +1209,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if shadowing == Shadowing::Unrestricted && binding.expansion != LocalExpnId::ROOT - && let NameBindingKind::Import { import, .. } = binding.kind + && let DeclKind::Import { import, .. } = binding.kind && matches!(import.kind, ImportKind::MacroExport) { self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); @@ -1255,15 +1255,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn single_import_can_define_name<'r>( mut self: CmResolver<'r, 'ra, 'tcx>, resolution: &NameResolution<'ra>, - binding: Option>, + binding: Option>, ns: Namespace, ignore_import: Option>, - ignore_binding: Option>, + ignore_binding: Option>, parent_scope: &ParentScope<'ra>, ) -> bool { for single_import in &resolution.single_imports { if let Some(binding) = resolution.non_glob_binding - && let NameBindingKind::Import { import, .. } = binding.kind + && let DeclKind::Import { import, .. } = binding.kind && import == *single_import { // Single import has already defined the name and we are aware of it, @@ -1277,7 +1277,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { continue; } if let Some(ignored) = ignore_binding - && let NameBindingKind::Import { import, .. } = ignored.kind + && let DeclKind::Import { import, .. } = ignored.kind && import == *single_import { continue; @@ -1668,7 +1668,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { opt_ns: Option, // `None` indicates a module path in import parent_scope: &ParentScope<'ra>, finalize: Option, - ignore_binding: Option>, + ignore_binding: Option>, ignore_import: Option>, ) -> PathResult<'ra> { self.resolve_path_with_ribs( @@ -1692,7 +1692,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { source: Option>, finalize: Option, ribs: Option<&PerNS>>>, - ignore_binding: Option>, + ignore_binding: Option>, ignore_import: Option>, diag_metadata: Option<&DiagMetadata<'_>>, ) -> PathResult<'ra> { diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 558f769eda19..7648b980ec5c 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -32,23 +32,23 @@ use crate::errors::{ }; use crate::ref_mut::CmCell; use crate::{ - AmbiguityError, BindingKey, CmResolver, Determinacy, Finalize, ImportSuggestion, Module, - ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind, ParentScope, PathResult, - PerNS, ResolutionError, Resolver, ScopeSet, Segment, Used, module_to_string, names_to_string, + AmbiguityError, BindingKey, CmResolver, Decl, DeclData, DeclKind, Determinacy, Finalize, + ImportSuggestion, Module, ModuleOrUniformRoot, ParentScope, PathResult, PerNS, ResolutionError, + Resolver, ScopeSet, Segment, Used, module_to_string, names_to_string, }; type Res = def::Res; -/// A [`NameBinding`] in the process of being resolved. +/// A [`Decl`] in the process of being resolved. #[derive(Clone, Copy, Default, PartialEq)] pub(crate) enum PendingBinding<'ra> { - Ready(Option>), + Ready(Option>), #[default] Pending, } impl<'ra> PendingBinding<'ra> { - pub(crate) fn binding(self) -> Option> { + pub(crate) fn binding(self) -> Option> { match self { PendingBinding::Ready(binding) => binding, PendingBinding::Pending => None, @@ -244,14 +244,14 @@ pub(crate) struct NameResolution<'ra> { /// Imports are arena-allocated, so it's ok to use pointers as keys. pub single_imports: FxIndexSet>, /// The non-glob binding for this name, if it is known to exist. - pub non_glob_binding: Option>, + pub non_glob_binding: Option>, /// The glob binding for this name, if it is known to exist. - pub glob_binding: Option>, + pub glob_binding: Option>, } impl<'ra> NameResolution<'ra> { /// Returns the binding for the name if it is known or None if it not known. - pub(crate) fn binding(&self) -> Option> { + pub(crate) fn binding(&self) -> Option> { self.best_binding().and_then(|binding| { if !binding.is_glob_import() || self.single_imports.is_empty() { Some(binding) @@ -261,7 +261,7 @@ impl<'ra> NameResolution<'ra> { }) } - pub(crate) fn best_binding(&self) -> Option> { + pub(crate) fn best_binding(&self) -> Option> { self.non_glob_binding.or(self.glob_binding) } } @@ -282,12 +282,9 @@ struct UnresolvedImportError { // Reexports of the form `pub use foo as bar;` where `foo` is `extern crate foo;` // are permitted for backward-compatibility under a deprecation lint. -fn pub_use_of_private_extern_crate_hack( - import: Import<'_>, - binding: NameBinding<'_>, -) -> Option { +fn pub_use_of_private_extern_crate_hack(import: Import<'_>, binding: Decl<'_>) -> Option { match (&import.kind, &binding.kind) { - (ImportKind::Single { .. }, NameBindingKind::Import { import: binding_import, .. }) + (ImportKind::Single { .. }, DeclKind::Import { import: binding_import, .. }) if let ImportKind::ExternCrate { id, .. } = binding_import.kind && import.vis.is_public() => { @@ -300,11 +297,7 @@ fn pub_use_of_private_extern_crate_hack( impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Given a binding and an import that resolves to it, /// return the corresponding binding defined by the import. - pub(crate) fn import( - &self, - binding: NameBinding<'ra>, - import: Import<'ra>, - ) -> NameBinding<'ra> { + pub(crate) fn import(&self, binding: Decl<'ra>, import: Import<'ra>) -> Decl<'ra> { let import_vis = import.vis.to_def_id(); let vis = if binding.vis.is_at_least(import_vis, self.tcx) || pub_use_of_private_extern_crate_hack(import, binding).is_some() @@ -321,8 +314,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { max_vis.set_unchecked(Some(vis.expect_local())) } - self.arenas.alloc_name_binding(NameBindingData { - kind: NameBindingKind::Import { binding, import }, + self.arenas.alloc_name_binding(DeclData { + kind: DeclKind::Import { binding, import }, ambiguity: None, warn_ambiguity: false, span: import.span, @@ -337,9 +330,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { module: Module<'ra>, ident: Ident, ns: Namespace, - binding: NameBinding<'ra>, + binding: Decl<'ra>, warn_ambiguity: bool, - ) -> Result<(), NameBinding<'ra>> { + ) -> Result<(), Decl<'ra>> { let res = binding.res(); self.check_reserved_macro_name(ident, res); self.set_binding_parent_module(binding, module); @@ -361,9 +354,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let (glob_binding, old_glob_binding) = (binding, old_binding); // FIXME: remove `!binding.is_ambiguity_recursive()` after delete the warning ambiguity. if !binding.is_ambiguity_recursive() - && let NameBindingKind::Import { import: old_import, .. } = + && let DeclKind::Import { import: old_import, .. } = old_glob_binding.kind - && let NameBindingKind::Import { import, .. } = glob_binding.kind + && let DeclKind::Import { import, .. } = glob_binding.kind && old_import == import { // When imported from the same glob-import statement, we should replace @@ -421,18 +414,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn new_ambiguity_binding( &self, - primary_binding: NameBinding<'ra>, - secondary_binding: NameBinding<'ra>, + primary_binding: Decl<'ra>, + secondary_binding: Decl<'ra>, warn_ambiguity: bool, - ) -> NameBinding<'ra> { + ) -> Decl<'ra> { let ambiguity = Some(secondary_binding); - let data = NameBindingData { ambiguity, warn_ambiguity, ..*primary_binding }; + let data = DeclData { ambiguity, warn_ambiguity, ..*primary_binding }; self.arenas.alloc_name_binding(data) } - fn new_warn_ambiguity_binding(&self, binding: NameBinding<'ra>) -> NameBinding<'ra> { + fn new_warn_ambiguity_binding(&self, binding: Decl<'ra>) -> Decl<'ra> { assert!(binding.is_ambiguity_recursive()); - self.arenas.alloc_name_binding(NameBindingData { warn_ambiguity: true, ..*binding }) + self.arenas.alloc_name_binding(DeclData { warn_ambiguity: true, ..*binding }) } // Use `f` to mutate the resolution of the name in the module. @@ -634,13 +627,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - pub(crate) fn lint_reexports(&mut self, exported_ambiguities: FxHashSet>) { + pub(crate) fn lint_reexports(&mut self, exported_ambiguities: FxHashSet>) { for module in &self.local_modules { for (key, resolution) in self.resolutions(*module).borrow().iter() { let resolution = resolution.borrow(); let Some(binding) = resolution.best_binding() else { continue }; - if let NameBindingKind::Import { import, .. } = binding.kind + if let DeclKind::Import { import, .. } = binding.kind && let Some(amb_binding) = binding.ambiguity && binding.res() != Res::Err && exported_ambiguities.contains(&binding) @@ -663,8 +656,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { { if binding.res() != Res::Err && glob_binding.res() != Res::Err - && let NameBindingKind::Import { import: glob_import, .. } = - glob_binding.kind + && let DeclKind::Import { import: glob_import, .. } = glob_binding.kind && let Some(glob_import_id) = glob_import.id() && let glob_import_def_id = self.local_def_id(glob_import_id) && self.effective_visibilities.is_exported(glob_import_def_id) @@ -672,10 +664,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && !binding.vis.is_public() { let binding_id = match binding.kind { - NameBindingKind::Res(res) => { + DeclKind::Def(res) => { Some(self.def_id_to_node_id(res.def_id().expect_local())) } - NameBindingKind::Import { import, .. } => import.id(), + DeclKind::Import { import, .. } => import.id(), }; if let Some(binding_id) = binding_id { self.lint_buffer.buffer_lint( @@ -693,7 +685,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - if let NameBindingKind::Import { import, .. } = binding.kind + if let DeclKind::Import { import, .. } = binding.kind && let Some(binding_id) = import.id() && let import_def_id = self.local_def_id(binding_id) && self.effective_visibilities.is_exported(import_def_id) @@ -1207,11 +1199,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let resolution = resolution.borrow(); if let Some(name_binding) = resolution.best_binding() { match name_binding.kind { - NameBindingKind::Import { binding, .. } => { + DeclKind::Import { binding, .. } => { match binding.kind { // Never suggest the name that has binding error // i.e., the name that cannot be previously resolved - NameBindingKind::Res(Res::Err) => None, + DeclKind::Def(Res::Err) => None, _ => Some(i.name), } } @@ -1342,7 +1334,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; match binding.kind { - NameBindingKind::Res(Res::Def(DefKind::Macro(_), def_id)) + DeclKind::Def(Res::Def(DefKind::Macro(_), def_id)) // exclude decl_macro if self.get_macro_by_def_id(def_id).macro_rules => { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 0bf6fcba539e..0ec17a2d6d57 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -43,9 +43,9 @@ use thin_vec::ThinVec; use tracing::{debug, instrument, trace}; use crate::{ - BindingError, BindingKey, Finalize, LexicalScopeBinding, Module, ModuleOrUniformRoot, - NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, Stage, TyCtxt, - UseError, Used, errors, path_names_to_string, rustdoc, + BindingError, BindingKey, Decl, Finalize, LexicalScopeBinding, Module, ModuleOrUniformRoot, + ParentScope, PathResult, ResolutionError, Resolver, Segment, Stage, TyCtxt, UseError, Used, + errors, path_names_to_string, rustdoc, }; mod diagnostics; @@ -1489,7 +1489,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ident: Ident, ns: Namespace, finalize: Option, - ignore_binding: Option>, + ignore_binding: Option>, ) -> Option> { self.r.resolve_ident_in_lexical_scope( ident, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index fbd16072c2c0..a0fda5511048 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -431,7 +431,7 @@ impl<'a> From<&'a ast::PathSegment> for Segment { /// forward. #[derive(Debug, Copy, Clone)] enum LexicalScopeBinding<'ra> { - Item(NameBinding<'ra>), + Item(Decl<'ra>), Res(Res), } @@ -624,8 +624,7 @@ struct ModuleData<'ra> { globs: CmRefCell>>, /// Used to memoize the traits in this module for faster searches through all traits in scope. - traits: - CmRefCell, Option>)]>>>, + traits: CmRefCell, Option>)]>>>, /// Span of the module itself. Used for error reporting. span: Span, @@ -634,7 +633,7 @@ struct ModuleData<'ra> { /// Binding for implicitly declared names that come with a module, /// like `self` (not yet used), or `crate`/`$crate` (for root modules). - self_binding: Option>, + self_binding: Option>, } /// All modules are unique and allocated on a same arena, @@ -663,7 +662,7 @@ impl<'ra> ModuleData<'ra> { expansion: ExpnId, span: Span, no_implicit_prelude: bool, - self_binding: Option>, + self_binding: Option>, ) -> Self { let is_foreign = match kind { ModuleKind::Def(_, def_id, _) => !def_id.is_local(), @@ -691,7 +690,7 @@ impl<'ra> Module<'ra> { fn for_each_child<'tcx, R: AsRef>>( self, resolver: &R, - mut f: impl FnMut(&R, Macros20NormalizedIdent, Namespace, NameBinding<'ra>), + mut f: impl FnMut(&R, Macros20NormalizedIdent, Namespace, Decl<'ra>), ) { for (key, name_resolution) in resolver.as_ref().resolutions(self).borrow().iter() { if let Some(binding) = name_resolution.borrow().best_binding() { @@ -703,7 +702,7 @@ impl<'ra> Module<'ra> { fn for_each_child_mut<'tcx, R: AsMut>>( self, resolver: &mut R, - mut f: impl FnMut(&mut R, Macros20NormalizedIdent, Namespace, NameBinding<'ra>), + mut f: impl FnMut(&mut R, Macros20NormalizedIdent, Namespace, Decl<'ra>), ) { for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() { if let Some(binding) = name_resolution.borrow().best_binding() { @@ -803,11 +802,11 @@ impl<'ra> fmt::Debug for Module<'ra> { } } -/// Records a possibly-private value, type, or module definition. +/// Data associated with any name declaration. #[derive(Clone, Copy, Debug)] -struct NameBindingData<'ra> { - kind: NameBindingKind<'ra>, - ambiguity: Option>, +struct DeclData<'ra> { + kind: DeclKind<'ra>, + ambiguity: Option>, /// Produce a warning instead of an error when reporting ambiguities inside this binding. /// May apply to indirect ambiguities under imports, so `ambiguity.is_some()` is not required. warn_ambiguity: bool, @@ -816,15 +815,15 @@ struct NameBindingData<'ra> { vis: Visibility, } -/// All name bindings are unique and allocated on a same arena, +/// All name declarations are unique and allocated on a same arena, /// so we can use referential equality to compare them. -type NameBinding<'ra> = Interned<'ra, NameBindingData<'ra>>; +type Decl<'ra> = Interned<'ra, DeclData<'ra>>; // Allows us to use Interned without actually enforcing (via Hash/PartialEq/...) uniqueness of the // contained data. // FIXME: We may wish to actually have at least debug-level assertions that Interned's guarantees // are upheld. -impl std::hash::Hash for NameBindingData<'_> { +impl std::hash::Hash for DeclData<'_> { fn hash(&self, _: &mut H) where H: std::hash::Hasher, @@ -833,23 +832,27 @@ impl std::hash::Hash for NameBindingData<'_> { } } +/// Name declaration kind. #[derive(Clone, Copy, Debug)] -enum NameBindingKind<'ra> { - Res(Res), - Import { binding: NameBinding<'ra>, import: Import<'ra> }, +enum DeclKind<'ra> { + /// The name declaration is a definition (possibly without a `DefId`), + /// can be provided by source code or built into the language. + Def(Res), + /// The name declaration is a link to another name declaration. + Import { binding: Decl<'ra>, import: Import<'ra> }, } -impl<'ra> NameBindingKind<'ra> { +impl<'ra> DeclKind<'ra> { /// Is this a name binding of an import? fn is_import(&self) -> bool { - matches!(*self, NameBindingKind::Import { .. }) + matches!(*self, DeclKind::Import { .. }) } } #[derive(Debug)] struct PrivacyError<'ra> { ident: Ident, - binding: NameBinding<'ra>, + binding: Decl<'ra>, dedup_span: Span, outermost_res: Option<(Res, Ident)>, parent_scope: ParentScope<'ra>, @@ -912,36 +915,34 @@ impl AmbiguityKind { struct AmbiguityError<'ra> { kind: AmbiguityKind, ident: Ident, - b1: NameBinding<'ra>, - b2: NameBinding<'ra>, + b1: Decl<'ra>, + b2: Decl<'ra>, // `empty_module` in module scope serves as an unknown module here. scope1: Scope<'ra>, scope2: Scope<'ra>, warning: bool, } -impl<'ra> NameBindingData<'ra> { +impl<'ra> DeclData<'ra> { fn res(&self) -> Res { match self.kind { - NameBindingKind::Res(res) => res, - NameBindingKind::Import { binding, .. } => binding.res(), + DeclKind::Def(res) => res, + DeclKind::Import { binding, .. } => binding.res(), } } - fn import_source(&self) -> NameBinding<'ra> { + fn import_source(&self) -> Decl<'ra> { match self.kind { - NameBindingKind::Import { binding, .. } => binding, + DeclKind::Import { binding, .. } => binding, _ => unreachable!(), } } - fn descent_to_ambiguity( - self: NameBinding<'ra>, - ) -> Option<(NameBinding<'ra>, NameBinding<'ra>)> { + fn descent_to_ambiguity(self: Decl<'ra>) -> Option<(Decl<'ra>, Decl<'ra>)> { match self.ambiguity { Some(ambig_binding) => Some((self, ambig_binding)), None => match self.kind { - NameBindingKind::Import { binding, .. } => binding.descent_to_ambiguity(), + DeclKind::Import { binding, .. } => binding.descent_to_ambiguity(), _ => None, }, } @@ -950,7 +951,7 @@ impl<'ra> NameBindingData<'ra> { fn is_ambiguity_recursive(&self) -> bool { self.ambiguity.is_some() || match self.kind { - NameBindingKind::Import { binding, .. } => binding.is_ambiguity_recursive(), + DeclKind::Import { binding, .. } => binding.is_ambiguity_recursive(), _ => false, } } @@ -958,46 +959,45 @@ impl<'ra> NameBindingData<'ra> { fn warn_ambiguity_recursive(&self) -> bool { self.warn_ambiguity || match self.kind { - NameBindingKind::Import { binding, .. } => binding.warn_ambiguity_recursive(), + DeclKind::Import { binding, .. } => binding.warn_ambiguity_recursive(), _ => false, } } fn is_possibly_imported_variant(&self) -> bool { match self.kind { - NameBindingKind::Import { binding, .. } => binding.is_possibly_imported_variant(), - NameBindingKind::Res(Res::Def( - DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), - _, - )) => true, - NameBindingKind::Res(..) => false, + DeclKind::Import { binding, .. } => binding.is_possibly_imported_variant(), + DeclKind::Def(Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), _)) => { + true + } + DeclKind::Def(..) => false, } } fn is_extern_crate(&self) -> bool { match self.kind { - NameBindingKind::Import { import, .. } => { + DeclKind::Import { import, .. } => { matches!(import.kind, ImportKind::ExternCrate { .. }) } - NameBindingKind::Res(Res::Def(_, def_id)) => def_id.is_crate_root(), + DeclKind::Def(Res::Def(_, def_id)) => def_id.is_crate_root(), _ => false, } } fn is_import(&self) -> bool { - matches!(self.kind, NameBindingKind::Import { .. }) + matches!(self.kind, DeclKind::Import { .. }) } /// The binding introduced by `#[macro_export] macro_rules` is a public import, but it might /// not be perceived as such by users, so treat it as a non-import in some diagnostics. fn is_import_user_facing(&self) -> bool { - matches!(self.kind, NameBindingKind::Import { import, .. } + matches!(self.kind, DeclKind::Import { import, .. } if !matches!(import.kind, ImportKind::MacroExport)) } fn is_glob_import(&self) -> bool { match self.kind { - NameBindingKind::Import { import, .. } => import.is_glob(), + DeclKind::Import { import, .. } => import.is_glob(), _ => false, } } @@ -1010,10 +1010,10 @@ impl<'ra> NameBindingData<'ra> { self.res().macro_kinds() } - fn reexport_chain(self: NameBinding<'ra>, r: &Resolver<'_, '_>) -> SmallVec<[Reexport; 2]> { + fn reexport_chain(self: Decl<'ra>, r: &Resolver<'_, '_>) -> SmallVec<[Reexport; 2]> { let mut reexport_chain = SmallVec::new(); let mut next_binding = self; - while let NameBindingKind::Import { binding, import, .. } = next_binding.kind { + while let DeclKind::Import { binding, import, .. } = next_binding.kind { reexport_chain.push(import.simplify(r)); next_binding = binding; } @@ -1026,11 +1026,7 @@ impl<'ra> NameBindingData<'ra> { // in some later round and screw up our previously found resolution. // See more detailed explanation in // https://github.com/rust-lang/rust/pull/53778#issuecomment-419224049 - fn may_appear_after( - &self, - invoc_parent_expansion: LocalExpnId, - binding: NameBinding<'_>, - ) -> bool { + fn may_appear_after(&self, invoc_parent_expansion: LocalExpnId, binding: Decl<'_>) -> bool { // self > max(invoc, binding) => !(self <= invoc || self <= binding) // Expansions are partially ordered, so "may appear after" is an inversion of // "certainly appears before or simultaneously" and includes unordered cases. @@ -1048,7 +1044,7 @@ impl<'ra> NameBindingData<'ra> { // FIXME: How can we integrate it with the `update_resolution`? fn determined(&self) -> bool { match &self.kind { - NameBindingKind::Import { binding, import, .. } if import.is_glob() => { + DeclKind::Import { binding, import, .. } if import.is_glob() => { import.parent_scope.module.unexpanded_invocations.borrow().is_empty() && binding.determined() } @@ -1061,7 +1057,7 @@ struct ExternPreludeEntry<'ra> { /// Binding from an `extern crate` item. /// The boolean flag is true is `item_binding` is non-redundant, happens either when /// `flag_binding` is `None`, or when `extern crate` introducing `item_binding` used renaming. - item_binding: Option<(NameBinding<'ra>, /* introduced by item */ bool)>, + item_binding: Option<(Decl<'ra>, /* introduced by item */ bool)>, /// Binding from an `--extern` flag, lazily populated on first use. flag_binding: Option, /* finalized */ bool)>>, } @@ -1181,7 +1177,7 @@ pub struct Resolver<'ra, 'tcx> { local_module_map: FxIndexMap>, /// Lazily populated cache of modules loaded from external crates. extern_module_map: CacheRefCell>>, - binding_parent_modules: FxHashMap, Module<'ra>>, + binding_parent_modules: FxHashMap, Module<'ra>>, /// Maps glob imports to the names of items actually imported. glob_map: FxIndexMap>, @@ -1206,14 +1202,14 @@ pub struct Resolver<'ra, 'tcx> { inaccessible_ctor_reexport: FxHashMap, arenas: &'ra ResolverArenas<'ra>, - dummy_binding: NameBinding<'ra>, - builtin_types_bindings: FxHashMap>, - builtin_attrs_bindings: FxHashMap>, - registered_tool_bindings: FxHashMap>, + dummy_binding: Decl<'ra>, + builtin_types_bindings: FxHashMap>, + builtin_attrs_bindings: FxHashMap>, + registered_tool_bindings: FxHashMap>, macro_names: FxHashSet, builtin_macros: FxHashMap, registered_tools: &'tcx RegisteredTools, - macro_use_prelude: FxIndexMap>, + macro_use_prelude: FxIndexMap>, /// Eagerly populated map of all local macro definitions. local_macro_map: FxHashMap, /// Lazily populated cache of macro definitions loaded from external crates. @@ -1229,7 +1225,7 @@ pub struct Resolver<'ra, 'tcx> { proc_macro_stubs: FxHashSet, /// Traces collected during macro resolution and validated when it's complete. single_segment_macro_resolutions: - CmRefCell, Option>, Option)>>, + CmRefCell, Option>, Option)>>, multi_segment_macro_resolutions: CmRefCell, Span, MacroKind, ParentScope<'ra>, Option, Namespace)>>, builtin_attrs: Vec<(Ident, ParentScope<'ra>)>, @@ -1246,7 +1242,7 @@ pub struct Resolver<'ra, 'tcx> { /// `macro_rules` scopes produced by `macro_rules` item definitions. macro_rules_scopes: FxHashMap>, /// Helper attributes that are in scope for the given expansion. - helper_attrs: FxHashMap)>>, + helper_attrs: FxHashMap)>>, /// Ready or in-progress results of resolving paths inside the `#[derive(...)]` attribute /// with the given `ExpnId`. derive_data: FxHashMap, @@ -1344,9 +1340,9 @@ impl<'ra> ResolverArenas<'ra> { vis: Visibility, span: Span, expansion: LocalExpnId, - ) -> NameBinding<'ra> { - self.alloc_name_binding(NameBindingData { - kind: NameBindingKind::Res(res), + ) -> Decl<'ra> { + self.alloc_name_binding(DeclData { + kind: DeclKind::Def(res), ambiguity: None, warn_ambiguity: false, vis, @@ -1355,12 +1351,7 @@ impl<'ra> ResolverArenas<'ra> { }) } - fn new_pub_res_binding( - &'ra self, - res: Res, - span: Span, - expn_id: LocalExpnId, - ) -> NameBinding<'ra> { + fn new_pub_res_binding(&'ra self, res: Res, span: Span, expn_id: LocalExpnId) -> Decl<'ra> { self.new_res_binding(res, Visibility::Public, span, expn_id) } @@ -1387,7 +1378,7 @@ impl<'ra> ResolverArenas<'ra> { self_binding, )))) } - fn alloc_name_binding(&'ra self, name_binding: NameBindingData<'ra>) -> NameBinding<'ra> { + fn alloc_name_binding(&'ra self, name_binding: DeclData<'ra>) -> Decl<'ra> { Interned::new_unchecked(self.dropless.alloc(name_binding)) } fn alloc_import(&'ra self, import: ImportData<'ra>) -> Import<'ra> { @@ -1994,11 +1985,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn find_transitive_imports( &mut self, - mut kind: &NameBindingKind<'_>, + mut kind: &DeclKind<'_>, trait_name: Ident, ) -> SmallVec<[LocalDefId; 1]> { let mut import_ids = smallvec![]; - while let NameBindingKind::Import { import, binding, .. } = kind { + while let DeclKind::Import { import, binding, .. } = kind { if let Some(node_id) = import.id() { let def_id = self.local_def_id(node_id); self.maybe_unused_trait_imports.insert(def_id); @@ -2053,14 +2044,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { false } - fn record_use(&mut self, ident: Ident, used_binding: NameBinding<'ra>, used: Used) { + fn record_use(&mut self, ident: Ident, used_binding: Decl<'ra>, used: Used) { self.record_use_inner(ident, used_binding, used, used_binding.warn_ambiguity); } fn record_use_inner( &mut self, ident: Ident, - used_binding: NameBinding<'ra>, + used_binding: Decl<'ra>, used: Used, warn_ambiguity: bool, ) { @@ -2079,7 +2070,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.ambiguity_errors.push(ambiguity_error); } } - if let NameBindingKind::Import { import, binding } = used_binding.kind { + if let DeclKind::Import { import, binding } = used_binding.kind { if let ImportKind::MacroUse { warn_private: true } = import.kind { // Do not report the lint if the macro name resolves in stdlib prelude // even without the problematic `macro_use` import. @@ -2236,7 +2227,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { vis.is_accessible_from(module.nearest_parent_mod(), self.tcx) } - fn set_binding_parent_module(&mut self, binding: NameBinding<'ra>, module: Module<'ra>) { + fn set_binding_parent_module(&mut self, binding: Decl<'ra>, module: Module<'ra>) { if let Some(old_module) = self.binding_parent_modules.insert(binding, module) { if module != old_module { span_bug!(binding.span, "parent module is reset for binding"); @@ -2246,8 +2237,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn disambiguate_macro_rules_vs_modularized( &self, - macro_rules: NameBinding<'ra>, - modularized: NameBinding<'ra>, + macro_rules: Decl<'ra>, + modularized: Decl<'ra>, ) -> bool { // Some non-controversial subset of ambiguities "modularized macro name" vs "macro_rules" // is disambiguated to mitigate regressions from macro modularization. @@ -2266,7 +2257,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { mut self: CmResolver<'r, 'ra, 'tcx>, ident: Ident, finalize: bool, - ) -> Option> { + ) -> Option> { let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)); entry.and_then(|entry| entry.item_binding).map(|(binding, _)| { if finalize { @@ -2276,7 +2267,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }) } - fn extern_prelude_get_flag(&self, ident: Ident, finalize: bool) -> Option> { + fn extern_prelude_get_flag(&self, ident: Ident, finalize: bool) -> Option> { let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)); entry.and_then(|entry| entry.flag_binding.as_ref()).and_then(|flag_binding| { let (pending_binding, finalized) = flag_binding.get(); diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 6bba985d87dd..07dd5d8fc889 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -38,9 +38,9 @@ use crate::errors::{ }; use crate::imports::Import; use crate::{ - BindingKey, CacheCell, CmResolver, DeriveData, Determinacy, Finalize, InvocationParent, - MacroData, ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, - PathResult, ResolutionError, Resolver, ScopeSet, Segment, Used, + BindingKey, CacheCell, CmResolver, Decl, DeclKind, DeriveData, Determinacy, Finalize, + InvocationParent, MacroData, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, + ResolutionError, Resolver, ScopeSet, Segment, Used, }; type Res = def::Res; @@ -49,7 +49,7 @@ type Res = def::Res; /// Not modularized, can shadow previous `macro_rules` bindings, etc. #[derive(Debug)] pub(crate) struct MacroRulesBinding<'ra> { - pub(crate) binding: NameBinding<'ra>, + pub(crate) binding: Decl<'ra>, /// `macro_rules` scope into which the `macro_rules` item was planted. pub(crate) parent_macro_rules_scope: MacroRulesScopeRef<'ra>, pub(crate) ident: Ident, @@ -1062,7 +1062,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn prohibit_imported_non_macro_attrs( &self, - binding: Option>, + binding: Option>, res: Option, span: Span, ) { @@ -1084,12 +1084,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { path: &ast::Path, parent_scope: &ParentScope<'ra>, invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>, - binding: Option>, + binding: Option>, ) { if let Some((mod_def_id, node_id)) = invoc_in_mod_inert_attr && let Some(binding) = binding // This is a `macro_rules` itself, not some import. - && let NameBindingKind::Res(res) = binding.kind + && let DeclKind::Def(res) = binding.kind && let Res::Def(DefKind::Macro(kinds), def_id) = res && kinds.contains(MacroKinds::BANG) // And the `macro_rules` is defined inside the attribute's module, From 7a34af2f67bde4d4ab067c5a41c2b388adfc9531 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 30 Dec 2025 20:36:30 +0300 Subject: [PATCH 0297/1061] resolve: Rename `LexicalScopeBinding::(Item,Res)` to `LateDecl::(Decl,RibDef)` --- compiler/rustc_resolve/src/check_unused.rs | 4 ++-- compiler/rustc_resolve/src/diagnostics.rs | 13 +++++----- compiler/rustc_resolve/src/ident.rs | 17 +++++++------ compiler/rustc_resolve/src/late.rs | 28 +++++++++++----------- compiler/rustc_resolve/src/lib.rs | 21 ++++++++-------- 5 files changed, 40 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index b7705773041f..a2e903ce48eb 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -36,7 +36,7 @@ use rustc_session::lint::builtin::{ use rustc_span::{DUMMY_SP, Ident, Macros20NormalizedIdent, Span, kw}; use crate::imports::{Import, ImportKind}; -use crate::{DeclKind, LexicalScopeBinding, Resolver, module_to_string}; +use crate::{DeclKind, LateDecl, Resolver, module_to_string}; struct UnusedImport { use_tree: ast::UseTree, @@ -542,7 +542,7 @@ impl Resolver<'_, '_> { // Deleting both unused imports and unnecessary segments of an item may result // in the item not being found. for unn_qua in &self.potentially_unnecessary_qualifications { - if let LexicalScopeBinding::Item(name_binding) = unn_qua.binding + if let LateDecl::Decl(name_binding) = unn_qua.binding && let DeclKind::Import { import, .. } = name_binding.kind && (is_unused_import(import, &unused_imports) || is_redundant_import(import, &redundant_imports)) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 7e78f66574ed..99812fe4df53 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -45,10 +45,9 @@ use crate::imports::{Import, ImportKind}; use crate::late::{DiagMetadata, PatternSource, Rib}; use crate::{ AmbiguityError, AmbiguityKind, BindingError, BindingKey, Decl, DeclKind, Finalize, - ForwardGenericParamBanReason, HasGenericParams, LexicalScopeBinding, MacroRulesScope, Module, - ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, PrivacyError, ResolutionError, - Resolver, Scope, ScopeSet, Segment, UseError, Used, VisResolutionError, errors as errs, - path_names_to_string, + ForwardGenericParamBanReason, HasGenericParams, LateDecl, MacroRulesScope, Module, ModuleKind, + ModuleOrUniformRoot, ParentScope, PathResult, PrivacyError, ResolutionError, Resolver, Scope, + ScopeSet, Segment, UseError, Used, VisResolutionError, errors as errs, path_names_to_string, }; type Res = def::Res; @@ -2528,7 +2527,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { diag_metadata, ) { // we found a locally-imported or available item/module - Some(LexicalScopeBinding::Item(binding)) => Some(binding), + Some(LateDecl::Decl(binding)) => Some(binding), _ => None, } } else { @@ -2590,7 +2589,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // // variable `Foo`. // } // ``` - Some(LexicalScopeBinding::Res(Res::Local(id))) => { + Some(LateDecl::RibDef(Res::Local(id))) => { Some(*self.pat_span_map.get(&id).unwrap()) } // Name matches item from a local name binding @@ -2604,7 +2603,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // // binding `Foo`. // } // ``` - Some(LexicalScopeBinding::Item(name_binding)) => Some(name_binding.span), + Some(LateDecl::Decl(name_binding)) => Some(name_binding.span), _ => None, }; let suggestion = match_span.map(|span| { diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 7ebc75abca89..a6a8545ac69e 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -20,9 +20,8 @@ use crate::late::{ use crate::macros::{MacroRulesScope, sub_namespace_match}; use crate::{ AmbiguityError, AmbiguityKind, BindingKey, CmResolver, Decl, DeclKind, Determinacy, Finalize, - ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot, ParentScope, - PathResult, PrivacyError, Res, ResolutionError, Resolver, Scope, ScopeSet, Segment, Stage, - Used, errors, + ImportKind, LateDecl, Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, + PrivacyError, Res, ResolutionError, Resolver, Scope, ScopeSet, Segment, Stage, Used, errors, }; #[derive(Copy, Clone)] @@ -307,7 +306,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ribs: &[Rib<'ra>], ignore_binding: Option>, diag_metadata: Option<&DiagMetadata<'_>>, - ) -> Option> { + ) -> Option> { let orig_ident = ident; let (general_span, normalized_span) = if ident.name == kw::SelfUpper { // FIXME(jseyfried) improve `Self` hygiene @@ -330,7 +329,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let rib_ident = if rib.kind.contains_params() { normalized_ident } else { ident }; if let Some((original_rib_ident_def, res)) = rib.bindings.get_key_value(&rib_ident) { // The ident resolves to a type parameter or local variable. - return Some(LexicalScopeBinding::Res(self.validate_res_from_ribs( + return Some(LateDecl::RibDef(self.validate_res_from_ribs( i, rib_ident, *res, @@ -351,7 +350,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) { // The ident resolves to an item in a block. - return Some(LexicalScopeBinding::Item(binding)); + return Some(LateDecl::Decl(binding)); } else if let RibKind::Module(module) = rib.kind { // Encountered a module item, abandon ribs and look into that module and preludes. let parent_scope = &ParentScope { module, ..*parent_scope }; @@ -368,7 +367,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None, ) .ok() - .map(LexicalScopeBinding::Item); + .map(LateDecl::Decl); } if let RibKind::MacroDefinition(def) = rib.kind @@ -1836,9 +1835,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { diag_metadata, ) { // we found a locally-imported or available item/module - Some(LexicalScopeBinding::Item(binding)) => Ok(binding), + Some(LateDecl::Decl(binding)) => Ok(binding), // we found a local variable or type param - Some(LexicalScopeBinding::Res(res)) => { + Some(LateDecl::RibDef(res)) => { record_segment_res(self.reborrow(), finalize, res, id); return PathResult::NonModule(PartialRes::with_unresolved_segments( res, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 0ec17a2d6d57..2685efa28b64 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -43,9 +43,9 @@ use thin_vec::ThinVec; use tracing::{debug, instrument, trace}; use crate::{ - BindingError, BindingKey, Decl, Finalize, LexicalScopeBinding, Module, ModuleOrUniformRoot, - ParentScope, PathResult, ResolutionError, Resolver, Segment, Stage, TyCtxt, UseError, Used, - errors, path_names_to_string, rustdoc, + BindingError, BindingKey, Decl, Finalize, LateDecl, Module, ModuleOrUniformRoot, ParentScope, + PathResult, ResolutionError, Resolver, Segment, Stage, TyCtxt, UseError, Used, errors, + path_names_to_string, rustdoc, }; mod diagnostics; @@ -677,7 +677,7 @@ impl MaybeExported<'_> { /// Used for recording UnnecessaryQualification. #[derive(Debug)] pub(crate) struct UnnecessaryQualification<'ra> { - pub binding: LexicalScopeBinding<'ra>, + pub binding: LateDecl<'ra>, pub node_id: NodeId, pub path_span: Span, pub removal_span: Span, @@ -1472,7 +1472,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { &mut self, ident: Ident, ns: Namespace, - ) -> Option> { + ) -> Option> { self.r.resolve_ident_in_lexical_scope( ident, ns, @@ -1490,7 +1490,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ns: Namespace, finalize: Option, ignore_binding: Option>, - ) -> Option> { + ) -> Option> { self.r.resolve_ident_in_lexical_scope( ident, ns, @@ -2685,11 +2685,11 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { for &ns in nss { match self.maybe_resolve_ident_in_lexical_scope(ident, ns) { - Some(LexicalScopeBinding::Res(..)) => { + Some(LateDecl::RibDef(..)) => { report_error(self, ns); } - Some(LexicalScopeBinding::Item(binding)) => { - if let Some(LexicalScopeBinding::Res(..)) = + Some(LateDecl::Decl(binding)) => { + if let Some(LateDecl::RibDef(..)) = self.resolve_ident_in_lexical_scope(ident, ns, None, Some(binding)) { report_error(self, ns); @@ -4257,7 +4257,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { let ls_binding = self.maybe_resolve_ident_in_lexical_scope(ident, ValueNS)?; let (res, binding) = match ls_binding { - LexicalScopeBinding::Item(binding) + LateDecl::Decl(binding) if is_syntactic_ambiguity && binding.is_ambiguity_recursive() => { // For ambiguous bindings we don't know all their definitions and cannot check @@ -4267,8 +4267,8 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.r.record_use(ident, binding, Used::Other); return None; } - LexicalScopeBinding::Item(binding) => (binding.res(), Some(binding)), - LexicalScopeBinding::Res(res) => (res, None), + LateDecl::Decl(binding) => (binding.res(), Some(binding)), + LateDecl::RibDef(res) => (res, None), }; match res { @@ -4641,13 +4641,13 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { fn self_type_is_available(&mut self) -> bool { let binding = self .maybe_resolve_ident_in_lexical_scope(Ident::with_dummy_span(kw::SelfUpper), TypeNS); - if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false } + if let Some(LateDecl::RibDef(res)) = binding { res != Res::Err } else { false } } fn self_value_is_available(&mut self, self_span: Span) -> bool { let ident = Ident::new(kw::SelfLower, self_span); let binding = self.maybe_resolve_ident_in_lexical_scope(ident, ValueNS); - if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false } + if let Some(LateDecl::RibDef(res)) = binding { res != Res::Err } else { false } } /// A wrapper around [`Resolver::report_error`]. diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index a0fda5511048..8982ec15de8f 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -424,22 +424,21 @@ impl<'a> From<&'a ast::PathSegment> for Segment { } } -/// An intermediate resolution result. -/// -/// This refers to the thing referred by a name. The difference between `Res` and `Item` is that -/// items are visible in their whole block, while `Res`es only from the place they are defined -/// forward. +/// Name declaration used during late resolution. #[derive(Debug, Copy, Clone)] -enum LexicalScopeBinding<'ra> { - Item(Decl<'ra>), - Res(Res), +enum LateDecl<'ra> { + /// A regular name declaration. + Decl(Decl<'ra>), + /// A name definition from a rib, e.g. a local variable. + /// Omits most of the data from regular `Decl` for performance reasons. + RibDef(Res), } -impl<'ra> LexicalScopeBinding<'ra> { +impl<'ra> LateDecl<'ra> { fn res(self) -> Res { match self { - LexicalScopeBinding::Item(binding) => binding.res(), - LexicalScopeBinding::Res(res) => res, + LateDecl::Decl(binding) => binding.res(), + LateDecl::RibDef(res) => res, } } } From 844e085de69c4d17cc21cbfda08d58caa286fa49 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 30 Dec 2025 20:47:03 +0300 Subject: [PATCH 0298/1061] resolve: `MacroRulesScope::Binding` -> `MacroRulesScope::Def` `MacroRulesBinding` -> `MacroRulesDef` --- compiler/rustc_resolve/src/build_reduced_graph.rs | 6 +++--- compiler/rustc_resolve/src/diagnostics.rs | 2 +- compiler/rustc_resolve/src/ident.rs | 6 ++---- compiler/rustc_resolve/src/lib.rs | 6 +++--- compiler/rustc_resolve/src/macros.rs | 6 +++--- 5 files changed, 12 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index d31723844290..d23e86273e52 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -33,7 +33,7 @@ use tracing::debug; use crate::Namespace::{MacroNS, TypeNS, ValueNS}; use crate::def_collector::collect_definitions; use crate::imports::{ImportData, ImportKind}; -use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; +use crate::macros::{MacroRulesDecl, MacroRulesScope, MacroRulesScopeRef}; use crate::ref_mut::CmCell; use crate::{ BindingKey, Decl, DeclData, DeclKind, ExternPreludeEntry, Finalize, MacroData, Module, @@ -1326,8 +1326,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.insert_unused_macro(ident, def_id, item.id); } self.r.feed_visibility(feed, vis); - let scope = self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Binding( - self.r.arenas.alloc_macro_rules_binding(MacroRulesBinding { + let scope = self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Def( + self.r.arenas.alloc_macro_rules_binding(MacroRulesDecl { parent_macro_rules_scope: parent_scope.macro_rules, binding, ident, diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 99812fe4df53..21328b39623e 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1195,7 +1195,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Never recommend deprecated helper attributes. } Scope::MacroRules(macro_rules_scope) => { - if let MacroRulesScope::Binding(macro_rules_binding) = macro_rules_scope.get() { + if let MacroRulesScope::Def(macro_rules_binding) = macro_rules_scope.get() { let res = macro_rules_binding.binding.res(); if filter_fn(res) { suggestions.push(TypoSuggestion::typo_from_ident( diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index a6a8545ac69e..7438403a4745 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -182,7 +182,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } Scope::DeriveHelpersCompat => Scope::MacroRules(parent_scope.macro_rules), Scope::MacroRules(macro_rules_scope) => match macro_rules_scope.get() { - MacroRulesScope::Binding(binding) => { + MacroRulesScope::Def(binding) => { Scope::MacroRules(binding.parent_macro_rules_scope) } MacroRulesScope::Invocation(invoc_id) => { @@ -559,9 +559,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { result } Scope::MacroRules(macro_rules_scope) => match macro_rules_scope.get() { - MacroRulesScope::Binding(macro_rules_binding) - if ident == macro_rules_binding.ident => - { + MacroRulesScope::Def(macro_rules_binding) if ident == macro_rules_binding.ident => { Ok(macro_rules_binding.binding) } MacroRulesScope::Invocation(_) => Err(Determinacy::Undetermined), diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 8982ec15de8f..ea13125f5417 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -38,7 +38,7 @@ use late::{ ForwardGenericParamBanReason, HasGenericParams, PathSource, PatternSource, UnnecessaryQualification, }; -use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; +use macros::{MacroRulesDecl, MacroRulesScope, MacroRulesScopeRef}; use rustc_arena::{DroplessArena, TypedArena}; use rustc_ast::node_id::NodeMap; use rustc_ast::{ @@ -1391,8 +1391,8 @@ impl<'ra> ResolverArenas<'ra> { } fn alloc_macro_rules_binding( &'ra self, - binding: MacroRulesBinding<'ra>, - ) -> &'ra MacroRulesBinding<'ra> { + binding: MacroRulesDecl<'ra>, + ) -> &'ra MacroRulesDecl<'ra> { self.dropless.alloc(binding) } fn alloc_ast_paths(&'ra self, paths: &[ast::Path]) -> &'ra [ast::Path] { diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 07dd5d8fc889..e07bb46ac568 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -45,10 +45,10 @@ use crate::{ type Res = def::Res; -/// Binding produced by a `macro_rules` item. +/// Name declaration produced by a `macro_rules` item definition. /// Not modularized, can shadow previous `macro_rules` bindings, etc. #[derive(Debug)] -pub(crate) struct MacroRulesBinding<'ra> { +pub(crate) struct MacroRulesDecl<'ra> { pub(crate) binding: Decl<'ra>, /// `macro_rules` scope into which the `macro_rules` item was planted. pub(crate) parent_macro_rules_scope: MacroRulesScopeRef<'ra>, @@ -65,7 +65,7 @@ pub(crate) enum MacroRulesScope<'ra> { /// Empty "root" scope at the crate start containing no names. Empty, /// The scope introduced by a `macro_rules!` macro definition. - Binding(&'ra MacroRulesBinding<'ra>), + Def(&'ra MacroRulesDecl<'ra>), /// The scope introduced by a macro invocation that can potentially /// create a `macro_rules!` macro definition. Invocation(LocalExpnId), From a67e289b4d9f0aaf3fef25a819b42a58536474c0 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 30 Dec 2025 21:32:07 +0300 Subject: [PATCH 0299/1061] Update some function names and fields from bindings to declarations --- .../rustc_resolve/src/build_reduced_graph.rs | 52 +++---- compiler/rustc_resolve/src/diagnostics.rs | 12 +- .../src/effective_visibilities.rs | 22 +-- compiler/rustc_resolve/src/ident.rs | 18 +-- compiler/rustc_resolve/src/imports.rs | 90 ++++++------- compiler/rustc_resolve/src/lib.rs | 127 +++++++++--------- compiler/rustc_resolve/src/macros.rs | 18 ++- 7 files changed, 167 insertions(+), 172 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index d23e86273e52..7569fc3d716b 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -51,10 +51,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent: Module<'ra>, ident: Ident, ns: Namespace, - binding: Decl<'ra>, + decl: Decl<'ra>, ) { - if let Err(old_binding) = self.try_define_local(parent, ident, ns, binding, false) { - self.report_conflict(parent, ident, ns, old_binding, binding); + if let Err(old_binding) = self.try_define_local(parent, ident, ns, decl, false) { + self.report_conflict(parent, ident, ns, old_binding, decl); } } @@ -68,7 +68,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { span: Span, expn_id: LocalExpnId, ) { - let binding = self.arenas.new_res_binding(res, vis.to_def_id(), span, expn_id); + let binding = self.arenas.new_def_decl(res, vis.to_def_id(), span, expn_id); self.define_binding_local(parent, ident, ns, binding); } @@ -84,7 +84,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { expansion: LocalExpnId, ambiguity: Option>, ) { - let binding = self.arenas.alloc_name_binding(DeclData { + let binding = self.arenas.alloc_decl(DeclData { kind: DeclKind::Def(res), ambiguity, // External ambiguities always report the `AMBIGUOUS_GLOB_IMPORTS` lint at the moment. @@ -284,7 +284,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let ModChild { ident: _, res, vis, ref reexport_chain } = *ambig_child; let span = child_span(self, reexport_chain, res); let res = res.expect_non_local(); - self.arenas.new_res_binding(res, vis, span, expansion) + self.arenas.new_def_decl(res, vis, span, expansion) }); // Record primary definitions. @@ -977,7 +977,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let parent_scope = self.parent_scope; let expansion = parent_scope.expansion; - let (used, module, binding) = if orig_name.is_none() && ident.name == kw::SelfLower { + let (used, module, decl) = if orig_name.is_none() && ident.name == kw::SelfLower { self.r.dcx().emit_err(errors::ExternCrateSelfRequiresRenaming { span: sp }); return; } else if orig_name == Some(kw::SelfLower) { @@ -997,10 +997,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } .map(|module| { let used = self.process_macro_use_imports(item, module); - let binding = self.r.arenas.new_pub_res_binding(module.res().unwrap(), sp, expansion); - (used, Some(ModuleOrUniformRoot::Module(module)), binding) + let decl = self.r.arenas.new_pub_def_decl(module.res().unwrap(), sp, expansion); + (used, Some(ModuleOrUniformRoot::Module(module)), decl) }) - .unwrap_or((true, None, self.r.dummy_binding)); + .unwrap_or((true, None, self.r.dummy_decl)); let import = self.r.arenas.alloc_import(ImportData { kind: ImportKind::ExternCrate { source: orig_name, target: ident, id: item.id }, root_id: item.id, @@ -1019,7 +1019,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.import_use_map.insert(import, Used::Other); } self.r.potentially_unused_imports.push(import); - let imported_binding = self.r.import(binding, import); + let imported_binding = self.r.import(decl, import); if ident.name != kw::Underscore && parent == self.r.graph_root { let norm_ident = Macros20NormalizedIdent::new(ident); // FIXME: this error is technically unnecessary now when extern prelude is split into @@ -1027,7 +1027,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { if let Some(entry) = self.r.extern_prelude.get(&norm_ident) && expansion != LocalExpnId::ROOT && orig_name.is_some() - && entry.item_binding.is_none() + && entry.item_decl.is_none() { self.r.dcx().emit_err( errors::MacroExpandedExternCrateCannotShadowExternArguments { span: item.span }, @@ -1038,17 +1038,17 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { match self.r.extern_prelude.entry(norm_ident) { Entry::Occupied(mut occupied) => { let entry = occupied.get_mut(); - if entry.item_binding.is_some() { + if entry.item_decl.is_some() { let msg = format!("extern crate `{ident}` already in extern prelude"); self.r.tcx.dcx().span_delayed_bug(item.span, msg); } else { - entry.item_binding = Some((imported_binding, orig_name.is_some())); + entry.item_decl = Some((imported_binding, orig_name.is_some())); } entry } Entry::Vacant(vacant) => vacant.insert(ExternPreludeEntry { - item_binding: Some((imported_binding, true)), - flag_binding: None, + item_decl: Some((imported_binding, true)), + flag_decl: None, }), }; } @@ -1089,14 +1089,14 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } } - fn add_macro_use_binding( + fn add_macro_use_decl( &mut self, name: Symbol, - binding: Decl<'ra>, + decl: Decl<'ra>, span: Span, allow_shadowing: bool, ) { - if self.r.macro_use_prelude.insert(name, binding).is_some() && !allow_shadowing { + if self.r.macro_use_prelude.insert(name, decl).is_some() && !allow_shadowing { self.r.dcx().emit_err(errors::MacroUseNameAlreadyInUse { span, name }); } } @@ -1168,7 +1168,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { macro_use_import(this, span, true) }; let import_binding = this.r.import(binding, import); - this.add_macro_use_binding(ident.name, import_binding, span, allow_shadowing); + this.add_macro_use_decl(ident.name, import_binding, span, allow_shadowing); } }); } else { @@ -1184,7 +1184,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let import = macro_use_import(self, ident.span, false); self.r.potentially_unused_imports.push(import); let imported_binding = self.r.import(binding, import); - self.add_macro_use_binding( + self.add_macro_use_decl( ident.name, imported_binding, ident.span, @@ -1300,8 +1300,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } else { Visibility::Restricted(CRATE_DEF_ID) }; - let binding = self.r.arenas.new_res_binding(res, vis.to_def_id(), span, expansion); - self.r.set_binding_parent_module(binding, parent_scope.module); + let decl = self.r.arenas.new_def_decl(res, vis.to_def_id(), span, expansion); + self.r.set_decl_parent_module(decl, parent_scope.module); self.r.all_macro_rules.insert(ident.name); if is_macro_export { let import = self.r.arenas.alloc_import(ImportData { @@ -1319,7 +1319,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { vis_span: item.vis.span, }); self.r.import_use_map.insert(import, Used::Other); - let import_binding = self.r.import(binding, import); + let import_binding = self.r.import(decl, import); self.r.define_binding_local(self.r.graph_root, ident, MacroNS, import_binding); } else { self.r.check_reserved_macro_name(ident, res); @@ -1327,9 +1327,9 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } self.r.feed_visibility(feed, vis); let scope = self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Def( - self.r.arenas.alloc_macro_rules_binding(MacroRulesDecl { + self.r.arenas.alloc_macro_rules_decl(MacroRulesDecl { parent_macro_rules_scope: parent_scope.macro_rules, - binding, + decl, ident, }), )); diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 21328b39623e..b77481d1b3ad 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1196,7 +1196,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } Scope::MacroRules(macro_rules_scope) => { if let MacroRulesScope::Def(macro_rules_binding) = macro_rules_scope.get() { - let res = macro_rules_binding.binding.res(); + let res = macro_rules_binding.decl.res(); if filter_fn(res) { suggestions.push(TypoSuggestion::typo_from_ident( macro_rules_binding.ident, @@ -1969,7 +1969,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { true } - fn binding_description(&self, b: Decl<'_>, ident: Ident, scope: Scope<'_>) -> String { + fn decl_description(&self, b: Decl<'_>, ident: Ident, scope: Scope<'_>) -> String { let res = b.res(); if b.span.is_dummy() || !self.tcx.sess.source_map().is_span_accessible(b.span) { let (built_in, from) = match scope { @@ -2005,7 +2005,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && self .extern_prelude .get(&Macros20NormalizedIdent::new(ident)) - .is_some_and(|entry| entry.item_binding.map(|(b, _)| b) == Some(b1)) + .is_some_and(|entry| entry.item_decl.map(|(b, _)| b) == Some(b1)) }; let (b1, b2, scope1, scope2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() { // We have to print the span-less alternative first, otherwise formatting looks bad. @@ -2015,7 +2015,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; let could_refer_to = |b: Decl<'_>, scope: Scope<'ra>, also: &str| { - let what = self.binding_description(b, ident, scope); + let what = self.decl_description(b, ident, scope); let note_msg = format!("`{ident}` could{also} refer to {what}"); let thing = b.res().descr(); @@ -2073,9 +2073,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// If the binding refers to a tuple struct constructor with fields, /// returns the span of its fields. - fn ctor_fields_span(&self, binding: Decl<'_>) -> Option { + fn ctor_fields_span(&self, decl: Decl<'_>) -> Option { let DeclKind::Def(Res::Def(DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), ctor_def_id)) = - binding.kind + decl.kind else { return None; }; diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 5d78f3752439..389bdbbec62b 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -42,8 +42,8 @@ impl Resolver<'_, '_> { self.get_nearest_non_block_module(def_id.to_def_id()).nearest_parent_mod().expect_local() } - fn private_vis_import(&self, binding: Decl<'_>) -> Visibility { - let DeclKind::Import { import, .. } = binding.kind else { unreachable!() }; + fn private_vis_import(&self, decl: Decl<'_>) -> Visibility { + let DeclKind::Import { import, .. } = decl.kind else { unreachable!() }; Visibility::Restricted( import .id() @@ -94,14 +94,14 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { // `EffectiveVisibilitiesVisitor` pass, because we have more detailed binding-based // information, but are used by later passes. Effective visibility of an import def id // is the maximum value among visibilities of bindings corresponding to that def id. - for (binding, eff_vis) in visitor.import_effective_visibilities.iter() { - let DeclKind::Import { import, .. } = binding.kind else { unreachable!() }; - if !binding.is_ambiguity_recursive() { + for (decl, eff_vis) in visitor.import_effective_visibilities.iter() { + let DeclKind::Import { import, .. } = decl.kind else { unreachable!() }; + if !decl.is_ambiguity_recursive() { if let Some(node_id) = import.id() { r.effective_visibilities.update_eff_vis(r.local_def_id(node_id), eff_vis, r.tcx) } - } else if binding.ambiguity.is_some() && eff_vis.is_public_at_level(Level::Reexported) { - exported_ambiguities.insert(*binding); + } else if decl.ambiguity.is_some() && eff_vis.is_public_at_level(Level::Reexported) { + exported_ambiguities.insert(*decl); } } @@ -188,15 +188,15 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { } } - fn update_import(&mut self, binding: Decl<'ra>, parent_id: ParentId<'ra>) { - let nominal_vis = binding.vis.expect_local(); + fn update_import(&mut self, decl: Decl<'ra>, parent_id: ParentId<'ra>) { + let nominal_vis = decl.vis.expect_local(); let Some(cheap_private_vis) = self.may_update(nominal_vis, parent_id) else { return }; let inherited_eff_vis = self.effective_vis_or_private(parent_id); let tcx = self.r.tcx; self.changed |= self.import_effective_visibilities.update( - binding, + decl, Some(nominal_vis), - || cheap_private_vis.unwrap_or_else(|| self.r.private_vis_import(binding)), + || cheap_private_vis.unwrap_or_else(|| self.r.private_vis_import(decl)), inherited_eff_vis, parent_id.level(), tcx, diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 7438403a4745..a5d9c1bae74f 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -543,7 +543,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) { Ok((Some(ext), _)) => { if ext.helper_attrs.contains(&ident.name) { - let binding = self.arenas.new_pub_res_binding( + let binding = self.arenas.new_pub_def_decl( Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat), derive.span, LocalExpnId::ROOT, @@ -559,8 +559,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { result } Scope::MacroRules(macro_rules_scope) => match macro_rules_scope.get() { - MacroRulesScope::Def(macro_rules_binding) if ident == macro_rules_binding.ident => { - Ok(macro_rules_binding.binding) + MacroRulesScope::Def(macro_rules_def) if ident == macro_rules_def.ident => { + Ok(macro_rules_def.decl) } MacroRulesScope::Invocation(_) => Err(Determinacy::Undetermined), _ => Err(Determinacy::Determined), @@ -671,7 +671,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.graph_root.unexpanded_invocations.borrow().is_empty(), )), }, - Scope::BuiltinAttrs => match self.builtin_attrs_bindings.get(&ident.name) { + Scope::BuiltinAttrs => match self.builtin_attr_decls.get(&ident.name) { Some(binding) => Ok(*binding), None => Err(Determinacy::Determined), }, @@ -689,7 +689,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None => Err(Determinacy::Determined), } } - Scope::ToolPrelude => match self.registered_tool_bindings.get(&ident) { + Scope::ToolPrelude => match self.registered_tool_decls.get(&ident) { Some(binding) => Ok(*binding), None => Err(Determinacy::Determined), }, @@ -713,7 +713,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { result } - Scope::BuiltinTypes => match self.builtin_types_bindings.get(&ident.name) { + Scope::BuiltinTypes => match self.builtin_type_decls.get(&ident.name) { Some(binding) => { if matches!(ident.name, sym::f16) && !self.tcx.features().f16() @@ -959,7 +959,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if ns == TypeNS { if ident.name == kw::Crate || ident.name == kw::DollarCrate { let module = self.resolve_crate_root(ident); - return Ok(module.self_binding.unwrap()); + return Ok(module.self_decl.unwrap()); } else if ident.name == kw::Super || ident.name == kw::SelfLower { // FIXME: Implement these with renaming requirements so that e.g. // `use super;` doesn't work, but `use super as name;` does. @@ -1287,9 +1287,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { unreachable!(); }; if source != target { - if bindings.iter().all(|binding| binding.get().binding().is_none()) { + if bindings.iter().all(|binding| binding.get().decl().is_none()) { return true; - } else if bindings[ns].get().binding().is_none() && binding.is_some() { + } else if bindings[ns].get().decl().is_none() && binding.is_some() { return true; } } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 7648b980ec5c..4f8877401638 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -39,19 +39,20 @@ use crate::{ type Res = def::Res; -/// A [`Decl`] in the process of being resolved. +/// A potential import declaration in the process of being planted into a module. +/// Also used for lazily planting names from `--extern` flags to extern prelude. #[derive(Clone, Copy, Default, PartialEq)] -pub(crate) enum PendingBinding<'ra> { +pub(crate) enum PendingDecl<'ra> { Ready(Option>), #[default] Pending, } -impl<'ra> PendingBinding<'ra> { - pub(crate) fn binding(self) -> Option> { +impl<'ra> PendingDecl<'ra> { + pub(crate) fn decl(self) -> Option> { match self { - PendingBinding::Ready(binding) => binding, - PendingBinding::Pending => None, + PendingDecl::Ready(decl) => decl, + PendingDecl::Pending => None, } } } @@ -66,7 +67,7 @@ pub(crate) enum ImportKind<'ra> { /// It will directly use `source` when the format is `use prefix::source`. target: Ident, /// Bindings introduced by the import. - bindings: PerNS>>, + bindings: PerNS>>, /// `true` for `...::{self [as target]}` imports, `false` otherwise. type_ns_only: bool, /// Did this import result from a nested import? ie. `use foo::{bar, baz};` @@ -116,7 +117,7 @@ impl<'ra> std::fmt::Debug for ImportKind<'ra> { // Ignore the nested bindings to avoid an infinite loop while printing. .field( "bindings", - &bindings.clone().map(|b| b.into_inner().binding().map(|_| format_args!(".."))), + &bindings.clone().map(|b| b.into_inner().decl().map(|_| format_args!(".."))), ) .field("type_ns_only", type_ns_only) .field("nested", nested) @@ -282,10 +283,10 @@ struct UnresolvedImportError { // Reexports of the form `pub use foo as bar;` where `foo` is `extern crate foo;` // are permitted for backward-compatibility under a deprecation lint. -fn pub_use_of_private_extern_crate_hack(import: Import<'_>, binding: Decl<'_>) -> Option { - match (&import.kind, &binding.kind) { - (ImportKind::Single { .. }, DeclKind::Import { import: binding_import, .. }) - if let ImportKind::ExternCrate { id, .. } = binding_import.kind +fn pub_use_of_private_extern_crate_hack(import: Import<'_>, decl: Decl<'_>) -> Option { + match (&import.kind, &decl.kind) { + (ImportKind::Single { .. }, DeclKind::Import { import: decl_import, .. }) + if let ImportKind::ExternCrate { id, .. } = decl_import.kind && import.vis.is_public() => { Some(id) @@ -314,7 +315,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { max_vis.set_unchecked(Some(vis.expect_local())) } - self.arenas.alloc_name_binding(DeclData { + self.arenas.alloc_decl(DeclData { kind: DeclKind::Import { binding, import }, ambiguity: None, warn_ambiguity: false, @@ -335,7 +336,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) -> Result<(), Decl<'ra>> { let res = binding.res(); self.check_reserved_macro_name(ident, res); - self.set_binding_parent_module(binding, module); + self.set_decl_parent_module(binding, module); // Even if underscore names cannot be looked up, we still need to add them to modules, // because they can be fetched by glob imports from those modules, and bring traits // into scope both directly and through glob imports. @@ -364,7 +365,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // they have the same resolution or not. resolution.glob_binding = Some(glob_binding); } else if res != old_glob_binding.res() { - resolution.glob_binding = Some(this.new_ambiguity_binding( + resolution.glob_binding = Some(this.new_decl_with_ambiguity( old_glob_binding, glob_binding, warn_ambiguity, @@ -374,7 +375,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { resolution.glob_binding = Some(glob_binding); } else if binding.is_ambiguity_recursive() { resolution.glob_binding = - Some(this.new_warn_ambiguity_binding(glob_binding)); + Some(this.new_decl_with_warn_ambiguity(glob_binding)); } } (old_glob @ true, false) | (old_glob @ false, true) => { @@ -384,7 +385,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if let Some(old_glob_binding) = resolution.glob_binding { assert!(old_glob_binding.is_glob_import()); if glob_binding.res() != old_glob_binding.res() { - resolution.glob_binding = Some(this.new_ambiguity_binding( + resolution.glob_binding = Some(this.new_decl_with_ambiguity( old_glob_binding, glob_binding, false, @@ -412,20 +413,20 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }) } - fn new_ambiguity_binding( + fn new_decl_with_ambiguity( &self, - primary_binding: Decl<'ra>, - secondary_binding: Decl<'ra>, + primary_decl: Decl<'ra>, + secondary_decl: Decl<'ra>, warn_ambiguity: bool, ) -> Decl<'ra> { - let ambiguity = Some(secondary_binding); - let data = DeclData { ambiguity, warn_ambiguity, ..*primary_binding }; - self.arenas.alloc_name_binding(data) + let ambiguity = Some(secondary_decl); + let data = DeclData { ambiguity, warn_ambiguity, ..*primary_decl }; + self.arenas.alloc_decl(data) } - fn new_warn_ambiguity_binding(&self, binding: Decl<'ra>) -> Decl<'ra> { - assert!(binding.is_ambiguity_recursive()); - self.arenas.alloc_name_binding(DeclData { warn_ambiguity: true, ..*binding }) + fn new_decl_with_warn_ambiguity(&self, decl: Decl<'ra>) -> Decl<'ra> { + assert!(decl.is_ambiguity_recursive()); + self.arenas.alloc_decl(DeclData { warn_ambiguity: true, ..*decl }) } // Use `f` to mutate the resolution of the name in the module. @@ -488,16 +489,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // or indeterminate resolution, also mark such failed imports as used to avoid duplicate diagnostics. fn import_dummy_binding(&mut self, import: Import<'ra>, is_indeterminate: bool) { if let ImportKind::Single { target, ref bindings, .. } = import.kind { - if !(is_indeterminate - || bindings.iter().all(|binding| binding.get().binding().is_none())) + if !(is_indeterminate || bindings.iter().all(|binding| binding.get().decl().is_none())) { return; // Has resolution, do not create the dummy binding } - let dummy_binding = self.dummy_binding; - let dummy_binding = self.import(dummy_binding, import); + let dummy_decl = self.dummy_decl; + let dummy_decl = self.import(dummy_decl, import); self.per_ns(|this, ns| { let module = import.parent_scope.module; - let _ = this.try_define_local(module, target, ns, dummy_binding, false); + let _ = this.try_define_local(module, target, ns, dummy_decl, false); // Don't remove underscores from `single_imports`, they were never added. if target.name != kw::Underscore { let key = BindingKey::new(target, ns); @@ -506,7 +506,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }) } }); - self.record_use(target, dummy_binding, Used::Other); + self.record_use(target, dummy_decl, Used::Other); } else if import.imported_module.get().is_none() { self.import_use_map.insert(import, Used::Other); if let Some(id) = import.id() { @@ -577,7 +577,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if let ImportKind::Single { source, ref bindings, .. } = import.kind && source.name == kw::SelfLower // Silence `unresolved import` error if E0429 is already emitted - && let PendingBinding::Ready(None) = bindings.value_ns.get() + && let PendingDecl::Ready(None) = bindings.value_ns.get() { continue; } @@ -851,7 +851,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut indeterminate_count = 0; self.per_ns_cm(|this, ns| { if !type_ns_only || ns == TypeNS { - if bindings[ns].get() != PendingBinding::Pending { + if bindings[ns].get() != PendingDecl::Pending { return; }; let binding_result = this.reborrow().maybe_resolve_ident_in_module( @@ -883,7 +883,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns, imported_binding, ); - PendingBinding::Ready(Some(imported_binding)) + PendingDecl::Ready(Some(imported_binding)) } Err(Determinacy::Determined) => { // Don't remove underscores from `single_imports`, they were never added. @@ -898,11 +898,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }, ); } - PendingBinding::Ready(None) + PendingDecl::Ready(None) } Err(Determinacy::Undetermined) => { indeterminate_count += 1; - PendingBinding::Pending + PendingDecl::Pending } }; bindings[ns].set_unchecked(binding); @@ -918,7 +918,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// consolidate multiple unresolved import errors into a single diagnostic. fn finalize_import(&mut self, import: Import<'ra>) -> Option { let ignore_binding = match &import.kind { - ImportKind::Single { bindings, .. } => bindings[TypeNS].get().binding(), + ImportKind::Single { bindings, .. } => bindings[TypeNS].get().decl(), _ => None, }; let ambiguity_errors_len = @@ -1113,14 +1113,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns, &import.parent_scope, Some(Finalize { report_private: false, ..finalize }), - bindings[ns].get().binding(), + bindings[ns].get().decl(), Some(import), ); match binding { Ok(binding) => { // Consistency checks, analogous to `finalize_macro_resolutions`. - let initial_res = bindings[ns].get().binding().map(|binding| { + let initial_res = bindings[ns].get().decl().map(|binding| { let initial_binding = binding.import_source(); all_ns_err = false; if target.name == kw::Underscore @@ -1287,7 +1287,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut any_successful_reexport = false; let mut crate_private_reexport = false; self.per_ns(|this, ns| { - let Some(binding) = bindings[ns].get().binding().map(|b| b.import_source()) else { + let Some(binding) = bindings[ns].get().decl().map(|b| b.import_source()) else { return; }; @@ -1362,7 +1362,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut full_path = import.module_path.clone(); full_path.push(Segment::from_ident(ident)); self.per_ns(|this, ns| { - if let Some(binding) = bindings[ns].get().binding().map(|b| b.import_source()) { + if let Some(binding) = bindings[ns].get().decl().map(|b| b.import_source()) { this.lint_if_path_starts_with_module(finalize, &full_path, Some(binding)); } }); @@ -1372,7 +1372,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // this may resolve to either a value or a type, but for documentation // purposes it's good enough to just favor one over the other. self.per_ns(|this, ns| { - if let Some(binding) = bindings[ns].get().binding().map(|b| b.import_source()) { + if let Some(binding) = bindings[ns].get().decl().map(|b| b.import_source()) { this.import_res_map.entry(import_id).or_default()[ns] = Some(binding.res()); } }); @@ -1410,7 +1410,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut is_redundant = true; let mut redundant_span = PerNS { value_ns: None, type_ns: None, macro_ns: None }; self.per_ns(|this, ns| { - let binding = bindings[ns].get().binding().map(|b| b.import_source()); + let binding = bindings[ns].get().decl().map(|b| b.import_source()); if is_redundant && let Some(binding) = binding { if binding.res() == Res::Err { return; @@ -1422,7 +1422,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { &import.parent_scope, None, false, - bindings[ns].get().binding(), + bindings[ns].get().decl(), None, ) { Ok(other_binding) => { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index ea13125f5417..67449050aea9 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -33,7 +33,7 @@ use std::sync::Arc; use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion}; use effective_visibilities::EffectiveVisibilitiesVisitor; use errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst}; -use imports::{Import, ImportData, ImportKind, NameResolution, PendingBinding}; +use imports::{Import, ImportData, ImportKind, NameResolution, PendingDecl}; use late::{ ForwardGenericParamBanReason, HasGenericParams, PathSource, PatternSource, UnnecessaryQualification, @@ -630,9 +630,9 @@ struct ModuleData<'ra> { expansion: ExpnId, - /// Binding for implicitly declared names that come with a module, + /// Declaration for implicitly declared names that come with a module, /// like `self` (not yet used), or `crate`/`$crate` (for root modules). - self_binding: Option>, + self_decl: Option>, } /// All modules are unique and allocated on a same arena, @@ -661,7 +661,7 @@ impl<'ra> ModuleData<'ra> { expansion: ExpnId, span: Span, no_implicit_prelude: bool, - self_binding: Option>, + self_decl: Option>, ) -> Self { let is_foreign = match kind { ModuleKind::Def(_, def_id, _) => !def_id.is_local(), @@ -680,7 +680,7 @@ impl<'ra> ModuleData<'ra> { traits: CmRefCell::new(None), span, expansion, - self_binding, + self_decl, } } } @@ -1025,12 +1025,12 @@ impl<'ra> DeclData<'ra> { // in some later round and screw up our previously found resolution. // See more detailed explanation in // https://github.com/rust-lang/rust/pull/53778#issuecomment-419224049 - fn may_appear_after(&self, invoc_parent_expansion: LocalExpnId, binding: Decl<'_>) -> bool { - // self > max(invoc, binding) => !(self <= invoc || self <= binding) + fn may_appear_after(&self, invoc_parent_expansion: LocalExpnId, decl: Decl<'_>) -> bool { + // self > max(invoc, decl) => !(self <= invoc || self <= decl) // Expansions are partially ordered, so "may appear after" is an inversion of // "certainly appears before or simultaneously" and includes unordered cases. let self_parent_expansion = self.expansion; - let other_parent_expansion = binding.expansion; + let other_parent_expansion = decl.expansion; let certainly_before_other_or_simultaneously = other_parent_expansion.is_descendant_of(self_parent_expansion); let certainly_before_invoc_or_simultaneously = @@ -1053,23 +1053,23 @@ impl<'ra> DeclData<'ra> { } struct ExternPreludeEntry<'ra> { - /// Binding from an `extern crate` item. - /// The boolean flag is true is `item_binding` is non-redundant, happens either when - /// `flag_binding` is `None`, or when `extern crate` introducing `item_binding` used renaming. - item_binding: Option<(Decl<'ra>, /* introduced by item */ bool)>, - /// Binding from an `--extern` flag, lazily populated on first use. - flag_binding: Option, /* finalized */ bool)>>, + /// Name declaration from an `extern crate` item. + /// The boolean flag is true is `item_decl` is non-redundant, happens either when + /// `flag_decl` is `None`, or when `extern crate` introducing `item_decl` used renaming. + item_decl: Option<(Decl<'ra>, /* introduced by item */ bool)>, + /// Name declaration from an `--extern` flag, lazily populated on first use. + flag_decl: Option, /* finalized */ bool)>>, } impl ExternPreludeEntry<'_> { fn introduced_by_item(&self) -> bool { - matches!(self.item_binding, Some((_, true))) + matches!(self.item_decl, Some((_, true))) } fn flag() -> Self { ExternPreludeEntry { - item_binding: None, - flag_binding: Some(CacheCell::new((PendingBinding::Pending, false))), + item_decl: None, + flag_decl: Some(CacheCell::new((PendingDecl::Pending, false))), } } } @@ -1176,7 +1176,7 @@ pub struct Resolver<'ra, 'tcx> { local_module_map: FxIndexMap>, /// Lazily populated cache of modules loaded from external crates. extern_module_map: CacheRefCell>>, - binding_parent_modules: FxHashMap, Module<'ra>>, + decl_parent_modules: FxHashMap, Module<'ra>>, /// Maps glob imports to the names of items actually imported. glob_map: FxIndexMap>, @@ -1201,10 +1201,10 @@ pub struct Resolver<'ra, 'tcx> { inaccessible_ctor_reexport: FxHashMap, arenas: &'ra ResolverArenas<'ra>, - dummy_binding: Decl<'ra>, - builtin_types_bindings: FxHashMap>, - builtin_attrs_bindings: FxHashMap>, - registered_tool_bindings: FxHashMap>, + dummy_decl: Decl<'ra>, + builtin_type_decls: FxHashMap>, + builtin_attr_decls: FxHashMap>, + registered_tool_decls: FxHashMap>, macro_names: FxHashSet, builtin_macros: FxHashMap, registered_tools: &'tcx RegisteredTools, @@ -1333,14 +1333,14 @@ pub struct ResolverArenas<'ra> { } impl<'ra> ResolverArenas<'ra> { - fn new_res_binding( + fn new_def_decl( &'ra self, res: Res, vis: Visibility, span: Span, expansion: LocalExpnId, ) -> Decl<'ra> { - self.alloc_name_binding(DeclData { + self.alloc_decl(DeclData { kind: DeclKind::Def(res), ambiguity: None, warn_ambiguity: false, @@ -1350,8 +1350,8 @@ impl<'ra> ResolverArenas<'ra> { }) } - fn new_pub_res_binding(&'ra self, res: Res, span: Span, expn_id: LocalExpnId) -> Decl<'ra> { - self.new_res_binding(res, Visibility::Public, span, expn_id) + fn new_pub_def_decl(&'ra self, res: Res, span: Span, expn_id: LocalExpnId) -> Decl<'ra> { + self.new_def_decl(res, Visibility::Public, span, expn_id) } fn new_module( @@ -1362,9 +1362,9 @@ impl<'ra> ResolverArenas<'ra> { span: Span, no_implicit_prelude: bool, ) -> Module<'ra> { - let self_binding = match kind { + let self_decl = match kind { ModuleKind::Def(def_kind, def_id, _) => { - Some(self.new_pub_res_binding(Res::Def(def_kind, def_id), span, LocalExpnId::ROOT)) + Some(self.new_pub_def_decl(Res::Def(def_kind, def_id), span, LocalExpnId::ROOT)) } ModuleKind::Block => None, }; @@ -1374,11 +1374,11 @@ impl<'ra> ResolverArenas<'ra> { expn_id, span, no_implicit_prelude, - self_binding, + self_decl, )))) } - fn alloc_name_binding(&'ra self, name_binding: DeclData<'ra>) -> Decl<'ra> { - Interned::new_unchecked(self.dropless.alloc(name_binding)) + fn alloc_decl(&'ra self, data: DeclData<'ra>) -> Decl<'ra> { + Interned::new_unchecked(self.dropless.alloc(data)) } fn alloc_import(&'ra self, import: ImportData<'ra>) -> Import<'ra> { Interned::new_unchecked(self.imports.alloc(import)) @@ -1389,11 +1389,8 @@ impl<'ra> ResolverArenas<'ra> { fn alloc_macro_rules_scope(&'ra self, scope: MacroRulesScope<'ra>) -> MacroRulesScopeRef<'ra> { self.dropless.alloc(CacheCell::new(scope)) } - fn alloc_macro_rules_binding( - &'ra self, - binding: MacroRulesDecl<'ra>, - ) -> &'ra MacroRulesDecl<'ra> { - self.dropless.alloc(binding) + fn alloc_macro_rules_decl(&'ra self, decl: MacroRulesDecl<'ra>) -> &'ra MacroRulesDecl<'ra> { + self.dropless.alloc(decl) } fn alloc_ast_paths(&'ra self, paths: &[ast::Path]) -> &'ra [ast::Path] { self.ast_paths.alloc_from_iter(paths.iter().cloned()) @@ -1609,7 +1606,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { local_module_map, extern_module_map: Default::default(), block_map: Default::default(), - binding_parent_modules: FxHashMap::default(), + decl_parent_modules: FxHashMap::default(), ast_transform_scopes: FxHashMap::default(), glob_map: Default::default(), @@ -1618,29 +1615,29 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { inaccessible_ctor_reexport: Default::default(), arenas, - dummy_binding: arenas.new_pub_res_binding(Res::Err, DUMMY_SP, LocalExpnId::ROOT), - builtin_types_bindings: PrimTy::ALL + dummy_decl: arenas.new_pub_def_decl(Res::Err, DUMMY_SP, LocalExpnId::ROOT), + builtin_type_decls: PrimTy::ALL .iter() .map(|prim_ty| { let res = Res::PrimTy(*prim_ty); - let binding = arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT); - (prim_ty.name(), binding) + let decl = arenas.new_pub_def_decl(res, DUMMY_SP, LocalExpnId::ROOT); + (prim_ty.name(), decl) }) .collect(), - builtin_attrs_bindings: BUILTIN_ATTRIBUTES + builtin_attr_decls: BUILTIN_ATTRIBUTES .iter() .map(|builtin_attr| { let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin(builtin_attr.name)); - let binding = arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT); - (builtin_attr.name, binding) + let decl = arenas.new_pub_def_decl(res, DUMMY_SP, LocalExpnId::ROOT); + (builtin_attr.name, decl) }) .collect(), - registered_tool_bindings: registered_tools + registered_tool_decls: registered_tools .iter() .map(|ident| { let res = Res::ToolMod; - let binding = arenas.new_pub_res_binding(res, ident.span, LocalExpnId::ROOT); - (*ident, binding) + let decl = arenas.new_pub_def_decl(res, ident.span, LocalExpnId::ROOT); + (*ident, decl) }) .collect(), macro_names: FxHashSet::default(), @@ -2043,8 +2040,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { false } - fn record_use(&mut self, ident: Ident, used_binding: Decl<'ra>, used: Used) { - self.record_use_inner(ident, used_binding, used, used_binding.warn_ambiguity); + fn record_use(&mut self, ident: Ident, used_decl: Decl<'ra>, used: Used) { + self.record_use_inner(ident, used_decl, used, used_decl.warn_ambiguity); } fn record_use_inner( @@ -2099,7 +2096,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // but not introduce it, as used if they are accessed from lexical scope. if used == Used::Scope && let Some(entry) = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)) - && entry.item_binding == Some((used_binding, false)) + && entry.item_decl == Some((used_binding, false)) { return; } @@ -2226,10 +2223,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { vis.is_accessible_from(module.nearest_parent_mod(), self.tcx) } - fn set_binding_parent_module(&mut self, binding: Decl<'ra>, module: Module<'ra>) { - if let Some(old_module) = self.binding_parent_modules.insert(binding, module) { + fn set_decl_parent_module(&mut self, decl: Decl<'ra>, module: Module<'ra>) { + if let Some(old_module) = self.decl_parent_modules.insert(decl, module) { if module != old_module { - span_bug!(binding.span, "parent module is reset for binding"); + span_bug!(decl.span, "parent module is reset for a name declaration"); } } } @@ -2246,8 +2243,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // panic on index should be impossible, the only name_bindings passed in should be from // `resolve_ident_in_scope_set` which will always refer to a local binding from an // import or macro definition - let macro_rules = &self.binding_parent_modules[¯o_rules]; - let modularized = &self.binding_parent_modules[&modularized]; + let macro_rules = &self.decl_parent_modules[¯o_rules]; + let modularized = &self.decl_parent_modules[&modularized]; macro_rules.nearest_parent_mod() == modularized.nearest_parent_mod() && modularized.is_ancestor_of(*macro_rules) } @@ -2258,7 +2255,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { finalize: bool, ) -> Option> { let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)); - entry.and_then(|entry| entry.item_binding).map(|(binding, _)| { + entry.and_then(|entry| entry.item_decl).map(|(binding, _)| { if finalize { self.get_mut().record_use(ident, binding, Used::Scope); } @@ -2268,16 +2265,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn extern_prelude_get_flag(&self, ident: Ident, finalize: bool) -> Option> { let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)); - entry.and_then(|entry| entry.flag_binding.as_ref()).and_then(|flag_binding| { - let (pending_binding, finalized) = flag_binding.get(); - let binding = match pending_binding { - PendingBinding::Ready(binding) => { + entry.and_then(|entry| entry.flag_decl.as_ref()).and_then(|flag_decl| { + let (pending_decl, finalized) = flag_decl.get(); + let decl = match pending_decl { + PendingDecl::Ready(decl) => { if finalize && !finalized { self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span); } - binding + decl } - PendingBinding::Pending => { + PendingDecl::Pending => { debug_assert!(!finalized); let crate_id = if finalize { self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span) @@ -2286,12 +2283,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; crate_id.map(|crate_id| { let res = Res::Def(DefKind::Mod, crate_id.as_def_id()); - self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT) + self.arenas.new_pub_def_decl(res, DUMMY_SP, LocalExpnId::ROOT) }) } }; - flag_binding.set((PendingBinding::Ready(binding), finalize || finalized)); - binding.or_else(|| finalize.then_some(self.dummy_binding)) + flag_decl.set((PendingDecl::Ready(decl), finalize || finalized)); + decl.or_else(|| finalize.then_some(self.dummy_decl)) }) } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index e07bb46ac568..898d198c5475 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -49,7 +49,7 @@ type Res = def::Res; /// Not modularized, can shadow previous `macro_rules` bindings, etc. #[derive(Debug)] pub(crate) struct MacroRulesDecl<'ra> { - pub(crate) binding: Decl<'ra>, + pub(crate) decl: Decl<'ra>, /// `macro_rules` scope into which the `macro_rules` item was planted. pub(crate) parent_macro_rules_scope: MacroRulesScopeRef<'ra>, pub(crate) ident: Ident, @@ -431,8 +431,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { .iter() .map(|(_, ident)| { let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper); - let binding = self.arenas.new_pub_res_binding(res, ident.span, expn_id); - (*ident, binding) + (*ident, self.arenas.new_pub_def_decl(res, ident.span, expn_id)) }) .collect(); self.helper_attrs.insert(expn_id, helper_attrs); @@ -1062,18 +1061,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn prohibit_imported_non_macro_attrs( &self, - binding: Option>, + decl: Option>, res: Option, span: Span, ) { if let Some(Res::NonMacroAttr(kind)) = res { - if kind != NonMacroAttrKind::Tool && binding.is_none_or(|b| b.is_import()) { - let binding_span = binding.map(|binding| binding.span); + if kind != NonMacroAttrKind::Tool && decl.is_none_or(|b| b.is_import()) { self.dcx().emit_err(errors::CannotUseThroughAnImport { span, article: kind.article(), descr: kind.descr(), - binding_span, + binding_span: decl.map(|d| d.span), }); } } @@ -1084,12 +1082,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { path: &ast::Path, parent_scope: &ParentScope<'ra>, invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>, - binding: Option>, + decl: Option>, ) { if let Some((mod_def_id, node_id)) = invoc_in_mod_inert_attr - && let Some(binding) = binding + && let Some(decl) = decl // This is a `macro_rules` itself, not some import. - && let DeclKind::Def(res) = binding.kind + && let DeclKind::Def(res) = decl.kind && let Res::Def(DefKind::Macro(kinds), def_id) = res && kinds.contains(MacroKinds::BANG) // And the `macro_rules` is defined inside the attribute's module, From a0ea3b0635064a9191e5df6e36ecb75cd5168df8 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 30 Dec 2025 22:27:43 +0300 Subject: [PATCH 0300/1061] Update more function names and fields from bindings to declarations --- .../rustc_resolve/src/build_reduced_graph.rs | 50 +++-- compiler/rustc_resolve/src/check_unused.rs | 8 +- compiler/rustc_resolve/src/diagnostics.rs | 38 ++-- .../src/effective_visibilities.rs | 33 ++- compiler/rustc_resolve/src/ident.rs | 165 +++++++-------- compiler/rustc_resolve/src/imports.rs | 200 +++++++++--------- compiler/rustc_resolve/src/late.rs | 28 +-- .../rustc_resolve/src/late/diagnostics.rs | 34 ++- compiler/rustc_resolve/src/lib.rs | 22 +- compiler/rustc_resolve/src/macros.rs | 2 +- 10 files changed, 284 insertions(+), 296 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 7569fc3d716b..d56ca7c079cb 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -44,20 +44,22 @@ use crate::{ type Res = def::Res; impl<'ra, 'tcx> Resolver<'ra, 'tcx> { - /// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined; - /// otherwise, reports an error. - pub(crate) fn define_binding_local( + /// Attempt to put the declaration with the given name and namespace into the module, + /// and report an error in case of a collision. + pub(crate) fn plant_decl_into_local_module( &mut self, parent: Module<'ra>, ident: Ident, ns: Namespace, decl: Decl<'ra>, ) { - if let Err(old_binding) = self.try_define_local(parent, ident, ns, decl, false) { - self.report_conflict(parent, ident, ns, old_binding, decl); + if let Err(old_decl) = self.try_plant_decl_into_local_module(parent, ident, ns, decl, false) + { + self.report_conflict(parent, ident, ns, old_decl, decl); } } + /// Create a name definitinon from the given components, and put it into the local module. fn define_local( &mut self, parent: Module<'ra>, @@ -68,10 +70,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { span: Span, expn_id: LocalExpnId, ) { - let binding = self.arenas.new_def_decl(res, vis.to_def_id(), span, expn_id); - self.define_binding_local(parent, ident, ns, binding); + let decl = self.arenas.new_def_decl(res, vis.to_def_id(), span, expn_id); + self.plant_decl_into_local_module(parent, ident, ns, decl); } + /// Create a name definitinon from the given components, and put it into the extern module. fn define_extern( &self, parent: Module<'ra>, @@ -84,7 +87,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { expansion: LocalExpnId, ambiguity: Option>, ) { - let binding = self.arenas.alloc_decl(DeclData { + let decl = self.arenas.alloc_decl(DeclData { kind: DeclKind::Def(res), ambiguity, // External ambiguities always report the `AMBIGUOUS_GLOB_IMPORTS` lint at the moment. @@ -101,8 +104,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if self .resolution_or_default(parent, key) .borrow_mut_unchecked() - .non_glob_binding - .replace(binding) + .non_glob_decl + .replace(decl) .is_some() { span_bug!(span, "an external binding was already defined"); @@ -691,7 +694,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let kind = ImportKind::Single { source: source.ident, target: ident, - bindings: Default::default(), + decls: Default::default(), type_ns_only, nested, id, @@ -1019,7 +1022,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.import_use_map.insert(import, Used::Other); } self.r.potentially_unused_imports.push(import); - let imported_binding = self.r.import(decl, import); + let import_decl = self.r.new_import_decl(decl, import); if ident.name != kw::Underscore && parent == self.r.graph_root { let norm_ident = Macros20NormalizedIdent::new(ident); // FIXME: this error is technically unnecessary now when extern prelude is split into @@ -1042,17 +1045,17 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let msg = format!("extern crate `{ident}` already in extern prelude"); self.r.tcx.dcx().span_delayed_bug(item.span, msg); } else { - entry.item_decl = Some((imported_binding, orig_name.is_some())); + entry.item_decl = Some((import_decl, orig_name.is_some())); } entry } Entry::Vacant(vacant) => vacant.insert(ExternPreludeEntry { - item_decl: Some((imported_binding, true)), + item_decl: Some((import_decl, true)), flag_decl: None, }), }; } - self.r.define_binding_local(parent, ident, TypeNS, imported_binding); + self.r.plant_decl_into_local_module(parent, ident, TypeNS, import_decl); } /// Constructs the reduced graph for one foreign item. @@ -1167,8 +1170,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } macro_use_import(this, span, true) }; - let import_binding = this.r.import(binding, import); - this.add_macro_use_decl(ident.name, import_binding, span, allow_shadowing); + let import_decl = this.r.new_import_decl(binding, import); + this.add_macro_use_decl(ident.name, import_decl, span, allow_shadowing); } }); } else { @@ -1183,13 +1186,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { if let Ok(binding) = result { let import = macro_use_import(self, ident.span, false); self.r.potentially_unused_imports.push(import); - let imported_binding = self.r.import(binding, import); - self.add_macro_use_decl( - ident.name, - imported_binding, - ident.span, - allow_shadowing, - ); + let import_decl = self.r.new_import_decl(binding, import); + self.add_macro_use_decl(ident.name, import_decl, ident.span, allow_shadowing); } else { self.r.dcx().emit_err(errors::ImportedMacroNotFound { span: ident.span }); } @@ -1319,8 +1317,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { vis_span: item.vis.span, }); self.r.import_use_map.insert(import, Used::Other); - let import_binding = self.r.import(decl, import); - self.r.define_binding_local(self.r.graph_root, ident, MacroNS, import_binding); + let import_decl = self.r.new_import_decl(decl, import); + self.r.plant_decl_into_local_module(self.r.graph_root, ident, MacroNS, import_decl); } else { self.r.check_reserved_macro_name(ident, res); self.insert_unused_macro(ident, def_id, item.id); diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index a2e903ce48eb..3724fcfce40f 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -514,8 +514,8 @@ impl Resolver<'_, '_> { let mut check_redundant_imports = FxIndexSet::default(); for module in &self.local_modules { for (_key, resolution) in self.resolutions(*module).borrow().iter() { - if let Some(binding) = resolution.borrow().best_binding() - && let DeclKind::Import { import, .. } = binding.kind + if let Some(decl) = resolution.borrow().best_decl() + && let DeclKind::Import { import, .. } = decl.kind && let ImportKind::Single { id, .. } = import.kind { if let Some(unused_import) = unused_imports.get(&import.root_id) @@ -542,8 +542,8 @@ impl Resolver<'_, '_> { // Deleting both unused imports and unnecessary segments of an item may result // in the item not being found. for unn_qua in &self.potentially_unnecessary_qualifications { - if let LateDecl::Decl(name_binding) = unn_qua.binding - && let DeclKind::Import { import, .. } = name_binding.kind + if let LateDecl::Decl(decl) = unn_qua.decl + && let DeclKind::Import { import, .. } = decl.kind && (is_unused_import(import, &unused_imports) || is_redundant_import(import, &redundant_imports)) { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index b77481d1b3ad..7ed29b91b67a 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1195,13 +1195,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Never recommend deprecated helper attributes. } Scope::MacroRules(macro_rules_scope) => { - if let MacroRulesScope::Def(macro_rules_binding) = macro_rules_scope.get() { - let res = macro_rules_binding.decl.res(); + if let MacroRulesScope::Def(macro_rules_def) = macro_rules_scope.get() { + let res = macro_rules_def.decl.res(); if filter_fn(res) { - suggestions.push(TypoSuggestion::typo_from_ident( - macro_rules_binding.ident, - res, - )) + suggestions + .push(TypoSuggestion::typo_from_ident(macro_rules_def.ident, res)) } } } @@ -1581,9 +1579,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { |(key, name_resolution)| { if key.ns == TypeNS && key.ident == ident - && let Some(binding) = name_resolution.borrow().best_binding() + && let Some(decl) = name_resolution.borrow().best_decl() { - match binding.res() { + match decl.res() { // No disambiguation needed if the identically named item we // found in scope actually refers to the crate in question. Res::Def(_, def_id) => def_id != crate_def_id, @@ -2087,7 +2085,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) { let PrivacyError { ident, - binding, + decl, outermost_res, parent_scope, single_nested, @@ -2095,8 +2093,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ref source, } = *privacy_error; - let res = binding.res(); - let ctor_fields_span = self.ctor_fields_span(binding); + let res = decl.res(); + let ctor_fields_span = self.ctor_fields_span(decl); let plain_descr = res.descr().to_string(); let nonimport_descr = if ctor_fields_span.is_some() { plain_descr + " constructor" } else { plain_descr }; @@ -2104,7 +2102,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let get_descr = |b: Decl<'_>| if b.is_import() { &import_descr } else { &nonimport_descr }; // Print the primary message. - let ident_descr = get_descr(binding); + let ident_descr = get_descr(decl); let mut err = self.dcx().create_err(errors::IsPrivate { span: ident.span, ident_descr, ident }); @@ -2204,8 +2202,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // Print the whole import chain to make it easier to see what happens. - let first_binding = binding; - let mut next_binding = Some(binding); + let first_binding = decl; + let mut next_binding = Some(decl); let mut next_ident = ident; let mut path = vec![]; while let Some(binding) = next_binding { @@ -2413,7 +2411,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { opt_ns: Option, // `None` indicates a module path in import parent_scope: &ParentScope<'ra>, ribs: Option<&PerNS>>>, - ignore_binding: Option>, + ignore_decl: Option>, ignore_import: Option>, module: Option>, failed_segment_idx: usize, @@ -2509,7 +2507,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns_to_try, parent_scope, None, - ignore_binding, + ignore_decl, ignore_import, ) .ok() @@ -2523,7 +2521,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope, None, &ribs[ns_to_try], - ignore_binding, + ignore_decl, diag_metadata, ) { // we found a locally-imported or available item/module @@ -2538,7 +2536,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope, None, false, - ignore_binding, + ignore_decl, ignore_import, ) .ok() @@ -2574,7 +2572,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope, None, &ribs[ValueNS], - ignore_binding, + ignore_decl, diag_metadata, ) } else { @@ -2642,7 +2640,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope, None, false, - ignore_binding, + ignore_decl, ignore_import, ) { let descr = binding.res().descr(); diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 389bdbbec62b..87be913df535 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -28,9 +28,9 @@ impl ParentId<'_> { pub(crate) struct EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { r: &'a mut Resolver<'ra, 'tcx>, def_effective_visibilities: EffectiveVisibilities, - /// While walking import chains we need to track effective visibilities per-binding, and def id + /// While walking import chains we need to track effective visibilities per-decl, and def id /// keys in `Resolver::effective_visibilities` are not enough for that, because multiple - /// bindings can correspond to a single def id in imports. So we keep a separate table. + /// declarations can correspond to a single def id in imports. So we keep a separate table. import_effective_visibilities: EffectiveVisibilities>, // It's possible to recalculate this at any point, but it's relatively expensive. current_private_vis: Visibility, @@ -91,9 +91,9 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { let mut exported_ambiguities = FxHashSet::default(); // Update visibilities for import def ids. These are not used during the - // `EffectiveVisibilitiesVisitor` pass, because we have more detailed binding-based + // `EffectiveVisibilitiesVisitor` pass, because we have more detailed declaration-based // information, but are used by later passes. Effective visibility of an import def id - // is the maximum value among visibilities of bindings corresponding to that def id. + // is the maximum value among visibilities of declarations corresponding to that def id. for (decl, eff_vis) in visitor.import_effective_visibilities.iter() { let DeclKind::Import { import, .. } = decl.kind else { unreachable!() }; if !decl.is_ambiguity_recursive() { @@ -110,12 +110,12 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { exported_ambiguities } - /// Update effective visibilities of bindings in the given module, + /// Update effective visibilities of name declarations in the given module, /// including their whole reexport chains. fn set_bindings_effective_visibilities(&mut self, module_id: LocalDefId) { let module = self.r.expect_module(module_id.to_def_id()); for (_, name_resolution) in self.r.resolutions(module).borrow().iter() { - let Some(mut binding) = name_resolution.borrow().binding() else { + let Some(mut decl) = name_resolution.borrow().binding() else { continue; }; // Set the given effective visibility level to `Level::Direct` and @@ -125,28 +125,27 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { // If the binding is ambiguous, put the root ambiguity binding and all reexports // leading to it into the table. They are used by the `ambiguous_glob_reexports` // lint. For all bindings added to the table this way `is_ambiguity` returns true. - let is_ambiguity = - |binding: Decl<'ra>, warn: bool| binding.ambiguity.is_some() && !warn; + let is_ambiguity = |decl: Decl<'ra>, warn: bool| decl.ambiguity.is_some() && !warn; let mut parent_id = ParentId::Def(module_id); - let mut warn_ambiguity = binding.warn_ambiguity; - while let DeclKind::Import { binding: nested_binding, .. } = binding.kind { - self.update_import(binding, parent_id); + let mut warn_ambiguity = decl.warn_ambiguity; + while let DeclKind::Import { binding: nested_binding, .. } = decl.kind { + self.update_import(decl, parent_id); - if is_ambiguity(binding, warn_ambiguity) { + if is_ambiguity(decl, warn_ambiguity) { // Stop at the root ambiguity, further bindings in the chain should not // be reexported because the root ambiguity blocks any access to them. // (Those further bindings are most likely not ambiguities themselves.) break; } - parent_id = ParentId::Import(binding); - binding = nested_binding; + parent_id = ParentId::Import(decl); + decl = nested_binding; warn_ambiguity |= nested_binding.warn_ambiguity; } - if !is_ambiguity(binding, warn_ambiguity) - && let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) + if !is_ambiguity(decl, warn_ambiguity) + && let Some(def_id) = decl.res().opt_def_id().and_then(|id| id.as_local()) { - self.update_def(def_id, binding.vis.expect_local(), parent_id); + self.update_def(def_id, decl.vis.expect_local(), parent_id); } } } diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index a5d9c1bae74f..e0acf043ffcf 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -304,7 +304,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, finalize: Option, ribs: &[Rib<'ra>], - ignore_binding: Option>, + ignore_decl: Option>, diag_metadata: Option<&DiagMetadata<'_>>, ) -> Option> { let orig_ident = ident; @@ -345,7 +345,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope, finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }), finalize.is_some(), - ignore_binding, + ignore_decl, None, ) { @@ -363,7 +363,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope, finalize, finalize.is_some(), - ignore_binding, + ignore_decl, None, ) .ok() @@ -391,7 +391,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, finalize: Option, force: bool, - ignore_binding: Option>, + ignore_decl: Option>, ignore_import: Option>, ) -> Result, Determinacy> { assert!(force || finalize.is_none()); // `finalize` implies `force` @@ -442,13 +442,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ctxt, scope_set, parent_scope, - // Shadowed bindings don't need to be marked as used or non-speculatively loaded. + // Shadowed decls don't need to be marked as used or non-speculatively loaded. if innermost_results.is_empty() { finalize } else { None }, force, - ignore_binding, + ignore_decl, ignore_import, ) { - Ok(binding) => Ok(binding), + Ok(decl) => Ok(decl), // We can break with an error at this step, it means we cannot determine the // resolution right now, but we must block and wait until we can, instead of // considering outer scopes. Although there's no need to do that if we already @@ -459,32 +459,32 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Err(determinacy) => Err(determinacy.into_value()), }; match res { - Ok(binding) if sub_namespace_match(binding.macro_kinds(), macro_kind) => { + Ok(decl) if sub_namespace_match(decl.macro_kinds(), macro_kind) => { // Below we report various ambiguity errors. // We do not need to report them if we are either in speculative resolution, // or in late resolution when everything is already imported and expanded // and no ambiguities exist. if matches!(finalize, None | Some(Finalize { stage: Stage::Late, .. })) { - return ControlFlow::Break(Ok(binding)); + return ControlFlow::Break(Ok(decl)); } - if let Some(&(innermost_binding, _)) = innermost_results.first() { + if let Some(&(innermost_decl, _)) = innermost_results.first() { // Found another solution, if the first one was "weak", report an error. if this.get_mut().maybe_push_ambiguity( orig_ident, ns, scope_set, parent_scope, - binding, + decl, scope, &innermost_results, ) { // No need to search for more potential ambiguities, one is enough. - return ControlFlow::Break(Ok(innermost_binding)); + return ControlFlow::Break(Ok(innermost_decl)); } } - innermost_results.push((binding, scope)); + innermost_results.push((decl, scope)); } Ok(_) | Err(Determinacy::Determined) => {} Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined, @@ -501,7 +501,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Scope visiting walked all the scopes and maybe found something in one of them. match innermost_results.first() { - Some(&(binding, ..)) => Ok(binding), + Some(&(decl, ..)) => Ok(decl), None => Err(Determinacy::determined(determinacy == Determinacy::Determined || force)), } } @@ -517,16 +517,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, finalize: Option, force: bool, - ignore_binding: Option>, + ignore_decl: Option>, ignore_import: Option>, ) -> Result, ControlFlow> { let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt)); let ret = match scope { Scope::DeriveHelpers(expn_id) => { - if let Some(binding) = self.helper_attrs.get(&expn_id).and_then(|attrs| { - attrs.iter().rfind(|(i, _)| ident == *i).map(|(_, binding)| *binding) - }) { - Ok(binding) + if let Some(decl) = self + .helper_attrs + .get(&expn_id) + .and_then(|attrs| attrs.iter().rfind(|(i, _)| ident == *i).map(|(_, d)| *d)) + { + Ok(decl) } else { Err(Determinacy::Determined) } @@ -543,12 +545,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) { Ok((Some(ext), _)) => { if ext.helper_attrs.contains(&ident.name) { - let binding = self.arenas.new_pub_def_decl( + let decl = self.arenas.new_pub_def_decl( Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat), derive.span, LocalExpnId::ROOT, ); - result = Ok(binding); + result = Ok(decl); break; } } @@ -577,7 +579,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { finalize.map(|f| Finalize { used: Used::Scope, ..f }), ) }; - let binding = self.reborrow().resolve_ident_in_module_non_globs_unadjusted( + let decl = self.reborrow().resolve_ident_in_module_non_globs_unadjusted( module, ident, ns, @@ -588,11 +590,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Shadowing::Restricted }, adjusted_finalize, - ignore_binding, + ignore_decl, ignore_import, ); - match binding { - Ok(binding) => { + match decl { + Ok(decl) => { if let Some(lint_id) = derive_fallback_lint_id { self.get_mut().lint_buffer.buffer_lint( PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, @@ -605,7 +607,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }, ); } - Ok(binding) + Ok(decl) } Err(ControlFlow::Continue(determinacy)) => Err(determinacy), Err(ControlFlow::Break(determinacy)) => { @@ -638,7 +640,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Shadowing::Restricted }, adjusted_finalize, - ignore_binding, + ignore_decl, ignore_import, ); match binding { @@ -666,18 +668,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } Scope::MacroUsePrelude => match self.macro_use_prelude.get(&ident.name).cloned() { - Some(binding) => Ok(binding), + Some(decl) => Ok(decl), None => Err(Determinacy::determined( self.graph_root.unexpanded_invocations.borrow().is_empty(), )), }, Scope::BuiltinAttrs => match self.builtin_attr_decls.get(&ident.name) { - Some(binding) => Ok(*binding), + Some(decl) => Ok(*decl), None => Err(Determinacy::Determined), }, Scope::ExternPreludeItems => { match self.reborrow().extern_prelude_get_item(ident, finalize.is_some()) { - Some(binding) => Ok(binding), + Some(decl) => Ok(decl), None => Err(Determinacy::determined( self.graph_root.unexpanded_invocations.borrow().is_empty(), )), @@ -685,36 +687,35 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } Scope::ExternPreludeFlags => { match self.extern_prelude_get_flag(ident, finalize.is_some()) { - Some(binding) => Ok(binding), + Some(decl) => Ok(decl), None => Err(Determinacy::Determined), } } Scope::ToolPrelude => match self.registered_tool_decls.get(&ident) { - Some(binding) => Ok(*binding), + Some(decl) => Ok(*decl), None => Err(Determinacy::Determined), }, Scope::StdLibPrelude => { let mut result = Err(Determinacy::Determined); if let Some(prelude) = self.prelude - && let Ok(binding) = self.reborrow().resolve_ident_in_scope_set( + && let Ok(decl) = self.reborrow().resolve_ident_in_scope_set( ident, ScopeSet::Module(ns, prelude), parent_scope, None, false, - ignore_binding, + ignore_decl, ignore_import, ) - && (matches!(use_prelude, UsePrelude::Yes) - || self.is_builtin_macro(binding.res())) + && (matches!(use_prelude, UsePrelude::Yes) || self.is_builtin_macro(decl.res())) { - result = Ok(binding) + result = Ok(decl) } result } Scope::BuiltinTypes => match self.builtin_type_decls.get(&ident.name) { - Some(binding) => { + Some(decl) => { if matches!(ident.name, sym::f16) && !self.tcx.features().f16() && !ident.span.allows_unstable(sym::f16) @@ -741,7 +742,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) .emit(); } - Ok(*binding) + Ok(*decl) } None => Err(Determinacy::Determined), }, @@ -756,12 +757,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns: Namespace, scope_set: ScopeSet<'ra>, parent_scope: &ParentScope<'ra>, - binding: Decl<'ra>, + decl: Decl<'ra>, scope: Scope<'ra>, innermost_results: &[(Decl<'ra>, Scope<'ra>)], ) -> bool { - let (innermost_binding, innermost_scope) = *innermost_results.first().unwrap(); - let (res, innermost_res) = (binding.res(), innermost_binding.res()); + let (innermost_decl, innermost_scope) = innermost_results[0]; + let (res, innermost_res) = (decl.res(), innermost_decl.res()); if res == innermost_res { return false; } @@ -781,7 +782,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { span_bug!(orig_ident.span, "impossible inner resolution kind") } else if matches!(innermost_scope, Scope::MacroRules(_)) && matches!(scope, Scope::ModuleNonGlobs(..) | Scope::ModuleGlobs(..)) - && !self.disambiguate_macro_rules_vs_modularized(innermost_binding, binding) + && !self.disambiguate_macro_rules_vs_modularized(innermost_decl, decl) { Some(AmbiguityKind::MacroRulesVsModularized) } else if matches!(scope, Scope::MacroRules(_)) @@ -797,13 +798,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { "ambiguous scoped macro resolutions with path-based \ scope resolution as first candidate" ) - } else if innermost_binding.is_glob_import() { + } else if innermost_decl.is_glob_import() { Some(AmbiguityKind::GlobVsOuter) - } else if !module_only - && innermost_binding.may_appear_after(parent_scope.expansion, binding) - { + } else if !module_only && innermost_decl.may_appear_after(parent_scope.expansion, decl) { Some(AmbiguityKind::MoreExpandedVsOuter) - } else if innermost_binding.expansion != LocalExpnId::ROOT + } else if innermost_decl.expansion != LocalExpnId::ROOT && (!module_only || ns == MacroNS) && let Scope::ModuleGlobs(m1, _) = scope && let Scope::ModuleNonGlobs(m2, _) = innermost_scope @@ -822,9 +821,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // by extern item bindings. // FIXME: Remove with lang team approval. let issue_145575_hack = matches!(scope, Scope::ExternPreludeFlags) - && innermost_results[1..].iter().any(|(b, s)| { - matches!(s, Scope::ExternPreludeItems) && *b != innermost_binding - }); + && innermost_results[1..] + .iter() + .any(|(b, s)| matches!(s, Scope::ExternPreludeItems) && *b != innermost_decl); // Skip ambiguity errors for nonglob module bindings "overridden" // by glob module bindings in the same module. // FIXME: Remove with lang team approval. @@ -845,8 +844,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.ambiguity_errors.push(AmbiguityError { kind, ident: orig_ident, - b1: innermost_binding, - b2: binding, + b1: innermost_decl, + b2: decl, scope1: innermost_scope, scope2: scope, warning: false, @@ -878,7 +877,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns: Namespace, parent_scope: &ParentScope<'ra>, finalize: Option, - ignore_binding: Option>, + ignore_decl: Option>, ignore_import: Option>, ) -> Result, Determinacy> { let tmp_parent_scope; @@ -904,7 +903,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns, adjusted_parent_scope, finalize, - ignore_binding, + ignore_decl, ignore_import, ) } @@ -918,7 +917,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns: Namespace, parent_scope: &ParentScope<'ra>, finalize: Option, - ignore_binding: Option>, + ignore_decl: Option>, ignore_import: Option>, ) -> Result, Determinacy> { match module { @@ -928,7 +927,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope, finalize, finalize.is_some(), - ignore_binding, + ignore_decl, ignore_import, ), ModuleOrUniformRoot::ModuleAndExternPrelude(module) => self.resolve_ident_in_scope_set( @@ -937,7 +936,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope, finalize, finalize.is_some(), - ignore_binding, + ignore_decl, ignore_import, ), ModuleOrUniformRoot::ExternPrelude => { @@ -950,7 +949,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope, finalize, finalize.is_some(), - ignore_binding, + ignore_decl, ignore_import, ) } @@ -973,7 +972,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope, finalize, finalize.is_some(), - ignore_binding, + ignore_decl, ignore_import, ) } @@ -991,7 +990,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { finalize: Option, // This binding should be ignored during in-module resolution, so that we don't get // "self-confirming" import resolutions during import validation and checking. - ignore_binding: Option>, + ignore_decl: Option>, ignore_import: Option>, ) -> Result, ControlFlow> { let key = BindingKey::new(ident, ns); @@ -1003,7 +1002,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .try_borrow_mut_unchecked() .map_err(|_| ControlFlow::Continue(Determined))?; - let binding = resolution.non_glob_binding.filter(|b| Some(*b) != ignore_binding); + let binding = resolution.non_glob_decl.filter(|b| Some(*b) != ignore_decl); if let Some(finalize) = finalize { return self.get_mut().finalize_module_binding( @@ -1028,7 +1027,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None, ns, ignore_import, - ignore_binding, + ignore_decl, parent_scope, ) { return Err(ControlFlow::Break(Undetermined)); @@ -1052,7 +1051,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, shadowing: Shadowing, finalize: Option, - ignore_binding: Option>, + ignore_decl: Option>, ignore_import: Option>, ) -> Result, ControlFlow> { let key = BindingKey::new(ident, ns); @@ -1064,7 +1063,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .try_borrow_mut_unchecked() .map_err(|_| ControlFlow::Continue(Determined))?; - let binding = resolution.glob_binding.filter(|b| Some(*b) != ignore_binding); + let binding = resolution.glob_decl.filter(|b| Some(*b) != ignore_decl); if let Some(finalize) = finalize { return self.get_mut().finalize_module_binding( @@ -1084,7 +1083,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { binding, ns, ignore_import, - ignore_binding, + ignore_decl, parent_scope, ) { return Err(ControlFlow::Break(Undetermined)); @@ -1154,7 +1153,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { adjusted_parent_scope, None, false, - ignore_binding, + ignore_decl, ignore_import, ); @@ -1192,7 +1191,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if report_private { self.privacy_errors.push(PrivacyError { ident, - binding, + decl: binding, dedup_span: path_span, outermost_res: None, source: None, @@ -1255,12 +1254,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { binding: Option>, ns: Namespace, ignore_import: Option>, - ignore_binding: Option>, + ignore_decl: Option>, parent_scope: &ParentScope<'ra>, ) -> bool { for single_import in &resolution.single_imports { - if let Some(binding) = resolution.non_glob_binding - && let DeclKind::Import { import, .. } = binding.kind + if let Some(decl) = resolution.non_glob_decl + && let DeclKind::Import { import, .. } = decl.kind && import == *single_import { // Single import has already defined the name and we are aware of it, @@ -1273,7 +1272,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if !self.is_accessible_from(single_import.vis, parent_scope.module) { continue; } - if let Some(ignored) = ignore_binding + if let Some(ignored) = ignore_decl && let DeclKind::Import { import, .. } = ignored.kind && import == *single_import { @@ -1283,13 +1282,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let Some(module) = single_import.imported_module.get() else { return true; }; - let ImportKind::Single { source, target, bindings, .. } = &single_import.kind else { + let ImportKind::Single { source, target, decls, .. } = &single_import.kind else { unreachable!(); }; if source != target { - if bindings.iter().all(|binding| binding.get().decl().is_none()) { + if decls.iter().all(|d| d.get().decl().is_none()) { return true; - } else if bindings[ns].get().decl().is_none() && binding.is_some() { + } else if decls[ns].get().decl().is_none() && binding.is_some() { return true; } } @@ -1300,7 +1299,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns, &single_import.parent_scope, None, - ignore_binding, + ignore_decl, ignore_import, ) { Err(Determined) => continue, @@ -1665,7 +1664,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { opt_ns: Option, // `None` indicates a module path in import parent_scope: &ParentScope<'ra>, finalize: Option, - ignore_binding: Option>, + ignore_decl: Option>, ignore_import: Option>, ) -> PathResult<'ra> { self.resolve_path_with_ribs( @@ -1675,7 +1674,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None, finalize, None, - ignore_binding, + ignore_decl, ignore_import, None, ) @@ -1689,7 +1688,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { source: Option>, finalize: Option, ribs: Option<&PerNS>>>, - ignore_binding: Option>, + ignore_decl: Option>, ignore_import: Option>, diag_metadata: Option<&DiagMetadata<'_>>, ) -> PathResult<'ra> { @@ -1816,7 +1815,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns, parent_scope, finalize, - ignore_binding, + ignore_decl, ignore_import, ) } else if let Some(ribs) = ribs @@ -1829,7 +1828,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope, finalize, &ribs[ns], - ignore_binding, + ignore_decl, diag_metadata, ) { // we found a locally-imported or available item/module @@ -1851,7 +1850,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope, finalize, finalize.is_some(), - ignore_binding, + ignore_decl, ignore_import, ) }; @@ -1951,7 +1950,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { opt_ns, parent_scope, ribs, - ignore_binding, + ignore_decl, ignore_import, module, segment_idx, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 4f8877401638..0fbfbd95a026 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -66,8 +66,8 @@ pub(crate) enum ImportKind<'ra> { /// `target` in `use prefix::source as target`. /// It will directly use `source` when the format is `use prefix::source`. target: Ident, - /// Bindings introduced by the import. - bindings: PerNS>>, + /// Name declarations introduced by the import. + decls: PerNS>>, /// `true` for `...::{self [as target]}` imports, `false` otherwise. type_ns_only: bool, /// Did this import result from a nested import? ie. `use foo::{bar, baz};` @@ -110,14 +110,14 @@ impl<'ra> std::fmt::Debug for ImportKind<'ra> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { use ImportKind::*; match self { - Single { source, target, bindings, type_ns_only, nested, id, .. } => f + Single { source, target, decls, type_ns_only, nested, id, .. } => f .debug_struct("Single") .field("source", source) .field("target", target) // Ignore the nested bindings to avoid an infinite loop while printing. .field( - "bindings", - &bindings.clone().map(|b| b.into_inner().decl().map(|_| format_args!(".."))), + "decls", + &decls.clone().map(|b| b.into_inner().decl().map(|_| format_args!(".."))), ) .field("type_ns_only", type_ns_only) .field("nested", nested) @@ -244,16 +244,16 @@ pub(crate) struct NameResolution<'ra> { /// Single imports that may define the name in the namespace. /// Imports are arena-allocated, so it's ok to use pointers as keys. pub single_imports: FxIndexSet>, - /// The non-glob binding for this name, if it is known to exist. - pub non_glob_binding: Option>, - /// The glob binding for this name, if it is known to exist. - pub glob_binding: Option>, + /// The non-glob declaration for this name, if it is known to exist. + pub non_glob_decl: Option>, + /// The glob declaration for this name, if it is known to exist. + pub glob_decl: Option>, } impl<'ra> NameResolution<'ra> { /// Returns the binding for the name if it is known or None if it not known. pub(crate) fn binding(&self) -> Option> { - self.best_binding().and_then(|binding| { + self.best_decl().and_then(|binding| { if !binding.is_glob_import() || self.single_imports.is_empty() { Some(binding) } else { @@ -262,8 +262,8 @@ impl<'ra> NameResolution<'ra> { }) } - pub(crate) fn best_binding(&self) -> Option> { - self.non_glob_binding.or(self.glob_binding) + pub(crate) fn best_decl(&self) -> Option> { + self.non_glob_decl.or(self.glob_decl) } } @@ -296,16 +296,16 @@ fn pub_use_of_private_extern_crate_hack(import: Import<'_>, decl: Decl<'_>) -> O } impl<'ra, 'tcx> Resolver<'ra, 'tcx> { - /// Given a binding and an import that resolves to it, - /// return the corresponding binding defined by the import. - pub(crate) fn import(&self, binding: Decl<'ra>, import: Import<'ra>) -> Decl<'ra> { + /// Given an import and the declaration that it points to, + /// create the corresponding import declaration. + pub(crate) fn new_import_decl(&self, decl: Decl<'ra>, import: Import<'ra>) -> Decl<'ra> { let import_vis = import.vis.to_def_id(); - let vis = if binding.vis.is_at_least(import_vis, self.tcx) - || pub_use_of_private_extern_crate_hack(import, binding).is_some() + let vis = if decl.vis.is_at_least(import_vis, self.tcx) + || pub_use_of_private_extern_crate_hack(import, decl).is_some() { import_vis } else { - binding.vis + decl.vis }; if let ImportKind::Glob { ref max_vis, .. } = import.kind @@ -316,7 +316,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } self.arenas.alloc_decl(DeclData { - kind: DeclKind::Import { binding, import }, + kind: DeclKind::Import { binding: decl, import }, ambiguity: None, warn_ambiguity: false, span: import.span, @@ -325,18 +325,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }) } - /// Define the name or return the existing binding if there is a collision. - pub(crate) fn try_define_local( + /// Attempt to put the declaration with the given name and namespace into the module, + /// and return existing declaration if there is a collision. + pub(crate) fn try_plant_decl_into_local_module( &mut self, module: Module<'ra>, ident: Ident, ns: Namespace, - binding: Decl<'ra>, + decl: Decl<'ra>, warn_ambiguity: bool, ) -> Result<(), Decl<'ra>> { - let res = binding.res(); + let res = decl.res(); self.check_reserved_macro_name(ident, res); - self.set_decl_parent_module(binding, module); + self.set_decl_parent_module(decl, module); // Even if underscore names cannot be looked up, we still need to add them to modules, // because they can be fetched by glob imports from those modules, and bring traits // into scope both directly and through glob imports. @@ -345,67 +346,66 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { module.underscore_disambiguator.get() }); self.update_local_resolution(module, key, warn_ambiguity, |this, resolution| { - if let Some(old_binding) = resolution.best_binding() { - if res == Res::Err && old_binding.res() != Res::Err { - // Do not override real bindings with `Res::Err`s from error recovery. + if let Some(old_decl) = resolution.best_decl() { + if res == Res::Err && old_decl.res() != Res::Err { + // Do not override real declarations with `Res::Err`s from error recovery. return Ok(()); } - match (old_binding.is_glob_import(), binding.is_glob_import()) { + match (old_decl.is_glob_import(), decl.is_glob_import()) { (true, true) => { - let (glob_binding, old_glob_binding) = (binding, old_binding); - // FIXME: remove `!binding.is_ambiguity_recursive()` after delete the warning ambiguity. - if !binding.is_ambiguity_recursive() - && let DeclKind::Import { import: old_import, .. } = - old_glob_binding.kind - && let DeclKind::Import { import, .. } = glob_binding.kind + let (glob_decl, old_glob_decl) = (decl, old_decl); + // FIXME: remove `!decl.is_ambiguity_recursive()` after delete the warning ambiguity. + if !decl.is_ambiguity_recursive() + && let DeclKind::Import { import: old_import, .. } = old_glob_decl.kind + && let DeclKind::Import { import, .. } = glob_decl.kind && old_import == import { // When imported from the same glob-import statement, we should replace - // `old_glob_binding` with `glob_binding`, regardless of whether + // `old_glob_decl` with `glob_decl`, regardless of whether // they have the same resolution or not. - resolution.glob_binding = Some(glob_binding); - } else if res != old_glob_binding.res() { - resolution.glob_binding = Some(this.new_decl_with_ambiguity( - old_glob_binding, - glob_binding, + resolution.glob_decl = Some(glob_decl); + } else if res != old_glob_decl.res() { + resolution.glob_decl = Some(this.new_decl_with_ambiguity( + old_glob_decl, + glob_decl, warn_ambiguity, )); - } else if !old_binding.vis.is_at_least(binding.vis, this.tcx) { + } else if !old_decl.vis.is_at_least(decl.vis, this.tcx) { // We are glob-importing the same item but with greater visibility. - resolution.glob_binding = Some(glob_binding); - } else if binding.is_ambiguity_recursive() { - resolution.glob_binding = - Some(this.new_decl_with_warn_ambiguity(glob_binding)); + resolution.glob_decl = Some(glob_decl); + } else if decl.is_ambiguity_recursive() { + resolution.glob_decl = + Some(this.new_decl_with_warn_ambiguity(glob_decl)); } } (old_glob @ true, false) | (old_glob @ false, true) => { - let (glob_binding, non_glob_binding) = - if old_glob { (old_binding, binding) } else { (binding, old_binding) }; - resolution.non_glob_binding = Some(non_glob_binding); - if let Some(old_glob_binding) = resolution.glob_binding { - assert!(old_glob_binding.is_glob_import()); - if glob_binding.res() != old_glob_binding.res() { - resolution.glob_binding = Some(this.new_decl_with_ambiguity( - old_glob_binding, - glob_binding, + let (glob_decl, non_glob_decl) = + if old_glob { (old_decl, decl) } else { (decl, old_decl) }; + resolution.non_glob_decl = Some(non_glob_decl); + if let Some(old_glob_decl) = resolution.glob_decl { + assert!(old_glob_decl.is_glob_import()); + if glob_decl.res() != old_glob_decl.res() { + resolution.glob_decl = Some(this.new_decl_with_ambiguity( + old_glob_decl, + glob_decl, false, )); - } else if !old_glob_binding.vis.is_at_least(binding.vis, this.tcx) { - resolution.glob_binding = Some(glob_binding); + } else if !old_glob_decl.vis.is_at_least(decl.vis, this.tcx) { + resolution.glob_decl = Some(glob_decl); } } else { - resolution.glob_binding = Some(glob_binding); + resolution.glob_decl = Some(glob_decl); } } (false, false) => { - return Err(old_binding); + return Err(old_decl); } } } else { - if binding.is_glob_import() { - resolution.glob_binding = Some(binding); + if decl.is_glob_import() { + resolution.glob_decl = Some(decl); } else { - resolution.non_glob_binding = Some(binding); + resolution.non_glob_decl = Some(decl); } } @@ -445,14 +445,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // during which the resolution might end up getting re-defined via a glob cycle. let (binding, t, warn_ambiguity) = { let resolution = &mut *self.resolution_or_default(module, key).borrow_mut_unchecked(); - let old_binding = resolution.binding(); + let old_decl = resolution.binding(); let t = f(self, resolution); if let Some(binding) = resolution.binding() - && old_binding != Some(binding) + && old_decl != Some(binding) { - (binding, t, warn_ambiguity || old_binding.is_some()) + (binding, t, warn_ambiguity || old_decl.is_some()) } else { return t; } @@ -471,12 +471,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None => continue, }; if self.is_accessible_from(binding.vis, scope) { - let imported_binding = self.import(binding, *import); - let _ = self.try_define_local( + let import_decl = self.new_import_decl(binding, *import); + let _ = self.try_plant_decl_into_local_module( import.parent_scope.module, ident.0, key.ns, - imported_binding, + import_decl, warn_ambiguity, ); } @@ -488,16 +488,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Define a dummy resolution containing a `Res::Err` as a placeholder for a failed // or indeterminate resolution, also mark such failed imports as used to avoid duplicate diagnostics. fn import_dummy_binding(&mut self, import: Import<'ra>, is_indeterminate: bool) { - if let ImportKind::Single { target, ref bindings, .. } = import.kind { - if !(is_indeterminate || bindings.iter().all(|binding| binding.get().decl().is_none())) - { + if let ImportKind::Single { target, ref decls, .. } = import.kind { + if !(is_indeterminate || decls.iter().all(|d| d.get().decl().is_none())) { return; // Has resolution, do not create the dummy binding } let dummy_decl = self.dummy_decl; - let dummy_decl = self.import(dummy_decl, import); + let dummy_decl = self.new_import_decl(dummy_decl, import); self.per_ns(|this, ns| { let module = import.parent_scope.module; - let _ = this.try_define_local(module, target, ns, dummy_decl, false); + let _ = + this.try_plant_decl_into_local_module(module, target, ns, dummy_decl, false); // Don't remove underscores from `single_imports`, they were never added. if target.name != kw::Underscore { let key = BindingKey::new(target, ns); @@ -574,10 +574,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { glob_error |= import.is_glob(); - if let ImportKind::Single { source, ref bindings, .. } = import.kind + if let ImportKind::Single { source, ref decls, .. } = import.kind && source.name == kw::SelfLower // Silence `unresolved import` error if E0429 is already emitted - && let PendingDecl::Ready(None) = bindings.value_ns.get() + && let PendingDecl::Ready(None) = decls.value_ns.get() { continue; } @@ -631,7 +631,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for module in &self.local_modules { for (key, resolution) in self.resolutions(*module).borrow().iter() { let resolution = resolution.borrow(); - let Some(binding) = resolution.best_binding() else { continue }; + let Some(binding) = resolution.best_decl() else { continue }; if let DeclKind::Import { import, .. } = binding.kind && let Some(amb_binding) = binding.ambiguity @@ -651,16 +651,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ); } - if let Some(glob_binding) = resolution.glob_binding - && resolution.non_glob_binding.is_some() + if let Some(glob_decl) = resolution.glob_decl + && resolution.non_glob_decl.is_some() { if binding.res() != Res::Err - && glob_binding.res() != Res::Err - && let DeclKind::Import { import: glob_import, .. } = glob_binding.kind + && glob_decl.res() != Res::Err + && let DeclKind::Import { import: glob_import, .. } = glob_decl.kind && let Some(glob_import_id) = glob_import.id() && let glob_import_def_id = self.local_def_id(glob_import_id) && self.effective_visibilities.is_exported(glob_import_def_id) - && glob_binding.vis.is_public() + && glob_decl.vis.is_public() && !binding.vis.is_public() { let binding_id = match binding.kind { @@ -677,7 +677,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { BuiltinLintDiag::HiddenGlobReexports { name: key.ident.name.to_string(), namespace: key.ns.descr().to_owned(), - glob_reexport_span: glob_binding.span, + glob_reexport_span: glob_decl.span, private_item_span: binding.span, }, ); @@ -838,8 +838,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { import.imported_module.set_unchecked(Some(module)); let (source, target, bindings, type_ns_only) = match import.kind { - ImportKind::Single { source, target, ref bindings, type_ns_only, .. } => { - (source, target, bindings, type_ns_only) + ImportKind::Single { source, target, ref decls, type_ns_only, .. } => { + (source, target, decls, type_ns_only) } ImportKind::Glob { .. } => { self.get_mut_unchecked().resolve_glob_import(import); @@ -876,14 +876,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .emit(); } // We need the `target`, `source` can be extracted. - let imported_binding = this.import(binding, import); - this.get_mut_unchecked().define_binding_local( + let import_decl = this.new_import_decl(binding, import); + this.get_mut_unchecked().plant_decl_into_local_module( parent, target, ns, - imported_binding, + import_decl, ); - PendingDecl::Ready(Some(imported_binding)) + PendingDecl::Ready(Some(import_decl)) } Err(Determinacy::Determined) => { // Don't remove underscores from `single_imports`, they were never added. @@ -917,8 +917,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Optionally returns an unresolved import error. This error is buffered and used to /// consolidate multiple unresolved import errors into a single diagnostic. fn finalize_import(&mut self, import: Import<'ra>) -> Option { - let ignore_binding = match &import.kind { - ImportKind::Single { bindings, .. } => bindings[TypeNS].get().decl(), + let ignore_decl = match &import.kind { + ImportKind::Single { decls, .. } => decls[TypeNS].get().decl(), _ => None, }; let ambiguity_errors_len = @@ -934,7 +934,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None, &import.parent_scope, Some(finalize), - ignore_binding, + ignore_decl, Some(import), ); @@ -1037,8 +1037,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; let (ident, target, bindings, type_ns_only, import_id) = match import.kind { - ImportKind::Single { source, target, ref bindings, type_ns_only, id, .. } => { - (source, target, bindings, type_ns_only, id) + ImportKind::Single { source, target, ref decls, type_ns_only, id, .. } => { + (source, target, decls, type_ns_only, id) } ImportKind::Glob { ref max_vis, id } => { if import.module_path.len() <= 1 { @@ -1094,7 +1094,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None, &import.parent_scope, Some(finalize), - ignore_binding, + ignore_decl, None, ) { let res = module.res().map(|r| (r, ident)); @@ -1197,7 +1197,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // Never suggest the same name let resolution = resolution.borrow(); - if let Some(name_binding) = resolution.best_binding() { + if let Some(name_binding) = resolution.best_decl() { match name_binding.kind { DeclKind::Import { binding, .. } => { match binding.kind { @@ -1383,7 +1383,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn check_for_redundant_imports(&mut self, import: Import<'ra>) -> bool { // This function is only called for single imports. - let ImportKind::Single { source, target, ref bindings, id, .. } = import.kind else { + let ImportKind::Single { source, target, ref decls, id, .. } = import.kind else { unreachable!() }; @@ -1410,7 +1410,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut is_redundant = true; let mut redundant_span = PerNS { value_ns: None, type_ns: None, macro_ns: None }; self.per_ns(|this, ns| { - let binding = bindings[ns].get().decl().map(|b| b.import_source()); + let binding = decls[ns].get().decl().map(|b| b.import_source()); if is_redundant && let Some(binding) = binding { if binding.res() == Res::Err { return; @@ -1422,7 +1422,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { &import.parent_scope, None, false, - bindings[ns].get().decl(), + decls[ns].get().decl(), None, ) { Ok(other_binding) => { @@ -1497,16 +1497,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None => continue, }; if self.is_accessible_from(binding.vis, scope) { - let imported_binding = self.import(binding, import); + let import_decl = self.new_import_decl(binding, import); let warn_ambiguity = self .resolution(import.parent_scope.module, key) .and_then(|r| r.binding()) .is_some_and(|binding| binding.warn_ambiguity_recursive()); - let _ = self.try_define_local( + let _ = self.try_plant_decl_into_local_module( import.parent_scope.module, key.ident.0, key.ns, - imported_binding, + import_decl, warn_ambiguity, ); } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 2685efa28b64..b4941a6f5b99 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -677,7 +677,7 @@ impl MaybeExported<'_> { /// Used for recording UnnecessaryQualification. #[derive(Debug)] pub(crate) struct UnnecessaryQualification<'ra> { - pub binding: LateDecl<'ra>, + pub decl: LateDecl<'ra>, pub node_id: NodeId, pub path_span: Span, pub removal_span: Span, @@ -1489,7 +1489,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ident: Ident, ns: Namespace, finalize: Option, - ignore_binding: Option>, + ignore_decl: Option>, ) -> Option> { self.r.resolve_ident_in_lexical_scope( ident, @@ -1497,7 +1497,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { &self.parent_scope, finalize, &self.ribs[ns], - ignore_binding, + ignore_decl, Some(&self.diag_metadata), ) } @@ -3630,9 +3630,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }; ident.span.normalize_to_macros_2_0_and_adjust(module.expansion); let key = BindingKey::new(ident, ns); - let mut binding = self.r.resolution(module, key).and_then(|r| r.best_binding()); - debug!(?binding); - if binding.is_none() { + let mut decl = self.r.resolution(module, key).and_then(|r| r.best_decl()); + debug!(?decl); + if decl.is_none() { // We could not find the trait item in the correct namespace. // Check the other namespace to report an error. let ns = match ns { @@ -3641,8 +3641,8 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { _ => ns, }; let key = BindingKey::new(ident, ns); - binding = self.r.resolution(module, key).and_then(|r| r.best_binding()); - debug!(?binding); + decl = self.r.resolution(module, key).and_then(|r| r.best_decl()); + debug!(?decl); } let feed_visibility = |this: &mut Self, def_id| { @@ -3659,7 +3659,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { this.r.feed_visibility(this.r.feed(id), vis); }; - let Some(binding) = binding else { + let Some(decl) = decl else { // We could not find the method: report an error. let candidate = self.find_similarly_named_assoc_item(ident.name, kind); let path = &self.current_trait_ref.as_ref().unwrap().1.path; @@ -3669,7 +3669,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { return; }; - let res = binding.res(); + let res = decl.res(); let Res::Def(def_kind, id_in_trait) = res else { bug!() }; feed_visibility(self, id_in_trait); @@ -3680,7 +3680,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ResolutionError::TraitImplDuplicate { name: ident, old_span: *entry.get(), - trait_item_span: binding.span, + trait_item_span: decl.span, }, ); return; @@ -3720,7 +3720,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { kind, code, trait_path, - trait_item_span: binding.span, + trait_item_span: decl.span, }, ); } @@ -5356,9 +5356,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { (res == binding.res()).then_some((seg, binding)) }); - if let Some((seg, binding)) = unqualified { + if let Some((seg, decl)) = unqualified { self.r.potentially_unnecessary_qualifications.push(UnnecessaryQualification { - binding, + decl, node_id: finalize.node_id, path_span: finalize.path_span, removal_span: path[0].ident.span.until(seg.ident.span), diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index f75ac400dc0b..73e1a8f0c3bc 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -891,10 +891,8 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn lookup_doc_alias_name(&mut self, path: &[Segment], ns: Namespace) -> Option<(DefId, Ident)> { let find_doc_alias_name = |r: &mut Resolver<'ra, '_>, m: Module<'ra>, item_name: Symbol| { for resolution in r.resolutions(m).borrow().values() { - let Some(did) = resolution - .borrow() - .best_binding() - .and_then(|binding| binding.res().opt_def_id()) + let Some(did) = + resolution.borrow().best_decl().and_then(|binding| binding.res().opt_def_id()) else { continue; }; @@ -1589,19 +1587,17 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self.resolve_path(mod_path, None, None, *source) { - let targets: Vec<_> = self - .r - .resolutions(module) - .borrow() - .iter() - .filter_map(|(key, resolution)| { - resolution - .borrow() - .best_binding() - .map(|binding| binding.res()) - .and_then(|res| if filter_fn(res) { Some((*key, res)) } else { None }) - }) - .collect(); + let targets: Vec<_> = + self.r + .resolutions(module) + .borrow() + .iter() + .filter_map(|(key, resolution)| { + resolution.borrow().best_decl().map(|binding| binding.res()).and_then( + |res| if filter_fn(res) { Some((*key, res)) } else { None }, + ) + }) + .collect(); if let [target] = targets.as_slice() { return Some(TypoSuggestion::single_item_from_ident( target.0.ident.0, @@ -2486,9 +2482,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { .resolutions(*module) .borrow() .iter() - .filter_map(|(key, res)| { - res.borrow().best_binding().map(|binding| (key, binding.res())) - }) + .filter_map(|(key, res)| res.borrow().best_decl().map(|binding| (key, binding.res()))) .filter(|(_, res)| match (kind, res) { (AssocItemKind::Const(..), Res::Def(DefKind::AssocConst, _)) => true, (AssocItemKind::Fn(_), Res::Def(DefKind::AssocFn, _)) => true, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 67449050aea9..27817c0473ab 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -692,8 +692,8 @@ impl<'ra> Module<'ra> { mut f: impl FnMut(&R, Macros20NormalizedIdent, Namespace, Decl<'ra>), ) { for (key, name_resolution) in resolver.as_ref().resolutions(self).borrow().iter() { - if let Some(binding) = name_resolution.borrow().best_binding() { - f(resolver, key.ident, key.ns, binding); + if let Some(decl) = name_resolution.borrow().best_decl() { + f(resolver, key.ident, key.ns, decl); } } } @@ -704,8 +704,8 @@ impl<'ra> Module<'ra> { mut f: impl FnMut(&mut R, Macros20NormalizedIdent, Namespace, Decl<'ra>), ) { for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() { - if let Some(binding) = name_resolution.borrow().best_binding() { - f(resolver, key.ident, key.ns, binding); + if let Some(decl) = name_resolution.borrow().best_decl() { + f(resolver, key.ident, key.ns, decl); } } } @@ -842,7 +842,7 @@ enum DeclKind<'ra> { } impl<'ra> DeclKind<'ra> { - /// Is this a name binding of an import? + /// Is this an import declaration? fn is_import(&self) -> bool { matches!(*self, DeclKind::Import { .. }) } @@ -851,7 +851,7 @@ impl<'ra> DeclKind<'ra> { #[derive(Debug)] struct PrivacyError<'ra> { ident: Ident, - binding: Decl<'ra>, + decl: Decl<'ra>, dedup_span: Span, outermost_res: Option<(Res, Ident)>, parent_scope: ParentScope<'ra>, @@ -2047,15 +2047,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn record_use_inner( &mut self, ident: Ident, - used_binding: Decl<'ra>, + used_decl: Decl<'ra>, used: Used, warn_ambiguity: bool, ) { - if let Some(b2) = used_binding.ambiguity { + if let Some(b2) = used_decl.ambiguity { let ambiguity_error = AmbiguityError { kind: AmbiguityKind::GlobVsGlob, ident, - b1: used_binding, + b1: used_decl, b2, scope1: Scope::ModuleGlobs(self.empty_module, None), scope2: Scope::ModuleGlobs(self.empty_module, None), @@ -2066,7 +2066,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.ambiguity_errors.push(ambiguity_error); } } - if let DeclKind::Import { import, binding } = used_binding.kind { + if let DeclKind::Import { import, binding } = used_decl.kind { if let ImportKind::MacroUse { warn_private: true } = import.kind { // Do not report the lint if the macro name resolves in stdlib prelude // even without the problematic `macro_use` import. @@ -2096,7 +2096,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // but not introduce it, as used if they are accessed from lexical scope. if used == Used::Scope && let Some(entry) = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)) - && entry.item_decl == Some((used_binding, false)) + && entry.item_decl == Some((used_decl, false)) { return; } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 898d198c5475..c9c754374c87 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -46,7 +46,7 @@ use crate::{ type Res = def::Res; /// Name declaration produced by a `macro_rules` item definition. -/// Not modularized, can shadow previous `macro_rules` bindings, etc. +/// Not modularized, can shadow previous `macro_rules` definitions, etc. #[derive(Debug)] pub(crate) struct MacroRulesDecl<'ra> { pub(crate) decl: Decl<'ra>, From db26d01211b55e1834b427049fc06c64a1ca0d0c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 30 Dec 2025 23:51:07 +0300 Subject: [PATCH 0301/1061] resolve: `DeclKind::Import::binding` -> `DeclKind::Import::source_decl` --- compiler/rustc_resolve/src/diagnostics.rs | 12 +++---- .../src/effective_visibilities.rs | 6 ++-- compiler/rustc_resolve/src/imports.rs | 10 +++--- compiler/rustc_resolve/src/lib.rs | 32 +++++++++---------- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 7ed29b91b67a..7c86ed91a07a 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1357,8 +1357,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // #90113: Do not count an inaccessible reexported item as a candidate. - if let DeclKind::Import { binding, .. } = name_binding.kind - && this.is_accessible_from(binding.vis, parent_scope.module) + if let DeclKind::Import { source_decl, .. } = name_binding.kind + && this.is_accessible_from(source_decl.vis, parent_scope.module) && !this.is_accessible_from(name_binding.vis, parent_scope.module) { return; @@ -2210,15 +2210,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let name = next_ident; next_binding = match binding.kind { _ if res == Res::Err => None, - DeclKind::Import { binding, import, .. } => match import.kind { - _ if binding.span.is_dummy() => None, + DeclKind::Import { source_decl, import, .. } => match import.kind { + _ if source_decl.span.is_dummy() => None, ImportKind::Single { source, .. } => { next_ident = source; - Some(binding) + Some(source_decl) } ImportKind::Glob { .. } | ImportKind::MacroUse { .. } - | ImportKind::MacroExport => Some(binding), + | ImportKind::MacroExport => Some(source_decl), ImportKind::ExternCrate { .. } => None, }, _ => None, diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 87be913df535..e5144332f2b7 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -128,7 +128,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { let is_ambiguity = |decl: Decl<'ra>, warn: bool| decl.ambiguity.is_some() && !warn; let mut parent_id = ParentId::Def(module_id); let mut warn_ambiguity = decl.warn_ambiguity; - while let DeclKind::Import { binding: nested_binding, .. } = decl.kind { + while let DeclKind::Import { source_decl, .. } = decl.kind { self.update_import(decl, parent_id); if is_ambiguity(decl, warn_ambiguity) { @@ -139,8 +139,8 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { } parent_id = ParentId::Import(decl); - decl = nested_binding; - warn_ambiguity |= nested_binding.warn_ambiguity; + decl = source_decl; + warn_ambiguity |= source_decl.warn_ambiguity; } if !is_ambiguity(decl, warn_ambiguity) && let Some(def_id) = decl.res().opt_def_id().and_then(|id| id.as_local()) diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 0fbfbd95a026..a8bb53cc7f27 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -316,7 +316,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } self.arenas.alloc_decl(DeclData { - kind: DeclKind::Import { binding: decl, import }, + kind: DeclKind::Import { source_decl: decl, import }, ambiguity: None, warn_ambiguity: false, span: import.span, @@ -1199,10 +1199,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let resolution = resolution.borrow(); if let Some(name_binding) = resolution.best_decl() { match name_binding.kind { - DeclKind::Import { binding, .. } => { - match binding.kind { - // Never suggest the name that has binding error - // i.e., the name that cannot be previously resolved + DeclKind::Import { source_decl, .. } => { + match source_decl.kind { + // Never suggest names that previously could not + // be resolved. DeclKind::Def(Res::Err) => None, _ => Some(i.name), } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 27817c0473ab..063b6b4058f0 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -838,7 +838,7 @@ enum DeclKind<'ra> { /// can be provided by source code or built into the language. Def(Res), /// The name declaration is a link to another name declaration. - Import { binding: Decl<'ra>, import: Import<'ra> }, + Import { source_decl: Decl<'ra>, import: Import<'ra> }, } impl<'ra> DeclKind<'ra> { @@ -926,13 +926,13 @@ impl<'ra> DeclData<'ra> { fn res(&self) -> Res { match self.kind { DeclKind::Def(res) => res, - DeclKind::Import { binding, .. } => binding.res(), + DeclKind::Import { source_decl, .. } => source_decl.res(), } } fn import_source(&self) -> Decl<'ra> { match self.kind { - DeclKind::Import { binding, .. } => binding, + DeclKind::Import { source_decl, .. } => source_decl, _ => unreachable!(), } } @@ -941,7 +941,7 @@ impl<'ra> DeclData<'ra> { match self.ambiguity { Some(ambig_binding) => Some((self, ambig_binding)), None => match self.kind { - DeclKind::Import { binding, .. } => binding.descent_to_ambiguity(), + DeclKind::Import { source_decl, .. } => source_decl.descent_to_ambiguity(), _ => None, }, } @@ -950,7 +950,7 @@ impl<'ra> DeclData<'ra> { fn is_ambiguity_recursive(&self) -> bool { self.ambiguity.is_some() || match self.kind { - DeclKind::Import { binding, .. } => binding.is_ambiguity_recursive(), + DeclKind::Import { source_decl, .. } => source_decl.is_ambiguity_recursive(), _ => false, } } @@ -958,14 +958,14 @@ impl<'ra> DeclData<'ra> { fn warn_ambiguity_recursive(&self) -> bool { self.warn_ambiguity || match self.kind { - DeclKind::Import { binding, .. } => binding.warn_ambiguity_recursive(), + DeclKind::Import { source_decl, .. } => source_decl.warn_ambiguity_recursive(), _ => false, } } fn is_possibly_imported_variant(&self) -> bool { match self.kind { - DeclKind::Import { binding, .. } => binding.is_possibly_imported_variant(), + DeclKind::Import { source_decl, .. } => source_decl.is_possibly_imported_variant(), DeclKind::Def(Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), _)) => { true } @@ -1012,9 +1012,9 @@ impl<'ra> DeclData<'ra> { fn reexport_chain(self: Decl<'ra>, r: &Resolver<'_, '_>) -> SmallVec<[Reexport; 2]> { let mut reexport_chain = SmallVec::new(); let mut next_binding = self; - while let DeclKind::Import { binding, import, .. } = next_binding.kind { + while let DeclKind::Import { source_decl, import, .. } = next_binding.kind { reexport_chain.push(import.simplify(r)); - next_binding = binding; + next_binding = source_decl; } reexport_chain } @@ -1043,9 +1043,9 @@ impl<'ra> DeclData<'ra> { // FIXME: How can we integrate it with the `update_resolution`? fn determined(&self) -> bool { match &self.kind { - DeclKind::Import { binding, import, .. } if import.is_glob() => { + DeclKind::Import { source_decl, import, .. } if import.is_glob() => { import.parent_scope.module.unexpanded_invocations.borrow().is_empty() - && binding.determined() + && source_decl.determined() } _ => true, } @@ -1985,14 +1985,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { trait_name: Ident, ) -> SmallVec<[LocalDefId; 1]> { let mut import_ids = smallvec![]; - while let DeclKind::Import { import, binding, .. } = kind { + while let DeclKind::Import { import, source_decl, .. } = kind { if let Some(node_id) = import.id() { let def_id = self.local_def_id(node_id); self.maybe_unused_trait_imports.insert(def_id); import_ids.push(def_id); } self.add_to_glob_map(*import, trait_name); - kind = &binding.kind; + kind = &source_decl.kind; } import_ids } @@ -2066,7 +2066,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.ambiguity_errors.push(ambiguity_error); } } - if let DeclKind::Import { import, binding } = used_decl.kind { + if let DeclKind::Import { import, source_decl } = used_decl.kind { if let ImportKind::MacroUse { warn_private: true } = import.kind { // Do not report the lint if the macro name resolves in stdlib prelude // even without the problematic `macro_use` import. @@ -2110,9 +2110,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.add_to_glob_map(import, ident); self.record_use_inner( ident, - binding, + source_decl, Used::Other, - warn_ambiguity || binding.warn_ambiguity, + warn_ambiguity || source_decl.warn_ambiguity, ); } } From 14ac6a1d3a3e153a546d3e71b51866ca77a02dcd Mon Sep 17 00:00:00 2001 From: sgasho Date: Wed, 7 Jan 2026 00:19:09 +0900 Subject: [PATCH 0302/1061] Modified to output error messages appropriate to the situation --- compiler/rustc_codegen_llvm/messages.ftl | 6 ++-- compiler/rustc_codegen_llvm/src/errors.rs | 8 ++++- compiler/rustc_codegen_llvm/src/lib.rs | 12 ++++--- .../rustc_codegen_llvm/src/llvm/enzyme_ffi.rs | 34 ++++++++++++++----- 4 files changed, 44 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl index 018d240b2ae5..85cb7499cca4 100644 --- a/compiler/rustc_codegen_llvm/messages.ftl +++ b/compiler/rustc_codegen_llvm/messages.ftl @@ -1,5 +1,7 @@ -codegen_llvm_autodiff_component_unavailable = failed to load our autodiff backend. - .note = load error: {$err} +codegen_llvm_autodiff_component_missing = autodiff backend not found in the sysroot: {$err} + .note = it will be distributed via rustup in the future + +codegen_llvm_autodiff_component_unavailable = failed to load our autodiff backend: {$err} codegen_llvm_autodiff_without_enable = using the autodiff feature requires -Z autodiff=Enable codegen_llvm_autodiff_without_lto = using the autodiff feature requires setting `lto="fat"` in your Cargo.toml diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index 439664b8b9a2..bd42cf556966 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -34,11 +34,17 @@ impl Diagnostic<'_, G> for ParseTargetMachineConfig<'_> { #[derive(Diagnostic)] #[diag(codegen_llvm_autodiff_component_unavailable)] -#[note] pub(crate) struct AutoDiffComponentUnavailable { pub err: String, } +#[derive(Diagnostic)] +#[diag(codegen_llvm_autodiff_component_missing)] +#[note] +pub(crate) struct AutoDiffComponentMissing { + pub err: String, +} + #[derive(Diagnostic)] #[diag(codegen_llvm_autodiff_without_lto)] pub(crate) struct AutoDiffWithoutLto; diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 801d23342973..438a74e0a091 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -249,10 +249,14 @@ impl CodegenBackend for LlvmCodegenBackend { use crate::back::lto::enable_autodiff_settings; if sess.opts.unstable_opts.autodiff.contains(&AutoDiff::Enable) { - if let Err(err) = llvm::EnzymeWrapper::get_or_init(&sess.opts.sysroot) { - sess.dcx().emit_fatal(crate::errors::AutoDiffComponentUnavailable { - err: format!("{err:?}"), - }); + match llvm::EnzymeWrapper::get_or_init(&sess.opts.sysroot) { + Ok(_) => {} + Err(llvm::EnzymeLibraryError::NotFound { err }) => { + sess.dcx().emit_fatal(crate::errors::AutoDiffComponentMissing { err }); + } + Err(llvm::EnzymeLibraryError::LoadFailed { err }) => { + sess.dcx().emit_fatal(crate::errors::AutoDiffComponentUnavailable { err }); + } } enable_autodiff_settings(&sess.opts.unstable_opts.autodiff); } diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs index b11310b970d0..67fbc0f53adc 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs @@ -153,7 +153,7 @@ pub(crate) mod Enzyme_AD { fn load_ptr_by_symbol_mut_void( lib: &libloading::Library, bytes: &[u8], - ) -> Result<*mut c_void, Box> { + ) -> Result<*mut c_void, libloading::Error> { unsafe { let s: libloading::Symbol<'_, *mut c_void> = lib.get(bytes)?; // libloading = 0.9.0: try_as_raw_ptr always succeeds and returns Some @@ -192,15 +192,27 @@ pub(crate) mod Enzyme_AD { static ENZYME_INSTANCE: OnceLock> = OnceLock::new(); + #[derive(Debug)] + pub(crate) enum EnzymeLibraryError { + NotFound { err: String }, + LoadFailed { err: String }, + } + + impl From for EnzymeLibraryError { + fn from(err: libloading::Error) -> Self { + Self::LoadFailed { err: format!("{err:?}") } + } + } + impl EnzymeWrapper { /// Initialize EnzymeWrapper with the given sysroot if not already initialized. /// Safe to call multiple times - subsequent calls are no-ops due to OnceLock. pub(crate) fn get_or_init( sysroot: &rustc_session::config::Sysroot, - ) -> Result, Box> { + ) -> Result, EnzymeLibraryError> { let mtx: &'static Mutex = ENZYME_INSTANCE.get_or_try_init(|| { let w = Self::call_dynamic(sysroot)?; - Ok::<_, Box>(Mutex::new(w)) + Ok::<_, EnzymeLibraryError>(Mutex::new(w)) })?; Ok(mtx.lock().unwrap()) @@ -351,7 +363,7 @@ pub(crate) mod Enzyme_AD { #[allow(non_snake_case)] fn call_dynamic( sysroot: &rustc_session::config::Sysroot, - ) -> Result> { + ) -> Result { let enzyme_path = Self::get_enzyme_path(sysroot)?; let lib = unsafe { libloading::Library::new(enzyme_path)? }; @@ -416,7 +428,7 @@ pub(crate) mod Enzyme_AD { }) } - fn get_enzyme_path(sysroot: &Sysroot) -> Result { + fn get_enzyme_path(sysroot: &Sysroot) -> Result { let llvm_version_major = unsafe { LLVMRustVersionMajor() }; let path_buf = sysroot @@ -434,15 +446,19 @@ pub(crate) mod Enzyme_AD { .map(|p| p.join("lib").display().to_string()) .collect::>() .join("\n* "); - format!( - "failed to find a `libEnzyme-{llvm_version_major}` folder \ + EnzymeLibraryError::NotFound { + err: format!( + "failed to find a `libEnzyme-{llvm_version_major}` folder \ in the sysroot candidates:\n* {candidates}" - ) + ), + } })?; Ok(path_buf .to_str() - .ok_or_else(|| format!("invalid UTF-8 in path: {}", path_buf.display()))? + .ok_or_else(|| EnzymeLibraryError::LoadFailed { + err: format!("invalid UTF-8 in path: {}", path_buf.display()), + })? .to_string()) } } From 76d0843f8d05e34b49b4ec830ff745593269d8e4 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 31 Oct 2025 19:07:29 +0100 Subject: [PATCH 0303/1061] naked functions: emit `.private_extern` on macos --- .../rustc_codegen_ssa/src/mir/naked_asm.rs | 3 +- .../rustc_monomorphize/src/partitioning.rs | 10 +++++ tests/assembly-llvm/naked-functions/aix.rs | 2 +- tests/assembly-llvm/naked-functions/hidden.rs | 41 +++++++++++++++++++ 4 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 tests/assembly-llvm/naked-functions/hidden.rs diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index 4a47799b2bdc..4bbb7470debe 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -181,7 +181,8 @@ fn prefix_and_suffix<'tcx>( } } Linkage::Internal => { - // write nothing + // LTO can fail when internal linkage is used. + emit_fatal("naked functions may not have internal linkage") } Linkage::Common => emit_fatal("Functions may not have common linkage"), Linkage::AvailableExternally => { diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 1c8d6db08c31..e7af1d45cff8 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -580,6 +580,16 @@ fn internalize_symbols<'tcx>( } } + // When LTO inlines the caller of a naked function, it will attempt but fail to make the + // naked function symbol visible. To ensure that LTO works correctly, do not default + // naked functions to internal linkage and default visibility. + if let MonoItem::Fn(instance) = item { + let flags = cx.tcx.codegen_instance_attrs(instance.def).flags; + if flags.contains(CodegenFnAttrFlags::NAKED) { + continue; + } + } + // If we got here, we did not find any uses from other CGUs, so // it's fine to make this monomorphization internal. data.linkage = Linkage::Internal; diff --git a/tests/assembly-llvm/naked-functions/aix.rs b/tests/assembly-llvm/naked-functions/aix.rs index 3cc84fa0c9c6..8391331d8341 100644 --- a/tests/assembly-llvm/naked-functions/aix.rs +++ b/tests/assembly-llvm/naked-functions/aix.rs @@ -9,7 +9,7 @@ //@[aix] needs-llvm-components: powerpc #![crate_type = "lib"] -#![feature(no_core, asm_experimental_arch, f128, linkage, fn_align)] +#![feature(no_core, asm_experimental_arch)] #![no_core] // tests that naked functions work for the `powerpc64-ibm-aix` target. diff --git a/tests/assembly-llvm/naked-functions/hidden.rs b/tests/assembly-llvm/naked-functions/hidden.rs new file mode 100644 index 000000000000..7686dbab07fb --- /dev/null +++ b/tests/assembly-llvm/naked-functions/hidden.rs @@ -0,0 +1,41 @@ +//@ revisions: macos-x86 macos-aarch64 linux-x86 +//@ add-minicore +//@ assembly-output: emit-asm +// +//@[macos-aarch64] compile-flags: --target aarch64-apple-darwin +//@[macos-aarch64] needs-llvm-components: aarch64 +// +//@[macos-x86] compile-flags: --target x86_64-apple-darwin +//@[macos-x86] needs-llvm-components: x86 +// +//@[linux-x86] compile-flags: --target x86_64-unknown-linux-gnu +//@[linux-x86] needs-llvm-components: x86 + +#![crate_type = "lib"] +#![feature(no_core, asm_experimental_arch)] +#![no_core] + +// Tests that naked functions that are not externally linked (e.g. via `no_mangle`) +// are marked as `Visibility::Hidden` and emit `.private_extern` or `.hidden`. +// +// Without this directive, LTO may fail because the symbol is not visible. +// See also https://github.com/rust-lang/rust/issues/148307. + +extern crate minicore; +use minicore::*; + +// CHECK: .p2align 2 +// macos-x86,macos-aarch64: .private_extern +// linux-x86: .globl +// linux-x86: .hidden +// CHECK: ret +#[unsafe(naked)] +extern "C" fn ret() { + naked_asm!("ret") +} + +// CHECK-LABEL: entry +#[no_mangle] +pub fn entry() { + ret() +} From 021a551d5da251d91251ad08f976319dc78d25c4 Mon Sep 17 00:00:00 2001 From: andjsrk Date: Wed, 7 Jan 2026 00:51:54 +0900 Subject: [PATCH 0304/1061] add test for repeats --- ...can-have-side-effects-depend-on-element.rs | 19 +++++++++++++++++++ ...have-side-effects-depend-on-element.stderr | 13 +++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 tests/ui/repeat-expr/can-have-side-effects-depend-on-element.rs create mode 100644 tests/ui/repeat-expr/can-have-side-effects-depend-on-element.stderr diff --git a/tests/ui/repeat-expr/can-have-side-effects-depend-on-element.rs b/tests/ui/repeat-expr/can-have-side-effects-depend-on-element.rs new file mode 100644 index 000000000000..cd385587d491 --- /dev/null +++ b/tests/ui/repeat-expr/can-have-side-effects-depend-on-element.rs @@ -0,0 +1,19 @@ +//@ check-pass + +#![allow(unused)] + +// Test if `Expr::can_have_side_effects` considers element of repeat expressions. + +fn drop_repeat_in_arm_body() { + // Built-in lint `dropping_copy_types` relies on `Expr::can_have_side_effects` (See rust-clippy#9482) + + match () { + () => drop([0; 1]), // No side effects + //~^ WARNING calls to `std::mem::drop` with a value that implements `Copy` does nothing + } + match () { + () => drop([return; 1]), // Definitely has side effects + } +} + +fn main() {} diff --git a/tests/ui/repeat-expr/can-have-side-effects-depend-on-element.stderr b/tests/ui/repeat-expr/can-have-side-effects-depend-on-element.stderr new file mode 100644 index 000000000000..0f15e7577dca --- /dev/null +++ b/tests/ui/repeat-expr/can-have-side-effects-depend-on-element.stderr @@ -0,0 +1,13 @@ +warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing + --> $DIR/can-have-side-effects-depend-on-element.rs:11:15 + | +LL | () => drop([0; 1]), // No side effects + | ^^^^^------^ + | | + | argument has type `[i32; 1]` + | + = note: use `let _ = ...` to ignore the expression or result + = note: `#[warn(dropping_copy_types)]` on by default + +warning: 1 warning emitted + From 61ca012d4b6b1678fb6649811187d8f1335d1df8 Mon Sep 17 00:00:00 2001 From: andjsrk Date: Wed, 7 Jan 2026 00:55:58 +0900 Subject: [PATCH 0305/1061] rename test --- ...-on-element.rs => can-have-side-effects-consider-element.rs} | 0 ...ent.stderr => can-have-side-effects-consider-element.stderr} | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/ui/repeat-expr/{can-have-side-effects-depend-on-element.rs => can-have-side-effects-consider-element.rs} (100%) rename tests/ui/repeat-expr/{can-have-side-effects-depend-on-element.stderr => can-have-side-effects-consider-element.stderr} (87%) diff --git a/tests/ui/repeat-expr/can-have-side-effects-depend-on-element.rs b/tests/ui/repeat-expr/can-have-side-effects-consider-element.rs similarity index 100% rename from tests/ui/repeat-expr/can-have-side-effects-depend-on-element.rs rename to tests/ui/repeat-expr/can-have-side-effects-consider-element.rs diff --git a/tests/ui/repeat-expr/can-have-side-effects-depend-on-element.stderr b/tests/ui/repeat-expr/can-have-side-effects-consider-element.stderr similarity index 87% rename from tests/ui/repeat-expr/can-have-side-effects-depend-on-element.stderr rename to tests/ui/repeat-expr/can-have-side-effects-consider-element.stderr index 0f15e7577dca..6948d64ebcc3 100644 --- a/tests/ui/repeat-expr/can-have-side-effects-depend-on-element.stderr +++ b/tests/ui/repeat-expr/can-have-side-effects-consider-element.stderr @@ -1,5 +1,5 @@ warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing - --> $DIR/can-have-side-effects-depend-on-element.rs:11:15 + --> $DIR/can-have-side-effects-consider-element.rs:11:15 | LL | () => drop([0; 1]), // No side effects | ^^^^^------^ From 1cd87525e6b566b560a540626de9bfac6cc90b4a Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sun, 4 Jan 2026 11:23:35 +0100 Subject: [PATCH 0306/1061] Unix implementation for stdio set/take/replace --- library/std/src/os/unix/io/mod.rs | 129 ++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/library/std/src/os/unix/io/mod.rs b/library/std/src/os/unix/io/mod.rs index 6d4090ee31cf..708ebaec362e 100644 --- a/library/std/src/os/unix/io/mod.rs +++ b/library/std/src/os/unix/io/mod.rs @@ -92,9 +92,138 @@ #![stable(feature = "rust1", since = "1.0.0")] +use crate::io::{self, Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock, Write}; #[stable(feature = "rust1", since = "1.0.0")] pub use crate::os::fd::*; +#[allow(unused_imports)] // not used on all targets +use crate::sys::cvt; // Tests for this module #[cfg(test)] mod tests; + +#[unstable(feature = "stdio_swap", issue = "150667", reason = "recently added")] +pub trait StdioExt: crate::sealed::Sealed { + /// Redirects the stdio file descriptor to point to the file description underpinning `fd`. + /// + /// Rust std::io write buffers (if any) are flushed, but other runtimes + /// (e.g. C stdio) or libraries that acquire a clone of the file descriptor + /// will not be aware of this change. + /// + /// # Platform-specific behavior + /// + /// This is [currently] implemented using + /// + /// - `fd_renumber` on wasip1 + /// - `dup2` on most unixes + /// + /// [currently]: crate::io#platform-specific-behavior + /// + /// ``` + /// #![feature(stdio_swap)] + /// use std::io::{self, Read, Write}; + /// use std::os::unix::io::StdioExt; + /// + /// fn main() -> io::Result<()> { + /// let (reader, mut writer) = io::pipe()?; + /// let mut stdin = io::stdin(); + /// stdin.set_fd(reader)?; + /// writer.write_all(b"Hello, world!")?; + /// let mut buffer = vec![0; 13]; + /// assert_eq!(stdin.read(&mut buffer)?, 13); + /// assert_eq!(&buffer, b"Hello, world!"); + /// Ok(()) + /// } + /// ``` + fn set_fd>(&mut self, fd: T) -> io::Result<()>; + + /// Redirects the stdio file descriptor and returns a new `OwnedFd` + /// backed by the previous file description. + /// + /// See [`set_fd()`] for details. + /// + /// [`set_fd()`]: StdioExt::set_fd + fn replace_fd>(&mut self, replace_with: T) -> io::Result; + + /// Redirects the stdio file descriptor to the null device (`/dev/null`) + /// and returns a new `OwnedFd` backed by the previous file description. + /// + /// Programs that communicate structured data via stdio can use this early in `main()` to + /// extract the fds, treat them as other IO types (`File`, `UnixStream`, etc), + /// apply custom buffering or avoid interference from stdio use later in the program. + /// + /// See [`set_fd()`] for additional details. + /// + /// [`set_fd()`]: StdioExt::set_fd + fn take_fd(&mut self) -> io::Result; +} + +macro io_ext_impl($stdio_ty:ty, $stdio_lock_ty:ty, $writer:literal) { + #[unstable(feature = "stdio_swap", issue = "150667", reason = "recently added")] + impl StdioExt for $stdio_ty { + fn set_fd>(&mut self, fd: T) -> io::Result<()> { + self.lock().set_fd(fd) + } + + fn take_fd(&mut self) -> io::Result { + self.lock().take_fd() + } + + fn replace_fd>(&mut self, replace_with: T) -> io::Result { + self.lock().replace_fd(replace_with) + } + } + + #[unstable(feature = "stdio_swap", issue = "150667", reason = "recently added")] + impl StdioExt for $stdio_lock_ty { + fn set_fd>(&mut self, fd: T) -> io::Result<()> { + #[cfg($writer)] + self.flush()?; + replace_stdio_fd(self.as_fd(), fd.into()) + } + + fn take_fd(&mut self) -> io::Result { + let null = null_fd()?; + let cloned = self.as_fd().try_clone_to_owned()?; + self.set_fd(null)?; + Ok(cloned) + } + + fn replace_fd>(&mut self, replace_with: T) -> io::Result { + let cloned = self.as_fd().try_clone_to_owned()?; + self.set_fd(replace_with)?; + Ok(cloned) + } + } +} + +io_ext_impl!(Stdout, StdoutLock<'_>, true); +io_ext_impl!(Stdin, StdinLock<'_>, false); +io_ext_impl!(Stderr, StderrLock<'_>, true); + +fn null_fd() -> io::Result { + let null_dev = crate::fs::OpenOptions::new().read(true).write(true).open("/dev/null")?; + Ok(null_dev.into()) +} + +/// Replaces the underlying file descriptor with the one from `other`. +/// Does not set CLOEXEC. +fn replace_stdio_fd(this: BorrowedFd<'_>, other: OwnedFd) -> io::Result<()> { + cfg_select! { + all(target_os = "wasi", target_env = "p1") => { + cvt(unsafe { libc::__wasilibc_fd_renumber(other.as_raw_fd(), this.as_raw_fd()) }).map(|_| ()) + } + not(any( + target_arch = "wasm32", + target_os = "hermit", + target_os = "trusty", + target_os = "motor" + )) => { + cvt(unsafe {libc::dup2(other.as_raw_fd(), this.as_raw_fd())}).map(|_| ()) + } + _ => { + let _ = (this, other); + Err(io::Error::UNSUPPORTED_PLATFORM) + } + } +} From 630c7596e959e6ab9b18552e81081e5ff346b1c3 Mon Sep 17 00:00:00 2001 From: kulst Date: Thu, 1 Jan 2026 19:25:29 +0100 Subject: [PATCH 0307/1061] Ensure that static initializers are acyclic for NVPTX NVPTX does not support cycles in static initializers. LLVM produces an error when attempting to codegen such constructs (like self referential structs). To not produce LLVM UB we instead emit a post-monomorphization error on Rust side before reaching codegen. This is achieved by analysing a subgraph of the "mono item graph" that only contains statics: 1. Calculate the strongly connected components (SCCs) of the graph 2. Check for cycles (more than one node in a SCC or exactly one node which references itself) --- Cargo.lock | 1 + compiler/rustc_monomorphize/Cargo.toml | 1 + compiler/rustc_monomorphize/messages.ftl | 4 + compiler/rustc_monomorphize/src/collector.rs | 3 +- compiler/rustc_monomorphize/src/errors.rs | 12 ++ .../src/graph_checks/mod.rs | 18 +++ .../src/graph_checks/statics.rs | 115 ++++++++++++++++++ compiler/rustc_monomorphize/src/lib.rs | 1 + .../rustc_monomorphize/src/partitioning.rs | 3 + compiler/rustc_target/src/spec/json.rs | 3 + compiler/rustc_target/src/spec/mod.rs | 4 + .../src/spec/targets/nvptx64_nvidia_cuda.rs | 3 + .../platform-support/nvptx64-nvidia-cuda.md | 33 +++++ tests/auxiliary/minicore.rs | 2 +- ...static-initializer-acyclic-issue-146787.rs | 29 +++++ ...ic-initializer-acyclic-issue-146787.stderr | 32 +++++ 16 files changed, 262 insertions(+), 2 deletions(-) create mode 100644 compiler/rustc_monomorphize/src/graph_checks/mod.rs create mode 100644 compiler/rustc_monomorphize/src/graph_checks/statics.rs create mode 100644 tests/ui/static/static-initializer-acyclic-issue-146787.rs create mode 100644 tests/ui/static/static-initializer-acyclic-issue-146787.stderr diff --git a/Cargo.lock b/Cargo.lock index 816bb1a37859..d0d47f882a89 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4421,6 +4421,7 @@ dependencies = [ "rustc_errors", "rustc_fluent_macro", "rustc_hir", + "rustc_index", "rustc_macros", "rustc_middle", "rustc_session", diff --git a/compiler/rustc_monomorphize/Cargo.toml b/compiler/rustc_monomorphize/Cargo.toml index 09a55f0b5f8d..0829d52283ab 100644 --- a/compiler/rustc_monomorphize/Cargo.toml +++ b/compiler/rustc_monomorphize/Cargo.toml @@ -10,6 +10,7 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } +rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl index edb91d8f2eda..09500ba73359 100644 --- a/compiler/rustc_monomorphize/messages.ftl +++ b/compiler/rustc_monomorphize/messages.ftl @@ -75,4 +75,8 @@ monomorphize_recursion_limit = monomorphize_start_not_found = using `fn main` requires the standard library .help = use `#![no_main]` to bypass the Rust generated entrypoint and declare a platform specific entrypoint yourself, usually with `#[no_mangle]` +monomorphize_static_initializer_cyclic = static initializer forms a cycle involving `{$head}` + .label = part of this cycle + .note = cyclic static initializers are not supported for target `{$target}` + monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 4b2f8e03afc1..070db1ae6b5e 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -267,7 +267,8 @@ pub(crate) struct UsageMap<'tcx> { // Maps every mono item to the mono items used by it. pub used_map: UnordMap, Vec>>, - // Maps every mono item to the mono items that use it. + // Maps each mono item with users to the mono items that use it. + // Be careful: subsets `used_map`, so unused items are vacant. user_map: UnordMap, Vec>>, } diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index 4949d9ae3922..723649f22117 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -117,3 +117,15 @@ pub(crate) struct AbiRequiredTargetFeature<'a> { /// Whether this is a problem at a call site or at a declaration. pub is_call: bool, } + +#[derive(Diagnostic)] +#[diag(monomorphize_static_initializer_cyclic)] +#[note] +pub(crate) struct StaticInitializerCyclic<'a> { + #[primary_span] + pub span: Span, + #[label] + pub labels: Vec, + pub head: &'a str, + pub target: &'a str, +} diff --git a/compiler/rustc_monomorphize/src/graph_checks/mod.rs b/compiler/rustc_monomorphize/src/graph_checks/mod.rs new file mode 100644 index 000000000000..2b9b7cfff0b2 --- /dev/null +++ b/compiler/rustc_monomorphize/src/graph_checks/mod.rs @@ -0,0 +1,18 @@ +//! Checks that need to operate on the entire mono item graph +use rustc_middle::mir::mono::MonoItem; +use rustc_middle::ty::TyCtxt; + +use crate::collector::UsageMap; +use crate::graph_checks::statics::check_static_initializers_are_acyclic; + +mod statics; + +pub(super) fn target_specific_checks<'tcx, 'a, 'b>( + tcx: TyCtxt<'tcx>, + mono_items: &'a [MonoItem<'tcx>], + usage_map: &'b UsageMap<'tcx>, +) { + if tcx.sess.target.options.static_initializer_must_be_acyclic { + check_static_initializers_are_acyclic(tcx, mono_items, usage_map); + } +} diff --git a/compiler/rustc_monomorphize/src/graph_checks/statics.rs b/compiler/rustc_monomorphize/src/graph_checks/statics.rs new file mode 100644 index 000000000000..a764d307b3d4 --- /dev/null +++ b/compiler/rustc_monomorphize/src/graph_checks/statics.rs @@ -0,0 +1,115 @@ +use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::graph::scc::Sccs; +use rustc_data_structures::graph::{DirectedGraph, Successors}; +use rustc_data_structures::unord::UnordMap; +use rustc_hir::def_id::DefId; +use rustc_index::{Idx, IndexVec, newtype_index}; +use rustc_middle::mir::mono::MonoItem; +use rustc_middle::ty::TyCtxt; + +use crate::collector::UsageMap; +use crate::errors; + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +struct StaticNodeIdx(usize); + +impl Idx for StaticNodeIdx { + fn new(idx: usize) -> Self { + Self(idx) + } + + fn index(self) -> usize { + self.0 + } +} + +impl From for StaticNodeIdx { + fn from(value: usize) -> Self { + StaticNodeIdx(value) + } +} + +newtype_index! { + #[derive(Ord, PartialOrd)] + struct StaticSccIdx {} +} + +// Adjacency-list graph for statics using `StaticNodeIdx` as node type. +// We cannot use `DefId` as the node type directly because each node must be +// represented by an index in the range `0..num_nodes`. +struct StaticRefGraph<'a, 'b, 'tcx> { + // maps from `StaticNodeIdx` to `DefId` and vice versa + statics: &'a FxIndexSet, + // contains for each `MonoItem` the `MonoItem`s it uses + used_map: &'b UnordMap, Vec>>, +} + +impl<'a, 'b, 'tcx> DirectedGraph for StaticRefGraph<'a, 'b, 'tcx> { + type Node = StaticNodeIdx; + + fn num_nodes(&self) -> usize { + self.statics.len() + } +} + +impl<'a, 'b, 'tcx> Successors for StaticRefGraph<'a, 'b, 'tcx> { + fn successors(&self, node_idx: StaticNodeIdx) -> impl Iterator { + let def_id = self.statics[node_idx.index()]; + self.used_map[&MonoItem::Static(def_id)].iter().filter_map(|&mono_item| match mono_item { + MonoItem::Static(def_id) => self.statics.get_index_of(&def_id).map(|idx| idx.into()), + _ => None, + }) + } +} + +pub(super) fn check_static_initializers_are_acyclic<'tcx, 'a, 'b>( + tcx: TyCtxt<'tcx>, + mono_items: &'a [MonoItem<'tcx>], + usage_map: &'b UsageMap<'tcx>, +) { + // Collect statics + let statics: FxIndexSet = mono_items + .iter() + .filter_map(|&mono_item| match mono_item { + MonoItem::Static(def_id) => Some(def_id), + _ => None, + }) + .collect(); + + // If we don't have any statics the check is not necessary + if statics.is_empty() { + return; + } + // Create a subgraph from the mono item graph, which only contains statics + let graph = StaticRefGraph { statics: &statics, used_map: &usage_map.used_map }; + // Calculate its SCCs + let sccs: Sccs = Sccs::new(&graph); + // Group statics by SCCs + let mut nodes_of_sccs: IndexVec> = + IndexVec::from_elem_n(Vec::new(), sccs.num_sccs()); + for i in graph.iter_nodes() { + nodes_of_sccs[sccs.scc(i)].push(i); + } + let is_cyclic = |nodes_of_scc: &[StaticNodeIdx]| -> bool { + match nodes_of_scc.len() { + 0 => false, + 1 => graph.successors(nodes_of_scc[0]).any(|x| x == nodes_of_scc[0]), + 2.. => true, + } + }; + // Emit errors for all cycles + for nodes in nodes_of_sccs.iter_mut().filter(|nodes| is_cyclic(nodes)) { + // We sort the nodes by their Span to have consistent error line numbers + nodes.sort_by_key(|node| tcx.def_span(statics[node.index()])); + + let head_def = statics[nodes[0].index()]; + let head_span = tcx.def_span(head_def); + + tcx.dcx().emit_err(errors::StaticInitializerCyclic { + span: head_span, + labels: nodes.iter().map(|&n| tcx.def_span(statics[n.index()])).collect(), + head: &tcx.def_path_str(head_def), + target: &tcx.sess.target.llvm_target, + }); + } +} diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 8b48cf5a6501..5b4f74ca6a70 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -16,6 +16,7 @@ use rustc_span::ErrorGuaranteed; mod collector; mod errors; +mod graph_checks; mod mono_checks; mod partitioning; mod util; diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 1c8d6db08c31..6a1d64bd28bc 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -124,6 +124,7 @@ use tracing::debug; use crate::collector::{self, MonoItemCollectionStrategy, UsageMap}; use crate::errors::{CouldntDumpMonoStats, SymbolAlreadyDefined}; +use crate::graph_checks::target_specific_checks; struct PartitioningCx<'a, 'tcx> { tcx: TyCtxt<'tcx>, @@ -1125,6 +1126,8 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> MonoItemPartitio }; let (items, usage_map) = collector::collect_crate_mono_items(tcx, collection_strategy); + // Perform checks that need to operate on the entire mono item graph + target_specific_checks(tcx, &items, &usage_map); // If there was an error during collection (e.g. from one of the constants we evaluated), // then we stop here. This way codegen does not have to worry about failing constants. diff --git a/compiler/rustc_target/src/spec/json.rs b/compiler/rustc_target/src/spec/json.rs index a972299deeac..20fbb687b308 100644 --- a/compiler/rustc_target/src/spec/json.rs +++ b/compiler/rustc_target/src/spec/json.rs @@ -163,6 +163,7 @@ impl Target { forward!(relro_level); forward!(archive_format); forward!(allow_asm); + forward!(static_initializer_must_be_acyclic); forward!(main_needs_argc_argv); forward!(has_thread_local); forward!(obj_is_bitcode); @@ -360,6 +361,7 @@ impl ToJson for Target { target_option_val!(relro_level); target_option_val!(archive_format); target_option_val!(allow_asm); + target_option_val!(static_initializer_must_be_acyclic); target_option_val!(main_needs_argc_argv); target_option_val!(has_thread_local); target_option_val!(obj_is_bitcode); @@ -581,6 +583,7 @@ struct TargetSpecJson { relro_level: Option, archive_format: Option>, allow_asm: Option, + static_initializer_must_be_acyclic: Option, main_needs_argc_argv: Option, has_thread_local: Option, obj_is_bitcode: Option, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index b06339f59425..89c9fdc935cc 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2394,6 +2394,9 @@ pub struct TargetOptions { pub archive_format: StaticCow, /// Is asm!() allowed? Defaults to true. pub allow_asm: bool, + /// Static initializers must be acyclic. + /// Defaults to false + pub static_initializer_must_be_acyclic: bool, /// Whether the runtime startup code requires the `main` function be passed /// `argc` and `argv` values. pub main_needs_argc_argv: bool, @@ -2777,6 +2780,7 @@ impl Default for TargetOptions { archive_format: "gnu".into(), main_needs_argc_argv: true, allow_asm: true, + static_initializer_must_be_acyclic: false, has_thread_local: false, obj_is_bitcode: false, min_atomic_width: None, diff --git a/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs index be09681b1f35..87c2693e9877 100644 --- a/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs +++ b/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs @@ -59,6 +59,9 @@ pub(crate) fn target() -> Target { // Support using `self-contained` linkers like the llvm-bitcode-linker link_self_contained: LinkSelfContainedDefault::True, + // Static initializers must not have cycles on this target + static_initializer_must_be_acyclic: true, + ..Default::default() }, } diff --git a/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md b/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md index 0eb7e1d84bd0..c722a7086967 100644 --- a/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md +++ b/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md @@ -49,6 +49,39 @@ $ rustup component add llvm-tools --toolchain nightly $ rustup component add llvm-bitcode-linker --toolchain nightly ``` +## Target specific restrictions + +The PTX instruction set architecture has special requirements regarding what is +and isn't allowed. In order to avoid producing invalid PTX or generating undefined +behavior by LLVM, some Rust language features are disallowed when compiling for this target. + +### Static initializers must be acyclic + +A static's initializer must not form a cycle with itself or another static's +initializer. Therefore, the compiler will reject not only the self-referencing static `A`, +but all of the following statics. + +```Rust +struct Foo(&'static Foo); + +static A: Foo = Foo(&A); //~ ERROR static initializer forms a cycle involving `A` + +static B0: Foo = Foo(&B1); //~ ERROR static initializer forms a cycle involving `B0` +static B1: Foo = Foo(&B0); + +static C0: Foo = Foo(&C1); //~ ERROR static initializer forms a cycle involving `C0` +static C1: Foo = Foo(&C2); +static C2: Foo = Foo(&C0); +``` + +Initializers that are acyclic are allowed: + +```Rust +struct Bar(&'static u32); + +static BAR: Bar = Bar(&INT); // is allowed +static INT: u32 = 42u32; // also allowed +``` $DIR/static-initializer-acyclic-issue-146787.rs:21:1 + | +LL | static C0: Foo = Foo(&C1); + | ^^^^^^^^^^^^^^ part of this cycle +LL | static C1: Foo = Foo(&C2); + | -------------- part of this cycle +LL | static C2: Foo = Foo(&C0); + | -------------- part of this cycle + | + = note: cyclic static initializers are not supported for target `nvptx64-nvidia-cuda` + +error: static initializer forms a cycle involving `B0` + --> $DIR/static-initializer-acyclic-issue-146787.rs:18:1 + | +LL | static B0: Foo = Foo(&B1); + | ^^^^^^^^^^^^^^ part of this cycle +LL | static B1: Foo = Foo(&B0); + | -------------- part of this cycle + | + = note: cyclic static initializers are not supported for target `nvptx64-nvidia-cuda` + +error: static initializer forms a cycle involving `A` + --> $DIR/static-initializer-acyclic-issue-146787.rs:16:1 + | +LL | static A: Foo = Foo(&A); + | ^^^^^^^^^^^^^ part of this cycle + | + = note: cyclic static initializers are not supported for target `nvptx64-nvidia-cuda` + +error: aborting due to 3 previous errors + From f805d1b210b5bd1e765e07903804b7cdea1d48ae Mon Sep 17 00:00:00 2001 From: andjsrk Date: Wed, 7 Jan 2026 01:08:19 +0900 Subject: [PATCH 0308/1061] format --- tests/ui/repeat-expr/can-have-side-effects-consider-element.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/ui/repeat-expr/can-have-side-effects-consider-element.rs b/tests/ui/repeat-expr/can-have-side-effects-consider-element.rs index cd385587d491..d0b5d12455dc 100644 --- a/tests/ui/repeat-expr/can-have-side-effects-consider-element.rs +++ b/tests/ui/repeat-expr/can-have-side-effects-consider-element.rs @@ -5,7 +5,8 @@ // Test if `Expr::can_have_side_effects` considers element of repeat expressions. fn drop_repeat_in_arm_body() { - // Built-in lint `dropping_copy_types` relies on `Expr::can_have_side_effects` (See rust-clippy#9482) + // Built-in lint `dropping_copy_types` relies on + // `Expr::can_have_side_effects` (See rust-clippy#9482) match () { () => drop([0; 1]), // No side effects From c73b64b8c518e055681ba3a35802f2f316b58988 Mon Sep 17 00:00:00 2001 From: andjsrk Date: Wed, 7 Jan 2026 02:02:26 +0900 Subject: [PATCH 0309/1061] update expected output as well --- .../repeat-expr/can-have-side-effects-consider-element.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/repeat-expr/can-have-side-effects-consider-element.stderr b/tests/ui/repeat-expr/can-have-side-effects-consider-element.stderr index 6948d64ebcc3..70c7e8b404e0 100644 --- a/tests/ui/repeat-expr/can-have-side-effects-consider-element.stderr +++ b/tests/ui/repeat-expr/can-have-side-effects-consider-element.stderr @@ -1,5 +1,5 @@ warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing - --> $DIR/can-have-side-effects-consider-element.rs:11:15 + --> $DIR/can-have-side-effects-consider-element.rs:12:15 | LL | () => drop([0; 1]), // No side effects | ^^^^^------^ From d101412517a4fdbb108c193eb1cf5632c89534f3 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Tue, 6 Jan 2026 17:23:16 +0000 Subject: [PATCH 0310/1061] Cleanup some ui tests for const-traits --- tests/ui/const-generics/issues/issue-88119.rs | 3 +- .../const-generics/issues/issue-88119.stderr | 95 ------------------- .../consts/rustc-impl-const-stability.stderr | 11 --- .../ui/specialization/const_trait_impl.stderr | 59 ------------ .../derive-const-non-const-type.rs | 12 +-- .../derive-const-non-const-type.stderr | 21 ++-- .../rustc-impl-const-stability.rs | 9 +- ...fault-bound-non-const-specialized-bound.rs | 8 +- ...t-bound-non-const-specialized-bound.stderr | 8 +- .../const-traits/specialization/pass.rs} | 14 ++- .../specializing-constness-2.rs | 5 +- .../specializing-constness-2.stderr | 2 +- .../specializing-constness.rs | 0 .../specializing-constness.stderr | 0 14 files changed, 35 insertions(+), 212 deletions(-) delete mode 100644 tests/ui/const-generics/issues/issue-88119.stderr delete mode 100644 tests/ui/consts/rustc-impl-const-stability.stderr delete mode 100644 tests/ui/specialization/const_trait_impl.stderr rename tests/ui/{consts => traits/const-traits}/rustc-impl-const-stability.rs (63%) rename tests/ui/{specialization/const_trait_impl.rs => traits/const-traits/specialization/pass.rs} (70%) rename tests/ui/traits/const-traits/{ => specialization}/specializing-constness-2.rs (81%) rename tests/ui/traits/const-traits/{ => specialization}/specializing-constness-2.stderr (88%) rename tests/ui/traits/const-traits/{ => specialization}/specializing-constness.rs (100%) rename tests/ui/traits/const-traits/{ => specialization}/specializing-constness.stderr (100%) diff --git a/tests/ui/const-generics/issues/issue-88119.rs b/tests/ui/const-generics/issues/issue-88119.rs index d44b5ab985b0..fb279dd824f8 100644 --- a/tests/ui/const-generics/issues/issue-88119.rs +++ b/tests/ui/const-generics/issues/issue-88119.rs @@ -1,5 +1,4 @@ -//@ known-bug: #110395 -//@ compile-flags: -Znext-solver +//@ check-pass #![allow(incomplete_features)] #![feature(const_trait_impl, generic_const_exprs)] diff --git a/tests/ui/const-generics/issues/issue-88119.stderr b/tests/ui/const-generics/issues/issue-88119.stderr deleted file mode 100644 index 0bdf153468bc..000000000000 --- a/tests/ui/const-generics/issues/issue-88119.stderr +++ /dev/null @@ -1,95 +0,0 @@ -error: `-Znext-solver=globally` and `generic_const_exprs` are incompatible, using them at the same time is not allowed - --> $DIR/issue-88119.rs:4:30 - | -LL | #![feature(const_trait_impl, generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ - | - = help: remove one of these features - -error[E0275]: overflow evaluating the requirement `&T: [const] ConstName` - --> $DIR/issue-88119.rs:18:49 - | -LL | impl const ConstName for &T - | ^^ - -error[E0275]: overflow evaluating the requirement `&T: ConstName` - --> $DIR/issue-88119.rs:18:49 - | -LL | impl const ConstName for &T - | ^^ - -error[E0275]: overflow evaluating the requirement `[(); name_len::()] well-formed` - --> $DIR/issue-88119.rs:20:5 - | -LL | [(); name_len::()]:, - | ^^^^^^^^^^^^^^^^^^^^^ - | -note: required by a bound in `<&T as ConstName>` - --> $DIR/issue-88119.rs:20:5 - | -LL | [(); name_len::()]:, - | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<&T as ConstName>` - -error[E0275]: overflow evaluating the requirement `[(); name_len::()] well-formed` - --> $DIR/issue-88119.rs:20:10 - | -LL | [(); name_len::()]:, - | ^^^^^^^^^^^^^^^ - | -note: required by a bound in `<&T as ConstName>` - --> $DIR/issue-88119.rs:20:5 - | -LL | [(); name_len::()]:, - | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<&T as ConstName>` - -error[E0275]: overflow evaluating the requirement `&mut T: [const] ConstName` - --> $DIR/issue-88119.rs:25:49 - | -LL | impl const ConstName for &mut T - | ^^^^^^ - -error[E0275]: overflow evaluating the requirement `&mut T: ConstName` - --> $DIR/issue-88119.rs:25:49 - | -LL | impl const ConstName for &mut T - | ^^^^^^ - -error[E0275]: overflow evaluating the requirement `[(); name_len::()] well-formed` - --> $DIR/issue-88119.rs:27:5 - | -LL | [(); name_len::()]:, - | ^^^^^^^^^^^^^^^^^^^^^ - | -note: required by a bound in `<&mut T as ConstName>` - --> $DIR/issue-88119.rs:27:5 - | -LL | [(); name_len::()]:, - | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<&mut T as ConstName>` - -error[E0275]: overflow evaluating the requirement `[(); name_len::()] well-formed` - --> $DIR/issue-88119.rs:27:10 - | -LL | [(); name_len::()]:, - | ^^^^^^^^^^^^^^^ - | -note: required by a bound in `<&mut T as ConstName>` - --> $DIR/issue-88119.rs:27:5 - | -LL | [(); name_len::()]:, - | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<&mut T as ConstName>` - -error[E0275]: overflow evaluating the requirement `&&mut u8: ConstName` - --> $DIR/issue-88119.rs:32:35 - | -LL | pub const ICE_1: &'static [u8] = <&&mut u8 as ConstName>::NAME_BYTES; - | ^^^^^^^^ - -error[E0275]: overflow evaluating the requirement `&mut &u8: ConstName` - --> $DIR/issue-88119.rs:33:35 - | -LL | pub const ICE_2: &'static [u8] = <&mut &u8 as ConstName>::NAME_BYTES; - | ^^^^^^^^ - -error: aborting due to 11 previous errors - -For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/consts/rustc-impl-const-stability.stderr b/tests/ui/consts/rustc-impl-const-stability.stderr deleted file mode 100644 index 55c085396882..000000000000 --- a/tests/ui/consts/rustc-impl-const-stability.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error: const `impl` for trait `Debug` which is not `const` - --> $DIR/rustc-impl-const-stability.rs:15:12 - | -LL | impl const std::fmt::Debug for Data { - | ^^^^^^^^^^^^^^^ this trait is not `const` - | - = note: marking a trait with `const` ensures all default method bodies are `const` - = note: adding a non-const method body in the future would be a breaking change - -error: aborting due to 1 previous error - diff --git a/tests/ui/specialization/const_trait_impl.stderr b/tests/ui/specialization/const_trait_impl.stderr deleted file mode 100644 index 93ed7234e563..000000000000 --- a/tests/ui/specialization/const_trait_impl.stderr +++ /dev/null @@ -1,59 +0,0 @@ -error: `[const]` can only be applied to `const` traits - --> $DIR/const_trait_impl.rs:33:9 - | -LL | impl const A for T { - | ^^^^^^^ can't be applied to `Debug` - | -note: `Debug` can't be used with `[const]` because it isn't `const` - --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL - -error: `[const]` can only be applied to `const` traits - --> $DIR/const_trait_impl.rs:39:9 - | -LL | impl const A for T { - | ^^^^^^^ can't be applied to `Debug` - | -note: `Debug` can't be used with `[const]` because it isn't `const` - --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL - -error: `[const]` can only be applied to `const` traits - --> $DIR/const_trait_impl.rs:45:9 - | -LL | impl const A for T { - | ^^^^^^^ can't be applied to `Debug` - | -note: `Debug` can't be used with `[const]` because it isn't `const` - --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL - -error: `[const]` can only be applied to `const` traits - --> $DIR/const_trait_impl.rs:39:9 - | -LL | impl const A for T { - | ^^^^^^^ can't be applied to `Debug` - | -note: `Debug` can't be used with `[const]` because it isn't `const` - --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `[const]` can only be applied to `const` traits - --> $DIR/const_trait_impl.rs:33:9 - | -LL | impl const A for T { - | ^^^^^^^ can't be applied to `Debug` - | -note: `Debug` can't be used with `[const]` because it isn't `const` - --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `[const]` can only be applied to `const` traits - --> $DIR/const_trait_impl.rs:45:9 - | -LL | impl const A for T { - | ^^^^^^^ can't be applied to `Debug` - | -note: `Debug` can't be used with `[const]` because it isn't `const` - --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 6 previous errors - diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.rs b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.rs index 0bc25ce5f650..e61ae2760aab 100644 --- a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.rs +++ b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.rs @@ -1,15 +1,15 @@ -//@ known-bug: #110395 -#![feature(derive_const)] +#![feature(const_default, derive_const)] pub struct A; -impl std::fmt::Debug for A { - fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - panic!() +impl Default for A { + fn default() -> A { + A } } -#[derive_const(Debug)] +#[derive_const(Default)] pub struct S(A); +//~^ ERROR: cannot call non-const associated function fn main() {} diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr index 93638801895d..558957985328 100644 --- a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr +++ b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr @@ -1,20 +1,13 @@ -error: const `impl` for trait `Debug` which is not `const` - --> $DIR/derive-const-non-const-type.rs:12:16 +error[E0015]: cannot call non-const associated function `::default` in constant functions + --> $DIR/derive-const-non-const-type.rs:12:14 | -LL | #[derive_const(Debug)] - | ^^^^^ this trait is not `const` - | - = note: marking a trait with `const` ensures all default method bodies are `const` - = note: adding a non-const method body in the future would be a breaking change - -error[E0015]: cannot call non-const method `Formatter::<'_>::debug_tuple_field1_finish` in constant functions - --> $DIR/derive-const-non-const-type.rs:12:16 - | -LL | #[derive_const(Debug)] - | ^^^^^ +LL | #[derive_const(Default)] + | ------- in this derive macro expansion +LL | pub struct S(A); + | ^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/rustc-impl-const-stability.rs b/tests/ui/traits/const-traits/rustc-impl-const-stability.rs similarity index 63% rename from tests/ui/consts/rustc-impl-const-stability.rs rename to tests/ui/traits/const-traits/rustc-impl-const-stability.rs index 93a5e8e4f458..7d30342d11ca 100644 --- a/tests/ui/consts/rustc-impl-const-stability.rs +++ b/tests/ui/traits/const-traits/rustc-impl-const-stability.rs @@ -1,5 +1,4 @@ -//@ compile-flags: -Znext-solver -//@ known-bug: #110395 +//@ check-pass #![crate_type = "lib"] #![feature(staged_api, const_trait_impl, const_default)] @@ -12,8 +11,8 @@ pub struct Data { #[stable(feature = "potato", since = "1.27.0")] #[rustc_const_unstable(feature = "data_foo", issue = "none")] -impl const std::fmt::Debug for Data { - fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - Ok(()) +impl const Default for Data { + fn default() -> Data { + Data { _data: 0xbeef } } } diff --git a/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.rs b/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.rs index 5125d2580238..f771107ec068 100644 --- a/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.rs +++ b/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.rs @@ -1,7 +1,5 @@ // Tests that trait bounds on specializing trait impls must be `[const]` if the // same bound is present on the default impl and is `[const]` there. -//@ known-bug: #110395 -// FIXME(const_trait_impl) ^ should error #![feature(const_trait_impl)] #![feature(rustc_attrs)] @@ -23,9 +21,9 @@ where default fn bar() {} } -impl Bar for T +impl Bar for T //~ ERROR conflicting implementations of trait `Bar` where - T: Foo, //FIXME ~ ERROR missing `[const]` qualifier + T: Foo, T: Specialize, { fn bar() {} @@ -42,7 +40,7 @@ where default fn baz() {} } -impl const Baz for T //FIXME ~ ERROR conflicting implementations of trait `Baz` +impl const Baz for T //~ ERROR conflicting implementations of trait `Baz` where T: Foo, T: Specialize, diff --git a/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr b/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr index 85e9fda5c2a3..ff27559c8ec6 100644 --- a/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr +++ b/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `Bar` - --> $DIR/const-default-bound-non-const-specialized-bound.rs:26:1 + --> $DIR/const-default-bound-non-const-specialized-bound.rs:24:1 | LL | / impl const Bar for T LL | | where @@ -8,19 +8,19 @@ LL | | T: [const] Foo, ... LL | / impl Bar for T LL | | where -LL | | T: Foo, //FIXME ~ ERROR missing `[const]` qualifier +LL | | T: Foo, LL | | T: Specialize, | |__________________^ conflicting implementation error[E0119]: conflicting implementations of trait `Baz` - --> $DIR/const-default-bound-non-const-specialized-bound.rs:45:1 + --> $DIR/const-default-bound-non-const-specialized-bound.rs:43:1 | LL | / impl const Baz for T LL | | where LL | | T: [const] Foo, | |___________________- first implementation here ... -LL | / impl const Baz for T //FIXME ~ ERROR conflicting implementations of trait `Baz` +LL | / impl const Baz for T LL | | where LL | | T: Foo, LL | | T: Specialize, diff --git a/tests/ui/specialization/const_trait_impl.rs b/tests/ui/traits/const-traits/specialization/pass.rs similarity index 70% rename from tests/ui/specialization/const_trait_impl.rs rename to tests/ui/traits/const-traits/specialization/pass.rs index adfef77a15ca..0ba4e40ee30a 100644 --- a/tests/ui/specialization/const_trait_impl.rs +++ b/tests/ui/traits/const-traits/specialization/pass.rs @@ -1,8 +1,6 @@ -//@ known-bug: #110395 - -#![feature(const_trait_impl, min_specialization, rustc_attrs)] - -use std::fmt::Debug; +//@ check-pass +#![feature(const_trait_impl, const_default, min_specialization, rustc_attrs)] +#![allow(internal_features)] #[rustc_specialization_trait] pub const unsafe trait Sup { @@ -30,19 +28,19 @@ pub const trait A { fn a() -> u32; } -impl const A for T { +impl const A for T { default fn a() -> u32 { 2 } } -impl const A for T { +impl const A for T { default fn a() -> u32 { 3 } } -impl const A for T { +impl const A for T { fn a() -> u32 { T::foo() } diff --git a/tests/ui/traits/const-traits/specializing-constness-2.rs b/tests/ui/traits/const-traits/specialization/specializing-constness-2.rs similarity index 81% rename from tests/ui/traits/const-traits/specializing-constness-2.rs rename to tests/ui/traits/const-traits/specialization/specializing-constness-2.rs index 455dd111603d..78cfbe361d91 100644 --- a/tests/ui/traits/const-traits/specializing-constness-2.rs +++ b/tests/ui/traits/const-traits/specialization/specializing-constness-2.rs @@ -1,5 +1,6 @@ #![feature(const_trait_impl, min_specialization, rustc_attrs)] -//@ known-bug: #110395 +#![allow(internal_features)] + #[rustc_specialization_trait] pub const trait Sup {} @@ -23,7 +24,7 @@ impl const A for T { const fn generic() { ::a(); - //FIXME ~^ ERROR: the trait bound `T: [const] Sup` is not satisfied + //~^ ERROR: the trait bound `T: [const] A` is not satisfied } fn main() {} diff --git a/tests/ui/traits/const-traits/specializing-constness-2.stderr b/tests/ui/traits/const-traits/specialization/specializing-constness-2.stderr similarity index 88% rename from tests/ui/traits/const-traits/specializing-constness-2.stderr rename to tests/ui/traits/const-traits/specialization/specializing-constness-2.stderr index bd6ffa544d0e..bb1c9ac78531 100644 --- a/tests/ui/traits/const-traits/specializing-constness-2.stderr +++ b/tests/ui/traits/const-traits/specialization/specializing-constness-2.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `T: [const] A` is not satisfied - --> $DIR/specializing-constness-2.rs:25:6 + --> $DIR/specializing-constness-2.rs:26:6 | LL | ::a(); | ^ diff --git a/tests/ui/traits/const-traits/specializing-constness.rs b/tests/ui/traits/const-traits/specialization/specializing-constness.rs similarity index 100% rename from tests/ui/traits/const-traits/specializing-constness.rs rename to tests/ui/traits/const-traits/specialization/specializing-constness.rs diff --git a/tests/ui/traits/const-traits/specializing-constness.stderr b/tests/ui/traits/const-traits/specialization/specializing-constness.stderr similarity index 100% rename from tests/ui/traits/const-traits/specializing-constness.stderr rename to tests/ui/traits/const-traits/specialization/specializing-constness.stderr From 064b95ed04dca45f583c96001ef3b9eaa953fc3a Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Sat, 27 Dec 2025 22:37:19 +0000 Subject: [PATCH 0311/1061] Allow `expect` on `impl` for `derive_ord_xor_partial_ord` --- .../src/derive/derive_ord_xor_partial_ord.rs | 9 ++++++--- clippy_lints/src/derive/mod.rs | 2 +- tests/ui/derive_ord_xor_partial_ord.rs | 14 ++++++++++++++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/derive/derive_ord_xor_partial_ord.rs b/clippy_lints/src/derive/derive_ord_xor_partial_ord.rs index 2bd5e2cbfb1a..316d800a70c9 100644 --- a/clippy_lints/src/derive/derive_ord_xor_partial_ord.rs +++ b/clippy_lints/src/derive/derive_ord_xor_partial_ord.rs @@ -1,15 +1,16 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; +use clippy_utils::fulfill_or_allowed; use rustc_hir::{self as hir, HirId}; use rustc_lint::LateContext; use rustc_middle::ty::Ty; -use rustc_span::{Span, sym}; +use rustc_span::sym; use super::DERIVE_ORD_XOR_PARTIAL_ORD; /// Implementation of the `DERIVE_ORD_XOR_PARTIAL_ORD` lint. pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, - span: Span, + item: &hir::Item<'_>, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>, adt_hir_id: HirId, @@ -19,6 +20,8 @@ pub(super) fn check<'tcx>( && let Some(partial_ord_trait_def_id) = cx.tcx.lang_items().partial_ord_trait() && let Some(def_id) = &trait_ref.trait_def_id() && *def_id == ord_trait_def_id + && let item_hir_id = cx.tcx.local_def_id_to_hir_id(item.owner_id) + && !fulfill_or_allowed(cx, DERIVE_ORD_XOR_PARTIAL_ORD, [adt_hir_id]) { // Look for the PartialOrd implementations for `ty` cx.tcx.for_each_relevant_impl(partial_ord_trait_def_id, ty, |impl_id| { @@ -39,7 +42,7 @@ pub(super) fn check<'tcx>( "you are deriving `Ord` but have implemented `PartialOrd` explicitly" }; - span_lint_hir_and_then(cx, DERIVE_ORD_XOR_PARTIAL_ORD, adt_hir_id, span, mess, |diag| { + span_lint_hir_and_then(cx, DERIVE_ORD_XOR_PARTIAL_ORD, item_hir_id, item.span, mess, |diag| { if let Some(local_def_id) = impl_id.as_local() { let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id); diag.span_note(cx.tcx.hir_span(hir_id), "`PartialOrd` implemented here"); diff --git a/clippy_lints/src/derive/mod.rs b/clippy_lints/src/derive/mod.rs index eafe7c4bb9f2..86614201c406 100644 --- a/clippy_lints/src/derive/mod.rs +++ b/clippy_lints/src/derive/mod.rs @@ -208,7 +208,7 @@ impl<'tcx> LateLintPass<'tcx> for Derive { let is_automatically_derived = cx.tcx.is_automatically_derived(item.owner_id.to_def_id()); derived_hash_with_manual_eq::check(cx, item.span, trait_ref, ty, adt_hir_id, is_automatically_derived); - derive_ord_xor_partial_ord::check(cx, item.span, trait_ref, ty, adt_hir_id, is_automatically_derived); + derive_ord_xor_partial_ord::check(cx, item, trait_ref, ty, adt_hir_id, is_automatically_derived); if is_automatically_derived { unsafe_derive_deserialize::check(cx, item, trait_ref, ty, adt_hir_id); diff --git a/tests/ui/derive_ord_xor_partial_ord.rs b/tests/ui/derive_ord_xor_partial_ord.rs index b4bb24b0d2fe..386ab39401c5 100644 --- a/tests/ui/derive_ord_xor_partial_ord.rs +++ b/tests/ui/derive_ord_xor_partial_ord.rs @@ -91,3 +91,17 @@ mod issue15708 { } } } + +mod issue16298 { + #[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)] + struct Normalized(S); + + impl Eq for Normalized {} + + #[expect(clippy::derive_ord_xor_partial_ord)] + impl Ord for Normalized { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.partial_cmp(other).unwrap() + } + } +} From 1f207edc5a646a6c4d98f929423974bbe3a1cb5e Mon Sep 17 00:00:00 2001 From: keir Date: Wed, 17 Dec 2025 19:04:50 +0530 Subject: [PATCH 0312/1061] fix(useless_conversion): stop adjustments when target type is reached --- clippy_lints/src/useless_conversion.rs | 14 ++- tests/ui/useless_conversion.fixed | 10 ++ tests/ui/useless_conversion.rs | 10 ++ tests/ui/useless_conversion.stderr | 135 ++++++++++++++----------- 4 files changed, 109 insertions(+), 60 deletions(-) diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index c06313d1a4c4..423301edfe83 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -456,13 +456,25 @@ fn has_eligible_receiver(cx: &LateContext<'_>, recv: &Expr<'_>, expr: &Expr<'_>) fn adjustments(cx: &LateContext<'_>, expr: &Expr<'_>) -> String { let mut prefix = String::new(); - for adj in cx.typeck_results().expr_adjustments(expr) { + + let adjustments = cx.typeck_results().expr_adjustments(expr); + + let [.., last] = adjustments else { return prefix }; + let target = last.target; + + for adj in adjustments { match adj.kind { Adjust::Deref(_) => prefix = format!("*{prefix}"), Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Mut { .. })) => prefix = format!("&mut {prefix}"), Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Not)) => prefix = format!("&{prefix}"), _ => {}, } + + // Stop once we reach the final target type. + // This prevents over-adjusting (e.g. suggesting &**y instead of *y). + if adj.target == target { + break; + } } prefix } diff --git a/tests/ui/useless_conversion.fixed b/tests/ui/useless_conversion.fixed index adf5e58d9a1a..4832e922fa8e 100644 --- a/tests/ui/useless_conversion.fixed +++ b/tests/ui/useless_conversion.fixed @@ -1,4 +1,5 @@ #![deny(clippy::useless_conversion)] +#![allow(clippy::into_iter_on_ref)] #![allow(clippy::needless_ifs, clippy::unnecessary_wraps, unused)] // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint #![allow(static_mut_refs)] @@ -131,6 +132,15 @@ fn main() { dont_lint_into_iter_on_copy_iter(); dont_lint_into_iter_on_static_copy_iter(); + { + // triggers the IntoIterator trait + fn consume(_: impl IntoIterator) {} + + // Should suggest `*items` instead of `&**items` + let items = &&[1, 2, 3]; + consume(*items); //~ useless_conversion + } + let _: String = "foo".into(); let _: String = From::from("foo"); let _ = String::from("foo"); diff --git a/tests/ui/useless_conversion.rs b/tests/ui/useless_conversion.rs index d95fe49e2e2b..6ef1f93a5606 100644 --- a/tests/ui/useless_conversion.rs +++ b/tests/ui/useless_conversion.rs @@ -1,4 +1,5 @@ #![deny(clippy::useless_conversion)] +#![allow(clippy::into_iter_on_ref)] #![allow(clippy::needless_ifs, clippy::unnecessary_wraps, unused)] // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint #![allow(static_mut_refs)] @@ -131,6 +132,15 @@ fn main() { dont_lint_into_iter_on_copy_iter(); dont_lint_into_iter_on_static_copy_iter(); + { + // triggers the IntoIterator trait + fn consume(_: impl IntoIterator) {} + + // Should suggest `*items` instead of `&**items` + let items = &&[1, 2, 3]; + consume(items.into_iter()); //~ useless_conversion + } + let _: String = "foo".into(); let _: String = From::from("foo"); let _ = String::from("foo"); diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr index 052c664f6f2e..d28b7a5cbfb6 100644 --- a/tests/ui/useless_conversion.stderr +++ b/tests/ui/useless_conversion.stderr @@ -1,5 +1,5 @@ error: useless conversion to the same type: `T` - --> tests/ui/useless_conversion.rs:9:13 + --> tests/ui/useless_conversion.rs:10:13 | LL | let _ = T::from(val); | ^^^^^^^^^^^^ help: consider removing `T::from()`: `val` @@ -11,115 +11,132 @@ LL | #![deny(clippy::useless_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: useless conversion to the same type: `T` - --> tests/ui/useless_conversion.rs:11:5 + --> tests/ui/useless_conversion.rs:12:5 | LL | val.into() | ^^^^^^^^^^ help: consider removing `.into()`: `val` error: useless conversion to the same type: `i32` - --> tests/ui/useless_conversion.rs:24:22 + --> tests/ui/useless_conversion.rs:25:22 | LL | let _: i32 = 0i32.into(); | ^^^^^^^^^^^ help: consider removing `.into()`: `0i32` error: useless conversion to the same type: `std::str::Lines<'_>` - --> tests/ui/useless_conversion.rs:55:22 + --> tests/ui/useless_conversion.rs:56:22 | LL | if Some("ok") == lines.into_iter().next() {} | ^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `lines` error: useless conversion to the same type: `std::str::Lines<'_>` - --> tests/ui/useless_conversion.rs:61:21 + --> tests/ui/useless_conversion.rs:62:21 | LL | let mut lines = text.lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()` error: useless conversion to the same type: `std::str::Lines<'_>` - --> tests/ui/useless_conversion.rs:68:22 + --> tests/ui/useless_conversion.rs:69:22 | LL | if Some("ok") == text.lines().into_iter().next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()` error: useless conversion to the same type: `std::ops::Range` - --> tests/ui/useless_conversion.rs:75:13 + --> tests/ui/useless_conversion.rs:76:13 | LL | let _ = NUMBERS.into_iter().next(); | ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS` error: useless conversion to the same type: `std::ops::Range` - --> tests/ui/useless_conversion.rs:81:17 + --> tests/ui/useless_conversion.rs:82:17 | LL | let mut n = NUMBERS.into_iter(); | ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS` +error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` + --> tests/ui/useless_conversion.rs:141:17 + | +LL | consume(items.into_iter()); + | ^^^^^^^^^^^^^^^^^ + | +note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` + --> tests/ui/useless_conversion.rs:137:28 + | +LL | fn consume(_: impl IntoIterator) {} + | ^^^^^^^^^^^^ +help: consider removing the `.into_iter()` + | +LL - consume(items.into_iter()); +LL + consume(*items); + | + error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:144:21 + --> tests/ui/useless_conversion.rs:154:21 | LL | let _: String = "foo".to_string().into(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:146:21 + --> tests/ui/useless_conversion.rs:156:21 | LL | let _: String = From::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:148:13 + --> tests/ui/useless_conversion.rs:158:13 | LL | let _ = String::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:150:13 + --> tests/ui/useless_conversion.rs:160:13 | LL | let _ = String::from(format!("A: {:04}", 123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)` error: useless conversion to the same type: `std::str::Lines<'_>` - --> tests/ui/useless_conversion.rs:152:13 + --> tests/ui/useless_conversion.rs:162:13 | LL | let _ = "".lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()` error: useless conversion to the same type: `std::vec::IntoIter` - --> tests/ui/useless_conversion.rs:154:13 + --> tests/ui/useless_conversion.rs:164:13 | LL | let _ = vec![1, 2, 3].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:156:21 + --> tests/ui/useless_conversion.rs:166:21 | LL | let _: String = format!("Hello {}", "world").into(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")` error: useless conversion to the same type: `i32` - --> tests/ui/useless_conversion.rs:162:13 + --> tests/ui/useless_conversion.rs:172:13 | LL | let _ = i32::from(a + b) * 3; | ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)` error: useless conversion to the same type: `Foo<'a'>` - --> tests/ui/useless_conversion.rs:169:23 + --> tests/ui/useless_conversion.rs:179:23 | LL | let _: Foo<'a'> = s2.into(); | ^^^^^^^^^ help: consider removing `.into()`: `s2` error: useless conversion to the same type: `Foo<'a'>` - --> tests/ui/useless_conversion.rs:172:13 + --> tests/ui/useless_conversion.rs:182:13 | LL | let _ = Foo::<'a'>::from(s3); | ^^^^^^^^^^^^^^^^^^^^ help: consider removing `Foo::<'a'>::from()`: `s3` error: useless conversion to the same type: `std::vec::IntoIter>` - --> tests/ui/useless_conversion.rs:175:13 + --> tests/ui/useless_conversion.rs:185:13 | LL | let _ = vec![s4, s4, s4].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![s4, s4, s4].into_iter()` error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:208:7 + --> tests/ui/useless_conversion.rs:218:7 | LL | b(vec![1, 2].into_iter()); | ^^^^^^^^^^------------ @@ -127,13 +144,13 @@ LL | b(vec![1, 2].into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:198:13 + --> tests/ui/useless_conversion.rs:208:13 | LL | fn b>(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:210:7 + --> tests/ui/useless_conversion.rs:220:7 | LL | c(vec![1, 2].into_iter()); | ^^^^^^^^^^------------ @@ -141,13 +158,13 @@ LL | c(vec![1, 2].into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:199:18 + --> tests/ui/useless_conversion.rs:209:18 | LL | fn c(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:212:7 + --> tests/ui/useless_conversion.rs:222:7 | LL | d(vec![1, 2].into_iter()); | ^^^^^^^^^^------------ @@ -155,13 +172,13 @@ LL | d(vec![1, 2].into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:202:12 + --> tests/ui/useless_conversion.rs:212:12 | LL | T: IntoIterator, | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:216:7 + --> tests/ui/useless_conversion.rs:226:7 | LL | b(vec![1, 2].into_iter().into_iter()); | ^^^^^^^^^^------------------------ @@ -169,13 +186,13 @@ LL | b(vec![1, 2].into_iter().into_iter()); | help: consider removing the `.into_iter()`s | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:198:13 + --> tests/ui/useless_conversion.rs:208:13 | LL | fn b>(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:218:7 + --> tests/ui/useless_conversion.rs:228:7 | LL | b(vec![1, 2].into_iter().into_iter().into_iter()); | ^^^^^^^^^^------------------------------------ @@ -183,13 +200,13 @@ LL | b(vec![1, 2].into_iter().into_iter().into_iter()); | help: consider removing the `.into_iter()`s | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:198:13 + --> tests/ui/useless_conversion.rs:208:13 | LL | fn b>(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:265:24 + --> tests/ui/useless_conversion.rs:275:24 | LL | foo2::([1, 2, 3].into_iter()); | ^^^^^^^^^------------ @@ -197,13 +214,13 @@ LL | foo2::([1, 2, 3].into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:244:12 + --> tests/ui/useless_conversion.rs:254:12 | LL | I: IntoIterator + Helper, | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:274:14 + --> tests/ui/useless_conversion.rs:284:14 | LL | foo3([1, 2, 3].into_iter()); | ^^^^^^^^^------------ @@ -211,13 +228,13 @@ LL | foo3([1, 2, 3].into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:253:12 + --> tests/ui/useless_conversion.rs:263:12 | LL | I: IntoIterator, | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:284:16 + --> tests/ui/useless_conversion.rs:294:16 | LL | S1.foo([1, 2].into_iter()); | ^^^^^^------------ @@ -225,13 +242,13 @@ LL | S1.foo([1, 2].into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:281:27 + --> tests/ui/useless_conversion.rs:291:27 | LL | pub fn foo(&self, _: I) {} | ^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:304:44 + --> tests/ui/useless_conversion.rs:314:44 | LL | v0.into_iter().interleave_shortest(v1.into_iter()); | ^^------------ @@ -239,67 +256,67 @@ LL | v0.into_iter().interleave_shortest(v1.into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:291:20 + --> tests/ui/useless_conversion.rs:301:20 | LL | J: IntoIterator, | ^^^^^^^^^^^^ error: useless conversion to the same type: `()` - --> tests/ui/useless_conversion.rs:332:58 + --> tests/ui/useless_conversion.rs:342:58 | LL | let _: Result<(), std::io::Error> = test_issue_3913().map(Into::into); | ^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `std::io::Error` - --> tests/ui/useless_conversion.rs:335:58 + --> tests/ui/useless_conversion.rs:345:58 | LL | let _: Result<(), std::io::Error> = test_issue_3913().map_err(Into::into); | ^^^^^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `()` - --> tests/ui/useless_conversion.rs:338:58 + --> tests/ui/useless_conversion.rs:348:58 | LL | let _: Result<(), std::io::Error> = test_issue_3913().map(From::from); | ^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `std::io::Error` - --> tests/ui/useless_conversion.rs:341:58 + --> tests/ui/useless_conversion.rs:351:58 | LL | let _: Result<(), std::io::Error> = test_issue_3913().map_err(From::from); | ^^^^^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `()` - --> tests/ui/useless_conversion.rs:345:31 + --> tests/ui/useless_conversion.rs:355:31 | LL | let _: ControlFlow<()> = c.map_break(Into::into); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `()` - --> tests/ui/useless_conversion.rs:349:31 + --> tests/ui/useless_conversion.rs:359:31 | LL | let _: ControlFlow<()> = c.map_continue(Into::into); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `u32` - --> tests/ui/useless_conversion.rs:363:41 + --> tests/ui/useless_conversion.rs:373:41 | LL | let _: Vec = [1u32].into_iter().map(Into::into).collect(); | ^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `T` - --> tests/ui/useless_conversion.rs:374:18 + --> tests/ui/useless_conversion.rs:384:18 | LL | x.into_iter().map(Into::into).collect() | ^^^^^^^^^^^^^^^^ help: consider removing error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:390:29 + --> tests/ui/useless_conversion.rs:400:29 | LL | takes_into_iter(self.my_field.into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:379:32 + --> tests/ui/useless_conversion.rs:389:32 | LL | fn takes_into_iter(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -310,13 +327,13 @@ LL + takes_into_iter(&self.my_field); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:398:29 + --> tests/ui/useless_conversion.rs:408:29 | LL | takes_into_iter(self.my_field.into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:379:32 + --> tests/ui/useless_conversion.rs:389:32 | LL | fn takes_into_iter(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -327,13 +344,13 @@ LL + takes_into_iter(&mut self.my_field); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:407:29 + --> tests/ui/useless_conversion.rs:417:29 | LL | takes_into_iter(self.my_field.into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:379:32 + --> tests/ui/useless_conversion.rs:389:32 | LL | fn takes_into_iter(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -344,13 +361,13 @@ LL + takes_into_iter(*self.my_field); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:416:29 + --> tests/ui/useless_conversion.rs:426:29 | LL | takes_into_iter(self.my_field.into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:379:32 + --> tests/ui/useless_conversion.rs:389:32 | LL | fn takes_into_iter(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -361,13 +378,13 @@ LL + takes_into_iter(&*self.my_field); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:425:29 + --> tests/ui/useless_conversion.rs:435:29 | LL | takes_into_iter(self.my_field.into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:379:32 + --> tests/ui/useless_conversion.rs:389:32 | LL | fn takes_into_iter(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -378,22 +395,22 @@ LL + takes_into_iter(&mut *self.my_field); | error: useless conversion to the same type: `std::ops::Range` - --> tests/ui/useless_conversion.rs:440:5 + --> tests/ui/useless_conversion.rs:450:5 | LL | R.into_iter().for_each(|_x| {}); | ^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `R` error: useless conversion to the same type: `std::ops::Range` - --> tests/ui/useless_conversion.rs:442:13 + --> tests/ui/useless_conversion.rs:452:13 | LL | let _ = R.into_iter().map(|_x| 0); | ^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `R` error: useless conversion to the same type: `std::slice::Iter<'_, i32>` - --> tests/ui/useless_conversion.rs:453:14 + --> tests/ui/useless_conversion.rs:463:14 | LL | for _ in mac!(iter [1, 2]).into_iter() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `mac!(iter [1, 2])` -error: aborting due to 44 previous errors +error: aborting due to 45 previous errors From af69f157129e154f050a224ba384703e57115032 Mon Sep 17 00:00:00 2001 From: Orson Peters Date: Tue, 6 Jan 2026 22:09:11 +0100 Subject: [PATCH 0313/1061] Add AtomicPtr::null --- library/core/src/sync/atomic.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 1eae06ebd33e..c675fd1381d8 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -1550,6 +1550,23 @@ impl AtomicPtr { unsafe { &*ptr.cast() } } + /// Creates a new `AtomicPtr` initialized with a null pointer. + /// + /// # Examples + /// + /// ``` + /// use std::sync::atomic::{AtomicPtr, Ordering}; + /// + /// let atomic_ptr = AtomicPtr::<()>::null(); + /// assert!(atomic_ptr.load(Ordering::Relaxed).is_null()); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "atomic_ptr_null", issue = "150733")] + pub const fn null() -> AtomicPtr { + AtomicPtr::new(crate::ptr::null_mut()) + } + /// Returns a mutable reference to the underlying pointer. /// /// This is safe because the mutable reference guarantees that no other threads are From 0dfff23114662255119e33030de7ccc289a385b0 Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Tue, 6 Jan 2026 21:43:21 +0000 Subject: [PATCH 0314/1061] address reviews --- src/tools/tidy/src/extra_checks/mod.rs | 3 +- src/tools/tidy/src/extra_checks/tests.rs | 46 ++++++++++++------------ 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index a1d9ad436885..1c81a485608a 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -121,12 +121,12 @@ fn check_impl( .collect(), None => vec![], }; + lint_args.retain(|ck| ck.is_non_if_installed_or_matches(root_path, outdir)); if lint_args.iter().any(|ck| ck.auto) { crate::files_modified_batch_filter(ci_info, &mut lint_args, |ck, path| { ck.is_non_auto_or_matches(path) }); } - lint_args.retain(|ck| ck.is_non_if_installed_or_matches(root_path, outdir)); macro_rules! extra_check { ($lang:ident, $kind:ident) => { @@ -963,7 +963,6 @@ impl FromStr for ExtraCheckArg { }; if_installed = true; first = part; - continue; } _ => break, } diff --git a/src/tools/tidy/src/extra_checks/tests.rs b/src/tools/tidy/src/extra_checks/tests.rs index 62501803b255..5d274069a80c 100644 --- a/src/tools/tidy/src/extra_checks/tests.rs +++ b/src/tools/tidy/src/extra_checks/tests.rs @@ -7,80 +7,80 @@ fn test_extra_check_arg_from_str_ok() { let test_cases = [ ( "auto:if-installed:spellcheck", - Ok(ExtraCheckArg { + ExtraCheckArg { auto: true, if_installed: true, lang: ExtraCheckLang::Spellcheck, kind: None, - }), + }, ), ( "if-installed:auto:spellcheck", - Ok(ExtraCheckArg { + ExtraCheckArg { auto: true, if_installed: true, lang: ExtraCheckLang::Spellcheck, kind: None, - }), + }, ), ( "auto:spellcheck", - Ok(ExtraCheckArg { + ExtraCheckArg { auto: true, if_installed: false, lang: ExtraCheckLang::Spellcheck, kind: None, - }), + }, ), ( "if-installed:spellcheck", - Ok(ExtraCheckArg { + ExtraCheckArg { auto: false, if_installed: true, lang: ExtraCheckLang::Spellcheck, kind: None, - }), + }, ), ( "spellcheck", - Ok(ExtraCheckArg { + ExtraCheckArg { auto: false, if_installed: false, lang: ExtraCheckLang::Spellcheck, kind: None, - }), + }, ), ( "js:lint", - Ok(ExtraCheckArg { + ExtraCheckArg { auto: false, if_installed: false, lang: ExtraCheckLang::Js, kind: Some(ExtraCheckKind::Lint), - }), + }, ), ]; for (s, expected) in test_cases { - assert_eq!(ExtraCheckArg::from_str(s), expected); + assert_eq!(ExtraCheckArg::from_str(s), Ok(expected)); } } #[test] fn test_extra_check_arg_from_str_err() { let test_cases = [ - ("some:spellcheck", Err(ExtraCheckParseError::UnknownLang("some".to_string()))), - ("spellcheck:some", Err(ExtraCheckParseError::UnknownKind("some".to_string()))), - ("spellcheck:lint", Err(ExtraCheckParseError::UnsupportedKindForLang)), - ("auto:spellcheck:some", Err(ExtraCheckParseError::UnknownKind("some".to_string()))), - ("auto:js:lint:some", Err(ExtraCheckParseError::TooManyParts)), - ("some", Err(ExtraCheckParseError::UnknownLang("some".to_string()))), - ("auto", Err(ExtraCheckParseError::AutoRequiresLang)), - ("if-installed", Err(ExtraCheckParseError::IfInstalledRequiresLang)), - ("", Err(ExtraCheckParseError::Empty)), + ("some:spellcheck", ExtraCheckParseError::UnknownLang("some".to_string())), + ("spellcheck:some", ExtraCheckParseError::UnknownKind("some".to_string())), + ("spellcheck:lint", ExtraCheckParseError::UnsupportedKindForLang), + ("auto:spellcheck:some", ExtraCheckParseError::UnknownKind("some".to_string())), + ("auto:js:lint:some", ExtraCheckParseError::TooManyParts), + ("some", ExtraCheckParseError::UnknownLang("some".to_string())), + ("auto", ExtraCheckParseError::AutoRequiresLang), + ("if-installed", ExtraCheckParseError::IfInstalledRequiresLang), + ("", ExtraCheckParseError::Empty), ]; for (s, expected) in test_cases { - assert_eq!(ExtraCheckArg::from_str(s), expected); + assert_eq!(ExtraCheckArg::from_str(s), Err(expected)); } } From bd0d0f707e10fe9ee278c53c58f5cd7bce7f2bda Mon Sep 17 00:00:00 2001 From: Urgau Date: Tue, 6 Jan 2026 23:02:48 +0100 Subject: [PATCH 0315/1061] Factorize triagebot float parsing mentions with a glob matching --- triagebot.toml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index fbb2bac2267b..2d3757d241f5 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1059,14 +1059,10 @@ gets adapted for the changes, if necessary. """ cc = ["@rust-lang/miri", "@RalfJung", "@oli-obk", "@lcnr"] -[mentions."library/core/src/num/dec2flt"] +[mentions."library/core/src/num/{dec2flt,flt2dec}"] message = "Some changes occurred in float parsing" cc = ["@tgross35"] -[mentions."library/core/src/num/flt2dec"] -message = "Some changes occurred in float printing" -cc = ["@tgross35"] - [mentions."library/core/src/fmt/num.rs"] message = "Some changes occurred in integer formatting" cc = ["@tgross35"] From fff9c623bfc75bce9f9e5c64ed67d9b04ea655c1 Mon Sep 17 00:00:00 2001 From: Orson Peters Date: Tue, 6 Jan 2026 23:38:31 +0100 Subject: [PATCH 0316/1061] Add feature to doc example --- library/core/src/sync/atomic.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index c675fd1381d8..22f46ec385ce 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -1555,6 +1555,7 @@ impl AtomicPtr { /// # Examples /// /// ``` + /// #![feature(atomic_ptr_null)] /// use std::sync::atomic::{AtomicPtr, Ordering}; /// /// let atomic_ptr = AtomicPtr::<()>::null(); From af76a2456d1ce3ff200215e3593c10090ddfa725 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Sun, 4 Jan 2026 10:36:36 +0800 Subject: [PATCH 0317/1061] MGCA: Support tuple expressions as direct const arguments --- compiler/rustc_ast_lowering/src/lib.rs | 18 +++++ compiler/rustc_hir/src/hir.rs | 2 + compiler/rustc_hir/src/intravisit.rs | 4 ++ compiler/rustc_hir_analysis/src/collect.rs | 9 +-- .../src/hir_ty_lowering/mod.rs | 68 ++++++++++++++----- compiler/rustc_hir_analysis/src/lib.rs | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 10 +++ .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 4 +- .../rustc_hir_typeck/src/method/confirm.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 1 + compiler/rustc_resolve/src/def_collector.rs | 4 +- src/librustdoc/clean/mod.rs | 7 +- .../doesnt_unify_evaluatable.stderr | 4 +- .../mgca/adt_expr_arg_tuple_expr_complex.rs | 20 ++++++ .../adt_expr_arg_tuple_expr_complex.stderr | 26 +++++++ .../mgca/adt_expr_arg_tuple_expr_simple.rs | 22 ++++++ ...ce-hir-wf-check-anon-const-issue-122989.rs | 1 - ...ir-wf-check-anon-const-issue-122989.stderr | 26 +------ 18 files changed, 177 insertions(+), 53 deletions(-) create mode 100644 tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_complex.rs create mode 100644 tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_complex.stderr create mode 100644 tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_simple.rs diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index e11e24c0263f..5c65aa192b7e 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2427,6 +2427,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { kind: hir::ConstArgKind::TupleCall(qpath, lowered_args), } } + ExprKind::Tup(exprs) => { + let exprs = self.arena.alloc_from_iter(exprs.iter().map(|expr| { + let expr = if let ExprKind::ConstBlock(anon_const) = &expr.kind { + let def_id = self.local_def_id(anon_const.id); + let def_kind = self.tcx.def_kind(def_id); + assert_eq!(DefKind::AnonConst, def_kind); + + self.lower_anon_const_to_const_arg(anon_const) + } else { + self.lower_expr_to_const_arg_direct(&expr) + }; + + &*self.arena.alloc(expr) + })); + + ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Tup(expr.span, exprs) } + } ExprKind::Path(qself, path) => { let qpath = self.lower_qpath( expr.id, @@ -2495,6 +2512,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { | ExprKind::Path(..) | ExprKind::Struct(..) | ExprKind::Call(..) + | ExprKind::Tup(..) ) { return self.lower_expr_to_const_arg_direct(expr); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e13782282891..5c3f0e5ccd31 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -497,6 +497,7 @@ impl<'hir, Unambig> ConstArg<'hir, Unambig> { pub fn span(&self) -> Span { match self.kind { + ConstArgKind::Tup(span, ..) => span, ConstArgKind::Struct(path, _) => path.span(), ConstArgKind::Path(path) => path.span(), ConstArgKind::TupleCall(path, _) => path.span(), @@ -511,6 +512,7 @@ impl<'hir, Unambig> ConstArg<'hir, Unambig> { #[derive(Clone, Copy, Debug, HashStable_Generic)] #[repr(u8, C)] pub enum ConstArgKind<'hir, Unambig = ()> { + Tup(Span, &'hir [&'hir ConstArg<'hir, Unambig>]), /// **Note:** Currently this is only used for bare const params /// (`N` where `fn foo(...)`), /// not paths to any const (`N` where `const N: usize = ...`). diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 853e7db0757a..576f74b8b02b 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1081,6 +1081,10 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>( let ConstArg { hir_id, kind } = const_arg; try_visit!(visitor.visit_id(*hir_id)); match kind { + ConstArgKind::Tup(_, exprs) => { + walk_list!(visitor, visit_const_arg, *exprs); + V::Result::output() + } ConstArgKind::Struct(qpath, field_exprs) => { try_visit!(visitor.visit_qpath(qpath, *hir_id, qpath.span())); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 9343bcd27a33..9d4cb6d7684b 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1493,9 +1493,10 @@ fn const_param_default<'tcx>( }; let icx = ItemCtxt::new(tcx, def_id); let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id); - let ct = icx - .lowerer() - .lower_const_arg(default_ct, FeedConstTy::Param(def_id.to_def_id(), identity_args)); + let ct = icx.lowerer().lower_const_arg( + default_ct, + FeedConstTy::with_type_of(tcx, def_id.to_def_id(), identity_args), + ); ty::EarlyBinder::bind(ct) } @@ -1553,7 +1554,7 @@ fn const_of_item<'tcx>( let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id); let ct = icx .lowerer() - .lower_const_arg(ct_arg, FeedConstTy::Param(def_id.to_def_id(), identity_args)); + .lower_const_arg(ct_arg, FeedConstTy::with_type_of(tcx, def_id.to_def_id(), identity_args)); if let Err(e) = icx.check_tainted_by_errors() && !ct.references_error() { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index a22729fd287e..ad037c195d55 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -259,17 +259,26 @@ impl AssocItemQSelf { /// Use this enum with `::lower_const_arg` to instruct it with the /// desired behavior. #[derive(Debug, Clone, Copy)] -pub enum FeedConstTy<'a, 'tcx> { - /// Feed the type. - /// +pub enum FeedConstTy<'tcx> { + /// Feed the type to the (anno) const arg. + WithTy(Ty<'tcx>), + /// Don't feed the type. + No, +} + +impl<'tcx> FeedConstTy<'tcx> { /// The `DefId` belongs to the const param that we are supplying /// this (anon) const arg to. /// /// The list of generic args is used to instantiate the parameters /// used by the type of the const param specified by `DefId`. - Param(DefId, &'a [ty::GenericArg<'tcx>]), - /// Don't feed the type. - No, + pub fn with_type_of( + tcx: TyCtxt<'tcx>, + def_id: DefId, + generic_args: &[ty::GenericArg<'tcx>], + ) -> Self { + Self::WithTy(tcx.type_of(def_id).instantiate(tcx, generic_args)) + } } #[derive(Debug, Clone, Copy)] @@ -723,7 +732,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Ambig portions of `ConstArg` are handled in the match arm below .lower_const_arg( ct.as_unambig_ct(), - FeedConstTy::Param(param.def_id, preceding_args), + FeedConstTy::with_type_of(tcx, param.def_id, preceding_args), ) .into(), (&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { @@ -2303,15 +2312,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { pub fn lower_const_arg( &self, const_arg: &hir::ConstArg<'tcx>, - feed: FeedConstTy<'_, 'tcx>, + feed: FeedConstTy<'tcx>, ) -> Const<'tcx> { let tcx = self.tcx(); - if let FeedConstTy::Param(param_def_id, args) = feed + if let FeedConstTy::WithTy(anon_const_type) = feed && let hir::ConstArgKind::Anon(anon) = &const_arg.kind { - let anon_const_type = tcx.type_of(param_def_id).instantiate(tcx, args); - // FIXME(generic_const_parameter_types): Ideally we remove these errors below when // we have the ability to intermix typeck of anon const const args with the parent // bodies typeck. @@ -2352,14 +2359,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { return ty::Const::new_error(tcx, e); } - tcx.feed_anon_const_type( - anon.def_id, - ty::EarlyBinder::bind(tcx.type_of(param_def_id).instantiate(tcx, args)), - ); + tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(anon_const_type)); } let hir_id = const_arg.hir_id; match const_arg.kind { + hir::ConstArgKind::Tup(span, exprs) => self.lower_const_arg_tup(exprs, feed, span), hir::ConstArgKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { debug!(?maybe_qself, ?path); let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); @@ -2464,7 +2469,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .iter() .zip(args) .map(|(field_def, arg)| { - self.lower_const_arg(arg, FeedConstTy::Param(field_def.did, adt_args)) + self.lower_const_arg(arg, FeedConstTy::with_type_of(tcx, field_def.did, adt_args)) }) .collect::>(); @@ -2480,6 +2485,32 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::Const::new_value(tcx, valtree, adt_ty) } + fn lower_const_arg_tup( + &self, + exprs: &'tcx [&'tcx hir::ConstArg<'tcx>], + feed: FeedConstTy<'tcx>, + span: Span, + ) -> Const<'tcx> { + let tcx = self.tcx(); + + let FeedConstTy::WithTy(ty) = feed else { + return Const::new_error_with_message(tcx, span, "unsupported const tuple"); + }; + + let ty::Tuple(tys) = ty.kind() else { + return Const::new_error_with_message(tcx, span, "const tuple must have a tuple type"); + }; + + let exprs = exprs + .iter() + .zip(tys.iter()) + .map(|(expr, ty)| self.lower_const_arg(expr, FeedConstTy::WithTy(ty))) + .collect::>(); + + let valtree = ty::ValTree::from_branches(tcx, exprs); + ty::Const::new_value(tcx, valtree, ty) + } + fn lower_const_arg_struct( &self, hir_id: HirId, @@ -2558,7 +2589,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { return ty::Const::new_error(tcx, e); } - self.lower_const_arg(expr.expr, FeedConstTy::Param(field_def.did, adt_args)) + self.lower_const_arg( + expr.expr, + FeedConstTy::with_type_of(tcx, field_def.did, adt_args), + ) } None => { let e = tcx.dcx().span_err( diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 65f6a11e8e9b..7296ba6f964a 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -301,7 +301,7 @@ pub fn lower_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { pub fn lower_const_arg_for_rustdoc<'tcx>( tcx: TyCtxt<'tcx>, hir_ct: &hir::ConstArg<'tcx>, - feed: FeedConstTy<'_, 'tcx>, + feed: FeedConstTy<'tcx>, ) -> Const<'tcx> { let env_def_id = tcx.hir_get_parent_item(hir_ct.hir_id); collect::ItemCtxt::new(tcx, env_def_id.def_id).lowerer().lower_const_arg(hir_ct, feed) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 932e78958345..d360a18676ff 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1141,6 +1141,16 @@ impl<'a> State<'a> { fn print_const_arg(&mut self, const_arg: &hir::ConstArg<'_>) { match &const_arg.kind { + ConstArgKind::Tup(_, exprs) => { + self.popen(); + self.commasep_cmnt( + Inconsistent, + exprs, + |s, arg| s.print_const_arg(arg), + |arg| arg.span(), + ); + self.pclose(); + } ConstArgKind::Struct(qpath, fields) => self.print_const_struct(qpath, fields), ConstArgKind::TupleCall(qpath, args) => self.print_const_ctor(qpath, args), ConstArgKind::Path(qpath) => self.print_qpath(qpath, true), diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 339e77ac6edd..a66ff2a23c25 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -525,7 +525,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn lower_const_arg( &self, const_arg: &'tcx hir::ConstArg<'tcx>, - feed: FeedConstTy<'_, 'tcx>, + feed: FeedConstTy<'tcx>, ) -> ty::Const<'tcx> { let ct = self.lowerer().lower_const_arg(const_arg, feed); self.register_wf_obligation( @@ -1228,7 +1228,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Ambiguous parts of `ConstArg` are handled in the match arms below .lower_const_arg( ct.as_unambig_ct(), - FeedConstTy::Param(param.def_id, preceding_args), + FeedConstTy::with_type_of(self.fcx.tcx, param.def_id, preceding_args), ) .into(), (&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index e81537008bb5..aab4e3985555 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -447,7 +447,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // We handle the ambig portions of `ConstArg` in the match arms below .lower_const_arg( ct.as_unambig_ct(), - FeedConstTy::Param(param.def_id, preceding_args), + FeedConstTy::with_type_of(self.cfcx.tcx, param.def_id, preceding_args), ) .into(), (GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index d79ab9eaf759..d0e8bc50c495 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1442,6 +1442,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ConstArgKind::Error(..) | hir::ConstArgKind::Struct(..) | hir::ConstArgKind::TupleCall(..) + | hir::ConstArgKind::Tup(..) | hir::ConstArgKind::Path(..) | hir::ConstArgKind::Infer(..) => true, hir::ConstArgKind::Anon(..) => false, diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index f7b85453448c..b392b7747b55 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -419,7 +419,9 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { // Avoid overwriting `const_arg_context` as we may want to treat const blocks // as being anon consts if we are inside a const argument. - ExprKind::Struct(_) | ExprKind::Call(..) => return visit::walk_expr(self, expr), + ExprKind::Struct(_) | ExprKind::Call(..) | ExprKind::Tup(..) => { + return visit::walk_expr(self, expr); + } // FIXME(mgca): we may want to handle block labels in some manner ExprKind::Block(block, _) if let [stmt] = block.stmts.as_slice() => match stmt.kind { // FIXME(mgca): this probably means that mac calls that expand diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0768e6a56b3c..01f5d6f22f91 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -326,6 +326,10 @@ pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg<'tcx>) -> ConstantKind hir::ConstArgKind::TupleCall(..) => { ConstantKind::Path { path: "/* TUPLE CALL */".to_string().into() } } + hir::ConstArgKind::Tup(..) => { + // FIXME(mgca): proper printing :3 + ConstantKind::Path { path: "/* TUPLE EXPR */".to_string().into() } + } hir::ConstArgKind::Anon(anon) => ConstantKind::Anonymous { body: anon.body }, hir::ConstArgKind::Infer(..) | hir::ConstArgKind::Error(..) => ConstantKind::Infer, } @@ -1809,7 +1813,8 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T } hir::ConstArgKind::Struct(..) | hir::ConstArgKind::Path(..) - | hir::ConstArgKind::TupleCall(..) => { + | hir::ConstArgKind::TupleCall(..) + | hir::ConstArgKind::Tup(..) => { let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, FeedConstTy::No); print_const(cx, ct) } diff --git a/tests/ui/const-generics/generic_const_exprs/assoc_const_unification/doesnt_unify_evaluatable.stderr b/tests/ui/const-generics/generic_const_exprs/assoc_const_unification/doesnt_unify_evaluatable.stderr index 6cf4e881adae..62bebd53b14a 100644 --- a/tests/ui/const-generics/generic_const_exprs/assoc_const_unification/doesnt_unify_evaluatable.stderr +++ b/tests/ui/const-generics/generic_const_exprs/assoc_const_unification/doesnt_unify_evaluatable.stderr @@ -1,8 +1,8 @@ error: unconstrained generic constant - --> $DIR/doesnt_unify_evaluatable.rs:9:11 + --> $DIR/doesnt_unify_evaluatable.rs:9:13 | LL | bar::<{ T::ASSOC }>(); - | ^^^^^^^^^^^^ + | ^^^^^^^^ | help: try adding a `where` bound | diff --git a/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_complex.rs b/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_complex.rs new file mode 100644 index 000000000000..e47052523fa3 --- /dev/null +++ b/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_complex.rs @@ -0,0 +1,20 @@ +#![feature(min_generic_const_args, adt_const_params, unsized_const_params)] +#![expect(incomplete_features)] + +trait Trait { + #[type_const] + const ASSOC: usize; +} + +fn takes_tuple() {} +fn takes_nested_tuple() {} + +fn generic_caller() { + takes_tuple::<{ (N, N + 1) }>(); //~ ERROR complex const arguments must be placed inside of a `const` block + takes_tuple::<{ (N, T::ASSOC + 1) }>(); //~ ERROR complex const arguments must be placed inside of a `const` block + + takes_nested_tuple::<{ (N, (N, N + 1)) }>(); //~ ERROR complex const arguments must be placed inside of a `const` block + takes_nested_tuple::<{ (N, (N, const { N + 1 })) }>(); //~ ERROR generic parameters may not be used in const operations +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_complex.stderr b/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_complex.stderr new file mode 100644 index 000000000000..dbc64a1bf59d --- /dev/null +++ b/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_complex.stderr @@ -0,0 +1,26 @@ +error: complex const arguments must be placed inside of a `const` block + --> $DIR/adt_expr_arg_tuple_expr_complex.rs:13:25 + | +LL | takes_tuple::<{ (N, N + 1) }>(); + | ^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/adt_expr_arg_tuple_expr_complex.rs:14:25 + | +LL | takes_tuple::<{ (N, T::ASSOC + 1) }>(); + | ^^^^^^^^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/adt_expr_arg_tuple_expr_complex.rs:16:36 + | +LL | takes_nested_tuple::<{ (N, (N, N + 1)) }>(); + | ^^^^^ + +error: generic parameters may not be used in const operations + --> $DIR/adt_expr_arg_tuple_expr_complex.rs:17:44 + | +LL | takes_nested_tuple::<{ (N, (N, const { N + 1 })) }>(); + | ^ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_simple.rs b/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_simple.rs new file mode 100644 index 000000000000..60c4c6e952cf --- /dev/null +++ b/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_simple.rs @@ -0,0 +1,22 @@ +//@ check-pass + +#![feature(min_generic_const_args, adt_const_params, unsized_const_params)] +#![expect(incomplete_features)] + +trait Trait { + #[type_const] + const ASSOC: usize; +} + +fn takes_tuple() {} +fn takes_nested_tuple() {} + +fn generic_caller() { + takes_tuple::<{ (N, N2) }>(); + takes_tuple::<{ (N, T::ASSOC) }>(); + + takes_nested_tuple::<{ (N, (N, N2)) }>(); + takes_nested_tuple::<{ (N, (N, T::ASSOC)) }>(); +} + +fn main() {} diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs index 519e913480ec..f2b9f037ea5f 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs @@ -4,7 +4,6 @@ trait Foo> { //~^ WARN trait objects without an explicit `dyn` are deprecated //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! //~| ERROR cycle detected when computing type of `Foo::N` - //~| ERROR cycle detected when computing type of `Foo::N` fn func() {} } diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr index 0ecb3e74eb57..4024f57af4ff 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr @@ -13,7 +13,7 @@ LL | trait Foo> { | +++ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:20 + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:10:20 | LL | trait Bar> {} | ^^^^^^ @@ -32,7 +32,7 @@ LL | trait Foo> { | ^^^^^^^^^^^^^^^ | note: ...which requires computing type of `Bar::M`... - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:11 + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:10:11 | LL | trait Bar> {} | ^^^^^^^^^^^^^^^ @@ -44,26 +44,6 @@ LL | trait Foo> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0391]: cycle detected when computing type of `Foo::N` - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:3:11 - | -LL | trait Foo> { - | ^^^^^^^^^^^^^^^ - | -note: ...which requires computing type of `Bar::M`... - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:11 - | -LL | trait Bar> {} - | ^^^^^^^^^^^^^^^ - = note: ...which again requires computing type of `Foo::N`, completing the cycle -note: cycle used when checking that `Foo` is well-formed - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:3:1 - | -LL | trait Foo> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors; 2 warnings emitted +error: aborting due to 1 previous error; 2 warnings emitted For more information about this error, try `rustc --explain E0391`. From d572e6d415ab0796ef6d7beb960ff479be3628c2 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Tue, 6 Jan 2026 20:23:31 +0800 Subject: [PATCH 0318/1061] Add span field for ConstArg --- compiler/rustc_ast_lowering/src/index.rs | 2 +- compiler/rustc_ast_lowering/src/lib.rs | 47 ++++++++++++++----- compiler/rustc_ast_lowering/src/pat.rs | 3 +- compiler/rustc_hir/src/hir.rs | 25 +++------- compiler/rustc_hir/src/hir/tests.rs | 12 +++-- compiler/rustc_hir/src/intravisit.rs | 10 ++-- .../src/hir_ty_lowering/errors.rs | 4 +- .../src/hir_ty_lowering/mod.rs | 18 +++---- compiler/rustc_hir_pretty/src/lib.rs | 6 +-- compiler/rustc_hir_typeck/src/expr.rs | 4 +- compiler/rustc_lint/src/pass_by_value.rs | 9 ++-- compiler/rustc_middle/src/hir/map.rs | 2 +- .../src/error_reporting/infer/mod.rs | 2 +- .../clippy_lints/src/large_stack_arrays.rs | 2 +- .../clippy/clippy_lints/src/utils/author.rs | 1 + src/tools/clippy/clippy_utils/src/consts.rs | 2 +- .../clippy/clippy_utils/src/hir_utils.rs | 16 +++++++ .../mgca/adt_expr_erroneuous_inits.stderr | 6 +-- ...inting_valtrees_supports_non_values.stderr | 8 ++-- .../mgca/tuple_ctor_erroneous.stderr | 10 ++-- 20 files changed, 111 insertions(+), 78 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index f6edcaa64dfe..be0a1d490da6 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -312,7 +312,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { fn visit_const_arg(&mut self, const_arg: &'hir ConstArg<'hir, AmbigArg>) { self.insert( - const_arg.as_unambig_ct().span(), + const_arg.as_unambig_ct().span, const_arg.hir_id, Node::ConstArg(const_arg.as_unambig_ct()), ); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 5c65aa192b7e..a81d2297ef85 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2285,8 +2285,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // `ExprKind::Paren(ExprKind::Underscore)` and should also be lowered to `GenericArg::Infer` match c.value.peel_parens().kind { ExprKind::Underscore => { - let ct_kind = hir::ConstArgKind::Infer(self.lower_span(c.value.span), ()); - self.arena.alloc(hir::ConstArg { hir_id: self.lower_node_id(c.id), kind: ct_kind }) + let ct_kind = hir::ConstArgKind::Infer(()); + self.arena.alloc(hir::ConstArg { + hir_id: self.lower_node_id(c.id), + kind: ct_kind, + span: self.lower_span(c.value.span), + }) } _ => self.lower_anon_const_to_const_arg_and_alloc(c), } @@ -2356,7 +2360,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::ConstArgKind::Anon(ct) }; - self.arena.alloc(hir::ConstArg { hir_id: self.next_id(), kind: ct_kind }) + self.arena.alloc(hir::ConstArg { + hir_id: self.next_id(), + kind: ct_kind, + span: self.lower_span(span), + }) } fn lower_const_item_rhs( @@ -2373,9 +2381,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let const_arg = ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Error( - DUMMY_SP, self.dcx().span_delayed_bug(DUMMY_SP, "no block"), ), + span: DUMMY_SP, }; hir::ConstItemRhs::TypeConst(self.arena.alloc(const_arg)) } @@ -2388,13 +2396,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { #[instrument(level = "debug", skip(self), ret)] fn lower_expr_to_const_arg_direct(&mut self, expr: &Expr) -> hir::ConstArg<'hir> { + let span = self.lower_span(expr.span); + let overly_complex_const = |this: &mut Self| { let e = this.dcx().struct_span_err( expr.span, "complex const arguments must be placed inside of a `const` block", ); - ConstArg { hir_id: this.next_id(), kind: hir::ConstArgKind::Error(expr.span, e.emit()) } + ConstArg { hir_id: this.next_id(), kind: hir::ConstArgKind::Error(e.emit()), span } }; match &expr.kind { @@ -2425,6 +2435,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::TupleCall(qpath, lowered_args), + span, } } ExprKind::Tup(exprs) => { @@ -2442,7 +2453,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &*self.arena.alloc(expr) })); - ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Tup(expr.span, exprs) } + ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Tup(exprs), span } } ExprKind::Path(qself, path) => { let qpath = self.lower_qpath( @@ -2456,7 +2467,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { None, ); - ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath) } + ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath), span } } ExprKind::Struct(se) => { let path = self.lower_qpath( @@ -2497,11 +2508,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }) })); - ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Struct(path, fields) } + ConstArg { + hir_id: self.next_id(), + kind: hir::ConstArgKind::Struct(path, fields), + span, + } } ExprKind::Underscore => ConstArg { hir_id: self.lower_node_id(expr.id), - kind: hir::ConstArgKind::Infer(expr.span, ()), + kind: hir::ConstArgKind::Infer(()), + span, }, ExprKind::Block(block, _) => { if let [stmt] = block.stmts.as_slice() @@ -2546,7 +2562,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { return match anon.mgca_disambiguation { MgcaDisambiguation::AnonConst => { let lowered_anon = self.lower_anon_const_to_anon_const(anon); - ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(lowered_anon) } + ConstArg { + hir_id: self.next_id(), + kind: hir::ConstArgKind::Anon(lowered_anon), + span: lowered_anon.span, + } } MgcaDisambiguation::Direct => self.lower_expr_to_const_arg_direct(&anon.value), }; @@ -2583,11 +2603,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { return ConstArg { hir_id: self.lower_node_id(anon.id), kind: hir::ConstArgKind::Path(qpath), + span: self.lower_span(expr.span), }; } let lowered_anon = self.lower_anon_const_to_anon_const(anon); - ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(lowered_anon) } + ConstArg { + hir_id: self.next_id(), + kind: hir::ConstArgKind::Anon(lowered_anon), + span: self.lower_span(expr.span), + } } /// See [`hir::ConstArg`] for when to use this function vs diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index f09bbb9c4972..e066bce95158 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -513,6 +513,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.arena.alloc(hir::ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(self.arena.alloc(anon_const)), + span, }) } @@ -557,6 +558,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }) }); let hir_id = self.next_id(); - self.arena.alloc(hir::ConstArg { kind: hir::ConstArgKind::Anon(ct), hir_id }) + self.arena.alloc(hir::ConstArg { kind: hir::ConstArgKind::Anon(ct), hir_id, span }) } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 5c3f0e5ccd31..dc6790f7a3f1 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -423,7 +423,7 @@ impl<'hir> ConstItemRhs<'hir> { pub fn span<'tcx>(&self, tcx: impl crate::intravisit::HirTyCtxt<'tcx>) -> Span { match self { ConstItemRhs::Body(body_id) => tcx.hir_body(*body_id).value.span, - ConstItemRhs::TypeConst(ct_arg) => ct_arg.span(), + ConstItemRhs::TypeConst(ct_arg) => ct_arg.span, } } } @@ -447,6 +447,7 @@ pub struct ConstArg<'hir, Unambig = ()> { #[stable_hasher(ignore)] pub hir_id: HirId, pub kind: ConstArgKind<'hir, Unambig>, + pub span: Span, } impl<'hir> ConstArg<'hir, AmbigArg> { @@ -475,7 +476,7 @@ impl<'hir> ConstArg<'hir> { /// Functions accepting ambiguous consts will not handle the [`ConstArgKind::Infer`] variant, if /// infer consts are relevant to you then care should be taken to handle them separately. pub fn try_as_ambig_ct(&self) -> Option<&ConstArg<'hir, AmbigArg>> { - if let ConstArgKind::Infer(_, ()) = self.kind { + if let ConstArgKind::Infer(()) = self.kind { return None; } @@ -494,25 +495,13 @@ impl<'hir, Unambig> ConstArg<'hir, Unambig> { _ => None, } } - - pub fn span(&self) -> Span { - match self.kind { - ConstArgKind::Tup(span, ..) => span, - ConstArgKind::Struct(path, _) => path.span(), - ConstArgKind::Path(path) => path.span(), - ConstArgKind::TupleCall(path, _) => path.span(), - ConstArgKind::Anon(anon) => anon.span, - ConstArgKind::Error(span, _) => span, - ConstArgKind::Infer(span, _) => span, - } - } } /// See [`ConstArg`]. #[derive(Clone, Copy, Debug, HashStable_Generic)] #[repr(u8, C)] pub enum ConstArgKind<'hir, Unambig = ()> { - Tup(Span, &'hir [&'hir ConstArg<'hir, Unambig>]), + Tup(&'hir [&'hir ConstArg<'hir, Unambig>]), /// **Note:** Currently this is only used for bare const params /// (`N` where `fn foo(...)`), /// not paths to any const (`N` where `const N: usize = ...`). @@ -525,10 +514,10 @@ pub enum ConstArgKind<'hir, Unambig = ()> { /// Tuple constructor variant TupleCall(QPath<'hir>, &'hir [&'hir ConstArg<'hir>]), /// Error const - Error(Span, ErrorGuaranteed), + Error(ErrorGuaranteed), /// This variant is not always used to represent inference consts, sometimes /// [`GenericArg::Infer`] is used instead. - Infer(Span, Unambig), + Infer(Unambig), } #[derive(Clone, Copy, Debug, HashStable_Generic)] @@ -574,7 +563,7 @@ impl GenericArg<'_> { match self { GenericArg::Lifetime(l) => l.ident.span, GenericArg::Type(t) => t.span, - GenericArg::Const(c) => c.span(), + GenericArg::Const(c) => c.span, GenericArg::Infer(i) => i.span, } } diff --git a/compiler/rustc_hir/src/hir/tests.rs b/compiler/rustc_hir/src/hir/tests.rs index 4f9609fd360d..2ac33a369cbd 100644 --- a/compiler/rustc_hir/src/hir/tests.rs +++ b/compiler/rustc_hir/src/hir/tests.rs @@ -24,12 +24,16 @@ define_tests! { cast_ptr TyKind Ptr { 0: MutTy { ty: &Ty { span: DUMMY_SP, hir_id: HirId::INVALID, kind: TyKind::Never }, mutbl: Mutability::Not }} cast_array TyKind Array { 0: &Ty { span: DUMMY_SP, hir_id: HirId::INVALID, kind: TyKind::Never }, - 1: &ConstArg { hir_id: HirId::INVALID, kind: ConstArgKind::Anon(&AnonConst { + 1: &ConstArg { hir_id: HirId::INVALID, - def_id: LocalDefId { local_def_index: DefIndex::ZERO }, - body: BodyId { hir_id: HirId::INVALID }, + kind: ConstArgKind::Anon(&AnonConst { + hir_id: HirId::INVALID, + def_id: LocalDefId { local_def_index: DefIndex::ZERO }, + body: BodyId { hir_id: HirId::INVALID }, + span: DUMMY_SP, + }), span: DUMMY_SP, - })} + }, } cast_anon ConstArgKind Anon { diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 576f74b8b02b..59db60fdc55c 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1068,8 +1068,8 @@ pub fn walk_unambig_const_arg<'v, V: Visitor<'v>>( match const_arg.try_as_ambig_ct() { Some(ambig_ct) => visitor.visit_const_arg(ambig_ct), None => { - let ConstArg { hir_id, kind: _ } = const_arg; - visitor.visit_infer(*hir_id, const_arg.span(), InferKind::Const(const_arg)) + let ConstArg { hir_id, kind: _, span } = const_arg; + visitor.visit_infer(*hir_id, *span, InferKind::Const(const_arg)) } } } @@ -1078,10 +1078,10 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>( visitor: &mut V, const_arg: &'v ConstArg<'v, AmbigArg>, ) -> V::Result { - let ConstArg { hir_id, kind } = const_arg; + let ConstArg { hir_id, kind, span: _ } = const_arg; try_visit!(visitor.visit_id(*hir_id)); match kind { - ConstArgKind::Tup(_, exprs) => { + ConstArgKind::Tup(exprs) => { walk_list!(visitor, visit_const_arg, *exprs); V::Result::output() } @@ -1103,7 +1103,7 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>( } ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, qpath.span()), ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon), - ConstArgKind::Error(_, _) => V::Result::output(), // errors and spans are not important + ConstArgKind::Error(_) => V::Result::output(), // errors and spans are not important } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 51c664921804..92b77a2042b1 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -381,7 +381,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { { let span = match term { hir::Term::Ty(ty) => ty.span, - hir::Term::Const(ct) => ct.span(), + hir::Term::Const(ct) => ct.span, }; (span, Some(ident.span), assoc_item.as_tag(), assoc_tag) } else { @@ -1466,7 +1466,7 @@ pub fn prohibit_assoc_item_constraint( hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(c) }, GenericParamDefKind::Const { .. }, ) => { - suggest_direct_use(&mut err, c.span()); + suggest_direct_use(&mut err, c.span); } (hir::AssocItemConstraintKind::Bound { bounds }, _) => { // Suggest `impl Trait for Foo` when finding diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index ad037c195d55..aaa566760013 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2331,7 +2331,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { && (anon_const_type.has_free_regions() || anon_const_type.has_erased_regions()) { let e = self.dcx().span_err( - const_arg.span(), + const_arg.span, "anonymous constants with lifetimes in their type are not yet supported", ); tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, e))); @@ -2342,7 +2342,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // variables otherwise we will ICE. if anon_const_type.has_non_region_infer() { let e = self.dcx().span_err( - const_arg.span(), + const_arg.span, "anonymous constants with inferred types are not yet supported", ); tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, e))); @@ -2352,7 +2352,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // give the anon const any of the generics from the parent. if anon_const_type.has_non_region_param() { let e = self.dcx().span_err( - const_arg.span(), + const_arg.span, "anonymous constants referencing generics are not yet supported", ); tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, e))); @@ -2364,7 +2364,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let hir_id = const_arg.hir_id; match const_arg.kind { - hir::ConstArgKind::Tup(span, exprs) => self.lower_const_arg_tup(exprs, feed, span), + hir::ConstArgKind::Tup(exprs) => self.lower_const_arg_tup(exprs, feed, const_arg.span), hir::ConstArgKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { debug!(?maybe_qself, ?path); let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); @@ -2378,19 +2378,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir_self_ty, segment, hir_id, - const_arg.span(), + const_arg.span, ) .unwrap_or_else(|guar| Const::new_error(tcx, guar)) } hir::ConstArgKind::Struct(qpath, inits) => { - self.lower_const_arg_struct(hir_id, qpath, inits, const_arg.span()) + self.lower_const_arg_struct(hir_id, qpath, inits, const_arg.span) } hir::ConstArgKind::TupleCall(qpath, args) => { - self.lower_const_arg_tuple_call(hir_id, qpath, args, const_arg.span()) + self.lower_const_arg_tuple_call(hir_id, qpath, args, const_arg.span) } hir::ConstArgKind::Anon(anon) => self.lower_const_arg_anon(anon), - hir::ConstArgKind::Infer(span, ()) => self.ct_infer(None, span), - hir::ConstArgKind::Error(_, e) => ty::Const::new_error(tcx, e), + hir::ConstArgKind::Infer(()) => self.ct_infer(None, const_arg.span), + hir::ConstArgKind::Error(e) => ty::Const::new_error(tcx, e), } } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index d360a18676ff..2c160ccef2b6 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1141,13 +1141,13 @@ impl<'a> State<'a> { fn print_const_arg(&mut self, const_arg: &hir::ConstArg<'_>) { match &const_arg.kind { - ConstArgKind::Tup(_, exprs) => { + ConstArgKind::Tup(exprs) => { self.popen(); self.commasep_cmnt( Inconsistent, exprs, |s, arg| s.print_const_arg(arg), - |arg| arg.span(), + |arg| arg.span, ); self.pclose(); } @@ -1155,7 +1155,7 @@ impl<'a> State<'a> { ConstArgKind::TupleCall(qpath, args) => self.print_const_ctor(qpath, args), ConstArgKind::Path(qpath) => self.print_qpath(qpath, true), ConstArgKind::Anon(anon) => self.print_anon_const(anon), - ConstArgKind::Error(_, _) => self.word("/*ERROR*/"), + ConstArgKind::Error(_) => self.word("/*ERROR*/"), ConstArgKind::Infer(..) => self.word("_"), } } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index c4fa39c6c2c8..9d7e09b020a7 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1705,7 +1705,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; }; if let hir::TyKind::Array(_, ct) = ty.peel_refs().kind { - let span = ct.span(); + let span = ct.span; self.dcx().try_steal_modify_and_emit_err( span, StashKey::UnderscoreForArrayLengths, @@ -1746,7 +1746,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; - let count_span = count.span(); + let count_span = count.span; let count = self.try_structurally_resolve_const( count_span, self.normalize(count_span, self.lower_const_arg(count, FeedConstTy::No)), diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs index 29006732aade..f4a506d50a41 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -74,12 +74,9 @@ fn gen_args(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> String { GenericArg::Type(ty) => { cx.tcx.sess.source_map().span_to_snippet(ty.span).unwrap_or_else(|_| "_".into()) } - GenericArg::Const(c) => cx - .tcx - .sess - .source_map() - .span_to_snippet(c.span()) - .unwrap_or_else(|_| "_".into()), + GenericArg::Const(c) => { + cx.tcx.sess.source_map().span_to_snippet(c.span).unwrap_or_else(|_| "_".into()) + } GenericArg::Infer(_) => String::from("_"), }) .collect::>(); diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 8cc66802e435..ca783311586f 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -1003,7 +1003,7 @@ impl<'tcx> TyCtxt<'tcx> { Node::Field(field) => field.span, Node::AnonConst(constant) => constant.span, Node::ConstBlock(constant) => self.hir_body(constant.body).value.span, - Node::ConstArg(const_arg) => const_arg.span(), + Node::ConstArg(const_arg) => const_arg.span, Node::Expr(expr) => expr.span, Node::ExprField(field) => field.span, Node::ConstArgExprField(field) => field.span, diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index cea69c699628..47810e2578df 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -1879,7 +1879,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && let Some(length_val) = sz.found.try_to_target_usize(self.tcx) { Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength { - span: length_arg.span(), + span: length_arg.span, length: length_val, }) } else { diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs index 620e27fa67c6..261b03abba17 100644 --- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs @@ -126,7 +126,7 @@ fn might_be_expanded<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool { let ExprKind::Repeat(_, len_ct) = expr.kind else { return false; }; - !expr.span.contains(len_ct.span()) + !expr.span.contains(len_ct.span) } expr.span.from_expansion() || is_from_proc_macro(cx, expr) || repeat_expr_might_be_expanded(expr) diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index f515f9987a80..455f76edc904 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -321,6 +321,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { }, ConstArgKind::Struct(..) => chain!(self, "let ConstArgKind::Struct(..) = {const_arg}.kind"), ConstArgKind::TupleCall(..) => chain!(self, "let ConstArgKind::TupleCall(..) = {const_arg}.kind"), + ConstArgKind::Tup(..) => chain!(self, "let ConstArgKind::Tup(..) = {const_arg}.kind"), ConstArgKind::Infer(..) => chain!(self, "let ConstArgKind::Infer(..) = {const_arg}.kind"), ConstArgKind::Error(..) => chain!(self, "let ConstArgKind::Error(..) = {const_arg}.kind"), } diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index a44cd31dc123..46b87fd5df96 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -1140,7 +1140,7 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx ConstItemRhs::Body(body_id) => Some(tcx.hir_body(body_id).value), ConstItemRhs::TypeConst(const_arg) => match const_arg.kind { ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value), - ConstArgKind::Struct(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => { + ConstArgKind::Struct(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Tup(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => { None }, }, diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index f1ee534c500d..57c896c97172 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -661,6 +661,10 @@ impl HirEqInterExpr<'_, '_, '_> { } fn eq_const_arg(&mut self, left: &ConstArg<'_>, right: &ConstArg<'_>) -> bool { + if !self.check_ctxt(left.span.ctxt(), right.span.ctxt()) { + return false; + } + match (&left.kind, &right.kind) { (ConstArgKind::Path(l_p), ConstArgKind::Path(r_p)) => self.eq_qpath(l_p, r_p), (ConstArgKind::Anon(l_an), ConstArgKind::Anon(r_an)) => self.eq_body(l_an.body, r_an.body), @@ -679,11 +683,18 @@ impl HirEqInterExpr<'_, '_, '_> { .zip(*args_b) .all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b)) } + (ConstArgKind::Tup(args_a), ConstArgKind::Tup(args_b)) => { + args_a + .iter() + .zip(*args_b) + .all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b)) + } // Use explicit match for now since ConstArg is undergoing flux. ( ConstArgKind::Path(..) | ConstArgKind::Anon(..) | ConstArgKind::TupleCall(..) + | ConstArgKind::Tup(..) | ConstArgKind::Infer(..) | ConstArgKind::Struct(..) | ConstArgKind::Error(..), @@ -1560,6 +1571,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_const_arg(arg); } }, + ConstArgKind::Tup(args) => { + for arg in *args { + self.hash_const_arg(arg); + } + }, ConstArgKind::Infer(..) | ConstArgKind::Error(..) => {}, } } diff --git a/tests/ui/const-generics/mgca/adt_expr_erroneuous_inits.stderr b/tests/ui/const-generics/mgca/adt_expr_erroneuous_inits.stderr index 49d3f67003dc..72e0e94ff625 100644 --- a/tests/ui/const-generics/mgca/adt_expr_erroneuous_inits.stderr +++ b/tests/ui/const-generics/mgca/adt_expr_erroneuous_inits.stderr @@ -23,7 +23,7 @@ error: struct expression with missing field initialiser for `field` --> $DIR/adt_expr_erroneuous_inits.rs:16:17 | LL | accepts::<{ Foo:: { }}>(); - | ^^^^^^^^^ + | ^^^^^^^^^^^^^ error: struct expression with multiple initialisers for `field` --> $DIR/adt_expr_erroneuous_inits.rs:18:49 @@ -35,13 +35,13 @@ error: struct expression with invalid base path --> $DIR/adt_expr_erroneuous_inits.rs:20:17 | LL | accepts::<{ Fooo:: { field: const { 1 } }}>(); - | ^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: struct expression with invalid base path --> $DIR/adt_expr_erroneuous_inits.rs:23:17 | LL | accepts::<{ NonStruct { }}>(); - | ^^^^^^^^^ + | ^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.stderr b/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.stderr index b4f03e07b569..bd2162468944 100644 --- a/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.stderr +++ b/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.stderr @@ -2,7 +2,7 @@ error: the constant `Option::::Some(N)` is not of type `Foo` --> $DIR/printing_valtrees_supports_non_values.rs:18:13 | LL | foo::<{ Option::Some:: { 0: N } }>; - | ^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option` | note: required by a const generic parameter in `foo` --> $DIR/printing_valtrees_supports_non_values.rs:15:8 @@ -14,7 +14,7 @@ error: the constant `Option::::Some(::ASSOC)` is not of type `F --> $DIR/printing_valtrees_supports_non_values.rs:23:13 | LL | foo::<{ Option::Some:: { 0: ::ASSOC } }>(); - | ^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option` | note: required by a const generic parameter in `foo` --> $DIR/printing_valtrees_supports_non_values.rs:15:8 @@ -37,7 +37,7 @@ error: the constant `Option::::Some(_)` is not of type `Foo` --> $DIR/printing_valtrees_supports_non_values.rs:30:12 | LL | foo::<{Option::Some::{0: ::ASSOC}}>(); - | ^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option` | note: required by a const generic parameter in `foo` --> $DIR/printing_valtrees_supports_non_values.rs:15:8 @@ -49,7 +49,7 @@ error: the constant `Option::::Some(_)` is not of type `Foo` --> $DIR/printing_valtrees_supports_non_values.rs:36:13 | LL | foo::<{ Option::Some:: { 0: _ } }>(); - | ^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option` | note: required by a const generic parameter in `foo` --> $DIR/printing_valtrees_supports_non_values.rs:15:8 diff --git a/tests/ui/const-generics/mgca/tuple_ctor_erroneous.stderr b/tests/ui/const-generics/mgca/tuple_ctor_erroneous.stderr index fbcdf35461ec..cc6144b9c88a 100644 --- a/tests/ui/const-generics/mgca/tuple_ctor_erroneous.stderr +++ b/tests/ui/const-generics/mgca/tuple_ctor_erroneous.stderr @@ -13,31 +13,31 @@ error: tuple constructor has 2 arguments but 1 were provided --> $DIR/tuple_ctor_erroneous.rs:23:23 | LL | accepts_point::<{ Point(N) }>(); - | ^^^^^ + | ^^^^^^^^ error: tuple constructor has 2 arguments but 3 were provided --> $DIR/tuple_ctor_erroneous.rs:26:23 | LL | accepts_point::<{ Point(N, N, N) }>(); - | ^^^^^ + | ^^^^^^^^^^^^^^ error: tuple constructor with invalid base path --> $DIR/tuple_ctor_erroneous.rs:29:23 | LL | accepts_point::<{ UnresolvedIdent(N, N) }>(); - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: tuple constructor with invalid base path --> $DIR/tuple_ctor_erroneous.rs:33:23 | LL | accepts_point::<{ non_ctor(N, N) }>(); - | ^^^^^^^^ + | ^^^^^^^^^^^^^^ error: tuple constructor with invalid base path --> $DIR/tuple_ctor_erroneous.rs:36:23 | LL | accepts_point::<{ CONST_ITEM(N, N) }>(); - | ^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: the constant `Point` is not of type `Point` --> $DIR/tuple_ctor_erroneous.rs:39:23 From cb1de296591e7220495c7f37a862678ee55edd71 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Tue, 6 Jan 2026 23:07:24 +0800 Subject: [PATCH 0319/1061] Use parent's identity_args to instantiate the type of const param --- compiler/rustc_hir_analysis/src/collect.rs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 9d4cb6d7684b..bacdf0049806 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1479,24 +1479,27 @@ fn rendered_precise_capturing_args<'tcx>( fn const_param_default<'tcx>( tcx: TyCtxt<'tcx>, - def_id: LocalDefId, + local_def_id: LocalDefId, ) -> ty::EarlyBinder<'tcx, Const<'tcx>> { let hir::Node::GenericParam(hir::GenericParam { kind: hir::GenericParamKind::Const { default: Some(default_ct), .. }, .. - }) = tcx.hir_node_by_def_id(def_id) + }) = tcx.hir_node_by_def_id(local_def_id) else { span_bug!( - tcx.def_span(def_id), + tcx.def_span(local_def_id), "`const_param_default` expected a generic parameter with a constant" ) }; - let icx = ItemCtxt::new(tcx, def_id); - let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id); - let ct = icx.lowerer().lower_const_arg( - default_ct, - FeedConstTy::with_type_of(tcx, def_id.to_def_id(), identity_args), - ); + + let icx = ItemCtxt::new(tcx, local_def_id); + + let def_id = local_def_id.to_def_id(); + let identity_args = ty::GenericArgs::identity_for_item(tcx, tcx.parent(def_id)); + + let ct = icx + .lowerer() + .lower_const_arg(default_ct, FeedConstTy::with_type_of(tcx, def_id, identity_args)); ty::EarlyBinder::bind(ct) } From 6b11237e7dca81a57340ac4ab5ca2437b2c59a93 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Tue, 6 Jan 2026 20:23:31 +0800 Subject: [PATCH 0320/1061] Add span field for ConstArg --- clippy_lints/src/large_stack_arrays.rs | 2 +- clippy_lints/src/utils/author.rs | 1 + clippy_utils/src/consts.rs | 2 +- clippy_utils/src/hir_utils.rs | 16 ++++++++++++++++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index 620e27fa67c6..261b03abba17 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -126,7 +126,7 @@ fn might_be_expanded<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool { let ExprKind::Repeat(_, len_ct) = expr.kind else { return false; }; - !expr.span.contains(len_ct.span()) + !expr.span.contains(len_ct.span) } expr.span.from_expansion() || is_from_proc_macro(cx, expr) || repeat_expr_might_be_expanded(expr) diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index f515f9987a80..455f76edc904 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -321,6 +321,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { }, ConstArgKind::Struct(..) => chain!(self, "let ConstArgKind::Struct(..) = {const_arg}.kind"), ConstArgKind::TupleCall(..) => chain!(self, "let ConstArgKind::TupleCall(..) = {const_arg}.kind"), + ConstArgKind::Tup(..) => chain!(self, "let ConstArgKind::Tup(..) = {const_arg}.kind"), ConstArgKind::Infer(..) => chain!(self, "let ConstArgKind::Infer(..) = {const_arg}.kind"), ConstArgKind::Error(..) => chain!(self, "let ConstArgKind::Error(..) = {const_arg}.kind"), } diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index a44cd31dc123..46b87fd5df96 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -1140,7 +1140,7 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx ConstItemRhs::Body(body_id) => Some(tcx.hir_body(body_id).value), ConstItemRhs::TypeConst(const_arg) => match const_arg.kind { ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value), - ConstArgKind::Struct(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => { + ConstArgKind::Struct(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Tup(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => { None }, }, diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index f1ee534c500d..57c896c97172 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -661,6 +661,10 @@ impl HirEqInterExpr<'_, '_, '_> { } fn eq_const_arg(&mut self, left: &ConstArg<'_>, right: &ConstArg<'_>) -> bool { + if !self.check_ctxt(left.span.ctxt(), right.span.ctxt()) { + return false; + } + match (&left.kind, &right.kind) { (ConstArgKind::Path(l_p), ConstArgKind::Path(r_p)) => self.eq_qpath(l_p, r_p), (ConstArgKind::Anon(l_an), ConstArgKind::Anon(r_an)) => self.eq_body(l_an.body, r_an.body), @@ -679,11 +683,18 @@ impl HirEqInterExpr<'_, '_, '_> { .zip(*args_b) .all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b)) } + (ConstArgKind::Tup(args_a), ConstArgKind::Tup(args_b)) => { + args_a + .iter() + .zip(*args_b) + .all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b)) + } // Use explicit match for now since ConstArg is undergoing flux. ( ConstArgKind::Path(..) | ConstArgKind::Anon(..) | ConstArgKind::TupleCall(..) + | ConstArgKind::Tup(..) | ConstArgKind::Infer(..) | ConstArgKind::Struct(..) | ConstArgKind::Error(..), @@ -1560,6 +1571,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_const_arg(arg); } }, + ConstArgKind::Tup(args) => { + for arg in *args { + self.hash_const_arg(arg); + } + }, ConstArgKind::Infer(..) | ConstArgKind::Error(..) => {}, } } From 139d59f7ecbf0146a5c0e475473e71aca47e0b39 Mon Sep 17 00:00:00 2001 From: neo Date: Wed, 7 Jan 2026 09:53:06 +0900 Subject: [PATCH 0321/1061] Reword the collect() docs to stress that the return type determines the resulting collection --- library/core/src/iter/traits/iterator.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index f106900a3983..e418f481ad2a 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1906,9 +1906,12 @@ pub trait Iterator { /// Transforms an iterator into a collection. /// - /// `collect()` can take anything iterable, and turn it into a relevant - /// collection. This is one of the more powerful methods in the standard - /// library, used in a variety of contexts. + /// `collect()` takes ownership of an iterator and produces whichever + /// collection type you request. The iterator itself carries no knowledge of + /// the eventual container; the target collection is chosen entirely by the + /// type you ask `collect()` to return. This makes `collect()` one of the + /// more powerful methods in the standard library, and it shows up in a wide + /// variety of contexts. /// /// The most basic pattern in which `collect()` is used is to turn one /// collection into another. You take a collection, call [`iter`] on it, From 6346d14202ce2c4ac3e92595a6fd1b619803145d Mon Sep 17 00:00:00 2001 From: tison Date: Wed, 7 Jan 2026 09:31:59 +0800 Subject: [PATCH 0322/1061] Apply suggestion from @tisonkun --- library/alloc/src/task.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs index 73b732241974..aa1901314e37 100644 --- a/library/alloc/src/task.rs +++ b/library/alloc/src/task.rs @@ -360,6 +360,7 @@ impl From> for RawWaker { /// waker.wake_by_ref(); // Prints "woken". /// waker.wake(); // Prints "woken". /// ``` +// #[unstable(feature = "local_waker", issue = "118959")] #[unstable(feature = "waker_fn", issue = "149580")] pub fn local_waker_fn(f: F) -> LocalWaker { struct LocalWakeFn { From 6c2dc40666b1564a9621fcccc2f32a70d3e89e38 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Wed, 7 Jan 2026 00:03:32 +0800 Subject: [PATCH 0323/1061] Bless other tests --- tests/crashes/133965.rs | 9 --- tests/incremental/const-generic-type-cycle.rs | 1 - ...ith-same-name-and-derive-default-133965.rs | 14 ++++ ...same-name-and-derive-default-133965.stderr | 81 +++++++++++++++++++ .../non_scalar_alignment_value.stderr | 8 +- 5 files changed, 99 insertions(+), 14 deletions(-) delete mode 100644 tests/crashes/133965.rs create mode 100644 tests/ui/duplicate/multiple-types-with-same-name-and-derive-default-133965.rs create mode 100644 tests/ui/duplicate/multiple-types-with-same-name-and-derive-default-133965.stderr diff --git a/tests/crashes/133965.rs b/tests/crashes/133965.rs deleted file mode 100644 index 69f533ccbe98..000000000000 --- a/tests/crashes/133965.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ known-bug: #133965 -//@ needs-rustc-debug-assertions - -struct NonGeneric {} - -#[derive(Default)] -struct NonGeneric<'a, const N: usize> {} - -pub fn main() {} diff --git a/tests/incremental/const-generic-type-cycle.rs b/tests/incremental/const-generic-type-cycle.rs index 40a40ebd13fe..5bcbc1d5dafe 100644 --- a/tests/incremental/const-generic-type-cycle.rs +++ b/tests/incremental/const-generic-type-cycle.rs @@ -14,7 +14,6 @@ trait Bar {} trait Bar {} //[cfail]~^ ERROR cycle detected when computing type of `Bar::N` //[cfail]~| ERROR cycle detected when computing type of `Bar::N` -//[cfail]~| ERROR cycle detected when computing type of `Bar::N` //[cfail]~| ERROR `(dyn Bar<{ 2 + 1 }> + 'static)` is forbidden as the type of a const generic parameter trait BB = Bar<{ 2 + 1 }>; diff --git a/tests/ui/duplicate/multiple-types-with-same-name-and-derive-default-133965.rs b/tests/ui/duplicate/multiple-types-with-same-name-and-derive-default-133965.rs new file mode 100644 index 000000000000..8e5cd4248f14 --- /dev/null +++ b/tests/ui/duplicate/multiple-types-with-same-name-and-derive-default-133965.rs @@ -0,0 +1,14 @@ +//@ needs-rustc-debug-assertions + +struct NonGeneric {} + +#[derive(Default)] +//~^ ERROR struct takes 0 lifetime arguments but 1 lifetime argument was supplied +//~^^ ERROR struct takes 0 lifetime arguments but 1 lifetime argument was supplied +//~^^^ ERROR struct takes 0 generic arguments but 1 generic argument was supplied +//~^^^^ ERROR struct takes 0 generic arguments but 1 generic argument was supplied +struct NonGeneric<'a, const N: usize> {} +//~^ ERROR lifetime parameter `'a` is never used +//~^^ ERROR the name `NonGeneric` is defined multiple times + +pub fn main() {} diff --git a/tests/ui/duplicate/multiple-types-with-same-name-and-derive-default-133965.stderr b/tests/ui/duplicate/multiple-types-with-same-name-and-derive-default-133965.stderr new file mode 100644 index 000000000000..cf9c0d0ad3be --- /dev/null +++ b/tests/ui/duplicate/multiple-types-with-same-name-and-derive-default-133965.stderr @@ -0,0 +1,81 @@ +error[E0428]: the name `NonGeneric` is defined multiple times + --> $DIR/multiple-types-with-same-name-and-derive-default-133965.rs:10:1 + | +LL | struct NonGeneric {} + | ----------------- previous definition of the type `NonGeneric` here +... +LL | struct NonGeneric<'a, const N: usize> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `NonGeneric` redefined here + | + = note: `NonGeneric` must be defined only once in the type namespace of this module + +error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supplied + --> $DIR/multiple-types-with-same-name-and-derive-default-133965.rs:5:10 + | +LL | #[derive(Default)] + | ^^^^^^^ expected 0 lifetime arguments +... +LL | struct NonGeneric<'a, const N: usize> {} + | -- help: remove the lifetime argument + | +note: struct defined here, with 0 lifetime parameters + --> $DIR/multiple-types-with-same-name-and-derive-default-133965.rs:3:8 + | +LL | struct NonGeneric {} + | ^^^^^^^^^^ + +error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/multiple-types-with-same-name-and-derive-default-133965.rs:5:10 + | +LL | #[derive(Default)] + | ^^^^^^^ expected 0 generic arguments + | +note: struct defined here, with 0 generic parameters + --> $DIR/multiple-types-with-same-name-and-derive-default-133965.rs:3:8 + | +LL | struct NonGeneric {} + | ^^^^^^^^^^ + +error[E0392]: lifetime parameter `'a` is never used + --> $DIR/multiple-types-with-same-name-and-derive-default-133965.rs:10:19 + | +LL | struct NonGeneric<'a, const N: usize> {} + | ^^ unused lifetime parameter + | + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` + +error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supplied + --> $DIR/multiple-types-with-same-name-and-derive-default-133965.rs:5:10 + | +LL | #[derive(Default)] + | ^^^^^^^ expected 0 lifetime arguments +... +LL | struct NonGeneric<'a, const N: usize> {} + | -- help: remove the lifetime argument + | +note: struct defined here, with 0 lifetime parameters + --> $DIR/multiple-types-with-same-name-and-derive-default-133965.rs:3:8 + | +LL | struct NonGeneric {} + | ^^^^^^^^^^ + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/multiple-types-with-same-name-and-derive-default-133965.rs:5:10 + | +LL | #[derive(Default)] + | ^^^^^^^ expected 0 generic arguments +... +LL | struct NonGeneric<'a, const N: usize> {} + | - help: remove the unnecessary generic argument + | +note: struct defined here, with 0 generic parameters + --> $DIR/multiple-types-with-same-name-and-derive-default-133965.rs:3:8 + | +LL | struct NonGeneric {} + | ^^^^^^^^^^ + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0107, E0392, E0428. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/transmutability/non_scalar_alignment_value.stderr b/tests/ui/transmutability/non_scalar_alignment_value.stderr index 06487dea82e0..d22c6d0b27e8 100644 --- a/tests/ui/transmutability/non_scalar_alignment_value.stderr +++ b/tests/ui/transmutability/non_scalar_alignment_value.stderr @@ -11,25 +11,25 @@ error: struct expression with missing field initialiser for `alignment` --> $DIR/non_scalar_alignment_value.rs:15:32 | LL | alignment: Assume {}, - | ^^^^^^ + | ^^^^^^^^^ error: struct expression with missing field initialiser for `lifetimes` --> $DIR/non_scalar_alignment_value.rs:15:32 | LL | alignment: Assume {}, - | ^^^^^^ + | ^^^^^^^^^ error: struct expression with missing field initialiser for `safety` --> $DIR/non_scalar_alignment_value.rs:15:32 | LL | alignment: Assume {}, - | ^^^^^^ + | ^^^^^^^^^ error: struct expression with missing field initialiser for `validity` --> $DIR/non_scalar_alignment_value.rs:15:32 | LL | alignment: Assume {}, - | ^^^^^^ + | ^^^^^^^^^ error: aborting due to 4 previous errors; 1 warning emitted From d848437814ac8796a540b762dcb446f20384969e Mon Sep 17 00:00:00 2001 From: andjsrk Date: Wed, 7 Jan 2026 12:09:07 +0900 Subject: [PATCH 0324/1061] add more information in comment --- .../ui/repeat-expr/can-have-side-effects-consider-element.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui/repeat-expr/can-have-side-effects-consider-element.rs b/tests/ui/repeat-expr/can-have-side-effects-consider-element.rs index d0b5d12455dc..274942f9379f 100644 --- a/tests/ui/repeat-expr/can-have-side-effects-consider-element.rs +++ b/tests/ui/repeat-expr/can-have-side-effects-consider-element.rs @@ -5,8 +5,8 @@ // Test if `Expr::can_have_side_effects` considers element of repeat expressions. fn drop_repeat_in_arm_body() { - // Built-in lint `dropping_copy_types` relies on - // `Expr::can_have_side_effects` (See rust-clippy#9482) + // Built-in lint `dropping_copy_types` relies on `Expr::can_have_side_effects` + // (See rust-clippy#9482 and rust#113231) match () { () => drop([0; 1]), // No side effects From 11324546168855ddb221b019e0fa004e9de78881 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Wed, 7 Jan 2026 06:03:51 +0100 Subject: [PATCH 0325/1061] tests/ui/runtime/on-broken-pipe/with-rustc_main.rs: Not needed so remove It was added in ddee45e1d7fd when SIGPIPE was controlled with an attribute on `fn main()` which meant it could also be combined with `#[rustc_main]`: #[unix_sigpipe = "sig_dfl"] #[rustc_main] fn rustc_main() { It stopped being needed cde0cde151f3 when `#[unix_sigpipe = "..."]` was replaced by `-Zon-broken-pipe=...`. And it will not be needed when `-Zon-broken-pipe=...` is replaced by an Externally Implementable Item. Let's remove this test. --- .../ui/runtime/on-broken-pipe/with-rustc_main.rs | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 tests/ui/runtime/on-broken-pipe/with-rustc_main.rs diff --git a/tests/ui/runtime/on-broken-pipe/with-rustc_main.rs b/tests/ui/runtime/on-broken-pipe/with-rustc_main.rs deleted file mode 100644 index c40590ad87f4..000000000000 --- a/tests/ui/runtime/on-broken-pipe/with-rustc_main.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ run-pass -//@ aux-build:sigpipe-utils.rs -//@ compile-flags: -Zon-broken-pipe=kill -//@ only-unix because SIGPIPE is a unix thing - -#![feature(rustc_attrs)] - -#[rustc_main] -fn rustc_main() { - extern crate sigpipe_utils; - - // `-Zon-broken-pipe=kill` is active, so SIGPIPE handler shall be - // SIG_DFL. Note that we have a #[rustc_main], but it should still work. - sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default); -} From d37d04a37c6a9cd62e4c9518ffd47352a2a2ad1e Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Sun, 4 Jan 2026 04:51:44 +0100 Subject: [PATCH 0326/1061] recognize safety comments inside blocks and on same line in macros allow only whitespace between the comment marker and `SAFETY:` --- .../src/undocumented_unsafe_blocks.rs | 35 ++++ .../undocumented_unsafe_blocks.default.stderr | 156 +++++++++------- ...undocumented_unsafe_blocks.disabled.stderr | 168 ++++++++++-------- .../undocumented_unsafe_blocks.rs | 67 +++++++ 4 files changed, 288 insertions(+), 138 deletions(-) diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs index 9d27a66a9ab8..1b26b1b32b80 100644 --- a/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -115,6 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { && !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, block.hir_id) && !is_unsafe_from_proc_macro(cx, block.span) && !block_has_safety_comment(cx, block.span, self.accept_comment_above_attributes) + && !block_has_inner_safety_comment(cx, block.span) && !block_parents_have_safety_comment( self.accept_comment_above_statement, self.accept_comment_above_attributes, @@ -839,6 +840,23 @@ fn text_has_safety_comment( } } } + // Check for a comment that appears after other code on the same line (e.g., `let x = // SAFETY:`) + // This handles cases in macros where the comment is on the same line as preceding code. + // We only check the first (immediate preceding) line for this pattern. + // Only whitespace is allowed between the comment marker and `SAFETY:`. + if let Some(comment_start) = [line.find("//"), line.find("/*")].into_iter().flatten().min() + && let after_marker = &line[comment_start + 2..] // skip marker + && let trimmed = after_marker.trim_start() // skip whitespace + && trimmed.get(..7).is_some_and(|s| s.eq_ignore_ascii_case("SAFETY:")) + { + let safety_offset = 2 + (after_marker.len() - trimmed.len()); + return HasSafetyComment::Yes( + start_pos + + BytePos(u32::try_from(line_start).unwrap()) + + BytePos(u32::try_from(comment_start + safety_offset).unwrap()), + false, + ); + } // No line comments; look for the start of a block comment. // This will only find them if they are at the start of a line. let (mut line_start, mut line) = (line_start, line); @@ -894,3 +912,20 @@ fn is_const_or_static(node: &Node<'_>) -> bool { }) ) } + +fn block_has_inner_safety_comment(cx: &LateContext<'_>, span: Span) -> bool { + let source_map = cx.sess().source_map(); + if let Ok(src) = source_map.span_to_snippet(span) + && let Some(after_brace) = src + .strip_prefix("unsafe") + .and_then(|s| s.trim_start().strip_prefix('{')) + && let Some(comment) = after_brace + .trim_start() + .strip_prefix("//") + .or_else(|| after_brace.trim_start().strip_prefix("/*")) + { + comment.trim_start().to_ascii_uppercase().starts_with("SAFETY:") + } else { + false + } +} diff --git a/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr b/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr index 61e5af81d827..bcc46adda8a0 100644 --- a/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr +++ b/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr @@ -1,15 +1,39 @@ error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:270:19 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:244:22 + | +LL | let _x = unsafe { 1 }; + | ^^^^^^^^^^^^ +... +LL | t!(); + | ---- in this macro invocation + | + = help: consider adding a safety comment on the preceding line + = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::undocumented_unsafe_blocks)]` + = note: this error originates in the macro `t` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: unsafe block missing a safety comment + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:256:13 + | +LL | unsafe { 1 }; + | ^^^^^^^^^^^^ +... +LL | t!(); + | ---- in this macro invocation + | + = help: consider adding a safety comment on the preceding line + = note: this error originates in the macro `t` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: unsafe block missing a safety comment + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:337:19 | LL | /* Safety: */ unsafe {} | ^^^^^^^^^ | = help: consider adding a safety comment on the preceding line - = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::undocumented_unsafe_blocks)]` error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:275:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:342:5 | LL | unsafe {} | ^^^^^^^^^ @@ -17,7 +41,7 @@ LL | unsafe {} = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:280:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:347:14 | LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; | ^^^^^^^^^^^^^ @@ -25,7 +49,7 @@ LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:280:29 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:347:29 | LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; | ^^^^^^^^^^^^^ @@ -33,7 +57,7 @@ LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:280:48 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:347:48 | LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; | ^^^^^^^^^^^^^ @@ -41,7 +65,7 @@ LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:287:18 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:354:18 | LL | let _ = (42, unsafe {}, "test", unsafe {}); | ^^^^^^^^^ @@ -49,7 +73,7 @@ LL | let _ = (42, unsafe {}, "test", unsafe {}); = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:287:37 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:354:37 | LL | let _ = (42, unsafe {}, "test", unsafe {}); | ^^^^^^^^^ @@ -57,7 +81,7 @@ LL | let _ = (42, unsafe {}, "test", unsafe {}); = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:293:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:360:14 | LL | let _ = *unsafe { &42 }; | ^^^^^^^^^^^^^^ @@ -65,7 +89,7 @@ LL | let _ = *unsafe { &42 }; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:299:19 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:366:19 | LL | let _ = match unsafe {} { | ^^^^^^^^^ @@ -73,7 +97,7 @@ LL | let _ = match unsafe {} { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:306:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:373:14 | LL | let _ = &unsafe {}; | ^^^^^^^^^ @@ -81,7 +105,7 @@ LL | let _ = &unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:311:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:378:14 | LL | let _ = [unsafe {}; 5]; | ^^^^^^^^^ @@ -89,7 +113,7 @@ LL | let _ = [unsafe {}; 5]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:316:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:383:13 | LL | let _ = unsafe {}; | ^^^^^^^^^ @@ -97,7 +121,7 @@ LL | let _ = unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:327:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:394:8 | LL | t!(unsafe {}); | ^^^^^^^^^ @@ -105,7 +129,7 @@ LL | t!(unsafe {}); = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:334:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:401:13 | LL | unsafe {} | ^^^^^^^^^ @@ -117,7 +141,7 @@ LL | t!(); = note: this error originates in the macro `t` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:343:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:410:5 | LL | unsafe {} // SAFETY: | ^^^^^^^^^ @@ -125,7 +149,7 @@ LL | unsafe {} // SAFETY: = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:349:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:416:5 | LL | unsafe { | ^^^^^^^^ @@ -133,7 +157,7 @@ LL | unsafe { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:360:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:427:5 | LL | unsafe {}; | ^^^^^^^^^ @@ -141,7 +165,7 @@ LL | unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:365:20 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:432:20 | LL | println!("{}", unsafe { String::from_utf8_unchecked(vec![]) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -149,7 +173,7 @@ LL | println!("{}", unsafe { String::from_utf8_unchecked(vec![]) }); = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:373:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:440:5 | LL | unsafe impl A for () {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +181,7 @@ LL | unsafe impl A for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:381:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:448:9 | LL | unsafe impl B for (u32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -165,7 +189,7 @@ LL | unsafe impl B for (u32) {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:403:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:470:13 | LL | unsafe impl T for $t {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -177,7 +201,7 @@ LL | no_safety_comment!(()); = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:429:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:496:13 | LL | unsafe impl T for $t {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -189,7 +213,7 @@ LL | no_safety_comment!(()); = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:439:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:506:5 | LL | unsafe impl T for (i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -197,7 +221,7 @@ LL | unsafe impl T for (i32) {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:429:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:496:13 | LL | unsafe impl T for $t {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -209,7 +233,7 @@ LL | no_safety_comment!(u32); = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:446:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:513:5 | LL | unsafe impl T for (bool) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -217,7 +241,7 @@ LL | unsafe impl T for (bool) {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:493:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:560:5 | LL | unsafe impl NoComment for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -225,7 +249,7 @@ LL | unsafe impl NoComment for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:498:19 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:565:19 | LL | /* SAFETY: */ unsafe impl InlineComment for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -233,7 +257,7 @@ LL | /* SAFETY: */ unsafe impl InlineComment for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:503:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:570:5 | LL | unsafe impl TrailingComment for () {} // SAFETY: | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -241,13 +265,13 @@ LL | unsafe impl TrailingComment for () {} // SAFETY: = help: consider adding a safety comment on the preceding line error: constant has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:508:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:575:5 | LL | const BIG_NUMBER: i32 = 1000000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:507:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:574:8 | LL | // SAFETY: | ^^^^^^^ @@ -255,7 +279,7 @@ LL | // SAFETY: = help: to override `-D warnings` add `#[allow(clippy::unnecessary_safety_comment)]` error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:510:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:577:5 | LL | unsafe impl Interference for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -263,7 +287,7 @@ LL | unsafe impl Interference for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:518:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:585:5 | LL | unsafe impl ImplInFn for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -271,7 +295,7 @@ LL | unsafe impl ImplInFn for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:528:1 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:595:1 | LL | unsafe impl CrateRoot for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -279,7 +303,7 @@ LL | unsafe impl CrateRoot for () {} = help: consider adding a safety comment on the preceding line error: statement has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:543:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:610:5 | LL | / let _ = { LL | | @@ -289,13 +313,13 @@ LL | | }; | |______^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:542:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:609:8 | LL | // SAFETY: this is more than one level away, so it should warn | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:545:12 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:612:12 | LL | if unsafe { true } { | ^^^^^^^^^^^^^^^ @@ -303,7 +327,7 @@ LL | if unsafe { true } { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:549:23 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:616:23 | LL | let bar = unsafe {}; | ^^^^^^^^^ @@ -311,7 +335,7 @@ LL | let bar = unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:638:52 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:705:52 | LL | const NO_SAFETY_IN_TRAIT_BUT_IN_IMPL: u8 = unsafe { 0 }; | ^^^^^^^^^^^^ @@ -319,7 +343,7 @@ LL | const NO_SAFETY_IN_TRAIT_BUT_IN_IMPL: u8 = unsafe { 0 }; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:647:41 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:714:41 | LL | const NO_SAFETY_IN_TRAIT: i32 = unsafe { 1 }; | ^^^^^^^^^^^^ @@ -327,7 +351,7 @@ LL | const NO_SAFETY_IN_TRAIT: i32 = unsafe { 1 }; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:657:42 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:724:42 | LL | const HAS_SAFETY_IN_TRAIT: i32 = unsafe { 3 }; | ^^^^^^^^^^^^ @@ -335,7 +359,7 @@ LL | const HAS_SAFETY_IN_TRAIT: i32 = unsafe { 3 }; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:662:40 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:729:40 | LL | const NO_SAFETY_IN_IMPL: i32 = unsafe { 1 }; | ^^^^^^^^^^^^ @@ -343,136 +367,136 @@ LL | const NO_SAFETY_IN_IMPL: i32 = unsafe { 1 }; = help: consider adding a safety comment on the preceding line error: constant has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:701:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:768:5 | LL | const UNIX_EPOCH_JULIAN_DAY: i32 = | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:699:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:766:8 | LL | // SAFETY: fail ONLY if `accept-comment-above-attribute = false` | ^^^^^^^ error: statement has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:721:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:788:5 | LL | _ = bar(); | ^^^^^^^^^^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:720:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:787:8 | LL | // SAFETY: unnecessary_safety_comment triggers here | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: module has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:741:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:808:5 | LL | mod x {} | ^^^^^^^^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:740:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:807:8 | LL | // SAFETY: ... | ^^^^^^^ error: module has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:746:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:813:5 | LL | mod y {} | ^^^^^^^^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:744:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:811:8 | LL | // SAFETY: ... | ^^^^^^^ error: module has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:751:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:818:5 | LL | mod z {} | ^^^^^^^^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:750:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:817:8 | LL | // SAFETY: ... | ^^^^^^^ error: module has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:759:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:826:5 | LL | mod y {} | ^^^^^^^^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:757:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:824:8 | LL | // SAFETY: ... | ^^^^^^^ error: statement has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:774:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:841:9 | LL | let x = 34; | ^^^^^^^^^^^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:772:12 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:839:12 | LL | // SAFETY: ... | ^^^^^^^^^^^ error: function has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:781:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:848:5 | LL | unsafe fn unsafe_comment() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider changing the `safety` comment for a `# Safety` doc comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:780:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:847:8 | LL | // SAFETY: Bla | ^^^^^^^ error: function has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:787:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:854:5 | LL | unsafe fn unsafe_block_comment() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider changing the `safety` comment for a `# Safety` doc comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:785:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:852:8 | LL | SAFETY: Bla | ^^^^^^^ error: function has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:791:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:858:5 | LL | fn safe_comment() {} | ^^^^^^^^^^^^^^^^^^^^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:790:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:857:8 | LL | // SAFETY: Bla | ^^^^^^^ error: function has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:795:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:862:5 | LL | fn safe_doc_comment() {} | ^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:794:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:861:9 | LL | /// SAFETY: Bla | ^^^^^^^ -error: aborting due to 50 previous errors +error: aborting due to 52 previous errors diff --git a/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr b/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr index e252cffea916..0de8ed716bed 100644 --- a/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr +++ b/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr @@ -1,15 +1,39 @@ error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:270:19 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:244:22 + | +LL | let _x = unsafe { 1 }; + | ^^^^^^^^^^^^ +... +LL | t!(); + | ---- in this macro invocation + | + = help: consider adding a safety comment on the preceding line + = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::undocumented_unsafe_blocks)]` + = note: this error originates in the macro `t` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: unsafe block missing a safety comment + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:256:13 + | +LL | unsafe { 1 }; + | ^^^^^^^^^^^^ +... +LL | t!(); + | ---- in this macro invocation + | + = help: consider adding a safety comment on the preceding line + = note: this error originates in the macro `t` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: unsafe block missing a safety comment + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:337:19 | LL | /* Safety: */ unsafe {} | ^^^^^^^^^ | = help: consider adding a safety comment on the preceding line - = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::undocumented_unsafe_blocks)]` error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:275:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:342:5 | LL | unsafe {} | ^^^^^^^^^ @@ -17,7 +41,7 @@ LL | unsafe {} = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:280:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:347:14 | LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; | ^^^^^^^^^^^^^ @@ -25,7 +49,7 @@ LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:280:29 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:347:29 | LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; | ^^^^^^^^^^^^^ @@ -33,7 +57,7 @@ LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:280:48 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:347:48 | LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; | ^^^^^^^^^^^^^ @@ -41,7 +65,7 @@ LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:287:18 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:354:18 | LL | let _ = (42, unsafe {}, "test", unsafe {}); | ^^^^^^^^^ @@ -49,7 +73,7 @@ LL | let _ = (42, unsafe {}, "test", unsafe {}); = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:287:37 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:354:37 | LL | let _ = (42, unsafe {}, "test", unsafe {}); | ^^^^^^^^^ @@ -57,7 +81,7 @@ LL | let _ = (42, unsafe {}, "test", unsafe {}); = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:293:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:360:14 | LL | let _ = *unsafe { &42 }; | ^^^^^^^^^^^^^^ @@ -65,7 +89,7 @@ LL | let _ = *unsafe { &42 }; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:299:19 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:366:19 | LL | let _ = match unsafe {} { | ^^^^^^^^^ @@ -73,7 +97,7 @@ LL | let _ = match unsafe {} { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:306:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:373:14 | LL | let _ = &unsafe {}; | ^^^^^^^^^ @@ -81,7 +105,7 @@ LL | let _ = &unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:311:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:378:14 | LL | let _ = [unsafe {}; 5]; | ^^^^^^^^^ @@ -89,7 +113,7 @@ LL | let _ = [unsafe {}; 5]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:316:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:383:13 | LL | let _ = unsafe {}; | ^^^^^^^^^ @@ -97,7 +121,7 @@ LL | let _ = unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:327:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:394:8 | LL | t!(unsafe {}); | ^^^^^^^^^ @@ -105,7 +129,7 @@ LL | t!(unsafe {}); = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:334:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:401:13 | LL | unsafe {} | ^^^^^^^^^ @@ -117,7 +141,7 @@ LL | t!(); = note: this error originates in the macro `t` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:343:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:410:5 | LL | unsafe {} // SAFETY: | ^^^^^^^^^ @@ -125,7 +149,7 @@ LL | unsafe {} // SAFETY: = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:349:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:416:5 | LL | unsafe { | ^^^^^^^^ @@ -133,7 +157,7 @@ LL | unsafe { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:360:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:427:5 | LL | unsafe {}; | ^^^^^^^^^ @@ -141,7 +165,7 @@ LL | unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:365:20 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:432:20 | LL | println!("{}", unsafe { String::from_utf8_unchecked(vec![]) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -149,7 +173,7 @@ LL | println!("{}", unsafe { String::from_utf8_unchecked(vec![]) }); = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:373:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:440:5 | LL | unsafe impl A for () {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +181,7 @@ LL | unsafe impl A for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:381:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:448:9 | LL | unsafe impl B for (u32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -165,7 +189,7 @@ LL | unsafe impl B for (u32) {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:403:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:470:13 | LL | unsafe impl T for $t {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -177,7 +201,7 @@ LL | no_safety_comment!(()); = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:429:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:496:13 | LL | unsafe impl T for $t {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -189,7 +213,7 @@ LL | no_safety_comment!(()); = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:439:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:506:5 | LL | unsafe impl T for (i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -197,7 +221,7 @@ LL | unsafe impl T for (i32) {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:429:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:496:13 | LL | unsafe impl T for $t {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -209,7 +233,7 @@ LL | no_safety_comment!(u32); = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:446:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:513:5 | LL | unsafe impl T for (bool) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -217,7 +241,7 @@ LL | unsafe impl T for (bool) {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:493:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:560:5 | LL | unsafe impl NoComment for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -225,7 +249,7 @@ LL | unsafe impl NoComment for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:498:19 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:565:19 | LL | /* SAFETY: */ unsafe impl InlineComment for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -233,7 +257,7 @@ LL | /* SAFETY: */ unsafe impl InlineComment for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:503:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:570:5 | LL | unsafe impl TrailingComment for () {} // SAFETY: | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -241,13 +265,13 @@ LL | unsafe impl TrailingComment for () {} // SAFETY: = help: consider adding a safety comment on the preceding line error: constant has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:508:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:575:5 | LL | const BIG_NUMBER: i32 = 1000000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:507:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:574:8 | LL | // SAFETY: | ^^^^^^^ @@ -255,7 +279,7 @@ LL | // SAFETY: = help: to override `-D warnings` add `#[allow(clippy::unnecessary_safety_comment)]` error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:510:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:577:5 | LL | unsafe impl Interference for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -263,7 +287,7 @@ LL | unsafe impl Interference for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:518:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:585:5 | LL | unsafe impl ImplInFn for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -271,7 +295,7 @@ LL | unsafe impl ImplInFn for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:528:1 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:595:1 | LL | unsafe impl CrateRoot for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -279,7 +303,7 @@ LL | unsafe impl CrateRoot for () {} = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:539:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:606:9 | LL | unsafe {}; | ^^^^^^^^^ @@ -287,7 +311,7 @@ LL | unsafe {}; = help: consider adding a safety comment on the preceding line error: statement has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:543:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:610:5 | LL | / let _ = { LL | | @@ -297,13 +321,13 @@ LL | | }; | |______^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:542:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:609:8 | LL | // SAFETY: this is more than one level away, so it should warn | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:545:12 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:612:12 | LL | if unsafe { true } { | ^^^^^^^^^^^^^^^ @@ -311,7 +335,7 @@ LL | if unsafe { true } { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:549:23 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:616:23 | LL | let bar = unsafe {}; | ^^^^^^^^^ @@ -319,7 +343,7 @@ LL | let bar = unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:568:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:635:9 | LL | unsafe { a_function_with_a_very_long_name_to_break_the_line() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -327,7 +351,7 @@ LL | unsafe { a_function_with_a_very_long_name_to_break_the_line() }; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:573:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:640:9 | LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -335,7 +359,7 @@ LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:578:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:645:9 | LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -343,7 +367,7 @@ LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:585:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:652:5 | LL | unsafe {} | ^^^^^^^^^ @@ -351,7 +375,7 @@ LL | unsafe {} = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:590:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:657:5 | LL | unsafe { | ^^^^^^^^ @@ -359,7 +383,7 @@ LL | unsafe { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:598:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:665:9 | LL | unsafe { a_function_with_a_very_long_name_to_break_the_line() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -367,7 +391,7 @@ LL | unsafe { a_function_with_a_very_long_name_to_break_the_line() }; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:604:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:671:9 | LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -375,7 +399,7 @@ LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:611:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:678:9 | LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -383,7 +407,7 @@ LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:617:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:684:5 | LL | unsafe {} | ^^^^^^^^^ @@ -391,7 +415,7 @@ LL | unsafe {} = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:638:52 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:705:52 | LL | const NO_SAFETY_IN_TRAIT_BUT_IN_IMPL: u8 = unsafe { 0 }; | ^^^^^^^^^^^^ @@ -399,7 +423,7 @@ LL | const NO_SAFETY_IN_TRAIT_BUT_IN_IMPL: u8 = unsafe { 0 }; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:647:41 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:714:41 | LL | const NO_SAFETY_IN_TRAIT: i32 = unsafe { 1 }; | ^^^^^^^^^^^^ @@ -407,7 +431,7 @@ LL | const NO_SAFETY_IN_TRAIT: i32 = unsafe { 1 }; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:657:42 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:724:42 | LL | const HAS_SAFETY_IN_TRAIT: i32 = unsafe { 3 }; | ^^^^^^^^^^^^ @@ -415,7 +439,7 @@ LL | const HAS_SAFETY_IN_TRAIT: i32 = unsafe { 3 }; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:662:40 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:729:40 | LL | const NO_SAFETY_IN_IMPL: i32 = unsafe { 1 }; | ^^^^^^^^^^^^ @@ -423,7 +447,7 @@ LL | const NO_SAFETY_IN_IMPL: i32 = unsafe { 1 }; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:673:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:740:9 | LL | unsafe { here_is_another_variable_with_long_name }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -431,7 +455,7 @@ LL | unsafe { here_is_another_variable_with_long_name }; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:702:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:769:9 | LL | unsafe { Date::__from_ordinal_date_unchecked(1970, 1) }.into_julian_day_just_make_this_line_longer(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -439,19 +463,19 @@ LL | unsafe { Date::__from_ordinal_date_unchecked(1970, 1) }.into_julian = help: consider adding a safety comment on the preceding line error: statement has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:721:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:788:5 | LL | _ = bar(); | ^^^^^^^^^^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:720:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:787:8 | LL | // SAFETY: unnecessary_safety_comment triggers here | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:735:12 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:802:12 | LL | return unsafe { h() }; | ^^^^^^^^^^^^^^ @@ -459,31 +483,31 @@ LL | return unsafe { h() }; = help: consider adding a safety comment on the preceding line error: module has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:741:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:808:5 | LL | mod x {} | ^^^^^^^^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:740:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:807:8 | LL | // SAFETY: ... | ^^^^^^^ error: module has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:751:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:818:5 | LL | mod z {} | ^^^^^^^^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:750:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:817:8 | LL | // SAFETY: ... | ^^^^^^^ error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:766:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:833:9 | LL | unsafe {} | ^^^^^^^^^ @@ -491,52 +515,52 @@ LL | unsafe {} = help: consider adding a safety comment on the preceding line error: function has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:781:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:848:5 | LL | unsafe fn unsafe_comment() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider changing the `safety` comment for a `# Safety` doc comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:780:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:847:8 | LL | // SAFETY: Bla | ^^^^^^^ error: function has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:787:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:854:5 | LL | unsafe fn unsafe_block_comment() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider changing the `safety` comment for a `# Safety` doc comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:785:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:852:8 | LL | SAFETY: Bla | ^^^^^^^ error: function has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:791:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:858:5 | LL | fn safe_comment() {} | ^^^^^^^^^^^^^^^^^^^^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:790:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:857:8 | LL | // SAFETY: Bla | ^^^^^^^ error: function has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:795:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:862:5 | LL | fn safe_doc_comment() {} | ^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:794:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:861:9 | LL | /// SAFETY: Bla | ^^^^^^^ -error: aborting due to 60 previous errors +error: aborting due to 62 previous errors diff --git a/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs b/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs index db9e81cf10a1..8032c388ccfe 100644 --- a/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs +++ b/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs @@ -201,6 +201,66 @@ fn comment_macro_def() { t!(); } +fn comment_macro_def_with_let() { + macro_rules! t { + () => { + let _x = + // SAFETY: here be exactly one dragon + unsafe { 1 }; + }; + } + + t!(); +} + +#[rustfmt::skip] +fn comment_macro_def_with_let_same_line() { + macro_rules! t { + () => { + let _x =// SAFETY: same line comment + unsafe { 1 }; + }; + } + + t!(); +} + +fn inner_comment_macro_def_with_let() { + macro_rules! t { + () => { + let _x = unsafe { + // SAFETY: inside the block + 1 + }; + }; + } + + t!(); +} + +fn no_comment_macro_def_with_let() { + macro_rules! t { + () => { + let _x = unsafe { 1 }; + //~^ undocumented_unsafe_blocks + }; + } + + t!(); +} + +fn prefixed_safety_comment_macro_def_with_let() { + macro_rules! t { + () => { + let _x =// not a SAFETY: comment, should lint + unsafe { 1 }; + //~^ undocumented_unsafe_blocks + }; + } + + t!(); +} + fn non_ascii_comment() { // ॐ᧻໒ SaFeTy: ௵∰ unsafe {}; @@ -263,6 +323,13 @@ fn in_closure(x: *const u32) { let _ = || unsafe { *x }; } +fn inner_block_comment_block_style(x: *const u32) { + let _ = unsafe { + /* SAFETY: block comment inside */ + *x + }; +} + // Invalid comments #[rustfmt::skip] From f02ed7b565e6d9ba3b7b13abe86ea3a2dec3bf3c Mon Sep 17 00:00:00 2001 From: Spxg Date: Wed, 7 Jan 2026 17:10:56 +0800 Subject: [PATCH 0327/1061] Fix `alloc_error_handler` signature mismatch --- compiler/rustc_codegen_ssa/src/base.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 8ab0b367f08a..c8aa7c04585c 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -6,7 +6,8 @@ use std::time::{Duration, Instant}; use itertools::Itertools; use rustc_abi::FIRST_VARIANT; use rustc_ast::expand::allocator::{ - ALLOC_ERROR_HANDLER, ALLOCATOR_METHODS, AllocatorKind, AllocatorMethod, AllocatorTy, + ALLOC_ERROR_HANDLER, ALLOCATOR_METHODS, AllocatorKind, AllocatorMethod, AllocatorMethodInput, + AllocatorTy, }; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; @@ -671,7 +672,7 @@ pub fn allocator_shim_contents(tcx: TyCtxt<'_>, kind: AllocatorKind) -> Vec Date: Wed, 7 Jan 2026 10:03:04 +0100 Subject: [PATCH 0328/1061] Do not warn about large stack arrays without having a valid span The libtest harness generates an array with all the tests on the stack. However, it is generated with no location information, so we cannot tell the user anything useful. This commit is not accompanied by a test, as it would require running Clippy on the result of libtest harness with a lot of tests, which would take a very long time. A note has been added to the source to indicate not to remove the check. --- clippy_lints/src/large_stack_arrays.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index 620e27fa67c6..7bb7bc91f0c9 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -94,6 +94,15 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { }) && u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size) { + // libtest might generate a large array containing the test cases, and no span will be associated + // to it. In this case it is better not to complain. + // + // Note that this condition is not checked explicitly by a unit test. Do not remove it without + // ensuring that stays fixed. + if expr.span.is_dummy() { + return; + } + span_lint_and_then( cx, LARGE_STACK_ARRAYS, From d2497820d02ddec3b57cd9cb60e698bf472d2808 Mon Sep 17 00:00:00 2001 From: Colin Finck Date: Wed, 7 Jan 2026 12:06:37 +0100 Subject: [PATCH 0329/1061] build-manifest: Add `rust-mingw` also as extension for "pc-windows-gnu" hosts. This should enable `rustup component add --target aarch64-pc-windows-gnullvm rust-mingw` when running an `x86_64-pc-windows-gnullvm` toolchain (and vice-versa). Which itself enables proper cross-compiling of Windows ARM64 binaries on a Windows x64 host without using commercial MSVC. --- src/tools/build-manifest/src/main.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 42db12e5e117..4cec1b1f164b 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -282,6 +282,14 @@ impl Builder { PkgType::RustMingw => { if host.contains("pc-windows-gnu") { components.push(host_component(pkg)); + extensions.extend( + TARGETS + .iter() + .filter(|&&target| { + target.contains("pc-windows-gnu") && target != host + }) + .map(|target| Component::from_pkg(pkg, target)), + ); } } // Tools are always present in the manifest, From 6f7313e8adaec57196cec3d368cac8dd5fbf3d99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 7 Jan 2026 12:55:38 +0100 Subject: [PATCH 0330/1061] Make verify-channel.sh script compatible with new bors --- src/ci/scripts/verify-channel.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ci/scripts/verify-channel.sh b/src/ci/scripts/verify-channel.sh index 9a9e713243d7..cac8ba332ed1 100755 --- a/src/ci/scripts/verify-channel.sh +++ b/src/ci/scripts/verify-channel.sh @@ -8,7 +8,8 @@ IFS=$'\n\t' source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" -if isCiBranch auto || isCiBranch try || isCiBranch try-perf || isCiBranch automation/bors/try; then +if isCiBranch auto || isCiBranch try || isCiBranch try-perf || \ + isCiBranch automation/bors/try || isCiBranch automation/bors/auto; then echo "channel verification is only executed on PR builds" exit fi From 43e1604defa289b21cacf5f8e3c7d1ae741ecdca Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 7 Jan 2026 14:51:18 +0200 Subject: [PATCH 0331/1061] rustc book: fix grammar --- src/doc/rustc/src/remap-source-paths.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/remap-source-paths.md b/src/doc/rustc/src/remap-source-paths.md index ebe92d71158a..a499f9d3c77e 100644 --- a/src/doc/rustc/src/remap-source-paths.md +++ b/src/doc/rustc/src/remap-source-paths.md @@ -41,7 +41,7 @@ This example replaces all occurrences of `/home/user/project` in emitted paths w ## Caveats and Limitations -### Linkers generated paths +### Paths generated by linkers On some platforms like `x86_64-pc-windows-msvc`, the linker may embed absolute host paths and compiler arguments into debug info files (like `.pdb`) independently of `rustc`. From 5b4dbe02131e184a21cffea58f4550b1787edf9b Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 7 Jan 2026 14:53:21 +0200 Subject: [PATCH 0332/1061] add missing commas --- src/doc/rustc/src/remap-source-paths.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc/src/remap-source-paths.md b/src/doc/rustc/src/remap-source-paths.md index a499f9d3c77e..dc00278fac67 100644 --- a/src/doc/rustc/src/remap-source-paths.md +++ b/src/doc/rustc/src/remap-source-paths.md @@ -3,7 +3,7 @@ `rustc` supports remapping source paths prefixes **as a best effort** in all compiler generated output, including compiler diagnostics, debugging information, macro expansions, etc. -This is useful for normalizing build products, for example by removing the current directory +This is useful for normalizing build products, for example, by removing the current directory out of the paths emitted into object files. The remapping is done via the `--remap-path-prefix` option. @@ -54,7 +54,7 @@ The `--remap-path-prefix` option does not affect these linker-generated paths. ### Textual replacement only The remapping is strictly textual and does not account for different path separator conventions across -platforms. Care must be taken when specifying prefixes, especially on Windows where both `/` and `\` may +platforms. Care must be taken when specifying prefixes, especially on Windows, where both `/` and `\` may appear in paths. ### External tools From ea7ada90c61c4edc748c7a1a3c89c77ec5648b99 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 7 Jan 2026 13:55:53 +0100 Subject: [PATCH 0333/1061] Update browser-ui-test version to `0.23.1` --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ef74853b77a5..0cba589d23f5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "dependencies": { - "browser-ui-test": "^0.23.0", + "browser-ui-test": "^0.23.1", "es-check": "^9.4.4", "eslint": "^8.57.1", "typescript": "^5.8.3" From a928f3352d43ce4034e664aa310982657dc55c26 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 3 Jan 2026 13:06:54 +0100 Subject: [PATCH 0334/1061] Rename `tests/rustdoc` into `tests/rustdoc-html` --- rustfmt.toml | 2 +- src/bootstrap/src/core/build_steps/test.rs | 14 +++++++------- .../src/core/build_steps/test/compiletest.rs | 4 ++-- src/bootstrap/src/core/builder/cli_paths.rs | 2 +- .../builder/cli_paths/snapshots/x_test.snap | 5 ++--- .../snapshots/x_test_librustdoc_rustdoc.snap | 3 --- .../x_test_librustdoc_rustdoc_html.snap | 10 ++++++++++ .../cli_paths/snapshots/x_test_rustdoc.snap | 3 --- .../snapshots/x_test_rustdoc_html.snap | 7 +++++++ .../snapshots/x_test_skip_coverage.snap | 5 ++--- .../cli_paths/snapshots/x_test_tests.snap | 6 +++--- .../snapshots/x_test_tests_skip_coverage.snap | 6 +++--- .../src/core/builder/cli_paths/tests.rs | 2 ++ src/bootstrap/src/core/builder/mod.rs | 2 +- src/bootstrap/src/core/builder/tests.rs | 19 ++++++++----------- src/ci/citool/tests/test-jobs.yml | 2 +- .../host-x86_64/x86_64-gnu-gcc/Dockerfile | 2 +- src/librustdoc/html/render/write_shared.rs | 3 ++- src/tools/compiletest/src/common.rs | 4 ++-- src/tools/compiletest/src/directives.rs | 2 +- src/tools/compiletest/src/directives/tests.rs | 2 +- src/tools/compiletest/src/lib.rs | 6 +++--- src/tools/compiletest/src/runtest.rs | 4 ++-- src/tools/compiletest/src/runtest/rustdoc.rs | 2 +- src/tools/compiletest/src/rustdoc_gui_test.rs | 2 +- src/tools/opt-dist/src/tests.rs | 2 +- src/tools/tidy/src/features.rs | 2 +- tests/{rustdoc => rustdoc-html}/all.rs | 0 .../anchor-id-duplicate-method-name-25001.rs | 0 .../anchors/anchor-id-trait-method-15169.rs | 0 .../anchors/anchor-id-trait-tymethod-28478.rs | 0 .../anchors/anchors.no_const_anchor.html | 0 .../anchors/anchors.no_const_anchor2.html | 0 .../anchors/anchors.no_method_anchor.html | 0 .../anchors.no_trait_method_anchor.html | 0 .../anchors/anchors.no_tymethod_anchor.html | 0 .../anchors/anchors.no_type_anchor.html | 0 .../anchors/anchors.no_type_anchor2.html | 0 .../anchors/anchors.rs | 0 .../anchors/auxiliary/issue-86620-1.rs | 0 .../anchors/disambiguate-anchors-32890.rs | 0 .../disambiguate-anchors-header-29449.rs | 0 .../method-anchor-in-blanket-impl-86620.rs | 0 .../trait-impl-items-links-and-anchors.rs | 0 .../anon-fn-params.rs | 0 .../anonymous-lifetime.rs | 0 .../array-links.link_box_generic.html | 0 .../array-links.link_box_u32.html | 0 .../array-links.link_slice_generic.html | 0 .../array-links.link_slice_u32.html | 0 .../{rustdoc => rustdoc-html}/array-links.rs | 0 .../{rustdoc => rustdoc-html}/asm-foreign.rs | 0 .../{rustdoc => rustdoc-html}/asm-foreign2.rs | 0 .../asref-for-and-of-local-82465.rs | 0 .../assoc/assoc-fns.rs | 0 .../assoc/assoc-item-cast.rs | 0 .../assoc/assoc-type-bindings-20646.rs | 0 .../assoc/assoc-types.rs | 0 .../cross-crate-hidden-assoc-trait-items.rs | 0 .../assoc/auxiliary/issue-20646.rs | 0 .../assoc/auxiliary/issue-20727.rs | 0 .../assoc/auxiliary/normalize-assoc-item.rs | 0 .../cross-crate-hidden-assoc-trait-items.rs | 0 .../assoc/doc-assoc-item.rs | 0 .../assoc/inline-assoc-type-20727-bindings.rs | 0 .../inline-assoc-type-20727-bounds-deref.rs | 0 .../inline-assoc-type-20727-bounds-index.rs | 0 .../assoc/inline-assoc-type-20727-bounds.rs | 0 .../assoc/normalize-assoc-item.rs | 0 .../async/async-fn-opaque-item.rs | 0 .../async/async-fn.rs | 0 .../async/async-move-doctest.rs | 0 .../async/async-trait-sig.rs | 0 .../async/async-trait.rs | 0 .../async/auxiliary/async-trait-dep.rs | 0 .../attributes-2021-edition.rs | 0 .../attributes-inlining-108281.rs | 0 .../attributes-re-export-2021-edition.rs | 0 .../attributes-re-export.rs | 0 tests/{rustdoc => rustdoc-html}/attributes.rs | 0 .../auto/auto-impl-for-trait.rs | 0 .../auto/auto-impl-primitive.rs | 0 ...o-trait-bounds-by-associated-type-50159.rs | 0 ...-trait-bounds-inference-variables-54705.rs | 0 .../auto/auto-trait-bounds-where-51236.rs | 0 .../auto/auto-trait-negative-impl-55321.rs | 0 .../auto/auto-trait-not-send.rs | 0 .../auto/auto-traits.rs | 0 .../auto/auto_aliases.rs | 0 .../auto/auxiliary/auto-traits.rs | 0 .../auxiliary/all-item-types.rs | 0 .../auxiliary/cross_crate_generic_typedef.rs | 0 .../auxiliary/elided-lifetime.rs | 0 .../auxiliary/empty.rs | 0 .../auxiliary/enum-primitive.rs | 0 .../auxiliary/ext-anon-fn-params.rs | 0 .../auxiliary/ext-repr.rs | 0 .../auxiliary/ext-trait-aliases.rs | 0 .../auxiliary/inline-default-methods.rs | 0 .../auxiliary/issue-106421-force-unstable.rs | 0 .../auxiliary/issue-13698.rs | 0 .../auxiliary/issue-19190-3.rs | 0 .../auxiliary/issue-61592.rs | 0 .../auxiliary/issue-99221-aux.rs | 0 .../auxiliary/issue-99734-aux.rs | 0 .../jump-to-def-res-err-handling-aux.rs | 0 .../auxiliary/masked.rs | 0 .../auxiliary/mod-stackoverflow.rs | 0 .../auxiliary/reexp-stripped.rs | 0 .../auxiliary/remapped-paths.rs | 0 .../auxiliary/rustdoc-ffi.rs | 0 .../auxiliary/trait-visibility.rs | 0 .../auxiliary/unit-return.rs | 0 .../auxiliary/unsafe-binder-dep.rs | 0 .../auxiliary/unstable-trait.rs | 0 .../bad-codeblock-syntax.rs | 0 .../blank-line-in-doc-block-47197.rs | 0 .../bold-tag-101743.rs | 0 tests/{rustdoc => rustdoc-html}/bounds.rs | 0 tests/{rustdoc => rustdoc-html}/cap-lints.rs | 0 tests/{rustdoc => rustdoc-html}/cfg-bool.rs | 0 .../{rustdoc => rustdoc-html}/cfg-doctest.rs | 0 .../check-styled-link.rs | 0 tests/{rustdoc => rustdoc-html}/check.rs | 0 .../codeblock-title.rs | 0 .../comment-in-doctest.rs | 0 .../const-fn-76501.rs | 0 .../const-fn-effects.rs | 0 tests/{rustdoc => rustdoc-html}/const-fn.rs | 0 .../const-generics/add-impl.rs | 0 .../const-generics/auxiliary/extern_crate.rs | 0 .../const-generics/const-generic-defaults.rs | 0 .../const-generics/const-generic-slice.rs | 0 .../const-generics/const-generics-docs.rs | 0 .../const-generics/const-impl.rs | 0 .../const-param-type-references-generics.rs | 0 .../const-generics/generic_const_exprs.rs | 0 .../const-equate-pred.rs | 0 .../const-generics/type-alias.rs | 0 .../const-intrinsic.rs | 0 .../constant/assoc-consts-underscore.rs | 0 .../constant/assoc-consts-version.rs | 0 .../constant/assoc-consts.rs | 0 .../constant/associated-consts.rs | 0 .../constant/const-display.rs | 0 .../constant/const-doc.rs | 0 .../constant/const-effect-param.rs | 0 .../constant/const-trait-and-impl-methods.rs | 0 .../constant/const-underscore.rs | 0 .../constant/const-value-display.rs | 0 .../constant/const.rs | 0 ...m-with-associated-const-in-where-clause.rs | 0 .../constant/generic-const-items.rs | 0 .../constant/generic_const_exprs.rs | 0 .../constant/glob-shadowing-const.rs | 0 ...ide-complex-unevaluated-const-arguments.rs | 0 .../hide-complex-unevaluated-consts.rs | 0 .../ice-associated-const-equality-105952.rs | 0 .../constant/legacy-const-generic.rs | 0 .../constant/link-assoc-const.rs | 0 .../constant/redirect-const.rs | 0 .../constant/rfc-2632-const-trait-impl.rs | 0 .../constant/show-const-contents.rs | 0 .../constructor-imports.rs | 0 .../crate-doc-hidden-109695.rs | 0 .../crate-version-escape.rs | 0 .../crate-version-extra.rs | 0 .../crate-version.rs | 0 .../cargo-transitive-no-index/auxiliary/q.rs | 0 .../cargo-transitive-no-index/auxiliary/t.rs | 0 .../cargo-transitive-no-index/s.rs | 0 .../cargo-transitive/auxiliary/q.rs | 0 .../cargo-transitive/auxiliary/t.rs | 0 .../cross-crate-info/cargo-transitive/s.rs | 0 .../cargo-two-no-index/auxiliary/f.rs | 0 .../cross-crate-info/cargo-two-no-index/e.rs | 0 .../cross-crate-info/cargo-two/auxiliary/f.rs | 0 .../cross-crate-info/cargo-two/e.rs | 0 .../index-on-last/auxiliary/f.rs | 0 .../cross-crate-info/index-on-last/e.rs | 0 .../kitchen-sink/auxiliary/q.rs | 0 .../kitchen-sink/auxiliary/r.rs | 0 .../kitchen-sink/auxiliary/s.rs | 0 .../kitchen-sink/auxiliary/t.rs | 0 .../cross-crate-info/kitchen-sink/i.rs | 0 .../single-crate-baseline/q.rs | 0 .../single-crate-no-index/q.rs | 0 .../transitive/auxiliary/q.rs | 0 .../transitive/auxiliary/t.rs | 0 .../cross-crate-info/transitive/s.rs | 0 .../cross-crate-info/two/auxiliary/f.rs | 0 .../cross-crate-info/two/e.rs | 0 .../working-dir-examples/q.rs | 0 .../write-docs-somewhere-else/auxiliary/f.rs | 0 .../write-docs-somewhere-else/e.rs | 0 .../cross-crate-links.rs | 0 .../custom_code_classes.rs | 0 ...ecl-line-wrapping-empty-arg-list.decl.html | 0 .../decl-line-wrapping-empty-arg-list.rs | 0 .../decl-trailing-whitespace.declaration.html | 0 .../decl-trailing-whitespace.rs | 0 .../deep-structures.rs | 0 .../default-theme.rs | 0 .../default-trait-method-link.rs | 0 .../default-trait-method.rs | 0 .../demo-allocator-54478.rs | 0 .../deprecated-future-staged-api.rs | 0 .../deprecated-future.rs | 0 tests/{rustdoc => rustdoc-html}/deprecated.rs | 0 .../deref-methods-19190-foreign-type.rs | 0 .../deref-methods-19190-inline.rs | 0 .../deref-methods-19190.rs | 0 .../deref-mut-35169-2.rs | 0 .../deref-mut-35169.rs | 0 .../deref/deref-const-fn.rs | 0 .../deref/deref-methods-24686-target.rs | 0 .../deref/deref-multiple-impl-blocks.rs | 0 .../deref/deref-mut-methods.rs | 0 .../deref/deref-recursive-pathbuf.rs | 0 .../deref/deref-recursive.rs | 0 .../deref/deref-slice-core.rs | 0 .../deref/deref-to-primitive.rs | 0 .../deref/deref-typedef.rs | 0 .../deref/escape-deref-methods.rs | 0 .../deref/recursive-deref-sidebar.rs | 0 .../deref/recursive-deref.rs | 0 .../deref/sidebar-links-deref-100679.rs | 0 .../{rustdoc => rustdoc-html}/description.rs | 0 .../description_default.rs | 0 .../display-hidden-items.rs | 0 .../doc-attr-comment-mix-42760.rs | 0 .../doc-attribute.rs | 0 .../doc-auto-cfg-public-in-private.rs | 0 .../{rustdoc => rustdoc-html}/doc-auto-cfg.rs | 0 .../doc-cfg/doc-cfg-hide.rs | 0 .../doc-cfg/doc-cfg-implicit-gate.rs | 0 .../doc-cfg/doc-cfg-implicit.rs | 0 .../doc-cfg-inherit-from-module-79201.rs | 0 .../doc-cfg/doc-cfg-simplification.rs | 0 .../doc-cfg/doc-cfg-target-feature.rs | 0 .../doc-cfg/doc-cfg-traits.rs | 0 .../doc-cfg/doc-cfg.rs | 0 .../doc-cfg/duplicate-cfg.rs | 0 .../doc-hidden-crate.rs | 0 .../doc-hidden-method-13698.rs | 0 .../doc-on-keyword.rs | 0 .../doc-test-attr-18199.rs | 0 .../{rustdoc => rustdoc-html}/doc_auto_cfg.rs | 0 .../doc_auto_cfg_reexports.rs | 0 .../doctest/auxiliary/doctest-runtool.rs | 0 .../doctest/auxiliary/empty.rs | 0 .../doctest/doctest-cfg-feature-30252.rs | 0 .../doctest/doctest-crate-attributes-38129.rs | 0 ...doctest-escape-boring-41783.codeblock.html | 0 .../doctest/doctest-escape-boring-41783.rs | 0 .../doctest/doctest-hide-empty-line-23106.rs | 0 .../doctest/doctest-ignore-32556.rs | 0 .../doctest/doctest-include-43153.rs | 0 .../doctest/doctest-macro-38219.rs | 0 .../doctest/doctest-manual-crate-name.rs | 0 .../doctest-markdown-inline-parse-23744.rs | 0 ...octest-markdown-trailing-docblock-48377.rs | 0 ...doctest-multi-line-string-literal-25944.rs | 0 .../doctest/doctest-runtool.rs | 0 .../doctest/ignore-sometimes.rs | 0 .../document-hidden-items-15347.rs | 0 .../double-hyphen-to-dash.rs | 0 .../double-quote-escape.rs | 0 .../duplicate-flags.rs | 0 .../duplicate_impls/impls.rs | 0 .../sidebar-links-duplicate-impls-33054.rs | 0 .../dyn-compatibility.rs | 0 .../early-unindent.rs | 0 .../edition-doctest.rs | 0 .../{rustdoc => rustdoc-html}/edition-flag.rs | 0 .../elided-lifetime.rs | 0 .../empty-doc-comment.rs | 0 .../empty-mod-public.rs | 0 .../empty-section.rs | 0 .../empty-tuple-struct-118180.rs | 0 .../ensure-src-link.rs | 0 .../enum/auxiliary/enum-variant.rs | 0 .../enum/auxiliary/variant-struct.rs | 0 .../enum/enum-headings.rs | 0 .../enum/enum-non-exhaustive-108925.rs | 0 .../enum-variant-doc-hidden-field-88600.rs | 0 .../enum/enum-variant-fields-heading.rs | 0 .../enum-variant-fields-heading.variants.html | 0 .../enum/enum-variant-non_exhaustive.rs | 0 ...ariant-non_exhaustive.type-alias-code.html | 0 ...enum-variant-non_exhaustive.type-code.html | 0 .../enum/enum-variant-value.rs | 0 .../render-enum-variant-structlike-32395.rs | 0 .../enum/strip-enum-variant.no-not-shown.html | 0 .../enum/strip-enum-variant.rs | 0 .../extern/auxiliary/empty.rs | 0 .../extern/auxiliary/extern-links.rs | 0 .../extern/auxiliary/external-cross-doc.md | 0 .../extern/auxiliary/external-cross.rs | 0 .../extern/auxiliary/external-doc.md | 0 .../extern/auxiliary/html_root.rs | 0 .../extern/auxiliary/issue-30109-1.rs | 0 .../extern/auxiliary/no_html_root.rs | 0 .../extern/auxiliary/panic-item.rs | 0 .../extern/auxiliary/pub-extern-crate.rs | 0 .../rustdoc-extern-default-method.rs | 0 .../extern/auxiliary/rustdoc-extern-method.rs | 0 .../extern/auxiliary/variant-struct.rs | 0 .../duplicate-reexports-section-150211.rs | 0 ...tern-default-method.no_href_on_anchor.html | 0 .../extern/extern-default-method.rs | 0 .../extern/extern-fn-22038.rs | 0 .../extern/extern-html-alias.rs | 0 .../extern/extern-html-fallback.rs | 0 .../extern/extern-html-root-url-precedence.rs | 0 .../extern/extern-html-root-url.rs | 0 .../extern/extern-links.rs | 0 .../extern/extern-method.rs | 0 .../extern/external-cross.rs | 0 .../extern/external-doc.rs | 0 .../extern/hidden-extern-34025.rs | 0 .../extern/link-extern-crate-33178.rs | 0 .../extern/link-extern-crate-item-30109.rs | 0 .../extern/link-extern-crate-title-33178.rs | 0 .../extern/pub-extern-crate-150176.rs | 0 .../extern/pub-extern-crate.rs | 0 .../extern/unsafe-extern-blocks.rs | 0 .../extern/unused-extern-crate.rs | 0 ...long_typename.extremely_long_typename.html | 0 .../extremely_long_typename.rs | 0 .../feature-gate-doc_auto_cfg.rs | 0 tests/{rustdoc => rustdoc-html}/ffi.rs | 0 .../file-creation-111249.rs | 0 .../files-creation-hidden.rs | 0 tests/{rustdoc => rustdoc-html}/fn-bound.rs | 0 .../fn-pointer-arg-name.rs | 0 tests/{rustdoc => rustdoc-html}/fn-sidebar.rs | 0 tests/{rustdoc => rustdoc-html}/fn-type.rs | 0 ...te-definition-without-blank-line-100638.rs | 0 .../{rustdoc => rustdoc-html}/footnote-ids.rs | 0 .../footnote-in-summary.rs | 0 .../footnote-reference-ids.rs | 0 .../footnote-reference-in-footnote-def.rs | 0 .../force-target-feature.rs | 0 ...nstable-if-unmarked-106421-not-internal.rs | 0 .../force-unstable-if-unmarked-106421.rs | 0 .../{rustdoc => rustdoc-html}/foreigntype.rs | 0 .../gat-elided-lifetime-94683.rs | 0 .../gat-linkification-109488.rs | 0 .../generic-associated-types/gats.rs | 0 .../glob-shadowing.rs | 0 .../heading-levels-89309.rs | 0 .../heterogeneous-concat.rs | 0 .../{rustdoc => rustdoc-html}/hidden-line.rs | 0 .../hidden-methods.rs | 0 ...rait-methods-with-document-hidden-items.rs | 0 .../hidden-trait-methods.rs | 0 .../hide-unstable-trait.rs | 0 .../higher-ranked-trait-bounds.rs | 0 .../highlight-invalid-rust-12834.rs | 0 .../ice-type-error-19181.rs | 0 .../cross-crate-hidden-impl-parameter.rs | 0 .../impl/auxiliary/extern-impl-trait.rs | 0 .../impl/auxiliary/incoherent-impl-types.rs | 0 .../impl/auxiliary/issue-100204-aux.rs | 0 .../impl/auxiliary/issue-17476.rs | 0 .../impl/auxiliary/issue-21092.rs | 0 .../impl/auxiliary/issue-22025.rs | 0 .../impl/auxiliary/issue-53689.rs | 0 .../impl/auxiliary/precise-capturing.rs | 0 .../impl/auxiliary/real_gimli.rs | 0 .../impl/auxiliary/realcore.rs | 0 .../impl/auxiliary/rustdoc-default-impl.rs | 0 .../rustdoc-impl-parts-crosscrate.rs | 0 .../impl/blanket-impl-29503.rs | 0 .../impl/blanket-impl-78673.rs | 0 .../impl/cross-crate-hidden-impl-parameter.rs | 0 .../deduplicate-glob-import-impl-21474.rs | 0 .../impl/deduplicate-trait-impl-22025.rs | 0 .../impl/default-impl.rs | 0 .../impl/deprecated-impls.rs | 0 .../doc-hidden-trait-implementors-33069.rs | 0 .../impl/doc_auto_cfg_nested_impl.rs | 0 .../impl/duplicated_impl.rs | 0 .../impl/empty-impl-block.rs | 0 .../impl/empty-impls.rs | 0 .../impl/extern-impl-trait.rs | 0 .../impl/extern-impl.rs | 0 .../impl/foreign-implementors-js-43701.rs | 0 .../impl/generic-impl.rs | 0 .../impl/hidden-implementors-90781.rs | 0 .../impl/hidden-impls.rs | 0 .../impl/hidden-trait-struct-impls.rs | 0 ...e-mut-methods-if-no-derefmut-impl-74083.rs | 0 .../impl/impl-alias-substituted.rs | 0 .../impl/impl-assoc-type-21092.rs | 0 .../impl/impl-associated-items-order.rs | 0 .../impl/impl-associated-items-sidebar.rs | 0 .../impl/impl-blanket-53689.rs | 0 .../impl/impl-box.rs | 0 .../impl/impl-disambiguation.rs | 0 .../impl/impl-everywhere.rs | 0 .../impl/impl-in-const-block.rs | 0 .../impl/impl-on-ty-alias-issue-119015.rs | 0 .../impl/impl-parts-crosscrate.rs | 0 .../impl/impl-parts.rs | 0 .../impl/impl-ref-20175.rs | 0 .../impl/impl-trait-43869.rs | 0 .../impl/impl-trait-alias.rs | 0 .../impl/impl-trait-precise-capturing.rs | 0 .../impl/impl-type-parameter-33592.rs | 0 .../impl/implementor-stable-version.rs | 0 .../impl/implementors-unstable-75588.rs | 0 .../inline-impl-through-glob-import-100204.rs | 0 .../impl/manual_impl.rs | 0 .../method-link-foreign-trait-impl-17476.rs | 0 .../impl/module-impls.rs | 0 .../impl/must_implement_one_of.rs | 0 .../impl/negative-impl-no-items.rs | 0 .../impl/negative-impl-sidebar.rs | 0 .../impl/negative-impl.rs | 0 .../impl/return-impl-trait.rs | 0 .../impl/rustc-incoherent-impls.rs | 0 .../impl/same-crate-hidden-impl-parameter.rs | 0 .../sidebar-trait-impl-disambiguate-78701.rs | 0 .../impl/struct-implementations-title.rs | 0 .../impl/trait-impl.rs | 0 ...it-implementations-duplicate-self-45584.rs | 0 .../underscore-type-in-trait-impl-96381.rs | 0 .../impl/universal-impl-trait.rs | 0 .../unneeded-trait-implementations-title.rs | 0 .../import-remapped-paths.rs | 0 .../impossible-default.rs | 0 .../include_str_cut.rs | 0 tests/{rustdoc => rustdoc-html}/index-page.rs | 0 .../infinite-redirection-16265-1.rs | 0 .../infinite-redirection-16265-2.rs | 0 .../infinite-redirection.rs | 0 .../inherent-projections.rs | 0 .../inline-default-methods.rs | 0 .../inline-rename-34473.rs | 0 .../inline_cross/add-docs.rs | 0 .../inline_cross/assoc-const-equality.rs | 0 .../inline_cross/assoc-items.rs | 0 .../assoc_item_trait_bounds.out0.html | 0 .../assoc_item_trait_bounds.out2.html | 0 .../assoc_item_trait_bounds.out9.html | 0 .../inline_cross/assoc_item_trait_bounds.rs | 0 .../inline_cross/async-fn.rs | 0 .../inline_cross/attributes.rs | 0 .../inline_cross/auxiliary/add-docs.rs | 0 .../auxiliary/assoc-const-equality.rs | 0 .../inline_cross/auxiliary/assoc-items.rs | 0 .../auxiliary/assoc_item_trait_bounds.rs | 0 .../inline_cross/auxiliary/async-fn.rs | 0 .../inline_cross/auxiliary/attributes.rs | 0 .../auxiliary/const-effect-param.rs | 0 .../inline_cross/auxiliary/cross-glob.rs | 0 .../auxiliary/default-generic-args.rs | 0 .../auxiliary/default-trait-method.rs | 0 .../inline_cross/auxiliary/doc-auto-cfg.rs | 0 .../inline_cross/auxiliary/dyn_trait.rs | 0 .../early-late-bound-lifetime-params.rs | 0 .../inline_cross/auxiliary/fn-ptr-ty.rs | 0 .../auxiliary/generic-const-items.rs | 0 .../auxiliary/impl-inline-without-trait.rs | 0 .../inline_cross/auxiliary/impl-sized.rs | 0 .../inline_cross/auxiliary/impl_trait_aux.rs | 0 .../auxiliary/implementors_inline.rs | 0 .../inline_cross/auxiliary/issue-21801.rs | 0 .../inline_cross/auxiliary/issue-23207-1.rs | 0 .../inline_cross/auxiliary/issue-23207-2.rs | 0 .../inline_cross/auxiliary/issue-24183.rs | 0 .../inline_cross/auxiliary/issue-27362-aux.rs | 0 .../inline_cross/auxiliary/issue-29584.rs | 0 .../inline_cross/auxiliary/issue-33113.rs | 0 .../inline_cross/auxiliary/issue-46727.rs | 0 .../inline_cross/auxiliary/issue-57180.rs | 0 .../inline_cross/auxiliary/issue-76736-1.rs | 0 .../inline_cross/auxiliary/issue-76736-2.rs | 0 .../inline_cross/auxiliary/issue-85454.rs | 0 .../inline_cross/auxiliary/macro-vis.rs | 0 .../inline_cross/auxiliary/macros.rs | 0 .../auxiliary/non_lifetime_binders.rs | 0 .../inline_cross/auxiliary/proc_macro.rs | 0 .../reexport-with-anonymous-lifetime-98697.rs | 0 .../auxiliary/renamed-via-module.rs | 0 .../auxiliary/ret-pos-impl-trait-in-trait.rs | 0 .../auxiliary/rustdoc-hidden-sig.rs | 0 .../inline_cross/auxiliary/rustdoc-hidden.rs | 0 .../auxiliary/rustdoc-nonreachable-impls.rs | 0 .../auxiliary/rustdoc-trait-object-impl.rs | 0 .../inline_cross/auxiliary/trait-vis.rs | 0 .../inline_cross/auxiliary/use_crate.rs | 0 .../inline_cross/auxiliary/use_crate_2.rs | 0 .../inline_cross/const-effect-param.rs | 0 .../inline_cross/const-eval-46727.rs | 0 .../inline_cross/const-fn-27362.rs | 0 .../inline_cross/cross-glob.rs | 0 .../deduplicate-inlined-items-23207.rs | 0 .../inline_cross/default-generic-args.rs | 0 .../inline_cross/default-trait-method.rs | 0 .../inline_cross/doc-auto-cfg.rs | 0 .../doc-hidden-broken-link-28480.rs | 0 .../doc-hidden-extern-trait-impl-29584.rs | 0 .../doc-reachability-impl-31948-1.rs | 0 .../doc-reachability-impl-31948-2.rs | 0 .../doc-reachability-impl-31948.rs | 0 .../inline_cross/dyn_trait.rs | 0 .../early-late-bound-lifetime-params.rs | 0 .../inline_cross/fn-ptr-ty.rs | 0 .../inline_cross/generic-const-items.rs | 0 .../inline_cross/hidden-use.rs | 0 .../inline_cross/ice-import-crate-57180.rs | 0 .../inline_cross/impl-dyn-trait-32881.rs | 0 .../inline_cross/impl-inline-without-trait.rs | 0 .../inline_cross/impl-ref-33113.rs | 0 .../inline_cross/impl-sized.rs | 0 .../inline_cross/impl_trait.rs | 0 .../inline_cross/implementors-js.rs | 0 .../inline_cross/inline_hidden.rs | 0 .../inline_cross/macro-vis.rs | 0 .../inline_cross/macros.rs | 0 .../inline_cross/non_lifetime_binders.rs | 0 .../inline_cross/proc_macro.rs | 0 .../inline_cross/qpath-self-85454.rs | 0 .../reexport-with-anonymous-lifetime-98697.rs | 0 .../inline_cross/renamed-via-module.rs | 0 .../ret-pos-impl-trait-in-trait.rs | 0 .../inline_cross/rustc-private-76736-1.rs | 0 .../inline_cross/rustc-private-76736-2.rs | 0 .../inline_cross/rustc-private-76736-3.rs | 0 .../inline_cross/rustc-private-76736-4.rs | 0 ...unds-24183.method_no_where_self_sized.html | 0 .../inline_cross/self-sized-bounds-24183.rs | 0 .../inline_cross/sugar-closure-crate-21801.rs | 0 .../inline_cross/trait-vis.rs | 0 .../inline_cross/use_crate.rs | 0 .../blanket-impl-reexported-trait-94183.rs | 0 .../inline_local/doc-no-inline-32343.rs | 0 .../enum-variant-reexport-46766.rs | 0 .../fully-stable-path-is-better.rs | 0 .../glob-extern-document-private-items.rs | 0 .../inline_local/glob-extern.rs | 0 .../glob-private-document-private-items.rs | 0 .../inline_local/glob-private.rs | 0 .../inline_local/hidden-use.rs | 0 .../inline_local/macro_by_example.rs | 0 .../inline_local/parent-path-is-better.rs | 0 .../inline_local/please_inline.rs | 0 .../private-reexport-in-public-api-81141-2.rs | 0 .../private-reexport-in-public-api-81141.rs | 0 ...e-reexport-in-public-api-generics-81141.rs | 0 ...ate-reexport-in-public-api-hidden-81141.rs | 0 ...te-reexport-in-public-api-private-81141.rs | 0 .../inline_local/pub-re-export-28537.rs | 0 ...ed-macro-and-macro-export-sidebar-89852.rs | 0 .../inline_local/staged-inline.rs | 0 .../inline_local/trait-vis.rs | 0 tests/{rustdoc => rustdoc-html}/internal.rs | 0 .../intra-doc-crate/auxiliary/self.rs | 0 .../intra-doc-crate/self.rs | 0 .../intra-doc/anchors.rs | 0 .../intra-doc/assoc-reexport-super.rs | 0 .../intra-doc/associated-defaults.rs | 0 .../intra-doc/associated-items.rs | 0 .../intra-doc/auxiliary/empty.rs | 0 .../intra-doc/auxiliary/empty2.rs | 0 .../auxiliary/extern-builtin-type-impl-dep.rs | 0 .../auxiliary/extern-inherent-impl-dep.rs | 0 .../auxiliary/intra-link-extern-crate.rs | 0 .../intra-doc/auxiliary/intra-link-pub-use.rs | 0 .../intra-link-reexport-additional-docs.rs | 0 .../auxiliary/intra-links-external-traits.rs | 0 .../intra-doc/auxiliary/issue-66159-1.rs | 0 .../intra-doc/auxiliary/my-core.rs | 0 .../intra-doc/auxiliary/proc-macro-macro.rs | 0 .../intra-doc/auxiliary/pub-struct.rs | 0 .../intra-doc/basic.rs | 0 .../intra-doc/builtin-macros.rs | 0 .../intra-doc/crate-relative-assoc.rs | 0 .../intra-doc/crate-relative.rs | 0 .../intra-doc/cross-crate/additional_doc.rs | 0 .../cross-crate/auxiliary/additional_doc.rs | 0 .../intra-doc/cross-crate/auxiliary/hidden.rs | 0 .../cross-crate/auxiliary/intra-doc-basic.rs | 0 .../auxiliary/intra-link-cross-crate-crate.rs | 0 .../cross-crate/auxiliary/macro_inner.rs | 0 .../intra-doc/cross-crate/auxiliary/module.rs | 0 .../cross-crate/auxiliary/proc_macro.rs | 0 .../cross-crate/auxiliary/submodule-inner.rs | 0 .../cross-crate/auxiliary/submodule-outer.rs | 0 .../intra-doc/cross-crate/auxiliary/traits.rs | 0 .../intra-doc/cross-crate/basic.rs | 0 .../intra-doc/cross-crate/crate.rs | 0 .../intra-doc/cross-crate/hidden.rs | 0 .../intra-doc/cross-crate/macro.rs | 0 .../intra-doc/cross-crate/module.rs | 0 .../intra-doc/cross-crate/submodule-inner.rs | 0 .../intra-doc/cross-crate/submodule-outer.rs | 0 .../intra-doc/cross-crate/traits.rs | 0 .../intra-doc/deps.rs | 0 .../intra-doc/disambiguators-removed.rs | 0 .../intra-doc/email-address.rs | 0 .../intra-doc/enum-self-82209.rs | 0 .../intra-doc/enum-struct-field.rs | 0 .../intra-doc/extern-builtin-type-impl.rs | 0 .../extern-crate-only-used-in-link.rs | 0 .../intra-doc/extern-crate.rs | 0 .../intra-doc/extern-inherent-impl.rs | 0 .../intra-doc/extern-reference-link.rs | 0 .../intra-doc/extern-type.rs | 0 .../intra-doc/external-traits.rs | 0 .../intra-doc/field.rs | 0 .../intra-doc/filter-out-private.rs | 0 .../intra-doc/generic-params.rs | 0 .../intra-doc/generic-trait-impl.rs | 0 .../intra-doc/ice-intra-doc-links-107995.rs | 0 .../intra-doc/in-bodies.rs | 0 .../intra-doc/inherent-associated-types.rs | 0 .../intra-doc-link-method-trait-impl-72340.rs | 0 .../intra-doc/libstd-re-export.rs | 0 .../intra-doc/link-in-footnotes-132208.rs | 0 ...ame-name-different-disambiguator-108459.rs | 0 .../intra-doc/link-to-proc-macro.rs | 0 .../intra-doc/macro-caching-144965.rs | 0 .../intra-doc/macros-disambiguators.rs | 0 .../intra-doc/mod-ambiguity.rs | 0 .../intra-doc/mod-relative.rs | 0 .../module-scope-name-resolution-55364.rs | 0 .../intra-doc/nested-use.rs | 0 .../intra-doc/no-doc-primitive.rs | 0 .../intra-doc/non-path-primitives.rs | 0 .../intra-doc/prim-assoc.rs | 0 .../intra-doc/prim-associated-traits.rs | 0 .../intra-doc/prim-methods-external-core.rs | 0 .../intra-doc/prim-methods-local.rs | 0 .../intra-doc/prim-methods.rs | 0 .../intra-doc/prim-precedence.rs | 0 .../intra-doc/prim-self.rs | 0 .../intra-doc/primitive-disambiguators.rs | 0 .../intra-doc/primitive-non-default-impl.rs | 0 .../intra-doc/private-failures-ignored.rs | 0 .../intra-doc/private.rs | 0 .../intra-doc/proc-macro.rs | 0 .../intra-doc/pub-use.rs | 0 .../intra-doc/raw-ident-self.rs | 0 .../intra-doc/reexport-additional-docs.rs | 0 .../same-name-different-crates-66159.rs | 0 .../intra-doc/self-cache.rs | 0 .../intra-doc/self.rs | 0 .../intra-doc/trait-impl.rs | 0 .../intra-doc/trait-item.rs | 0 .../intra-doc/true-false.rs | 0 .../intra-doc/type-alias-primitive.rs | 0 .../intra-doc/type-alias.rs | 0 .../invalid$crate$name.rs | 0 .../item-desc-list-at-start.item-table.html | 0 .../item-desc-list-at-start.rs | 0 .../jump-to-def/assoc-items.rs | 0 .../jump-to-def/assoc-types.rs | 0 .../jump-to-def/auxiliary/symbols.rs | 0 .../jump-to-def/derive-macro.rs | 0 .../jump-to-def/doc-links-calls.rs | 0 .../jump-to-def/doc-links.rs | 0 .../jump-to-def/macro.rs | 0 .../jump-to-def/no-body-items.rs | 0 .../jump-to-def/non-local-method.rs | 0 .../jump-to-def/patterns.rs | 0 .../jump-to-def/prelude-types.rs | 0 .../jump-to-def/shebang.rs | 0 tests/{rustdoc => rustdoc-html}/keyword.rs | 0 .../lifetime-name.rs | 0 .../{rustdoc => rustdoc-html}/line-breaks.rs | 0 .../link-on-path-with-generics.rs | 0 .../link-title-escape.rs | 0 .../links-in-headings.rs | 0 .../logo-class-default.rs | 0 .../logo-class-rust.rs | 0 tests/{rustdoc => rustdoc-html}/logo-class.rs | 0 .../field-followed-by-exclamation.rs | 0 .../macro-expansion/type-macro-expansion.rs | 0 .../macro/auxiliary/external-macro-src.rs | 0 .../macro/auxiliary/issue-99221-aux.rs | 0 .../macro/auxiliary/macro_pub_in_module.rs | 0 .../macro/auxiliary/one-line-expand.rs | 0 .../macro/auxiliary/pub-use-extern-macros.rs | 0 .../macro/compiler-derive-proc-macro.rs | 0 .../macro/const-rendering-macros-33302.rs | 0 .../macro/decl_macro.rs | 0 .../macro/decl_macro_priv.rs | 0 .../macro/doc-proc-macro.rs | 0 .../macro/external-macro-src.rs | 0 .../macro/macro-const-display-115295.rs | 0 .../macro/macro-doc-comment-23812.rs | 0 .../macro/macro-export-crate-root-108231.rs | 0 ...o-generated-macro.macro_linebreak_pre.html | 0 ...o-generated-macro.macro_morestuff_pre.html | 0 .../macro/macro-generated-macro.rs | 0 .../macro/macro-higher-kinded-function.rs | 0 .../macro/macro-ice-16019.rs | 0 .../macro/macro-in-async-block.rs | 0 .../macro/macro-in-closure.rs | 0 .../macro/macro-indirect-use.rs | 0 .../macro/macro_expansion.rs | 0 .../macro/macro_pub_in_module.rs | 0 .../macro/macro_rules-matchers.rs | 0 .../{rustdoc => rustdoc-html}/macro/macros.rs | 0 .../multiple-macro-rules-w-same-name-99221.rs | 0 ...macro-rules-w-same-name-submodule-99221.rs | 0 .../macro/one-line-expand.rs | 0 .../macro/proc-macro.rs | 0 .../macro/pub-use-extern-macros.rs | 0 .../macro/rustc-macro-crate.rs | 0 .../markdown-60482.rs | 0 .../markdown-table-escape-pipe-27862.rs | 0 tests/{rustdoc => rustdoc-html}/masked.rs | 0 .../auxiliary/quebec.rs | 0 .../auxiliary/tango.rs | 0 .../cargo-transitive-read-write/sierra.rs | 0 .../auxiliary/quebec.rs | 0 .../auxiliary/romeo.rs | 0 .../auxiliary/sierra.rs | 0 .../auxiliary/tango.rs | 0 .../kitchen-sink-separate-dirs/indigo.rs | 0 .../no-merge-separate/auxiliary/quebec.rs | 0 .../no-merge-separate/auxiliary/tango.rs | 0 .../no-merge-separate/sierra.rs | 0 .../no-merge-write-anyway/auxiliary/quebec.rs | 0 .../no-merge-write-anyway/auxiliary/tango.rs | 0 .../no-merge-write-anyway/sierra.rs | 0 .../overwrite-but-include/auxiliary/quebec.rs | 0 .../overwrite-but-include/auxiliary/tango.rs | 0 .../overwrite-but-include/sierra.rs | 0 .../auxiliary/quebec.rs | 0 .../overwrite-but-separate/auxiliary/tango.rs | 0 .../overwrite-but-separate/sierra.rs | 0 .../overwrite/auxiliary/quebec.rs | 0 .../overwrite/auxiliary/tango.rs | 0 .../overwrite/sierra.rs | 0 .../single-crate-finalize/quebec.rs | 0 .../single-crate-read-write/quebec.rs | 0 .../single-crate-write-anyway/quebec.rs | 0 .../single-merge-none-useless-write/quebec.rs | 0 .../transitive-finalize/auxiliary/quebec.rs | 0 .../transitive-finalize/auxiliary/tango.rs | 0 .../transitive-finalize/sierra.rs | 0 .../transitive-merge-none/auxiliary/quebec.rs | 0 .../transitive-merge-none/auxiliary/tango.rs | 0 .../transitive-merge-none/sierra.rs | 0 .../auxiliary/quebec.rs | 0 .../auxiliary/tango.rs | 0 .../transitive-merge-read-write/sierra.rs | 0 .../transitive-no-info/auxiliary/quebec.rs | 0 .../transitive-no-info/auxiliary/tango.rs | 0 .../transitive-no-info/sierra.rs | 0 .../two-separate-out-dir/auxiliary/foxtrot.rs | 0 .../two-separate-out-dir/echo.rs | 0 .../{rustdoc => rustdoc-html}/method-list.rs | 0 ...ing-doc-comments-and-attrs.S1_top-doc.html | 0 ...ing-doc-comments-and-attrs.S2_top-doc.html | 0 ...ing-doc-comments-and-attrs.S3_top-doc.html | 0 .../mixing-doc-comments-and-attrs.rs | 0 .../mod-stackoverflow.rs | 0 .../multiple-foreigns-w-same-name-99734.rs | 0 .../multiple-import-levels.rs | 0 .../multiple-mods-w-same-name-99734.rs | 0 ...tiple-mods-w-same-name-doc-inline-83375.rs | 0 ...-w-same-name-doc-inline-last-item-83375.rs | 0 .../multiple-structs-w-same-name-99221.rs | 0 tests/{rustdoc => rustdoc-html}/mut-params.rs | 0 tests/{rustdoc => rustdoc-html}/namespaces.rs | 0 .../nested-items-issue-111415.rs | 0 .../nested-modules.rs | 0 .../no-run-still-checks-lints.rs | 0 .../no-stack-overflow-25295.rs | 0 .../no-unit-struct-field.rs | 0 .../non_lifetime_binders.rs | 0 ...-notable_trait-mut_t_is_not_an_iterator.rs | 0 .../doc-notable_trait-mut_t_is_not_ref_t.rs | 0 .../doc-notable_trait-negative.negative.html | 0 .../doc-notable_trait-negative.positive.html | 0 .../doc-notable_trait-negative.rs | 0 ...c-notable_trait-slice.bare_fn_matches.html | 0 .../notable-trait/doc-notable_trait-slice.rs | 0 .../doc-notable_trait.bare-fn.html | 0 .../notable-trait/doc-notable_trait.rs | 0 .../doc-notable_trait.some-struct-new.html | 0 .../doc-notable_trait.wrap-me.html | 0 ...oc-notable_trait_box_is_not_an_iterator.rs | 0 .../notable-trait/notable-trait-generics.rs | 0 .../spotlight-from-dependency.odd.html | 0 .../spotlight-from-dependency.rs | 0 tests/{rustdoc => rustdoc-html}/nul-error.rs | 0 .../playground-arg.rs | 0 .../playground-empty.rs | 0 .../playground-none.rs | 0 .../playground-syntax-error.rs | 0 tests/{rustdoc => rustdoc-html}/playground.rs | 0 .../primitive/auxiliary/issue-15318.rs | 0 .../primitive/auxiliary/primitive-doc.rs | 0 .../primitive/cross-crate-primitive-doc.rs | 0 .../primitive/no_std-primitive.rs | 0 .../primitive/no_std.rs | 0 .../primitive/primitive-generic-impl.rs | 0 .../primitive/primitive-link.rs | 0 .../primitive-raw-pointer-dox-15318-3.rs | 0 .../primitive-raw-pointer-link-15318.rs | 0 ...ive-raw-pointer-link-no-inlined-15318-2.rs | 0 .../primitive/primitive-reference.rs | 0 .../primitive/primitive-slice-auto-trait.rs | 0 .../primitive/primitive-tuple-auto-trait.rs | 0 .../primitive/primitive-tuple-variadic.rs | 0 .../primitive/primitive-unit-auto-trait.rs | 0 .../primitive/primitive.rs | 0 ...h-index-primitive-inherent-method-23511.rs | 0 .../private/doc-hidden-private-67851-both.rs | 0 .../doc-hidden-private-67851-hidden.rs | 0 .../doc-hidden-private-67851-neither.rs | 0 .../doc-hidden-private-67851-private.rs | 0 .../empty-impl-block-private-with-doc.rs | 0 .../private/empty-impl-block-private.rs | 0 .../private/empty-mod-private.rs | 0 .../private/enum-variant-private-46767.rs | 0 .../private/files-creation-private.rs | 0 .../private/hidden-private.rs | 0 ...ne-private-with-intermediate-doc-hidden.rs | 0 .../private/inner-private-110422.rs | 0 .../macro-document-private-duplicate.rs | 0 .../private/macro-document-private.rs | 0 .../private/macro-private-not-documented.rs | 0 .../missing-private-inlining-109258.rs | 0 .../private/private-fields-tuple-struct.rs | 0 .../private/private-non-local-fields-2.rs | 0 .../private/private-non-local-fields.rs | 0 .../private/private-type-alias.rs | 0 .../private/private-type-cycle-110629.rs | 0 .../private/private-use-decl-macro-47038.rs | 0 .../private/private-use.rs | 0 ...ic-impl-mention-private-generic-46380-2.rs | 0 .../private/traits-in-bodies-private.rs | 0 .../process-termination.rs | 0 tests/{rustdoc => rustdoc-html}/pub-method.rs | 0 .../pub-use-loop-107350.rs | 0 .../pub-use-root-path-95873.rs | 0 .../range-arg-pattern.rs | 0 .../raw-ident-eliminate-r-hashtag.rs | 0 .../read-more-unneeded.rs | 0 tests/{rustdoc => rustdoc-html}/recursion1.rs | 0 tests/{rustdoc => rustdoc-html}/recursion2.rs | 0 tests/{rustdoc => rustdoc-html}/recursion3.rs | 0 .../redirect-map-empty.rs | 0 .../{rustdoc => rustdoc-html}/redirect-map.rs | 0 .../redirect-rename.rs | 0 tests/{rustdoc => rustdoc-html}/redirect.rs | 0 .../reexport/alias-reexport.rs | 0 .../reexport/alias-reexport2.rs | 0 .../reexport/anonymous-reexport-108931.rs | 0 .../reexport/anonymous-reexport.rs | 0 .../reexport/auxiliary/alias-reexport.rs | 0 .../reexport/auxiliary/alias-reexport2.rs | 0 .../reexport/auxiliary/all-item-types.rs | 0 .../reexport/auxiliary/issue-28927-1.rs | 0 .../reexport/auxiliary/issue-28927-2.rs | 0 .../reexport/auxiliary/primitive-reexport.rs | 0 .../reexport/auxiliary/reexport-check.rs | 0 .../reexport/auxiliary/reexport-doc-aux.rs | 0 .../reexport/auxiliary/reexports.rs | 0 .../reexport/auxiliary/wrap-unnamable-type.rs | 0 .../reexport/blanket-reexport-item.rs | 0 .../reexport/cfg_doc_reexport.rs | 0 .../reexport/doc-hidden-reexports-109449.rs | 0 .../duplicated-glob-reexport-60522.rs | 0 .../reexport/enum-variant-reexport-35488.rs | 0 .../reexport/enum-variant.rs | 0 .../reexport/extern-135092.rs | 0 .../reexport/foreigntype-reexport.rs | 0 .../glob-reexport-attribute-merge-120487.rs | 0 ...b-reexport-attribute-merge-doc-auto-cfg.rs | 0 .../reexport/ice-reexport-crate-root-28927.rs | 0 .../import_trait_associated_functions.rs | 0 .../reexport/local-reexport-doc.rs | 0 .../reexport/merge-glob-and-non-glob.rs | 0 .../reexport/no-compiler-reexport.rs | 0 .../reexport/overlapping-reexport-105735-2.rs | 0 .../reexport/overlapping-reexport-105735.rs | 0 .../reexport/primitive-reexport.rs | 0 .../reexport/private-mod-override-reexport.rs | 0 .../pub-reexport-of-pub-reexport-46506.rs | 0 .../reexport/reexport-attr-merge.rs | 0 .../reexport/reexport-cfg.rs | 0 .../reexport/reexport-check.rs | 0 .../reexport/reexport-dep-foreign-fn.rs | 0 .../reexport-doc-hidden-inside-private.rs | 0 .../reexport/reexport-doc-hidden.rs | 0 .../reexport/reexport-doc.rs | 0 .../reexport/reexport-hidden-macro.rs | 0 .../reexport/reexport-macro.rs | 0 .../reexport/reexport-of-doc-hidden.rs | 0 .../reexport/reexport-of-reexport-108679.rs | 0 ...ability-tags-deprecated-and-portability.rs | 0 ...stability-tags-unstable-and-portability.rs | 0 .../reexport-trait-from-hidden-111064-2.rs | 0 .../reexport-trait-from-hidden-111064.rs | 0 .../reexport/reexports-of-same-name.rs | 0 .../reexport/reexports-priv.rs | 0 .../reexport/reexports.rs | 0 .../reexport/wrapped-unnamble-type-143222.rs | 0 .../remove-duplicates.rs | 0 .../remove-url-from-headings.rs | 0 tests/{rustdoc => rustdoc-html}/repr.rs | 0 .../resolve-ice-124363.rs | 0 .../return-type-notation.rs | 0 .../safe-intrinsic.rs | 0 .../sanitizer-option.rs | 0 .../search-index-summaries.rs | 0 .../{rustdoc => rustdoc-html}/search-index.rs | 0 .../short-docblock-codeblock.rs | 0 .../short-docblock.rs | 0 tests/{rustdoc => rustdoc-html}/short-line.md | 0 .../sidebar/module.rs | 0 .../sidebar/sidebar-all-page.rs | 0 .../sidebar/sidebar-items.rs | 0 .../sidebar/sidebar-link-generation.rs | 0 .../sidebar/sidebar-links-to-foreign-impl.rs | 0 .../sidebar/top-toc-html.rs | 0 .../sidebar/top-toc-idmap.rs | 0 .../sidebar/top-toc-nil.rs | 0 .../{rustdoc => rustdoc-html}/sized_trait.rs | 0 .../slice-links.link_box_generic.html | 0 .../slice-links.link_box_u32.html | 0 .../slice-links.link_slice_generic.html | 0 .../slice-links.link_slice_u32.html | 0 .../{rustdoc => rustdoc-html}/slice-links.rs | 0 .../{rustdoc => rustdoc-html}/smart-punct.rs | 0 tests/{rustdoc => rustdoc-html}/smoke.rs | 0 tests/{rustdoc => rustdoc-html}/sort-53812.rs | 0 .../sort-modules-by-appearance.rs | 0 .../assoc-type-source-link.rs | 0 .../auxiliary/issue-26606-macro.rs | 0 .../auxiliary/issue-34274.rs | 0 .../auxiliary/source-code-bar.rs | 0 .../auxiliary/source_code.rs | 0 .../auxiliary/src-links-external.rs | 0 .../check-source-code-urls-to-def-std.rs | 0 .../check-source-code-urls-to-def.rs | 0 .../source-code-pages/doc-hidden-source.rs | 0 .../failing-expansion-on-wrong-macro.rs | 0 .../source-code-pages/frontmatter.rs | 0 .../source-code-pages/html-no-source.rs | 0 .../source-code-pages/keyword-macros.rs | 0 .../source-code-pages/shebang.rs | 0 .../source-code-highlight.rs | 0 .../source-code-pages/source-file.rs | 0 .../source-code-pages/source-line-numbers.rs | 0 .../source-version-separator.rs | 0 .../src-link-external-macro-26606.rs | 0 .../source-code-pages/src-links-auto-impls.rs | 0 .../source-code-pages/src-links-external.rs | 0 .../src-links-implementor-43893.rs | 0 .../src-links-inlined-34274.rs | 0 .../source-code-pages/src-links.rs | 0 .../src-links/compiletest-ignore-dir | 0 .../source-code-pages/src-links/fizz.rs | 0 .../source-code-pages/src-links/mod.rs | 0 .../src-mod-path-absolute-26995.rs | 0 .../version-separator-without-source.rs | 0 tests/{rustdoc => rustdoc-html}/stability.rs | 0 .../staged-api-deprecated-unstable-32374.rs | 0 .../staged-api-feature-issue-27759.rs | 0 .../static-root-path.rs | 0 tests/{rustdoc => rustdoc-html}/static.rs | 0 ...rip-block-doc-comments-stars.docblock.html | 0 .../strip-block-doc-comments-stars.rs | 0 .../strip-priv-imports-pass-27104.rs | 0 .../struct-arg-pattern.rs | 0 .../{rustdoc => rustdoc-html}/struct-field.rs | 0 .../{rustdoc => rustdoc-html}/structfields.rs | 0 .../summary-codeblock-31899.rs | 0 .../summary-header-46377.rs | 0 .../summary-reference-link-30366.rs | 0 .../auto-trait-lifetimes-56822.rs | 0 .../synthetic_auto/basic.rs | 0 .../synthetic_auto/bounds.rs | 0 .../synthetic_auto/complex.rs | 0 .../synthetic_auto/crate-local.rs | 0 .../issue-72213-projection-lifetime.rs | 0 .../synthetic_auto/lifetimes.rs | 0 .../synthetic_auto/manual.rs | 0 .../synthetic_auto/negative.rs | 0 .../synthetic_auto/nested.rs | 0 .../synthetic_auto/no-redundancy.rs | 0 .../normalize-auto-trait-80233.rs | 0 .../synthetic_auto/overflow.rs | 0 .../synthetic_auto/project.rs | 0 .../synthetic_auto/self-referential.rs | 0 .../send-impl-conditional-60726.rs | 0 .../synthetic_auto/static-region.rs | 0 .../synthetic_auto/supertrait-bounds.rs | 0 tests/{rustdoc => rustdoc-html}/tab_title.rs | 0 .../table-in-docblock.rs | 0 .../target-feature.rs | 0 tests/{rustdoc => rustdoc-html}/task-lists.rs | 0 tests/{rustdoc => rustdoc-html}/test-lists.rs | 0 .../{rustdoc => rustdoc-html}/test-parens.rs | 0 .../test-strikethrough.rs | 0 .../test_option_check/bar.rs | 0 .../test_option_check/test.rs | 0 .../thread-local-src.rs | 0 tests/{rustdoc => rustdoc-html}/titles.rs | 0 .../toggle-item-contents.rs | 0 .../toggle-method.rs | 0 .../toggle-trait-fn.rs | 0 .../trait-aliases.rs | 0 .../trait-item-info.rs | 0 .../trait-self-link.rs | 0 .../trait-src-link.rs | 0 .../trait-visibility.rs | 0 .../traits-in-bodies.rs | 0 .../tuple-struct-fields-doc.rs | 0 .../tuple-struct-where-clause-34928.rs | 0 .../tuples.link1_i32.html | 0 .../tuples.link1_t.html | 0 .../tuples.link2_i32.html | 0 .../tuples.link2_t.html | 0 .../tuples.link2_tu.html | 0 .../tuples.link_unit.html | 0 tests/{rustdoc => rustdoc-html}/tuples.rs | 0 .../auxiliary/parent-crate-115718.rs | 0 .../type-alias/cross-crate-115718.rs | 0 .../type-alias/deeply-nested-112515.rs | 0 .../type-alias/deref-32077.rs | 0 .../type-alias/impl_trait_in_assoc_type.rs | 0 .../type-alias/primitive-local-link-121106.rs | 0 .../type-alias/repr.rs | 0 .../type-alias/same-crate-115718.rs | 0 .../type-layout-flag-required.rs | 0 .../{rustdoc => rustdoc-html}/type-layout.rs | 0 .../typedef-inner-variants-lazy_type_alias.rs | 0 .../typedef-inner-variants.rs | 0 tests/{rustdoc => rustdoc-html}/typedef.rs | 0 .../underscore-import-61592.rs | 0 tests/{rustdoc => rustdoc-html}/unindent.md | 0 tests/{rustdoc => rustdoc-html}/unindent.rs | 0 .../union-fields-html.rs | 0 tests/{rustdoc => rustdoc-html}/union.rs | 0 .../{rustdoc => rustdoc-html}/unit-return.rs | 0 .../unsafe-binder.rs | 0 tests/{rustdoc => rustdoc-html}/use-attr.rs | 0 .../useless_lifetime_bound.rs | 0 tests/{rustdoc => rustdoc-html}/variadic.rs | 0 .../viewpath-rename.rs | 0 .../viewpath-self.rs | 0 tests/{rustdoc => rustdoc-html}/visibility.rs | 0 .../where-clause-order.rs | 0 .../{rustdoc => rustdoc-html}/where-sized.rs | 0 .../where.SWhere_Echo_impl.html | 0 .../where.SWhere_Simd_item-decl.html | 0 .../where.SWhere_TraitWhere_item-decl.html | 0 .../where.alpha_trait_decl.html | 0 .../where.bravo_trait_decl.html | 0 .../where.charlie_fn_decl.html | 0 .../where.golf_type_alias_decl.html | 0 tests/{rustdoc => rustdoc-html}/where.rs | 0 .../whitespace-after-where-clause.enum.html | 0 .../whitespace-after-where-clause.enum2.html | 0 .../whitespace-after-where-clause.rs | 0 .../whitespace-after-where-clause.struct.html | 0 ...whitespace-after-where-clause.struct2.html | 0 .../whitespace-after-where-clause.trait.html | 0 .../whitespace-after-where-clause.trait2.html | 0 .../whitespace-after-where-clause.union.html | 0 .../whitespace-after-where-clause.union2.html | 0 .../without-redirect.rs | 0 tests/{rustdoc => rustdoc-html}/wrapping.rs | 0 triagebot.toml | 6 +++--- 1076 files changed, 69 insertions(+), 60 deletions(-) create mode 100644 src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_librustdoc_rustdoc_html.snap create mode 100644 src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_rustdoc_html.snap rename tests/{rustdoc => rustdoc-html}/all.rs (100%) rename tests/{rustdoc => rustdoc-html}/anchors/anchor-id-duplicate-method-name-25001.rs (100%) rename tests/{rustdoc => rustdoc-html}/anchors/anchor-id-trait-method-15169.rs (100%) rename tests/{rustdoc => rustdoc-html}/anchors/anchor-id-trait-tymethod-28478.rs (100%) rename tests/{rustdoc => rustdoc-html}/anchors/anchors.no_const_anchor.html (100%) rename tests/{rustdoc => rustdoc-html}/anchors/anchors.no_const_anchor2.html (100%) rename tests/{rustdoc => rustdoc-html}/anchors/anchors.no_method_anchor.html (100%) rename tests/{rustdoc => rustdoc-html}/anchors/anchors.no_trait_method_anchor.html (100%) rename tests/{rustdoc => rustdoc-html}/anchors/anchors.no_tymethod_anchor.html (100%) rename tests/{rustdoc => rustdoc-html}/anchors/anchors.no_type_anchor.html (100%) rename tests/{rustdoc => rustdoc-html}/anchors/anchors.no_type_anchor2.html (100%) rename tests/{rustdoc => rustdoc-html}/anchors/anchors.rs (100%) rename tests/{rustdoc => rustdoc-html}/anchors/auxiliary/issue-86620-1.rs (100%) rename tests/{rustdoc => rustdoc-html}/anchors/disambiguate-anchors-32890.rs (100%) rename tests/{rustdoc => rustdoc-html}/anchors/disambiguate-anchors-header-29449.rs (100%) rename tests/{rustdoc => rustdoc-html}/anchors/method-anchor-in-blanket-impl-86620.rs (100%) rename tests/{rustdoc => rustdoc-html}/anchors/trait-impl-items-links-and-anchors.rs (100%) rename tests/{rustdoc => rustdoc-html}/anon-fn-params.rs (100%) rename tests/{rustdoc => rustdoc-html}/anonymous-lifetime.rs (100%) rename tests/{rustdoc => rustdoc-html}/array-links.link_box_generic.html (100%) rename tests/{rustdoc => rustdoc-html}/array-links.link_box_u32.html (100%) rename tests/{rustdoc => rustdoc-html}/array-links.link_slice_generic.html (100%) rename tests/{rustdoc => rustdoc-html}/array-links.link_slice_u32.html (100%) rename tests/{rustdoc => rustdoc-html}/array-links.rs (100%) rename tests/{rustdoc => rustdoc-html}/asm-foreign.rs (100%) rename tests/{rustdoc => rustdoc-html}/asm-foreign2.rs (100%) rename tests/{rustdoc => rustdoc-html}/asref-for-and-of-local-82465.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/assoc-fns.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/assoc-item-cast.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/assoc-type-bindings-20646.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/assoc-types.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/auxiliary/cross-crate-hidden-assoc-trait-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/auxiliary/issue-20646.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/auxiliary/issue-20727.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/auxiliary/normalize-assoc-item.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/cross-crate-hidden-assoc-trait-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/doc-assoc-item.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/inline-assoc-type-20727-bindings.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/inline-assoc-type-20727-bounds-deref.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/inline-assoc-type-20727-bounds-index.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/inline-assoc-type-20727-bounds.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/normalize-assoc-item.rs (100%) rename tests/{rustdoc => rustdoc-html}/async/async-fn-opaque-item.rs (100%) rename tests/{rustdoc => rustdoc-html}/async/async-fn.rs (100%) rename tests/{rustdoc => rustdoc-html}/async/async-move-doctest.rs (100%) rename tests/{rustdoc => rustdoc-html}/async/async-trait-sig.rs (100%) rename tests/{rustdoc => rustdoc-html}/async/async-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/async/auxiliary/async-trait-dep.rs (100%) rename tests/{rustdoc => rustdoc-html}/attributes-2021-edition.rs (100%) rename tests/{rustdoc => rustdoc-html}/attributes-inlining-108281.rs (100%) rename tests/{rustdoc => rustdoc-html}/attributes-re-export-2021-edition.rs (100%) rename tests/{rustdoc => rustdoc-html}/attributes-re-export.rs (100%) rename tests/{rustdoc => rustdoc-html}/attributes.rs (100%) rename tests/{rustdoc => rustdoc-html}/auto/auto-impl-for-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/auto/auto-impl-primitive.rs (100%) rename tests/{rustdoc => rustdoc-html}/auto/auto-trait-bounds-by-associated-type-50159.rs (100%) rename tests/{rustdoc => rustdoc-html}/auto/auto-trait-bounds-inference-variables-54705.rs (100%) rename tests/{rustdoc => rustdoc-html}/auto/auto-trait-bounds-where-51236.rs (100%) rename tests/{rustdoc => rustdoc-html}/auto/auto-trait-negative-impl-55321.rs (100%) rename tests/{rustdoc => rustdoc-html}/auto/auto-trait-not-send.rs (100%) rename tests/{rustdoc => rustdoc-html}/auto/auto-traits.rs (100%) rename tests/{rustdoc => rustdoc-html}/auto/auto_aliases.rs (100%) rename tests/{rustdoc => rustdoc-html}/auto/auxiliary/auto-traits.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/all-item-types.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/cross_crate_generic_typedef.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/elided-lifetime.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/empty.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/enum-primitive.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/ext-anon-fn-params.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/ext-repr.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/ext-trait-aliases.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/inline-default-methods.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/issue-106421-force-unstable.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/issue-13698.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/issue-19190-3.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/issue-61592.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/issue-99221-aux.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/issue-99734-aux.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/jump-to-def-res-err-handling-aux.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/masked.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/mod-stackoverflow.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/reexp-stripped.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/remapped-paths.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/rustdoc-ffi.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/trait-visibility.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/unit-return.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/unsafe-binder-dep.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/unstable-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/bad-codeblock-syntax.rs (100%) rename tests/{rustdoc => rustdoc-html}/blank-line-in-doc-block-47197.rs (100%) rename tests/{rustdoc => rustdoc-html}/bold-tag-101743.rs (100%) rename tests/{rustdoc => rustdoc-html}/bounds.rs (100%) rename tests/{rustdoc => rustdoc-html}/cap-lints.rs (100%) rename tests/{rustdoc => rustdoc-html}/cfg-bool.rs (100%) rename tests/{rustdoc => rustdoc-html}/cfg-doctest.rs (100%) rename tests/{rustdoc => rustdoc-html}/check-styled-link.rs (100%) rename tests/{rustdoc => rustdoc-html}/check.rs (100%) rename tests/{rustdoc => rustdoc-html}/codeblock-title.rs (100%) rename tests/{rustdoc => rustdoc-html}/comment-in-doctest.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-fn-76501.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-fn-effects.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-fn.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-generics/add-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-generics/auxiliary/extern_crate.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-generics/const-generic-defaults.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-generics/const-generic-slice.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-generics/const-generics-docs.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-generics/const-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-generics/const-param-type-references-generics.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-generics/generic_const_exprs.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-generics/lazy_normalization_consts/const-equate-pred.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-generics/type-alias.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-intrinsic.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/assoc-consts-underscore.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/assoc-consts-version.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/assoc-consts.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/associated-consts.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/const-display.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/const-doc.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/const-effect-param.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/const-trait-and-impl-methods.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/const-underscore.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/const-value-display.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/const.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/document-item-with-associated-const-in-where-clause.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/generic-const-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/generic_const_exprs.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/glob-shadowing-const.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/hide-complex-unevaluated-const-arguments.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/hide-complex-unevaluated-consts.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/ice-associated-const-equality-105952.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/legacy-const-generic.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/link-assoc-const.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/redirect-const.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/rfc-2632-const-trait-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/show-const-contents.rs (100%) rename tests/{rustdoc => rustdoc-html}/constructor-imports.rs (100%) rename tests/{rustdoc => rustdoc-html}/crate-doc-hidden-109695.rs (100%) rename tests/{rustdoc => rustdoc-html}/crate-version-escape.rs (100%) rename tests/{rustdoc => rustdoc-html}/crate-version-extra.rs (100%) rename tests/{rustdoc => rustdoc-html}/crate-version.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/cargo-transitive-no-index/auxiliary/q.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/cargo-transitive-no-index/auxiliary/t.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/cargo-transitive-no-index/s.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/cargo-transitive/auxiliary/q.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/cargo-transitive/auxiliary/t.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/cargo-transitive/s.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/cargo-two-no-index/auxiliary/f.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/cargo-two-no-index/e.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/cargo-two/auxiliary/f.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/cargo-two/e.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/index-on-last/auxiliary/f.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/index-on-last/e.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/kitchen-sink/auxiliary/q.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/kitchen-sink/auxiliary/r.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/kitchen-sink/auxiliary/s.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/kitchen-sink/auxiliary/t.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/kitchen-sink/i.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/single-crate-baseline/q.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/single-crate-no-index/q.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/transitive/auxiliary/q.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/transitive/auxiliary/t.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/transitive/s.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/two/auxiliary/f.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/two/e.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/working-dir-examples/q.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/write-docs-somewhere-else/auxiliary/f.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/write-docs-somewhere-else/e.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-links.rs (100%) rename tests/{rustdoc => rustdoc-html}/custom_code_classes.rs (100%) rename tests/{rustdoc => rustdoc-html}/decl-line-wrapping-empty-arg-list.decl.html (100%) rename tests/{rustdoc => rustdoc-html}/decl-line-wrapping-empty-arg-list.rs (100%) rename tests/{rustdoc => rustdoc-html}/decl-trailing-whitespace.declaration.html (100%) rename tests/{rustdoc => rustdoc-html}/decl-trailing-whitespace.rs (100%) rename tests/{rustdoc => rustdoc-html}/deep-structures.rs (100%) rename tests/{rustdoc => rustdoc-html}/default-theme.rs (100%) rename tests/{rustdoc => rustdoc-html}/default-trait-method-link.rs (100%) rename tests/{rustdoc => rustdoc-html}/default-trait-method.rs (100%) rename tests/{rustdoc => rustdoc-html}/demo-allocator-54478.rs (100%) rename tests/{rustdoc => rustdoc-html}/deprecated-future-staged-api.rs (100%) rename tests/{rustdoc => rustdoc-html}/deprecated-future.rs (100%) rename tests/{rustdoc => rustdoc-html}/deprecated.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref-methods-19190-foreign-type.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref-methods-19190-inline.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref-methods-19190.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref-mut-35169-2.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref-mut-35169.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref/deref-const-fn.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref/deref-methods-24686-target.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref/deref-multiple-impl-blocks.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref/deref-mut-methods.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref/deref-recursive-pathbuf.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref/deref-recursive.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref/deref-slice-core.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref/deref-to-primitive.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref/deref-typedef.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref/escape-deref-methods.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref/recursive-deref-sidebar.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref/recursive-deref.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref/sidebar-links-deref-100679.rs (100%) rename tests/{rustdoc => rustdoc-html}/description.rs (100%) rename tests/{rustdoc => rustdoc-html}/description_default.rs (100%) rename tests/{rustdoc => rustdoc-html}/display-hidden-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-attr-comment-mix-42760.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-attribute.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-auto-cfg-public-in-private.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-auto-cfg.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-cfg/doc-cfg-hide.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-cfg/doc-cfg-implicit-gate.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-cfg/doc-cfg-implicit.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-cfg/doc-cfg-inherit-from-module-79201.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-cfg/doc-cfg-simplification.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-cfg/doc-cfg-target-feature.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-cfg/doc-cfg-traits.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-cfg/doc-cfg.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-cfg/duplicate-cfg.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-hidden-crate.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-hidden-method-13698.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-on-keyword.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-test-attr-18199.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc_auto_cfg.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc_auto_cfg_reexports.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/auxiliary/doctest-runtool.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/auxiliary/empty.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/doctest-cfg-feature-30252.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/doctest-crate-attributes-38129.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/doctest-escape-boring-41783.codeblock.html (100%) rename tests/{rustdoc => rustdoc-html}/doctest/doctest-escape-boring-41783.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/doctest-hide-empty-line-23106.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/doctest-ignore-32556.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/doctest-include-43153.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/doctest-macro-38219.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/doctest-manual-crate-name.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/doctest-markdown-inline-parse-23744.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/doctest-markdown-trailing-docblock-48377.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/doctest-multi-line-string-literal-25944.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/doctest-runtool.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/ignore-sometimes.rs (100%) rename tests/{rustdoc => rustdoc-html}/document-hidden-items-15347.rs (100%) rename tests/{rustdoc => rustdoc-html}/double-hyphen-to-dash.rs (100%) rename tests/{rustdoc => rustdoc-html}/double-quote-escape.rs (100%) rename tests/{rustdoc => rustdoc-html}/duplicate-flags.rs (100%) rename tests/{rustdoc => rustdoc-html}/duplicate_impls/impls.rs (100%) rename tests/{rustdoc => rustdoc-html}/duplicate_impls/sidebar-links-duplicate-impls-33054.rs (100%) rename tests/{rustdoc => rustdoc-html}/dyn-compatibility.rs (100%) rename tests/{rustdoc => rustdoc-html}/early-unindent.rs (100%) rename tests/{rustdoc => rustdoc-html}/edition-doctest.rs (100%) rename tests/{rustdoc => rustdoc-html}/edition-flag.rs (100%) rename tests/{rustdoc => rustdoc-html}/elided-lifetime.rs (100%) rename tests/{rustdoc => rustdoc-html}/empty-doc-comment.rs (100%) rename tests/{rustdoc => rustdoc-html}/empty-mod-public.rs (100%) rename tests/{rustdoc => rustdoc-html}/empty-section.rs (100%) rename tests/{rustdoc => rustdoc-html}/empty-tuple-struct-118180.rs (100%) rename tests/{rustdoc => rustdoc-html}/ensure-src-link.rs (100%) rename tests/{rustdoc => rustdoc-html}/enum/auxiliary/enum-variant.rs (100%) rename tests/{rustdoc => rustdoc-html}/enum/auxiliary/variant-struct.rs (100%) rename tests/{rustdoc => rustdoc-html}/enum/enum-headings.rs (100%) rename tests/{rustdoc => rustdoc-html}/enum/enum-non-exhaustive-108925.rs (100%) rename tests/{rustdoc => rustdoc-html}/enum/enum-variant-doc-hidden-field-88600.rs (100%) rename tests/{rustdoc => rustdoc-html}/enum/enum-variant-fields-heading.rs (100%) rename tests/{rustdoc => rustdoc-html}/enum/enum-variant-fields-heading.variants.html (100%) rename tests/{rustdoc => rustdoc-html}/enum/enum-variant-non_exhaustive.rs (100%) rename tests/{rustdoc => rustdoc-html}/enum/enum-variant-non_exhaustive.type-alias-code.html (100%) rename tests/{rustdoc => rustdoc-html}/enum/enum-variant-non_exhaustive.type-code.html (100%) rename tests/{rustdoc => rustdoc-html}/enum/enum-variant-value.rs (100%) rename tests/{rustdoc => rustdoc-html}/enum/render-enum-variant-structlike-32395.rs (100%) rename tests/{rustdoc => rustdoc-html}/enum/strip-enum-variant.no-not-shown.html (100%) rename tests/{rustdoc => rustdoc-html}/enum/strip-enum-variant.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/auxiliary/empty.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/auxiliary/extern-links.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/auxiliary/external-cross-doc.md (100%) rename tests/{rustdoc => rustdoc-html}/extern/auxiliary/external-cross.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/auxiliary/external-doc.md (100%) rename tests/{rustdoc => rustdoc-html}/extern/auxiliary/html_root.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/auxiliary/issue-30109-1.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/auxiliary/no_html_root.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/auxiliary/panic-item.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/auxiliary/pub-extern-crate.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/auxiliary/rustdoc-extern-default-method.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/auxiliary/rustdoc-extern-method.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/auxiliary/variant-struct.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/duplicate-reexports-section-150211.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/extern-default-method.no_href_on_anchor.html (100%) rename tests/{rustdoc => rustdoc-html}/extern/extern-default-method.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/extern-fn-22038.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/extern-html-alias.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/extern-html-fallback.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/extern-html-root-url-precedence.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/extern-html-root-url.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/extern-links.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/extern-method.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/external-cross.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/external-doc.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/hidden-extern-34025.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/link-extern-crate-33178.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/link-extern-crate-item-30109.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/link-extern-crate-title-33178.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/pub-extern-crate-150176.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/pub-extern-crate.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/unsafe-extern-blocks.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/unused-extern-crate.rs (100%) rename tests/{rustdoc => rustdoc-html}/extremely_long_typename.extremely_long_typename.html (100%) rename tests/{rustdoc => rustdoc-html}/extremely_long_typename.rs (100%) rename tests/{rustdoc => rustdoc-html}/feature-gate-doc_auto_cfg.rs (100%) rename tests/{rustdoc => rustdoc-html}/ffi.rs (100%) rename tests/{rustdoc => rustdoc-html}/file-creation-111249.rs (100%) rename tests/{rustdoc => rustdoc-html}/files-creation-hidden.rs (100%) rename tests/{rustdoc => rustdoc-html}/fn-bound.rs (100%) rename tests/{rustdoc => rustdoc-html}/fn-pointer-arg-name.rs (100%) rename tests/{rustdoc => rustdoc-html}/fn-sidebar.rs (100%) rename tests/{rustdoc => rustdoc-html}/fn-type.rs (100%) rename tests/{rustdoc => rustdoc-html}/footnote-definition-without-blank-line-100638.rs (100%) rename tests/{rustdoc => rustdoc-html}/footnote-ids.rs (100%) rename tests/{rustdoc => rustdoc-html}/footnote-in-summary.rs (100%) rename tests/{rustdoc => rustdoc-html}/footnote-reference-ids.rs (100%) rename tests/{rustdoc => rustdoc-html}/footnote-reference-in-footnote-def.rs (100%) rename tests/{rustdoc => rustdoc-html}/force-target-feature.rs (100%) rename tests/{rustdoc => rustdoc-html}/force-unstable-if-unmarked-106421-not-internal.rs (100%) rename tests/{rustdoc => rustdoc-html}/force-unstable-if-unmarked-106421.rs (100%) rename tests/{rustdoc => rustdoc-html}/foreigntype.rs (100%) rename tests/{rustdoc => rustdoc-html}/generic-associated-types/gat-elided-lifetime-94683.rs (100%) rename tests/{rustdoc => rustdoc-html}/generic-associated-types/gat-linkification-109488.rs (100%) rename tests/{rustdoc => rustdoc-html}/generic-associated-types/gats.rs (100%) rename tests/{rustdoc => rustdoc-html}/glob-shadowing.rs (100%) rename tests/{rustdoc => rustdoc-html}/heading-levels-89309.rs (100%) rename tests/{rustdoc => rustdoc-html}/heterogeneous-concat.rs (100%) rename tests/{rustdoc => rustdoc-html}/hidden-line.rs (100%) rename tests/{rustdoc => rustdoc-html}/hidden-methods.rs (100%) rename tests/{rustdoc => rustdoc-html}/hidden-trait-methods-with-document-hidden-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/hidden-trait-methods.rs (100%) rename tests/{rustdoc => rustdoc-html}/hide-unstable-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/higher-ranked-trait-bounds.rs (100%) rename tests/{rustdoc => rustdoc-html}/highlight-invalid-rust-12834.rs (100%) rename tests/{rustdoc => rustdoc-html}/ice-type-error-19181.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/auxiliary/cross-crate-hidden-impl-parameter.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/auxiliary/extern-impl-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/auxiliary/incoherent-impl-types.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/auxiliary/issue-100204-aux.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/auxiliary/issue-17476.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/auxiliary/issue-21092.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/auxiliary/issue-22025.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/auxiliary/issue-53689.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/auxiliary/precise-capturing.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/auxiliary/real_gimli.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/auxiliary/realcore.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/auxiliary/rustdoc-default-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/auxiliary/rustdoc-impl-parts-crosscrate.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/blanket-impl-29503.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/blanket-impl-78673.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/cross-crate-hidden-impl-parameter.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/deduplicate-glob-import-impl-21474.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/deduplicate-trait-impl-22025.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/default-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/deprecated-impls.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/doc-hidden-trait-implementors-33069.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/doc_auto_cfg_nested_impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/duplicated_impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/empty-impl-block.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/empty-impls.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/extern-impl-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/extern-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/foreign-implementors-js-43701.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/generic-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/hidden-implementors-90781.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/hidden-impls.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/hidden-trait-struct-impls.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/hide-mut-methods-if-no-derefmut-impl-74083.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-alias-substituted.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-assoc-type-21092.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-associated-items-order.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-associated-items-sidebar.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-blanket-53689.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-box.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-disambiguation.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-everywhere.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-in-const-block.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-on-ty-alias-issue-119015.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-parts-crosscrate.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-parts.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-ref-20175.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-trait-43869.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-trait-alias.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-trait-precise-capturing.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-type-parameter-33592.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/implementor-stable-version.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/implementors-unstable-75588.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/inline-impl-through-glob-import-100204.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/manual_impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/method-link-foreign-trait-impl-17476.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/module-impls.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/must_implement_one_of.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/negative-impl-no-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/negative-impl-sidebar.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/negative-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/return-impl-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/rustc-incoherent-impls.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/same-crate-hidden-impl-parameter.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/sidebar-trait-impl-disambiguate-78701.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/struct-implementations-title.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/trait-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/trait-implementations-duplicate-self-45584.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/underscore-type-in-trait-impl-96381.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/universal-impl-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/unneeded-trait-implementations-title.rs (100%) rename tests/{rustdoc => rustdoc-html}/import-remapped-paths.rs (100%) rename tests/{rustdoc => rustdoc-html}/impossible-default.rs (100%) rename tests/{rustdoc => rustdoc-html}/include_str_cut.rs (100%) rename tests/{rustdoc => rustdoc-html}/index-page.rs (100%) rename tests/{rustdoc => rustdoc-html}/infinite-redirection-16265-1.rs (100%) rename tests/{rustdoc => rustdoc-html}/infinite-redirection-16265-2.rs (100%) rename tests/{rustdoc => rustdoc-html}/infinite-redirection.rs (100%) rename tests/{rustdoc => rustdoc-html}/inherent-projections.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline-default-methods.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline-rename-34473.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/add-docs.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/assoc-const-equality.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/assoc-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/assoc_item_trait_bounds.out0.html (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/assoc_item_trait_bounds.out2.html (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/assoc_item_trait_bounds.out9.html (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/assoc_item_trait_bounds.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/async-fn.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/attributes.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/add-docs.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/assoc-const-equality.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/assoc-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/assoc_item_trait_bounds.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/async-fn.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/attributes.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/const-effect-param.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/cross-glob.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/default-generic-args.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/default-trait-method.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/doc-auto-cfg.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/dyn_trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/early-late-bound-lifetime-params.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/fn-ptr-ty.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/generic-const-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/impl-inline-without-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/impl-sized.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/impl_trait_aux.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/implementors_inline.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/issue-21801.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/issue-23207-1.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/issue-23207-2.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/issue-24183.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/issue-27362-aux.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/issue-29584.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/issue-33113.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/issue-46727.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/issue-57180.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/issue-76736-1.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/issue-76736-2.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/issue-85454.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/macro-vis.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/macros.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/non_lifetime_binders.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/proc_macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/reexport-with-anonymous-lifetime-98697.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/renamed-via-module.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/ret-pos-impl-trait-in-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/rustdoc-hidden-sig.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/rustdoc-hidden.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/rustdoc-nonreachable-impls.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/rustdoc-trait-object-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/trait-vis.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/use_crate.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/use_crate_2.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/const-effect-param.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/const-eval-46727.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/const-fn-27362.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/cross-glob.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/deduplicate-inlined-items-23207.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/default-generic-args.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/default-trait-method.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/doc-auto-cfg.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/doc-hidden-broken-link-28480.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/doc-hidden-extern-trait-impl-29584.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/doc-reachability-impl-31948-1.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/doc-reachability-impl-31948-2.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/doc-reachability-impl-31948.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/dyn_trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/early-late-bound-lifetime-params.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/fn-ptr-ty.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/generic-const-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/hidden-use.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/ice-import-crate-57180.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/impl-dyn-trait-32881.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/impl-inline-without-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/impl-ref-33113.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/impl-sized.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/impl_trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/implementors-js.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/inline_hidden.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/macro-vis.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/macros.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/non_lifetime_binders.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/proc_macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/qpath-self-85454.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/reexport-with-anonymous-lifetime-98697.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/renamed-via-module.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/ret-pos-impl-trait-in-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/rustc-private-76736-1.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/rustc-private-76736-2.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/rustc-private-76736-3.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/rustc-private-76736-4.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/self-sized-bounds-24183.method_no_where_self_sized.html (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/self-sized-bounds-24183.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/sugar-closure-crate-21801.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/trait-vis.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/use_crate.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/blanket-impl-reexported-trait-94183.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/doc-no-inline-32343.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/enum-variant-reexport-46766.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/fully-stable-path-is-better.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/glob-extern-document-private-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/glob-extern.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/glob-private-document-private-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/glob-private.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/hidden-use.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/macro_by_example.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/parent-path-is-better.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/please_inline.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/private-reexport-in-public-api-81141-2.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/private-reexport-in-public-api-81141.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/private-reexport-in-public-api-generics-81141.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/private-reexport-in-public-api-hidden-81141.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/private-reexport-in-public-api-private-81141.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/pub-re-export-28537.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/reexported-macro-and-macro-export-sidebar-89852.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/staged-inline.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/trait-vis.rs (100%) rename tests/{rustdoc => rustdoc-html}/internal.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc-crate/auxiliary/self.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc-crate/self.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/anchors.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/assoc-reexport-super.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/associated-defaults.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/associated-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/auxiliary/empty.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/auxiliary/empty2.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/auxiliary/extern-builtin-type-impl-dep.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/auxiliary/extern-inherent-impl-dep.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/auxiliary/intra-link-extern-crate.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/auxiliary/intra-link-pub-use.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/auxiliary/intra-link-reexport-additional-docs.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/auxiliary/intra-links-external-traits.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/auxiliary/issue-66159-1.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/auxiliary/my-core.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/auxiliary/proc-macro-macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/auxiliary/pub-struct.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/basic.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/builtin-macros.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/crate-relative-assoc.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/crate-relative.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/additional_doc.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/auxiliary/additional_doc.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/auxiliary/hidden.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/auxiliary/intra-link-cross-crate-crate.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/auxiliary/macro_inner.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/auxiliary/module.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/auxiliary/proc_macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/auxiliary/submodule-inner.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/auxiliary/submodule-outer.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/auxiliary/traits.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/basic.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/crate.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/hidden.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/module.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/submodule-inner.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/submodule-outer.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/traits.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/deps.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/disambiguators-removed.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/email-address.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/enum-self-82209.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/enum-struct-field.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/extern-builtin-type-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/extern-crate-only-used-in-link.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/extern-crate.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/extern-inherent-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/extern-reference-link.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/extern-type.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/external-traits.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/field.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/filter-out-private.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/generic-params.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/generic-trait-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/ice-intra-doc-links-107995.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/in-bodies.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/inherent-associated-types.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/intra-doc-link-method-trait-impl-72340.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/libstd-re-export.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/link-in-footnotes-132208.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/link-same-name-different-disambiguator-108459.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/link-to-proc-macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/macro-caching-144965.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/macros-disambiguators.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/mod-ambiguity.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/mod-relative.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/module-scope-name-resolution-55364.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/nested-use.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/no-doc-primitive.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/non-path-primitives.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/prim-assoc.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/prim-associated-traits.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/prim-methods-external-core.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/prim-methods-local.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/prim-methods.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/prim-precedence.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/prim-self.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/primitive-disambiguators.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/primitive-non-default-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/private-failures-ignored.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/private.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/proc-macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/pub-use.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/raw-ident-self.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/reexport-additional-docs.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/same-name-different-crates-66159.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/self-cache.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/self.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/trait-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/trait-item.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/true-false.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/type-alias-primitive.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/type-alias.rs (100%) rename tests/{rustdoc => rustdoc-html}/invalid$crate$name.rs (100%) rename tests/{rustdoc => rustdoc-html}/item-desc-list-at-start.item-table.html (100%) rename tests/{rustdoc => rustdoc-html}/item-desc-list-at-start.rs (100%) rename tests/{rustdoc => rustdoc-html}/jump-to-def/assoc-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/jump-to-def/assoc-types.rs (100%) rename tests/{rustdoc => rustdoc-html}/jump-to-def/auxiliary/symbols.rs (100%) rename tests/{rustdoc => rustdoc-html}/jump-to-def/derive-macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/jump-to-def/doc-links-calls.rs (100%) rename tests/{rustdoc => rustdoc-html}/jump-to-def/doc-links.rs (100%) rename tests/{rustdoc => rustdoc-html}/jump-to-def/macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/jump-to-def/no-body-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/jump-to-def/non-local-method.rs (100%) rename tests/{rustdoc => rustdoc-html}/jump-to-def/patterns.rs (100%) rename tests/{rustdoc => rustdoc-html}/jump-to-def/prelude-types.rs (100%) rename tests/{rustdoc => rustdoc-html}/jump-to-def/shebang.rs (100%) rename tests/{rustdoc => rustdoc-html}/keyword.rs (100%) rename tests/{rustdoc => rustdoc-html}/lifetime-name.rs (100%) rename tests/{rustdoc => rustdoc-html}/line-breaks.rs (100%) rename tests/{rustdoc => rustdoc-html}/link-on-path-with-generics.rs (100%) rename tests/{rustdoc => rustdoc-html}/link-title-escape.rs (100%) rename tests/{rustdoc => rustdoc-html}/links-in-headings.rs (100%) rename tests/{rustdoc => rustdoc-html}/logo-class-default.rs (100%) rename tests/{rustdoc => rustdoc-html}/logo-class-rust.rs (100%) rename tests/{rustdoc => rustdoc-html}/logo-class.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro-expansion/field-followed-by-exclamation.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro-expansion/type-macro-expansion.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/auxiliary/external-macro-src.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/auxiliary/issue-99221-aux.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/auxiliary/macro_pub_in_module.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/auxiliary/one-line-expand.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/auxiliary/pub-use-extern-macros.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/compiler-derive-proc-macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/const-rendering-macros-33302.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/decl_macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/decl_macro_priv.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/doc-proc-macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/external-macro-src.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro-const-display-115295.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro-doc-comment-23812.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro-export-crate-root-108231.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro-generated-macro.macro_linebreak_pre.html (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro-generated-macro.macro_morestuff_pre.html (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro-generated-macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro-higher-kinded-function.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro-ice-16019.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro-in-async-block.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro-in-closure.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro-indirect-use.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro_expansion.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro_pub_in_module.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro_rules-matchers.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/macros.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/multiple-macro-rules-w-same-name-99221.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/multiple-macro-rules-w-same-name-submodule-99221.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/one-line-expand.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/proc-macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/pub-use-extern-macros.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/rustc-macro-crate.rs (100%) rename tests/{rustdoc => rustdoc-html}/markdown-60482.rs (100%) rename tests/{rustdoc => rustdoc-html}/markdown-table-escape-pipe-27862.rs (100%) rename tests/{rustdoc => rustdoc-html}/masked.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/cargo-transitive-read-write/auxiliary/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/cargo-transitive-read-write/auxiliary/tango.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/cargo-transitive-read-write/sierra.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/romeo.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/sierra.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/tango.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/kitchen-sink-separate-dirs/indigo.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/no-merge-separate/auxiliary/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/no-merge-separate/auxiliary/tango.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/no-merge-separate/sierra.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/no-merge-write-anyway/auxiliary/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/no-merge-write-anyway/auxiliary/tango.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/no-merge-write-anyway/sierra.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/overwrite-but-include/auxiliary/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/overwrite-but-include/auxiliary/tango.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/overwrite-but-include/sierra.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/overwrite-but-separate/auxiliary/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/overwrite-but-separate/auxiliary/tango.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/overwrite-but-separate/sierra.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/overwrite/auxiliary/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/overwrite/auxiliary/tango.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/overwrite/sierra.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/single-crate-finalize/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/single-crate-read-write/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/single-crate-write-anyway/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/single-merge-none-useless-write/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/transitive-finalize/auxiliary/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/transitive-finalize/auxiliary/tango.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/transitive-finalize/sierra.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/transitive-merge-none/auxiliary/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/transitive-merge-none/auxiliary/tango.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/transitive-merge-none/sierra.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/transitive-merge-read-write/auxiliary/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/transitive-merge-read-write/auxiliary/tango.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/transitive-merge-read-write/sierra.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/transitive-no-info/auxiliary/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/transitive-no-info/auxiliary/tango.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/transitive-no-info/sierra.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/two-separate-out-dir/auxiliary/foxtrot.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/two-separate-out-dir/echo.rs (100%) rename tests/{rustdoc => rustdoc-html}/method-list.rs (100%) rename tests/{rustdoc => rustdoc-html}/mixing-doc-comments-and-attrs.S1_top-doc.html (100%) rename tests/{rustdoc => rustdoc-html}/mixing-doc-comments-and-attrs.S2_top-doc.html (100%) rename tests/{rustdoc => rustdoc-html}/mixing-doc-comments-and-attrs.S3_top-doc.html (100%) rename tests/{rustdoc => rustdoc-html}/mixing-doc-comments-and-attrs.rs (100%) rename tests/{rustdoc => rustdoc-html}/mod-stackoverflow.rs (100%) rename tests/{rustdoc => rustdoc-html}/multiple-foreigns-w-same-name-99734.rs (100%) rename tests/{rustdoc => rustdoc-html}/multiple-import-levels.rs (100%) rename tests/{rustdoc => rustdoc-html}/multiple-mods-w-same-name-99734.rs (100%) rename tests/{rustdoc => rustdoc-html}/multiple-mods-w-same-name-doc-inline-83375.rs (100%) rename tests/{rustdoc => rustdoc-html}/multiple-mods-w-same-name-doc-inline-last-item-83375.rs (100%) rename tests/{rustdoc => rustdoc-html}/multiple-structs-w-same-name-99221.rs (100%) rename tests/{rustdoc => rustdoc-html}/mut-params.rs (100%) rename tests/{rustdoc => rustdoc-html}/namespaces.rs (100%) rename tests/{rustdoc => rustdoc-html}/nested-items-issue-111415.rs (100%) rename tests/{rustdoc => rustdoc-html}/nested-modules.rs (100%) rename tests/{rustdoc => rustdoc-html}/no-run-still-checks-lints.rs (100%) rename tests/{rustdoc => rustdoc-html}/no-stack-overflow-25295.rs (100%) rename tests/{rustdoc => rustdoc-html}/no-unit-struct-field.rs (100%) rename tests/{rustdoc => rustdoc-html}/non_lifetime_binders.rs (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/doc-notable_trait-negative.negative.html (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/doc-notable_trait-negative.positive.html (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/doc-notable_trait-negative.rs (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/doc-notable_trait-slice.bare_fn_matches.html (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/doc-notable_trait-slice.rs (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/doc-notable_trait.bare-fn.html (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/doc-notable_trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/doc-notable_trait.some-struct-new.html (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/doc-notable_trait.wrap-me.html (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/doc-notable_trait_box_is_not_an_iterator.rs (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/notable-trait-generics.rs (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/spotlight-from-dependency.odd.html (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/spotlight-from-dependency.rs (100%) rename tests/{rustdoc => rustdoc-html}/nul-error.rs (100%) rename tests/{rustdoc => rustdoc-html}/playground-arg.rs (100%) rename tests/{rustdoc => rustdoc-html}/playground-empty.rs (100%) rename tests/{rustdoc => rustdoc-html}/playground-none.rs (100%) rename tests/{rustdoc => rustdoc-html}/playground-syntax-error.rs (100%) rename tests/{rustdoc => rustdoc-html}/playground.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/auxiliary/issue-15318.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/auxiliary/primitive-doc.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/cross-crate-primitive-doc.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/no_std-primitive.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/no_std.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/primitive-generic-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/primitive-link.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/primitive-raw-pointer-dox-15318-3.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/primitive-raw-pointer-link-15318.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/primitive-raw-pointer-link-no-inlined-15318-2.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/primitive-reference.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/primitive-slice-auto-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/primitive-tuple-auto-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/primitive-tuple-variadic.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/primitive-unit-auto-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/primitive.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/search-index-primitive-inherent-method-23511.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/doc-hidden-private-67851-both.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/doc-hidden-private-67851-hidden.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/doc-hidden-private-67851-neither.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/doc-hidden-private-67851-private.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/empty-impl-block-private-with-doc.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/empty-impl-block-private.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/empty-mod-private.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/enum-variant-private-46767.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/files-creation-private.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/hidden-private.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/inline-private-with-intermediate-doc-hidden.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/inner-private-110422.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/macro-document-private-duplicate.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/macro-document-private.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/macro-private-not-documented.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/missing-private-inlining-109258.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/private-fields-tuple-struct.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/private-non-local-fields-2.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/private-non-local-fields.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/private-type-alias.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/private-type-cycle-110629.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/private-use-decl-macro-47038.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/private-use.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/public-impl-mention-private-generic-46380-2.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/traits-in-bodies-private.rs (100%) rename tests/{rustdoc => rustdoc-html}/process-termination.rs (100%) rename tests/{rustdoc => rustdoc-html}/pub-method.rs (100%) rename tests/{rustdoc => rustdoc-html}/pub-use-loop-107350.rs (100%) rename tests/{rustdoc => rustdoc-html}/pub-use-root-path-95873.rs (100%) rename tests/{rustdoc => rustdoc-html}/range-arg-pattern.rs (100%) rename tests/{rustdoc => rustdoc-html}/raw-ident-eliminate-r-hashtag.rs (100%) rename tests/{rustdoc => rustdoc-html}/read-more-unneeded.rs (100%) rename tests/{rustdoc => rustdoc-html}/recursion1.rs (100%) rename tests/{rustdoc => rustdoc-html}/recursion2.rs (100%) rename tests/{rustdoc => rustdoc-html}/recursion3.rs (100%) rename tests/{rustdoc => rustdoc-html}/redirect-map-empty.rs (100%) rename tests/{rustdoc => rustdoc-html}/redirect-map.rs (100%) rename tests/{rustdoc => rustdoc-html}/redirect-rename.rs (100%) rename tests/{rustdoc => rustdoc-html}/redirect.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/alias-reexport.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/alias-reexport2.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/anonymous-reexport-108931.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/anonymous-reexport.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/auxiliary/alias-reexport.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/auxiliary/alias-reexport2.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/auxiliary/all-item-types.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/auxiliary/issue-28927-1.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/auxiliary/issue-28927-2.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/auxiliary/primitive-reexport.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/auxiliary/reexport-check.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/auxiliary/reexport-doc-aux.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/auxiliary/reexports.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/auxiliary/wrap-unnamable-type.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/blanket-reexport-item.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/cfg_doc_reexport.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/doc-hidden-reexports-109449.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/duplicated-glob-reexport-60522.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/enum-variant-reexport-35488.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/enum-variant.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/extern-135092.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/foreigntype-reexport.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/glob-reexport-attribute-merge-120487.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/glob-reexport-attribute-merge-doc-auto-cfg.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/ice-reexport-crate-root-28927.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/import_trait_associated_functions.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/local-reexport-doc.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/merge-glob-and-non-glob.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/no-compiler-reexport.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/overlapping-reexport-105735-2.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/overlapping-reexport-105735.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/primitive-reexport.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/private-mod-override-reexport.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/pub-reexport-of-pub-reexport-46506.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-attr-merge.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-cfg.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-check.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-dep-foreign-fn.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-doc-hidden-inside-private.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-doc-hidden.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-doc.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-hidden-macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-of-doc-hidden.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-of-reexport-108679.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-stability-tags-deprecated-and-portability.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-stability-tags-unstable-and-portability.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-trait-from-hidden-111064-2.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-trait-from-hidden-111064.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexports-of-same-name.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexports-priv.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexports.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/wrapped-unnamble-type-143222.rs (100%) rename tests/{rustdoc => rustdoc-html}/remove-duplicates.rs (100%) rename tests/{rustdoc => rustdoc-html}/remove-url-from-headings.rs (100%) rename tests/{rustdoc => rustdoc-html}/repr.rs (100%) rename tests/{rustdoc => rustdoc-html}/resolve-ice-124363.rs (100%) rename tests/{rustdoc => rustdoc-html}/return-type-notation.rs (100%) rename tests/{rustdoc => rustdoc-html}/safe-intrinsic.rs (100%) rename tests/{rustdoc => rustdoc-html}/sanitizer-option.rs (100%) rename tests/{rustdoc => rustdoc-html}/search-index-summaries.rs (100%) rename tests/{rustdoc => rustdoc-html}/search-index.rs (100%) rename tests/{rustdoc => rustdoc-html}/short-docblock-codeblock.rs (100%) rename tests/{rustdoc => rustdoc-html}/short-docblock.rs (100%) rename tests/{rustdoc => rustdoc-html}/short-line.md (100%) rename tests/{rustdoc => rustdoc-html}/sidebar/module.rs (100%) rename tests/{rustdoc => rustdoc-html}/sidebar/sidebar-all-page.rs (100%) rename tests/{rustdoc => rustdoc-html}/sidebar/sidebar-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/sidebar/sidebar-link-generation.rs (100%) rename tests/{rustdoc => rustdoc-html}/sidebar/sidebar-links-to-foreign-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/sidebar/top-toc-html.rs (100%) rename tests/{rustdoc => rustdoc-html}/sidebar/top-toc-idmap.rs (100%) rename tests/{rustdoc => rustdoc-html}/sidebar/top-toc-nil.rs (100%) rename tests/{rustdoc => rustdoc-html}/sized_trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/slice-links.link_box_generic.html (100%) rename tests/{rustdoc => rustdoc-html}/slice-links.link_box_u32.html (100%) rename tests/{rustdoc => rustdoc-html}/slice-links.link_slice_generic.html (100%) rename tests/{rustdoc => rustdoc-html}/slice-links.link_slice_u32.html (100%) rename tests/{rustdoc => rustdoc-html}/slice-links.rs (100%) rename tests/{rustdoc => rustdoc-html}/smart-punct.rs (100%) rename tests/{rustdoc => rustdoc-html}/smoke.rs (100%) rename tests/{rustdoc => rustdoc-html}/sort-53812.rs (100%) rename tests/{rustdoc => rustdoc-html}/sort-modules-by-appearance.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/assoc-type-source-link.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/auxiliary/issue-26606-macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/auxiliary/issue-34274.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/auxiliary/source-code-bar.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/auxiliary/source_code.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/auxiliary/src-links-external.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/check-source-code-urls-to-def-std.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/check-source-code-urls-to-def.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/doc-hidden-source.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/failing-expansion-on-wrong-macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/frontmatter.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/html-no-source.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/keyword-macros.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/shebang.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/source-code-highlight.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/source-file.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/source-line-numbers.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/source-version-separator.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/src-link-external-macro-26606.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/src-links-auto-impls.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/src-links-external.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/src-links-implementor-43893.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/src-links-inlined-34274.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/src-links.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/src-links/compiletest-ignore-dir (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/src-links/fizz.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/src-links/mod.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/src-mod-path-absolute-26995.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/version-separator-without-source.rs (100%) rename tests/{rustdoc => rustdoc-html}/stability.rs (100%) rename tests/{rustdoc => rustdoc-html}/staged-api-deprecated-unstable-32374.rs (100%) rename tests/{rustdoc => rustdoc-html}/staged-api-feature-issue-27759.rs (100%) rename tests/{rustdoc => rustdoc-html}/static-root-path.rs (100%) rename tests/{rustdoc => rustdoc-html}/static.rs (100%) rename tests/{rustdoc => rustdoc-html}/strip-block-doc-comments-stars.docblock.html (100%) rename tests/{rustdoc => rustdoc-html}/strip-block-doc-comments-stars.rs (100%) rename tests/{rustdoc => rustdoc-html}/strip-priv-imports-pass-27104.rs (100%) rename tests/{rustdoc => rustdoc-html}/struct-arg-pattern.rs (100%) rename tests/{rustdoc => rustdoc-html}/struct-field.rs (100%) rename tests/{rustdoc => rustdoc-html}/structfields.rs (100%) rename tests/{rustdoc => rustdoc-html}/summary-codeblock-31899.rs (100%) rename tests/{rustdoc => rustdoc-html}/summary-header-46377.rs (100%) rename tests/{rustdoc => rustdoc-html}/summary-reference-link-30366.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/auto-trait-lifetimes-56822.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/basic.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/bounds.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/complex.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/crate-local.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/issue-72213-projection-lifetime.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/lifetimes.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/manual.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/negative.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/nested.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/no-redundancy.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/normalize-auto-trait-80233.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/overflow.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/project.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/self-referential.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/send-impl-conditional-60726.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/static-region.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/supertrait-bounds.rs (100%) rename tests/{rustdoc => rustdoc-html}/tab_title.rs (100%) rename tests/{rustdoc => rustdoc-html}/table-in-docblock.rs (100%) rename tests/{rustdoc => rustdoc-html}/target-feature.rs (100%) rename tests/{rustdoc => rustdoc-html}/task-lists.rs (100%) rename tests/{rustdoc => rustdoc-html}/test-lists.rs (100%) rename tests/{rustdoc => rustdoc-html}/test-parens.rs (100%) rename tests/{rustdoc => rustdoc-html}/test-strikethrough.rs (100%) rename tests/{rustdoc => rustdoc-html}/test_option_check/bar.rs (100%) rename tests/{rustdoc => rustdoc-html}/test_option_check/test.rs (100%) rename tests/{rustdoc => rustdoc-html}/thread-local-src.rs (100%) rename tests/{rustdoc => rustdoc-html}/titles.rs (100%) rename tests/{rustdoc => rustdoc-html}/toggle-item-contents.rs (100%) rename tests/{rustdoc => rustdoc-html}/toggle-method.rs (100%) rename tests/{rustdoc => rustdoc-html}/toggle-trait-fn.rs (100%) rename tests/{rustdoc => rustdoc-html}/trait-aliases.rs (100%) rename tests/{rustdoc => rustdoc-html}/trait-item-info.rs (100%) rename tests/{rustdoc => rustdoc-html}/trait-self-link.rs (100%) rename tests/{rustdoc => rustdoc-html}/trait-src-link.rs (100%) rename tests/{rustdoc => rustdoc-html}/trait-visibility.rs (100%) rename tests/{rustdoc => rustdoc-html}/traits-in-bodies.rs (100%) rename tests/{rustdoc => rustdoc-html}/tuple-struct-fields-doc.rs (100%) rename tests/{rustdoc => rustdoc-html}/tuple-struct-where-clause-34928.rs (100%) rename tests/{rustdoc => rustdoc-html}/tuples.link1_i32.html (100%) rename tests/{rustdoc => rustdoc-html}/tuples.link1_t.html (100%) rename tests/{rustdoc => rustdoc-html}/tuples.link2_i32.html (100%) rename tests/{rustdoc => rustdoc-html}/tuples.link2_t.html (100%) rename tests/{rustdoc => rustdoc-html}/tuples.link2_tu.html (100%) rename tests/{rustdoc => rustdoc-html}/tuples.link_unit.html (100%) rename tests/{rustdoc => rustdoc-html}/tuples.rs (100%) rename tests/{rustdoc => rustdoc-html}/type-alias/auxiliary/parent-crate-115718.rs (100%) rename tests/{rustdoc => rustdoc-html}/type-alias/cross-crate-115718.rs (100%) rename tests/{rustdoc => rustdoc-html}/type-alias/deeply-nested-112515.rs (100%) rename tests/{rustdoc => rustdoc-html}/type-alias/deref-32077.rs (100%) rename tests/{rustdoc => rustdoc-html}/type-alias/impl_trait_in_assoc_type.rs (100%) rename tests/{rustdoc => rustdoc-html}/type-alias/primitive-local-link-121106.rs (100%) rename tests/{rustdoc => rustdoc-html}/type-alias/repr.rs (100%) rename tests/{rustdoc => rustdoc-html}/type-alias/same-crate-115718.rs (100%) rename tests/{rustdoc => rustdoc-html}/type-layout-flag-required.rs (100%) rename tests/{rustdoc => rustdoc-html}/type-layout.rs (100%) rename tests/{rustdoc => rustdoc-html}/typedef-inner-variants-lazy_type_alias.rs (100%) rename tests/{rustdoc => rustdoc-html}/typedef-inner-variants.rs (100%) rename tests/{rustdoc => rustdoc-html}/typedef.rs (100%) rename tests/{rustdoc => rustdoc-html}/underscore-import-61592.rs (100%) rename tests/{rustdoc => rustdoc-html}/unindent.md (100%) rename tests/{rustdoc => rustdoc-html}/unindent.rs (100%) rename tests/{rustdoc => rustdoc-html}/union-fields-html.rs (100%) rename tests/{rustdoc => rustdoc-html}/union.rs (100%) rename tests/{rustdoc => rustdoc-html}/unit-return.rs (100%) rename tests/{rustdoc => rustdoc-html}/unsafe-binder.rs (100%) rename tests/{rustdoc => rustdoc-html}/use-attr.rs (100%) rename tests/{rustdoc => rustdoc-html}/useless_lifetime_bound.rs (100%) rename tests/{rustdoc => rustdoc-html}/variadic.rs (100%) rename tests/{rustdoc => rustdoc-html}/viewpath-rename.rs (100%) rename tests/{rustdoc => rustdoc-html}/viewpath-self.rs (100%) rename tests/{rustdoc => rustdoc-html}/visibility.rs (100%) rename tests/{rustdoc => rustdoc-html}/where-clause-order.rs (100%) rename tests/{rustdoc => rustdoc-html}/where-sized.rs (100%) rename tests/{rustdoc => rustdoc-html}/where.SWhere_Echo_impl.html (100%) rename tests/{rustdoc => rustdoc-html}/where.SWhere_Simd_item-decl.html (100%) rename tests/{rustdoc => rustdoc-html}/where.SWhere_TraitWhere_item-decl.html (100%) rename tests/{rustdoc => rustdoc-html}/where.alpha_trait_decl.html (100%) rename tests/{rustdoc => rustdoc-html}/where.bravo_trait_decl.html (100%) rename tests/{rustdoc => rustdoc-html}/where.charlie_fn_decl.html (100%) rename tests/{rustdoc => rustdoc-html}/where.golf_type_alias_decl.html (100%) rename tests/{rustdoc => rustdoc-html}/where.rs (100%) rename tests/{rustdoc => rustdoc-html}/whitespace-after-where-clause.enum.html (100%) rename tests/{rustdoc => rustdoc-html}/whitespace-after-where-clause.enum2.html (100%) rename tests/{rustdoc => rustdoc-html}/whitespace-after-where-clause.rs (100%) rename tests/{rustdoc => rustdoc-html}/whitespace-after-where-clause.struct.html (100%) rename tests/{rustdoc => rustdoc-html}/whitespace-after-where-clause.struct2.html (100%) rename tests/{rustdoc => rustdoc-html}/whitespace-after-where-clause.trait.html (100%) rename tests/{rustdoc => rustdoc-html}/whitespace-after-where-clause.trait2.html (100%) rename tests/{rustdoc => rustdoc-html}/whitespace-after-where-clause.union.html (100%) rename tests/{rustdoc => rustdoc-html}/whitespace-after-where-clause.union2.html (100%) rename tests/{rustdoc => rustdoc-html}/without-redirect.rs (100%) rename tests/{rustdoc => rustdoc-html}/wrapping.rs (100%) diff --git a/rustfmt.toml b/rustfmt.toml index 6172a2bb3bf9..910eea103798 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -21,7 +21,7 @@ ignore = [ "/tests/pretty/", # These tests are very sensitive to source code layout. "/tests/run-make/export", # These tests contain syntax errors. "/tests/run-make/translation/test.rs", # This test contains syntax errors. - "/tests/rustdoc/", # Some have syntax errors, some are whitespace-sensitive. + "/tests/rustdoc-html/", # Some have syntax errors, some are whitespace-sensitive. "/tests/rustdoc-gui/", # Some tests are sensitive to source code layout. "/tests/rustdoc-ui/", # Some have syntax errors, some are whitespace-sensitive. "/tests/ui/", # Some have syntax errors, some are whitespace-sensitive. diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index a3c13fc4b095..b26df1586e71 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1582,10 +1582,10 @@ test!(UiFullDeps { IS_HOST: true, }); -test!(Rustdoc { - path: "tests/rustdoc", - mode: CompiletestMode::Rustdoc, - suite: "rustdoc", +test!(RustdocHtml { + path: "tests/rustdoc-html", + mode: CompiletestMode::RustdocHtml, + suite: "rustdoc-html", default: true, IS_HOST: true, }); @@ -1969,7 +1969,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the if matches!( mode, CompiletestMode::RunMake - | CompiletestMode::Rustdoc + | CompiletestMode::RustdocHtml | CompiletestMode::RustdocJs | CompiletestMode::RustdocJson ) || matches!(suite, "rustdoc-ui" | "coverage-run-rustdoc") @@ -2758,7 +2758,7 @@ impl Step for ErrorIndex { fn make_run(run: RunConfig<'_>) { // error_index_generator depends on librustdoc. Use the compiler that // is normally used to build rustdoc for other tests (like compiletest - // tests in tests/rustdoc) so that it shares the same artifacts. + // tests in tests/rustdoc-html) so that it shares the same artifacts. let compilers = RustcPrivateCompilers::new( run.builder, run.builder.top_stage, @@ -3159,7 +3159,7 @@ impl Step for CrateRustdoc { builder.compiler(builder.top_stage, target) } else { // Use the previous stage compiler to reuse the artifacts that are - // created when running compiletest for tests/rustdoc. If this used + // created when running compiletest for tests/rustdoc-html. If this used // `compiler`, then it would cause rustdoc to be built *again*, which // isn't really necessary. builder.compiler_for(builder.top_stage, target, target) diff --git a/src/bootstrap/src/core/build_steps/test/compiletest.rs b/src/bootstrap/src/core/build_steps/test/compiletest.rs index 359f6bb1a6ef..230ed75a0868 100644 --- a/src/bootstrap/src/core/build_steps/test/compiletest.rs +++ b/src/bootstrap/src/core/build_steps/test/compiletest.rs @@ -21,7 +21,7 @@ pub(crate) enum CompiletestMode { MirOpt, Pretty, RunMake, - Rustdoc, + RustdocHtml, RustdocJs, RustdocJson, Ui, @@ -49,7 +49,7 @@ impl CompiletestMode { Self::MirOpt => "mir-opt", Self::Pretty => "pretty", Self::RunMake => "run-make", - Self::Rustdoc => "rustdoc", + Self::RustdocHtml => "rustdoc-html", Self::RustdocJs => "rustdoc-js", Self::RustdocJson => "rustdoc-json", Self::Ui => "ui", diff --git a/src/bootstrap/src/core/builder/cli_paths.rs b/src/bootstrap/src/core/builder/cli_paths.rs index 470e83d341c7..5ff2b380e4b9 100644 --- a/src/bootstrap/src/core/builder/cli_paths.rs +++ b/src/bootstrap/src/core/builder/cli_paths.rs @@ -31,8 +31,8 @@ pub(crate) const PATH_REMAP: &[(&str, &[&str])] = &[ "tests/pretty", "tests/run-make", "tests/run-make-cargo", - "tests/rustdoc", "tests/rustdoc-gui", + "tests/rustdoc-html", "tests/rustdoc-js", "tests/rustdoc-js-std", "tests/rustdoc-json", diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap index fd18b59a9c6d..4ab84c3cabc1 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap @@ -1,6 +1,5 @@ --- source: src/bootstrap/src/core/builder/cli_paths/tests.rs -assertion_line: 68 expression: test --- [Test] test::Tidy @@ -38,9 +37,9 @@ expression: test [Test] test::UiFullDeps targets: [x86_64-unknown-linux-gnu] - Suite(test::tests/ui-fulldeps) -[Test] test::Rustdoc +[Test] test::RustdocHtml targets: [x86_64-unknown-linux-gnu] - - Suite(test::tests/rustdoc) + - Suite(test::tests/rustdoc-html) [Test] test::CoverageRunRustdoc targets: [x86_64-unknown-linux-gnu] - Suite(test::tests/coverage-run-rustdoc) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_librustdoc_rustdoc.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_librustdoc_rustdoc.snap index 6522a7e8edaf..c8eee72aec42 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_librustdoc_rustdoc.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_librustdoc_rustdoc.snap @@ -5,9 +5,6 @@ expression: test librustdoc rustdoc [Test] test::CrateRustdoc targets: [x86_64-unknown-linux-gnu] - Set({test::src/librustdoc, test::src/tools/rustdoc}) -[Test] test::Rustdoc - targets: [x86_64-unknown-linux-gnu] - - Suite(test::tests/rustdoc) [Test] test::RustdocBook targets: [x86_64-unknown-linux-gnu] - Set({test::src/doc/rustdoc}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_librustdoc_rustdoc_html.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_librustdoc_rustdoc_html.snap new file mode 100644 index 000000000000..21acc1e46069 --- /dev/null +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_librustdoc_rustdoc_html.snap @@ -0,0 +1,10 @@ +--- +source: src/bootstrap/src/core/builder/cli_paths/tests.rs +expression: test librustdoc rustdoc-html +--- +[Test] test::CrateRustdoc + targets: [x86_64-unknown-linux-gnu] + - Set({test::src/librustdoc}) +[Test] test::RustdocHtml + targets: [x86_64-unknown-linux-gnu] + - Suite(test::tests/rustdoc-html) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_rustdoc.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_rustdoc.snap index 337ad33fe35f..897372dcd1c7 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_rustdoc.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_rustdoc.snap @@ -2,9 +2,6 @@ source: src/bootstrap/src/core/builder/cli_paths/tests.rs expression: test rustdoc --- -[Test] test::Rustdoc - targets: [x86_64-unknown-linux-gnu] - - Suite(test::tests/rustdoc) [Test] test::CrateRustdoc targets: [x86_64-unknown-linux-gnu] - Set({test::src/tools/rustdoc}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_rustdoc_html.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_rustdoc_html.snap new file mode 100644 index 000000000000..a6a2a27c075e --- /dev/null +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_rustdoc_html.snap @@ -0,0 +1,7 @@ +--- +source: src/bootstrap/src/core/builder/cli_paths/tests.rs +expression: test rustdoc-html +--- +[Test] test::RustdocHtml + targets: [x86_64-unknown-linux-gnu] + - Suite(test::tests/rustdoc-html) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap index 171680515476..2a4805e4fd68 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap @@ -1,6 +1,5 @@ --- source: src/bootstrap/src/core/builder/cli_paths/tests.rs -assertion_line: 68 expression: test --skip=coverage --- [Test] test::Tidy @@ -37,9 +36,9 @@ expression: test --skip=coverage [Test] test::UiFullDeps targets: [x86_64-unknown-linux-gnu] - Suite(test::tests/ui-fulldeps) -[Test] test::Rustdoc +[Test] test::RustdocHtml targets: [x86_64-unknown-linux-gnu] - - Suite(test::tests/rustdoc) + - Suite(test::tests/rustdoc-html) [Test] test::CoverageRunRustdoc targets: [x86_64-unknown-linux-gnu] - Suite(test::tests/coverage-run-rustdoc) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_tests.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_tests.snap index b38af13d49c3..ad9660ef5c91 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_tests.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_tests.snap @@ -38,12 +38,12 @@ expression: test tests [Test] test::RunMakeCargo targets: [aarch64-unknown-linux-gnu] - Suite(test::tests/run-make-cargo) -[Test] test::Rustdoc - targets: [x86_64-unknown-linux-gnu] - - Suite(test::tests/rustdoc) [Test] test::RustdocGUI targets: [x86_64-unknown-linux-gnu] - Suite(test::tests/rustdoc-gui) +[Test] test::RustdocHtml + targets: [x86_64-unknown-linux-gnu] + - Suite(test::tests/rustdoc-html) [Test] test::RustdocJSNotStd targets: [x86_64-unknown-linux-gnu] - Suite(test::tests/rustdoc-js) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_tests_skip_coverage.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_tests_skip_coverage.snap index 6a158ea62bb3..4572f089b0ae 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_tests_skip_coverage.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_tests_skip_coverage.snap @@ -35,12 +35,12 @@ expression: test tests --skip=coverage [Test] test::RunMakeCargo targets: [aarch64-unknown-linux-gnu] - Suite(test::tests/run-make-cargo) -[Test] test::Rustdoc - targets: [x86_64-unknown-linux-gnu] - - Suite(test::tests/rustdoc) [Test] test::RustdocGUI targets: [x86_64-unknown-linux-gnu] - Suite(test::tests/rustdoc-gui) +[Test] test::RustdocHtml + targets: [x86_64-unknown-linux-gnu] + - Suite(test::tests/rustdoc-html) [Test] test::RustdocJSNotStd targets: [x86_64-unknown-linux-gnu] - Suite(test::tests/rustdoc-js) diff --git a/src/bootstrap/src/core/builder/cli_paths/tests.rs b/src/bootstrap/src/core/builder/cli_paths/tests.rs index 49f75c8bea77..39293abd4fb9 100644 --- a/src/bootstrap/src/core/builder/cli_paths/tests.rs +++ b/src/bootstrap/src/core/builder/cli_paths/tests.rs @@ -169,7 +169,9 @@ declare_tests!( (x_test_library, "test library"), (x_test_librustdoc, "test librustdoc"), (x_test_librustdoc_rustdoc, "test librustdoc rustdoc"), + (x_test_librustdoc_rustdoc_html, "test librustdoc rustdoc-html"), (x_test_rustdoc, "test rustdoc"), + (x_test_rustdoc_html, "test rustdoc-html"), (x_test_skip_coverage, "test --skip=coverage"), // FIXME(Zalathar): This doesn't skip the coverage-map or coverage-run tests. (x_test_skip_tests, "test --skip=tests"), diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 92a6eb8ce837..9e1a65bca79d 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -880,7 +880,7 @@ impl<'a> Builder<'a> { test::Incremental, test::Debuginfo, test::UiFullDeps, - test::Rustdoc, + test::RustdocHtml, test::CoverageRunRustdoc, test::Pretty, test::CodegenCranelift, diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 9146c470e358..66614cc6cced 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2099,7 +2099,7 @@ mod snapshot { [test] compiletest-debuginfo 1 [test] compiletest-ui-fulldeps 1 [build] rustdoc 1 - [test] compiletest-rustdoc 1 + [test] compiletest-rustdoc-html 1 [test] compiletest-coverage-run-rustdoc 1 [test] compiletest-pretty 1 [build] rustc 1 -> std 1 @@ -2169,7 +2169,7 @@ mod snapshot { let ctx = TestCtx::new(); insta::assert_snapshot!( ctx.config("test") - .args(&["ui", "ui-fulldeps", "run-make", "rustdoc", "rustdoc-gui", "incremental"]) + .args(&["ui", "ui-fulldeps", "run-make", "rustdoc-html", "rustdoc-gui", "incremental"]) .render_steps(), @r" [build] llvm [build] rustc 0 -> rustc 1 @@ -2180,11 +2180,10 @@ mod snapshot { [build] rustc 0 -> RunMakeSupport 1 [build] rustdoc 1 [test] compiletest-run-make 1 - [test] compiletest-rustdoc 1 + [test] compiletest-rustdoc-html 1 [build] rustc 0 -> RustdocGUITest 1 [test] rustdoc-gui 1 [test] compiletest-incremental 1 - [build] rustc 1 -> rustc 2 "); } @@ -2193,7 +2192,7 @@ mod snapshot { let ctx = TestCtx::new(); insta::assert_snapshot!( ctx.config("test") - .args(&["ui", "ui-fulldeps", "run-make", "rustdoc", "rustdoc-gui", "incremental"]) + .args(&["ui", "ui-fulldeps", "run-make", "rustdoc-html", "rustdoc-gui", "incremental"]) .stage(2) .render_steps(), @r" [build] llvm @@ -2208,11 +2207,10 @@ mod snapshot { [build] rustc 0 -> RunMakeSupport 1 [build] rustdoc 2 [test] compiletest-run-make 2 - [test] compiletest-rustdoc 2 + [test] compiletest-rustdoc-html 2 [build] rustc 0 -> RustdocGUITest 1 [test] rustdoc-gui 2 [test] compiletest-incremental 2 - [build] rustdoc 1 "); } @@ -2241,12 +2239,11 @@ mod snapshot { [build] rustc 0 -> RunMakeSupport 1 [build] rustdoc 2 [test] compiletest-run-make 2 - [test] compiletest-rustdoc 2 + [build] rustc 1 -> rustc 2 + [build] rustdoc 1 [build] rustc 0 -> RustdocGUITest 1 [test] rustdoc-gui 2 [test] compiletest-incremental 2 - [build] rustc 1 -> rustc 2 - [build] rustdoc 1 [build] rustc 2 -> std 2 [build] rustdoc 2 "); @@ -2283,7 +2280,7 @@ mod snapshot { [build] rustc 2 -> rustc 3 [test] compiletest-ui-fulldeps 2 [build] rustdoc 2 - [test] compiletest-rustdoc 2 + [test] compiletest-rustdoc-html 2 [test] compiletest-coverage-run-rustdoc 2 [test] compiletest-pretty 2 [build] rustc 2 -> std 2 diff --git a/src/ci/citool/tests/test-jobs.yml b/src/ci/citool/tests/test-jobs.yml index 512c80628574..e26104905491 100644 --- a/src/ci/citool/tests/test-jobs.yml +++ b/src/ci/citool/tests/test-jobs.yml @@ -27,7 +27,7 @@ runners: <<: *base-job envs: env-x86_64-apple-tests: &env-x86_64-apple-tests - SCRIPT: ./x.py check compiletest && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact + SCRIPT: ./x.py check compiletest && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc-html -- --exact RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 # Ensure that host tooling is tested on our minimum supported macOS version. diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-gcc/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-gcc/Dockerfile index 0fd14ae232d7..f9c1ea531add 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-gcc/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-gcc/Dockerfile @@ -45,7 +45,7 @@ ENV SCRIPT python3 ../x.py \ --test-codegen-backend gcc \ --skip tests/coverage \ --skip tests/coverage-run-rustdoc \ - --skip tests/rustdoc \ + --skip tests/rustdoc-html \ --skip tests/rustdoc-gui \ --skip tests/rustdoc-js \ --skip tests/rustdoc-js-std \ diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index e0a37c95257c..af97ae93a2b9 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -882,7 +882,8 @@ impl<'item> DocVisitor<'item> for TypeImplCollector<'_, '_, 'item> { // // FIXME(lazy_type_alias): Once the feature is complete or stable, rewrite this // to use type unification. - // Be aware of `tests/rustdoc/type-alias/deeply-nested-112515.rs` which might regress. + // Be aware of `tests/rustdoc-html/type-alias/deeply-nested-112515.rs` which might + // regress. let Some(impl_did) = impl_item_id.as_def_id() else { continue }; let for_ty = self.cx.tcx().type_of(impl_did).skip_binder(); let reject_cx = DeepRejectCtxt::relate_infer_infer(self.cx.tcx()); diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 5563abe92a80..450fde3bbc38 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -18,7 +18,7 @@ string_enum! { Pretty => "pretty", DebugInfo => "debuginfo", Codegen => "codegen", - Rustdoc => "rustdoc", + RustdocHtml => "rustdoc-html", RustdocJson => "rustdoc-json", CodegenUnits => "codegen-units", Incremental => "incremental", @@ -69,7 +69,7 @@ string_enum! { Pretty => "pretty", RunMake => "run-make", RunMakeCargo => "run-make-cargo", - Rustdoc => "rustdoc", + RustdocHtml => "rustdoc-html", RustdocGui => "rustdoc-gui", RustdocJs => "rustdoc-js", RustdocJsStd=> "rustdoc-js-std", diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 5865954558d8..624f4dd7c2b1 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -552,7 +552,7 @@ fn check_directive<'a>( let is_known_directive = KNOWN_DIRECTIVE_NAMES_SET.contains(&directive_name) || match mode { - TestMode::Rustdoc => KNOWN_HTMLDOCCK_DIRECTIVE_NAMES.contains(&directive_name), + TestMode::RustdocHtml => KNOWN_HTMLDOCCK_DIRECTIVE_NAMES.contains(&directive_name), TestMode::RustdocJson => KNOWN_JSONDOCCK_DIRECTIVE_NAMES.contains(&directive_name), _ => false, }; diff --git a/src/tools/compiletest/src/directives/tests.rs b/src/tools/compiletest/src/directives/tests.rs index 0d3777b8e60c..2dc878fa2a20 100644 --- a/src/tools/compiletest/src/directives/tests.rs +++ b/src/tools/compiletest/src/directives/tests.rs @@ -630,7 +630,7 @@ fn test_forbidden_revisions_allowed_in_non_filecheck_dir() { let modes = [ "pretty", "debuginfo", - "rustdoc", + "rustdoc-html", "rustdoc-json", "codegen-units", "incremental", diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index a64c7850aad4..c219a8887f8f 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -85,7 +85,7 @@ fn parse_config(args: Vec) -> Config { "", "mode", "which sort of compile tests to run", - "pretty | debug-info | codegen | rustdoc \ + "pretty | debug-info | codegen | rustdoc-html \ | rustdoc-json | codegen-units | incremental | run-make | ui \ | rustdoc-js | mir-opt | assembly | crashes", ) @@ -1094,8 +1094,8 @@ fn make_test_name_and_filterable_path( /// of some other tests's name. /// /// For example, suppose the test suite contains these two test files: -/// - `tests/rustdoc/primitive.rs` -/// - `tests/rustdoc/primitive/no_std.rs` +/// - `tests/rustdoc-html/primitive.rs` +/// - `tests/rustdoc-html/primitive/no_std.rs` /// /// The test runner might put the output from those tests in these directories: /// - `$build/test/rustdoc/primitive/` diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 1216ba888328..6efdb5a99ee2 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -269,7 +269,7 @@ impl<'test> TestCx<'test> { TestMode::Pretty => self.run_pretty_test(), TestMode::DebugInfo => self.run_debuginfo_test(), TestMode::Codegen => self.run_codegen_test(), - TestMode::Rustdoc => self.run_rustdoc_test(), + TestMode::RustdocHtml => self.run_rustdoc_html_test(), TestMode::RustdocJson => self.run_rustdoc_json_test(), TestMode::CodegenUnits => self.run_codegen_units_test(), TestMode::Incremental => self.run_incremental_test(), @@ -1758,7 +1758,7 @@ impl<'test> TestCx<'test> { } TestMode::Pretty | TestMode::DebugInfo - | TestMode::Rustdoc + | TestMode::RustdocHtml | TestMode::RustdocJson | TestMode::RunMake | TestMode::RustdocJs => { diff --git a/src/tools/compiletest/src/runtest/rustdoc.rs b/src/tools/compiletest/src/runtest/rustdoc.rs index 3c80521e51ec..8907848e0ca5 100644 --- a/src/tools/compiletest/src/runtest/rustdoc.rs +++ b/src/tools/compiletest/src/runtest/rustdoc.rs @@ -3,7 +3,7 @@ use std::process::Command; use super::{DocKind, TestCx, remove_and_create_dir_all}; impl TestCx<'_> { - pub(super) fn run_rustdoc_test(&self) { + pub(super) fn run_rustdoc_html_test(&self) { assert!(self.revision.is_none(), "revisions not supported in this test suite"); let out_dir = self.output_base_dir(); diff --git a/src/tools/compiletest/src/rustdoc_gui_test.rs b/src/tools/compiletest/src/rustdoc_gui_test.rs index 4454ffb1f59e..bacc8061d209 100644 --- a/src/tools/compiletest/src/rustdoc_gui_test.rs +++ b/src/tools/compiletest/src/rustdoc_gui_test.rs @@ -50,7 +50,7 @@ fn incomplete_config_for_rustdoc_gui_test() -> Config { // // For instance, `//@ ignore-stage1` will not work at all. Config { - mode: TestMode::Rustdoc, + mode: TestMode::RustdocHtml, // E.g. this has no sensible default tbh. suite: TestSuite::Ui, diff --git a/src/tools/opt-dist/src/tests.rs b/src/tools/opt-dist/src/tests.rs index 29168b25f7f6..1aacfeaf538e 100644 --- a/src/tools/opt-dist/src/tests.rs +++ b/src/tools/opt-dist/src/tests.rs @@ -123,7 +123,7 @@ llvm-config = "{llvm_config}" "tests/run-make/rust-lld-x86_64-unknown-linux-gnu-dist", "tests/ui", "tests/crashes", - "tests/rustdoc", + "tests/rustdoc-html", ]; for test_path in env.skipped_tests() { args.extend(["--skip", test_path]); diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 08061bd834e3..43e6c18382af 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -107,7 +107,7 @@ pub fn check( &tests_path.join("ui"), &tests_path.join("ui-fulldeps"), &tests_path.join("rustdoc-ui"), - &tests_path.join("rustdoc"), + &tests_path.join("rustdoc-html"), ], |path, _is_dir| { filter_dirs(path) diff --git a/tests/rustdoc/all.rs b/tests/rustdoc-html/all.rs similarity index 100% rename from tests/rustdoc/all.rs rename to tests/rustdoc-html/all.rs diff --git a/tests/rustdoc/anchors/anchor-id-duplicate-method-name-25001.rs b/tests/rustdoc-html/anchors/anchor-id-duplicate-method-name-25001.rs similarity index 100% rename from tests/rustdoc/anchors/anchor-id-duplicate-method-name-25001.rs rename to tests/rustdoc-html/anchors/anchor-id-duplicate-method-name-25001.rs diff --git a/tests/rustdoc/anchors/anchor-id-trait-method-15169.rs b/tests/rustdoc-html/anchors/anchor-id-trait-method-15169.rs similarity index 100% rename from tests/rustdoc/anchors/anchor-id-trait-method-15169.rs rename to tests/rustdoc-html/anchors/anchor-id-trait-method-15169.rs diff --git a/tests/rustdoc/anchors/anchor-id-trait-tymethod-28478.rs b/tests/rustdoc-html/anchors/anchor-id-trait-tymethod-28478.rs similarity index 100% rename from tests/rustdoc/anchors/anchor-id-trait-tymethod-28478.rs rename to tests/rustdoc-html/anchors/anchor-id-trait-tymethod-28478.rs diff --git a/tests/rustdoc/anchors/anchors.no_const_anchor.html b/tests/rustdoc-html/anchors/anchors.no_const_anchor.html similarity index 100% rename from tests/rustdoc/anchors/anchors.no_const_anchor.html rename to tests/rustdoc-html/anchors/anchors.no_const_anchor.html diff --git a/tests/rustdoc/anchors/anchors.no_const_anchor2.html b/tests/rustdoc-html/anchors/anchors.no_const_anchor2.html similarity index 100% rename from tests/rustdoc/anchors/anchors.no_const_anchor2.html rename to tests/rustdoc-html/anchors/anchors.no_const_anchor2.html diff --git a/tests/rustdoc/anchors/anchors.no_method_anchor.html b/tests/rustdoc-html/anchors/anchors.no_method_anchor.html similarity index 100% rename from tests/rustdoc/anchors/anchors.no_method_anchor.html rename to tests/rustdoc-html/anchors/anchors.no_method_anchor.html diff --git a/tests/rustdoc/anchors/anchors.no_trait_method_anchor.html b/tests/rustdoc-html/anchors/anchors.no_trait_method_anchor.html similarity index 100% rename from tests/rustdoc/anchors/anchors.no_trait_method_anchor.html rename to tests/rustdoc-html/anchors/anchors.no_trait_method_anchor.html diff --git a/tests/rustdoc/anchors/anchors.no_tymethod_anchor.html b/tests/rustdoc-html/anchors/anchors.no_tymethod_anchor.html similarity index 100% rename from tests/rustdoc/anchors/anchors.no_tymethod_anchor.html rename to tests/rustdoc-html/anchors/anchors.no_tymethod_anchor.html diff --git a/tests/rustdoc/anchors/anchors.no_type_anchor.html b/tests/rustdoc-html/anchors/anchors.no_type_anchor.html similarity index 100% rename from tests/rustdoc/anchors/anchors.no_type_anchor.html rename to tests/rustdoc-html/anchors/anchors.no_type_anchor.html diff --git a/tests/rustdoc/anchors/anchors.no_type_anchor2.html b/tests/rustdoc-html/anchors/anchors.no_type_anchor2.html similarity index 100% rename from tests/rustdoc/anchors/anchors.no_type_anchor2.html rename to tests/rustdoc-html/anchors/anchors.no_type_anchor2.html diff --git a/tests/rustdoc/anchors/anchors.rs b/tests/rustdoc-html/anchors/anchors.rs similarity index 100% rename from tests/rustdoc/anchors/anchors.rs rename to tests/rustdoc-html/anchors/anchors.rs diff --git a/tests/rustdoc/anchors/auxiliary/issue-86620-1.rs b/tests/rustdoc-html/anchors/auxiliary/issue-86620-1.rs similarity index 100% rename from tests/rustdoc/anchors/auxiliary/issue-86620-1.rs rename to tests/rustdoc-html/anchors/auxiliary/issue-86620-1.rs diff --git a/tests/rustdoc/anchors/disambiguate-anchors-32890.rs b/tests/rustdoc-html/anchors/disambiguate-anchors-32890.rs similarity index 100% rename from tests/rustdoc/anchors/disambiguate-anchors-32890.rs rename to tests/rustdoc-html/anchors/disambiguate-anchors-32890.rs diff --git a/tests/rustdoc/anchors/disambiguate-anchors-header-29449.rs b/tests/rustdoc-html/anchors/disambiguate-anchors-header-29449.rs similarity index 100% rename from tests/rustdoc/anchors/disambiguate-anchors-header-29449.rs rename to tests/rustdoc-html/anchors/disambiguate-anchors-header-29449.rs diff --git a/tests/rustdoc/anchors/method-anchor-in-blanket-impl-86620.rs b/tests/rustdoc-html/anchors/method-anchor-in-blanket-impl-86620.rs similarity index 100% rename from tests/rustdoc/anchors/method-anchor-in-blanket-impl-86620.rs rename to tests/rustdoc-html/anchors/method-anchor-in-blanket-impl-86620.rs diff --git a/tests/rustdoc/anchors/trait-impl-items-links-and-anchors.rs b/tests/rustdoc-html/anchors/trait-impl-items-links-and-anchors.rs similarity index 100% rename from tests/rustdoc/anchors/trait-impl-items-links-and-anchors.rs rename to tests/rustdoc-html/anchors/trait-impl-items-links-and-anchors.rs diff --git a/tests/rustdoc/anon-fn-params.rs b/tests/rustdoc-html/anon-fn-params.rs similarity index 100% rename from tests/rustdoc/anon-fn-params.rs rename to tests/rustdoc-html/anon-fn-params.rs diff --git a/tests/rustdoc/anonymous-lifetime.rs b/tests/rustdoc-html/anonymous-lifetime.rs similarity index 100% rename from tests/rustdoc/anonymous-lifetime.rs rename to tests/rustdoc-html/anonymous-lifetime.rs diff --git a/tests/rustdoc/array-links.link_box_generic.html b/tests/rustdoc-html/array-links.link_box_generic.html similarity index 100% rename from tests/rustdoc/array-links.link_box_generic.html rename to tests/rustdoc-html/array-links.link_box_generic.html diff --git a/tests/rustdoc/array-links.link_box_u32.html b/tests/rustdoc-html/array-links.link_box_u32.html similarity index 100% rename from tests/rustdoc/array-links.link_box_u32.html rename to tests/rustdoc-html/array-links.link_box_u32.html diff --git a/tests/rustdoc/array-links.link_slice_generic.html b/tests/rustdoc-html/array-links.link_slice_generic.html similarity index 100% rename from tests/rustdoc/array-links.link_slice_generic.html rename to tests/rustdoc-html/array-links.link_slice_generic.html diff --git a/tests/rustdoc/array-links.link_slice_u32.html b/tests/rustdoc-html/array-links.link_slice_u32.html similarity index 100% rename from tests/rustdoc/array-links.link_slice_u32.html rename to tests/rustdoc-html/array-links.link_slice_u32.html diff --git a/tests/rustdoc/array-links.rs b/tests/rustdoc-html/array-links.rs similarity index 100% rename from tests/rustdoc/array-links.rs rename to tests/rustdoc-html/array-links.rs diff --git a/tests/rustdoc/asm-foreign.rs b/tests/rustdoc-html/asm-foreign.rs similarity index 100% rename from tests/rustdoc/asm-foreign.rs rename to tests/rustdoc-html/asm-foreign.rs diff --git a/tests/rustdoc/asm-foreign2.rs b/tests/rustdoc-html/asm-foreign2.rs similarity index 100% rename from tests/rustdoc/asm-foreign2.rs rename to tests/rustdoc-html/asm-foreign2.rs diff --git a/tests/rustdoc/asref-for-and-of-local-82465.rs b/tests/rustdoc-html/asref-for-and-of-local-82465.rs similarity index 100% rename from tests/rustdoc/asref-for-and-of-local-82465.rs rename to tests/rustdoc-html/asref-for-and-of-local-82465.rs diff --git a/tests/rustdoc/assoc/assoc-fns.rs b/tests/rustdoc-html/assoc/assoc-fns.rs similarity index 100% rename from tests/rustdoc/assoc/assoc-fns.rs rename to tests/rustdoc-html/assoc/assoc-fns.rs diff --git a/tests/rustdoc/assoc/assoc-item-cast.rs b/tests/rustdoc-html/assoc/assoc-item-cast.rs similarity index 100% rename from tests/rustdoc/assoc/assoc-item-cast.rs rename to tests/rustdoc-html/assoc/assoc-item-cast.rs diff --git a/tests/rustdoc/assoc/assoc-type-bindings-20646.rs b/tests/rustdoc-html/assoc/assoc-type-bindings-20646.rs similarity index 100% rename from tests/rustdoc/assoc/assoc-type-bindings-20646.rs rename to tests/rustdoc-html/assoc/assoc-type-bindings-20646.rs diff --git a/tests/rustdoc/assoc/assoc-types.rs b/tests/rustdoc-html/assoc/assoc-types.rs similarity index 100% rename from tests/rustdoc/assoc/assoc-types.rs rename to tests/rustdoc-html/assoc/assoc-types.rs diff --git a/tests/rustdoc/assoc/auxiliary/cross-crate-hidden-assoc-trait-items.rs b/tests/rustdoc-html/assoc/auxiliary/cross-crate-hidden-assoc-trait-items.rs similarity index 100% rename from tests/rustdoc/assoc/auxiliary/cross-crate-hidden-assoc-trait-items.rs rename to tests/rustdoc-html/assoc/auxiliary/cross-crate-hidden-assoc-trait-items.rs diff --git a/tests/rustdoc/assoc/auxiliary/issue-20646.rs b/tests/rustdoc-html/assoc/auxiliary/issue-20646.rs similarity index 100% rename from tests/rustdoc/assoc/auxiliary/issue-20646.rs rename to tests/rustdoc-html/assoc/auxiliary/issue-20646.rs diff --git a/tests/rustdoc/assoc/auxiliary/issue-20727.rs b/tests/rustdoc-html/assoc/auxiliary/issue-20727.rs similarity index 100% rename from tests/rustdoc/assoc/auxiliary/issue-20727.rs rename to tests/rustdoc-html/assoc/auxiliary/issue-20727.rs diff --git a/tests/rustdoc/assoc/auxiliary/normalize-assoc-item.rs b/tests/rustdoc-html/assoc/auxiliary/normalize-assoc-item.rs similarity index 100% rename from tests/rustdoc/assoc/auxiliary/normalize-assoc-item.rs rename to tests/rustdoc-html/assoc/auxiliary/normalize-assoc-item.rs diff --git a/tests/rustdoc/assoc/cross-crate-hidden-assoc-trait-items.rs b/tests/rustdoc-html/assoc/cross-crate-hidden-assoc-trait-items.rs similarity index 100% rename from tests/rustdoc/assoc/cross-crate-hidden-assoc-trait-items.rs rename to tests/rustdoc-html/assoc/cross-crate-hidden-assoc-trait-items.rs diff --git a/tests/rustdoc/assoc/doc-assoc-item.rs b/tests/rustdoc-html/assoc/doc-assoc-item.rs similarity index 100% rename from tests/rustdoc/assoc/doc-assoc-item.rs rename to tests/rustdoc-html/assoc/doc-assoc-item.rs diff --git a/tests/rustdoc/assoc/inline-assoc-type-20727-bindings.rs b/tests/rustdoc-html/assoc/inline-assoc-type-20727-bindings.rs similarity index 100% rename from tests/rustdoc/assoc/inline-assoc-type-20727-bindings.rs rename to tests/rustdoc-html/assoc/inline-assoc-type-20727-bindings.rs diff --git a/tests/rustdoc/assoc/inline-assoc-type-20727-bounds-deref.rs b/tests/rustdoc-html/assoc/inline-assoc-type-20727-bounds-deref.rs similarity index 100% rename from tests/rustdoc/assoc/inline-assoc-type-20727-bounds-deref.rs rename to tests/rustdoc-html/assoc/inline-assoc-type-20727-bounds-deref.rs diff --git a/tests/rustdoc/assoc/inline-assoc-type-20727-bounds-index.rs b/tests/rustdoc-html/assoc/inline-assoc-type-20727-bounds-index.rs similarity index 100% rename from tests/rustdoc/assoc/inline-assoc-type-20727-bounds-index.rs rename to tests/rustdoc-html/assoc/inline-assoc-type-20727-bounds-index.rs diff --git a/tests/rustdoc/assoc/inline-assoc-type-20727-bounds.rs b/tests/rustdoc-html/assoc/inline-assoc-type-20727-bounds.rs similarity index 100% rename from tests/rustdoc/assoc/inline-assoc-type-20727-bounds.rs rename to tests/rustdoc-html/assoc/inline-assoc-type-20727-bounds.rs diff --git a/tests/rustdoc/assoc/normalize-assoc-item.rs b/tests/rustdoc-html/assoc/normalize-assoc-item.rs similarity index 100% rename from tests/rustdoc/assoc/normalize-assoc-item.rs rename to tests/rustdoc-html/assoc/normalize-assoc-item.rs diff --git a/tests/rustdoc/async/async-fn-opaque-item.rs b/tests/rustdoc-html/async/async-fn-opaque-item.rs similarity index 100% rename from tests/rustdoc/async/async-fn-opaque-item.rs rename to tests/rustdoc-html/async/async-fn-opaque-item.rs diff --git a/tests/rustdoc/async/async-fn.rs b/tests/rustdoc-html/async/async-fn.rs similarity index 100% rename from tests/rustdoc/async/async-fn.rs rename to tests/rustdoc-html/async/async-fn.rs diff --git a/tests/rustdoc/async/async-move-doctest.rs b/tests/rustdoc-html/async/async-move-doctest.rs similarity index 100% rename from tests/rustdoc/async/async-move-doctest.rs rename to tests/rustdoc-html/async/async-move-doctest.rs diff --git a/tests/rustdoc/async/async-trait-sig.rs b/tests/rustdoc-html/async/async-trait-sig.rs similarity index 100% rename from tests/rustdoc/async/async-trait-sig.rs rename to tests/rustdoc-html/async/async-trait-sig.rs diff --git a/tests/rustdoc/async/async-trait.rs b/tests/rustdoc-html/async/async-trait.rs similarity index 100% rename from tests/rustdoc/async/async-trait.rs rename to tests/rustdoc-html/async/async-trait.rs diff --git a/tests/rustdoc/async/auxiliary/async-trait-dep.rs b/tests/rustdoc-html/async/auxiliary/async-trait-dep.rs similarity index 100% rename from tests/rustdoc/async/auxiliary/async-trait-dep.rs rename to tests/rustdoc-html/async/auxiliary/async-trait-dep.rs diff --git a/tests/rustdoc/attributes-2021-edition.rs b/tests/rustdoc-html/attributes-2021-edition.rs similarity index 100% rename from tests/rustdoc/attributes-2021-edition.rs rename to tests/rustdoc-html/attributes-2021-edition.rs diff --git a/tests/rustdoc/attributes-inlining-108281.rs b/tests/rustdoc-html/attributes-inlining-108281.rs similarity index 100% rename from tests/rustdoc/attributes-inlining-108281.rs rename to tests/rustdoc-html/attributes-inlining-108281.rs diff --git a/tests/rustdoc/attributes-re-export-2021-edition.rs b/tests/rustdoc-html/attributes-re-export-2021-edition.rs similarity index 100% rename from tests/rustdoc/attributes-re-export-2021-edition.rs rename to tests/rustdoc-html/attributes-re-export-2021-edition.rs diff --git a/tests/rustdoc/attributes-re-export.rs b/tests/rustdoc-html/attributes-re-export.rs similarity index 100% rename from tests/rustdoc/attributes-re-export.rs rename to tests/rustdoc-html/attributes-re-export.rs diff --git a/tests/rustdoc/attributes.rs b/tests/rustdoc-html/attributes.rs similarity index 100% rename from tests/rustdoc/attributes.rs rename to tests/rustdoc-html/attributes.rs diff --git a/tests/rustdoc/auto/auto-impl-for-trait.rs b/tests/rustdoc-html/auto/auto-impl-for-trait.rs similarity index 100% rename from tests/rustdoc/auto/auto-impl-for-trait.rs rename to tests/rustdoc-html/auto/auto-impl-for-trait.rs diff --git a/tests/rustdoc/auto/auto-impl-primitive.rs b/tests/rustdoc-html/auto/auto-impl-primitive.rs similarity index 100% rename from tests/rustdoc/auto/auto-impl-primitive.rs rename to tests/rustdoc-html/auto/auto-impl-primitive.rs diff --git a/tests/rustdoc/auto/auto-trait-bounds-by-associated-type-50159.rs b/tests/rustdoc-html/auto/auto-trait-bounds-by-associated-type-50159.rs similarity index 100% rename from tests/rustdoc/auto/auto-trait-bounds-by-associated-type-50159.rs rename to tests/rustdoc-html/auto/auto-trait-bounds-by-associated-type-50159.rs diff --git a/tests/rustdoc/auto/auto-trait-bounds-inference-variables-54705.rs b/tests/rustdoc-html/auto/auto-trait-bounds-inference-variables-54705.rs similarity index 100% rename from tests/rustdoc/auto/auto-trait-bounds-inference-variables-54705.rs rename to tests/rustdoc-html/auto/auto-trait-bounds-inference-variables-54705.rs diff --git a/tests/rustdoc/auto/auto-trait-bounds-where-51236.rs b/tests/rustdoc-html/auto/auto-trait-bounds-where-51236.rs similarity index 100% rename from tests/rustdoc/auto/auto-trait-bounds-where-51236.rs rename to tests/rustdoc-html/auto/auto-trait-bounds-where-51236.rs diff --git a/tests/rustdoc/auto/auto-trait-negative-impl-55321.rs b/tests/rustdoc-html/auto/auto-trait-negative-impl-55321.rs similarity index 100% rename from tests/rustdoc/auto/auto-trait-negative-impl-55321.rs rename to tests/rustdoc-html/auto/auto-trait-negative-impl-55321.rs diff --git a/tests/rustdoc/auto/auto-trait-not-send.rs b/tests/rustdoc-html/auto/auto-trait-not-send.rs similarity index 100% rename from tests/rustdoc/auto/auto-trait-not-send.rs rename to tests/rustdoc-html/auto/auto-trait-not-send.rs diff --git a/tests/rustdoc/auto/auto-traits.rs b/tests/rustdoc-html/auto/auto-traits.rs similarity index 100% rename from tests/rustdoc/auto/auto-traits.rs rename to tests/rustdoc-html/auto/auto-traits.rs diff --git a/tests/rustdoc/auto/auto_aliases.rs b/tests/rustdoc-html/auto/auto_aliases.rs similarity index 100% rename from tests/rustdoc/auto/auto_aliases.rs rename to tests/rustdoc-html/auto/auto_aliases.rs diff --git a/tests/rustdoc/auto/auxiliary/auto-traits.rs b/tests/rustdoc-html/auto/auxiliary/auto-traits.rs similarity index 100% rename from tests/rustdoc/auto/auxiliary/auto-traits.rs rename to tests/rustdoc-html/auto/auxiliary/auto-traits.rs diff --git a/tests/rustdoc/auxiliary/all-item-types.rs b/tests/rustdoc-html/auxiliary/all-item-types.rs similarity index 100% rename from tests/rustdoc/auxiliary/all-item-types.rs rename to tests/rustdoc-html/auxiliary/all-item-types.rs diff --git a/tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs b/tests/rustdoc-html/auxiliary/cross_crate_generic_typedef.rs similarity index 100% rename from tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs rename to tests/rustdoc-html/auxiliary/cross_crate_generic_typedef.rs diff --git a/tests/rustdoc/auxiliary/elided-lifetime.rs b/tests/rustdoc-html/auxiliary/elided-lifetime.rs similarity index 100% rename from tests/rustdoc/auxiliary/elided-lifetime.rs rename to tests/rustdoc-html/auxiliary/elided-lifetime.rs diff --git a/tests/rustdoc/auxiliary/empty.rs b/tests/rustdoc-html/auxiliary/empty.rs similarity index 100% rename from tests/rustdoc/auxiliary/empty.rs rename to tests/rustdoc-html/auxiliary/empty.rs diff --git a/tests/rustdoc/auxiliary/enum-primitive.rs b/tests/rustdoc-html/auxiliary/enum-primitive.rs similarity index 100% rename from tests/rustdoc/auxiliary/enum-primitive.rs rename to tests/rustdoc-html/auxiliary/enum-primitive.rs diff --git a/tests/rustdoc/auxiliary/ext-anon-fn-params.rs b/tests/rustdoc-html/auxiliary/ext-anon-fn-params.rs similarity index 100% rename from tests/rustdoc/auxiliary/ext-anon-fn-params.rs rename to tests/rustdoc-html/auxiliary/ext-anon-fn-params.rs diff --git a/tests/rustdoc/auxiliary/ext-repr.rs b/tests/rustdoc-html/auxiliary/ext-repr.rs similarity index 100% rename from tests/rustdoc/auxiliary/ext-repr.rs rename to tests/rustdoc-html/auxiliary/ext-repr.rs diff --git a/tests/rustdoc/auxiliary/ext-trait-aliases.rs b/tests/rustdoc-html/auxiliary/ext-trait-aliases.rs similarity index 100% rename from tests/rustdoc/auxiliary/ext-trait-aliases.rs rename to tests/rustdoc-html/auxiliary/ext-trait-aliases.rs diff --git a/tests/rustdoc/auxiliary/inline-default-methods.rs b/tests/rustdoc-html/auxiliary/inline-default-methods.rs similarity index 100% rename from tests/rustdoc/auxiliary/inline-default-methods.rs rename to tests/rustdoc-html/auxiliary/inline-default-methods.rs diff --git a/tests/rustdoc/auxiliary/issue-106421-force-unstable.rs b/tests/rustdoc-html/auxiliary/issue-106421-force-unstable.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-106421-force-unstable.rs rename to tests/rustdoc-html/auxiliary/issue-106421-force-unstable.rs diff --git a/tests/rustdoc/auxiliary/issue-13698.rs b/tests/rustdoc-html/auxiliary/issue-13698.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-13698.rs rename to tests/rustdoc-html/auxiliary/issue-13698.rs diff --git a/tests/rustdoc/auxiliary/issue-19190-3.rs b/tests/rustdoc-html/auxiliary/issue-19190-3.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-19190-3.rs rename to tests/rustdoc-html/auxiliary/issue-19190-3.rs diff --git a/tests/rustdoc/auxiliary/issue-61592.rs b/tests/rustdoc-html/auxiliary/issue-61592.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-61592.rs rename to tests/rustdoc-html/auxiliary/issue-61592.rs diff --git a/tests/rustdoc/auxiliary/issue-99221-aux.rs b/tests/rustdoc-html/auxiliary/issue-99221-aux.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-99221-aux.rs rename to tests/rustdoc-html/auxiliary/issue-99221-aux.rs diff --git a/tests/rustdoc/auxiliary/issue-99734-aux.rs b/tests/rustdoc-html/auxiliary/issue-99734-aux.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-99734-aux.rs rename to tests/rustdoc-html/auxiliary/issue-99734-aux.rs diff --git a/tests/rustdoc/auxiliary/jump-to-def-res-err-handling-aux.rs b/tests/rustdoc-html/auxiliary/jump-to-def-res-err-handling-aux.rs similarity index 100% rename from tests/rustdoc/auxiliary/jump-to-def-res-err-handling-aux.rs rename to tests/rustdoc-html/auxiliary/jump-to-def-res-err-handling-aux.rs diff --git a/tests/rustdoc/auxiliary/masked.rs b/tests/rustdoc-html/auxiliary/masked.rs similarity index 100% rename from tests/rustdoc/auxiliary/masked.rs rename to tests/rustdoc-html/auxiliary/masked.rs diff --git a/tests/rustdoc/auxiliary/mod-stackoverflow.rs b/tests/rustdoc-html/auxiliary/mod-stackoverflow.rs similarity index 100% rename from tests/rustdoc/auxiliary/mod-stackoverflow.rs rename to tests/rustdoc-html/auxiliary/mod-stackoverflow.rs diff --git a/tests/rustdoc/auxiliary/reexp-stripped.rs b/tests/rustdoc-html/auxiliary/reexp-stripped.rs similarity index 100% rename from tests/rustdoc/auxiliary/reexp-stripped.rs rename to tests/rustdoc-html/auxiliary/reexp-stripped.rs diff --git a/tests/rustdoc/auxiliary/remapped-paths.rs b/tests/rustdoc-html/auxiliary/remapped-paths.rs similarity index 100% rename from tests/rustdoc/auxiliary/remapped-paths.rs rename to tests/rustdoc-html/auxiliary/remapped-paths.rs diff --git a/tests/rustdoc/auxiliary/rustdoc-ffi.rs b/tests/rustdoc-html/auxiliary/rustdoc-ffi.rs similarity index 100% rename from tests/rustdoc/auxiliary/rustdoc-ffi.rs rename to tests/rustdoc-html/auxiliary/rustdoc-ffi.rs diff --git a/tests/rustdoc/auxiliary/trait-visibility.rs b/tests/rustdoc-html/auxiliary/trait-visibility.rs similarity index 100% rename from tests/rustdoc/auxiliary/trait-visibility.rs rename to tests/rustdoc-html/auxiliary/trait-visibility.rs diff --git a/tests/rustdoc/auxiliary/unit-return.rs b/tests/rustdoc-html/auxiliary/unit-return.rs similarity index 100% rename from tests/rustdoc/auxiliary/unit-return.rs rename to tests/rustdoc-html/auxiliary/unit-return.rs diff --git a/tests/rustdoc/auxiliary/unsafe-binder-dep.rs b/tests/rustdoc-html/auxiliary/unsafe-binder-dep.rs similarity index 100% rename from tests/rustdoc/auxiliary/unsafe-binder-dep.rs rename to tests/rustdoc-html/auxiliary/unsafe-binder-dep.rs diff --git a/tests/rustdoc/auxiliary/unstable-trait.rs b/tests/rustdoc-html/auxiliary/unstable-trait.rs similarity index 100% rename from tests/rustdoc/auxiliary/unstable-trait.rs rename to tests/rustdoc-html/auxiliary/unstable-trait.rs diff --git a/tests/rustdoc/bad-codeblock-syntax.rs b/tests/rustdoc-html/bad-codeblock-syntax.rs similarity index 100% rename from tests/rustdoc/bad-codeblock-syntax.rs rename to tests/rustdoc-html/bad-codeblock-syntax.rs diff --git a/tests/rustdoc/blank-line-in-doc-block-47197.rs b/tests/rustdoc-html/blank-line-in-doc-block-47197.rs similarity index 100% rename from tests/rustdoc/blank-line-in-doc-block-47197.rs rename to tests/rustdoc-html/blank-line-in-doc-block-47197.rs diff --git a/tests/rustdoc/bold-tag-101743.rs b/tests/rustdoc-html/bold-tag-101743.rs similarity index 100% rename from tests/rustdoc/bold-tag-101743.rs rename to tests/rustdoc-html/bold-tag-101743.rs diff --git a/tests/rustdoc/bounds.rs b/tests/rustdoc-html/bounds.rs similarity index 100% rename from tests/rustdoc/bounds.rs rename to tests/rustdoc-html/bounds.rs diff --git a/tests/rustdoc/cap-lints.rs b/tests/rustdoc-html/cap-lints.rs similarity index 100% rename from tests/rustdoc/cap-lints.rs rename to tests/rustdoc-html/cap-lints.rs diff --git a/tests/rustdoc/cfg-bool.rs b/tests/rustdoc-html/cfg-bool.rs similarity index 100% rename from tests/rustdoc/cfg-bool.rs rename to tests/rustdoc-html/cfg-bool.rs diff --git a/tests/rustdoc/cfg-doctest.rs b/tests/rustdoc-html/cfg-doctest.rs similarity index 100% rename from tests/rustdoc/cfg-doctest.rs rename to tests/rustdoc-html/cfg-doctest.rs diff --git a/tests/rustdoc/check-styled-link.rs b/tests/rustdoc-html/check-styled-link.rs similarity index 100% rename from tests/rustdoc/check-styled-link.rs rename to tests/rustdoc-html/check-styled-link.rs diff --git a/tests/rustdoc/check.rs b/tests/rustdoc-html/check.rs similarity index 100% rename from tests/rustdoc/check.rs rename to tests/rustdoc-html/check.rs diff --git a/tests/rustdoc/codeblock-title.rs b/tests/rustdoc-html/codeblock-title.rs similarity index 100% rename from tests/rustdoc/codeblock-title.rs rename to tests/rustdoc-html/codeblock-title.rs diff --git a/tests/rustdoc/comment-in-doctest.rs b/tests/rustdoc-html/comment-in-doctest.rs similarity index 100% rename from tests/rustdoc/comment-in-doctest.rs rename to tests/rustdoc-html/comment-in-doctest.rs diff --git a/tests/rustdoc/const-fn-76501.rs b/tests/rustdoc-html/const-fn-76501.rs similarity index 100% rename from tests/rustdoc/const-fn-76501.rs rename to tests/rustdoc-html/const-fn-76501.rs diff --git a/tests/rustdoc/const-fn-effects.rs b/tests/rustdoc-html/const-fn-effects.rs similarity index 100% rename from tests/rustdoc/const-fn-effects.rs rename to tests/rustdoc-html/const-fn-effects.rs diff --git a/tests/rustdoc/const-fn.rs b/tests/rustdoc-html/const-fn.rs similarity index 100% rename from tests/rustdoc/const-fn.rs rename to tests/rustdoc-html/const-fn.rs diff --git a/tests/rustdoc/const-generics/add-impl.rs b/tests/rustdoc-html/const-generics/add-impl.rs similarity index 100% rename from tests/rustdoc/const-generics/add-impl.rs rename to tests/rustdoc-html/const-generics/add-impl.rs diff --git a/tests/rustdoc/const-generics/auxiliary/extern_crate.rs b/tests/rustdoc-html/const-generics/auxiliary/extern_crate.rs similarity index 100% rename from tests/rustdoc/const-generics/auxiliary/extern_crate.rs rename to tests/rustdoc-html/const-generics/auxiliary/extern_crate.rs diff --git a/tests/rustdoc/const-generics/const-generic-defaults.rs b/tests/rustdoc-html/const-generics/const-generic-defaults.rs similarity index 100% rename from tests/rustdoc/const-generics/const-generic-defaults.rs rename to tests/rustdoc-html/const-generics/const-generic-defaults.rs diff --git a/tests/rustdoc/const-generics/const-generic-slice.rs b/tests/rustdoc-html/const-generics/const-generic-slice.rs similarity index 100% rename from tests/rustdoc/const-generics/const-generic-slice.rs rename to tests/rustdoc-html/const-generics/const-generic-slice.rs diff --git a/tests/rustdoc/const-generics/const-generics-docs.rs b/tests/rustdoc-html/const-generics/const-generics-docs.rs similarity index 100% rename from tests/rustdoc/const-generics/const-generics-docs.rs rename to tests/rustdoc-html/const-generics/const-generics-docs.rs diff --git a/tests/rustdoc/const-generics/const-impl.rs b/tests/rustdoc-html/const-generics/const-impl.rs similarity index 100% rename from tests/rustdoc/const-generics/const-impl.rs rename to tests/rustdoc-html/const-generics/const-impl.rs diff --git a/tests/rustdoc/const-generics/const-param-type-references-generics.rs b/tests/rustdoc-html/const-generics/const-param-type-references-generics.rs similarity index 100% rename from tests/rustdoc/const-generics/const-param-type-references-generics.rs rename to tests/rustdoc-html/const-generics/const-param-type-references-generics.rs diff --git a/tests/rustdoc/const-generics/generic_const_exprs.rs b/tests/rustdoc-html/const-generics/generic_const_exprs.rs similarity index 100% rename from tests/rustdoc/const-generics/generic_const_exprs.rs rename to tests/rustdoc-html/const-generics/generic_const_exprs.rs diff --git a/tests/rustdoc/const-generics/lazy_normalization_consts/const-equate-pred.rs b/tests/rustdoc-html/const-generics/lazy_normalization_consts/const-equate-pred.rs similarity index 100% rename from tests/rustdoc/const-generics/lazy_normalization_consts/const-equate-pred.rs rename to tests/rustdoc-html/const-generics/lazy_normalization_consts/const-equate-pred.rs diff --git a/tests/rustdoc/const-generics/type-alias.rs b/tests/rustdoc-html/const-generics/type-alias.rs similarity index 100% rename from tests/rustdoc/const-generics/type-alias.rs rename to tests/rustdoc-html/const-generics/type-alias.rs diff --git a/tests/rustdoc/const-intrinsic.rs b/tests/rustdoc-html/const-intrinsic.rs similarity index 100% rename from tests/rustdoc/const-intrinsic.rs rename to tests/rustdoc-html/const-intrinsic.rs diff --git a/tests/rustdoc/constant/assoc-consts-underscore.rs b/tests/rustdoc-html/constant/assoc-consts-underscore.rs similarity index 100% rename from tests/rustdoc/constant/assoc-consts-underscore.rs rename to tests/rustdoc-html/constant/assoc-consts-underscore.rs diff --git a/tests/rustdoc/constant/assoc-consts-version.rs b/tests/rustdoc-html/constant/assoc-consts-version.rs similarity index 100% rename from tests/rustdoc/constant/assoc-consts-version.rs rename to tests/rustdoc-html/constant/assoc-consts-version.rs diff --git a/tests/rustdoc/constant/assoc-consts.rs b/tests/rustdoc-html/constant/assoc-consts.rs similarity index 100% rename from tests/rustdoc/constant/assoc-consts.rs rename to tests/rustdoc-html/constant/assoc-consts.rs diff --git a/tests/rustdoc/constant/associated-consts.rs b/tests/rustdoc-html/constant/associated-consts.rs similarity index 100% rename from tests/rustdoc/constant/associated-consts.rs rename to tests/rustdoc-html/constant/associated-consts.rs diff --git a/tests/rustdoc/constant/const-display.rs b/tests/rustdoc-html/constant/const-display.rs similarity index 100% rename from tests/rustdoc/constant/const-display.rs rename to tests/rustdoc-html/constant/const-display.rs diff --git a/tests/rustdoc/constant/const-doc.rs b/tests/rustdoc-html/constant/const-doc.rs similarity index 100% rename from tests/rustdoc/constant/const-doc.rs rename to tests/rustdoc-html/constant/const-doc.rs diff --git a/tests/rustdoc/constant/const-effect-param.rs b/tests/rustdoc-html/constant/const-effect-param.rs similarity index 100% rename from tests/rustdoc/constant/const-effect-param.rs rename to tests/rustdoc-html/constant/const-effect-param.rs diff --git a/tests/rustdoc/constant/const-trait-and-impl-methods.rs b/tests/rustdoc-html/constant/const-trait-and-impl-methods.rs similarity index 100% rename from tests/rustdoc/constant/const-trait-and-impl-methods.rs rename to tests/rustdoc-html/constant/const-trait-and-impl-methods.rs diff --git a/tests/rustdoc/constant/const-underscore.rs b/tests/rustdoc-html/constant/const-underscore.rs similarity index 100% rename from tests/rustdoc/constant/const-underscore.rs rename to tests/rustdoc-html/constant/const-underscore.rs diff --git a/tests/rustdoc/constant/const-value-display.rs b/tests/rustdoc-html/constant/const-value-display.rs similarity index 100% rename from tests/rustdoc/constant/const-value-display.rs rename to tests/rustdoc-html/constant/const-value-display.rs diff --git a/tests/rustdoc/constant/const.rs b/tests/rustdoc-html/constant/const.rs similarity index 100% rename from tests/rustdoc/constant/const.rs rename to tests/rustdoc-html/constant/const.rs diff --git a/tests/rustdoc/constant/document-item-with-associated-const-in-where-clause.rs b/tests/rustdoc-html/constant/document-item-with-associated-const-in-where-clause.rs similarity index 100% rename from tests/rustdoc/constant/document-item-with-associated-const-in-where-clause.rs rename to tests/rustdoc-html/constant/document-item-with-associated-const-in-where-clause.rs diff --git a/tests/rustdoc/constant/generic-const-items.rs b/tests/rustdoc-html/constant/generic-const-items.rs similarity index 100% rename from tests/rustdoc/constant/generic-const-items.rs rename to tests/rustdoc-html/constant/generic-const-items.rs diff --git a/tests/rustdoc/constant/generic_const_exprs.rs b/tests/rustdoc-html/constant/generic_const_exprs.rs similarity index 100% rename from tests/rustdoc/constant/generic_const_exprs.rs rename to tests/rustdoc-html/constant/generic_const_exprs.rs diff --git a/tests/rustdoc/constant/glob-shadowing-const.rs b/tests/rustdoc-html/constant/glob-shadowing-const.rs similarity index 100% rename from tests/rustdoc/constant/glob-shadowing-const.rs rename to tests/rustdoc-html/constant/glob-shadowing-const.rs diff --git a/tests/rustdoc/constant/hide-complex-unevaluated-const-arguments.rs b/tests/rustdoc-html/constant/hide-complex-unevaluated-const-arguments.rs similarity index 100% rename from tests/rustdoc/constant/hide-complex-unevaluated-const-arguments.rs rename to tests/rustdoc-html/constant/hide-complex-unevaluated-const-arguments.rs diff --git a/tests/rustdoc/constant/hide-complex-unevaluated-consts.rs b/tests/rustdoc-html/constant/hide-complex-unevaluated-consts.rs similarity index 100% rename from tests/rustdoc/constant/hide-complex-unevaluated-consts.rs rename to tests/rustdoc-html/constant/hide-complex-unevaluated-consts.rs diff --git a/tests/rustdoc/constant/ice-associated-const-equality-105952.rs b/tests/rustdoc-html/constant/ice-associated-const-equality-105952.rs similarity index 100% rename from tests/rustdoc/constant/ice-associated-const-equality-105952.rs rename to tests/rustdoc-html/constant/ice-associated-const-equality-105952.rs diff --git a/tests/rustdoc/constant/legacy-const-generic.rs b/tests/rustdoc-html/constant/legacy-const-generic.rs similarity index 100% rename from tests/rustdoc/constant/legacy-const-generic.rs rename to tests/rustdoc-html/constant/legacy-const-generic.rs diff --git a/tests/rustdoc/constant/link-assoc-const.rs b/tests/rustdoc-html/constant/link-assoc-const.rs similarity index 100% rename from tests/rustdoc/constant/link-assoc-const.rs rename to tests/rustdoc-html/constant/link-assoc-const.rs diff --git a/tests/rustdoc/constant/redirect-const.rs b/tests/rustdoc-html/constant/redirect-const.rs similarity index 100% rename from tests/rustdoc/constant/redirect-const.rs rename to tests/rustdoc-html/constant/redirect-const.rs diff --git a/tests/rustdoc/constant/rfc-2632-const-trait-impl.rs b/tests/rustdoc-html/constant/rfc-2632-const-trait-impl.rs similarity index 100% rename from tests/rustdoc/constant/rfc-2632-const-trait-impl.rs rename to tests/rustdoc-html/constant/rfc-2632-const-trait-impl.rs diff --git a/tests/rustdoc/constant/show-const-contents.rs b/tests/rustdoc-html/constant/show-const-contents.rs similarity index 100% rename from tests/rustdoc/constant/show-const-contents.rs rename to tests/rustdoc-html/constant/show-const-contents.rs diff --git a/tests/rustdoc/constructor-imports.rs b/tests/rustdoc-html/constructor-imports.rs similarity index 100% rename from tests/rustdoc/constructor-imports.rs rename to tests/rustdoc-html/constructor-imports.rs diff --git a/tests/rustdoc/crate-doc-hidden-109695.rs b/tests/rustdoc-html/crate-doc-hidden-109695.rs similarity index 100% rename from tests/rustdoc/crate-doc-hidden-109695.rs rename to tests/rustdoc-html/crate-doc-hidden-109695.rs diff --git a/tests/rustdoc/crate-version-escape.rs b/tests/rustdoc-html/crate-version-escape.rs similarity index 100% rename from tests/rustdoc/crate-version-escape.rs rename to tests/rustdoc-html/crate-version-escape.rs diff --git a/tests/rustdoc/crate-version-extra.rs b/tests/rustdoc-html/crate-version-extra.rs similarity index 100% rename from tests/rustdoc/crate-version-extra.rs rename to tests/rustdoc-html/crate-version-extra.rs diff --git a/tests/rustdoc/crate-version.rs b/tests/rustdoc-html/crate-version.rs similarity index 100% rename from tests/rustdoc/crate-version.rs rename to tests/rustdoc-html/crate-version.rs diff --git a/tests/rustdoc/cross-crate-info/cargo-transitive-no-index/auxiliary/q.rs b/tests/rustdoc-html/cross-crate-info/cargo-transitive-no-index/auxiliary/q.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/cargo-transitive-no-index/auxiliary/q.rs rename to tests/rustdoc-html/cross-crate-info/cargo-transitive-no-index/auxiliary/q.rs diff --git a/tests/rustdoc/cross-crate-info/cargo-transitive-no-index/auxiliary/t.rs b/tests/rustdoc-html/cross-crate-info/cargo-transitive-no-index/auxiliary/t.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/cargo-transitive-no-index/auxiliary/t.rs rename to tests/rustdoc-html/cross-crate-info/cargo-transitive-no-index/auxiliary/t.rs diff --git a/tests/rustdoc/cross-crate-info/cargo-transitive-no-index/s.rs b/tests/rustdoc-html/cross-crate-info/cargo-transitive-no-index/s.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/cargo-transitive-no-index/s.rs rename to tests/rustdoc-html/cross-crate-info/cargo-transitive-no-index/s.rs diff --git a/tests/rustdoc/cross-crate-info/cargo-transitive/auxiliary/q.rs b/tests/rustdoc-html/cross-crate-info/cargo-transitive/auxiliary/q.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/cargo-transitive/auxiliary/q.rs rename to tests/rustdoc-html/cross-crate-info/cargo-transitive/auxiliary/q.rs diff --git a/tests/rustdoc/cross-crate-info/cargo-transitive/auxiliary/t.rs b/tests/rustdoc-html/cross-crate-info/cargo-transitive/auxiliary/t.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/cargo-transitive/auxiliary/t.rs rename to tests/rustdoc-html/cross-crate-info/cargo-transitive/auxiliary/t.rs diff --git a/tests/rustdoc/cross-crate-info/cargo-transitive/s.rs b/tests/rustdoc-html/cross-crate-info/cargo-transitive/s.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/cargo-transitive/s.rs rename to tests/rustdoc-html/cross-crate-info/cargo-transitive/s.rs diff --git a/tests/rustdoc/cross-crate-info/cargo-two-no-index/auxiliary/f.rs b/tests/rustdoc-html/cross-crate-info/cargo-two-no-index/auxiliary/f.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/cargo-two-no-index/auxiliary/f.rs rename to tests/rustdoc-html/cross-crate-info/cargo-two-no-index/auxiliary/f.rs diff --git a/tests/rustdoc/cross-crate-info/cargo-two-no-index/e.rs b/tests/rustdoc-html/cross-crate-info/cargo-two-no-index/e.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/cargo-two-no-index/e.rs rename to tests/rustdoc-html/cross-crate-info/cargo-two-no-index/e.rs diff --git a/tests/rustdoc/cross-crate-info/cargo-two/auxiliary/f.rs b/tests/rustdoc-html/cross-crate-info/cargo-two/auxiliary/f.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/cargo-two/auxiliary/f.rs rename to tests/rustdoc-html/cross-crate-info/cargo-two/auxiliary/f.rs diff --git a/tests/rustdoc/cross-crate-info/cargo-two/e.rs b/tests/rustdoc-html/cross-crate-info/cargo-two/e.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/cargo-two/e.rs rename to tests/rustdoc-html/cross-crate-info/cargo-two/e.rs diff --git a/tests/rustdoc/cross-crate-info/index-on-last/auxiliary/f.rs b/tests/rustdoc-html/cross-crate-info/index-on-last/auxiliary/f.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/index-on-last/auxiliary/f.rs rename to tests/rustdoc-html/cross-crate-info/index-on-last/auxiliary/f.rs diff --git a/tests/rustdoc/cross-crate-info/index-on-last/e.rs b/tests/rustdoc-html/cross-crate-info/index-on-last/e.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/index-on-last/e.rs rename to tests/rustdoc-html/cross-crate-info/index-on-last/e.rs diff --git a/tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/q.rs b/tests/rustdoc-html/cross-crate-info/kitchen-sink/auxiliary/q.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/q.rs rename to tests/rustdoc-html/cross-crate-info/kitchen-sink/auxiliary/q.rs diff --git a/tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/r.rs b/tests/rustdoc-html/cross-crate-info/kitchen-sink/auxiliary/r.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/r.rs rename to tests/rustdoc-html/cross-crate-info/kitchen-sink/auxiliary/r.rs diff --git a/tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/s.rs b/tests/rustdoc-html/cross-crate-info/kitchen-sink/auxiliary/s.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/s.rs rename to tests/rustdoc-html/cross-crate-info/kitchen-sink/auxiliary/s.rs diff --git a/tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/t.rs b/tests/rustdoc-html/cross-crate-info/kitchen-sink/auxiliary/t.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/t.rs rename to tests/rustdoc-html/cross-crate-info/kitchen-sink/auxiliary/t.rs diff --git a/tests/rustdoc/cross-crate-info/kitchen-sink/i.rs b/tests/rustdoc-html/cross-crate-info/kitchen-sink/i.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/kitchen-sink/i.rs rename to tests/rustdoc-html/cross-crate-info/kitchen-sink/i.rs diff --git a/tests/rustdoc/cross-crate-info/single-crate-baseline/q.rs b/tests/rustdoc-html/cross-crate-info/single-crate-baseline/q.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/single-crate-baseline/q.rs rename to tests/rustdoc-html/cross-crate-info/single-crate-baseline/q.rs diff --git a/tests/rustdoc/cross-crate-info/single-crate-no-index/q.rs b/tests/rustdoc-html/cross-crate-info/single-crate-no-index/q.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/single-crate-no-index/q.rs rename to tests/rustdoc-html/cross-crate-info/single-crate-no-index/q.rs diff --git a/tests/rustdoc/cross-crate-info/transitive/auxiliary/q.rs b/tests/rustdoc-html/cross-crate-info/transitive/auxiliary/q.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/transitive/auxiliary/q.rs rename to tests/rustdoc-html/cross-crate-info/transitive/auxiliary/q.rs diff --git a/tests/rustdoc/cross-crate-info/transitive/auxiliary/t.rs b/tests/rustdoc-html/cross-crate-info/transitive/auxiliary/t.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/transitive/auxiliary/t.rs rename to tests/rustdoc-html/cross-crate-info/transitive/auxiliary/t.rs diff --git a/tests/rustdoc/cross-crate-info/transitive/s.rs b/tests/rustdoc-html/cross-crate-info/transitive/s.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/transitive/s.rs rename to tests/rustdoc-html/cross-crate-info/transitive/s.rs diff --git a/tests/rustdoc/cross-crate-info/two/auxiliary/f.rs b/tests/rustdoc-html/cross-crate-info/two/auxiliary/f.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/two/auxiliary/f.rs rename to tests/rustdoc-html/cross-crate-info/two/auxiliary/f.rs diff --git a/tests/rustdoc/cross-crate-info/two/e.rs b/tests/rustdoc-html/cross-crate-info/two/e.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/two/e.rs rename to tests/rustdoc-html/cross-crate-info/two/e.rs diff --git a/tests/rustdoc/cross-crate-info/working-dir-examples/q.rs b/tests/rustdoc-html/cross-crate-info/working-dir-examples/q.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/working-dir-examples/q.rs rename to tests/rustdoc-html/cross-crate-info/working-dir-examples/q.rs diff --git a/tests/rustdoc/cross-crate-info/write-docs-somewhere-else/auxiliary/f.rs b/tests/rustdoc-html/cross-crate-info/write-docs-somewhere-else/auxiliary/f.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/write-docs-somewhere-else/auxiliary/f.rs rename to tests/rustdoc-html/cross-crate-info/write-docs-somewhere-else/auxiliary/f.rs diff --git a/tests/rustdoc/cross-crate-info/write-docs-somewhere-else/e.rs b/tests/rustdoc-html/cross-crate-info/write-docs-somewhere-else/e.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/write-docs-somewhere-else/e.rs rename to tests/rustdoc-html/cross-crate-info/write-docs-somewhere-else/e.rs diff --git a/tests/rustdoc/cross-crate-links.rs b/tests/rustdoc-html/cross-crate-links.rs similarity index 100% rename from tests/rustdoc/cross-crate-links.rs rename to tests/rustdoc-html/cross-crate-links.rs diff --git a/tests/rustdoc/custom_code_classes.rs b/tests/rustdoc-html/custom_code_classes.rs similarity index 100% rename from tests/rustdoc/custom_code_classes.rs rename to tests/rustdoc-html/custom_code_classes.rs diff --git a/tests/rustdoc/decl-line-wrapping-empty-arg-list.decl.html b/tests/rustdoc-html/decl-line-wrapping-empty-arg-list.decl.html similarity index 100% rename from tests/rustdoc/decl-line-wrapping-empty-arg-list.decl.html rename to tests/rustdoc-html/decl-line-wrapping-empty-arg-list.decl.html diff --git a/tests/rustdoc/decl-line-wrapping-empty-arg-list.rs b/tests/rustdoc-html/decl-line-wrapping-empty-arg-list.rs similarity index 100% rename from tests/rustdoc/decl-line-wrapping-empty-arg-list.rs rename to tests/rustdoc-html/decl-line-wrapping-empty-arg-list.rs diff --git a/tests/rustdoc/decl-trailing-whitespace.declaration.html b/tests/rustdoc-html/decl-trailing-whitespace.declaration.html similarity index 100% rename from tests/rustdoc/decl-trailing-whitespace.declaration.html rename to tests/rustdoc-html/decl-trailing-whitespace.declaration.html diff --git a/tests/rustdoc/decl-trailing-whitespace.rs b/tests/rustdoc-html/decl-trailing-whitespace.rs similarity index 100% rename from tests/rustdoc/decl-trailing-whitespace.rs rename to tests/rustdoc-html/decl-trailing-whitespace.rs diff --git a/tests/rustdoc/deep-structures.rs b/tests/rustdoc-html/deep-structures.rs similarity index 100% rename from tests/rustdoc/deep-structures.rs rename to tests/rustdoc-html/deep-structures.rs diff --git a/tests/rustdoc/default-theme.rs b/tests/rustdoc-html/default-theme.rs similarity index 100% rename from tests/rustdoc/default-theme.rs rename to tests/rustdoc-html/default-theme.rs diff --git a/tests/rustdoc/default-trait-method-link.rs b/tests/rustdoc-html/default-trait-method-link.rs similarity index 100% rename from tests/rustdoc/default-trait-method-link.rs rename to tests/rustdoc-html/default-trait-method-link.rs diff --git a/tests/rustdoc/default-trait-method.rs b/tests/rustdoc-html/default-trait-method.rs similarity index 100% rename from tests/rustdoc/default-trait-method.rs rename to tests/rustdoc-html/default-trait-method.rs diff --git a/tests/rustdoc/demo-allocator-54478.rs b/tests/rustdoc-html/demo-allocator-54478.rs similarity index 100% rename from tests/rustdoc/demo-allocator-54478.rs rename to tests/rustdoc-html/demo-allocator-54478.rs diff --git a/tests/rustdoc/deprecated-future-staged-api.rs b/tests/rustdoc-html/deprecated-future-staged-api.rs similarity index 100% rename from tests/rustdoc/deprecated-future-staged-api.rs rename to tests/rustdoc-html/deprecated-future-staged-api.rs diff --git a/tests/rustdoc/deprecated-future.rs b/tests/rustdoc-html/deprecated-future.rs similarity index 100% rename from tests/rustdoc/deprecated-future.rs rename to tests/rustdoc-html/deprecated-future.rs diff --git a/tests/rustdoc/deprecated.rs b/tests/rustdoc-html/deprecated.rs similarity index 100% rename from tests/rustdoc/deprecated.rs rename to tests/rustdoc-html/deprecated.rs diff --git a/tests/rustdoc/deref-methods-19190-foreign-type.rs b/tests/rustdoc-html/deref-methods-19190-foreign-type.rs similarity index 100% rename from tests/rustdoc/deref-methods-19190-foreign-type.rs rename to tests/rustdoc-html/deref-methods-19190-foreign-type.rs diff --git a/tests/rustdoc/deref-methods-19190-inline.rs b/tests/rustdoc-html/deref-methods-19190-inline.rs similarity index 100% rename from tests/rustdoc/deref-methods-19190-inline.rs rename to tests/rustdoc-html/deref-methods-19190-inline.rs diff --git a/tests/rustdoc/deref-methods-19190.rs b/tests/rustdoc-html/deref-methods-19190.rs similarity index 100% rename from tests/rustdoc/deref-methods-19190.rs rename to tests/rustdoc-html/deref-methods-19190.rs diff --git a/tests/rustdoc/deref-mut-35169-2.rs b/tests/rustdoc-html/deref-mut-35169-2.rs similarity index 100% rename from tests/rustdoc/deref-mut-35169-2.rs rename to tests/rustdoc-html/deref-mut-35169-2.rs diff --git a/tests/rustdoc/deref-mut-35169.rs b/tests/rustdoc-html/deref-mut-35169.rs similarity index 100% rename from tests/rustdoc/deref-mut-35169.rs rename to tests/rustdoc-html/deref-mut-35169.rs diff --git a/tests/rustdoc/deref/deref-const-fn.rs b/tests/rustdoc-html/deref/deref-const-fn.rs similarity index 100% rename from tests/rustdoc/deref/deref-const-fn.rs rename to tests/rustdoc-html/deref/deref-const-fn.rs diff --git a/tests/rustdoc/deref/deref-methods-24686-target.rs b/tests/rustdoc-html/deref/deref-methods-24686-target.rs similarity index 100% rename from tests/rustdoc/deref/deref-methods-24686-target.rs rename to tests/rustdoc-html/deref/deref-methods-24686-target.rs diff --git a/tests/rustdoc/deref/deref-multiple-impl-blocks.rs b/tests/rustdoc-html/deref/deref-multiple-impl-blocks.rs similarity index 100% rename from tests/rustdoc/deref/deref-multiple-impl-blocks.rs rename to tests/rustdoc-html/deref/deref-multiple-impl-blocks.rs diff --git a/tests/rustdoc/deref/deref-mut-methods.rs b/tests/rustdoc-html/deref/deref-mut-methods.rs similarity index 100% rename from tests/rustdoc/deref/deref-mut-methods.rs rename to tests/rustdoc-html/deref/deref-mut-methods.rs diff --git a/tests/rustdoc/deref/deref-recursive-pathbuf.rs b/tests/rustdoc-html/deref/deref-recursive-pathbuf.rs similarity index 100% rename from tests/rustdoc/deref/deref-recursive-pathbuf.rs rename to tests/rustdoc-html/deref/deref-recursive-pathbuf.rs diff --git a/tests/rustdoc/deref/deref-recursive.rs b/tests/rustdoc-html/deref/deref-recursive.rs similarity index 100% rename from tests/rustdoc/deref/deref-recursive.rs rename to tests/rustdoc-html/deref/deref-recursive.rs diff --git a/tests/rustdoc/deref/deref-slice-core.rs b/tests/rustdoc-html/deref/deref-slice-core.rs similarity index 100% rename from tests/rustdoc/deref/deref-slice-core.rs rename to tests/rustdoc-html/deref/deref-slice-core.rs diff --git a/tests/rustdoc/deref/deref-to-primitive.rs b/tests/rustdoc-html/deref/deref-to-primitive.rs similarity index 100% rename from tests/rustdoc/deref/deref-to-primitive.rs rename to tests/rustdoc-html/deref/deref-to-primitive.rs diff --git a/tests/rustdoc/deref/deref-typedef.rs b/tests/rustdoc-html/deref/deref-typedef.rs similarity index 100% rename from tests/rustdoc/deref/deref-typedef.rs rename to tests/rustdoc-html/deref/deref-typedef.rs diff --git a/tests/rustdoc/deref/escape-deref-methods.rs b/tests/rustdoc-html/deref/escape-deref-methods.rs similarity index 100% rename from tests/rustdoc/deref/escape-deref-methods.rs rename to tests/rustdoc-html/deref/escape-deref-methods.rs diff --git a/tests/rustdoc/deref/recursive-deref-sidebar.rs b/tests/rustdoc-html/deref/recursive-deref-sidebar.rs similarity index 100% rename from tests/rustdoc/deref/recursive-deref-sidebar.rs rename to tests/rustdoc-html/deref/recursive-deref-sidebar.rs diff --git a/tests/rustdoc/deref/recursive-deref.rs b/tests/rustdoc-html/deref/recursive-deref.rs similarity index 100% rename from tests/rustdoc/deref/recursive-deref.rs rename to tests/rustdoc-html/deref/recursive-deref.rs diff --git a/tests/rustdoc/deref/sidebar-links-deref-100679.rs b/tests/rustdoc-html/deref/sidebar-links-deref-100679.rs similarity index 100% rename from tests/rustdoc/deref/sidebar-links-deref-100679.rs rename to tests/rustdoc-html/deref/sidebar-links-deref-100679.rs diff --git a/tests/rustdoc/description.rs b/tests/rustdoc-html/description.rs similarity index 100% rename from tests/rustdoc/description.rs rename to tests/rustdoc-html/description.rs diff --git a/tests/rustdoc/description_default.rs b/tests/rustdoc-html/description_default.rs similarity index 100% rename from tests/rustdoc/description_default.rs rename to tests/rustdoc-html/description_default.rs diff --git a/tests/rustdoc/display-hidden-items.rs b/tests/rustdoc-html/display-hidden-items.rs similarity index 100% rename from tests/rustdoc/display-hidden-items.rs rename to tests/rustdoc-html/display-hidden-items.rs diff --git a/tests/rustdoc/doc-attr-comment-mix-42760.rs b/tests/rustdoc-html/doc-attr-comment-mix-42760.rs similarity index 100% rename from tests/rustdoc/doc-attr-comment-mix-42760.rs rename to tests/rustdoc-html/doc-attr-comment-mix-42760.rs diff --git a/tests/rustdoc/doc-attribute.rs b/tests/rustdoc-html/doc-attribute.rs similarity index 100% rename from tests/rustdoc/doc-attribute.rs rename to tests/rustdoc-html/doc-attribute.rs diff --git a/tests/rustdoc/doc-auto-cfg-public-in-private.rs b/tests/rustdoc-html/doc-auto-cfg-public-in-private.rs similarity index 100% rename from tests/rustdoc/doc-auto-cfg-public-in-private.rs rename to tests/rustdoc-html/doc-auto-cfg-public-in-private.rs diff --git a/tests/rustdoc/doc-auto-cfg.rs b/tests/rustdoc-html/doc-auto-cfg.rs similarity index 100% rename from tests/rustdoc/doc-auto-cfg.rs rename to tests/rustdoc-html/doc-auto-cfg.rs diff --git a/tests/rustdoc/doc-cfg/doc-cfg-hide.rs b/tests/rustdoc-html/doc-cfg/doc-cfg-hide.rs similarity index 100% rename from tests/rustdoc/doc-cfg/doc-cfg-hide.rs rename to tests/rustdoc-html/doc-cfg/doc-cfg-hide.rs diff --git a/tests/rustdoc/doc-cfg/doc-cfg-implicit-gate.rs b/tests/rustdoc-html/doc-cfg/doc-cfg-implicit-gate.rs similarity index 100% rename from tests/rustdoc/doc-cfg/doc-cfg-implicit-gate.rs rename to tests/rustdoc-html/doc-cfg/doc-cfg-implicit-gate.rs diff --git a/tests/rustdoc/doc-cfg/doc-cfg-implicit.rs b/tests/rustdoc-html/doc-cfg/doc-cfg-implicit.rs similarity index 100% rename from tests/rustdoc/doc-cfg/doc-cfg-implicit.rs rename to tests/rustdoc-html/doc-cfg/doc-cfg-implicit.rs diff --git a/tests/rustdoc/doc-cfg/doc-cfg-inherit-from-module-79201.rs b/tests/rustdoc-html/doc-cfg/doc-cfg-inherit-from-module-79201.rs similarity index 100% rename from tests/rustdoc/doc-cfg/doc-cfg-inherit-from-module-79201.rs rename to tests/rustdoc-html/doc-cfg/doc-cfg-inherit-from-module-79201.rs diff --git a/tests/rustdoc/doc-cfg/doc-cfg-simplification.rs b/tests/rustdoc-html/doc-cfg/doc-cfg-simplification.rs similarity index 100% rename from tests/rustdoc/doc-cfg/doc-cfg-simplification.rs rename to tests/rustdoc-html/doc-cfg/doc-cfg-simplification.rs diff --git a/tests/rustdoc/doc-cfg/doc-cfg-target-feature.rs b/tests/rustdoc-html/doc-cfg/doc-cfg-target-feature.rs similarity index 100% rename from tests/rustdoc/doc-cfg/doc-cfg-target-feature.rs rename to tests/rustdoc-html/doc-cfg/doc-cfg-target-feature.rs diff --git a/tests/rustdoc/doc-cfg/doc-cfg-traits.rs b/tests/rustdoc-html/doc-cfg/doc-cfg-traits.rs similarity index 100% rename from tests/rustdoc/doc-cfg/doc-cfg-traits.rs rename to tests/rustdoc-html/doc-cfg/doc-cfg-traits.rs diff --git a/tests/rustdoc/doc-cfg/doc-cfg.rs b/tests/rustdoc-html/doc-cfg/doc-cfg.rs similarity index 100% rename from tests/rustdoc/doc-cfg/doc-cfg.rs rename to tests/rustdoc-html/doc-cfg/doc-cfg.rs diff --git a/tests/rustdoc/doc-cfg/duplicate-cfg.rs b/tests/rustdoc-html/doc-cfg/duplicate-cfg.rs similarity index 100% rename from tests/rustdoc/doc-cfg/duplicate-cfg.rs rename to tests/rustdoc-html/doc-cfg/duplicate-cfg.rs diff --git a/tests/rustdoc/doc-hidden-crate.rs b/tests/rustdoc-html/doc-hidden-crate.rs similarity index 100% rename from tests/rustdoc/doc-hidden-crate.rs rename to tests/rustdoc-html/doc-hidden-crate.rs diff --git a/tests/rustdoc/doc-hidden-method-13698.rs b/tests/rustdoc-html/doc-hidden-method-13698.rs similarity index 100% rename from tests/rustdoc/doc-hidden-method-13698.rs rename to tests/rustdoc-html/doc-hidden-method-13698.rs diff --git a/tests/rustdoc/doc-on-keyword.rs b/tests/rustdoc-html/doc-on-keyword.rs similarity index 100% rename from tests/rustdoc/doc-on-keyword.rs rename to tests/rustdoc-html/doc-on-keyword.rs diff --git a/tests/rustdoc/doc-test-attr-18199.rs b/tests/rustdoc-html/doc-test-attr-18199.rs similarity index 100% rename from tests/rustdoc/doc-test-attr-18199.rs rename to tests/rustdoc-html/doc-test-attr-18199.rs diff --git a/tests/rustdoc/doc_auto_cfg.rs b/tests/rustdoc-html/doc_auto_cfg.rs similarity index 100% rename from tests/rustdoc/doc_auto_cfg.rs rename to tests/rustdoc-html/doc_auto_cfg.rs diff --git a/tests/rustdoc/doc_auto_cfg_reexports.rs b/tests/rustdoc-html/doc_auto_cfg_reexports.rs similarity index 100% rename from tests/rustdoc/doc_auto_cfg_reexports.rs rename to tests/rustdoc-html/doc_auto_cfg_reexports.rs diff --git a/tests/rustdoc/doctest/auxiliary/doctest-runtool.rs b/tests/rustdoc-html/doctest/auxiliary/doctest-runtool.rs similarity index 100% rename from tests/rustdoc/doctest/auxiliary/doctest-runtool.rs rename to tests/rustdoc-html/doctest/auxiliary/doctest-runtool.rs diff --git a/tests/rustdoc/doctest/auxiliary/empty.rs b/tests/rustdoc-html/doctest/auxiliary/empty.rs similarity index 100% rename from tests/rustdoc/doctest/auxiliary/empty.rs rename to tests/rustdoc-html/doctest/auxiliary/empty.rs diff --git a/tests/rustdoc/doctest/doctest-cfg-feature-30252.rs b/tests/rustdoc-html/doctest/doctest-cfg-feature-30252.rs similarity index 100% rename from tests/rustdoc/doctest/doctest-cfg-feature-30252.rs rename to tests/rustdoc-html/doctest/doctest-cfg-feature-30252.rs diff --git a/tests/rustdoc/doctest/doctest-crate-attributes-38129.rs b/tests/rustdoc-html/doctest/doctest-crate-attributes-38129.rs similarity index 100% rename from tests/rustdoc/doctest/doctest-crate-attributes-38129.rs rename to tests/rustdoc-html/doctest/doctest-crate-attributes-38129.rs diff --git a/tests/rustdoc/doctest/doctest-escape-boring-41783.codeblock.html b/tests/rustdoc-html/doctest/doctest-escape-boring-41783.codeblock.html similarity index 100% rename from tests/rustdoc/doctest/doctest-escape-boring-41783.codeblock.html rename to tests/rustdoc-html/doctest/doctest-escape-boring-41783.codeblock.html diff --git a/tests/rustdoc/doctest/doctest-escape-boring-41783.rs b/tests/rustdoc-html/doctest/doctest-escape-boring-41783.rs similarity index 100% rename from tests/rustdoc/doctest/doctest-escape-boring-41783.rs rename to tests/rustdoc-html/doctest/doctest-escape-boring-41783.rs diff --git a/tests/rustdoc/doctest/doctest-hide-empty-line-23106.rs b/tests/rustdoc-html/doctest/doctest-hide-empty-line-23106.rs similarity index 100% rename from tests/rustdoc/doctest/doctest-hide-empty-line-23106.rs rename to tests/rustdoc-html/doctest/doctest-hide-empty-line-23106.rs diff --git a/tests/rustdoc/doctest/doctest-ignore-32556.rs b/tests/rustdoc-html/doctest/doctest-ignore-32556.rs similarity index 100% rename from tests/rustdoc/doctest/doctest-ignore-32556.rs rename to tests/rustdoc-html/doctest/doctest-ignore-32556.rs diff --git a/tests/rustdoc/doctest/doctest-include-43153.rs b/tests/rustdoc-html/doctest/doctest-include-43153.rs similarity index 100% rename from tests/rustdoc/doctest/doctest-include-43153.rs rename to tests/rustdoc-html/doctest/doctest-include-43153.rs diff --git a/tests/rustdoc/doctest/doctest-macro-38219.rs b/tests/rustdoc-html/doctest/doctest-macro-38219.rs similarity index 100% rename from tests/rustdoc/doctest/doctest-macro-38219.rs rename to tests/rustdoc-html/doctest/doctest-macro-38219.rs diff --git a/tests/rustdoc/doctest/doctest-manual-crate-name.rs b/tests/rustdoc-html/doctest/doctest-manual-crate-name.rs similarity index 100% rename from tests/rustdoc/doctest/doctest-manual-crate-name.rs rename to tests/rustdoc-html/doctest/doctest-manual-crate-name.rs diff --git a/tests/rustdoc/doctest/doctest-markdown-inline-parse-23744.rs b/tests/rustdoc-html/doctest/doctest-markdown-inline-parse-23744.rs similarity index 100% rename from tests/rustdoc/doctest/doctest-markdown-inline-parse-23744.rs rename to tests/rustdoc-html/doctest/doctest-markdown-inline-parse-23744.rs diff --git a/tests/rustdoc/doctest/doctest-markdown-trailing-docblock-48377.rs b/tests/rustdoc-html/doctest/doctest-markdown-trailing-docblock-48377.rs similarity index 100% rename from tests/rustdoc/doctest/doctest-markdown-trailing-docblock-48377.rs rename to tests/rustdoc-html/doctest/doctest-markdown-trailing-docblock-48377.rs diff --git a/tests/rustdoc/doctest/doctest-multi-line-string-literal-25944.rs b/tests/rustdoc-html/doctest/doctest-multi-line-string-literal-25944.rs similarity index 100% rename from tests/rustdoc/doctest/doctest-multi-line-string-literal-25944.rs rename to tests/rustdoc-html/doctest/doctest-multi-line-string-literal-25944.rs diff --git a/tests/rustdoc/doctest/doctest-runtool.rs b/tests/rustdoc-html/doctest/doctest-runtool.rs similarity index 100% rename from tests/rustdoc/doctest/doctest-runtool.rs rename to tests/rustdoc-html/doctest/doctest-runtool.rs diff --git a/tests/rustdoc/doctest/ignore-sometimes.rs b/tests/rustdoc-html/doctest/ignore-sometimes.rs similarity index 100% rename from tests/rustdoc/doctest/ignore-sometimes.rs rename to tests/rustdoc-html/doctest/ignore-sometimes.rs diff --git a/tests/rustdoc/document-hidden-items-15347.rs b/tests/rustdoc-html/document-hidden-items-15347.rs similarity index 100% rename from tests/rustdoc/document-hidden-items-15347.rs rename to tests/rustdoc-html/document-hidden-items-15347.rs diff --git a/tests/rustdoc/double-hyphen-to-dash.rs b/tests/rustdoc-html/double-hyphen-to-dash.rs similarity index 100% rename from tests/rustdoc/double-hyphen-to-dash.rs rename to tests/rustdoc-html/double-hyphen-to-dash.rs diff --git a/tests/rustdoc/double-quote-escape.rs b/tests/rustdoc-html/double-quote-escape.rs similarity index 100% rename from tests/rustdoc/double-quote-escape.rs rename to tests/rustdoc-html/double-quote-escape.rs diff --git a/tests/rustdoc/duplicate-flags.rs b/tests/rustdoc-html/duplicate-flags.rs similarity index 100% rename from tests/rustdoc/duplicate-flags.rs rename to tests/rustdoc-html/duplicate-flags.rs diff --git a/tests/rustdoc/duplicate_impls/impls.rs b/tests/rustdoc-html/duplicate_impls/impls.rs similarity index 100% rename from tests/rustdoc/duplicate_impls/impls.rs rename to tests/rustdoc-html/duplicate_impls/impls.rs diff --git a/tests/rustdoc/duplicate_impls/sidebar-links-duplicate-impls-33054.rs b/tests/rustdoc-html/duplicate_impls/sidebar-links-duplicate-impls-33054.rs similarity index 100% rename from tests/rustdoc/duplicate_impls/sidebar-links-duplicate-impls-33054.rs rename to tests/rustdoc-html/duplicate_impls/sidebar-links-duplicate-impls-33054.rs diff --git a/tests/rustdoc/dyn-compatibility.rs b/tests/rustdoc-html/dyn-compatibility.rs similarity index 100% rename from tests/rustdoc/dyn-compatibility.rs rename to tests/rustdoc-html/dyn-compatibility.rs diff --git a/tests/rustdoc/early-unindent.rs b/tests/rustdoc-html/early-unindent.rs similarity index 100% rename from tests/rustdoc/early-unindent.rs rename to tests/rustdoc-html/early-unindent.rs diff --git a/tests/rustdoc/edition-doctest.rs b/tests/rustdoc-html/edition-doctest.rs similarity index 100% rename from tests/rustdoc/edition-doctest.rs rename to tests/rustdoc-html/edition-doctest.rs diff --git a/tests/rustdoc/edition-flag.rs b/tests/rustdoc-html/edition-flag.rs similarity index 100% rename from tests/rustdoc/edition-flag.rs rename to tests/rustdoc-html/edition-flag.rs diff --git a/tests/rustdoc/elided-lifetime.rs b/tests/rustdoc-html/elided-lifetime.rs similarity index 100% rename from tests/rustdoc/elided-lifetime.rs rename to tests/rustdoc-html/elided-lifetime.rs diff --git a/tests/rustdoc/empty-doc-comment.rs b/tests/rustdoc-html/empty-doc-comment.rs similarity index 100% rename from tests/rustdoc/empty-doc-comment.rs rename to tests/rustdoc-html/empty-doc-comment.rs diff --git a/tests/rustdoc/empty-mod-public.rs b/tests/rustdoc-html/empty-mod-public.rs similarity index 100% rename from tests/rustdoc/empty-mod-public.rs rename to tests/rustdoc-html/empty-mod-public.rs diff --git a/tests/rustdoc/empty-section.rs b/tests/rustdoc-html/empty-section.rs similarity index 100% rename from tests/rustdoc/empty-section.rs rename to tests/rustdoc-html/empty-section.rs diff --git a/tests/rustdoc/empty-tuple-struct-118180.rs b/tests/rustdoc-html/empty-tuple-struct-118180.rs similarity index 100% rename from tests/rustdoc/empty-tuple-struct-118180.rs rename to tests/rustdoc-html/empty-tuple-struct-118180.rs diff --git a/tests/rustdoc/ensure-src-link.rs b/tests/rustdoc-html/ensure-src-link.rs similarity index 100% rename from tests/rustdoc/ensure-src-link.rs rename to tests/rustdoc-html/ensure-src-link.rs diff --git a/tests/rustdoc/enum/auxiliary/enum-variant.rs b/tests/rustdoc-html/enum/auxiliary/enum-variant.rs similarity index 100% rename from tests/rustdoc/enum/auxiliary/enum-variant.rs rename to tests/rustdoc-html/enum/auxiliary/enum-variant.rs diff --git a/tests/rustdoc/enum/auxiliary/variant-struct.rs b/tests/rustdoc-html/enum/auxiliary/variant-struct.rs similarity index 100% rename from tests/rustdoc/enum/auxiliary/variant-struct.rs rename to tests/rustdoc-html/enum/auxiliary/variant-struct.rs diff --git a/tests/rustdoc/enum/enum-headings.rs b/tests/rustdoc-html/enum/enum-headings.rs similarity index 100% rename from tests/rustdoc/enum/enum-headings.rs rename to tests/rustdoc-html/enum/enum-headings.rs diff --git a/tests/rustdoc/enum/enum-non-exhaustive-108925.rs b/tests/rustdoc-html/enum/enum-non-exhaustive-108925.rs similarity index 100% rename from tests/rustdoc/enum/enum-non-exhaustive-108925.rs rename to tests/rustdoc-html/enum/enum-non-exhaustive-108925.rs diff --git a/tests/rustdoc/enum/enum-variant-doc-hidden-field-88600.rs b/tests/rustdoc-html/enum/enum-variant-doc-hidden-field-88600.rs similarity index 100% rename from tests/rustdoc/enum/enum-variant-doc-hidden-field-88600.rs rename to tests/rustdoc-html/enum/enum-variant-doc-hidden-field-88600.rs diff --git a/tests/rustdoc/enum/enum-variant-fields-heading.rs b/tests/rustdoc-html/enum/enum-variant-fields-heading.rs similarity index 100% rename from tests/rustdoc/enum/enum-variant-fields-heading.rs rename to tests/rustdoc-html/enum/enum-variant-fields-heading.rs diff --git a/tests/rustdoc/enum/enum-variant-fields-heading.variants.html b/tests/rustdoc-html/enum/enum-variant-fields-heading.variants.html similarity index 100% rename from tests/rustdoc/enum/enum-variant-fields-heading.variants.html rename to tests/rustdoc-html/enum/enum-variant-fields-heading.variants.html diff --git a/tests/rustdoc/enum/enum-variant-non_exhaustive.rs b/tests/rustdoc-html/enum/enum-variant-non_exhaustive.rs similarity index 100% rename from tests/rustdoc/enum/enum-variant-non_exhaustive.rs rename to tests/rustdoc-html/enum/enum-variant-non_exhaustive.rs diff --git a/tests/rustdoc/enum/enum-variant-non_exhaustive.type-alias-code.html b/tests/rustdoc-html/enum/enum-variant-non_exhaustive.type-alias-code.html similarity index 100% rename from tests/rustdoc/enum/enum-variant-non_exhaustive.type-alias-code.html rename to tests/rustdoc-html/enum/enum-variant-non_exhaustive.type-alias-code.html diff --git a/tests/rustdoc/enum/enum-variant-non_exhaustive.type-code.html b/tests/rustdoc-html/enum/enum-variant-non_exhaustive.type-code.html similarity index 100% rename from tests/rustdoc/enum/enum-variant-non_exhaustive.type-code.html rename to tests/rustdoc-html/enum/enum-variant-non_exhaustive.type-code.html diff --git a/tests/rustdoc/enum/enum-variant-value.rs b/tests/rustdoc-html/enum/enum-variant-value.rs similarity index 100% rename from tests/rustdoc/enum/enum-variant-value.rs rename to tests/rustdoc-html/enum/enum-variant-value.rs diff --git a/tests/rustdoc/enum/render-enum-variant-structlike-32395.rs b/tests/rustdoc-html/enum/render-enum-variant-structlike-32395.rs similarity index 100% rename from tests/rustdoc/enum/render-enum-variant-structlike-32395.rs rename to tests/rustdoc-html/enum/render-enum-variant-structlike-32395.rs diff --git a/tests/rustdoc/enum/strip-enum-variant.no-not-shown.html b/tests/rustdoc-html/enum/strip-enum-variant.no-not-shown.html similarity index 100% rename from tests/rustdoc/enum/strip-enum-variant.no-not-shown.html rename to tests/rustdoc-html/enum/strip-enum-variant.no-not-shown.html diff --git a/tests/rustdoc/enum/strip-enum-variant.rs b/tests/rustdoc-html/enum/strip-enum-variant.rs similarity index 100% rename from tests/rustdoc/enum/strip-enum-variant.rs rename to tests/rustdoc-html/enum/strip-enum-variant.rs diff --git a/tests/rustdoc/extern/auxiliary/empty.rs b/tests/rustdoc-html/extern/auxiliary/empty.rs similarity index 100% rename from tests/rustdoc/extern/auxiliary/empty.rs rename to tests/rustdoc-html/extern/auxiliary/empty.rs diff --git a/tests/rustdoc/extern/auxiliary/extern-links.rs b/tests/rustdoc-html/extern/auxiliary/extern-links.rs similarity index 100% rename from tests/rustdoc/extern/auxiliary/extern-links.rs rename to tests/rustdoc-html/extern/auxiliary/extern-links.rs diff --git a/tests/rustdoc/extern/auxiliary/external-cross-doc.md b/tests/rustdoc-html/extern/auxiliary/external-cross-doc.md similarity index 100% rename from tests/rustdoc/extern/auxiliary/external-cross-doc.md rename to tests/rustdoc-html/extern/auxiliary/external-cross-doc.md diff --git a/tests/rustdoc/extern/auxiliary/external-cross.rs b/tests/rustdoc-html/extern/auxiliary/external-cross.rs similarity index 100% rename from tests/rustdoc/extern/auxiliary/external-cross.rs rename to tests/rustdoc-html/extern/auxiliary/external-cross.rs diff --git a/tests/rustdoc/extern/auxiliary/external-doc.md b/tests/rustdoc-html/extern/auxiliary/external-doc.md similarity index 100% rename from tests/rustdoc/extern/auxiliary/external-doc.md rename to tests/rustdoc-html/extern/auxiliary/external-doc.md diff --git a/tests/rustdoc/extern/auxiliary/html_root.rs b/tests/rustdoc-html/extern/auxiliary/html_root.rs similarity index 100% rename from tests/rustdoc/extern/auxiliary/html_root.rs rename to tests/rustdoc-html/extern/auxiliary/html_root.rs diff --git a/tests/rustdoc/extern/auxiliary/issue-30109-1.rs b/tests/rustdoc-html/extern/auxiliary/issue-30109-1.rs similarity index 100% rename from tests/rustdoc/extern/auxiliary/issue-30109-1.rs rename to tests/rustdoc-html/extern/auxiliary/issue-30109-1.rs diff --git a/tests/rustdoc/extern/auxiliary/no_html_root.rs b/tests/rustdoc-html/extern/auxiliary/no_html_root.rs similarity index 100% rename from tests/rustdoc/extern/auxiliary/no_html_root.rs rename to tests/rustdoc-html/extern/auxiliary/no_html_root.rs diff --git a/tests/rustdoc/extern/auxiliary/panic-item.rs b/tests/rustdoc-html/extern/auxiliary/panic-item.rs similarity index 100% rename from tests/rustdoc/extern/auxiliary/panic-item.rs rename to tests/rustdoc-html/extern/auxiliary/panic-item.rs diff --git a/tests/rustdoc/extern/auxiliary/pub-extern-crate.rs b/tests/rustdoc-html/extern/auxiliary/pub-extern-crate.rs similarity index 100% rename from tests/rustdoc/extern/auxiliary/pub-extern-crate.rs rename to tests/rustdoc-html/extern/auxiliary/pub-extern-crate.rs diff --git a/tests/rustdoc/extern/auxiliary/rustdoc-extern-default-method.rs b/tests/rustdoc-html/extern/auxiliary/rustdoc-extern-default-method.rs similarity index 100% rename from tests/rustdoc/extern/auxiliary/rustdoc-extern-default-method.rs rename to tests/rustdoc-html/extern/auxiliary/rustdoc-extern-default-method.rs diff --git a/tests/rustdoc/extern/auxiliary/rustdoc-extern-method.rs b/tests/rustdoc-html/extern/auxiliary/rustdoc-extern-method.rs similarity index 100% rename from tests/rustdoc/extern/auxiliary/rustdoc-extern-method.rs rename to tests/rustdoc-html/extern/auxiliary/rustdoc-extern-method.rs diff --git a/tests/rustdoc/extern/auxiliary/variant-struct.rs b/tests/rustdoc-html/extern/auxiliary/variant-struct.rs similarity index 100% rename from tests/rustdoc/extern/auxiliary/variant-struct.rs rename to tests/rustdoc-html/extern/auxiliary/variant-struct.rs diff --git a/tests/rustdoc/extern/duplicate-reexports-section-150211.rs b/tests/rustdoc-html/extern/duplicate-reexports-section-150211.rs similarity index 100% rename from tests/rustdoc/extern/duplicate-reexports-section-150211.rs rename to tests/rustdoc-html/extern/duplicate-reexports-section-150211.rs diff --git a/tests/rustdoc/extern/extern-default-method.no_href_on_anchor.html b/tests/rustdoc-html/extern/extern-default-method.no_href_on_anchor.html similarity index 100% rename from tests/rustdoc/extern/extern-default-method.no_href_on_anchor.html rename to tests/rustdoc-html/extern/extern-default-method.no_href_on_anchor.html diff --git a/tests/rustdoc/extern/extern-default-method.rs b/tests/rustdoc-html/extern/extern-default-method.rs similarity index 100% rename from tests/rustdoc/extern/extern-default-method.rs rename to tests/rustdoc-html/extern/extern-default-method.rs diff --git a/tests/rustdoc/extern/extern-fn-22038.rs b/tests/rustdoc-html/extern/extern-fn-22038.rs similarity index 100% rename from tests/rustdoc/extern/extern-fn-22038.rs rename to tests/rustdoc-html/extern/extern-fn-22038.rs diff --git a/tests/rustdoc/extern/extern-html-alias.rs b/tests/rustdoc-html/extern/extern-html-alias.rs similarity index 100% rename from tests/rustdoc/extern/extern-html-alias.rs rename to tests/rustdoc-html/extern/extern-html-alias.rs diff --git a/tests/rustdoc/extern/extern-html-fallback.rs b/tests/rustdoc-html/extern/extern-html-fallback.rs similarity index 100% rename from tests/rustdoc/extern/extern-html-fallback.rs rename to tests/rustdoc-html/extern/extern-html-fallback.rs diff --git a/tests/rustdoc/extern/extern-html-root-url-precedence.rs b/tests/rustdoc-html/extern/extern-html-root-url-precedence.rs similarity index 100% rename from tests/rustdoc/extern/extern-html-root-url-precedence.rs rename to tests/rustdoc-html/extern/extern-html-root-url-precedence.rs diff --git a/tests/rustdoc/extern/extern-html-root-url.rs b/tests/rustdoc-html/extern/extern-html-root-url.rs similarity index 100% rename from tests/rustdoc/extern/extern-html-root-url.rs rename to tests/rustdoc-html/extern/extern-html-root-url.rs diff --git a/tests/rustdoc/extern/extern-links.rs b/tests/rustdoc-html/extern/extern-links.rs similarity index 100% rename from tests/rustdoc/extern/extern-links.rs rename to tests/rustdoc-html/extern/extern-links.rs diff --git a/tests/rustdoc/extern/extern-method.rs b/tests/rustdoc-html/extern/extern-method.rs similarity index 100% rename from tests/rustdoc/extern/extern-method.rs rename to tests/rustdoc-html/extern/extern-method.rs diff --git a/tests/rustdoc/extern/external-cross.rs b/tests/rustdoc-html/extern/external-cross.rs similarity index 100% rename from tests/rustdoc/extern/external-cross.rs rename to tests/rustdoc-html/extern/external-cross.rs diff --git a/tests/rustdoc/extern/external-doc.rs b/tests/rustdoc-html/extern/external-doc.rs similarity index 100% rename from tests/rustdoc/extern/external-doc.rs rename to tests/rustdoc-html/extern/external-doc.rs diff --git a/tests/rustdoc/extern/hidden-extern-34025.rs b/tests/rustdoc-html/extern/hidden-extern-34025.rs similarity index 100% rename from tests/rustdoc/extern/hidden-extern-34025.rs rename to tests/rustdoc-html/extern/hidden-extern-34025.rs diff --git a/tests/rustdoc/extern/link-extern-crate-33178.rs b/tests/rustdoc-html/extern/link-extern-crate-33178.rs similarity index 100% rename from tests/rustdoc/extern/link-extern-crate-33178.rs rename to tests/rustdoc-html/extern/link-extern-crate-33178.rs diff --git a/tests/rustdoc/extern/link-extern-crate-item-30109.rs b/tests/rustdoc-html/extern/link-extern-crate-item-30109.rs similarity index 100% rename from tests/rustdoc/extern/link-extern-crate-item-30109.rs rename to tests/rustdoc-html/extern/link-extern-crate-item-30109.rs diff --git a/tests/rustdoc/extern/link-extern-crate-title-33178.rs b/tests/rustdoc-html/extern/link-extern-crate-title-33178.rs similarity index 100% rename from tests/rustdoc/extern/link-extern-crate-title-33178.rs rename to tests/rustdoc-html/extern/link-extern-crate-title-33178.rs diff --git a/tests/rustdoc/extern/pub-extern-crate-150176.rs b/tests/rustdoc-html/extern/pub-extern-crate-150176.rs similarity index 100% rename from tests/rustdoc/extern/pub-extern-crate-150176.rs rename to tests/rustdoc-html/extern/pub-extern-crate-150176.rs diff --git a/tests/rustdoc/extern/pub-extern-crate.rs b/tests/rustdoc-html/extern/pub-extern-crate.rs similarity index 100% rename from tests/rustdoc/extern/pub-extern-crate.rs rename to tests/rustdoc-html/extern/pub-extern-crate.rs diff --git a/tests/rustdoc/extern/unsafe-extern-blocks.rs b/tests/rustdoc-html/extern/unsafe-extern-blocks.rs similarity index 100% rename from tests/rustdoc/extern/unsafe-extern-blocks.rs rename to tests/rustdoc-html/extern/unsafe-extern-blocks.rs diff --git a/tests/rustdoc/extern/unused-extern-crate.rs b/tests/rustdoc-html/extern/unused-extern-crate.rs similarity index 100% rename from tests/rustdoc/extern/unused-extern-crate.rs rename to tests/rustdoc-html/extern/unused-extern-crate.rs diff --git a/tests/rustdoc/extremely_long_typename.extremely_long_typename.html b/tests/rustdoc-html/extremely_long_typename.extremely_long_typename.html similarity index 100% rename from tests/rustdoc/extremely_long_typename.extremely_long_typename.html rename to tests/rustdoc-html/extremely_long_typename.extremely_long_typename.html diff --git a/tests/rustdoc/extremely_long_typename.rs b/tests/rustdoc-html/extremely_long_typename.rs similarity index 100% rename from tests/rustdoc/extremely_long_typename.rs rename to tests/rustdoc-html/extremely_long_typename.rs diff --git a/tests/rustdoc/feature-gate-doc_auto_cfg.rs b/tests/rustdoc-html/feature-gate-doc_auto_cfg.rs similarity index 100% rename from tests/rustdoc/feature-gate-doc_auto_cfg.rs rename to tests/rustdoc-html/feature-gate-doc_auto_cfg.rs diff --git a/tests/rustdoc/ffi.rs b/tests/rustdoc-html/ffi.rs similarity index 100% rename from tests/rustdoc/ffi.rs rename to tests/rustdoc-html/ffi.rs diff --git a/tests/rustdoc/file-creation-111249.rs b/tests/rustdoc-html/file-creation-111249.rs similarity index 100% rename from tests/rustdoc/file-creation-111249.rs rename to tests/rustdoc-html/file-creation-111249.rs diff --git a/tests/rustdoc/files-creation-hidden.rs b/tests/rustdoc-html/files-creation-hidden.rs similarity index 100% rename from tests/rustdoc/files-creation-hidden.rs rename to tests/rustdoc-html/files-creation-hidden.rs diff --git a/tests/rustdoc/fn-bound.rs b/tests/rustdoc-html/fn-bound.rs similarity index 100% rename from tests/rustdoc/fn-bound.rs rename to tests/rustdoc-html/fn-bound.rs diff --git a/tests/rustdoc/fn-pointer-arg-name.rs b/tests/rustdoc-html/fn-pointer-arg-name.rs similarity index 100% rename from tests/rustdoc/fn-pointer-arg-name.rs rename to tests/rustdoc-html/fn-pointer-arg-name.rs diff --git a/tests/rustdoc/fn-sidebar.rs b/tests/rustdoc-html/fn-sidebar.rs similarity index 100% rename from tests/rustdoc/fn-sidebar.rs rename to tests/rustdoc-html/fn-sidebar.rs diff --git a/tests/rustdoc/fn-type.rs b/tests/rustdoc-html/fn-type.rs similarity index 100% rename from tests/rustdoc/fn-type.rs rename to tests/rustdoc-html/fn-type.rs diff --git a/tests/rustdoc/footnote-definition-without-blank-line-100638.rs b/tests/rustdoc-html/footnote-definition-without-blank-line-100638.rs similarity index 100% rename from tests/rustdoc/footnote-definition-without-blank-line-100638.rs rename to tests/rustdoc-html/footnote-definition-without-blank-line-100638.rs diff --git a/tests/rustdoc/footnote-ids.rs b/tests/rustdoc-html/footnote-ids.rs similarity index 100% rename from tests/rustdoc/footnote-ids.rs rename to tests/rustdoc-html/footnote-ids.rs diff --git a/tests/rustdoc/footnote-in-summary.rs b/tests/rustdoc-html/footnote-in-summary.rs similarity index 100% rename from tests/rustdoc/footnote-in-summary.rs rename to tests/rustdoc-html/footnote-in-summary.rs diff --git a/tests/rustdoc/footnote-reference-ids.rs b/tests/rustdoc-html/footnote-reference-ids.rs similarity index 100% rename from tests/rustdoc/footnote-reference-ids.rs rename to tests/rustdoc-html/footnote-reference-ids.rs diff --git a/tests/rustdoc/footnote-reference-in-footnote-def.rs b/tests/rustdoc-html/footnote-reference-in-footnote-def.rs similarity index 100% rename from tests/rustdoc/footnote-reference-in-footnote-def.rs rename to tests/rustdoc-html/footnote-reference-in-footnote-def.rs diff --git a/tests/rustdoc/force-target-feature.rs b/tests/rustdoc-html/force-target-feature.rs similarity index 100% rename from tests/rustdoc/force-target-feature.rs rename to tests/rustdoc-html/force-target-feature.rs diff --git a/tests/rustdoc/force-unstable-if-unmarked-106421-not-internal.rs b/tests/rustdoc-html/force-unstable-if-unmarked-106421-not-internal.rs similarity index 100% rename from tests/rustdoc/force-unstable-if-unmarked-106421-not-internal.rs rename to tests/rustdoc-html/force-unstable-if-unmarked-106421-not-internal.rs diff --git a/tests/rustdoc/force-unstable-if-unmarked-106421.rs b/tests/rustdoc-html/force-unstable-if-unmarked-106421.rs similarity index 100% rename from tests/rustdoc/force-unstable-if-unmarked-106421.rs rename to tests/rustdoc-html/force-unstable-if-unmarked-106421.rs diff --git a/tests/rustdoc/foreigntype.rs b/tests/rustdoc-html/foreigntype.rs similarity index 100% rename from tests/rustdoc/foreigntype.rs rename to tests/rustdoc-html/foreigntype.rs diff --git a/tests/rustdoc/generic-associated-types/gat-elided-lifetime-94683.rs b/tests/rustdoc-html/generic-associated-types/gat-elided-lifetime-94683.rs similarity index 100% rename from tests/rustdoc/generic-associated-types/gat-elided-lifetime-94683.rs rename to tests/rustdoc-html/generic-associated-types/gat-elided-lifetime-94683.rs diff --git a/tests/rustdoc/generic-associated-types/gat-linkification-109488.rs b/tests/rustdoc-html/generic-associated-types/gat-linkification-109488.rs similarity index 100% rename from tests/rustdoc/generic-associated-types/gat-linkification-109488.rs rename to tests/rustdoc-html/generic-associated-types/gat-linkification-109488.rs diff --git a/tests/rustdoc/generic-associated-types/gats.rs b/tests/rustdoc-html/generic-associated-types/gats.rs similarity index 100% rename from tests/rustdoc/generic-associated-types/gats.rs rename to tests/rustdoc-html/generic-associated-types/gats.rs diff --git a/tests/rustdoc/glob-shadowing.rs b/tests/rustdoc-html/glob-shadowing.rs similarity index 100% rename from tests/rustdoc/glob-shadowing.rs rename to tests/rustdoc-html/glob-shadowing.rs diff --git a/tests/rustdoc/heading-levels-89309.rs b/tests/rustdoc-html/heading-levels-89309.rs similarity index 100% rename from tests/rustdoc/heading-levels-89309.rs rename to tests/rustdoc-html/heading-levels-89309.rs diff --git a/tests/rustdoc/heterogeneous-concat.rs b/tests/rustdoc-html/heterogeneous-concat.rs similarity index 100% rename from tests/rustdoc/heterogeneous-concat.rs rename to tests/rustdoc-html/heterogeneous-concat.rs diff --git a/tests/rustdoc/hidden-line.rs b/tests/rustdoc-html/hidden-line.rs similarity index 100% rename from tests/rustdoc/hidden-line.rs rename to tests/rustdoc-html/hidden-line.rs diff --git a/tests/rustdoc/hidden-methods.rs b/tests/rustdoc-html/hidden-methods.rs similarity index 100% rename from tests/rustdoc/hidden-methods.rs rename to tests/rustdoc-html/hidden-methods.rs diff --git a/tests/rustdoc/hidden-trait-methods-with-document-hidden-items.rs b/tests/rustdoc-html/hidden-trait-methods-with-document-hidden-items.rs similarity index 100% rename from tests/rustdoc/hidden-trait-methods-with-document-hidden-items.rs rename to tests/rustdoc-html/hidden-trait-methods-with-document-hidden-items.rs diff --git a/tests/rustdoc/hidden-trait-methods.rs b/tests/rustdoc-html/hidden-trait-methods.rs similarity index 100% rename from tests/rustdoc/hidden-trait-methods.rs rename to tests/rustdoc-html/hidden-trait-methods.rs diff --git a/tests/rustdoc/hide-unstable-trait.rs b/tests/rustdoc-html/hide-unstable-trait.rs similarity index 100% rename from tests/rustdoc/hide-unstable-trait.rs rename to tests/rustdoc-html/hide-unstable-trait.rs diff --git a/tests/rustdoc/higher-ranked-trait-bounds.rs b/tests/rustdoc-html/higher-ranked-trait-bounds.rs similarity index 100% rename from tests/rustdoc/higher-ranked-trait-bounds.rs rename to tests/rustdoc-html/higher-ranked-trait-bounds.rs diff --git a/tests/rustdoc/highlight-invalid-rust-12834.rs b/tests/rustdoc-html/highlight-invalid-rust-12834.rs similarity index 100% rename from tests/rustdoc/highlight-invalid-rust-12834.rs rename to tests/rustdoc-html/highlight-invalid-rust-12834.rs diff --git a/tests/rustdoc/ice-type-error-19181.rs b/tests/rustdoc-html/ice-type-error-19181.rs similarity index 100% rename from tests/rustdoc/ice-type-error-19181.rs rename to tests/rustdoc-html/ice-type-error-19181.rs diff --git a/tests/rustdoc/impl/auxiliary/cross-crate-hidden-impl-parameter.rs b/tests/rustdoc-html/impl/auxiliary/cross-crate-hidden-impl-parameter.rs similarity index 100% rename from tests/rustdoc/impl/auxiliary/cross-crate-hidden-impl-parameter.rs rename to tests/rustdoc-html/impl/auxiliary/cross-crate-hidden-impl-parameter.rs diff --git a/tests/rustdoc/impl/auxiliary/extern-impl-trait.rs b/tests/rustdoc-html/impl/auxiliary/extern-impl-trait.rs similarity index 100% rename from tests/rustdoc/impl/auxiliary/extern-impl-trait.rs rename to tests/rustdoc-html/impl/auxiliary/extern-impl-trait.rs diff --git a/tests/rustdoc/impl/auxiliary/incoherent-impl-types.rs b/tests/rustdoc-html/impl/auxiliary/incoherent-impl-types.rs similarity index 100% rename from tests/rustdoc/impl/auxiliary/incoherent-impl-types.rs rename to tests/rustdoc-html/impl/auxiliary/incoherent-impl-types.rs diff --git a/tests/rustdoc/impl/auxiliary/issue-100204-aux.rs b/tests/rustdoc-html/impl/auxiliary/issue-100204-aux.rs similarity index 100% rename from tests/rustdoc/impl/auxiliary/issue-100204-aux.rs rename to tests/rustdoc-html/impl/auxiliary/issue-100204-aux.rs diff --git a/tests/rustdoc/impl/auxiliary/issue-17476.rs b/tests/rustdoc-html/impl/auxiliary/issue-17476.rs similarity index 100% rename from tests/rustdoc/impl/auxiliary/issue-17476.rs rename to tests/rustdoc-html/impl/auxiliary/issue-17476.rs diff --git a/tests/rustdoc/impl/auxiliary/issue-21092.rs b/tests/rustdoc-html/impl/auxiliary/issue-21092.rs similarity index 100% rename from tests/rustdoc/impl/auxiliary/issue-21092.rs rename to tests/rustdoc-html/impl/auxiliary/issue-21092.rs diff --git a/tests/rustdoc/impl/auxiliary/issue-22025.rs b/tests/rustdoc-html/impl/auxiliary/issue-22025.rs similarity index 100% rename from tests/rustdoc/impl/auxiliary/issue-22025.rs rename to tests/rustdoc-html/impl/auxiliary/issue-22025.rs diff --git a/tests/rustdoc/impl/auxiliary/issue-53689.rs b/tests/rustdoc-html/impl/auxiliary/issue-53689.rs similarity index 100% rename from tests/rustdoc/impl/auxiliary/issue-53689.rs rename to tests/rustdoc-html/impl/auxiliary/issue-53689.rs diff --git a/tests/rustdoc/impl/auxiliary/precise-capturing.rs b/tests/rustdoc-html/impl/auxiliary/precise-capturing.rs similarity index 100% rename from tests/rustdoc/impl/auxiliary/precise-capturing.rs rename to tests/rustdoc-html/impl/auxiliary/precise-capturing.rs diff --git a/tests/rustdoc/impl/auxiliary/real_gimli.rs b/tests/rustdoc-html/impl/auxiliary/real_gimli.rs similarity index 100% rename from tests/rustdoc/impl/auxiliary/real_gimli.rs rename to tests/rustdoc-html/impl/auxiliary/real_gimli.rs diff --git a/tests/rustdoc/impl/auxiliary/realcore.rs b/tests/rustdoc-html/impl/auxiliary/realcore.rs similarity index 100% rename from tests/rustdoc/impl/auxiliary/realcore.rs rename to tests/rustdoc-html/impl/auxiliary/realcore.rs diff --git a/tests/rustdoc/impl/auxiliary/rustdoc-default-impl.rs b/tests/rustdoc-html/impl/auxiliary/rustdoc-default-impl.rs similarity index 100% rename from tests/rustdoc/impl/auxiliary/rustdoc-default-impl.rs rename to tests/rustdoc-html/impl/auxiliary/rustdoc-default-impl.rs diff --git a/tests/rustdoc/impl/auxiliary/rustdoc-impl-parts-crosscrate.rs b/tests/rustdoc-html/impl/auxiliary/rustdoc-impl-parts-crosscrate.rs similarity index 100% rename from tests/rustdoc/impl/auxiliary/rustdoc-impl-parts-crosscrate.rs rename to tests/rustdoc-html/impl/auxiliary/rustdoc-impl-parts-crosscrate.rs diff --git a/tests/rustdoc/impl/blanket-impl-29503.rs b/tests/rustdoc-html/impl/blanket-impl-29503.rs similarity index 100% rename from tests/rustdoc/impl/blanket-impl-29503.rs rename to tests/rustdoc-html/impl/blanket-impl-29503.rs diff --git a/tests/rustdoc/impl/blanket-impl-78673.rs b/tests/rustdoc-html/impl/blanket-impl-78673.rs similarity index 100% rename from tests/rustdoc/impl/blanket-impl-78673.rs rename to tests/rustdoc-html/impl/blanket-impl-78673.rs diff --git a/tests/rustdoc/impl/cross-crate-hidden-impl-parameter.rs b/tests/rustdoc-html/impl/cross-crate-hidden-impl-parameter.rs similarity index 100% rename from tests/rustdoc/impl/cross-crate-hidden-impl-parameter.rs rename to tests/rustdoc-html/impl/cross-crate-hidden-impl-parameter.rs diff --git a/tests/rustdoc/impl/deduplicate-glob-import-impl-21474.rs b/tests/rustdoc-html/impl/deduplicate-glob-import-impl-21474.rs similarity index 100% rename from tests/rustdoc/impl/deduplicate-glob-import-impl-21474.rs rename to tests/rustdoc-html/impl/deduplicate-glob-import-impl-21474.rs diff --git a/tests/rustdoc/impl/deduplicate-trait-impl-22025.rs b/tests/rustdoc-html/impl/deduplicate-trait-impl-22025.rs similarity index 100% rename from tests/rustdoc/impl/deduplicate-trait-impl-22025.rs rename to tests/rustdoc-html/impl/deduplicate-trait-impl-22025.rs diff --git a/tests/rustdoc/impl/default-impl.rs b/tests/rustdoc-html/impl/default-impl.rs similarity index 100% rename from tests/rustdoc/impl/default-impl.rs rename to tests/rustdoc-html/impl/default-impl.rs diff --git a/tests/rustdoc/impl/deprecated-impls.rs b/tests/rustdoc-html/impl/deprecated-impls.rs similarity index 100% rename from tests/rustdoc/impl/deprecated-impls.rs rename to tests/rustdoc-html/impl/deprecated-impls.rs diff --git a/tests/rustdoc/impl/doc-hidden-trait-implementors-33069.rs b/tests/rustdoc-html/impl/doc-hidden-trait-implementors-33069.rs similarity index 100% rename from tests/rustdoc/impl/doc-hidden-trait-implementors-33069.rs rename to tests/rustdoc-html/impl/doc-hidden-trait-implementors-33069.rs diff --git a/tests/rustdoc/impl/doc_auto_cfg_nested_impl.rs b/tests/rustdoc-html/impl/doc_auto_cfg_nested_impl.rs similarity index 100% rename from tests/rustdoc/impl/doc_auto_cfg_nested_impl.rs rename to tests/rustdoc-html/impl/doc_auto_cfg_nested_impl.rs diff --git a/tests/rustdoc/impl/duplicated_impl.rs b/tests/rustdoc-html/impl/duplicated_impl.rs similarity index 100% rename from tests/rustdoc/impl/duplicated_impl.rs rename to tests/rustdoc-html/impl/duplicated_impl.rs diff --git a/tests/rustdoc/impl/empty-impl-block.rs b/tests/rustdoc-html/impl/empty-impl-block.rs similarity index 100% rename from tests/rustdoc/impl/empty-impl-block.rs rename to tests/rustdoc-html/impl/empty-impl-block.rs diff --git a/tests/rustdoc/impl/empty-impls.rs b/tests/rustdoc-html/impl/empty-impls.rs similarity index 100% rename from tests/rustdoc/impl/empty-impls.rs rename to tests/rustdoc-html/impl/empty-impls.rs diff --git a/tests/rustdoc/impl/extern-impl-trait.rs b/tests/rustdoc-html/impl/extern-impl-trait.rs similarity index 100% rename from tests/rustdoc/impl/extern-impl-trait.rs rename to tests/rustdoc-html/impl/extern-impl-trait.rs diff --git a/tests/rustdoc/impl/extern-impl.rs b/tests/rustdoc-html/impl/extern-impl.rs similarity index 100% rename from tests/rustdoc/impl/extern-impl.rs rename to tests/rustdoc-html/impl/extern-impl.rs diff --git a/tests/rustdoc/impl/foreign-implementors-js-43701.rs b/tests/rustdoc-html/impl/foreign-implementors-js-43701.rs similarity index 100% rename from tests/rustdoc/impl/foreign-implementors-js-43701.rs rename to tests/rustdoc-html/impl/foreign-implementors-js-43701.rs diff --git a/tests/rustdoc/impl/generic-impl.rs b/tests/rustdoc-html/impl/generic-impl.rs similarity index 100% rename from tests/rustdoc/impl/generic-impl.rs rename to tests/rustdoc-html/impl/generic-impl.rs diff --git a/tests/rustdoc/impl/hidden-implementors-90781.rs b/tests/rustdoc-html/impl/hidden-implementors-90781.rs similarity index 100% rename from tests/rustdoc/impl/hidden-implementors-90781.rs rename to tests/rustdoc-html/impl/hidden-implementors-90781.rs diff --git a/tests/rustdoc/impl/hidden-impls.rs b/tests/rustdoc-html/impl/hidden-impls.rs similarity index 100% rename from tests/rustdoc/impl/hidden-impls.rs rename to tests/rustdoc-html/impl/hidden-impls.rs diff --git a/tests/rustdoc/impl/hidden-trait-struct-impls.rs b/tests/rustdoc-html/impl/hidden-trait-struct-impls.rs similarity index 100% rename from tests/rustdoc/impl/hidden-trait-struct-impls.rs rename to tests/rustdoc-html/impl/hidden-trait-struct-impls.rs diff --git a/tests/rustdoc/impl/hide-mut-methods-if-no-derefmut-impl-74083.rs b/tests/rustdoc-html/impl/hide-mut-methods-if-no-derefmut-impl-74083.rs similarity index 100% rename from tests/rustdoc/impl/hide-mut-methods-if-no-derefmut-impl-74083.rs rename to tests/rustdoc-html/impl/hide-mut-methods-if-no-derefmut-impl-74083.rs diff --git a/tests/rustdoc/impl/impl-alias-substituted.rs b/tests/rustdoc-html/impl/impl-alias-substituted.rs similarity index 100% rename from tests/rustdoc/impl/impl-alias-substituted.rs rename to tests/rustdoc-html/impl/impl-alias-substituted.rs diff --git a/tests/rustdoc/impl/impl-assoc-type-21092.rs b/tests/rustdoc-html/impl/impl-assoc-type-21092.rs similarity index 100% rename from tests/rustdoc/impl/impl-assoc-type-21092.rs rename to tests/rustdoc-html/impl/impl-assoc-type-21092.rs diff --git a/tests/rustdoc/impl/impl-associated-items-order.rs b/tests/rustdoc-html/impl/impl-associated-items-order.rs similarity index 100% rename from tests/rustdoc/impl/impl-associated-items-order.rs rename to tests/rustdoc-html/impl/impl-associated-items-order.rs diff --git a/tests/rustdoc/impl/impl-associated-items-sidebar.rs b/tests/rustdoc-html/impl/impl-associated-items-sidebar.rs similarity index 100% rename from tests/rustdoc/impl/impl-associated-items-sidebar.rs rename to tests/rustdoc-html/impl/impl-associated-items-sidebar.rs diff --git a/tests/rustdoc/impl/impl-blanket-53689.rs b/tests/rustdoc-html/impl/impl-blanket-53689.rs similarity index 100% rename from tests/rustdoc/impl/impl-blanket-53689.rs rename to tests/rustdoc-html/impl/impl-blanket-53689.rs diff --git a/tests/rustdoc/impl/impl-box.rs b/tests/rustdoc-html/impl/impl-box.rs similarity index 100% rename from tests/rustdoc/impl/impl-box.rs rename to tests/rustdoc-html/impl/impl-box.rs diff --git a/tests/rustdoc/impl/impl-disambiguation.rs b/tests/rustdoc-html/impl/impl-disambiguation.rs similarity index 100% rename from tests/rustdoc/impl/impl-disambiguation.rs rename to tests/rustdoc-html/impl/impl-disambiguation.rs diff --git a/tests/rustdoc/impl/impl-everywhere.rs b/tests/rustdoc-html/impl/impl-everywhere.rs similarity index 100% rename from tests/rustdoc/impl/impl-everywhere.rs rename to tests/rustdoc-html/impl/impl-everywhere.rs diff --git a/tests/rustdoc/impl/impl-in-const-block.rs b/tests/rustdoc-html/impl/impl-in-const-block.rs similarity index 100% rename from tests/rustdoc/impl/impl-in-const-block.rs rename to tests/rustdoc-html/impl/impl-in-const-block.rs diff --git a/tests/rustdoc/impl/impl-on-ty-alias-issue-119015.rs b/tests/rustdoc-html/impl/impl-on-ty-alias-issue-119015.rs similarity index 100% rename from tests/rustdoc/impl/impl-on-ty-alias-issue-119015.rs rename to tests/rustdoc-html/impl/impl-on-ty-alias-issue-119015.rs diff --git a/tests/rustdoc/impl/impl-parts-crosscrate.rs b/tests/rustdoc-html/impl/impl-parts-crosscrate.rs similarity index 100% rename from tests/rustdoc/impl/impl-parts-crosscrate.rs rename to tests/rustdoc-html/impl/impl-parts-crosscrate.rs diff --git a/tests/rustdoc/impl/impl-parts.rs b/tests/rustdoc-html/impl/impl-parts.rs similarity index 100% rename from tests/rustdoc/impl/impl-parts.rs rename to tests/rustdoc-html/impl/impl-parts.rs diff --git a/tests/rustdoc/impl/impl-ref-20175.rs b/tests/rustdoc-html/impl/impl-ref-20175.rs similarity index 100% rename from tests/rustdoc/impl/impl-ref-20175.rs rename to tests/rustdoc-html/impl/impl-ref-20175.rs diff --git a/tests/rustdoc/impl/impl-trait-43869.rs b/tests/rustdoc-html/impl/impl-trait-43869.rs similarity index 100% rename from tests/rustdoc/impl/impl-trait-43869.rs rename to tests/rustdoc-html/impl/impl-trait-43869.rs diff --git a/tests/rustdoc/impl/impl-trait-alias.rs b/tests/rustdoc-html/impl/impl-trait-alias.rs similarity index 100% rename from tests/rustdoc/impl/impl-trait-alias.rs rename to tests/rustdoc-html/impl/impl-trait-alias.rs diff --git a/tests/rustdoc/impl/impl-trait-precise-capturing.rs b/tests/rustdoc-html/impl/impl-trait-precise-capturing.rs similarity index 100% rename from tests/rustdoc/impl/impl-trait-precise-capturing.rs rename to tests/rustdoc-html/impl/impl-trait-precise-capturing.rs diff --git a/tests/rustdoc/impl/impl-type-parameter-33592.rs b/tests/rustdoc-html/impl/impl-type-parameter-33592.rs similarity index 100% rename from tests/rustdoc/impl/impl-type-parameter-33592.rs rename to tests/rustdoc-html/impl/impl-type-parameter-33592.rs diff --git a/tests/rustdoc/impl/implementor-stable-version.rs b/tests/rustdoc-html/impl/implementor-stable-version.rs similarity index 100% rename from tests/rustdoc/impl/implementor-stable-version.rs rename to tests/rustdoc-html/impl/implementor-stable-version.rs diff --git a/tests/rustdoc/impl/implementors-unstable-75588.rs b/tests/rustdoc-html/impl/implementors-unstable-75588.rs similarity index 100% rename from tests/rustdoc/impl/implementors-unstable-75588.rs rename to tests/rustdoc-html/impl/implementors-unstable-75588.rs diff --git a/tests/rustdoc/impl/inline-impl-through-glob-import-100204.rs b/tests/rustdoc-html/impl/inline-impl-through-glob-import-100204.rs similarity index 100% rename from tests/rustdoc/impl/inline-impl-through-glob-import-100204.rs rename to tests/rustdoc-html/impl/inline-impl-through-glob-import-100204.rs diff --git a/tests/rustdoc/impl/manual_impl.rs b/tests/rustdoc-html/impl/manual_impl.rs similarity index 100% rename from tests/rustdoc/impl/manual_impl.rs rename to tests/rustdoc-html/impl/manual_impl.rs diff --git a/tests/rustdoc/impl/method-link-foreign-trait-impl-17476.rs b/tests/rustdoc-html/impl/method-link-foreign-trait-impl-17476.rs similarity index 100% rename from tests/rustdoc/impl/method-link-foreign-trait-impl-17476.rs rename to tests/rustdoc-html/impl/method-link-foreign-trait-impl-17476.rs diff --git a/tests/rustdoc/impl/module-impls.rs b/tests/rustdoc-html/impl/module-impls.rs similarity index 100% rename from tests/rustdoc/impl/module-impls.rs rename to tests/rustdoc-html/impl/module-impls.rs diff --git a/tests/rustdoc/impl/must_implement_one_of.rs b/tests/rustdoc-html/impl/must_implement_one_of.rs similarity index 100% rename from tests/rustdoc/impl/must_implement_one_of.rs rename to tests/rustdoc-html/impl/must_implement_one_of.rs diff --git a/tests/rustdoc/impl/negative-impl-no-items.rs b/tests/rustdoc-html/impl/negative-impl-no-items.rs similarity index 100% rename from tests/rustdoc/impl/negative-impl-no-items.rs rename to tests/rustdoc-html/impl/negative-impl-no-items.rs diff --git a/tests/rustdoc/impl/negative-impl-sidebar.rs b/tests/rustdoc-html/impl/negative-impl-sidebar.rs similarity index 100% rename from tests/rustdoc/impl/negative-impl-sidebar.rs rename to tests/rustdoc-html/impl/negative-impl-sidebar.rs diff --git a/tests/rustdoc/impl/negative-impl.rs b/tests/rustdoc-html/impl/negative-impl.rs similarity index 100% rename from tests/rustdoc/impl/negative-impl.rs rename to tests/rustdoc-html/impl/negative-impl.rs diff --git a/tests/rustdoc/impl/return-impl-trait.rs b/tests/rustdoc-html/impl/return-impl-trait.rs similarity index 100% rename from tests/rustdoc/impl/return-impl-trait.rs rename to tests/rustdoc-html/impl/return-impl-trait.rs diff --git a/tests/rustdoc/impl/rustc-incoherent-impls.rs b/tests/rustdoc-html/impl/rustc-incoherent-impls.rs similarity index 100% rename from tests/rustdoc/impl/rustc-incoherent-impls.rs rename to tests/rustdoc-html/impl/rustc-incoherent-impls.rs diff --git a/tests/rustdoc/impl/same-crate-hidden-impl-parameter.rs b/tests/rustdoc-html/impl/same-crate-hidden-impl-parameter.rs similarity index 100% rename from tests/rustdoc/impl/same-crate-hidden-impl-parameter.rs rename to tests/rustdoc-html/impl/same-crate-hidden-impl-parameter.rs diff --git a/tests/rustdoc/impl/sidebar-trait-impl-disambiguate-78701.rs b/tests/rustdoc-html/impl/sidebar-trait-impl-disambiguate-78701.rs similarity index 100% rename from tests/rustdoc/impl/sidebar-trait-impl-disambiguate-78701.rs rename to tests/rustdoc-html/impl/sidebar-trait-impl-disambiguate-78701.rs diff --git a/tests/rustdoc/impl/struct-implementations-title.rs b/tests/rustdoc-html/impl/struct-implementations-title.rs similarity index 100% rename from tests/rustdoc/impl/struct-implementations-title.rs rename to tests/rustdoc-html/impl/struct-implementations-title.rs diff --git a/tests/rustdoc/impl/trait-impl.rs b/tests/rustdoc-html/impl/trait-impl.rs similarity index 100% rename from tests/rustdoc/impl/trait-impl.rs rename to tests/rustdoc-html/impl/trait-impl.rs diff --git a/tests/rustdoc/impl/trait-implementations-duplicate-self-45584.rs b/tests/rustdoc-html/impl/trait-implementations-duplicate-self-45584.rs similarity index 100% rename from tests/rustdoc/impl/trait-implementations-duplicate-self-45584.rs rename to tests/rustdoc-html/impl/trait-implementations-duplicate-self-45584.rs diff --git a/tests/rustdoc/impl/underscore-type-in-trait-impl-96381.rs b/tests/rustdoc-html/impl/underscore-type-in-trait-impl-96381.rs similarity index 100% rename from tests/rustdoc/impl/underscore-type-in-trait-impl-96381.rs rename to tests/rustdoc-html/impl/underscore-type-in-trait-impl-96381.rs diff --git a/tests/rustdoc/impl/universal-impl-trait.rs b/tests/rustdoc-html/impl/universal-impl-trait.rs similarity index 100% rename from tests/rustdoc/impl/universal-impl-trait.rs rename to tests/rustdoc-html/impl/universal-impl-trait.rs diff --git a/tests/rustdoc/impl/unneeded-trait-implementations-title.rs b/tests/rustdoc-html/impl/unneeded-trait-implementations-title.rs similarity index 100% rename from tests/rustdoc/impl/unneeded-trait-implementations-title.rs rename to tests/rustdoc-html/impl/unneeded-trait-implementations-title.rs diff --git a/tests/rustdoc/import-remapped-paths.rs b/tests/rustdoc-html/import-remapped-paths.rs similarity index 100% rename from tests/rustdoc/import-remapped-paths.rs rename to tests/rustdoc-html/import-remapped-paths.rs diff --git a/tests/rustdoc/impossible-default.rs b/tests/rustdoc-html/impossible-default.rs similarity index 100% rename from tests/rustdoc/impossible-default.rs rename to tests/rustdoc-html/impossible-default.rs diff --git a/tests/rustdoc/include_str_cut.rs b/tests/rustdoc-html/include_str_cut.rs similarity index 100% rename from tests/rustdoc/include_str_cut.rs rename to tests/rustdoc-html/include_str_cut.rs diff --git a/tests/rustdoc/index-page.rs b/tests/rustdoc-html/index-page.rs similarity index 100% rename from tests/rustdoc/index-page.rs rename to tests/rustdoc-html/index-page.rs diff --git a/tests/rustdoc/infinite-redirection-16265-1.rs b/tests/rustdoc-html/infinite-redirection-16265-1.rs similarity index 100% rename from tests/rustdoc/infinite-redirection-16265-1.rs rename to tests/rustdoc-html/infinite-redirection-16265-1.rs diff --git a/tests/rustdoc/infinite-redirection-16265-2.rs b/tests/rustdoc-html/infinite-redirection-16265-2.rs similarity index 100% rename from tests/rustdoc/infinite-redirection-16265-2.rs rename to tests/rustdoc-html/infinite-redirection-16265-2.rs diff --git a/tests/rustdoc/infinite-redirection.rs b/tests/rustdoc-html/infinite-redirection.rs similarity index 100% rename from tests/rustdoc/infinite-redirection.rs rename to tests/rustdoc-html/infinite-redirection.rs diff --git a/tests/rustdoc/inherent-projections.rs b/tests/rustdoc-html/inherent-projections.rs similarity index 100% rename from tests/rustdoc/inherent-projections.rs rename to tests/rustdoc-html/inherent-projections.rs diff --git a/tests/rustdoc/inline-default-methods.rs b/tests/rustdoc-html/inline-default-methods.rs similarity index 100% rename from tests/rustdoc/inline-default-methods.rs rename to tests/rustdoc-html/inline-default-methods.rs diff --git a/tests/rustdoc/inline-rename-34473.rs b/tests/rustdoc-html/inline-rename-34473.rs similarity index 100% rename from tests/rustdoc/inline-rename-34473.rs rename to tests/rustdoc-html/inline-rename-34473.rs diff --git a/tests/rustdoc/inline_cross/add-docs.rs b/tests/rustdoc-html/inline_cross/add-docs.rs similarity index 100% rename from tests/rustdoc/inline_cross/add-docs.rs rename to tests/rustdoc-html/inline_cross/add-docs.rs diff --git a/tests/rustdoc/inline_cross/assoc-const-equality.rs b/tests/rustdoc-html/inline_cross/assoc-const-equality.rs similarity index 100% rename from tests/rustdoc/inline_cross/assoc-const-equality.rs rename to tests/rustdoc-html/inline_cross/assoc-const-equality.rs diff --git a/tests/rustdoc/inline_cross/assoc-items.rs b/tests/rustdoc-html/inline_cross/assoc-items.rs similarity index 100% rename from tests/rustdoc/inline_cross/assoc-items.rs rename to tests/rustdoc-html/inline_cross/assoc-items.rs diff --git a/tests/rustdoc/inline_cross/assoc_item_trait_bounds.out0.html b/tests/rustdoc-html/inline_cross/assoc_item_trait_bounds.out0.html similarity index 100% rename from tests/rustdoc/inline_cross/assoc_item_trait_bounds.out0.html rename to tests/rustdoc-html/inline_cross/assoc_item_trait_bounds.out0.html diff --git a/tests/rustdoc/inline_cross/assoc_item_trait_bounds.out2.html b/tests/rustdoc-html/inline_cross/assoc_item_trait_bounds.out2.html similarity index 100% rename from tests/rustdoc/inline_cross/assoc_item_trait_bounds.out2.html rename to tests/rustdoc-html/inline_cross/assoc_item_trait_bounds.out2.html diff --git a/tests/rustdoc/inline_cross/assoc_item_trait_bounds.out9.html b/tests/rustdoc-html/inline_cross/assoc_item_trait_bounds.out9.html similarity index 100% rename from tests/rustdoc/inline_cross/assoc_item_trait_bounds.out9.html rename to tests/rustdoc-html/inline_cross/assoc_item_trait_bounds.out9.html diff --git a/tests/rustdoc/inline_cross/assoc_item_trait_bounds.rs b/tests/rustdoc-html/inline_cross/assoc_item_trait_bounds.rs similarity index 100% rename from tests/rustdoc/inline_cross/assoc_item_trait_bounds.rs rename to tests/rustdoc-html/inline_cross/assoc_item_trait_bounds.rs diff --git a/tests/rustdoc/inline_cross/async-fn.rs b/tests/rustdoc-html/inline_cross/async-fn.rs similarity index 100% rename from tests/rustdoc/inline_cross/async-fn.rs rename to tests/rustdoc-html/inline_cross/async-fn.rs diff --git a/tests/rustdoc/inline_cross/attributes.rs b/tests/rustdoc-html/inline_cross/attributes.rs similarity index 100% rename from tests/rustdoc/inline_cross/attributes.rs rename to tests/rustdoc-html/inline_cross/attributes.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/add-docs.rs b/tests/rustdoc-html/inline_cross/auxiliary/add-docs.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/add-docs.rs rename to tests/rustdoc-html/inline_cross/auxiliary/add-docs.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/assoc-const-equality.rs b/tests/rustdoc-html/inline_cross/auxiliary/assoc-const-equality.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/assoc-const-equality.rs rename to tests/rustdoc-html/inline_cross/auxiliary/assoc-const-equality.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/assoc-items.rs b/tests/rustdoc-html/inline_cross/auxiliary/assoc-items.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/assoc-items.rs rename to tests/rustdoc-html/inline_cross/auxiliary/assoc-items.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds.rs b/tests/rustdoc-html/inline_cross/auxiliary/assoc_item_trait_bounds.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds.rs rename to tests/rustdoc-html/inline_cross/auxiliary/assoc_item_trait_bounds.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/async-fn.rs b/tests/rustdoc-html/inline_cross/auxiliary/async-fn.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/async-fn.rs rename to tests/rustdoc-html/inline_cross/auxiliary/async-fn.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/attributes.rs b/tests/rustdoc-html/inline_cross/auxiliary/attributes.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/attributes.rs rename to tests/rustdoc-html/inline_cross/auxiliary/attributes.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/const-effect-param.rs b/tests/rustdoc-html/inline_cross/auxiliary/const-effect-param.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/const-effect-param.rs rename to tests/rustdoc-html/inline_cross/auxiliary/const-effect-param.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/cross-glob.rs b/tests/rustdoc-html/inline_cross/auxiliary/cross-glob.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/cross-glob.rs rename to tests/rustdoc-html/inline_cross/auxiliary/cross-glob.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/default-generic-args.rs b/tests/rustdoc-html/inline_cross/auxiliary/default-generic-args.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/default-generic-args.rs rename to tests/rustdoc-html/inline_cross/auxiliary/default-generic-args.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/default-trait-method.rs b/tests/rustdoc-html/inline_cross/auxiliary/default-trait-method.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/default-trait-method.rs rename to tests/rustdoc-html/inline_cross/auxiliary/default-trait-method.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/doc-auto-cfg.rs b/tests/rustdoc-html/inline_cross/auxiliary/doc-auto-cfg.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/doc-auto-cfg.rs rename to tests/rustdoc-html/inline_cross/auxiliary/doc-auto-cfg.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/dyn_trait.rs b/tests/rustdoc-html/inline_cross/auxiliary/dyn_trait.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/dyn_trait.rs rename to tests/rustdoc-html/inline_cross/auxiliary/dyn_trait.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/early-late-bound-lifetime-params.rs b/tests/rustdoc-html/inline_cross/auxiliary/early-late-bound-lifetime-params.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/early-late-bound-lifetime-params.rs rename to tests/rustdoc-html/inline_cross/auxiliary/early-late-bound-lifetime-params.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/fn-ptr-ty.rs b/tests/rustdoc-html/inline_cross/auxiliary/fn-ptr-ty.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/fn-ptr-ty.rs rename to tests/rustdoc-html/inline_cross/auxiliary/fn-ptr-ty.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/generic-const-items.rs b/tests/rustdoc-html/inline_cross/auxiliary/generic-const-items.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/generic-const-items.rs rename to tests/rustdoc-html/inline_cross/auxiliary/generic-const-items.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/impl-inline-without-trait.rs b/tests/rustdoc-html/inline_cross/auxiliary/impl-inline-without-trait.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/impl-inline-without-trait.rs rename to tests/rustdoc-html/inline_cross/auxiliary/impl-inline-without-trait.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/impl-sized.rs b/tests/rustdoc-html/inline_cross/auxiliary/impl-sized.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/impl-sized.rs rename to tests/rustdoc-html/inline_cross/auxiliary/impl-sized.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs b/tests/rustdoc-html/inline_cross/auxiliary/impl_trait_aux.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs rename to tests/rustdoc-html/inline_cross/auxiliary/impl_trait_aux.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/implementors_inline.rs b/tests/rustdoc-html/inline_cross/auxiliary/implementors_inline.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/implementors_inline.rs rename to tests/rustdoc-html/inline_cross/auxiliary/implementors_inline.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/issue-21801.rs b/tests/rustdoc-html/inline_cross/auxiliary/issue-21801.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/issue-21801.rs rename to tests/rustdoc-html/inline_cross/auxiliary/issue-21801.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/issue-23207-1.rs b/tests/rustdoc-html/inline_cross/auxiliary/issue-23207-1.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/issue-23207-1.rs rename to tests/rustdoc-html/inline_cross/auxiliary/issue-23207-1.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/issue-23207-2.rs b/tests/rustdoc-html/inline_cross/auxiliary/issue-23207-2.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/issue-23207-2.rs rename to tests/rustdoc-html/inline_cross/auxiliary/issue-23207-2.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/issue-24183.rs b/tests/rustdoc-html/inline_cross/auxiliary/issue-24183.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/issue-24183.rs rename to tests/rustdoc-html/inline_cross/auxiliary/issue-24183.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/issue-27362-aux.rs b/tests/rustdoc-html/inline_cross/auxiliary/issue-27362-aux.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/issue-27362-aux.rs rename to tests/rustdoc-html/inline_cross/auxiliary/issue-27362-aux.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/issue-29584.rs b/tests/rustdoc-html/inline_cross/auxiliary/issue-29584.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/issue-29584.rs rename to tests/rustdoc-html/inline_cross/auxiliary/issue-29584.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/issue-33113.rs b/tests/rustdoc-html/inline_cross/auxiliary/issue-33113.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/issue-33113.rs rename to tests/rustdoc-html/inline_cross/auxiliary/issue-33113.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/issue-46727.rs b/tests/rustdoc-html/inline_cross/auxiliary/issue-46727.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/issue-46727.rs rename to tests/rustdoc-html/inline_cross/auxiliary/issue-46727.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/issue-57180.rs b/tests/rustdoc-html/inline_cross/auxiliary/issue-57180.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/issue-57180.rs rename to tests/rustdoc-html/inline_cross/auxiliary/issue-57180.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/issue-76736-1.rs b/tests/rustdoc-html/inline_cross/auxiliary/issue-76736-1.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/issue-76736-1.rs rename to tests/rustdoc-html/inline_cross/auxiliary/issue-76736-1.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/issue-76736-2.rs b/tests/rustdoc-html/inline_cross/auxiliary/issue-76736-2.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/issue-76736-2.rs rename to tests/rustdoc-html/inline_cross/auxiliary/issue-76736-2.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/issue-85454.rs b/tests/rustdoc-html/inline_cross/auxiliary/issue-85454.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/issue-85454.rs rename to tests/rustdoc-html/inline_cross/auxiliary/issue-85454.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/macro-vis.rs b/tests/rustdoc-html/inline_cross/auxiliary/macro-vis.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/macro-vis.rs rename to tests/rustdoc-html/inline_cross/auxiliary/macro-vis.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/macros.rs b/tests/rustdoc-html/inline_cross/auxiliary/macros.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/macros.rs rename to tests/rustdoc-html/inline_cross/auxiliary/macros.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/non_lifetime_binders.rs b/tests/rustdoc-html/inline_cross/auxiliary/non_lifetime_binders.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/non_lifetime_binders.rs rename to tests/rustdoc-html/inline_cross/auxiliary/non_lifetime_binders.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/proc_macro.rs b/tests/rustdoc-html/inline_cross/auxiliary/proc_macro.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/proc_macro.rs rename to tests/rustdoc-html/inline_cross/auxiliary/proc_macro.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/reexport-with-anonymous-lifetime-98697.rs b/tests/rustdoc-html/inline_cross/auxiliary/reexport-with-anonymous-lifetime-98697.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/reexport-with-anonymous-lifetime-98697.rs rename to tests/rustdoc-html/inline_cross/auxiliary/reexport-with-anonymous-lifetime-98697.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/renamed-via-module.rs b/tests/rustdoc-html/inline_cross/auxiliary/renamed-via-module.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/renamed-via-module.rs rename to tests/rustdoc-html/inline_cross/auxiliary/renamed-via-module.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/ret-pos-impl-trait-in-trait.rs b/tests/rustdoc-html/inline_cross/auxiliary/ret-pos-impl-trait-in-trait.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/ret-pos-impl-trait-in-trait.rs rename to tests/rustdoc-html/inline_cross/auxiliary/ret-pos-impl-trait-in-trait.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/rustdoc-hidden-sig.rs b/tests/rustdoc-html/inline_cross/auxiliary/rustdoc-hidden-sig.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/rustdoc-hidden-sig.rs rename to tests/rustdoc-html/inline_cross/auxiliary/rustdoc-hidden-sig.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/rustdoc-hidden.rs b/tests/rustdoc-html/inline_cross/auxiliary/rustdoc-hidden.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/rustdoc-hidden.rs rename to tests/rustdoc-html/inline_cross/auxiliary/rustdoc-hidden.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/rustdoc-nonreachable-impls.rs b/tests/rustdoc-html/inline_cross/auxiliary/rustdoc-nonreachable-impls.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/rustdoc-nonreachable-impls.rs rename to tests/rustdoc-html/inline_cross/auxiliary/rustdoc-nonreachable-impls.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/rustdoc-trait-object-impl.rs b/tests/rustdoc-html/inline_cross/auxiliary/rustdoc-trait-object-impl.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/rustdoc-trait-object-impl.rs rename to tests/rustdoc-html/inline_cross/auxiliary/rustdoc-trait-object-impl.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/trait-vis.rs b/tests/rustdoc-html/inline_cross/auxiliary/trait-vis.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/trait-vis.rs rename to tests/rustdoc-html/inline_cross/auxiliary/trait-vis.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/use_crate.rs b/tests/rustdoc-html/inline_cross/auxiliary/use_crate.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/use_crate.rs rename to tests/rustdoc-html/inline_cross/auxiliary/use_crate.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/use_crate_2.rs b/tests/rustdoc-html/inline_cross/auxiliary/use_crate_2.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/use_crate_2.rs rename to tests/rustdoc-html/inline_cross/auxiliary/use_crate_2.rs diff --git a/tests/rustdoc/inline_cross/const-effect-param.rs b/tests/rustdoc-html/inline_cross/const-effect-param.rs similarity index 100% rename from tests/rustdoc/inline_cross/const-effect-param.rs rename to tests/rustdoc-html/inline_cross/const-effect-param.rs diff --git a/tests/rustdoc/inline_cross/const-eval-46727.rs b/tests/rustdoc-html/inline_cross/const-eval-46727.rs similarity index 100% rename from tests/rustdoc/inline_cross/const-eval-46727.rs rename to tests/rustdoc-html/inline_cross/const-eval-46727.rs diff --git a/tests/rustdoc/inline_cross/const-fn-27362.rs b/tests/rustdoc-html/inline_cross/const-fn-27362.rs similarity index 100% rename from tests/rustdoc/inline_cross/const-fn-27362.rs rename to tests/rustdoc-html/inline_cross/const-fn-27362.rs diff --git a/tests/rustdoc/inline_cross/cross-glob.rs b/tests/rustdoc-html/inline_cross/cross-glob.rs similarity index 100% rename from tests/rustdoc/inline_cross/cross-glob.rs rename to tests/rustdoc-html/inline_cross/cross-glob.rs diff --git a/tests/rustdoc/inline_cross/deduplicate-inlined-items-23207.rs b/tests/rustdoc-html/inline_cross/deduplicate-inlined-items-23207.rs similarity index 100% rename from tests/rustdoc/inline_cross/deduplicate-inlined-items-23207.rs rename to tests/rustdoc-html/inline_cross/deduplicate-inlined-items-23207.rs diff --git a/tests/rustdoc/inline_cross/default-generic-args.rs b/tests/rustdoc-html/inline_cross/default-generic-args.rs similarity index 100% rename from tests/rustdoc/inline_cross/default-generic-args.rs rename to tests/rustdoc-html/inline_cross/default-generic-args.rs diff --git a/tests/rustdoc/inline_cross/default-trait-method.rs b/tests/rustdoc-html/inline_cross/default-trait-method.rs similarity index 100% rename from tests/rustdoc/inline_cross/default-trait-method.rs rename to tests/rustdoc-html/inline_cross/default-trait-method.rs diff --git a/tests/rustdoc/inline_cross/doc-auto-cfg.rs b/tests/rustdoc-html/inline_cross/doc-auto-cfg.rs similarity index 100% rename from tests/rustdoc/inline_cross/doc-auto-cfg.rs rename to tests/rustdoc-html/inline_cross/doc-auto-cfg.rs diff --git a/tests/rustdoc/inline_cross/doc-hidden-broken-link-28480.rs b/tests/rustdoc-html/inline_cross/doc-hidden-broken-link-28480.rs similarity index 100% rename from tests/rustdoc/inline_cross/doc-hidden-broken-link-28480.rs rename to tests/rustdoc-html/inline_cross/doc-hidden-broken-link-28480.rs diff --git a/tests/rustdoc/inline_cross/doc-hidden-extern-trait-impl-29584.rs b/tests/rustdoc-html/inline_cross/doc-hidden-extern-trait-impl-29584.rs similarity index 100% rename from tests/rustdoc/inline_cross/doc-hidden-extern-trait-impl-29584.rs rename to tests/rustdoc-html/inline_cross/doc-hidden-extern-trait-impl-29584.rs diff --git a/tests/rustdoc/inline_cross/doc-reachability-impl-31948-1.rs b/tests/rustdoc-html/inline_cross/doc-reachability-impl-31948-1.rs similarity index 100% rename from tests/rustdoc/inline_cross/doc-reachability-impl-31948-1.rs rename to tests/rustdoc-html/inline_cross/doc-reachability-impl-31948-1.rs diff --git a/tests/rustdoc/inline_cross/doc-reachability-impl-31948-2.rs b/tests/rustdoc-html/inline_cross/doc-reachability-impl-31948-2.rs similarity index 100% rename from tests/rustdoc/inline_cross/doc-reachability-impl-31948-2.rs rename to tests/rustdoc-html/inline_cross/doc-reachability-impl-31948-2.rs diff --git a/tests/rustdoc/inline_cross/doc-reachability-impl-31948.rs b/tests/rustdoc-html/inline_cross/doc-reachability-impl-31948.rs similarity index 100% rename from tests/rustdoc/inline_cross/doc-reachability-impl-31948.rs rename to tests/rustdoc-html/inline_cross/doc-reachability-impl-31948.rs diff --git a/tests/rustdoc/inline_cross/dyn_trait.rs b/tests/rustdoc-html/inline_cross/dyn_trait.rs similarity index 100% rename from tests/rustdoc/inline_cross/dyn_trait.rs rename to tests/rustdoc-html/inline_cross/dyn_trait.rs diff --git a/tests/rustdoc/inline_cross/early-late-bound-lifetime-params.rs b/tests/rustdoc-html/inline_cross/early-late-bound-lifetime-params.rs similarity index 100% rename from tests/rustdoc/inline_cross/early-late-bound-lifetime-params.rs rename to tests/rustdoc-html/inline_cross/early-late-bound-lifetime-params.rs diff --git a/tests/rustdoc/inline_cross/fn-ptr-ty.rs b/tests/rustdoc-html/inline_cross/fn-ptr-ty.rs similarity index 100% rename from tests/rustdoc/inline_cross/fn-ptr-ty.rs rename to tests/rustdoc-html/inline_cross/fn-ptr-ty.rs diff --git a/tests/rustdoc/inline_cross/generic-const-items.rs b/tests/rustdoc-html/inline_cross/generic-const-items.rs similarity index 100% rename from tests/rustdoc/inline_cross/generic-const-items.rs rename to tests/rustdoc-html/inline_cross/generic-const-items.rs diff --git a/tests/rustdoc/inline_cross/hidden-use.rs b/tests/rustdoc-html/inline_cross/hidden-use.rs similarity index 100% rename from tests/rustdoc/inline_cross/hidden-use.rs rename to tests/rustdoc-html/inline_cross/hidden-use.rs diff --git a/tests/rustdoc/inline_cross/ice-import-crate-57180.rs b/tests/rustdoc-html/inline_cross/ice-import-crate-57180.rs similarity index 100% rename from tests/rustdoc/inline_cross/ice-import-crate-57180.rs rename to tests/rustdoc-html/inline_cross/ice-import-crate-57180.rs diff --git a/tests/rustdoc/inline_cross/impl-dyn-trait-32881.rs b/tests/rustdoc-html/inline_cross/impl-dyn-trait-32881.rs similarity index 100% rename from tests/rustdoc/inline_cross/impl-dyn-trait-32881.rs rename to tests/rustdoc-html/inline_cross/impl-dyn-trait-32881.rs diff --git a/tests/rustdoc/inline_cross/impl-inline-without-trait.rs b/tests/rustdoc-html/inline_cross/impl-inline-without-trait.rs similarity index 100% rename from tests/rustdoc/inline_cross/impl-inline-without-trait.rs rename to tests/rustdoc-html/inline_cross/impl-inline-without-trait.rs diff --git a/tests/rustdoc/inline_cross/impl-ref-33113.rs b/tests/rustdoc-html/inline_cross/impl-ref-33113.rs similarity index 100% rename from tests/rustdoc/inline_cross/impl-ref-33113.rs rename to tests/rustdoc-html/inline_cross/impl-ref-33113.rs diff --git a/tests/rustdoc/inline_cross/impl-sized.rs b/tests/rustdoc-html/inline_cross/impl-sized.rs similarity index 100% rename from tests/rustdoc/inline_cross/impl-sized.rs rename to tests/rustdoc-html/inline_cross/impl-sized.rs diff --git a/tests/rustdoc/inline_cross/impl_trait.rs b/tests/rustdoc-html/inline_cross/impl_trait.rs similarity index 100% rename from tests/rustdoc/inline_cross/impl_trait.rs rename to tests/rustdoc-html/inline_cross/impl_trait.rs diff --git a/tests/rustdoc/inline_cross/implementors-js.rs b/tests/rustdoc-html/inline_cross/implementors-js.rs similarity index 100% rename from tests/rustdoc/inline_cross/implementors-js.rs rename to tests/rustdoc-html/inline_cross/implementors-js.rs diff --git a/tests/rustdoc/inline_cross/inline_hidden.rs b/tests/rustdoc-html/inline_cross/inline_hidden.rs similarity index 100% rename from tests/rustdoc/inline_cross/inline_hidden.rs rename to tests/rustdoc-html/inline_cross/inline_hidden.rs diff --git a/tests/rustdoc/inline_cross/macro-vis.rs b/tests/rustdoc-html/inline_cross/macro-vis.rs similarity index 100% rename from tests/rustdoc/inline_cross/macro-vis.rs rename to tests/rustdoc-html/inline_cross/macro-vis.rs diff --git a/tests/rustdoc/inline_cross/macros.rs b/tests/rustdoc-html/inline_cross/macros.rs similarity index 100% rename from tests/rustdoc/inline_cross/macros.rs rename to tests/rustdoc-html/inline_cross/macros.rs diff --git a/tests/rustdoc/inline_cross/non_lifetime_binders.rs b/tests/rustdoc-html/inline_cross/non_lifetime_binders.rs similarity index 100% rename from tests/rustdoc/inline_cross/non_lifetime_binders.rs rename to tests/rustdoc-html/inline_cross/non_lifetime_binders.rs diff --git a/tests/rustdoc/inline_cross/proc_macro.rs b/tests/rustdoc-html/inline_cross/proc_macro.rs similarity index 100% rename from tests/rustdoc/inline_cross/proc_macro.rs rename to tests/rustdoc-html/inline_cross/proc_macro.rs diff --git a/tests/rustdoc/inline_cross/qpath-self-85454.rs b/tests/rustdoc-html/inline_cross/qpath-self-85454.rs similarity index 100% rename from tests/rustdoc/inline_cross/qpath-self-85454.rs rename to tests/rustdoc-html/inline_cross/qpath-self-85454.rs diff --git a/tests/rustdoc/inline_cross/reexport-with-anonymous-lifetime-98697.rs b/tests/rustdoc-html/inline_cross/reexport-with-anonymous-lifetime-98697.rs similarity index 100% rename from tests/rustdoc/inline_cross/reexport-with-anonymous-lifetime-98697.rs rename to tests/rustdoc-html/inline_cross/reexport-with-anonymous-lifetime-98697.rs diff --git a/tests/rustdoc/inline_cross/renamed-via-module.rs b/tests/rustdoc-html/inline_cross/renamed-via-module.rs similarity index 100% rename from tests/rustdoc/inline_cross/renamed-via-module.rs rename to tests/rustdoc-html/inline_cross/renamed-via-module.rs diff --git a/tests/rustdoc/inline_cross/ret-pos-impl-trait-in-trait.rs b/tests/rustdoc-html/inline_cross/ret-pos-impl-trait-in-trait.rs similarity index 100% rename from tests/rustdoc/inline_cross/ret-pos-impl-trait-in-trait.rs rename to tests/rustdoc-html/inline_cross/ret-pos-impl-trait-in-trait.rs diff --git a/tests/rustdoc/inline_cross/rustc-private-76736-1.rs b/tests/rustdoc-html/inline_cross/rustc-private-76736-1.rs similarity index 100% rename from tests/rustdoc/inline_cross/rustc-private-76736-1.rs rename to tests/rustdoc-html/inline_cross/rustc-private-76736-1.rs diff --git a/tests/rustdoc/inline_cross/rustc-private-76736-2.rs b/tests/rustdoc-html/inline_cross/rustc-private-76736-2.rs similarity index 100% rename from tests/rustdoc/inline_cross/rustc-private-76736-2.rs rename to tests/rustdoc-html/inline_cross/rustc-private-76736-2.rs diff --git a/tests/rustdoc/inline_cross/rustc-private-76736-3.rs b/tests/rustdoc-html/inline_cross/rustc-private-76736-3.rs similarity index 100% rename from tests/rustdoc/inline_cross/rustc-private-76736-3.rs rename to tests/rustdoc-html/inline_cross/rustc-private-76736-3.rs diff --git a/tests/rustdoc/inline_cross/rustc-private-76736-4.rs b/tests/rustdoc-html/inline_cross/rustc-private-76736-4.rs similarity index 100% rename from tests/rustdoc/inline_cross/rustc-private-76736-4.rs rename to tests/rustdoc-html/inline_cross/rustc-private-76736-4.rs diff --git a/tests/rustdoc/inline_cross/self-sized-bounds-24183.method_no_where_self_sized.html b/tests/rustdoc-html/inline_cross/self-sized-bounds-24183.method_no_where_self_sized.html similarity index 100% rename from tests/rustdoc/inline_cross/self-sized-bounds-24183.method_no_where_self_sized.html rename to tests/rustdoc-html/inline_cross/self-sized-bounds-24183.method_no_where_self_sized.html diff --git a/tests/rustdoc/inline_cross/self-sized-bounds-24183.rs b/tests/rustdoc-html/inline_cross/self-sized-bounds-24183.rs similarity index 100% rename from tests/rustdoc/inline_cross/self-sized-bounds-24183.rs rename to tests/rustdoc-html/inline_cross/self-sized-bounds-24183.rs diff --git a/tests/rustdoc/inline_cross/sugar-closure-crate-21801.rs b/tests/rustdoc-html/inline_cross/sugar-closure-crate-21801.rs similarity index 100% rename from tests/rustdoc/inline_cross/sugar-closure-crate-21801.rs rename to tests/rustdoc-html/inline_cross/sugar-closure-crate-21801.rs diff --git a/tests/rustdoc/inline_cross/trait-vis.rs b/tests/rustdoc-html/inline_cross/trait-vis.rs similarity index 100% rename from tests/rustdoc/inline_cross/trait-vis.rs rename to tests/rustdoc-html/inline_cross/trait-vis.rs diff --git a/tests/rustdoc/inline_cross/use_crate.rs b/tests/rustdoc-html/inline_cross/use_crate.rs similarity index 100% rename from tests/rustdoc/inline_cross/use_crate.rs rename to tests/rustdoc-html/inline_cross/use_crate.rs diff --git a/tests/rustdoc/inline_local/blanket-impl-reexported-trait-94183.rs b/tests/rustdoc-html/inline_local/blanket-impl-reexported-trait-94183.rs similarity index 100% rename from tests/rustdoc/inline_local/blanket-impl-reexported-trait-94183.rs rename to tests/rustdoc-html/inline_local/blanket-impl-reexported-trait-94183.rs diff --git a/tests/rustdoc/inline_local/doc-no-inline-32343.rs b/tests/rustdoc-html/inline_local/doc-no-inline-32343.rs similarity index 100% rename from tests/rustdoc/inline_local/doc-no-inline-32343.rs rename to tests/rustdoc-html/inline_local/doc-no-inline-32343.rs diff --git a/tests/rustdoc/inline_local/enum-variant-reexport-46766.rs b/tests/rustdoc-html/inline_local/enum-variant-reexport-46766.rs similarity index 100% rename from tests/rustdoc/inline_local/enum-variant-reexport-46766.rs rename to tests/rustdoc-html/inline_local/enum-variant-reexport-46766.rs diff --git a/tests/rustdoc/inline_local/fully-stable-path-is-better.rs b/tests/rustdoc-html/inline_local/fully-stable-path-is-better.rs similarity index 100% rename from tests/rustdoc/inline_local/fully-stable-path-is-better.rs rename to tests/rustdoc-html/inline_local/fully-stable-path-is-better.rs diff --git a/tests/rustdoc/inline_local/glob-extern-document-private-items.rs b/tests/rustdoc-html/inline_local/glob-extern-document-private-items.rs similarity index 100% rename from tests/rustdoc/inline_local/glob-extern-document-private-items.rs rename to tests/rustdoc-html/inline_local/glob-extern-document-private-items.rs diff --git a/tests/rustdoc/inline_local/glob-extern.rs b/tests/rustdoc-html/inline_local/glob-extern.rs similarity index 100% rename from tests/rustdoc/inline_local/glob-extern.rs rename to tests/rustdoc-html/inline_local/glob-extern.rs diff --git a/tests/rustdoc/inline_local/glob-private-document-private-items.rs b/tests/rustdoc-html/inline_local/glob-private-document-private-items.rs similarity index 100% rename from tests/rustdoc/inline_local/glob-private-document-private-items.rs rename to tests/rustdoc-html/inline_local/glob-private-document-private-items.rs diff --git a/tests/rustdoc/inline_local/glob-private.rs b/tests/rustdoc-html/inline_local/glob-private.rs similarity index 100% rename from tests/rustdoc/inline_local/glob-private.rs rename to tests/rustdoc-html/inline_local/glob-private.rs diff --git a/tests/rustdoc/inline_local/hidden-use.rs b/tests/rustdoc-html/inline_local/hidden-use.rs similarity index 100% rename from tests/rustdoc/inline_local/hidden-use.rs rename to tests/rustdoc-html/inline_local/hidden-use.rs diff --git a/tests/rustdoc/inline_local/macro_by_example.rs b/tests/rustdoc-html/inline_local/macro_by_example.rs similarity index 100% rename from tests/rustdoc/inline_local/macro_by_example.rs rename to tests/rustdoc-html/inline_local/macro_by_example.rs diff --git a/tests/rustdoc/inline_local/parent-path-is-better.rs b/tests/rustdoc-html/inline_local/parent-path-is-better.rs similarity index 100% rename from tests/rustdoc/inline_local/parent-path-is-better.rs rename to tests/rustdoc-html/inline_local/parent-path-is-better.rs diff --git a/tests/rustdoc/inline_local/please_inline.rs b/tests/rustdoc-html/inline_local/please_inline.rs similarity index 100% rename from tests/rustdoc/inline_local/please_inline.rs rename to tests/rustdoc-html/inline_local/please_inline.rs diff --git a/tests/rustdoc/inline_local/private-reexport-in-public-api-81141-2.rs b/tests/rustdoc-html/inline_local/private-reexport-in-public-api-81141-2.rs similarity index 100% rename from tests/rustdoc/inline_local/private-reexport-in-public-api-81141-2.rs rename to tests/rustdoc-html/inline_local/private-reexport-in-public-api-81141-2.rs diff --git a/tests/rustdoc/inline_local/private-reexport-in-public-api-81141.rs b/tests/rustdoc-html/inline_local/private-reexport-in-public-api-81141.rs similarity index 100% rename from tests/rustdoc/inline_local/private-reexport-in-public-api-81141.rs rename to tests/rustdoc-html/inline_local/private-reexport-in-public-api-81141.rs diff --git a/tests/rustdoc/inline_local/private-reexport-in-public-api-generics-81141.rs b/tests/rustdoc-html/inline_local/private-reexport-in-public-api-generics-81141.rs similarity index 100% rename from tests/rustdoc/inline_local/private-reexport-in-public-api-generics-81141.rs rename to tests/rustdoc-html/inline_local/private-reexport-in-public-api-generics-81141.rs diff --git a/tests/rustdoc/inline_local/private-reexport-in-public-api-hidden-81141.rs b/tests/rustdoc-html/inline_local/private-reexport-in-public-api-hidden-81141.rs similarity index 100% rename from tests/rustdoc/inline_local/private-reexport-in-public-api-hidden-81141.rs rename to tests/rustdoc-html/inline_local/private-reexport-in-public-api-hidden-81141.rs diff --git a/tests/rustdoc/inline_local/private-reexport-in-public-api-private-81141.rs b/tests/rustdoc-html/inline_local/private-reexport-in-public-api-private-81141.rs similarity index 100% rename from tests/rustdoc/inline_local/private-reexport-in-public-api-private-81141.rs rename to tests/rustdoc-html/inline_local/private-reexport-in-public-api-private-81141.rs diff --git a/tests/rustdoc/inline_local/pub-re-export-28537.rs b/tests/rustdoc-html/inline_local/pub-re-export-28537.rs similarity index 100% rename from tests/rustdoc/inline_local/pub-re-export-28537.rs rename to tests/rustdoc-html/inline_local/pub-re-export-28537.rs diff --git a/tests/rustdoc/inline_local/reexported-macro-and-macro-export-sidebar-89852.rs b/tests/rustdoc-html/inline_local/reexported-macro-and-macro-export-sidebar-89852.rs similarity index 100% rename from tests/rustdoc/inline_local/reexported-macro-and-macro-export-sidebar-89852.rs rename to tests/rustdoc-html/inline_local/reexported-macro-and-macro-export-sidebar-89852.rs diff --git a/tests/rustdoc/inline_local/staged-inline.rs b/tests/rustdoc-html/inline_local/staged-inline.rs similarity index 100% rename from tests/rustdoc/inline_local/staged-inline.rs rename to tests/rustdoc-html/inline_local/staged-inline.rs diff --git a/tests/rustdoc/inline_local/trait-vis.rs b/tests/rustdoc-html/inline_local/trait-vis.rs similarity index 100% rename from tests/rustdoc/inline_local/trait-vis.rs rename to tests/rustdoc-html/inline_local/trait-vis.rs diff --git a/tests/rustdoc/internal.rs b/tests/rustdoc-html/internal.rs similarity index 100% rename from tests/rustdoc/internal.rs rename to tests/rustdoc-html/internal.rs diff --git a/tests/rustdoc/intra-doc-crate/auxiliary/self.rs b/tests/rustdoc-html/intra-doc-crate/auxiliary/self.rs similarity index 100% rename from tests/rustdoc/intra-doc-crate/auxiliary/self.rs rename to tests/rustdoc-html/intra-doc-crate/auxiliary/self.rs diff --git a/tests/rustdoc/intra-doc-crate/self.rs b/tests/rustdoc-html/intra-doc-crate/self.rs similarity index 100% rename from tests/rustdoc/intra-doc-crate/self.rs rename to tests/rustdoc-html/intra-doc-crate/self.rs diff --git a/tests/rustdoc/intra-doc/anchors.rs b/tests/rustdoc-html/intra-doc/anchors.rs similarity index 100% rename from tests/rustdoc/intra-doc/anchors.rs rename to tests/rustdoc-html/intra-doc/anchors.rs diff --git a/tests/rustdoc/intra-doc/assoc-reexport-super.rs b/tests/rustdoc-html/intra-doc/assoc-reexport-super.rs similarity index 100% rename from tests/rustdoc/intra-doc/assoc-reexport-super.rs rename to tests/rustdoc-html/intra-doc/assoc-reexport-super.rs diff --git a/tests/rustdoc/intra-doc/associated-defaults.rs b/tests/rustdoc-html/intra-doc/associated-defaults.rs similarity index 100% rename from tests/rustdoc/intra-doc/associated-defaults.rs rename to tests/rustdoc-html/intra-doc/associated-defaults.rs diff --git a/tests/rustdoc/intra-doc/associated-items.rs b/tests/rustdoc-html/intra-doc/associated-items.rs similarity index 100% rename from tests/rustdoc/intra-doc/associated-items.rs rename to tests/rustdoc-html/intra-doc/associated-items.rs diff --git a/tests/rustdoc/intra-doc/auxiliary/empty.rs b/tests/rustdoc-html/intra-doc/auxiliary/empty.rs similarity index 100% rename from tests/rustdoc/intra-doc/auxiliary/empty.rs rename to tests/rustdoc-html/intra-doc/auxiliary/empty.rs diff --git a/tests/rustdoc/intra-doc/auxiliary/empty2.rs b/tests/rustdoc-html/intra-doc/auxiliary/empty2.rs similarity index 100% rename from tests/rustdoc/intra-doc/auxiliary/empty2.rs rename to tests/rustdoc-html/intra-doc/auxiliary/empty2.rs diff --git a/tests/rustdoc/intra-doc/auxiliary/extern-builtin-type-impl-dep.rs b/tests/rustdoc-html/intra-doc/auxiliary/extern-builtin-type-impl-dep.rs similarity index 100% rename from tests/rustdoc/intra-doc/auxiliary/extern-builtin-type-impl-dep.rs rename to tests/rustdoc-html/intra-doc/auxiliary/extern-builtin-type-impl-dep.rs diff --git a/tests/rustdoc/intra-doc/auxiliary/extern-inherent-impl-dep.rs b/tests/rustdoc-html/intra-doc/auxiliary/extern-inherent-impl-dep.rs similarity index 100% rename from tests/rustdoc/intra-doc/auxiliary/extern-inherent-impl-dep.rs rename to tests/rustdoc-html/intra-doc/auxiliary/extern-inherent-impl-dep.rs diff --git a/tests/rustdoc/intra-doc/auxiliary/intra-link-extern-crate.rs b/tests/rustdoc-html/intra-doc/auxiliary/intra-link-extern-crate.rs similarity index 100% rename from tests/rustdoc/intra-doc/auxiliary/intra-link-extern-crate.rs rename to tests/rustdoc-html/intra-doc/auxiliary/intra-link-extern-crate.rs diff --git a/tests/rustdoc/intra-doc/auxiliary/intra-link-pub-use.rs b/tests/rustdoc-html/intra-doc/auxiliary/intra-link-pub-use.rs similarity index 100% rename from tests/rustdoc/intra-doc/auxiliary/intra-link-pub-use.rs rename to tests/rustdoc-html/intra-doc/auxiliary/intra-link-pub-use.rs diff --git a/tests/rustdoc/intra-doc/auxiliary/intra-link-reexport-additional-docs.rs b/tests/rustdoc-html/intra-doc/auxiliary/intra-link-reexport-additional-docs.rs similarity index 100% rename from tests/rustdoc/intra-doc/auxiliary/intra-link-reexport-additional-docs.rs rename to tests/rustdoc-html/intra-doc/auxiliary/intra-link-reexport-additional-docs.rs diff --git a/tests/rustdoc/intra-doc/auxiliary/intra-links-external-traits.rs b/tests/rustdoc-html/intra-doc/auxiliary/intra-links-external-traits.rs similarity index 100% rename from tests/rustdoc/intra-doc/auxiliary/intra-links-external-traits.rs rename to tests/rustdoc-html/intra-doc/auxiliary/intra-links-external-traits.rs diff --git a/tests/rustdoc/intra-doc/auxiliary/issue-66159-1.rs b/tests/rustdoc-html/intra-doc/auxiliary/issue-66159-1.rs similarity index 100% rename from tests/rustdoc/intra-doc/auxiliary/issue-66159-1.rs rename to tests/rustdoc-html/intra-doc/auxiliary/issue-66159-1.rs diff --git a/tests/rustdoc/intra-doc/auxiliary/my-core.rs b/tests/rustdoc-html/intra-doc/auxiliary/my-core.rs similarity index 100% rename from tests/rustdoc/intra-doc/auxiliary/my-core.rs rename to tests/rustdoc-html/intra-doc/auxiliary/my-core.rs diff --git a/tests/rustdoc/intra-doc/auxiliary/proc-macro-macro.rs b/tests/rustdoc-html/intra-doc/auxiliary/proc-macro-macro.rs similarity index 100% rename from tests/rustdoc/intra-doc/auxiliary/proc-macro-macro.rs rename to tests/rustdoc-html/intra-doc/auxiliary/proc-macro-macro.rs diff --git a/tests/rustdoc/intra-doc/auxiliary/pub-struct.rs b/tests/rustdoc-html/intra-doc/auxiliary/pub-struct.rs similarity index 100% rename from tests/rustdoc/intra-doc/auxiliary/pub-struct.rs rename to tests/rustdoc-html/intra-doc/auxiliary/pub-struct.rs diff --git a/tests/rustdoc/intra-doc/basic.rs b/tests/rustdoc-html/intra-doc/basic.rs similarity index 100% rename from tests/rustdoc/intra-doc/basic.rs rename to tests/rustdoc-html/intra-doc/basic.rs diff --git a/tests/rustdoc/intra-doc/builtin-macros.rs b/tests/rustdoc-html/intra-doc/builtin-macros.rs similarity index 100% rename from tests/rustdoc/intra-doc/builtin-macros.rs rename to tests/rustdoc-html/intra-doc/builtin-macros.rs diff --git a/tests/rustdoc/intra-doc/crate-relative-assoc.rs b/tests/rustdoc-html/intra-doc/crate-relative-assoc.rs similarity index 100% rename from tests/rustdoc/intra-doc/crate-relative-assoc.rs rename to tests/rustdoc-html/intra-doc/crate-relative-assoc.rs diff --git a/tests/rustdoc/intra-doc/crate-relative.rs b/tests/rustdoc-html/intra-doc/crate-relative.rs similarity index 100% rename from tests/rustdoc/intra-doc/crate-relative.rs rename to tests/rustdoc-html/intra-doc/crate-relative.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/additional_doc.rs b/tests/rustdoc-html/intra-doc/cross-crate/additional_doc.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/additional_doc.rs rename to tests/rustdoc-html/intra-doc/cross-crate/additional_doc.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/auxiliary/additional_doc.rs b/tests/rustdoc-html/intra-doc/cross-crate/auxiliary/additional_doc.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/auxiliary/additional_doc.rs rename to tests/rustdoc-html/intra-doc/cross-crate/auxiliary/additional_doc.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/auxiliary/hidden.rs b/tests/rustdoc-html/intra-doc/cross-crate/auxiliary/hidden.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/auxiliary/hidden.rs rename to tests/rustdoc-html/intra-doc/cross-crate/auxiliary/hidden.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs b/tests/rustdoc-html/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs rename to tests/rustdoc-html/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/auxiliary/intra-link-cross-crate-crate.rs b/tests/rustdoc-html/intra-doc/cross-crate/auxiliary/intra-link-cross-crate-crate.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/auxiliary/intra-link-cross-crate-crate.rs rename to tests/rustdoc-html/intra-doc/cross-crate/auxiliary/intra-link-cross-crate-crate.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/auxiliary/macro_inner.rs b/tests/rustdoc-html/intra-doc/cross-crate/auxiliary/macro_inner.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/auxiliary/macro_inner.rs rename to tests/rustdoc-html/intra-doc/cross-crate/auxiliary/macro_inner.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/auxiliary/module.rs b/tests/rustdoc-html/intra-doc/cross-crate/auxiliary/module.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/auxiliary/module.rs rename to tests/rustdoc-html/intra-doc/cross-crate/auxiliary/module.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/auxiliary/proc_macro.rs b/tests/rustdoc-html/intra-doc/cross-crate/auxiliary/proc_macro.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/auxiliary/proc_macro.rs rename to tests/rustdoc-html/intra-doc/cross-crate/auxiliary/proc_macro.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/auxiliary/submodule-inner.rs b/tests/rustdoc-html/intra-doc/cross-crate/auxiliary/submodule-inner.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/auxiliary/submodule-inner.rs rename to tests/rustdoc-html/intra-doc/cross-crate/auxiliary/submodule-inner.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/auxiliary/submodule-outer.rs b/tests/rustdoc-html/intra-doc/cross-crate/auxiliary/submodule-outer.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/auxiliary/submodule-outer.rs rename to tests/rustdoc-html/intra-doc/cross-crate/auxiliary/submodule-outer.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/auxiliary/traits.rs b/tests/rustdoc-html/intra-doc/cross-crate/auxiliary/traits.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/auxiliary/traits.rs rename to tests/rustdoc-html/intra-doc/cross-crate/auxiliary/traits.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/basic.rs b/tests/rustdoc-html/intra-doc/cross-crate/basic.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/basic.rs rename to tests/rustdoc-html/intra-doc/cross-crate/basic.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/crate.rs b/tests/rustdoc-html/intra-doc/cross-crate/crate.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/crate.rs rename to tests/rustdoc-html/intra-doc/cross-crate/crate.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/hidden.rs b/tests/rustdoc-html/intra-doc/cross-crate/hidden.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/hidden.rs rename to tests/rustdoc-html/intra-doc/cross-crate/hidden.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/macro.rs b/tests/rustdoc-html/intra-doc/cross-crate/macro.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/macro.rs rename to tests/rustdoc-html/intra-doc/cross-crate/macro.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/module.rs b/tests/rustdoc-html/intra-doc/cross-crate/module.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/module.rs rename to tests/rustdoc-html/intra-doc/cross-crate/module.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/submodule-inner.rs b/tests/rustdoc-html/intra-doc/cross-crate/submodule-inner.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/submodule-inner.rs rename to tests/rustdoc-html/intra-doc/cross-crate/submodule-inner.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/submodule-outer.rs b/tests/rustdoc-html/intra-doc/cross-crate/submodule-outer.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/submodule-outer.rs rename to tests/rustdoc-html/intra-doc/cross-crate/submodule-outer.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/traits.rs b/tests/rustdoc-html/intra-doc/cross-crate/traits.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/traits.rs rename to tests/rustdoc-html/intra-doc/cross-crate/traits.rs diff --git a/tests/rustdoc/intra-doc/deps.rs b/tests/rustdoc-html/intra-doc/deps.rs similarity index 100% rename from tests/rustdoc/intra-doc/deps.rs rename to tests/rustdoc-html/intra-doc/deps.rs diff --git a/tests/rustdoc/intra-doc/disambiguators-removed.rs b/tests/rustdoc-html/intra-doc/disambiguators-removed.rs similarity index 100% rename from tests/rustdoc/intra-doc/disambiguators-removed.rs rename to tests/rustdoc-html/intra-doc/disambiguators-removed.rs diff --git a/tests/rustdoc/intra-doc/email-address.rs b/tests/rustdoc-html/intra-doc/email-address.rs similarity index 100% rename from tests/rustdoc/intra-doc/email-address.rs rename to tests/rustdoc-html/intra-doc/email-address.rs diff --git a/tests/rustdoc/intra-doc/enum-self-82209.rs b/tests/rustdoc-html/intra-doc/enum-self-82209.rs similarity index 100% rename from tests/rustdoc/intra-doc/enum-self-82209.rs rename to tests/rustdoc-html/intra-doc/enum-self-82209.rs diff --git a/tests/rustdoc/intra-doc/enum-struct-field.rs b/tests/rustdoc-html/intra-doc/enum-struct-field.rs similarity index 100% rename from tests/rustdoc/intra-doc/enum-struct-field.rs rename to tests/rustdoc-html/intra-doc/enum-struct-field.rs diff --git a/tests/rustdoc/intra-doc/extern-builtin-type-impl.rs b/tests/rustdoc-html/intra-doc/extern-builtin-type-impl.rs similarity index 100% rename from tests/rustdoc/intra-doc/extern-builtin-type-impl.rs rename to tests/rustdoc-html/intra-doc/extern-builtin-type-impl.rs diff --git a/tests/rustdoc/intra-doc/extern-crate-only-used-in-link.rs b/tests/rustdoc-html/intra-doc/extern-crate-only-used-in-link.rs similarity index 100% rename from tests/rustdoc/intra-doc/extern-crate-only-used-in-link.rs rename to tests/rustdoc-html/intra-doc/extern-crate-only-used-in-link.rs diff --git a/tests/rustdoc/intra-doc/extern-crate.rs b/tests/rustdoc-html/intra-doc/extern-crate.rs similarity index 100% rename from tests/rustdoc/intra-doc/extern-crate.rs rename to tests/rustdoc-html/intra-doc/extern-crate.rs diff --git a/tests/rustdoc/intra-doc/extern-inherent-impl.rs b/tests/rustdoc-html/intra-doc/extern-inherent-impl.rs similarity index 100% rename from tests/rustdoc/intra-doc/extern-inherent-impl.rs rename to tests/rustdoc-html/intra-doc/extern-inherent-impl.rs diff --git a/tests/rustdoc/intra-doc/extern-reference-link.rs b/tests/rustdoc-html/intra-doc/extern-reference-link.rs similarity index 100% rename from tests/rustdoc/intra-doc/extern-reference-link.rs rename to tests/rustdoc-html/intra-doc/extern-reference-link.rs diff --git a/tests/rustdoc/intra-doc/extern-type.rs b/tests/rustdoc-html/intra-doc/extern-type.rs similarity index 100% rename from tests/rustdoc/intra-doc/extern-type.rs rename to tests/rustdoc-html/intra-doc/extern-type.rs diff --git a/tests/rustdoc/intra-doc/external-traits.rs b/tests/rustdoc-html/intra-doc/external-traits.rs similarity index 100% rename from tests/rustdoc/intra-doc/external-traits.rs rename to tests/rustdoc-html/intra-doc/external-traits.rs diff --git a/tests/rustdoc/intra-doc/field.rs b/tests/rustdoc-html/intra-doc/field.rs similarity index 100% rename from tests/rustdoc/intra-doc/field.rs rename to tests/rustdoc-html/intra-doc/field.rs diff --git a/tests/rustdoc/intra-doc/filter-out-private.rs b/tests/rustdoc-html/intra-doc/filter-out-private.rs similarity index 100% rename from tests/rustdoc/intra-doc/filter-out-private.rs rename to tests/rustdoc-html/intra-doc/filter-out-private.rs diff --git a/tests/rustdoc/intra-doc/generic-params.rs b/tests/rustdoc-html/intra-doc/generic-params.rs similarity index 100% rename from tests/rustdoc/intra-doc/generic-params.rs rename to tests/rustdoc-html/intra-doc/generic-params.rs diff --git a/tests/rustdoc/intra-doc/generic-trait-impl.rs b/tests/rustdoc-html/intra-doc/generic-trait-impl.rs similarity index 100% rename from tests/rustdoc/intra-doc/generic-trait-impl.rs rename to tests/rustdoc-html/intra-doc/generic-trait-impl.rs diff --git a/tests/rustdoc/intra-doc/ice-intra-doc-links-107995.rs b/tests/rustdoc-html/intra-doc/ice-intra-doc-links-107995.rs similarity index 100% rename from tests/rustdoc/intra-doc/ice-intra-doc-links-107995.rs rename to tests/rustdoc-html/intra-doc/ice-intra-doc-links-107995.rs diff --git a/tests/rustdoc/intra-doc/in-bodies.rs b/tests/rustdoc-html/intra-doc/in-bodies.rs similarity index 100% rename from tests/rustdoc/intra-doc/in-bodies.rs rename to tests/rustdoc-html/intra-doc/in-bodies.rs diff --git a/tests/rustdoc/intra-doc/inherent-associated-types.rs b/tests/rustdoc-html/intra-doc/inherent-associated-types.rs similarity index 100% rename from tests/rustdoc/intra-doc/inherent-associated-types.rs rename to tests/rustdoc-html/intra-doc/inherent-associated-types.rs diff --git a/tests/rustdoc/intra-doc/intra-doc-link-method-trait-impl-72340.rs b/tests/rustdoc-html/intra-doc/intra-doc-link-method-trait-impl-72340.rs similarity index 100% rename from tests/rustdoc/intra-doc/intra-doc-link-method-trait-impl-72340.rs rename to tests/rustdoc-html/intra-doc/intra-doc-link-method-trait-impl-72340.rs diff --git a/tests/rustdoc/intra-doc/libstd-re-export.rs b/tests/rustdoc-html/intra-doc/libstd-re-export.rs similarity index 100% rename from tests/rustdoc/intra-doc/libstd-re-export.rs rename to tests/rustdoc-html/intra-doc/libstd-re-export.rs diff --git a/tests/rustdoc/intra-doc/link-in-footnotes-132208.rs b/tests/rustdoc-html/intra-doc/link-in-footnotes-132208.rs similarity index 100% rename from tests/rustdoc/intra-doc/link-in-footnotes-132208.rs rename to tests/rustdoc-html/intra-doc/link-in-footnotes-132208.rs diff --git a/tests/rustdoc/intra-doc/link-same-name-different-disambiguator-108459.rs b/tests/rustdoc-html/intra-doc/link-same-name-different-disambiguator-108459.rs similarity index 100% rename from tests/rustdoc/intra-doc/link-same-name-different-disambiguator-108459.rs rename to tests/rustdoc-html/intra-doc/link-same-name-different-disambiguator-108459.rs diff --git a/tests/rustdoc/intra-doc/link-to-proc-macro.rs b/tests/rustdoc-html/intra-doc/link-to-proc-macro.rs similarity index 100% rename from tests/rustdoc/intra-doc/link-to-proc-macro.rs rename to tests/rustdoc-html/intra-doc/link-to-proc-macro.rs diff --git a/tests/rustdoc/intra-doc/macro-caching-144965.rs b/tests/rustdoc-html/intra-doc/macro-caching-144965.rs similarity index 100% rename from tests/rustdoc/intra-doc/macro-caching-144965.rs rename to tests/rustdoc-html/intra-doc/macro-caching-144965.rs diff --git a/tests/rustdoc/intra-doc/macros-disambiguators.rs b/tests/rustdoc-html/intra-doc/macros-disambiguators.rs similarity index 100% rename from tests/rustdoc/intra-doc/macros-disambiguators.rs rename to tests/rustdoc-html/intra-doc/macros-disambiguators.rs diff --git a/tests/rustdoc/intra-doc/mod-ambiguity.rs b/tests/rustdoc-html/intra-doc/mod-ambiguity.rs similarity index 100% rename from tests/rustdoc/intra-doc/mod-ambiguity.rs rename to tests/rustdoc-html/intra-doc/mod-ambiguity.rs diff --git a/tests/rustdoc/intra-doc/mod-relative.rs b/tests/rustdoc-html/intra-doc/mod-relative.rs similarity index 100% rename from tests/rustdoc/intra-doc/mod-relative.rs rename to tests/rustdoc-html/intra-doc/mod-relative.rs diff --git a/tests/rustdoc/intra-doc/module-scope-name-resolution-55364.rs b/tests/rustdoc-html/intra-doc/module-scope-name-resolution-55364.rs similarity index 100% rename from tests/rustdoc/intra-doc/module-scope-name-resolution-55364.rs rename to tests/rustdoc-html/intra-doc/module-scope-name-resolution-55364.rs diff --git a/tests/rustdoc/intra-doc/nested-use.rs b/tests/rustdoc-html/intra-doc/nested-use.rs similarity index 100% rename from tests/rustdoc/intra-doc/nested-use.rs rename to tests/rustdoc-html/intra-doc/nested-use.rs diff --git a/tests/rustdoc/intra-doc/no-doc-primitive.rs b/tests/rustdoc-html/intra-doc/no-doc-primitive.rs similarity index 100% rename from tests/rustdoc/intra-doc/no-doc-primitive.rs rename to tests/rustdoc-html/intra-doc/no-doc-primitive.rs diff --git a/tests/rustdoc/intra-doc/non-path-primitives.rs b/tests/rustdoc-html/intra-doc/non-path-primitives.rs similarity index 100% rename from tests/rustdoc/intra-doc/non-path-primitives.rs rename to tests/rustdoc-html/intra-doc/non-path-primitives.rs diff --git a/tests/rustdoc/intra-doc/prim-assoc.rs b/tests/rustdoc-html/intra-doc/prim-assoc.rs similarity index 100% rename from tests/rustdoc/intra-doc/prim-assoc.rs rename to tests/rustdoc-html/intra-doc/prim-assoc.rs diff --git a/tests/rustdoc/intra-doc/prim-associated-traits.rs b/tests/rustdoc-html/intra-doc/prim-associated-traits.rs similarity index 100% rename from tests/rustdoc/intra-doc/prim-associated-traits.rs rename to tests/rustdoc-html/intra-doc/prim-associated-traits.rs diff --git a/tests/rustdoc/intra-doc/prim-methods-external-core.rs b/tests/rustdoc-html/intra-doc/prim-methods-external-core.rs similarity index 100% rename from tests/rustdoc/intra-doc/prim-methods-external-core.rs rename to tests/rustdoc-html/intra-doc/prim-methods-external-core.rs diff --git a/tests/rustdoc/intra-doc/prim-methods-local.rs b/tests/rustdoc-html/intra-doc/prim-methods-local.rs similarity index 100% rename from tests/rustdoc/intra-doc/prim-methods-local.rs rename to tests/rustdoc-html/intra-doc/prim-methods-local.rs diff --git a/tests/rustdoc/intra-doc/prim-methods.rs b/tests/rustdoc-html/intra-doc/prim-methods.rs similarity index 100% rename from tests/rustdoc/intra-doc/prim-methods.rs rename to tests/rustdoc-html/intra-doc/prim-methods.rs diff --git a/tests/rustdoc/intra-doc/prim-precedence.rs b/tests/rustdoc-html/intra-doc/prim-precedence.rs similarity index 100% rename from tests/rustdoc/intra-doc/prim-precedence.rs rename to tests/rustdoc-html/intra-doc/prim-precedence.rs diff --git a/tests/rustdoc/intra-doc/prim-self.rs b/tests/rustdoc-html/intra-doc/prim-self.rs similarity index 100% rename from tests/rustdoc/intra-doc/prim-self.rs rename to tests/rustdoc-html/intra-doc/prim-self.rs diff --git a/tests/rustdoc/intra-doc/primitive-disambiguators.rs b/tests/rustdoc-html/intra-doc/primitive-disambiguators.rs similarity index 100% rename from tests/rustdoc/intra-doc/primitive-disambiguators.rs rename to tests/rustdoc-html/intra-doc/primitive-disambiguators.rs diff --git a/tests/rustdoc/intra-doc/primitive-non-default-impl.rs b/tests/rustdoc-html/intra-doc/primitive-non-default-impl.rs similarity index 100% rename from tests/rustdoc/intra-doc/primitive-non-default-impl.rs rename to tests/rustdoc-html/intra-doc/primitive-non-default-impl.rs diff --git a/tests/rustdoc/intra-doc/private-failures-ignored.rs b/tests/rustdoc-html/intra-doc/private-failures-ignored.rs similarity index 100% rename from tests/rustdoc/intra-doc/private-failures-ignored.rs rename to tests/rustdoc-html/intra-doc/private-failures-ignored.rs diff --git a/tests/rustdoc/intra-doc/private.rs b/tests/rustdoc-html/intra-doc/private.rs similarity index 100% rename from tests/rustdoc/intra-doc/private.rs rename to tests/rustdoc-html/intra-doc/private.rs diff --git a/tests/rustdoc/intra-doc/proc-macro.rs b/tests/rustdoc-html/intra-doc/proc-macro.rs similarity index 100% rename from tests/rustdoc/intra-doc/proc-macro.rs rename to tests/rustdoc-html/intra-doc/proc-macro.rs diff --git a/tests/rustdoc/intra-doc/pub-use.rs b/tests/rustdoc-html/intra-doc/pub-use.rs similarity index 100% rename from tests/rustdoc/intra-doc/pub-use.rs rename to tests/rustdoc-html/intra-doc/pub-use.rs diff --git a/tests/rustdoc/intra-doc/raw-ident-self.rs b/tests/rustdoc-html/intra-doc/raw-ident-self.rs similarity index 100% rename from tests/rustdoc/intra-doc/raw-ident-self.rs rename to tests/rustdoc-html/intra-doc/raw-ident-self.rs diff --git a/tests/rustdoc/intra-doc/reexport-additional-docs.rs b/tests/rustdoc-html/intra-doc/reexport-additional-docs.rs similarity index 100% rename from tests/rustdoc/intra-doc/reexport-additional-docs.rs rename to tests/rustdoc-html/intra-doc/reexport-additional-docs.rs diff --git a/tests/rustdoc/intra-doc/same-name-different-crates-66159.rs b/tests/rustdoc-html/intra-doc/same-name-different-crates-66159.rs similarity index 100% rename from tests/rustdoc/intra-doc/same-name-different-crates-66159.rs rename to tests/rustdoc-html/intra-doc/same-name-different-crates-66159.rs diff --git a/tests/rustdoc/intra-doc/self-cache.rs b/tests/rustdoc-html/intra-doc/self-cache.rs similarity index 100% rename from tests/rustdoc/intra-doc/self-cache.rs rename to tests/rustdoc-html/intra-doc/self-cache.rs diff --git a/tests/rustdoc/intra-doc/self.rs b/tests/rustdoc-html/intra-doc/self.rs similarity index 100% rename from tests/rustdoc/intra-doc/self.rs rename to tests/rustdoc-html/intra-doc/self.rs diff --git a/tests/rustdoc/intra-doc/trait-impl.rs b/tests/rustdoc-html/intra-doc/trait-impl.rs similarity index 100% rename from tests/rustdoc/intra-doc/trait-impl.rs rename to tests/rustdoc-html/intra-doc/trait-impl.rs diff --git a/tests/rustdoc/intra-doc/trait-item.rs b/tests/rustdoc-html/intra-doc/trait-item.rs similarity index 100% rename from tests/rustdoc/intra-doc/trait-item.rs rename to tests/rustdoc-html/intra-doc/trait-item.rs diff --git a/tests/rustdoc/intra-doc/true-false.rs b/tests/rustdoc-html/intra-doc/true-false.rs similarity index 100% rename from tests/rustdoc/intra-doc/true-false.rs rename to tests/rustdoc-html/intra-doc/true-false.rs diff --git a/tests/rustdoc/intra-doc/type-alias-primitive.rs b/tests/rustdoc-html/intra-doc/type-alias-primitive.rs similarity index 100% rename from tests/rustdoc/intra-doc/type-alias-primitive.rs rename to tests/rustdoc-html/intra-doc/type-alias-primitive.rs diff --git a/tests/rustdoc/intra-doc/type-alias.rs b/tests/rustdoc-html/intra-doc/type-alias.rs similarity index 100% rename from tests/rustdoc/intra-doc/type-alias.rs rename to tests/rustdoc-html/intra-doc/type-alias.rs diff --git a/tests/rustdoc/invalid$crate$name.rs b/tests/rustdoc-html/invalid$crate$name.rs similarity index 100% rename from tests/rustdoc/invalid$crate$name.rs rename to tests/rustdoc-html/invalid$crate$name.rs diff --git a/tests/rustdoc/item-desc-list-at-start.item-table.html b/tests/rustdoc-html/item-desc-list-at-start.item-table.html similarity index 100% rename from tests/rustdoc/item-desc-list-at-start.item-table.html rename to tests/rustdoc-html/item-desc-list-at-start.item-table.html diff --git a/tests/rustdoc/item-desc-list-at-start.rs b/tests/rustdoc-html/item-desc-list-at-start.rs similarity index 100% rename from tests/rustdoc/item-desc-list-at-start.rs rename to tests/rustdoc-html/item-desc-list-at-start.rs diff --git a/tests/rustdoc/jump-to-def/assoc-items.rs b/tests/rustdoc-html/jump-to-def/assoc-items.rs similarity index 100% rename from tests/rustdoc/jump-to-def/assoc-items.rs rename to tests/rustdoc-html/jump-to-def/assoc-items.rs diff --git a/tests/rustdoc/jump-to-def/assoc-types.rs b/tests/rustdoc-html/jump-to-def/assoc-types.rs similarity index 100% rename from tests/rustdoc/jump-to-def/assoc-types.rs rename to tests/rustdoc-html/jump-to-def/assoc-types.rs diff --git a/tests/rustdoc/jump-to-def/auxiliary/symbols.rs b/tests/rustdoc-html/jump-to-def/auxiliary/symbols.rs similarity index 100% rename from tests/rustdoc/jump-to-def/auxiliary/symbols.rs rename to tests/rustdoc-html/jump-to-def/auxiliary/symbols.rs diff --git a/tests/rustdoc/jump-to-def/derive-macro.rs b/tests/rustdoc-html/jump-to-def/derive-macro.rs similarity index 100% rename from tests/rustdoc/jump-to-def/derive-macro.rs rename to tests/rustdoc-html/jump-to-def/derive-macro.rs diff --git a/tests/rustdoc/jump-to-def/doc-links-calls.rs b/tests/rustdoc-html/jump-to-def/doc-links-calls.rs similarity index 100% rename from tests/rustdoc/jump-to-def/doc-links-calls.rs rename to tests/rustdoc-html/jump-to-def/doc-links-calls.rs diff --git a/tests/rustdoc/jump-to-def/doc-links.rs b/tests/rustdoc-html/jump-to-def/doc-links.rs similarity index 100% rename from tests/rustdoc/jump-to-def/doc-links.rs rename to tests/rustdoc-html/jump-to-def/doc-links.rs diff --git a/tests/rustdoc/jump-to-def/macro.rs b/tests/rustdoc-html/jump-to-def/macro.rs similarity index 100% rename from tests/rustdoc/jump-to-def/macro.rs rename to tests/rustdoc-html/jump-to-def/macro.rs diff --git a/tests/rustdoc/jump-to-def/no-body-items.rs b/tests/rustdoc-html/jump-to-def/no-body-items.rs similarity index 100% rename from tests/rustdoc/jump-to-def/no-body-items.rs rename to tests/rustdoc-html/jump-to-def/no-body-items.rs diff --git a/tests/rustdoc/jump-to-def/non-local-method.rs b/tests/rustdoc-html/jump-to-def/non-local-method.rs similarity index 100% rename from tests/rustdoc/jump-to-def/non-local-method.rs rename to tests/rustdoc-html/jump-to-def/non-local-method.rs diff --git a/tests/rustdoc/jump-to-def/patterns.rs b/tests/rustdoc-html/jump-to-def/patterns.rs similarity index 100% rename from tests/rustdoc/jump-to-def/patterns.rs rename to tests/rustdoc-html/jump-to-def/patterns.rs diff --git a/tests/rustdoc/jump-to-def/prelude-types.rs b/tests/rustdoc-html/jump-to-def/prelude-types.rs similarity index 100% rename from tests/rustdoc/jump-to-def/prelude-types.rs rename to tests/rustdoc-html/jump-to-def/prelude-types.rs diff --git a/tests/rustdoc/jump-to-def/shebang.rs b/tests/rustdoc-html/jump-to-def/shebang.rs similarity index 100% rename from tests/rustdoc/jump-to-def/shebang.rs rename to tests/rustdoc-html/jump-to-def/shebang.rs diff --git a/tests/rustdoc/keyword.rs b/tests/rustdoc-html/keyword.rs similarity index 100% rename from tests/rustdoc/keyword.rs rename to tests/rustdoc-html/keyword.rs diff --git a/tests/rustdoc/lifetime-name.rs b/tests/rustdoc-html/lifetime-name.rs similarity index 100% rename from tests/rustdoc/lifetime-name.rs rename to tests/rustdoc-html/lifetime-name.rs diff --git a/tests/rustdoc/line-breaks.rs b/tests/rustdoc-html/line-breaks.rs similarity index 100% rename from tests/rustdoc/line-breaks.rs rename to tests/rustdoc-html/line-breaks.rs diff --git a/tests/rustdoc/link-on-path-with-generics.rs b/tests/rustdoc-html/link-on-path-with-generics.rs similarity index 100% rename from tests/rustdoc/link-on-path-with-generics.rs rename to tests/rustdoc-html/link-on-path-with-generics.rs diff --git a/tests/rustdoc/link-title-escape.rs b/tests/rustdoc-html/link-title-escape.rs similarity index 100% rename from tests/rustdoc/link-title-escape.rs rename to tests/rustdoc-html/link-title-escape.rs diff --git a/tests/rustdoc/links-in-headings.rs b/tests/rustdoc-html/links-in-headings.rs similarity index 100% rename from tests/rustdoc/links-in-headings.rs rename to tests/rustdoc-html/links-in-headings.rs diff --git a/tests/rustdoc/logo-class-default.rs b/tests/rustdoc-html/logo-class-default.rs similarity index 100% rename from tests/rustdoc/logo-class-default.rs rename to tests/rustdoc-html/logo-class-default.rs diff --git a/tests/rustdoc/logo-class-rust.rs b/tests/rustdoc-html/logo-class-rust.rs similarity index 100% rename from tests/rustdoc/logo-class-rust.rs rename to tests/rustdoc-html/logo-class-rust.rs diff --git a/tests/rustdoc/logo-class.rs b/tests/rustdoc-html/logo-class.rs similarity index 100% rename from tests/rustdoc/logo-class.rs rename to tests/rustdoc-html/logo-class.rs diff --git a/tests/rustdoc/macro-expansion/field-followed-by-exclamation.rs b/tests/rustdoc-html/macro-expansion/field-followed-by-exclamation.rs similarity index 100% rename from tests/rustdoc/macro-expansion/field-followed-by-exclamation.rs rename to tests/rustdoc-html/macro-expansion/field-followed-by-exclamation.rs diff --git a/tests/rustdoc/macro-expansion/type-macro-expansion.rs b/tests/rustdoc-html/macro-expansion/type-macro-expansion.rs similarity index 100% rename from tests/rustdoc/macro-expansion/type-macro-expansion.rs rename to tests/rustdoc-html/macro-expansion/type-macro-expansion.rs diff --git a/tests/rustdoc/macro/auxiliary/external-macro-src.rs b/tests/rustdoc-html/macro/auxiliary/external-macro-src.rs similarity index 100% rename from tests/rustdoc/macro/auxiliary/external-macro-src.rs rename to tests/rustdoc-html/macro/auxiliary/external-macro-src.rs diff --git a/tests/rustdoc/macro/auxiliary/issue-99221-aux.rs b/tests/rustdoc-html/macro/auxiliary/issue-99221-aux.rs similarity index 100% rename from tests/rustdoc/macro/auxiliary/issue-99221-aux.rs rename to tests/rustdoc-html/macro/auxiliary/issue-99221-aux.rs diff --git a/tests/rustdoc/macro/auxiliary/macro_pub_in_module.rs b/tests/rustdoc-html/macro/auxiliary/macro_pub_in_module.rs similarity index 100% rename from tests/rustdoc/macro/auxiliary/macro_pub_in_module.rs rename to tests/rustdoc-html/macro/auxiliary/macro_pub_in_module.rs diff --git a/tests/rustdoc/macro/auxiliary/one-line-expand.rs b/tests/rustdoc-html/macro/auxiliary/one-line-expand.rs similarity index 100% rename from tests/rustdoc/macro/auxiliary/one-line-expand.rs rename to tests/rustdoc-html/macro/auxiliary/one-line-expand.rs diff --git a/tests/rustdoc/macro/auxiliary/pub-use-extern-macros.rs b/tests/rustdoc-html/macro/auxiliary/pub-use-extern-macros.rs similarity index 100% rename from tests/rustdoc/macro/auxiliary/pub-use-extern-macros.rs rename to tests/rustdoc-html/macro/auxiliary/pub-use-extern-macros.rs diff --git a/tests/rustdoc/macro/compiler-derive-proc-macro.rs b/tests/rustdoc-html/macro/compiler-derive-proc-macro.rs similarity index 100% rename from tests/rustdoc/macro/compiler-derive-proc-macro.rs rename to tests/rustdoc-html/macro/compiler-derive-proc-macro.rs diff --git a/tests/rustdoc/macro/const-rendering-macros-33302.rs b/tests/rustdoc-html/macro/const-rendering-macros-33302.rs similarity index 100% rename from tests/rustdoc/macro/const-rendering-macros-33302.rs rename to tests/rustdoc-html/macro/const-rendering-macros-33302.rs diff --git a/tests/rustdoc/macro/decl_macro.rs b/tests/rustdoc-html/macro/decl_macro.rs similarity index 100% rename from tests/rustdoc/macro/decl_macro.rs rename to tests/rustdoc-html/macro/decl_macro.rs diff --git a/tests/rustdoc/macro/decl_macro_priv.rs b/tests/rustdoc-html/macro/decl_macro_priv.rs similarity index 100% rename from tests/rustdoc/macro/decl_macro_priv.rs rename to tests/rustdoc-html/macro/decl_macro_priv.rs diff --git a/tests/rustdoc/macro/doc-proc-macro.rs b/tests/rustdoc-html/macro/doc-proc-macro.rs similarity index 100% rename from tests/rustdoc/macro/doc-proc-macro.rs rename to tests/rustdoc-html/macro/doc-proc-macro.rs diff --git a/tests/rustdoc/macro/external-macro-src.rs b/tests/rustdoc-html/macro/external-macro-src.rs similarity index 100% rename from tests/rustdoc/macro/external-macro-src.rs rename to tests/rustdoc-html/macro/external-macro-src.rs diff --git a/tests/rustdoc/macro/macro-const-display-115295.rs b/tests/rustdoc-html/macro/macro-const-display-115295.rs similarity index 100% rename from tests/rustdoc/macro/macro-const-display-115295.rs rename to tests/rustdoc-html/macro/macro-const-display-115295.rs diff --git a/tests/rustdoc/macro/macro-doc-comment-23812.rs b/tests/rustdoc-html/macro/macro-doc-comment-23812.rs similarity index 100% rename from tests/rustdoc/macro/macro-doc-comment-23812.rs rename to tests/rustdoc-html/macro/macro-doc-comment-23812.rs diff --git a/tests/rustdoc/macro/macro-export-crate-root-108231.rs b/tests/rustdoc-html/macro/macro-export-crate-root-108231.rs similarity index 100% rename from tests/rustdoc/macro/macro-export-crate-root-108231.rs rename to tests/rustdoc-html/macro/macro-export-crate-root-108231.rs diff --git a/tests/rustdoc/macro/macro-generated-macro.macro_linebreak_pre.html b/tests/rustdoc-html/macro/macro-generated-macro.macro_linebreak_pre.html similarity index 100% rename from tests/rustdoc/macro/macro-generated-macro.macro_linebreak_pre.html rename to tests/rustdoc-html/macro/macro-generated-macro.macro_linebreak_pre.html diff --git a/tests/rustdoc/macro/macro-generated-macro.macro_morestuff_pre.html b/tests/rustdoc-html/macro/macro-generated-macro.macro_morestuff_pre.html similarity index 100% rename from tests/rustdoc/macro/macro-generated-macro.macro_morestuff_pre.html rename to tests/rustdoc-html/macro/macro-generated-macro.macro_morestuff_pre.html diff --git a/tests/rustdoc/macro/macro-generated-macro.rs b/tests/rustdoc-html/macro/macro-generated-macro.rs similarity index 100% rename from tests/rustdoc/macro/macro-generated-macro.rs rename to tests/rustdoc-html/macro/macro-generated-macro.rs diff --git a/tests/rustdoc/macro/macro-higher-kinded-function.rs b/tests/rustdoc-html/macro/macro-higher-kinded-function.rs similarity index 100% rename from tests/rustdoc/macro/macro-higher-kinded-function.rs rename to tests/rustdoc-html/macro/macro-higher-kinded-function.rs diff --git a/tests/rustdoc/macro/macro-ice-16019.rs b/tests/rustdoc-html/macro/macro-ice-16019.rs similarity index 100% rename from tests/rustdoc/macro/macro-ice-16019.rs rename to tests/rustdoc-html/macro/macro-ice-16019.rs diff --git a/tests/rustdoc/macro/macro-in-async-block.rs b/tests/rustdoc-html/macro/macro-in-async-block.rs similarity index 100% rename from tests/rustdoc/macro/macro-in-async-block.rs rename to tests/rustdoc-html/macro/macro-in-async-block.rs diff --git a/tests/rustdoc/macro/macro-in-closure.rs b/tests/rustdoc-html/macro/macro-in-closure.rs similarity index 100% rename from tests/rustdoc/macro/macro-in-closure.rs rename to tests/rustdoc-html/macro/macro-in-closure.rs diff --git a/tests/rustdoc/macro/macro-indirect-use.rs b/tests/rustdoc-html/macro/macro-indirect-use.rs similarity index 100% rename from tests/rustdoc/macro/macro-indirect-use.rs rename to tests/rustdoc-html/macro/macro-indirect-use.rs diff --git a/tests/rustdoc/macro/macro_expansion.rs b/tests/rustdoc-html/macro/macro_expansion.rs similarity index 100% rename from tests/rustdoc/macro/macro_expansion.rs rename to tests/rustdoc-html/macro/macro_expansion.rs diff --git a/tests/rustdoc/macro/macro_pub_in_module.rs b/tests/rustdoc-html/macro/macro_pub_in_module.rs similarity index 100% rename from tests/rustdoc/macro/macro_pub_in_module.rs rename to tests/rustdoc-html/macro/macro_pub_in_module.rs diff --git a/tests/rustdoc/macro/macro_rules-matchers.rs b/tests/rustdoc-html/macro/macro_rules-matchers.rs similarity index 100% rename from tests/rustdoc/macro/macro_rules-matchers.rs rename to tests/rustdoc-html/macro/macro_rules-matchers.rs diff --git a/tests/rustdoc/macro/macros.rs b/tests/rustdoc-html/macro/macros.rs similarity index 100% rename from tests/rustdoc/macro/macros.rs rename to tests/rustdoc-html/macro/macros.rs diff --git a/tests/rustdoc/macro/multiple-macro-rules-w-same-name-99221.rs b/tests/rustdoc-html/macro/multiple-macro-rules-w-same-name-99221.rs similarity index 100% rename from tests/rustdoc/macro/multiple-macro-rules-w-same-name-99221.rs rename to tests/rustdoc-html/macro/multiple-macro-rules-w-same-name-99221.rs diff --git a/tests/rustdoc/macro/multiple-macro-rules-w-same-name-submodule-99221.rs b/tests/rustdoc-html/macro/multiple-macro-rules-w-same-name-submodule-99221.rs similarity index 100% rename from tests/rustdoc/macro/multiple-macro-rules-w-same-name-submodule-99221.rs rename to tests/rustdoc-html/macro/multiple-macro-rules-w-same-name-submodule-99221.rs diff --git a/tests/rustdoc/macro/one-line-expand.rs b/tests/rustdoc-html/macro/one-line-expand.rs similarity index 100% rename from tests/rustdoc/macro/one-line-expand.rs rename to tests/rustdoc-html/macro/one-line-expand.rs diff --git a/tests/rustdoc/macro/proc-macro.rs b/tests/rustdoc-html/macro/proc-macro.rs similarity index 100% rename from tests/rustdoc/macro/proc-macro.rs rename to tests/rustdoc-html/macro/proc-macro.rs diff --git a/tests/rustdoc/macro/pub-use-extern-macros.rs b/tests/rustdoc-html/macro/pub-use-extern-macros.rs similarity index 100% rename from tests/rustdoc/macro/pub-use-extern-macros.rs rename to tests/rustdoc-html/macro/pub-use-extern-macros.rs diff --git a/tests/rustdoc/macro/rustc-macro-crate.rs b/tests/rustdoc-html/macro/rustc-macro-crate.rs similarity index 100% rename from tests/rustdoc/macro/rustc-macro-crate.rs rename to tests/rustdoc-html/macro/rustc-macro-crate.rs diff --git a/tests/rustdoc/markdown-60482.rs b/tests/rustdoc-html/markdown-60482.rs similarity index 100% rename from tests/rustdoc/markdown-60482.rs rename to tests/rustdoc-html/markdown-60482.rs diff --git a/tests/rustdoc/markdown-table-escape-pipe-27862.rs b/tests/rustdoc-html/markdown-table-escape-pipe-27862.rs similarity index 100% rename from tests/rustdoc/markdown-table-escape-pipe-27862.rs rename to tests/rustdoc-html/markdown-table-escape-pipe-27862.rs diff --git a/tests/rustdoc/masked.rs b/tests/rustdoc-html/masked.rs similarity index 100% rename from tests/rustdoc/masked.rs rename to tests/rustdoc-html/masked.rs diff --git a/tests/rustdoc/merge-cross-crate-info/cargo-transitive-read-write/auxiliary/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/cargo-transitive-read-write/auxiliary/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/cargo-transitive-read-write/auxiliary/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/cargo-transitive-read-write/auxiliary/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/cargo-transitive-read-write/auxiliary/tango.rs b/tests/rustdoc-html/merge-cross-crate-info/cargo-transitive-read-write/auxiliary/tango.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/cargo-transitive-read-write/auxiliary/tango.rs rename to tests/rustdoc-html/merge-cross-crate-info/cargo-transitive-read-write/auxiliary/tango.rs diff --git a/tests/rustdoc/merge-cross-crate-info/cargo-transitive-read-write/sierra.rs b/tests/rustdoc-html/merge-cross-crate-info/cargo-transitive-read-write/sierra.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/cargo-transitive-read-write/sierra.rs rename to tests/rustdoc-html/merge-cross-crate-info/cargo-transitive-read-write/sierra.rs diff --git a/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/romeo.rs b/tests/rustdoc-html/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/romeo.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/romeo.rs rename to tests/rustdoc-html/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/romeo.rs diff --git a/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/sierra.rs b/tests/rustdoc-html/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/sierra.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/sierra.rs rename to tests/rustdoc-html/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/sierra.rs diff --git a/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/tango.rs b/tests/rustdoc-html/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/tango.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/tango.rs rename to tests/rustdoc-html/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/tango.rs diff --git a/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/indigo.rs b/tests/rustdoc-html/merge-cross-crate-info/kitchen-sink-separate-dirs/indigo.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/indigo.rs rename to tests/rustdoc-html/merge-cross-crate-info/kitchen-sink-separate-dirs/indigo.rs diff --git a/tests/rustdoc/merge-cross-crate-info/no-merge-separate/auxiliary/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/no-merge-separate/auxiliary/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/no-merge-separate/auxiliary/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/no-merge-separate/auxiliary/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/no-merge-separate/auxiliary/tango.rs b/tests/rustdoc-html/merge-cross-crate-info/no-merge-separate/auxiliary/tango.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/no-merge-separate/auxiliary/tango.rs rename to tests/rustdoc-html/merge-cross-crate-info/no-merge-separate/auxiliary/tango.rs diff --git a/tests/rustdoc/merge-cross-crate-info/no-merge-separate/sierra.rs b/tests/rustdoc-html/merge-cross-crate-info/no-merge-separate/sierra.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/no-merge-separate/sierra.rs rename to tests/rustdoc-html/merge-cross-crate-info/no-merge-separate/sierra.rs diff --git a/tests/rustdoc/merge-cross-crate-info/no-merge-write-anyway/auxiliary/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/no-merge-write-anyway/auxiliary/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/no-merge-write-anyway/auxiliary/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/no-merge-write-anyway/auxiliary/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/no-merge-write-anyway/auxiliary/tango.rs b/tests/rustdoc-html/merge-cross-crate-info/no-merge-write-anyway/auxiliary/tango.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/no-merge-write-anyway/auxiliary/tango.rs rename to tests/rustdoc-html/merge-cross-crate-info/no-merge-write-anyway/auxiliary/tango.rs diff --git a/tests/rustdoc/merge-cross-crate-info/no-merge-write-anyway/sierra.rs b/tests/rustdoc-html/merge-cross-crate-info/no-merge-write-anyway/sierra.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/no-merge-write-anyway/sierra.rs rename to tests/rustdoc-html/merge-cross-crate-info/no-merge-write-anyway/sierra.rs diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite-but-include/auxiliary/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/overwrite-but-include/auxiliary/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/overwrite-but-include/auxiliary/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/overwrite-but-include/auxiliary/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite-but-include/auxiliary/tango.rs b/tests/rustdoc-html/merge-cross-crate-info/overwrite-but-include/auxiliary/tango.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/overwrite-but-include/auxiliary/tango.rs rename to tests/rustdoc-html/merge-cross-crate-info/overwrite-but-include/auxiliary/tango.rs diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite-but-include/sierra.rs b/tests/rustdoc-html/merge-cross-crate-info/overwrite-but-include/sierra.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/overwrite-but-include/sierra.rs rename to tests/rustdoc-html/merge-cross-crate-info/overwrite-but-include/sierra.rs diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite-but-separate/auxiliary/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/overwrite-but-separate/auxiliary/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/overwrite-but-separate/auxiliary/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/overwrite-but-separate/auxiliary/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite-but-separate/auxiliary/tango.rs b/tests/rustdoc-html/merge-cross-crate-info/overwrite-but-separate/auxiliary/tango.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/overwrite-but-separate/auxiliary/tango.rs rename to tests/rustdoc-html/merge-cross-crate-info/overwrite-but-separate/auxiliary/tango.rs diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite-but-separate/sierra.rs b/tests/rustdoc-html/merge-cross-crate-info/overwrite-but-separate/sierra.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/overwrite-but-separate/sierra.rs rename to tests/rustdoc-html/merge-cross-crate-info/overwrite-but-separate/sierra.rs diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite/auxiliary/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/overwrite/auxiliary/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/overwrite/auxiliary/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/overwrite/auxiliary/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite/auxiliary/tango.rs b/tests/rustdoc-html/merge-cross-crate-info/overwrite/auxiliary/tango.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/overwrite/auxiliary/tango.rs rename to tests/rustdoc-html/merge-cross-crate-info/overwrite/auxiliary/tango.rs diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite/sierra.rs b/tests/rustdoc-html/merge-cross-crate-info/overwrite/sierra.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/overwrite/sierra.rs rename to tests/rustdoc-html/merge-cross-crate-info/overwrite/sierra.rs diff --git a/tests/rustdoc/merge-cross-crate-info/single-crate-finalize/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/single-crate-finalize/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/single-crate-finalize/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/single-crate-finalize/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/single-crate-read-write/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/single-crate-read-write/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/single-crate-read-write/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/single-crate-read-write/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/single-crate-write-anyway/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/single-crate-write-anyway/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/single-crate-write-anyway/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/single-crate-write-anyway/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/single-merge-none-useless-write/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/single-merge-none-useless-write/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/single-merge-none-useless-write/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/single-merge-none-useless-write/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-finalize/auxiliary/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/transitive-finalize/auxiliary/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/transitive-finalize/auxiliary/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/transitive-finalize/auxiliary/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-finalize/auxiliary/tango.rs b/tests/rustdoc-html/merge-cross-crate-info/transitive-finalize/auxiliary/tango.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/transitive-finalize/auxiliary/tango.rs rename to tests/rustdoc-html/merge-cross-crate-info/transitive-finalize/auxiliary/tango.rs diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-finalize/sierra.rs b/tests/rustdoc-html/merge-cross-crate-info/transitive-finalize/sierra.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/transitive-finalize/sierra.rs rename to tests/rustdoc-html/merge-cross-crate-info/transitive-finalize/sierra.rs diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-merge-none/auxiliary/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/transitive-merge-none/auxiliary/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/transitive-merge-none/auxiliary/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/transitive-merge-none/auxiliary/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-merge-none/auxiliary/tango.rs b/tests/rustdoc-html/merge-cross-crate-info/transitive-merge-none/auxiliary/tango.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/transitive-merge-none/auxiliary/tango.rs rename to tests/rustdoc-html/merge-cross-crate-info/transitive-merge-none/auxiliary/tango.rs diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-merge-none/sierra.rs b/tests/rustdoc-html/merge-cross-crate-info/transitive-merge-none/sierra.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/transitive-merge-none/sierra.rs rename to tests/rustdoc-html/merge-cross-crate-info/transitive-merge-none/sierra.rs diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-merge-read-write/auxiliary/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/transitive-merge-read-write/auxiliary/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/transitive-merge-read-write/auxiliary/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/transitive-merge-read-write/auxiliary/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-merge-read-write/auxiliary/tango.rs b/tests/rustdoc-html/merge-cross-crate-info/transitive-merge-read-write/auxiliary/tango.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/transitive-merge-read-write/auxiliary/tango.rs rename to tests/rustdoc-html/merge-cross-crate-info/transitive-merge-read-write/auxiliary/tango.rs diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-merge-read-write/sierra.rs b/tests/rustdoc-html/merge-cross-crate-info/transitive-merge-read-write/sierra.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/transitive-merge-read-write/sierra.rs rename to tests/rustdoc-html/merge-cross-crate-info/transitive-merge-read-write/sierra.rs diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-no-info/auxiliary/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/transitive-no-info/auxiliary/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/transitive-no-info/auxiliary/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/transitive-no-info/auxiliary/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-no-info/auxiliary/tango.rs b/tests/rustdoc-html/merge-cross-crate-info/transitive-no-info/auxiliary/tango.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/transitive-no-info/auxiliary/tango.rs rename to tests/rustdoc-html/merge-cross-crate-info/transitive-no-info/auxiliary/tango.rs diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-no-info/sierra.rs b/tests/rustdoc-html/merge-cross-crate-info/transitive-no-info/sierra.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/transitive-no-info/sierra.rs rename to tests/rustdoc-html/merge-cross-crate-info/transitive-no-info/sierra.rs diff --git a/tests/rustdoc/merge-cross-crate-info/two-separate-out-dir/auxiliary/foxtrot.rs b/tests/rustdoc-html/merge-cross-crate-info/two-separate-out-dir/auxiliary/foxtrot.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/two-separate-out-dir/auxiliary/foxtrot.rs rename to tests/rustdoc-html/merge-cross-crate-info/two-separate-out-dir/auxiliary/foxtrot.rs diff --git a/tests/rustdoc/merge-cross-crate-info/two-separate-out-dir/echo.rs b/tests/rustdoc-html/merge-cross-crate-info/two-separate-out-dir/echo.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/two-separate-out-dir/echo.rs rename to tests/rustdoc-html/merge-cross-crate-info/two-separate-out-dir/echo.rs diff --git a/tests/rustdoc/method-list.rs b/tests/rustdoc-html/method-list.rs similarity index 100% rename from tests/rustdoc/method-list.rs rename to tests/rustdoc-html/method-list.rs diff --git a/tests/rustdoc/mixing-doc-comments-and-attrs.S1_top-doc.html b/tests/rustdoc-html/mixing-doc-comments-and-attrs.S1_top-doc.html similarity index 100% rename from tests/rustdoc/mixing-doc-comments-and-attrs.S1_top-doc.html rename to tests/rustdoc-html/mixing-doc-comments-and-attrs.S1_top-doc.html diff --git a/tests/rustdoc/mixing-doc-comments-and-attrs.S2_top-doc.html b/tests/rustdoc-html/mixing-doc-comments-and-attrs.S2_top-doc.html similarity index 100% rename from tests/rustdoc/mixing-doc-comments-and-attrs.S2_top-doc.html rename to tests/rustdoc-html/mixing-doc-comments-and-attrs.S2_top-doc.html diff --git a/tests/rustdoc/mixing-doc-comments-and-attrs.S3_top-doc.html b/tests/rustdoc-html/mixing-doc-comments-and-attrs.S3_top-doc.html similarity index 100% rename from tests/rustdoc/mixing-doc-comments-and-attrs.S3_top-doc.html rename to tests/rustdoc-html/mixing-doc-comments-and-attrs.S3_top-doc.html diff --git a/tests/rustdoc/mixing-doc-comments-and-attrs.rs b/tests/rustdoc-html/mixing-doc-comments-and-attrs.rs similarity index 100% rename from tests/rustdoc/mixing-doc-comments-and-attrs.rs rename to tests/rustdoc-html/mixing-doc-comments-and-attrs.rs diff --git a/tests/rustdoc/mod-stackoverflow.rs b/tests/rustdoc-html/mod-stackoverflow.rs similarity index 100% rename from tests/rustdoc/mod-stackoverflow.rs rename to tests/rustdoc-html/mod-stackoverflow.rs diff --git a/tests/rustdoc/multiple-foreigns-w-same-name-99734.rs b/tests/rustdoc-html/multiple-foreigns-w-same-name-99734.rs similarity index 100% rename from tests/rustdoc/multiple-foreigns-w-same-name-99734.rs rename to tests/rustdoc-html/multiple-foreigns-w-same-name-99734.rs diff --git a/tests/rustdoc/multiple-import-levels.rs b/tests/rustdoc-html/multiple-import-levels.rs similarity index 100% rename from tests/rustdoc/multiple-import-levels.rs rename to tests/rustdoc-html/multiple-import-levels.rs diff --git a/tests/rustdoc/multiple-mods-w-same-name-99734.rs b/tests/rustdoc-html/multiple-mods-w-same-name-99734.rs similarity index 100% rename from tests/rustdoc/multiple-mods-w-same-name-99734.rs rename to tests/rustdoc-html/multiple-mods-w-same-name-99734.rs diff --git a/tests/rustdoc/multiple-mods-w-same-name-doc-inline-83375.rs b/tests/rustdoc-html/multiple-mods-w-same-name-doc-inline-83375.rs similarity index 100% rename from tests/rustdoc/multiple-mods-w-same-name-doc-inline-83375.rs rename to tests/rustdoc-html/multiple-mods-w-same-name-doc-inline-83375.rs diff --git a/tests/rustdoc/multiple-mods-w-same-name-doc-inline-last-item-83375.rs b/tests/rustdoc-html/multiple-mods-w-same-name-doc-inline-last-item-83375.rs similarity index 100% rename from tests/rustdoc/multiple-mods-w-same-name-doc-inline-last-item-83375.rs rename to tests/rustdoc-html/multiple-mods-w-same-name-doc-inline-last-item-83375.rs diff --git a/tests/rustdoc/multiple-structs-w-same-name-99221.rs b/tests/rustdoc-html/multiple-structs-w-same-name-99221.rs similarity index 100% rename from tests/rustdoc/multiple-structs-w-same-name-99221.rs rename to tests/rustdoc-html/multiple-structs-w-same-name-99221.rs diff --git a/tests/rustdoc/mut-params.rs b/tests/rustdoc-html/mut-params.rs similarity index 100% rename from tests/rustdoc/mut-params.rs rename to tests/rustdoc-html/mut-params.rs diff --git a/tests/rustdoc/namespaces.rs b/tests/rustdoc-html/namespaces.rs similarity index 100% rename from tests/rustdoc/namespaces.rs rename to tests/rustdoc-html/namespaces.rs diff --git a/tests/rustdoc/nested-items-issue-111415.rs b/tests/rustdoc-html/nested-items-issue-111415.rs similarity index 100% rename from tests/rustdoc/nested-items-issue-111415.rs rename to tests/rustdoc-html/nested-items-issue-111415.rs diff --git a/tests/rustdoc/nested-modules.rs b/tests/rustdoc-html/nested-modules.rs similarity index 100% rename from tests/rustdoc/nested-modules.rs rename to tests/rustdoc-html/nested-modules.rs diff --git a/tests/rustdoc/no-run-still-checks-lints.rs b/tests/rustdoc-html/no-run-still-checks-lints.rs similarity index 100% rename from tests/rustdoc/no-run-still-checks-lints.rs rename to tests/rustdoc-html/no-run-still-checks-lints.rs diff --git a/tests/rustdoc/no-stack-overflow-25295.rs b/tests/rustdoc-html/no-stack-overflow-25295.rs similarity index 100% rename from tests/rustdoc/no-stack-overflow-25295.rs rename to tests/rustdoc-html/no-stack-overflow-25295.rs diff --git a/tests/rustdoc/no-unit-struct-field.rs b/tests/rustdoc-html/no-unit-struct-field.rs similarity index 100% rename from tests/rustdoc/no-unit-struct-field.rs rename to tests/rustdoc-html/no-unit-struct-field.rs diff --git a/tests/rustdoc/non_lifetime_binders.rs b/tests/rustdoc-html/non_lifetime_binders.rs similarity index 100% rename from tests/rustdoc/non_lifetime_binders.rs rename to tests/rustdoc-html/non_lifetime_binders.rs diff --git a/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs b/tests/rustdoc-html/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs similarity index 100% rename from tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs rename to tests/rustdoc-html/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs diff --git a/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs b/tests/rustdoc-html/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs similarity index 100% rename from tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs rename to tests/rustdoc-html/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs diff --git a/tests/rustdoc/notable-trait/doc-notable_trait-negative.negative.html b/tests/rustdoc-html/notable-trait/doc-notable_trait-negative.negative.html similarity index 100% rename from tests/rustdoc/notable-trait/doc-notable_trait-negative.negative.html rename to tests/rustdoc-html/notable-trait/doc-notable_trait-negative.negative.html diff --git a/tests/rustdoc/notable-trait/doc-notable_trait-negative.positive.html b/tests/rustdoc-html/notable-trait/doc-notable_trait-negative.positive.html similarity index 100% rename from tests/rustdoc/notable-trait/doc-notable_trait-negative.positive.html rename to tests/rustdoc-html/notable-trait/doc-notable_trait-negative.positive.html diff --git a/tests/rustdoc/notable-trait/doc-notable_trait-negative.rs b/tests/rustdoc-html/notable-trait/doc-notable_trait-negative.rs similarity index 100% rename from tests/rustdoc/notable-trait/doc-notable_trait-negative.rs rename to tests/rustdoc-html/notable-trait/doc-notable_trait-negative.rs diff --git a/tests/rustdoc/notable-trait/doc-notable_trait-slice.bare_fn_matches.html b/tests/rustdoc-html/notable-trait/doc-notable_trait-slice.bare_fn_matches.html similarity index 100% rename from tests/rustdoc/notable-trait/doc-notable_trait-slice.bare_fn_matches.html rename to tests/rustdoc-html/notable-trait/doc-notable_trait-slice.bare_fn_matches.html diff --git a/tests/rustdoc/notable-trait/doc-notable_trait-slice.rs b/tests/rustdoc-html/notable-trait/doc-notable_trait-slice.rs similarity index 100% rename from tests/rustdoc/notable-trait/doc-notable_trait-slice.rs rename to tests/rustdoc-html/notable-trait/doc-notable_trait-slice.rs diff --git a/tests/rustdoc/notable-trait/doc-notable_trait.bare-fn.html b/tests/rustdoc-html/notable-trait/doc-notable_trait.bare-fn.html similarity index 100% rename from tests/rustdoc/notable-trait/doc-notable_trait.bare-fn.html rename to tests/rustdoc-html/notable-trait/doc-notable_trait.bare-fn.html diff --git a/tests/rustdoc/notable-trait/doc-notable_trait.rs b/tests/rustdoc-html/notable-trait/doc-notable_trait.rs similarity index 100% rename from tests/rustdoc/notable-trait/doc-notable_trait.rs rename to tests/rustdoc-html/notable-trait/doc-notable_trait.rs diff --git a/tests/rustdoc/notable-trait/doc-notable_trait.some-struct-new.html b/tests/rustdoc-html/notable-trait/doc-notable_trait.some-struct-new.html similarity index 100% rename from tests/rustdoc/notable-trait/doc-notable_trait.some-struct-new.html rename to tests/rustdoc-html/notable-trait/doc-notable_trait.some-struct-new.html diff --git a/tests/rustdoc/notable-trait/doc-notable_trait.wrap-me.html b/tests/rustdoc-html/notable-trait/doc-notable_trait.wrap-me.html similarity index 100% rename from tests/rustdoc/notable-trait/doc-notable_trait.wrap-me.html rename to tests/rustdoc-html/notable-trait/doc-notable_trait.wrap-me.html diff --git a/tests/rustdoc/notable-trait/doc-notable_trait_box_is_not_an_iterator.rs b/tests/rustdoc-html/notable-trait/doc-notable_trait_box_is_not_an_iterator.rs similarity index 100% rename from tests/rustdoc/notable-trait/doc-notable_trait_box_is_not_an_iterator.rs rename to tests/rustdoc-html/notable-trait/doc-notable_trait_box_is_not_an_iterator.rs diff --git a/tests/rustdoc/notable-trait/notable-trait-generics.rs b/tests/rustdoc-html/notable-trait/notable-trait-generics.rs similarity index 100% rename from tests/rustdoc/notable-trait/notable-trait-generics.rs rename to tests/rustdoc-html/notable-trait/notable-trait-generics.rs diff --git a/tests/rustdoc/notable-trait/spotlight-from-dependency.odd.html b/tests/rustdoc-html/notable-trait/spotlight-from-dependency.odd.html similarity index 100% rename from tests/rustdoc/notable-trait/spotlight-from-dependency.odd.html rename to tests/rustdoc-html/notable-trait/spotlight-from-dependency.odd.html diff --git a/tests/rustdoc/notable-trait/spotlight-from-dependency.rs b/tests/rustdoc-html/notable-trait/spotlight-from-dependency.rs similarity index 100% rename from tests/rustdoc/notable-trait/spotlight-from-dependency.rs rename to tests/rustdoc-html/notable-trait/spotlight-from-dependency.rs diff --git a/tests/rustdoc/nul-error.rs b/tests/rustdoc-html/nul-error.rs similarity index 100% rename from tests/rustdoc/nul-error.rs rename to tests/rustdoc-html/nul-error.rs diff --git a/tests/rustdoc/playground-arg.rs b/tests/rustdoc-html/playground-arg.rs similarity index 100% rename from tests/rustdoc/playground-arg.rs rename to tests/rustdoc-html/playground-arg.rs diff --git a/tests/rustdoc/playground-empty.rs b/tests/rustdoc-html/playground-empty.rs similarity index 100% rename from tests/rustdoc/playground-empty.rs rename to tests/rustdoc-html/playground-empty.rs diff --git a/tests/rustdoc/playground-none.rs b/tests/rustdoc-html/playground-none.rs similarity index 100% rename from tests/rustdoc/playground-none.rs rename to tests/rustdoc-html/playground-none.rs diff --git a/tests/rustdoc/playground-syntax-error.rs b/tests/rustdoc-html/playground-syntax-error.rs similarity index 100% rename from tests/rustdoc/playground-syntax-error.rs rename to tests/rustdoc-html/playground-syntax-error.rs diff --git a/tests/rustdoc/playground.rs b/tests/rustdoc-html/playground.rs similarity index 100% rename from tests/rustdoc/playground.rs rename to tests/rustdoc-html/playground.rs diff --git a/tests/rustdoc/primitive/auxiliary/issue-15318.rs b/tests/rustdoc-html/primitive/auxiliary/issue-15318.rs similarity index 100% rename from tests/rustdoc/primitive/auxiliary/issue-15318.rs rename to tests/rustdoc-html/primitive/auxiliary/issue-15318.rs diff --git a/tests/rustdoc/primitive/auxiliary/primitive-doc.rs b/tests/rustdoc-html/primitive/auxiliary/primitive-doc.rs similarity index 100% rename from tests/rustdoc/primitive/auxiliary/primitive-doc.rs rename to tests/rustdoc-html/primitive/auxiliary/primitive-doc.rs diff --git a/tests/rustdoc/primitive/cross-crate-primitive-doc.rs b/tests/rustdoc-html/primitive/cross-crate-primitive-doc.rs similarity index 100% rename from tests/rustdoc/primitive/cross-crate-primitive-doc.rs rename to tests/rustdoc-html/primitive/cross-crate-primitive-doc.rs diff --git a/tests/rustdoc/primitive/no_std-primitive.rs b/tests/rustdoc-html/primitive/no_std-primitive.rs similarity index 100% rename from tests/rustdoc/primitive/no_std-primitive.rs rename to tests/rustdoc-html/primitive/no_std-primitive.rs diff --git a/tests/rustdoc/primitive/no_std.rs b/tests/rustdoc-html/primitive/no_std.rs similarity index 100% rename from tests/rustdoc/primitive/no_std.rs rename to tests/rustdoc-html/primitive/no_std.rs diff --git a/tests/rustdoc/primitive/primitive-generic-impl.rs b/tests/rustdoc-html/primitive/primitive-generic-impl.rs similarity index 100% rename from tests/rustdoc/primitive/primitive-generic-impl.rs rename to tests/rustdoc-html/primitive/primitive-generic-impl.rs diff --git a/tests/rustdoc/primitive/primitive-link.rs b/tests/rustdoc-html/primitive/primitive-link.rs similarity index 100% rename from tests/rustdoc/primitive/primitive-link.rs rename to tests/rustdoc-html/primitive/primitive-link.rs diff --git a/tests/rustdoc/primitive/primitive-raw-pointer-dox-15318-3.rs b/tests/rustdoc-html/primitive/primitive-raw-pointer-dox-15318-3.rs similarity index 100% rename from tests/rustdoc/primitive/primitive-raw-pointer-dox-15318-3.rs rename to tests/rustdoc-html/primitive/primitive-raw-pointer-dox-15318-3.rs diff --git a/tests/rustdoc/primitive/primitive-raw-pointer-link-15318.rs b/tests/rustdoc-html/primitive/primitive-raw-pointer-link-15318.rs similarity index 100% rename from tests/rustdoc/primitive/primitive-raw-pointer-link-15318.rs rename to tests/rustdoc-html/primitive/primitive-raw-pointer-link-15318.rs diff --git a/tests/rustdoc/primitive/primitive-raw-pointer-link-no-inlined-15318-2.rs b/tests/rustdoc-html/primitive/primitive-raw-pointer-link-no-inlined-15318-2.rs similarity index 100% rename from tests/rustdoc/primitive/primitive-raw-pointer-link-no-inlined-15318-2.rs rename to tests/rustdoc-html/primitive/primitive-raw-pointer-link-no-inlined-15318-2.rs diff --git a/tests/rustdoc/primitive/primitive-reference.rs b/tests/rustdoc-html/primitive/primitive-reference.rs similarity index 100% rename from tests/rustdoc/primitive/primitive-reference.rs rename to tests/rustdoc-html/primitive/primitive-reference.rs diff --git a/tests/rustdoc/primitive/primitive-slice-auto-trait.rs b/tests/rustdoc-html/primitive/primitive-slice-auto-trait.rs similarity index 100% rename from tests/rustdoc/primitive/primitive-slice-auto-trait.rs rename to tests/rustdoc-html/primitive/primitive-slice-auto-trait.rs diff --git a/tests/rustdoc/primitive/primitive-tuple-auto-trait.rs b/tests/rustdoc-html/primitive/primitive-tuple-auto-trait.rs similarity index 100% rename from tests/rustdoc/primitive/primitive-tuple-auto-trait.rs rename to tests/rustdoc-html/primitive/primitive-tuple-auto-trait.rs diff --git a/tests/rustdoc/primitive/primitive-tuple-variadic.rs b/tests/rustdoc-html/primitive/primitive-tuple-variadic.rs similarity index 100% rename from tests/rustdoc/primitive/primitive-tuple-variadic.rs rename to tests/rustdoc-html/primitive/primitive-tuple-variadic.rs diff --git a/tests/rustdoc/primitive/primitive-unit-auto-trait.rs b/tests/rustdoc-html/primitive/primitive-unit-auto-trait.rs similarity index 100% rename from tests/rustdoc/primitive/primitive-unit-auto-trait.rs rename to tests/rustdoc-html/primitive/primitive-unit-auto-trait.rs diff --git a/tests/rustdoc/primitive/primitive.rs b/tests/rustdoc-html/primitive/primitive.rs similarity index 100% rename from tests/rustdoc/primitive/primitive.rs rename to tests/rustdoc-html/primitive/primitive.rs diff --git a/tests/rustdoc/primitive/search-index-primitive-inherent-method-23511.rs b/tests/rustdoc-html/primitive/search-index-primitive-inherent-method-23511.rs similarity index 100% rename from tests/rustdoc/primitive/search-index-primitive-inherent-method-23511.rs rename to tests/rustdoc-html/primitive/search-index-primitive-inherent-method-23511.rs diff --git a/tests/rustdoc/private/doc-hidden-private-67851-both.rs b/tests/rustdoc-html/private/doc-hidden-private-67851-both.rs similarity index 100% rename from tests/rustdoc/private/doc-hidden-private-67851-both.rs rename to tests/rustdoc-html/private/doc-hidden-private-67851-both.rs diff --git a/tests/rustdoc/private/doc-hidden-private-67851-hidden.rs b/tests/rustdoc-html/private/doc-hidden-private-67851-hidden.rs similarity index 100% rename from tests/rustdoc/private/doc-hidden-private-67851-hidden.rs rename to tests/rustdoc-html/private/doc-hidden-private-67851-hidden.rs diff --git a/tests/rustdoc/private/doc-hidden-private-67851-neither.rs b/tests/rustdoc-html/private/doc-hidden-private-67851-neither.rs similarity index 100% rename from tests/rustdoc/private/doc-hidden-private-67851-neither.rs rename to tests/rustdoc-html/private/doc-hidden-private-67851-neither.rs diff --git a/tests/rustdoc/private/doc-hidden-private-67851-private.rs b/tests/rustdoc-html/private/doc-hidden-private-67851-private.rs similarity index 100% rename from tests/rustdoc/private/doc-hidden-private-67851-private.rs rename to tests/rustdoc-html/private/doc-hidden-private-67851-private.rs diff --git a/tests/rustdoc/private/empty-impl-block-private-with-doc.rs b/tests/rustdoc-html/private/empty-impl-block-private-with-doc.rs similarity index 100% rename from tests/rustdoc/private/empty-impl-block-private-with-doc.rs rename to tests/rustdoc-html/private/empty-impl-block-private-with-doc.rs diff --git a/tests/rustdoc/private/empty-impl-block-private.rs b/tests/rustdoc-html/private/empty-impl-block-private.rs similarity index 100% rename from tests/rustdoc/private/empty-impl-block-private.rs rename to tests/rustdoc-html/private/empty-impl-block-private.rs diff --git a/tests/rustdoc/private/empty-mod-private.rs b/tests/rustdoc-html/private/empty-mod-private.rs similarity index 100% rename from tests/rustdoc/private/empty-mod-private.rs rename to tests/rustdoc-html/private/empty-mod-private.rs diff --git a/tests/rustdoc/private/enum-variant-private-46767.rs b/tests/rustdoc-html/private/enum-variant-private-46767.rs similarity index 100% rename from tests/rustdoc/private/enum-variant-private-46767.rs rename to tests/rustdoc-html/private/enum-variant-private-46767.rs diff --git a/tests/rustdoc/private/files-creation-private.rs b/tests/rustdoc-html/private/files-creation-private.rs similarity index 100% rename from tests/rustdoc/private/files-creation-private.rs rename to tests/rustdoc-html/private/files-creation-private.rs diff --git a/tests/rustdoc/private/hidden-private.rs b/tests/rustdoc-html/private/hidden-private.rs similarity index 100% rename from tests/rustdoc/private/hidden-private.rs rename to tests/rustdoc-html/private/hidden-private.rs diff --git a/tests/rustdoc/private/inline-private-with-intermediate-doc-hidden.rs b/tests/rustdoc-html/private/inline-private-with-intermediate-doc-hidden.rs similarity index 100% rename from tests/rustdoc/private/inline-private-with-intermediate-doc-hidden.rs rename to tests/rustdoc-html/private/inline-private-with-intermediate-doc-hidden.rs diff --git a/tests/rustdoc/private/inner-private-110422.rs b/tests/rustdoc-html/private/inner-private-110422.rs similarity index 100% rename from tests/rustdoc/private/inner-private-110422.rs rename to tests/rustdoc-html/private/inner-private-110422.rs diff --git a/tests/rustdoc/private/macro-document-private-duplicate.rs b/tests/rustdoc-html/private/macro-document-private-duplicate.rs similarity index 100% rename from tests/rustdoc/private/macro-document-private-duplicate.rs rename to tests/rustdoc-html/private/macro-document-private-duplicate.rs diff --git a/tests/rustdoc/private/macro-document-private.rs b/tests/rustdoc-html/private/macro-document-private.rs similarity index 100% rename from tests/rustdoc/private/macro-document-private.rs rename to tests/rustdoc-html/private/macro-document-private.rs diff --git a/tests/rustdoc/private/macro-private-not-documented.rs b/tests/rustdoc-html/private/macro-private-not-documented.rs similarity index 100% rename from tests/rustdoc/private/macro-private-not-documented.rs rename to tests/rustdoc-html/private/macro-private-not-documented.rs diff --git a/tests/rustdoc/private/missing-private-inlining-109258.rs b/tests/rustdoc-html/private/missing-private-inlining-109258.rs similarity index 100% rename from tests/rustdoc/private/missing-private-inlining-109258.rs rename to tests/rustdoc-html/private/missing-private-inlining-109258.rs diff --git a/tests/rustdoc/private/private-fields-tuple-struct.rs b/tests/rustdoc-html/private/private-fields-tuple-struct.rs similarity index 100% rename from tests/rustdoc/private/private-fields-tuple-struct.rs rename to tests/rustdoc-html/private/private-fields-tuple-struct.rs diff --git a/tests/rustdoc/private/private-non-local-fields-2.rs b/tests/rustdoc-html/private/private-non-local-fields-2.rs similarity index 100% rename from tests/rustdoc/private/private-non-local-fields-2.rs rename to tests/rustdoc-html/private/private-non-local-fields-2.rs diff --git a/tests/rustdoc/private/private-non-local-fields.rs b/tests/rustdoc-html/private/private-non-local-fields.rs similarity index 100% rename from tests/rustdoc/private/private-non-local-fields.rs rename to tests/rustdoc-html/private/private-non-local-fields.rs diff --git a/tests/rustdoc/private/private-type-alias.rs b/tests/rustdoc-html/private/private-type-alias.rs similarity index 100% rename from tests/rustdoc/private/private-type-alias.rs rename to tests/rustdoc-html/private/private-type-alias.rs diff --git a/tests/rustdoc/private/private-type-cycle-110629.rs b/tests/rustdoc-html/private/private-type-cycle-110629.rs similarity index 100% rename from tests/rustdoc/private/private-type-cycle-110629.rs rename to tests/rustdoc-html/private/private-type-cycle-110629.rs diff --git a/tests/rustdoc/private/private-use-decl-macro-47038.rs b/tests/rustdoc-html/private/private-use-decl-macro-47038.rs similarity index 100% rename from tests/rustdoc/private/private-use-decl-macro-47038.rs rename to tests/rustdoc-html/private/private-use-decl-macro-47038.rs diff --git a/tests/rustdoc/private/private-use.rs b/tests/rustdoc-html/private/private-use.rs similarity index 100% rename from tests/rustdoc/private/private-use.rs rename to tests/rustdoc-html/private/private-use.rs diff --git a/tests/rustdoc/private/public-impl-mention-private-generic-46380-2.rs b/tests/rustdoc-html/private/public-impl-mention-private-generic-46380-2.rs similarity index 100% rename from tests/rustdoc/private/public-impl-mention-private-generic-46380-2.rs rename to tests/rustdoc-html/private/public-impl-mention-private-generic-46380-2.rs diff --git a/tests/rustdoc/private/traits-in-bodies-private.rs b/tests/rustdoc-html/private/traits-in-bodies-private.rs similarity index 100% rename from tests/rustdoc/private/traits-in-bodies-private.rs rename to tests/rustdoc-html/private/traits-in-bodies-private.rs diff --git a/tests/rustdoc/process-termination.rs b/tests/rustdoc-html/process-termination.rs similarity index 100% rename from tests/rustdoc/process-termination.rs rename to tests/rustdoc-html/process-termination.rs diff --git a/tests/rustdoc/pub-method.rs b/tests/rustdoc-html/pub-method.rs similarity index 100% rename from tests/rustdoc/pub-method.rs rename to tests/rustdoc-html/pub-method.rs diff --git a/tests/rustdoc/pub-use-loop-107350.rs b/tests/rustdoc-html/pub-use-loop-107350.rs similarity index 100% rename from tests/rustdoc/pub-use-loop-107350.rs rename to tests/rustdoc-html/pub-use-loop-107350.rs diff --git a/tests/rustdoc/pub-use-root-path-95873.rs b/tests/rustdoc-html/pub-use-root-path-95873.rs similarity index 100% rename from tests/rustdoc/pub-use-root-path-95873.rs rename to tests/rustdoc-html/pub-use-root-path-95873.rs diff --git a/tests/rustdoc/range-arg-pattern.rs b/tests/rustdoc-html/range-arg-pattern.rs similarity index 100% rename from tests/rustdoc/range-arg-pattern.rs rename to tests/rustdoc-html/range-arg-pattern.rs diff --git a/tests/rustdoc/raw-ident-eliminate-r-hashtag.rs b/tests/rustdoc-html/raw-ident-eliminate-r-hashtag.rs similarity index 100% rename from tests/rustdoc/raw-ident-eliminate-r-hashtag.rs rename to tests/rustdoc-html/raw-ident-eliminate-r-hashtag.rs diff --git a/tests/rustdoc/read-more-unneeded.rs b/tests/rustdoc-html/read-more-unneeded.rs similarity index 100% rename from tests/rustdoc/read-more-unneeded.rs rename to tests/rustdoc-html/read-more-unneeded.rs diff --git a/tests/rustdoc/recursion1.rs b/tests/rustdoc-html/recursion1.rs similarity index 100% rename from tests/rustdoc/recursion1.rs rename to tests/rustdoc-html/recursion1.rs diff --git a/tests/rustdoc/recursion2.rs b/tests/rustdoc-html/recursion2.rs similarity index 100% rename from tests/rustdoc/recursion2.rs rename to tests/rustdoc-html/recursion2.rs diff --git a/tests/rustdoc/recursion3.rs b/tests/rustdoc-html/recursion3.rs similarity index 100% rename from tests/rustdoc/recursion3.rs rename to tests/rustdoc-html/recursion3.rs diff --git a/tests/rustdoc/redirect-map-empty.rs b/tests/rustdoc-html/redirect-map-empty.rs similarity index 100% rename from tests/rustdoc/redirect-map-empty.rs rename to tests/rustdoc-html/redirect-map-empty.rs diff --git a/tests/rustdoc/redirect-map.rs b/tests/rustdoc-html/redirect-map.rs similarity index 100% rename from tests/rustdoc/redirect-map.rs rename to tests/rustdoc-html/redirect-map.rs diff --git a/tests/rustdoc/redirect-rename.rs b/tests/rustdoc-html/redirect-rename.rs similarity index 100% rename from tests/rustdoc/redirect-rename.rs rename to tests/rustdoc-html/redirect-rename.rs diff --git a/tests/rustdoc/redirect.rs b/tests/rustdoc-html/redirect.rs similarity index 100% rename from tests/rustdoc/redirect.rs rename to tests/rustdoc-html/redirect.rs diff --git a/tests/rustdoc/reexport/alias-reexport.rs b/tests/rustdoc-html/reexport/alias-reexport.rs similarity index 100% rename from tests/rustdoc/reexport/alias-reexport.rs rename to tests/rustdoc-html/reexport/alias-reexport.rs diff --git a/tests/rustdoc/reexport/alias-reexport2.rs b/tests/rustdoc-html/reexport/alias-reexport2.rs similarity index 100% rename from tests/rustdoc/reexport/alias-reexport2.rs rename to tests/rustdoc-html/reexport/alias-reexport2.rs diff --git a/tests/rustdoc/reexport/anonymous-reexport-108931.rs b/tests/rustdoc-html/reexport/anonymous-reexport-108931.rs similarity index 100% rename from tests/rustdoc/reexport/anonymous-reexport-108931.rs rename to tests/rustdoc-html/reexport/anonymous-reexport-108931.rs diff --git a/tests/rustdoc/reexport/anonymous-reexport.rs b/tests/rustdoc-html/reexport/anonymous-reexport.rs similarity index 100% rename from tests/rustdoc/reexport/anonymous-reexport.rs rename to tests/rustdoc-html/reexport/anonymous-reexport.rs diff --git a/tests/rustdoc/reexport/auxiliary/alias-reexport.rs b/tests/rustdoc-html/reexport/auxiliary/alias-reexport.rs similarity index 100% rename from tests/rustdoc/reexport/auxiliary/alias-reexport.rs rename to tests/rustdoc-html/reexport/auxiliary/alias-reexport.rs diff --git a/tests/rustdoc/reexport/auxiliary/alias-reexport2.rs b/tests/rustdoc-html/reexport/auxiliary/alias-reexport2.rs similarity index 100% rename from tests/rustdoc/reexport/auxiliary/alias-reexport2.rs rename to tests/rustdoc-html/reexport/auxiliary/alias-reexport2.rs diff --git a/tests/rustdoc/reexport/auxiliary/all-item-types.rs b/tests/rustdoc-html/reexport/auxiliary/all-item-types.rs similarity index 100% rename from tests/rustdoc/reexport/auxiliary/all-item-types.rs rename to tests/rustdoc-html/reexport/auxiliary/all-item-types.rs diff --git a/tests/rustdoc/reexport/auxiliary/issue-28927-1.rs b/tests/rustdoc-html/reexport/auxiliary/issue-28927-1.rs similarity index 100% rename from tests/rustdoc/reexport/auxiliary/issue-28927-1.rs rename to tests/rustdoc-html/reexport/auxiliary/issue-28927-1.rs diff --git a/tests/rustdoc/reexport/auxiliary/issue-28927-2.rs b/tests/rustdoc-html/reexport/auxiliary/issue-28927-2.rs similarity index 100% rename from tests/rustdoc/reexport/auxiliary/issue-28927-2.rs rename to tests/rustdoc-html/reexport/auxiliary/issue-28927-2.rs diff --git a/tests/rustdoc/reexport/auxiliary/primitive-reexport.rs b/tests/rustdoc-html/reexport/auxiliary/primitive-reexport.rs similarity index 100% rename from tests/rustdoc/reexport/auxiliary/primitive-reexport.rs rename to tests/rustdoc-html/reexport/auxiliary/primitive-reexport.rs diff --git a/tests/rustdoc/reexport/auxiliary/reexport-check.rs b/tests/rustdoc-html/reexport/auxiliary/reexport-check.rs similarity index 100% rename from tests/rustdoc/reexport/auxiliary/reexport-check.rs rename to tests/rustdoc-html/reexport/auxiliary/reexport-check.rs diff --git a/tests/rustdoc/reexport/auxiliary/reexport-doc-aux.rs b/tests/rustdoc-html/reexport/auxiliary/reexport-doc-aux.rs similarity index 100% rename from tests/rustdoc/reexport/auxiliary/reexport-doc-aux.rs rename to tests/rustdoc-html/reexport/auxiliary/reexport-doc-aux.rs diff --git a/tests/rustdoc/reexport/auxiliary/reexports.rs b/tests/rustdoc-html/reexport/auxiliary/reexports.rs similarity index 100% rename from tests/rustdoc/reexport/auxiliary/reexports.rs rename to tests/rustdoc-html/reexport/auxiliary/reexports.rs diff --git a/tests/rustdoc/reexport/auxiliary/wrap-unnamable-type.rs b/tests/rustdoc-html/reexport/auxiliary/wrap-unnamable-type.rs similarity index 100% rename from tests/rustdoc/reexport/auxiliary/wrap-unnamable-type.rs rename to tests/rustdoc-html/reexport/auxiliary/wrap-unnamable-type.rs diff --git a/tests/rustdoc/reexport/blanket-reexport-item.rs b/tests/rustdoc-html/reexport/blanket-reexport-item.rs similarity index 100% rename from tests/rustdoc/reexport/blanket-reexport-item.rs rename to tests/rustdoc-html/reexport/blanket-reexport-item.rs diff --git a/tests/rustdoc/reexport/cfg_doc_reexport.rs b/tests/rustdoc-html/reexport/cfg_doc_reexport.rs similarity index 100% rename from tests/rustdoc/reexport/cfg_doc_reexport.rs rename to tests/rustdoc-html/reexport/cfg_doc_reexport.rs diff --git a/tests/rustdoc/reexport/doc-hidden-reexports-109449.rs b/tests/rustdoc-html/reexport/doc-hidden-reexports-109449.rs similarity index 100% rename from tests/rustdoc/reexport/doc-hidden-reexports-109449.rs rename to tests/rustdoc-html/reexport/doc-hidden-reexports-109449.rs diff --git a/tests/rustdoc/reexport/duplicated-glob-reexport-60522.rs b/tests/rustdoc-html/reexport/duplicated-glob-reexport-60522.rs similarity index 100% rename from tests/rustdoc/reexport/duplicated-glob-reexport-60522.rs rename to tests/rustdoc-html/reexport/duplicated-glob-reexport-60522.rs diff --git a/tests/rustdoc/reexport/enum-variant-reexport-35488.rs b/tests/rustdoc-html/reexport/enum-variant-reexport-35488.rs similarity index 100% rename from tests/rustdoc/reexport/enum-variant-reexport-35488.rs rename to tests/rustdoc-html/reexport/enum-variant-reexport-35488.rs diff --git a/tests/rustdoc/reexport/enum-variant.rs b/tests/rustdoc-html/reexport/enum-variant.rs similarity index 100% rename from tests/rustdoc/reexport/enum-variant.rs rename to tests/rustdoc-html/reexport/enum-variant.rs diff --git a/tests/rustdoc/reexport/extern-135092.rs b/tests/rustdoc-html/reexport/extern-135092.rs similarity index 100% rename from tests/rustdoc/reexport/extern-135092.rs rename to tests/rustdoc-html/reexport/extern-135092.rs diff --git a/tests/rustdoc/reexport/foreigntype-reexport.rs b/tests/rustdoc-html/reexport/foreigntype-reexport.rs similarity index 100% rename from tests/rustdoc/reexport/foreigntype-reexport.rs rename to tests/rustdoc-html/reexport/foreigntype-reexport.rs diff --git a/tests/rustdoc/reexport/glob-reexport-attribute-merge-120487.rs b/tests/rustdoc-html/reexport/glob-reexport-attribute-merge-120487.rs similarity index 100% rename from tests/rustdoc/reexport/glob-reexport-attribute-merge-120487.rs rename to tests/rustdoc-html/reexport/glob-reexport-attribute-merge-120487.rs diff --git a/tests/rustdoc/reexport/glob-reexport-attribute-merge-doc-auto-cfg.rs b/tests/rustdoc-html/reexport/glob-reexport-attribute-merge-doc-auto-cfg.rs similarity index 100% rename from tests/rustdoc/reexport/glob-reexport-attribute-merge-doc-auto-cfg.rs rename to tests/rustdoc-html/reexport/glob-reexport-attribute-merge-doc-auto-cfg.rs diff --git a/tests/rustdoc/reexport/ice-reexport-crate-root-28927.rs b/tests/rustdoc-html/reexport/ice-reexport-crate-root-28927.rs similarity index 100% rename from tests/rustdoc/reexport/ice-reexport-crate-root-28927.rs rename to tests/rustdoc-html/reexport/ice-reexport-crate-root-28927.rs diff --git a/tests/rustdoc/reexport/import_trait_associated_functions.rs b/tests/rustdoc-html/reexport/import_trait_associated_functions.rs similarity index 100% rename from tests/rustdoc/reexport/import_trait_associated_functions.rs rename to tests/rustdoc-html/reexport/import_trait_associated_functions.rs diff --git a/tests/rustdoc/reexport/local-reexport-doc.rs b/tests/rustdoc-html/reexport/local-reexport-doc.rs similarity index 100% rename from tests/rustdoc/reexport/local-reexport-doc.rs rename to tests/rustdoc-html/reexport/local-reexport-doc.rs diff --git a/tests/rustdoc/reexport/merge-glob-and-non-glob.rs b/tests/rustdoc-html/reexport/merge-glob-and-non-glob.rs similarity index 100% rename from tests/rustdoc/reexport/merge-glob-and-non-glob.rs rename to tests/rustdoc-html/reexport/merge-glob-and-non-glob.rs diff --git a/tests/rustdoc/reexport/no-compiler-reexport.rs b/tests/rustdoc-html/reexport/no-compiler-reexport.rs similarity index 100% rename from tests/rustdoc/reexport/no-compiler-reexport.rs rename to tests/rustdoc-html/reexport/no-compiler-reexport.rs diff --git a/tests/rustdoc/reexport/overlapping-reexport-105735-2.rs b/tests/rustdoc-html/reexport/overlapping-reexport-105735-2.rs similarity index 100% rename from tests/rustdoc/reexport/overlapping-reexport-105735-2.rs rename to tests/rustdoc-html/reexport/overlapping-reexport-105735-2.rs diff --git a/tests/rustdoc/reexport/overlapping-reexport-105735.rs b/tests/rustdoc-html/reexport/overlapping-reexport-105735.rs similarity index 100% rename from tests/rustdoc/reexport/overlapping-reexport-105735.rs rename to tests/rustdoc-html/reexport/overlapping-reexport-105735.rs diff --git a/tests/rustdoc/reexport/primitive-reexport.rs b/tests/rustdoc-html/reexport/primitive-reexport.rs similarity index 100% rename from tests/rustdoc/reexport/primitive-reexport.rs rename to tests/rustdoc-html/reexport/primitive-reexport.rs diff --git a/tests/rustdoc/reexport/private-mod-override-reexport.rs b/tests/rustdoc-html/reexport/private-mod-override-reexport.rs similarity index 100% rename from tests/rustdoc/reexport/private-mod-override-reexport.rs rename to tests/rustdoc-html/reexport/private-mod-override-reexport.rs diff --git a/tests/rustdoc/reexport/pub-reexport-of-pub-reexport-46506.rs b/tests/rustdoc-html/reexport/pub-reexport-of-pub-reexport-46506.rs similarity index 100% rename from tests/rustdoc/reexport/pub-reexport-of-pub-reexport-46506.rs rename to tests/rustdoc-html/reexport/pub-reexport-of-pub-reexport-46506.rs diff --git a/tests/rustdoc/reexport/reexport-attr-merge.rs b/tests/rustdoc-html/reexport/reexport-attr-merge.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-attr-merge.rs rename to tests/rustdoc-html/reexport/reexport-attr-merge.rs diff --git a/tests/rustdoc/reexport/reexport-cfg.rs b/tests/rustdoc-html/reexport/reexport-cfg.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-cfg.rs rename to tests/rustdoc-html/reexport/reexport-cfg.rs diff --git a/tests/rustdoc/reexport/reexport-check.rs b/tests/rustdoc-html/reexport/reexport-check.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-check.rs rename to tests/rustdoc-html/reexport/reexport-check.rs diff --git a/tests/rustdoc/reexport/reexport-dep-foreign-fn.rs b/tests/rustdoc-html/reexport/reexport-dep-foreign-fn.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-dep-foreign-fn.rs rename to tests/rustdoc-html/reexport/reexport-dep-foreign-fn.rs diff --git a/tests/rustdoc/reexport/reexport-doc-hidden-inside-private.rs b/tests/rustdoc-html/reexport/reexport-doc-hidden-inside-private.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-doc-hidden-inside-private.rs rename to tests/rustdoc-html/reexport/reexport-doc-hidden-inside-private.rs diff --git a/tests/rustdoc/reexport/reexport-doc-hidden.rs b/tests/rustdoc-html/reexport/reexport-doc-hidden.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-doc-hidden.rs rename to tests/rustdoc-html/reexport/reexport-doc-hidden.rs diff --git a/tests/rustdoc/reexport/reexport-doc.rs b/tests/rustdoc-html/reexport/reexport-doc.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-doc.rs rename to tests/rustdoc-html/reexport/reexport-doc.rs diff --git a/tests/rustdoc/reexport/reexport-hidden-macro.rs b/tests/rustdoc-html/reexport/reexport-hidden-macro.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-hidden-macro.rs rename to tests/rustdoc-html/reexport/reexport-hidden-macro.rs diff --git a/tests/rustdoc/reexport/reexport-macro.rs b/tests/rustdoc-html/reexport/reexport-macro.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-macro.rs rename to tests/rustdoc-html/reexport/reexport-macro.rs diff --git a/tests/rustdoc/reexport/reexport-of-doc-hidden.rs b/tests/rustdoc-html/reexport/reexport-of-doc-hidden.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-of-doc-hidden.rs rename to tests/rustdoc-html/reexport/reexport-of-doc-hidden.rs diff --git a/tests/rustdoc/reexport/reexport-of-reexport-108679.rs b/tests/rustdoc-html/reexport/reexport-of-reexport-108679.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-of-reexport-108679.rs rename to tests/rustdoc-html/reexport/reexport-of-reexport-108679.rs diff --git a/tests/rustdoc/reexport/reexport-stability-tags-deprecated-and-portability.rs b/tests/rustdoc-html/reexport/reexport-stability-tags-deprecated-and-portability.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-stability-tags-deprecated-and-portability.rs rename to tests/rustdoc-html/reexport/reexport-stability-tags-deprecated-and-portability.rs diff --git a/tests/rustdoc/reexport/reexport-stability-tags-unstable-and-portability.rs b/tests/rustdoc-html/reexport/reexport-stability-tags-unstable-and-portability.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-stability-tags-unstable-and-portability.rs rename to tests/rustdoc-html/reexport/reexport-stability-tags-unstable-and-portability.rs diff --git a/tests/rustdoc/reexport/reexport-trait-from-hidden-111064-2.rs b/tests/rustdoc-html/reexport/reexport-trait-from-hidden-111064-2.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-trait-from-hidden-111064-2.rs rename to tests/rustdoc-html/reexport/reexport-trait-from-hidden-111064-2.rs diff --git a/tests/rustdoc/reexport/reexport-trait-from-hidden-111064.rs b/tests/rustdoc-html/reexport/reexport-trait-from-hidden-111064.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-trait-from-hidden-111064.rs rename to tests/rustdoc-html/reexport/reexport-trait-from-hidden-111064.rs diff --git a/tests/rustdoc/reexport/reexports-of-same-name.rs b/tests/rustdoc-html/reexport/reexports-of-same-name.rs similarity index 100% rename from tests/rustdoc/reexport/reexports-of-same-name.rs rename to tests/rustdoc-html/reexport/reexports-of-same-name.rs diff --git a/tests/rustdoc/reexport/reexports-priv.rs b/tests/rustdoc-html/reexport/reexports-priv.rs similarity index 100% rename from tests/rustdoc/reexport/reexports-priv.rs rename to tests/rustdoc-html/reexport/reexports-priv.rs diff --git a/tests/rustdoc/reexport/reexports.rs b/tests/rustdoc-html/reexport/reexports.rs similarity index 100% rename from tests/rustdoc/reexport/reexports.rs rename to tests/rustdoc-html/reexport/reexports.rs diff --git a/tests/rustdoc/reexport/wrapped-unnamble-type-143222.rs b/tests/rustdoc-html/reexport/wrapped-unnamble-type-143222.rs similarity index 100% rename from tests/rustdoc/reexport/wrapped-unnamble-type-143222.rs rename to tests/rustdoc-html/reexport/wrapped-unnamble-type-143222.rs diff --git a/tests/rustdoc/remove-duplicates.rs b/tests/rustdoc-html/remove-duplicates.rs similarity index 100% rename from tests/rustdoc/remove-duplicates.rs rename to tests/rustdoc-html/remove-duplicates.rs diff --git a/tests/rustdoc/remove-url-from-headings.rs b/tests/rustdoc-html/remove-url-from-headings.rs similarity index 100% rename from tests/rustdoc/remove-url-from-headings.rs rename to tests/rustdoc-html/remove-url-from-headings.rs diff --git a/tests/rustdoc/repr.rs b/tests/rustdoc-html/repr.rs similarity index 100% rename from tests/rustdoc/repr.rs rename to tests/rustdoc-html/repr.rs diff --git a/tests/rustdoc/resolve-ice-124363.rs b/tests/rustdoc-html/resolve-ice-124363.rs similarity index 100% rename from tests/rustdoc/resolve-ice-124363.rs rename to tests/rustdoc-html/resolve-ice-124363.rs diff --git a/tests/rustdoc/return-type-notation.rs b/tests/rustdoc-html/return-type-notation.rs similarity index 100% rename from tests/rustdoc/return-type-notation.rs rename to tests/rustdoc-html/return-type-notation.rs diff --git a/tests/rustdoc/safe-intrinsic.rs b/tests/rustdoc-html/safe-intrinsic.rs similarity index 100% rename from tests/rustdoc/safe-intrinsic.rs rename to tests/rustdoc-html/safe-intrinsic.rs diff --git a/tests/rustdoc/sanitizer-option.rs b/tests/rustdoc-html/sanitizer-option.rs similarity index 100% rename from tests/rustdoc/sanitizer-option.rs rename to tests/rustdoc-html/sanitizer-option.rs diff --git a/tests/rustdoc/search-index-summaries.rs b/tests/rustdoc-html/search-index-summaries.rs similarity index 100% rename from tests/rustdoc/search-index-summaries.rs rename to tests/rustdoc-html/search-index-summaries.rs diff --git a/tests/rustdoc/search-index.rs b/tests/rustdoc-html/search-index.rs similarity index 100% rename from tests/rustdoc/search-index.rs rename to tests/rustdoc-html/search-index.rs diff --git a/tests/rustdoc/short-docblock-codeblock.rs b/tests/rustdoc-html/short-docblock-codeblock.rs similarity index 100% rename from tests/rustdoc/short-docblock-codeblock.rs rename to tests/rustdoc-html/short-docblock-codeblock.rs diff --git a/tests/rustdoc/short-docblock.rs b/tests/rustdoc-html/short-docblock.rs similarity index 100% rename from tests/rustdoc/short-docblock.rs rename to tests/rustdoc-html/short-docblock.rs diff --git a/tests/rustdoc/short-line.md b/tests/rustdoc-html/short-line.md similarity index 100% rename from tests/rustdoc/short-line.md rename to tests/rustdoc-html/short-line.md diff --git a/tests/rustdoc/sidebar/module.rs b/tests/rustdoc-html/sidebar/module.rs similarity index 100% rename from tests/rustdoc/sidebar/module.rs rename to tests/rustdoc-html/sidebar/module.rs diff --git a/tests/rustdoc/sidebar/sidebar-all-page.rs b/tests/rustdoc-html/sidebar/sidebar-all-page.rs similarity index 100% rename from tests/rustdoc/sidebar/sidebar-all-page.rs rename to tests/rustdoc-html/sidebar/sidebar-all-page.rs diff --git a/tests/rustdoc/sidebar/sidebar-items.rs b/tests/rustdoc-html/sidebar/sidebar-items.rs similarity index 100% rename from tests/rustdoc/sidebar/sidebar-items.rs rename to tests/rustdoc-html/sidebar/sidebar-items.rs diff --git a/tests/rustdoc/sidebar/sidebar-link-generation.rs b/tests/rustdoc-html/sidebar/sidebar-link-generation.rs similarity index 100% rename from tests/rustdoc/sidebar/sidebar-link-generation.rs rename to tests/rustdoc-html/sidebar/sidebar-link-generation.rs diff --git a/tests/rustdoc/sidebar/sidebar-links-to-foreign-impl.rs b/tests/rustdoc-html/sidebar/sidebar-links-to-foreign-impl.rs similarity index 100% rename from tests/rustdoc/sidebar/sidebar-links-to-foreign-impl.rs rename to tests/rustdoc-html/sidebar/sidebar-links-to-foreign-impl.rs diff --git a/tests/rustdoc/sidebar/top-toc-html.rs b/tests/rustdoc-html/sidebar/top-toc-html.rs similarity index 100% rename from tests/rustdoc/sidebar/top-toc-html.rs rename to tests/rustdoc-html/sidebar/top-toc-html.rs diff --git a/tests/rustdoc/sidebar/top-toc-idmap.rs b/tests/rustdoc-html/sidebar/top-toc-idmap.rs similarity index 100% rename from tests/rustdoc/sidebar/top-toc-idmap.rs rename to tests/rustdoc-html/sidebar/top-toc-idmap.rs diff --git a/tests/rustdoc/sidebar/top-toc-nil.rs b/tests/rustdoc-html/sidebar/top-toc-nil.rs similarity index 100% rename from tests/rustdoc/sidebar/top-toc-nil.rs rename to tests/rustdoc-html/sidebar/top-toc-nil.rs diff --git a/tests/rustdoc/sized_trait.rs b/tests/rustdoc-html/sized_trait.rs similarity index 100% rename from tests/rustdoc/sized_trait.rs rename to tests/rustdoc-html/sized_trait.rs diff --git a/tests/rustdoc/slice-links.link_box_generic.html b/tests/rustdoc-html/slice-links.link_box_generic.html similarity index 100% rename from tests/rustdoc/slice-links.link_box_generic.html rename to tests/rustdoc-html/slice-links.link_box_generic.html diff --git a/tests/rustdoc/slice-links.link_box_u32.html b/tests/rustdoc-html/slice-links.link_box_u32.html similarity index 100% rename from tests/rustdoc/slice-links.link_box_u32.html rename to tests/rustdoc-html/slice-links.link_box_u32.html diff --git a/tests/rustdoc/slice-links.link_slice_generic.html b/tests/rustdoc-html/slice-links.link_slice_generic.html similarity index 100% rename from tests/rustdoc/slice-links.link_slice_generic.html rename to tests/rustdoc-html/slice-links.link_slice_generic.html diff --git a/tests/rustdoc/slice-links.link_slice_u32.html b/tests/rustdoc-html/slice-links.link_slice_u32.html similarity index 100% rename from tests/rustdoc/slice-links.link_slice_u32.html rename to tests/rustdoc-html/slice-links.link_slice_u32.html diff --git a/tests/rustdoc/slice-links.rs b/tests/rustdoc-html/slice-links.rs similarity index 100% rename from tests/rustdoc/slice-links.rs rename to tests/rustdoc-html/slice-links.rs diff --git a/tests/rustdoc/smart-punct.rs b/tests/rustdoc-html/smart-punct.rs similarity index 100% rename from tests/rustdoc/smart-punct.rs rename to tests/rustdoc-html/smart-punct.rs diff --git a/tests/rustdoc/smoke.rs b/tests/rustdoc-html/smoke.rs similarity index 100% rename from tests/rustdoc/smoke.rs rename to tests/rustdoc-html/smoke.rs diff --git a/tests/rustdoc/sort-53812.rs b/tests/rustdoc-html/sort-53812.rs similarity index 100% rename from tests/rustdoc/sort-53812.rs rename to tests/rustdoc-html/sort-53812.rs diff --git a/tests/rustdoc/sort-modules-by-appearance.rs b/tests/rustdoc-html/sort-modules-by-appearance.rs similarity index 100% rename from tests/rustdoc/sort-modules-by-appearance.rs rename to tests/rustdoc-html/sort-modules-by-appearance.rs diff --git a/tests/rustdoc/source-code-pages/assoc-type-source-link.rs b/tests/rustdoc-html/source-code-pages/assoc-type-source-link.rs similarity index 100% rename from tests/rustdoc/source-code-pages/assoc-type-source-link.rs rename to tests/rustdoc-html/source-code-pages/assoc-type-source-link.rs diff --git a/tests/rustdoc/source-code-pages/auxiliary/issue-26606-macro.rs b/tests/rustdoc-html/source-code-pages/auxiliary/issue-26606-macro.rs similarity index 100% rename from tests/rustdoc/source-code-pages/auxiliary/issue-26606-macro.rs rename to tests/rustdoc-html/source-code-pages/auxiliary/issue-26606-macro.rs diff --git a/tests/rustdoc/source-code-pages/auxiliary/issue-34274.rs b/tests/rustdoc-html/source-code-pages/auxiliary/issue-34274.rs similarity index 100% rename from tests/rustdoc/source-code-pages/auxiliary/issue-34274.rs rename to tests/rustdoc-html/source-code-pages/auxiliary/issue-34274.rs diff --git a/tests/rustdoc/source-code-pages/auxiliary/source-code-bar.rs b/tests/rustdoc-html/source-code-pages/auxiliary/source-code-bar.rs similarity index 100% rename from tests/rustdoc/source-code-pages/auxiliary/source-code-bar.rs rename to tests/rustdoc-html/source-code-pages/auxiliary/source-code-bar.rs diff --git a/tests/rustdoc/source-code-pages/auxiliary/source_code.rs b/tests/rustdoc-html/source-code-pages/auxiliary/source_code.rs similarity index 100% rename from tests/rustdoc/source-code-pages/auxiliary/source_code.rs rename to tests/rustdoc-html/source-code-pages/auxiliary/source_code.rs diff --git a/tests/rustdoc/source-code-pages/auxiliary/src-links-external.rs b/tests/rustdoc-html/source-code-pages/auxiliary/src-links-external.rs similarity index 100% rename from tests/rustdoc/source-code-pages/auxiliary/src-links-external.rs rename to tests/rustdoc-html/source-code-pages/auxiliary/src-links-external.rs diff --git a/tests/rustdoc/source-code-pages/check-source-code-urls-to-def-std.rs b/tests/rustdoc-html/source-code-pages/check-source-code-urls-to-def-std.rs similarity index 100% rename from tests/rustdoc/source-code-pages/check-source-code-urls-to-def-std.rs rename to tests/rustdoc-html/source-code-pages/check-source-code-urls-to-def-std.rs diff --git a/tests/rustdoc/source-code-pages/check-source-code-urls-to-def.rs b/tests/rustdoc-html/source-code-pages/check-source-code-urls-to-def.rs similarity index 100% rename from tests/rustdoc/source-code-pages/check-source-code-urls-to-def.rs rename to tests/rustdoc-html/source-code-pages/check-source-code-urls-to-def.rs diff --git a/tests/rustdoc/source-code-pages/doc-hidden-source.rs b/tests/rustdoc-html/source-code-pages/doc-hidden-source.rs similarity index 100% rename from tests/rustdoc/source-code-pages/doc-hidden-source.rs rename to tests/rustdoc-html/source-code-pages/doc-hidden-source.rs diff --git a/tests/rustdoc/source-code-pages/failing-expansion-on-wrong-macro.rs b/tests/rustdoc-html/source-code-pages/failing-expansion-on-wrong-macro.rs similarity index 100% rename from tests/rustdoc/source-code-pages/failing-expansion-on-wrong-macro.rs rename to tests/rustdoc-html/source-code-pages/failing-expansion-on-wrong-macro.rs diff --git a/tests/rustdoc/source-code-pages/frontmatter.rs b/tests/rustdoc-html/source-code-pages/frontmatter.rs similarity index 100% rename from tests/rustdoc/source-code-pages/frontmatter.rs rename to tests/rustdoc-html/source-code-pages/frontmatter.rs diff --git a/tests/rustdoc/source-code-pages/html-no-source.rs b/tests/rustdoc-html/source-code-pages/html-no-source.rs similarity index 100% rename from tests/rustdoc/source-code-pages/html-no-source.rs rename to tests/rustdoc-html/source-code-pages/html-no-source.rs diff --git a/tests/rustdoc/source-code-pages/keyword-macros.rs b/tests/rustdoc-html/source-code-pages/keyword-macros.rs similarity index 100% rename from tests/rustdoc/source-code-pages/keyword-macros.rs rename to tests/rustdoc-html/source-code-pages/keyword-macros.rs diff --git a/tests/rustdoc/source-code-pages/shebang.rs b/tests/rustdoc-html/source-code-pages/shebang.rs similarity index 100% rename from tests/rustdoc/source-code-pages/shebang.rs rename to tests/rustdoc-html/source-code-pages/shebang.rs diff --git a/tests/rustdoc/source-code-pages/source-code-highlight.rs b/tests/rustdoc-html/source-code-pages/source-code-highlight.rs similarity index 100% rename from tests/rustdoc/source-code-pages/source-code-highlight.rs rename to tests/rustdoc-html/source-code-pages/source-code-highlight.rs diff --git a/tests/rustdoc/source-code-pages/source-file.rs b/tests/rustdoc-html/source-code-pages/source-file.rs similarity index 100% rename from tests/rustdoc/source-code-pages/source-file.rs rename to tests/rustdoc-html/source-code-pages/source-file.rs diff --git a/tests/rustdoc/source-code-pages/source-line-numbers.rs b/tests/rustdoc-html/source-code-pages/source-line-numbers.rs similarity index 100% rename from tests/rustdoc/source-code-pages/source-line-numbers.rs rename to tests/rustdoc-html/source-code-pages/source-line-numbers.rs diff --git a/tests/rustdoc/source-code-pages/source-version-separator.rs b/tests/rustdoc-html/source-code-pages/source-version-separator.rs similarity index 100% rename from tests/rustdoc/source-code-pages/source-version-separator.rs rename to tests/rustdoc-html/source-code-pages/source-version-separator.rs diff --git a/tests/rustdoc/source-code-pages/src-link-external-macro-26606.rs b/tests/rustdoc-html/source-code-pages/src-link-external-macro-26606.rs similarity index 100% rename from tests/rustdoc/source-code-pages/src-link-external-macro-26606.rs rename to tests/rustdoc-html/source-code-pages/src-link-external-macro-26606.rs diff --git a/tests/rustdoc/source-code-pages/src-links-auto-impls.rs b/tests/rustdoc-html/source-code-pages/src-links-auto-impls.rs similarity index 100% rename from tests/rustdoc/source-code-pages/src-links-auto-impls.rs rename to tests/rustdoc-html/source-code-pages/src-links-auto-impls.rs diff --git a/tests/rustdoc/source-code-pages/src-links-external.rs b/tests/rustdoc-html/source-code-pages/src-links-external.rs similarity index 100% rename from tests/rustdoc/source-code-pages/src-links-external.rs rename to tests/rustdoc-html/source-code-pages/src-links-external.rs diff --git a/tests/rustdoc/source-code-pages/src-links-implementor-43893.rs b/tests/rustdoc-html/source-code-pages/src-links-implementor-43893.rs similarity index 100% rename from tests/rustdoc/source-code-pages/src-links-implementor-43893.rs rename to tests/rustdoc-html/source-code-pages/src-links-implementor-43893.rs diff --git a/tests/rustdoc/source-code-pages/src-links-inlined-34274.rs b/tests/rustdoc-html/source-code-pages/src-links-inlined-34274.rs similarity index 100% rename from tests/rustdoc/source-code-pages/src-links-inlined-34274.rs rename to tests/rustdoc-html/source-code-pages/src-links-inlined-34274.rs diff --git a/tests/rustdoc/source-code-pages/src-links.rs b/tests/rustdoc-html/source-code-pages/src-links.rs similarity index 100% rename from tests/rustdoc/source-code-pages/src-links.rs rename to tests/rustdoc-html/source-code-pages/src-links.rs diff --git a/tests/rustdoc/source-code-pages/src-links/compiletest-ignore-dir b/tests/rustdoc-html/source-code-pages/src-links/compiletest-ignore-dir similarity index 100% rename from tests/rustdoc/source-code-pages/src-links/compiletest-ignore-dir rename to tests/rustdoc-html/source-code-pages/src-links/compiletest-ignore-dir diff --git a/tests/rustdoc/source-code-pages/src-links/fizz.rs b/tests/rustdoc-html/source-code-pages/src-links/fizz.rs similarity index 100% rename from tests/rustdoc/source-code-pages/src-links/fizz.rs rename to tests/rustdoc-html/source-code-pages/src-links/fizz.rs diff --git a/tests/rustdoc/source-code-pages/src-links/mod.rs b/tests/rustdoc-html/source-code-pages/src-links/mod.rs similarity index 100% rename from tests/rustdoc/source-code-pages/src-links/mod.rs rename to tests/rustdoc-html/source-code-pages/src-links/mod.rs diff --git a/tests/rustdoc/source-code-pages/src-mod-path-absolute-26995.rs b/tests/rustdoc-html/source-code-pages/src-mod-path-absolute-26995.rs similarity index 100% rename from tests/rustdoc/source-code-pages/src-mod-path-absolute-26995.rs rename to tests/rustdoc-html/source-code-pages/src-mod-path-absolute-26995.rs diff --git a/tests/rustdoc/source-code-pages/version-separator-without-source.rs b/tests/rustdoc-html/source-code-pages/version-separator-without-source.rs similarity index 100% rename from tests/rustdoc/source-code-pages/version-separator-without-source.rs rename to tests/rustdoc-html/source-code-pages/version-separator-without-source.rs diff --git a/tests/rustdoc/stability.rs b/tests/rustdoc-html/stability.rs similarity index 100% rename from tests/rustdoc/stability.rs rename to tests/rustdoc-html/stability.rs diff --git a/tests/rustdoc/staged-api-deprecated-unstable-32374.rs b/tests/rustdoc-html/staged-api-deprecated-unstable-32374.rs similarity index 100% rename from tests/rustdoc/staged-api-deprecated-unstable-32374.rs rename to tests/rustdoc-html/staged-api-deprecated-unstable-32374.rs diff --git a/tests/rustdoc/staged-api-feature-issue-27759.rs b/tests/rustdoc-html/staged-api-feature-issue-27759.rs similarity index 100% rename from tests/rustdoc/staged-api-feature-issue-27759.rs rename to tests/rustdoc-html/staged-api-feature-issue-27759.rs diff --git a/tests/rustdoc/static-root-path.rs b/tests/rustdoc-html/static-root-path.rs similarity index 100% rename from tests/rustdoc/static-root-path.rs rename to tests/rustdoc-html/static-root-path.rs diff --git a/tests/rustdoc/static.rs b/tests/rustdoc-html/static.rs similarity index 100% rename from tests/rustdoc/static.rs rename to tests/rustdoc-html/static.rs diff --git a/tests/rustdoc/strip-block-doc-comments-stars.docblock.html b/tests/rustdoc-html/strip-block-doc-comments-stars.docblock.html similarity index 100% rename from tests/rustdoc/strip-block-doc-comments-stars.docblock.html rename to tests/rustdoc-html/strip-block-doc-comments-stars.docblock.html diff --git a/tests/rustdoc/strip-block-doc-comments-stars.rs b/tests/rustdoc-html/strip-block-doc-comments-stars.rs similarity index 100% rename from tests/rustdoc/strip-block-doc-comments-stars.rs rename to tests/rustdoc-html/strip-block-doc-comments-stars.rs diff --git a/tests/rustdoc/strip-priv-imports-pass-27104.rs b/tests/rustdoc-html/strip-priv-imports-pass-27104.rs similarity index 100% rename from tests/rustdoc/strip-priv-imports-pass-27104.rs rename to tests/rustdoc-html/strip-priv-imports-pass-27104.rs diff --git a/tests/rustdoc/struct-arg-pattern.rs b/tests/rustdoc-html/struct-arg-pattern.rs similarity index 100% rename from tests/rustdoc/struct-arg-pattern.rs rename to tests/rustdoc-html/struct-arg-pattern.rs diff --git a/tests/rustdoc/struct-field.rs b/tests/rustdoc-html/struct-field.rs similarity index 100% rename from tests/rustdoc/struct-field.rs rename to tests/rustdoc-html/struct-field.rs diff --git a/tests/rustdoc/structfields.rs b/tests/rustdoc-html/structfields.rs similarity index 100% rename from tests/rustdoc/structfields.rs rename to tests/rustdoc-html/structfields.rs diff --git a/tests/rustdoc/summary-codeblock-31899.rs b/tests/rustdoc-html/summary-codeblock-31899.rs similarity index 100% rename from tests/rustdoc/summary-codeblock-31899.rs rename to tests/rustdoc-html/summary-codeblock-31899.rs diff --git a/tests/rustdoc/summary-header-46377.rs b/tests/rustdoc-html/summary-header-46377.rs similarity index 100% rename from tests/rustdoc/summary-header-46377.rs rename to tests/rustdoc-html/summary-header-46377.rs diff --git a/tests/rustdoc/summary-reference-link-30366.rs b/tests/rustdoc-html/summary-reference-link-30366.rs similarity index 100% rename from tests/rustdoc/summary-reference-link-30366.rs rename to tests/rustdoc-html/summary-reference-link-30366.rs diff --git a/tests/rustdoc/synthetic_auto/auto-trait-lifetimes-56822.rs b/tests/rustdoc-html/synthetic_auto/auto-trait-lifetimes-56822.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/auto-trait-lifetimes-56822.rs rename to tests/rustdoc-html/synthetic_auto/auto-trait-lifetimes-56822.rs diff --git a/tests/rustdoc/synthetic_auto/basic.rs b/tests/rustdoc-html/synthetic_auto/basic.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/basic.rs rename to tests/rustdoc-html/synthetic_auto/basic.rs diff --git a/tests/rustdoc/synthetic_auto/bounds.rs b/tests/rustdoc-html/synthetic_auto/bounds.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/bounds.rs rename to tests/rustdoc-html/synthetic_auto/bounds.rs diff --git a/tests/rustdoc/synthetic_auto/complex.rs b/tests/rustdoc-html/synthetic_auto/complex.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/complex.rs rename to tests/rustdoc-html/synthetic_auto/complex.rs diff --git a/tests/rustdoc/synthetic_auto/crate-local.rs b/tests/rustdoc-html/synthetic_auto/crate-local.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/crate-local.rs rename to tests/rustdoc-html/synthetic_auto/crate-local.rs diff --git a/tests/rustdoc/synthetic_auto/issue-72213-projection-lifetime.rs b/tests/rustdoc-html/synthetic_auto/issue-72213-projection-lifetime.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/issue-72213-projection-lifetime.rs rename to tests/rustdoc-html/synthetic_auto/issue-72213-projection-lifetime.rs diff --git a/tests/rustdoc/synthetic_auto/lifetimes.rs b/tests/rustdoc-html/synthetic_auto/lifetimes.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/lifetimes.rs rename to tests/rustdoc-html/synthetic_auto/lifetimes.rs diff --git a/tests/rustdoc/synthetic_auto/manual.rs b/tests/rustdoc-html/synthetic_auto/manual.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/manual.rs rename to tests/rustdoc-html/synthetic_auto/manual.rs diff --git a/tests/rustdoc/synthetic_auto/negative.rs b/tests/rustdoc-html/synthetic_auto/negative.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/negative.rs rename to tests/rustdoc-html/synthetic_auto/negative.rs diff --git a/tests/rustdoc/synthetic_auto/nested.rs b/tests/rustdoc-html/synthetic_auto/nested.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/nested.rs rename to tests/rustdoc-html/synthetic_auto/nested.rs diff --git a/tests/rustdoc/synthetic_auto/no-redundancy.rs b/tests/rustdoc-html/synthetic_auto/no-redundancy.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/no-redundancy.rs rename to tests/rustdoc-html/synthetic_auto/no-redundancy.rs diff --git a/tests/rustdoc/synthetic_auto/normalize-auto-trait-80233.rs b/tests/rustdoc-html/synthetic_auto/normalize-auto-trait-80233.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/normalize-auto-trait-80233.rs rename to tests/rustdoc-html/synthetic_auto/normalize-auto-trait-80233.rs diff --git a/tests/rustdoc/synthetic_auto/overflow.rs b/tests/rustdoc-html/synthetic_auto/overflow.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/overflow.rs rename to tests/rustdoc-html/synthetic_auto/overflow.rs diff --git a/tests/rustdoc/synthetic_auto/project.rs b/tests/rustdoc-html/synthetic_auto/project.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/project.rs rename to tests/rustdoc-html/synthetic_auto/project.rs diff --git a/tests/rustdoc/synthetic_auto/self-referential.rs b/tests/rustdoc-html/synthetic_auto/self-referential.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/self-referential.rs rename to tests/rustdoc-html/synthetic_auto/self-referential.rs diff --git a/tests/rustdoc/synthetic_auto/send-impl-conditional-60726.rs b/tests/rustdoc-html/synthetic_auto/send-impl-conditional-60726.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/send-impl-conditional-60726.rs rename to tests/rustdoc-html/synthetic_auto/send-impl-conditional-60726.rs diff --git a/tests/rustdoc/synthetic_auto/static-region.rs b/tests/rustdoc-html/synthetic_auto/static-region.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/static-region.rs rename to tests/rustdoc-html/synthetic_auto/static-region.rs diff --git a/tests/rustdoc/synthetic_auto/supertrait-bounds.rs b/tests/rustdoc-html/synthetic_auto/supertrait-bounds.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/supertrait-bounds.rs rename to tests/rustdoc-html/synthetic_auto/supertrait-bounds.rs diff --git a/tests/rustdoc/tab_title.rs b/tests/rustdoc-html/tab_title.rs similarity index 100% rename from tests/rustdoc/tab_title.rs rename to tests/rustdoc-html/tab_title.rs diff --git a/tests/rustdoc/table-in-docblock.rs b/tests/rustdoc-html/table-in-docblock.rs similarity index 100% rename from tests/rustdoc/table-in-docblock.rs rename to tests/rustdoc-html/table-in-docblock.rs diff --git a/tests/rustdoc/target-feature.rs b/tests/rustdoc-html/target-feature.rs similarity index 100% rename from tests/rustdoc/target-feature.rs rename to tests/rustdoc-html/target-feature.rs diff --git a/tests/rustdoc/task-lists.rs b/tests/rustdoc-html/task-lists.rs similarity index 100% rename from tests/rustdoc/task-lists.rs rename to tests/rustdoc-html/task-lists.rs diff --git a/tests/rustdoc/test-lists.rs b/tests/rustdoc-html/test-lists.rs similarity index 100% rename from tests/rustdoc/test-lists.rs rename to tests/rustdoc-html/test-lists.rs diff --git a/tests/rustdoc/test-parens.rs b/tests/rustdoc-html/test-parens.rs similarity index 100% rename from tests/rustdoc/test-parens.rs rename to tests/rustdoc-html/test-parens.rs diff --git a/tests/rustdoc/test-strikethrough.rs b/tests/rustdoc-html/test-strikethrough.rs similarity index 100% rename from tests/rustdoc/test-strikethrough.rs rename to tests/rustdoc-html/test-strikethrough.rs diff --git a/tests/rustdoc/test_option_check/bar.rs b/tests/rustdoc-html/test_option_check/bar.rs similarity index 100% rename from tests/rustdoc/test_option_check/bar.rs rename to tests/rustdoc-html/test_option_check/bar.rs diff --git a/tests/rustdoc/test_option_check/test.rs b/tests/rustdoc-html/test_option_check/test.rs similarity index 100% rename from tests/rustdoc/test_option_check/test.rs rename to tests/rustdoc-html/test_option_check/test.rs diff --git a/tests/rustdoc/thread-local-src.rs b/tests/rustdoc-html/thread-local-src.rs similarity index 100% rename from tests/rustdoc/thread-local-src.rs rename to tests/rustdoc-html/thread-local-src.rs diff --git a/tests/rustdoc/titles.rs b/tests/rustdoc-html/titles.rs similarity index 100% rename from tests/rustdoc/titles.rs rename to tests/rustdoc-html/titles.rs diff --git a/tests/rustdoc/toggle-item-contents.rs b/tests/rustdoc-html/toggle-item-contents.rs similarity index 100% rename from tests/rustdoc/toggle-item-contents.rs rename to tests/rustdoc-html/toggle-item-contents.rs diff --git a/tests/rustdoc/toggle-method.rs b/tests/rustdoc-html/toggle-method.rs similarity index 100% rename from tests/rustdoc/toggle-method.rs rename to tests/rustdoc-html/toggle-method.rs diff --git a/tests/rustdoc/toggle-trait-fn.rs b/tests/rustdoc-html/toggle-trait-fn.rs similarity index 100% rename from tests/rustdoc/toggle-trait-fn.rs rename to tests/rustdoc-html/toggle-trait-fn.rs diff --git a/tests/rustdoc/trait-aliases.rs b/tests/rustdoc-html/trait-aliases.rs similarity index 100% rename from tests/rustdoc/trait-aliases.rs rename to tests/rustdoc-html/trait-aliases.rs diff --git a/tests/rustdoc/trait-item-info.rs b/tests/rustdoc-html/trait-item-info.rs similarity index 100% rename from tests/rustdoc/trait-item-info.rs rename to tests/rustdoc-html/trait-item-info.rs diff --git a/tests/rustdoc/trait-self-link.rs b/tests/rustdoc-html/trait-self-link.rs similarity index 100% rename from tests/rustdoc/trait-self-link.rs rename to tests/rustdoc-html/trait-self-link.rs diff --git a/tests/rustdoc/trait-src-link.rs b/tests/rustdoc-html/trait-src-link.rs similarity index 100% rename from tests/rustdoc/trait-src-link.rs rename to tests/rustdoc-html/trait-src-link.rs diff --git a/tests/rustdoc/trait-visibility.rs b/tests/rustdoc-html/trait-visibility.rs similarity index 100% rename from tests/rustdoc/trait-visibility.rs rename to tests/rustdoc-html/trait-visibility.rs diff --git a/tests/rustdoc/traits-in-bodies.rs b/tests/rustdoc-html/traits-in-bodies.rs similarity index 100% rename from tests/rustdoc/traits-in-bodies.rs rename to tests/rustdoc-html/traits-in-bodies.rs diff --git a/tests/rustdoc/tuple-struct-fields-doc.rs b/tests/rustdoc-html/tuple-struct-fields-doc.rs similarity index 100% rename from tests/rustdoc/tuple-struct-fields-doc.rs rename to tests/rustdoc-html/tuple-struct-fields-doc.rs diff --git a/tests/rustdoc/tuple-struct-where-clause-34928.rs b/tests/rustdoc-html/tuple-struct-where-clause-34928.rs similarity index 100% rename from tests/rustdoc/tuple-struct-where-clause-34928.rs rename to tests/rustdoc-html/tuple-struct-where-clause-34928.rs diff --git a/tests/rustdoc/tuples.link1_i32.html b/tests/rustdoc-html/tuples.link1_i32.html similarity index 100% rename from tests/rustdoc/tuples.link1_i32.html rename to tests/rustdoc-html/tuples.link1_i32.html diff --git a/tests/rustdoc/tuples.link1_t.html b/tests/rustdoc-html/tuples.link1_t.html similarity index 100% rename from tests/rustdoc/tuples.link1_t.html rename to tests/rustdoc-html/tuples.link1_t.html diff --git a/tests/rustdoc/tuples.link2_i32.html b/tests/rustdoc-html/tuples.link2_i32.html similarity index 100% rename from tests/rustdoc/tuples.link2_i32.html rename to tests/rustdoc-html/tuples.link2_i32.html diff --git a/tests/rustdoc/tuples.link2_t.html b/tests/rustdoc-html/tuples.link2_t.html similarity index 100% rename from tests/rustdoc/tuples.link2_t.html rename to tests/rustdoc-html/tuples.link2_t.html diff --git a/tests/rustdoc/tuples.link2_tu.html b/tests/rustdoc-html/tuples.link2_tu.html similarity index 100% rename from tests/rustdoc/tuples.link2_tu.html rename to tests/rustdoc-html/tuples.link2_tu.html diff --git a/tests/rustdoc/tuples.link_unit.html b/tests/rustdoc-html/tuples.link_unit.html similarity index 100% rename from tests/rustdoc/tuples.link_unit.html rename to tests/rustdoc-html/tuples.link_unit.html diff --git a/tests/rustdoc/tuples.rs b/tests/rustdoc-html/tuples.rs similarity index 100% rename from tests/rustdoc/tuples.rs rename to tests/rustdoc-html/tuples.rs diff --git a/tests/rustdoc/type-alias/auxiliary/parent-crate-115718.rs b/tests/rustdoc-html/type-alias/auxiliary/parent-crate-115718.rs similarity index 100% rename from tests/rustdoc/type-alias/auxiliary/parent-crate-115718.rs rename to tests/rustdoc-html/type-alias/auxiliary/parent-crate-115718.rs diff --git a/tests/rustdoc/type-alias/cross-crate-115718.rs b/tests/rustdoc-html/type-alias/cross-crate-115718.rs similarity index 100% rename from tests/rustdoc/type-alias/cross-crate-115718.rs rename to tests/rustdoc-html/type-alias/cross-crate-115718.rs diff --git a/tests/rustdoc/type-alias/deeply-nested-112515.rs b/tests/rustdoc-html/type-alias/deeply-nested-112515.rs similarity index 100% rename from tests/rustdoc/type-alias/deeply-nested-112515.rs rename to tests/rustdoc-html/type-alias/deeply-nested-112515.rs diff --git a/tests/rustdoc/type-alias/deref-32077.rs b/tests/rustdoc-html/type-alias/deref-32077.rs similarity index 100% rename from tests/rustdoc/type-alias/deref-32077.rs rename to tests/rustdoc-html/type-alias/deref-32077.rs diff --git a/tests/rustdoc/type-alias/impl_trait_in_assoc_type.rs b/tests/rustdoc-html/type-alias/impl_trait_in_assoc_type.rs similarity index 100% rename from tests/rustdoc/type-alias/impl_trait_in_assoc_type.rs rename to tests/rustdoc-html/type-alias/impl_trait_in_assoc_type.rs diff --git a/tests/rustdoc/type-alias/primitive-local-link-121106.rs b/tests/rustdoc-html/type-alias/primitive-local-link-121106.rs similarity index 100% rename from tests/rustdoc/type-alias/primitive-local-link-121106.rs rename to tests/rustdoc-html/type-alias/primitive-local-link-121106.rs diff --git a/tests/rustdoc/type-alias/repr.rs b/tests/rustdoc-html/type-alias/repr.rs similarity index 100% rename from tests/rustdoc/type-alias/repr.rs rename to tests/rustdoc-html/type-alias/repr.rs diff --git a/tests/rustdoc/type-alias/same-crate-115718.rs b/tests/rustdoc-html/type-alias/same-crate-115718.rs similarity index 100% rename from tests/rustdoc/type-alias/same-crate-115718.rs rename to tests/rustdoc-html/type-alias/same-crate-115718.rs diff --git a/tests/rustdoc/type-layout-flag-required.rs b/tests/rustdoc-html/type-layout-flag-required.rs similarity index 100% rename from tests/rustdoc/type-layout-flag-required.rs rename to tests/rustdoc-html/type-layout-flag-required.rs diff --git a/tests/rustdoc/type-layout.rs b/tests/rustdoc-html/type-layout.rs similarity index 100% rename from tests/rustdoc/type-layout.rs rename to tests/rustdoc-html/type-layout.rs diff --git a/tests/rustdoc/typedef-inner-variants-lazy_type_alias.rs b/tests/rustdoc-html/typedef-inner-variants-lazy_type_alias.rs similarity index 100% rename from tests/rustdoc/typedef-inner-variants-lazy_type_alias.rs rename to tests/rustdoc-html/typedef-inner-variants-lazy_type_alias.rs diff --git a/tests/rustdoc/typedef-inner-variants.rs b/tests/rustdoc-html/typedef-inner-variants.rs similarity index 100% rename from tests/rustdoc/typedef-inner-variants.rs rename to tests/rustdoc-html/typedef-inner-variants.rs diff --git a/tests/rustdoc/typedef.rs b/tests/rustdoc-html/typedef.rs similarity index 100% rename from tests/rustdoc/typedef.rs rename to tests/rustdoc-html/typedef.rs diff --git a/tests/rustdoc/underscore-import-61592.rs b/tests/rustdoc-html/underscore-import-61592.rs similarity index 100% rename from tests/rustdoc/underscore-import-61592.rs rename to tests/rustdoc-html/underscore-import-61592.rs diff --git a/tests/rustdoc/unindent.md b/tests/rustdoc-html/unindent.md similarity index 100% rename from tests/rustdoc/unindent.md rename to tests/rustdoc-html/unindent.md diff --git a/tests/rustdoc/unindent.rs b/tests/rustdoc-html/unindent.rs similarity index 100% rename from tests/rustdoc/unindent.rs rename to tests/rustdoc-html/unindent.rs diff --git a/tests/rustdoc/union-fields-html.rs b/tests/rustdoc-html/union-fields-html.rs similarity index 100% rename from tests/rustdoc/union-fields-html.rs rename to tests/rustdoc-html/union-fields-html.rs diff --git a/tests/rustdoc/union.rs b/tests/rustdoc-html/union.rs similarity index 100% rename from tests/rustdoc/union.rs rename to tests/rustdoc-html/union.rs diff --git a/tests/rustdoc/unit-return.rs b/tests/rustdoc-html/unit-return.rs similarity index 100% rename from tests/rustdoc/unit-return.rs rename to tests/rustdoc-html/unit-return.rs diff --git a/tests/rustdoc/unsafe-binder.rs b/tests/rustdoc-html/unsafe-binder.rs similarity index 100% rename from tests/rustdoc/unsafe-binder.rs rename to tests/rustdoc-html/unsafe-binder.rs diff --git a/tests/rustdoc/use-attr.rs b/tests/rustdoc-html/use-attr.rs similarity index 100% rename from tests/rustdoc/use-attr.rs rename to tests/rustdoc-html/use-attr.rs diff --git a/tests/rustdoc/useless_lifetime_bound.rs b/tests/rustdoc-html/useless_lifetime_bound.rs similarity index 100% rename from tests/rustdoc/useless_lifetime_bound.rs rename to tests/rustdoc-html/useless_lifetime_bound.rs diff --git a/tests/rustdoc/variadic.rs b/tests/rustdoc-html/variadic.rs similarity index 100% rename from tests/rustdoc/variadic.rs rename to tests/rustdoc-html/variadic.rs diff --git a/tests/rustdoc/viewpath-rename.rs b/tests/rustdoc-html/viewpath-rename.rs similarity index 100% rename from tests/rustdoc/viewpath-rename.rs rename to tests/rustdoc-html/viewpath-rename.rs diff --git a/tests/rustdoc/viewpath-self.rs b/tests/rustdoc-html/viewpath-self.rs similarity index 100% rename from tests/rustdoc/viewpath-self.rs rename to tests/rustdoc-html/viewpath-self.rs diff --git a/tests/rustdoc/visibility.rs b/tests/rustdoc-html/visibility.rs similarity index 100% rename from tests/rustdoc/visibility.rs rename to tests/rustdoc-html/visibility.rs diff --git a/tests/rustdoc/where-clause-order.rs b/tests/rustdoc-html/where-clause-order.rs similarity index 100% rename from tests/rustdoc/where-clause-order.rs rename to tests/rustdoc-html/where-clause-order.rs diff --git a/tests/rustdoc/where-sized.rs b/tests/rustdoc-html/where-sized.rs similarity index 100% rename from tests/rustdoc/where-sized.rs rename to tests/rustdoc-html/where-sized.rs diff --git a/tests/rustdoc/where.SWhere_Echo_impl.html b/tests/rustdoc-html/where.SWhere_Echo_impl.html similarity index 100% rename from tests/rustdoc/where.SWhere_Echo_impl.html rename to tests/rustdoc-html/where.SWhere_Echo_impl.html diff --git a/tests/rustdoc/where.SWhere_Simd_item-decl.html b/tests/rustdoc-html/where.SWhere_Simd_item-decl.html similarity index 100% rename from tests/rustdoc/where.SWhere_Simd_item-decl.html rename to tests/rustdoc-html/where.SWhere_Simd_item-decl.html diff --git a/tests/rustdoc/where.SWhere_TraitWhere_item-decl.html b/tests/rustdoc-html/where.SWhere_TraitWhere_item-decl.html similarity index 100% rename from tests/rustdoc/where.SWhere_TraitWhere_item-decl.html rename to tests/rustdoc-html/where.SWhere_TraitWhere_item-decl.html diff --git a/tests/rustdoc/where.alpha_trait_decl.html b/tests/rustdoc-html/where.alpha_trait_decl.html similarity index 100% rename from tests/rustdoc/where.alpha_trait_decl.html rename to tests/rustdoc-html/where.alpha_trait_decl.html diff --git a/tests/rustdoc/where.bravo_trait_decl.html b/tests/rustdoc-html/where.bravo_trait_decl.html similarity index 100% rename from tests/rustdoc/where.bravo_trait_decl.html rename to tests/rustdoc-html/where.bravo_trait_decl.html diff --git a/tests/rustdoc/where.charlie_fn_decl.html b/tests/rustdoc-html/where.charlie_fn_decl.html similarity index 100% rename from tests/rustdoc/where.charlie_fn_decl.html rename to tests/rustdoc-html/where.charlie_fn_decl.html diff --git a/tests/rustdoc/where.golf_type_alias_decl.html b/tests/rustdoc-html/where.golf_type_alias_decl.html similarity index 100% rename from tests/rustdoc/where.golf_type_alias_decl.html rename to tests/rustdoc-html/where.golf_type_alias_decl.html diff --git a/tests/rustdoc/where.rs b/tests/rustdoc-html/where.rs similarity index 100% rename from tests/rustdoc/where.rs rename to tests/rustdoc-html/where.rs diff --git a/tests/rustdoc/whitespace-after-where-clause.enum.html b/tests/rustdoc-html/whitespace-after-where-clause.enum.html similarity index 100% rename from tests/rustdoc/whitespace-after-where-clause.enum.html rename to tests/rustdoc-html/whitespace-after-where-clause.enum.html diff --git a/tests/rustdoc/whitespace-after-where-clause.enum2.html b/tests/rustdoc-html/whitespace-after-where-clause.enum2.html similarity index 100% rename from tests/rustdoc/whitespace-after-where-clause.enum2.html rename to tests/rustdoc-html/whitespace-after-where-clause.enum2.html diff --git a/tests/rustdoc/whitespace-after-where-clause.rs b/tests/rustdoc-html/whitespace-after-where-clause.rs similarity index 100% rename from tests/rustdoc/whitespace-after-where-clause.rs rename to tests/rustdoc-html/whitespace-after-where-clause.rs diff --git a/tests/rustdoc/whitespace-after-where-clause.struct.html b/tests/rustdoc-html/whitespace-after-where-clause.struct.html similarity index 100% rename from tests/rustdoc/whitespace-after-where-clause.struct.html rename to tests/rustdoc-html/whitespace-after-where-clause.struct.html diff --git a/tests/rustdoc/whitespace-after-where-clause.struct2.html b/tests/rustdoc-html/whitespace-after-where-clause.struct2.html similarity index 100% rename from tests/rustdoc/whitespace-after-where-clause.struct2.html rename to tests/rustdoc-html/whitespace-after-where-clause.struct2.html diff --git a/tests/rustdoc/whitespace-after-where-clause.trait.html b/tests/rustdoc-html/whitespace-after-where-clause.trait.html similarity index 100% rename from tests/rustdoc/whitespace-after-where-clause.trait.html rename to tests/rustdoc-html/whitespace-after-where-clause.trait.html diff --git a/tests/rustdoc/whitespace-after-where-clause.trait2.html b/tests/rustdoc-html/whitespace-after-where-clause.trait2.html similarity index 100% rename from tests/rustdoc/whitespace-after-where-clause.trait2.html rename to tests/rustdoc-html/whitespace-after-where-clause.trait2.html diff --git a/tests/rustdoc/whitespace-after-where-clause.union.html b/tests/rustdoc-html/whitespace-after-where-clause.union.html similarity index 100% rename from tests/rustdoc/whitespace-after-where-clause.union.html rename to tests/rustdoc-html/whitespace-after-where-clause.union.html diff --git a/tests/rustdoc/whitespace-after-where-clause.union2.html b/tests/rustdoc-html/whitespace-after-where-clause.union2.html similarity index 100% rename from tests/rustdoc/whitespace-after-where-clause.union2.html rename to tests/rustdoc-html/whitespace-after-where-clause.union2.html diff --git a/tests/rustdoc/without-redirect.rs b/tests/rustdoc-html/without-redirect.rs similarity index 100% rename from tests/rustdoc/without-redirect.rs rename to tests/rustdoc-html/without-redirect.rs diff --git a/tests/rustdoc/wrapping.rs b/tests/rustdoc-html/wrapping.rs similarity index 100% rename from tests/rustdoc/wrapping.rs rename to tests/rustdoc-html/wrapping.rs diff --git a/triagebot.toml b/triagebot.toml index fbb2bac2267b..4c3e5c2a5931 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -240,7 +240,7 @@ trigger_files = [ "src/rustdoc-json-types", # Tests - "tests/rustdoc", + "tests/rustdoc-html", "tests/rustdoc-ui", "tests/rustdoc-gui", "tests/rustdoc-js/", @@ -315,7 +315,7 @@ trigger_labels = [ ] trigger_files = [ "src/librustdoc/html/", - "tests/rustdoc/", + "tests/rustdoc-html/", "tests/rustdoc-gui/", "tests/rustdoc-js/", "tests/rustdoc-js-std/", @@ -1638,7 +1638,7 @@ dep-bumps = [ "/src/stage0" = ["bootstrap"] "/tests/run-make" = ["compiler"] "/tests/run-make-cargo" = ["compiler"] -"/tests/rustdoc" = ["rustdoc"] +"/tests/rustdoc-html" = ["rustdoc"] "/tests/rustdoc-gui" = ["rustdoc"] "/tests/rustdoc-js-std" = ["rustdoc"] "/tests/rustdoc-js/" = ["rustdoc"] From 8256623ab478ff8d79f3b0305e002acdb6cbb76d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 3 Jan 2026 16:06:28 +0100 Subject: [PATCH 0335/1061] Update `rustc-dev-guide` about `tests/rustdoc` renamed into `tests/rustdoc-html` --- src/doc/rustc-dev-guide/src/SUMMARY.md | 2 +- .../{rustdoc-test-suite.md => rustdoc-html-test-suite.md} | 4 ++-- .../src/rustdoc-internals/rustdoc-json-test-suite.md | 2 +- src/doc/rustc-dev-guide/src/tests/compiletest.md | 4 ++-- src/doc/rustc-dev-guide/src/tests/directives.md | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) rename src/doc/rustc-dev-guide/src/rustdoc-internals/{rustdoc-test-suite.md => rustdoc-html-test-suite.md} (98%) diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index e80ee6a5137d..2dd07144a78c 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -100,7 +100,7 @@ - [Parallel compilation](./parallel-rustc.md) - [Rustdoc internals](./rustdoc-internals.md) - [Search](./rustdoc-internals/search.md) - - [The `rustdoc` test suite](./rustdoc-internals/rustdoc-test-suite.md) + - [The `rustdoc-html` test suite](./rustdoc-internals/rustdoc-html-test-suite.md) - [The `rustdoc-gui` test suite](./rustdoc-internals/rustdoc-gui-test-suite.md) - [The `rustdoc-json` test suite](./rustdoc-internals/rustdoc-json-test-suite.md) - [GPU offload internals](./offload/internals.md) diff --git a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-test-suite.md b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-html-test-suite.md similarity index 98% rename from src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-test-suite.md rename to src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-html-test-suite.md index 9516968df803..b74405d310eb 100644 --- a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-test-suite.md +++ b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-html-test-suite.md @@ -1,6 +1,6 @@ -# The `rustdoc` test suite +# The `rustdoc-html` test suite -This page is about the test suite named `rustdoc` used to test the HTML output of `rustdoc`. +This page is about the test suite named `rustdoc-html` used to test the HTML output of `rustdoc`. For other rustdoc-specific test suites, see [Rustdoc test suites]. Each test file in this test suite is simply a Rust source file `file.rs` sprinkled with diff --git a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-json-test-suite.md b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-json-test-suite.md index 5781a12ca44c..7a846b711326 100644 --- a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-json-test-suite.md +++ b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-json-test-suite.md @@ -24,7 +24,7 @@ Also, talk about how it works ## jsondocck [jsondocck] processes directives given in comments, to assert that the values in the output are expected. -It's a lot like [htmldocck](./rustdoc-test-suite.md) in that way. +It's a lot like [htmldocck](./rustdoc-html-test-suite.md) in that way. It uses [JSONPath] as a query language, which takes a path, and returns a *list* of values that that path is said to match to. diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md index e0924f8538ef..d69e0a5ce988 100644 --- a/src/doc/rustc-dev-guide/src/tests/compiletest.md +++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md @@ -82,7 +82,7 @@ The following test suites are available, with links for more information: | Test suite | Purpose | |--------------------------------------|--------------------------------------------------------------------------| -| [`rustdoc`][rustdoc-html-tests] | Check HTML output of `rustdoc` | +| [`rustdoc-html`][rustdoc-html-tests] | Check HTML output of `rustdoc` | | [`rustdoc-gui`][rustdoc-gui-tests] | Check `rustdoc`'s GUI using a web browser | | [`rustdoc-js`][rustdoc-js-tests] | Check `rustdoc`'s search engine and index | | [`rustdoc-js-std`][rustdoc-js-tests] | Check `rustdoc`'s search engine and index on the std library docs | @@ -94,7 +94,7 @@ These tests ensure that certain lints that are emitted as part of executing rust are also run when executing rustc. Run-make tests pertaining to rustdoc are typically named `run-make/rustdoc-*/`. -[rustdoc-html-tests]: ../rustdoc-internals/rustdoc-test-suite.md +[rustdoc-html-tests]: ../rustdoc-internals/rustdoc-html-test-suite.md [rustdoc-gui-tests]: ../rustdoc-internals/rustdoc-gui-test-suite.md [rustdoc-js-tests]: ../rustdoc-internals/search.md#testing-the-search-engine [rustdoc-json-tests]: ../rustdoc-internals/rustdoc-json-test-suite.md diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 4852c3623b05..52e1f09dca0f 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -308,12 +308,12 @@ Asked in #### Test-suite-specific directives -The test suites [`rustdoc`][rustdoc-html-tests], [`rustdoc-js`/`rustdoc-js-std`][rustdoc-js-tests] +The test suites [`rustdoc-html`][rustdoc-html-tests], [`rustdoc-js`/`rustdoc-js-std`][rustdoc-js-tests] and [`rustdoc-json`][rustdoc-json-tests] each feature an additional set of directives whose basic syntax resembles the one of compiletest directives but which are ultimately read and checked by separate tools. For more information, please read their respective chapters as linked above. -[rustdoc-html-tests]: ../rustdoc-internals/rustdoc-test-suite.md +[rustdoc-html-tests]: ../rustdoc-internals/rustdoc-html-test-suite.md [rustdoc-js-tests]: ../rustdoc-internals/search.html#testing-the-search-engine [rustdoc-json-tests]: ../rustdoc-internals/rustdoc-json-test-suite.md From 3d965bdc282a4a45cf2d5f83794cbe68a316bf60 Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Wed, 7 Jan 2026 13:15:17 +0000 Subject: [PATCH 0336/1061] Convert static lifetime to an nll var --- compiler/rustc_borrowck/src/type_check/mod.rs | 10 ++++++++-- ...-to-ptr-unsized-adt-tail-with-static-region.rs | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 tests/ui/cast/ptr-to-ptr-unsized-adt-tail-with-static-region.rs diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 097416b4f280..e5aad4cdbd06 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1581,12 +1581,18 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { .unwrap(); } (None, None) => { + // `struct_tail` returns regions which haven't been mapped + // to nll vars yet so we do it here as `outlives_constraints` + // expects nll vars. + let src_lt = self.universal_regions.to_region_vid(src_lt); + let dst_lt = self.universal_regions.to_region_vid(dst_lt); + // The principalless (no non-auto traits) case: // You can only cast `dyn Send + 'long` to `dyn Send + 'short`. self.constraints.outlives_constraints.push( OutlivesConstraint { - sup: src_lt.as_var(), - sub: dst_lt.as_var(), + sup: src_lt, + sub: dst_lt, locations: location.to_locations(), span: location.to_locations().span(self.body), category: ConstraintCategory::Cast { diff --git a/tests/ui/cast/ptr-to-ptr-unsized-adt-tail-with-static-region.rs b/tests/ui/cast/ptr-to-ptr-unsized-adt-tail-with-static-region.rs new file mode 100644 index 000000000000..7319a670c881 --- /dev/null +++ b/tests/ui/cast/ptr-to-ptr-unsized-adt-tail-with-static-region.rs @@ -0,0 +1,15 @@ +//@ check-pass + +// During MIR typeck when casting `*mut dyn Sync + '?x` to +// `*mut Wrap` we compute the tail of `Wrap` as `dyn Sync + 'static`. +// +// This test ensures that we first convert the `'static` lifetime to +// the nll var `'?0` before introducing the region constraint `'?x: 'static`. + +struct Wrap(dyn Sync + 'static); + +fn cast(x: *mut (dyn Sync + 'static)) { + x as *mut Wrap; +} + +fn main() {} From 87195e7a2a5046153ad6b718aa562a862d562ed6 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 6 Jan 2026 23:30:40 +0300 Subject: [PATCH 0337/1061] resolve: Do not query edition too eagerly in `visit_scopes` --- compiler/rustc_resolve/src/ident.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index e0acf043ffcf..cc05f35b327f 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -50,7 +50,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { mut self: CmResolver<'r, 'ra, 'tcx>, scope_set: ScopeSet<'ra>, parent_scope: &ParentScope<'ra>, - ctxt: SyntaxContext, + orig_ctxt: SyntaxContext, derive_fallback_lint_id: Option, mut visitor: impl FnMut( &mut CmResolver<'r, 'ra, 'tcx>, @@ -100,7 +100,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // 4c. Standard library prelude (de-facto closed, controlled). // 6. Language prelude: builtin attributes (closed, controlled). - let rust_2015 = ctxt.edition().is_rust_2015(); let (ns, macro_kind) = match scope_set { ScopeSet::All(ns) | ScopeSet::Module(ns, _) @@ -123,7 +122,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { TypeNS | ValueNS => Scope::ModuleNonGlobs(module, None), MacroNS => Scope::DeriveHelpers(parent_scope.expansion), }; - let mut ctxt = ctxt.normalize_to_macros_2_0(); + let mut ctxt = orig_ctxt.normalize_to_macros_2_0(); let mut use_prelude = !module.no_implicit_prelude; loop { @@ -148,7 +147,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { true } Scope::ModuleNonGlobs(..) | Scope::ModuleGlobs(..) => true, - Scope::MacroUsePrelude => use_prelude || rust_2015, + Scope::MacroUsePrelude => use_prelude || orig_ctxt.edition().is_rust_2015(), Scope::BuiltinAttrs => true, Scope::ExternPreludeItems | Scope::ExternPreludeFlags => { use_prelude || module_and_extern_prelude || extern_prelude From adbdf8dbf04593bcdadf2edda98c6284eef5d295 Mon Sep 17 00:00:00 2001 From: Jamie Hill-Daniel Date: Wed, 7 Jan 2026 14:02:09 +0000 Subject: [PATCH 0338/1061] Allow invoking all help options at once --- compiler/rustc_driver_impl/src/lib.rs | 92 ++++++++++++++++++++++----- compiler/rustc_session/src/options.rs | 2 + 2 files changed, 78 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 7820198f2dcf..81d25a307bdd 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -228,8 +228,10 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) let args = args::arg_expand_all(&default_early_dcx, at_args); - let Some(matches) = handle_options(&default_early_dcx, &args) else { - return; + let (matches, help_only) = match handle_options(&default_early_dcx, &args) { + HandledOptions::None => return, + HandledOptions::Normal(matches) => (matches, false), + HandledOptions::HelpOnly(matches) => (matches, true), }; let sopts = config::build_session_options(&mut default_early_dcx, &matches); @@ -291,6 +293,11 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) return early_exit(); } + // We have now handled all help options, exit + if help_only { + return early_exit(); + } + if print_crate_info(codegen_backend, sess, has_input) == Compilation::Stop { return early_exit(); } @@ -1092,7 +1099,7 @@ pub fn describe_flag_categories(early_dcx: &EarlyDiagCtxt, matches: &Matches) -> // Don't handle -W help here, because we might first load additional lints. let debug_flags = matches.opt_strs("Z"); if debug_flags.iter().any(|x| *x == "help") { - describe_debug_flags(); + describe_unstable_flags(); return true; } @@ -1131,8 +1138,8 @@ fn get_backend_from_raw_matches( get_codegen_backend(early_dcx, &sysroot, backend_name, &target) } -fn describe_debug_flags() { - safe_println!("\nAvailable options:\n"); +fn describe_unstable_flags() { + safe_println!("\nAvailable unstable options:\n"); print_flag_list("-Z", config::Z_OPTIONS); } @@ -1156,6 +1163,16 @@ fn print_flag_list(cmdline_opt: &str, flag_list: &[OptionDesc]) { } } +pub enum HandledOptions { + /// Parsing failed, or we parsed a flag causing an early exit + None, + /// Successful parsing + Normal(getopts::Matches), + /// Parsing succeeded, but we received one or more 'help' flags + /// The compiler should proceed only until a possible `-W help` flag has been processed + HelpOnly(getopts::Matches), +} + /// Process command line options. Emits messages as appropriate. If compilation /// should continue, returns a getopts::Matches object parsed from args, /// otherwise returns `None`. @@ -1183,7 +1200,7 @@ fn print_flag_list(cmdline_opt: &str, flag_list: &[OptionDesc]) { /// This does not need to be `pub` for rustc itself, but @chaosite needs it to /// be public when using rustc as a library, see /// -pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option { +pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> HandledOptions { // Parse with *all* options defined in the compiler, we don't worry about // option stability here we just want to parse as much as possible. let mut options = getopts::Options::new(); @@ -1229,26 +1246,69 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option bool { + let opt_pos = |opt| matches.opt_positions(opt).first().copied(); + let opt_help_pos = |opt| { + matches + .opt_strs_pos(opt) + .iter() + .filter_map(|(pos, oval)| if oval == "help" { Some(*pos) } else { None }) + .next() + }; + let help_pos = if args.is_empty() { Some(0) } else { opt_pos("h").or_else(|| opt_pos("help")) }; + let zhelp_pos = opt_help_pos("Z"); + let chelp_pos = opt_help_pos("C"); + let print_help = || { + // Only show unstable options in --help if we accept unstable options. + let unstable_enabled = nightly_options::is_unstable_enabled(&matches); + let nightly_build = nightly_options::match_is_nightly_build(&matches); + usage(matches.opt_present("verbose"), unstable_enabled, nightly_build); + }; + + let mut helps = [ + (help_pos, &print_help as &dyn Fn()), + (zhelp_pos, &describe_unstable_flags), + (chelp_pos, &describe_codegen_flags), + ]; + helps.sort_by_key(|(pos, _)| pos.clone()); + let mut printed_any = false; + for printer in helps.iter().filter_map(|(pos, func)| pos.is_some().then_some(func)) { + printer(); + printed_any = true; + } + printed_any } /// Warn if `-o` is used without a space between the flag name and the value diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 21fa3321a30a..0a29d45457d5 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2125,6 +2125,7 @@ options! { #[rustc_lint_opt_deny_field_access("use `Session::must_emit_unwind_tables` instead of this field")] force_unwind_tables: Option = (None, parse_opt_bool, [TRACKED], "force use of unwind tables"), + help: bool = (false, parse_no_value, [UNTRACKED], "Print codegen options"), incremental: Option = (None, parse_opt_string, [UNTRACKED], "enable incremental compilation"), #[rustc_lint_opt_deny_field_access("documented to do nothing")] @@ -2395,6 +2396,7 @@ options! { environment variable `RUSTC_GRAPHVIZ_FONT` (default: `Courier, monospace`)"), has_thread_local: Option = (None, parse_opt_bool, [TRACKED], "explicitly enable the `cfg(target_thread_local)` directive"), + help: bool = (false, parse_no_value, [UNTRACKED], "Print unstable compiler options"), higher_ranked_assumptions: bool = (false, parse_bool, [TRACKED], "allow deducing higher-ranked outlives assumptions from coroutines when proving auto traits"), hint_mostly_unused: bool = (false, parse_bool, [TRACKED], From 12007736ac5dc0a4020464ace43409ec6280f2b6 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 7 Jan 2026 00:08:18 +0300 Subject: [PATCH 0339/1061] resolve: Use `Macros20NormalizedIdent` in more interfaces It allows to avoid expensive double normalization in some cases --- .../rustc_resolve/src/build_reduced_graph.rs | 26 ++++++++-------- compiler/rustc_resolve/src/diagnostics.rs | 6 ++-- compiler/rustc_resolve/src/ident.rs | 26 ++++++++-------- compiler/rustc_resolve/src/imports.rs | 20 ++++++------- compiler/rustc_resolve/src/late.rs | 8 +++-- compiler/rustc_resolve/src/lib.rs | 30 +++++++++++-------- compiler/rustc_resolve/src/macros.rs | 17 +++++------ 7 files changed, 69 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index d56ca7c079cb..ac0f388009d6 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -49,13 +49,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn plant_decl_into_local_module( &mut self, parent: Module<'ra>, - ident: Ident, + ident: Macros20NormalizedIdent, ns: Namespace, decl: Decl<'ra>, ) { if let Err(old_decl) = self.try_plant_decl_into_local_module(parent, ident, ns, decl, false) { - self.report_conflict(parent, ident, ns, old_decl, decl); + self.report_conflict(parent, ident.0, ns, old_decl, decl); } } @@ -71,6 +71,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { expn_id: LocalExpnId, ) { let decl = self.arenas.new_def_decl(res, vis.to_def_id(), span, expn_id); + let ident = Macros20NormalizedIdent::new(ident); self.plant_decl_into_local_module(parent, ident, ns, decl); } @@ -78,7 +79,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn define_extern( &self, parent: Module<'ra>, - ident: Ident, + ident: Macros20NormalizedIdent, ns: Namespace, child_index: usize, res: Res, @@ -280,6 +281,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) }; let ModChild { ident, res, vis, ref reexport_chain } = *child; + let ident = Macros20NormalizedIdent::new(ident); let span = child_span(self, reexport_chain, res); let res = res.expect_non_local(); let expansion = parent_scope.expansion; @@ -532,7 +534,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { if target.name != kw::Underscore { self.r.per_ns(|this, ns| { if !type_ns_only || ns == TypeNS { - let key = BindingKey::new(target, ns); + let key = BindingKey::new(Macros20NormalizedIdent::new(target), ns); this.resolution_or_default(current_module, key) .borrow_mut(this) .single_imports @@ -1023,11 +1025,11 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } self.r.potentially_unused_imports.push(import); let import_decl = self.r.new_import_decl(decl, import); + let ident = Macros20NormalizedIdent::new(ident); if ident.name != kw::Underscore && parent == self.r.graph_root { - let norm_ident = Macros20NormalizedIdent::new(ident); // FIXME: this error is technically unnecessary now when extern prelude is split into // two scopes, remove it with lang team approval. - if let Some(entry) = self.r.extern_prelude.get(&norm_ident) + if let Some(entry) = self.r.extern_prelude.get(&ident) && expansion != LocalExpnId::ROOT && orig_name.is_some() && entry.item_decl.is_none() @@ -1038,7 +1040,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } use indexmap::map::Entry; - match self.r.extern_prelude.entry(norm_ident) { + match self.r.extern_prelude.entry(ident) { Entry::Occupied(mut occupied) => { let entry = occupied.get_mut(); if entry.item_decl.is_some() { @@ -1290,8 +1292,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.local_macro_def_scopes.insert(def_id, parent_scope.module); if macro_rules { - let ident = ident.normalize_to_macros_2_0(); - self.r.macro_names.insert(ident); + let ident = Macros20NormalizedIdent::new(ident); + self.r.macro_names.insert(ident.0); let is_macro_export = ast::attr::contains_name(&item.attrs, sym::macro_export); let vis = if is_macro_export { Visibility::Public @@ -1320,8 +1322,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let import_decl = self.r.new_import_decl(decl, import); self.r.plant_decl_into_local_module(self.r.graph_root, ident, MacroNS, import_decl); } else { - self.r.check_reserved_macro_name(ident, res); - self.insert_unused_macro(ident, def_id, item.id); + self.r.check_reserved_macro_name(ident.0, res); + self.insert_unused_macro(ident.0, def_id, item.id); } self.r.feed_visibility(feed, vis); let scope = self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Def( @@ -1488,7 +1490,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { { // Don't add underscore names, they cannot be looked up anyway. let impl_def_id = self.r.tcx.local_parent(local_def_id); - let key = BindingKey::new(ident, ns); + let key = BindingKey::new(Macros20NormalizedIdent::new(ident), ns); self.r.impl_binding_keys.entry(impl_def_id).or_default().insert(key); } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 7c86ed91a07a..71444770ae37 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1187,7 +1187,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .get(&expn_id) .into_iter() .flatten() - .map(|(ident, _)| TypoSuggestion::typo_from_ident(*ident, res)), + .map(|(ident, _)| TypoSuggestion::typo_from_ident(ident.0, res)), ); } } @@ -1199,7 +1199,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let res = macro_rules_def.decl.res(); if filter_fn(res) { suggestions - .push(TypoSuggestion::typo_from_ident(macro_rules_def.ident, res)) + .push(TypoSuggestion::typo_from_ident(macro_rules_def.ident.0, res)) } } } @@ -2892,7 +2892,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return None; } - let binding_key = BindingKey::new(ident, MacroNS); + let binding_key = BindingKey::new(Macros20NormalizedIdent::new(ident), MacroNS); let binding = self.resolution(crate_module, binding_key)?.binding()?; let Res::Def(DefKind::Macro(kinds), _) = binding.res() else { return None; diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index cc05f35b327f..811f48925f51 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -9,7 +9,7 @@ use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK; use rustc_session::parse::feature_err; use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext}; -use rustc_span::{Ident, Span, kw, sym}; +use rustc_span::{Ident, Macros20NormalizedIdent, Span, kw, sym}; use tracing::{debug, instrument}; use crate::errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst}; @@ -519,7 +519,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ignore_decl: Option>, ignore_import: Option>, ) -> Result, ControlFlow> { - let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt)); + let unnorm_ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt)); + let ident = Macros20NormalizedIdent::new(unnorm_ident); let ret = match scope { Scope::DeriveHelpers(expn_id) => { if let Some(decl) = self @@ -602,7 +603,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { errors::ProcMacroDeriveResolutionFallback { span: orig_ident.span, ns_descr: ns.descr(), - ident, + ident: unnorm_ident, }, ); } @@ -652,7 +653,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { errors::ProcMacroDeriveResolutionFallback { span: orig_ident.span, ns_descr: ns.descr(), - ident, + ident: unnorm_ident, }, ); } @@ -698,7 +699,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut result = Err(Determinacy::Determined); if let Some(prelude) = self.prelude && let Ok(decl) = self.reborrow().resolve_ident_in_scope_set( - ident, + unnorm_ident, ScopeSet::Module(ns, prelude), parent_scope, None, @@ -982,7 +983,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn resolve_ident_in_module_non_globs_unadjusted<'r>( mut self: CmResolver<'r, 'ra, 'tcx>, module: Module<'ra>, - ident: Ident, + ident: Macros20NormalizedIdent, ns: Namespace, parent_scope: &ParentScope<'ra>, shadowing: Shadowing, @@ -1005,7 +1006,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if let Some(finalize) = finalize { return self.get_mut().finalize_module_binding( - ident, + ident.0, binding, parent_scope, module, @@ -1045,7 +1046,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn resolve_ident_in_module_globs_unadjusted<'r>( mut self: CmResolver<'r, 'ra, 'tcx>, module: Module<'ra>, - ident: Ident, + ident: Macros20NormalizedIdent, ns: Namespace, parent_scope: &ParentScope<'ra>, shadowing: Shadowing, @@ -1066,7 +1067,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if let Some(finalize) = finalize { return self.get_mut().finalize_module_binding( - ident, + ident.0, binding, parent_scope, module, @@ -1135,9 +1136,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None => return Err(ControlFlow::Continue(Undetermined)), }; let tmp_parent_scope; - let (mut adjusted_parent_scope, mut ident) = - (parent_scope, ident.normalize_to_macros_2_0()); - match ident.span.glob_adjust(module.expansion, glob_import.span) { + let (mut adjusted_parent_scope, mut ident) = (parent_scope, ident); + match ident.0.span.glob_adjust(module.expansion, glob_import.span) { Some(Some(def)) => { tmp_parent_scope = ParentScope { module: self.expn_def_scope(def), ..*parent_scope }; @@ -1147,7 +1147,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None => continue, }; let result = self.reborrow().resolve_ident_in_scope_set( - ident, + ident.0, ScopeSet::Module(ns, module), adjusted_parent_scope, None, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index a8bb53cc7f27..30e980afadec 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -20,7 +20,7 @@ use rustc_session::lint::builtin::{ use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::LocalExpnId; -use rustc_span::{Ident, Span, Symbol, kw, sym}; +use rustc_span::{Ident, Macros20NormalizedIdent, Span, Symbol, kw, sym}; use tracing::debug; use crate::Namespace::{self, *}; @@ -330,13 +330,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn try_plant_decl_into_local_module( &mut self, module: Module<'ra>, - ident: Ident, + ident: Macros20NormalizedIdent, ns: Namespace, decl: Decl<'ra>, warn_ambiguity: bool, ) -> Result<(), Decl<'ra>> { let res = decl.res(); - self.check_reserved_macro_name(ident, res); + self.check_reserved_macro_name(ident.0, res); self.set_decl_parent_module(decl, module); // Even if underscore names cannot be looked up, we still need to add them to modules, // because they can be fetched by glob imports from those modules, and bring traits @@ -474,7 +474,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let import_decl = self.new_import_decl(binding, *import); let _ = self.try_plant_decl_into_local_module( import.parent_scope.module, - ident.0, + ident, key.ns, import_decl, warn_ambiguity, @@ -496,11 +496,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let dummy_decl = self.new_import_decl(dummy_decl, import); self.per_ns(|this, ns| { let module = import.parent_scope.module; - let _ = - this.try_plant_decl_into_local_module(module, target, ns, dummy_decl, false); + let ident = Macros20NormalizedIdent::new(target); + let _ = this.try_plant_decl_into_local_module(module, ident, ns, dummy_decl, false); // Don't remove underscores from `single_imports`, they were never added. if target.name != kw::Underscore { - let key = BindingKey::new(target, ns); + let key = BindingKey::new(ident, ns); this.update_local_resolution(module, key, false, |_, resolution| { resolution.single_imports.swap_remove(&import); }) @@ -879,7 +879,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let import_decl = this.new_import_decl(binding, import); this.get_mut_unchecked().plant_decl_into_local_module( parent, - target, + Macros20NormalizedIdent::new(target), ns, import_decl, ); @@ -888,7 +888,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Err(Determinacy::Determined) => { // Don't remove underscores from `single_imports`, they were never added. if target.name != kw::Underscore { - let key = BindingKey::new(target, ns); + let key = BindingKey::new(Macros20NormalizedIdent::new(target), ns); this.get_mut_unchecked().update_local_resolution( parent, key, @@ -1504,7 +1504,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .is_some_and(|binding| binding.warn_ambiguity_recursive()); let _ = self.try_plant_decl_into_local_module( import.parent_scope.module, - key.ident.0, + key.ident, key.ns, import_decl, warn_ambiguity, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index b4941a6f5b99..33344c64ebc7 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -37,7 +37,9 @@ use rustc_session::config::{CrateType, ResolveDocLinks}; use rustc_session::lint; use rustc_session::parse::feature_err; use rustc_span::source_map::{Spanned, respan}; -use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, SyntaxContext, kw, sym}; +use rustc_span::{ + BytePos, DUMMY_SP, Ident, Macros20NormalizedIdent, Span, Symbol, SyntaxContext, kw, sym, +}; use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; use tracing::{debug, instrument, trace}; @@ -3629,7 +3631,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { return; }; ident.span.normalize_to_macros_2_0_and_adjust(module.expansion); - let key = BindingKey::new(ident, ns); + let key = BindingKey::new(Macros20NormalizedIdent::new(ident), ns); let mut decl = self.r.resolution(module, key).and_then(|r| r.best_decl()); debug!(?decl); if decl.is_none() { @@ -3640,7 +3642,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { TypeNS => ValueNS, _ => ns, }; - let key = BindingKey::new(ident, ns); + let key = BindingKey::new(Macros20NormalizedIdent::new(ident), ns); decl = self.r.resolution(module, key).and_then(|r| r.best_decl()); debug!(?decl); } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 063b6b4058f0..36afcb455f23 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -572,17 +572,17 @@ struct BindingKey { } impl BindingKey { - fn new(ident: Ident, ns: Namespace) -> Self { - BindingKey { ident: Macros20NormalizedIdent::new(ident), ns, disambiguator: 0 } + fn new(ident: Macros20NormalizedIdent, ns: Namespace) -> Self { + BindingKey { ident, ns, disambiguator: 0 } } fn new_disambiguated( - ident: Ident, + ident: Macros20NormalizedIdent, ns: Namespace, disambiguator: impl FnOnce() -> u32, ) -> BindingKey { let disambiguator = if ident.name == kw::Underscore { disambiguator() } else { 0 }; - BindingKey { ident: Macros20NormalizedIdent::new(ident), ns, disambiguator } + BindingKey { ident, ns, disambiguator } } } @@ -1076,7 +1076,7 @@ impl ExternPreludeEntry<'_> { struct DeriveData { resolutions: Vec, - helper_attrs: Vec<(usize, Ident)>, + helper_attrs: Vec<(usize, Macros20NormalizedIdent)>, has_derive_copy: bool, } @@ -1241,7 +1241,7 @@ pub struct Resolver<'ra, 'tcx> { /// `macro_rules` scopes produced by `macro_rules` item definitions. macro_rules_scopes: FxHashMap>, /// Helper attributes that are in scope for the given expansion. - helper_attrs: FxHashMap)>>, + helper_attrs: FxHashMap)>>, /// Ready or in-progress results of resolving paths inside the `#[derive(...)]` attribute /// with the given `ExpnId`. derive_data: FxHashMap, @@ -2251,20 +2251,24 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn extern_prelude_get_item<'r>( mut self: CmResolver<'r, 'ra, 'tcx>, - ident: Ident, + ident: Macros20NormalizedIdent, finalize: bool, ) -> Option> { - let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)); - entry.and_then(|entry| entry.item_decl).map(|(binding, _)| { + let entry = self.extern_prelude.get(&ident); + entry.and_then(|entry| entry.item_decl).map(|(decl, _)| { if finalize { - self.get_mut().record_use(ident, binding, Used::Scope); + self.get_mut().record_use(ident.0, decl, Used::Scope); } - binding + decl }) } - fn extern_prelude_get_flag(&self, ident: Ident, finalize: bool) -> Option> { - let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)); + fn extern_prelude_get_flag( + &self, + ident: Macros20NormalizedIdent, + finalize: bool, + ) -> Option> { + let entry = self.extern_prelude.get(&ident); entry.and_then(|entry| entry.flag_decl.as_ref()).and_then(|flag_decl| { let (pending_decl, finalized) = flag_decl.get(); let decl = match pending_decl { diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index c9c754374c87..32d686d4f702 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -29,7 +29,7 @@ use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; use rustc_span::hygiene::{self, AstPass, ExpnData, ExpnKind, LocalExpnId, MacroKind}; -use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, Ident, Macros20NormalizedIdent, Span, Symbol, kw, sym}; use crate::Namespace::*; use crate::errors::{ @@ -52,7 +52,7 @@ pub(crate) struct MacroRulesDecl<'ra> { pub(crate) decl: Decl<'ra>, /// `macro_rules` scope into which the `macro_rules` item was planted. pub(crate) parent_macro_rules_scope: MacroRulesScopeRef<'ra>, - pub(crate) ident: Ident, + pub(crate) ident: Macros20NormalizedIdent, } /// The scope introduced by a `macro_rules!` macro. @@ -403,13 +403,10 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { ) { Ok((Some(ext), _)) => { if !ext.helper_attrs.is_empty() { - let last_seg = resolution.path.segments.last().unwrap(); - let span = last_seg.ident.span.normalize_to_macros_2_0(); - entry.helper_attrs.extend( - ext.helper_attrs - .iter() - .map(|name| (i, Ident::new(*name, span))), - ); + let span = resolution.path.segments.last().unwrap().ident.span; + entry.helper_attrs.extend(ext.helper_attrs.iter().map(|name| { + (i, Macros20NormalizedIdent::new(Ident::new(*name, span))) + })); } entry.has_derive_copy |= ext.builtin_name == Some(sym::Copy); ext @@ -530,7 +527,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { target_trait.for_each_child(self, |this, ident, ns, _binding| { // FIXME: Adjust hygiene for idents from globs, like for glob imports. if let Some(overriding_keys) = this.impl_binding_keys.get(&impl_def_id) - && overriding_keys.contains(&BindingKey::new(ident.0, ns)) + && overriding_keys.contains(&BindingKey::new(ident, ns)) { // The name is overridden, do not produce it from the glob delegation. } else { From 888e28b41b05e2b27f7ba530e1f330dbe852de92 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 7 Jan 2026 01:17:11 +0300 Subject: [PATCH 0340/1061] resolve: Pass a normalized ident to `resolve_ident_in_scope` In practice it was already normalized because `visit_scopes` normalized it --- compiler/rustc_resolve/src/ident.rs | 25 ++++++++++++------------- tests/ui/proc-macro/generate-mod.stderr | 10 ---------- 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 811f48925f51..8baf194e4a06 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -433,12 +433,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { orig_ident.span.ctxt(), derive_fallback_lint_id, |this, scope, use_prelude, ctxt| { + let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt)); + // The passed `ctxt` is already normalized, so avoid expensive double normalization. + let ident = Macros20NormalizedIdent(ident); let res = match this.reborrow().resolve_ident_in_scope( - orig_ident, + ident, ns, scope, use_prelude, - ctxt, scope_set, parent_scope, // Shadowed decls don't need to be marked as used or non-speculatively loaded. @@ -507,11 +509,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn resolve_ident_in_scope<'r>( mut self: CmResolver<'r, 'ra, 'tcx>, - orig_ident: Ident, + ident: Macros20NormalizedIdent, ns: Namespace, scope: Scope<'ra>, use_prelude: UsePrelude, - ctxt: SyntaxContext, scope_set: ScopeSet<'ra>, parent_scope: &ParentScope<'ra>, finalize: Option, @@ -519,8 +520,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ignore_decl: Option>, ignore_import: Option>, ) -> Result, ControlFlow> { - let unnorm_ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt)); - let ident = Macros20NormalizedIdent::new(unnorm_ident); let ret = match scope { Scope::DeriveHelpers(expn_id) => { if let Some(decl) = self @@ -599,11 +598,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.get_mut().lint_buffer.buffer_lint( PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, lint_id, - orig_ident.span, + ident.span, errors::ProcMacroDeriveResolutionFallback { - span: orig_ident.span, + span: ident.span, ns_descr: ns.descr(), - ident: unnorm_ident, + ident: ident.0, }, ); } @@ -649,11 +648,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.get_mut().lint_buffer.buffer_lint( PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, lint_id, - orig_ident.span, + ident.span, errors::ProcMacroDeriveResolutionFallback { - span: orig_ident.span, + span: ident.span, ns_descr: ns.descr(), - ident: unnorm_ident, + ident: ident.0, }, ); } @@ -699,7 +698,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut result = Err(Determinacy::Determined); if let Some(prelude) = self.prelude && let Ok(decl) = self.reborrow().resolve_ident_in_scope_set( - unnorm_ident, + ident.0, ScopeSet::Module(ns, prelude), parent_scope, None, diff --git a/tests/ui/proc-macro/generate-mod.stderr b/tests/ui/proc-macro/generate-mod.stderr index af90df2c3dc3..371fd73e507b 100644 --- a/tests/ui/proc-macro/generate-mod.stderr +++ b/tests/ui/proc-macro/generate-mod.stderr @@ -47,7 +47,6 @@ LL | #[derive(generate_mod::CheckDerive)] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83583 = note: `#[deny(proc_macro_derive_resolution_fallback)]` (part of `#[deny(future_incompatible)]`) on by default - = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) error: cannot find type `OuterDerive` in this scope --> $DIR/generate-mod.rs:18:10 @@ -57,7 +56,6 @@ LL | #[derive(generate_mod::CheckDerive)] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83583 - = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) error: cannot find type `FromOutside` in this scope --> $DIR/generate-mod.rs:25:14 @@ -67,7 +65,6 @@ LL | #[derive(generate_mod::CheckDerive)] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83583 - = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) error: cannot find type `OuterDerive` in this scope --> $DIR/generate-mod.rs:25:14 @@ -77,7 +74,6 @@ LL | #[derive(generate_mod::CheckDerive)] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83583 - = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 8 previous errors @@ -92,7 +88,6 @@ LL | #[derive(generate_mod::CheckDerive)] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83583 = note: `#[deny(proc_macro_derive_resolution_fallback)]` (part of `#[deny(future_incompatible)]`) on by default - = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) Future breakage diagnostic: error: cannot find type `OuterDerive` in this scope @@ -104,7 +99,6 @@ LL | #[derive(generate_mod::CheckDerive)] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83583 = note: `#[deny(proc_macro_derive_resolution_fallback)]` (part of `#[deny(future_incompatible)]`) on by default - = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) Future breakage diagnostic: error: cannot find type `FromOutside` in this scope @@ -116,7 +110,6 @@ LL | #[derive(generate_mod::CheckDerive)] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83583 = note: `#[deny(proc_macro_derive_resolution_fallback)]` (part of `#[deny(future_incompatible)]`) on by default - = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) Future breakage diagnostic: error: cannot find type `OuterDerive` in this scope @@ -128,7 +121,6 @@ LL | #[derive(generate_mod::CheckDerive)] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83583 = note: `#[deny(proc_macro_derive_resolution_fallback)]` (part of `#[deny(future_incompatible)]`) on by default - = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) Future breakage diagnostic: warning: cannot find type `FromOutside` in this scope @@ -139,7 +131,6 @@ LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83583 - = note: this warning originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info) Future breakage diagnostic: warning: cannot find type `OuterDeriveLint` in this scope @@ -150,5 +141,4 @@ LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83583 - = note: this warning originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info) From 99a7d285d46474e10bb854dccee73484916e3fb7 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 7 Jan 2026 17:10:57 +0300 Subject: [PATCH 0341/1061] resolve: Avoid most allocations in `resolve_ident_in_scope_set` Also evaluate one cheap and often-false condition first --- compiler/rustc_resolve/src/ident.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 8baf194e4a06..6ed99042a43f 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -10,6 +10,7 @@ use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK; use rustc_session::parse::feature_err; use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext}; use rustc_span::{Ident, Macros20NormalizedIdent, Span, kw, sym}; +use smallvec::SmallVec; use tracing::{debug, instrument}; use crate::errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst}; @@ -396,7 +397,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { assert!(force || finalize.is_none()); // `finalize` implies `force` // Make sure `self`, `super` etc produce an error when passed to here. - if orig_ident.is_path_segment_keyword() && !matches!(scope_set, ScopeSet::Module(..)) { + if !matches!(scope_set, ScopeSet::Module(..)) && orig_ident.is_path_segment_keyword() { return Err(Determinacy::Determined); } @@ -423,7 +424,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // } // So we have to save the innermost solution and continue searching in outer scopes // to detect potential ambiguities. - let mut innermost_results: Vec<(Decl<'_>, Scope<'_>)> = Vec::new(); + let mut innermost_results: SmallVec<[(Decl<'_>, Scope<'_>); 2]> = SmallVec::new(); let mut determinacy = Determinacy::Determined; // Go through all the scopes and try to resolve the name. From 9c4ead681480427806416cb09ea1f667bd6052b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 7 Jan 2026 16:44:51 +0100 Subject: [PATCH 0342/1061] Remove legacy homu `try` and `auto` branch mentions --- .github/workflows/ci.yml | 19 +++++++++---------- src/ci/citool/src/main.rs | 6 ++---- src/ci/scripts/verify-channel.sh | 3 +-- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bb6bc325a3bb..5d26d617ba88 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,11 +11,9 @@ name: CI on: push: branches: - - auto - - try - - try-perf - - automation/bors/try - automation/bors/auto + - automation/bors/try + - try-perf pull_request: branches: - "**" @@ -33,9 +31,10 @@ defaults: concurrency: # For a given workflow, if we push to the same branch, cancel all previous builds on that branch. - # We add an exception for try builds (try branch) and unrolled rollup builds (try-perf), which - # are all triggered on the same branch, but which should be able to run concurrently. - group: ${{ github.workflow }}-${{ ((github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try') && github.sha) || github.ref }} + # We add an exception for try builds (automation/bors/try branch) and unrolled rollup builds + # (try-perf), which are all triggered on the same branch, but which should be able to run + # concurrently. + group: ${{ github.workflow }}-${{ ((github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try') && github.sha) || github.ref }} cancel-in-progress: true env: TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate" @@ -57,7 +56,7 @@ jobs: - name: Test citool # Only test citool on the auto branch, to reduce latency of the calculate matrix job # on PR/try builds. - if: ${{ github.ref == 'refs/heads/auto' || github.ref == 'refs/heads/automation/bors/auto' }} + if: ${{ github.ref == 'refs/heads/automation/bors/auto' }} run: | cd src/ci/citool CARGO_INCREMENTAL=0 cargo test @@ -80,7 +79,7 @@ jobs: # access the environment. # # We only enable the environment for the rust-lang/rust repository, so that CI works on forks. - environment: ${{ ((github.repository == 'rust-lang/rust' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try' || github.ref == 'refs/heads/auto' || github.ref == 'refs/heads/automation/bors/auto')) && 'bors') || '' }} + environment: ${{ ((github.repository == 'rust-lang/rust' && (github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try' || github.ref == 'refs/heads/automation/bors/auto')) && 'bors') || '' }} env: CI_JOB_NAME: ${{ matrix.name }} CI_JOB_DOC_URL: ${{ matrix.doc_url }} @@ -314,7 +313,7 @@ jobs: needs: [ calculate_matrix, job ] # !cancelled() executes the job regardless of whether the previous jobs passed or failed if: ${{ !cancelled() && contains(fromJSON('["auto", "try"]'), needs.calculate_matrix.outputs.run_type) }} - environment: ${{ ((github.repository == 'rust-lang/rust' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try' || github.ref == 'refs/heads/auto' || github.ref == 'refs/heads/automation/bors/auto')) && 'bors') || '' }} + environment: ${{ ((github.repository == 'rust-lang/rust' && (github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try' || github.ref == 'refs/heads/automation/bors/auto')) && 'bors') || '' }} steps: - name: checkout the source code uses: actions/checkout@v5 diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index d7b491d38f41..01c0650b3c98 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -41,14 +41,12 @@ impl GitHubContext { match (self.event_name.as_str(), self.branch_ref.as_str()) { ("pull_request", _) => Some(RunType::PullRequest), ("push", "refs/heads/try-perf") => Some(RunType::TryJob { job_patterns: None }), - ("push", "refs/heads/try" | "refs/heads/automation/bors/try") => { + ("push", "refs/heads/automation/bors/try") => { let patterns = self.get_try_job_patterns(); let patterns = if !patterns.is_empty() { Some(patterns) } else { None }; Some(RunType::TryJob { job_patterns: patterns }) } - ("push", "refs/heads/auto" | "refs/heads/automation/bors/auto") => { - Some(RunType::AutoJob) - } + ("push", "refs/heads/automation/bors/auto") => Some(RunType::AutoJob), ("push", "refs/heads/main") => Some(RunType::MainJob), _ => None, } diff --git a/src/ci/scripts/verify-channel.sh b/src/ci/scripts/verify-channel.sh index cac8ba332ed1..286869e8a411 100755 --- a/src/ci/scripts/verify-channel.sh +++ b/src/ci/scripts/verify-channel.sh @@ -8,8 +8,7 @@ IFS=$'\n\t' source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" -if isCiBranch auto || isCiBranch try || isCiBranch try-perf || \ - isCiBranch automation/bors/try || isCiBranch automation/bors/auto; then +if isCiBranch try-perf || isCiBranch automation/bors/try || isCiBranch automation/bors/auto; then echo "channel verification is only executed on PR builds" exit fi From 4909fd8c7732ffa7d9641dc200b1010a2614c30f Mon Sep 17 00:00:00 2001 From: Jamie Hill-Daniel Date: Wed, 7 Jan 2026 16:53:05 +0000 Subject: [PATCH 0343/1061] Add tests for invoking multiple help options at once --- tests/run-make/rustc-help/rmake.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/run-make/rustc-help/rmake.rs b/tests/run-make/rustc-help/rmake.rs index 85e90e6352d0..3569cba3fcce 100644 --- a/tests/run-make/rustc-help/rmake.rs +++ b/tests/run-make/rustc-help/rmake.rs @@ -18,4 +18,31 @@ fn main() { // Check the diff between `rustc --help` and `rustc --help -v`. let help_v_diff = similar::TextDiff::from_lines(&help, &help_v).unified_diff().to_string(); diff().expected_file("help-v.diff").actual_text("actual", &help_v_diff).run(); + + // Check that all help options can be invoked at once + let codegen_help = bare_rustc().arg("-Chelp").run().stdout_utf8(); + let unstable_help = bare_rustc().arg("-Zhelp").run().stdout_utf8(); + let lints_help = bare_rustc().arg("-Whelp").run().stdout_utf8(); + let expected_all = format!("{help}{codegen_help}{unstable_help}{lints_help}"); + let all_help = bare_rustc().args(["--help", "-Chelp", "-Zhelp", "-Whelp"]).run().stdout_utf8(); + diff() + .expected_text( + "(rustc --help && rustc -Chelp && rustc -Zhelp && rustc -Whelp)", + &expected_all, + ) + .actual_text("(rustc --help -Chelp -Zhelp -Whelp)", &all_help) + .run(); + + // Check that the ordering of help options is respected + // Note that this is except for `-Whelp`, which always comes last + let expected_ordered_help = format!("{unstable_help}{codegen_help}{help}{lints_help}"); + let ordered_help = + bare_rustc().args(["-Whelp", "-Zhelp", "-Chelp", "--help"]).run().stdout_utf8(); + diff() + .expected_text( + "(rustc -Whelp && rustc -Zhelp && rustc -Chelp && rustc --help)", + &expected_ordered_help, + ) + .actual_text("(rustc -Whelp -Zhelp -Chelp --help)", &ordered_help) + .run(); } From e834e60987288843436e7d44bb784cb297475dc0 Mon Sep 17 00:00:00 2001 From: Jamie Hill-Daniel Date: Wed, 7 Jan 2026 16:55:37 +0000 Subject: [PATCH 0344/1061] Test behavior of `--help --invalid-flag` --- tests/run-make/rustc-help/rmake.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/run-make/rustc-help/rmake.rs b/tests/run-make/rustc-help/rmake.rs index 3569cba3fcce..17811ef18449 100644 --- a/tests/run-make/rustc-help/rmake.rs +++ b/tests/run-make/rustc-help/rmake.rs @@ -45,4 +45,7 @@ fn main() { ) .actual_text("(rustc -Whelp -Zhelp -Chelp --help)", &ordered_help) .run(); + + // Test that `rustc --help` does not suppress invalid flag errors + let help = bare_rustc().arg("--help --invalid-flag").run_fail().stdout_utf8(); } From bbdba48aeb9029b0cf95ce3d6b7d417ce2be3860 Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 7 Jan 2026 00:03:46 +0100 Subject: [PATCH 0345/1061] Update tidy check for triagebot path mentions with glob support --- Cargo.lock | 1 + src/tools/tidy/Cargo.toml | 1 + src/tools/tidy/src/triagebot.rs | 35 ++++++++++++++++++++++++++++++++- 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 470b38d5a91c..427e93e56cd8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5658,6 +5658,7 @@ dependencies = [ "build_helper", "cargo_metadata 0.21.0", "fluent-syntax", + "globset", "ignore", "miropt-test-tools", "regex", diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index 47b59543c59c..cbf27ea87a07 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -8,6 +8,7 @@ autobins = false build_helper = { path = "../../build_helper" } cargo_metadata = "0.21" regex = "1" +globset = "0.4.18" miropt-test-tools = { path = "../miropt-test-tools" } walkdir = "2" ignore = "0.4.18" diff --git a/src/tools/tidy/src/triagebot.rs b/src/tools/tidy/src/triagebot.rs index 01401c94d730..59cd9d80b07a 100644 --- a/src/tools/tidy/src/triagebot.rs +++ b/src/tools/tidy/src/triagebot.rs @@ -1,5 +1,6 @@ //! Tidy check to ensure paths mentioned in triagebot.toml exist in the project. +use std::collections::HashSet; use std::path::Path; use toml::Value; @@ -22,6 +23,9 @@ pub fn check(path: &Path, tidy_ctx: TidyCtx) { // Check [mentions."*"] sections, i.e. [mentions."compiler/rustc_const_eval/src/"] if let Some(Value::Table(mentions)) = config.get("mentions") { + let mut builder = globset::GlobSetBuilder::new(); + let mut glob_entries = Vec::new(); + for (entry_key, entry_val) in mentions.iter() { // If the type is set to something other than "filename", then this is not a path. if entry_val.get("type").is_some_and(|t| t.as_str().unwrap_or_default() != "filename") { @@ -33,8 +37,37 @@ pub fn check(path: &Path, tidy_ctx: TidyCtx) { let full_path = path.join(clean_path); if !full_path.exists() { + // The full-path doesn't exists, maybe it's a glob, let's add it to the glob set builder + // to be checked against all the file and directories in the repository. + builder.add(globset::Glob::new(&format!("{clean_path}*")).unwrap()); + glob_entries.push(clean_path.to_string()); + } + } + + let gs = builder.build().unwrap(); + + let mut found = HashSet::new(); + let mut matches = Vec::new(); + + // Walk the entire repository and match any entry against the remaining paths + for entry in ignore::WalkBuilder::new(path).build().flatten() { + // Strip the prefix as mentions entries are always relative to the repo + let entry_path = entry.path().strip_prefix(path).unwrap(); + + // Find the matches and add them to the found set + gs.matches_into(entry_path, &mut matches); + found.extend(matches.iter().copied()); + + // Early-exist if all the globs have been matched + if found.len() == glob_entries.len() { + break; + } + } + + for (i, clean_path) in glob_entries.iter().enumerate() { + if !found.contains(&i) { check.error(format!( - "triagebot.toml [mentions.*] contains path '{clean_path}' which doesn't exist" + "triagebot.toml [mentions.*] contains '{clean_path}' which doesn't match any file or directory in the repository" )); } } From f36b249f3fdca81c227075b7dafe61f3014ad508 Mon Sep 17 00:00:00 2001 From: Sergio Giro Date: Wed, 7 Jan 2026 17:29:11 +0000 Subject: [PATCH 0346/1061] missing_enforced_import_rename: Do not enforce for underscores --- clippy_lints/src/missing_enforced_import_rename.rs | 3 ++- tests/ui-toml/missing_enforced_import_rename/clippy.toml | 3 ++- .../conf_missing_enforced_import_rename.fixed | 1 + .../conf_missing_enforced_import_rename.rs | 1 + .../conf_missing_enforced_import_rename.stderr | 2 +- 5 files changed, 7 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs index eeea6dfd5f4b..5dd38cf059c2 100644 --- a/clippy_lints/src/missing_enforced_import_rename.rs +++ b/clippy_lints/src/missing_enforced_import_rename.rs @@ -82,7 +82,8 @@ impl LateLintPass<'_> for ImportRename { && let Some(import) = match snip.split_once(" as ") { None => Some(snip.as_str()), Some((import, rename)) => { - if rename.trim() == name.as_str() { + let trimmed_rename = rename.trim(); + if trimmed_rename == "_" || trimmed_rename == name.as_str() { None } else { Some(import.trim()) diff --git a/tests/ui-toml/missing_enforced_import_rename/clippy.toml b/tests/ui-toml/missing_enforced_import_rename/clippy.toml index 05ba822874d5..11af5b0a3306 100644 --- a/tests/ui-toml/missing_enforced_import_rename/clippy.toml +++ b/tests/ui-toml/missing_enforced_import_rename/clippy.toml @@ -6,5 +6,6 @@ enforced-import-renames = [ { path = "std::clone", rename = "foo" }, { path = "std::thread::sleep", rename = "thread_sleep" }, { path = "std::any::type_name", rename = "ident" }, - { path = "std::sync::Mutex", rename = "StdMutie" } + { path = "std::sync::Mutex", rename = "StdMutie" }, + { path = "std::io::Write", rename = "to_test_rename_as_underscore" } ] diff --git a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed index 3e882f496985..c96df2884b8d 100644 --- a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed +++ b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed @@ -15,6 +15,7 @@ use std::{ sync :: Mutex as StdMutie, //~^ missing_enforced_import_renames }; +use std::io::Write as _; fn main() { use std::collections::BTreeMap as Map; diff --git a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs index 32255af5117f..662e89157675 100644 --- a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs +++ b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs @@ -15,6 +15,7 @@ use std::{ sync :: Mutex, //~^ missing_enforced_import_renames }; +use std::io::Write as _; fn main() { use std::collections::BTreeMap as OopsWrongRename; diff --git a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr index 982b144eb872..139331d17619 100644 --- a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr +++ b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr @@ -32,7 +32,7 @@ LL | sync :: Mutex, | ^^^^^^^^^^^^^ help: try: `sync :: Mutex as StdMutie` error: this import should be renamed - --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:20:5 + --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:21:5 | LL | use std::collections::BTreeMap as OopsWrongRename; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `use std::collections::BTreeMap as Map` From ebd0151c81a39b358c6e6e17caf9458b0a4f78b4 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Wed, 7 Jan 2026 10:42:00 -0700 Subject: [PATCH 0347/1061] Fix the connect_error test on FreeBSD 15+ On FreeBSD 15, the error code returned in this situation changed. It's now ENETUNREACH. I think that error code is reasonable, and it's documented for connect(2), so we should expect that it might be returned. --- library/std/src/net/tcp/tests.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs index 7c7ef7b2f701..e4a30b80e3df 100644 --- a/library/std/src/net/tcp/tests.rs +++ b/library/std/src/net/tcp/tests.rs @@ -37,7 +37,8 @@ fn connect_error() { e.kind() == ErrorKind::ConnectionRefused || e.kind() == ErrorKind::InvalidInput || e.kind() == ErrorKind::AddrInUse - || e.kind() == ErrorKind::AddrNotAvailable, + || e.kind() == ErrorKind::AddrNotAvailable + || e.kind() == ErrorKind::NetworkUnreachable, "bad error: {} {:?}", e, e.kind() From 870626a390f267fc1a21e0712b6639bde3091c71 Mon Sep 17 00:00:00 2001 From: Immad Mir Date: Wed, 7 Jan 2026 23:10:44 +0530 Subject: [PATCH 0348/1061] Move issue-12660 to 'ui/cross-crate/ with a descriptive name Author: Immad Mir --- .../issue-12660-aux.rs => cross-crate/auxiliary/aux-12660.rs} | 0 .../cross-crate-unit-struct-reexport.rs} | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/ui/{issues/auxiliary/issue-12660-aux.rs => cross-crate/auxiliary/aux-12660.rs} (100%) rename tests/ui/{issues/issue-12660.rs => cross-crate/cross-crate-unit-struct-reexport.rs} (82%) diff --git a/tests/ui/issues/auxiliary/issue-12660-aux.rs b/tests/ui/cross-crate/auxiliary/aux-12660.rs similarity index 100% rename from tests/ui/issues/auxiliary/issue-12660-aux.rs rename to tests/ui/cross-crate/auxiliary/aux-12660.rs diff --git a/tests/ui/issues/issue-12660.rs b/tests/ui/cross-crate/cross-crate-unit-struct-reexport.rs similarity index 82% rename from tests/ui/issues/issue-12660.rs rename to tests/ui/cross-crate/cross-crate-unit-struct-reexport.rs index 3aa3426519af..2d4e0c654ef3 100644 --- a/tests/ui/issues/issue-12660.rs +++ b/tests/ui/cross-crate/cross-crate-unit-struct-reexport.rs @@ -1,5 +1,5 @@ //@ run-pass -//@ aux-build:issue-12660-aux.rs +//@ aux-build:aux-12660.rs extern crate issue12660aux; From 5548a84c87c61697454c04b4762a5e55e5bab815 Mon Sep 17 00:00:00 2001 From: wr7 Date: Wed, 7 Jan 2026 10:57:20 -0700 Subject: [PATCH 0349/1061] Stabilize `slice::element_offset` --- library/core/src/slice/mod.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 889fd4cd65df..1bca13b14ed4 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -4809,8 +4809,6 @@ impl [T] { /// # Examples /// Basic usage: /// ``` - /// #![feature(substr_range)] - /// /// let nums: &[u32] = &[1, 7, 1, 1]; /// let num = &nums[2]; /// @@ -4819,8 +4817,6 @@ impl [T] { /// ``` /// Returning `None` with an unaligned element: /// ``` - /// #![feature(substr_range)] - /// /// let arr: &[[u32; 2]] = &[[0, 1], [2, 3]]; /// let flat_arr: &[u32] = arr.as_flattened(); /// @@ -4834,7 +4830,7 @@ impl [T] { /// assert_eq!(arr.element_offset(weird_elm), None); // Points between element 0 and 1 /// ``` #[must_use] - #[unstable(feature = "substr_range", issue = "126769")] + #[stable(feature = "element_offset", since = "CURRENT_RUSTC_VERSION")] pub fn element_offset(&self, element: &T) -> Option { if T::IS_ZST { panic!("elements are zero-sized"); From ac505cc2cb98e625844f7c49b00c58dd90193d7c Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Sat, 20 Dec 2025 18:53:58 +0000 Subject: [PATCH 0350/1061] fix: `str_to_string` wrongly unmangled macros --- clippy_lints/src/strings.rs | 5 +++-- tests/ui/str_to_string.fixed | 14 ++++++++++++++ tests/ui/str_to_string.rs | 14 ++++++++++++++ tests/ui/str_to_string.stderr | 8 +++++++- 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 1d0efa46a14c..609504ffc233 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::res::{MaybeDef, MaybeQPath}; -use clippy_utils::source::{snippet, snippet_with_applicability}; +use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context}; use clippy_utils::{ SpanlessEq, get_expr_use_or_unification_node, get_parent_expr, is_lint_allowed, method_calls, peel_blocks, sym, }; @@ -404,7 +404,8 @@ impl<'tcx> LateLintPass<'tcx> for StrToString { "`to_string()` called on a `&str`", |diag| { let mut applicability = Applicability::MachineApplicable; - let snippet = snippet_with_applicability(cx, self_arg.span, "..", &mut applicability); + let (snippet, _) = + snippet_with_context(cx, self_arg.span, expr.span.ctxt(), "..", &mut applicability); diag.span_suggestion(expr.span, "try", format!("{snippet}.to_owned()"), applicability); }, ); diff --git a/tests/ui/str_to_string.fixed b/tests/ui/str_to_string.fixed index 2941c4dbd33d..8713c4f9bc86 100644 --- a/tests/ui/str_to_string.fixed +++ b/tests/ui/str_to_string.fixed @@ -8,3 +8,17 @@ fn main() { msg.to_owned(); //~^ str_to_string } + +fn issue16271(key: &[u8]) { + macro_rules! t { + ($e:expr) => { + match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + } + }; + } + + let _value = t!(str::from_utf8(key)).to_owned(); + //~^ str_to_string +} diff --git a/tests/ui/str_to_string.rs b/tests/ui/str_to_string.rs index 4c4d2bb18062..b81759e1037b 100644 --- a/tests/ui/str_to_string.rs +++ b/tests/ui/str_to_string.rs @@ -8,3 +8,17 @@ fn main() { msg.to_string(); //~^ str_to_string } + +fn issue16271(key: &[u8]) { + macro_rules! t { + ($e:expr) => { + match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + } + }; + } + + let _value = t!(str::from_utf8(key)).to_string(); + //~^ str_to_string +} diff --git a/tests/ui/str_to_string.stderr b/tests/ui/str_to_string.stderr index cb7b6b48843a..c0a38c8ebe46 100644 --- a/tests/ui/str_to_string.stderr +++ b/tests/ui/str_to_string.stderr @@ -13,5 +13,11 @@ error: `to_string()` called on a `&str` LL | msg.to_string(); | ^^^^^^^^^^^^^^^ help: try: `msg.to_owned()` -error: aborting due to 2 previous errors +error: `to_string()` called on a `&str` + --> tests/ui/str_to_string.rs:22:18 + | +LL | let _value = t!(str::from_utf8(key)).to_string(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t!(str::from_utf8(key)).to_owned()` + +error: aborting due to 3 previous errors From 15fc6cfd1ca770891a10ea1eb2ddf2fe05bc2428 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Fri, 2 Jan 2026 05:20:23 +0000 Subject: [PATCH 0351/1061] fix: `string_from_utf8_as_bytes` wrongly unmangled macros --- clippy_lints/src/strings.rs | 3 ++- tests/ui/string_from_utf8_as_bytes.fixed | 10 ++++++++++ tests/ui/string_from_utf8_as_bytes.rs | 10 ++++++++++ tests/ui/string_from_utf8_as_bytes.stderr | 10 ++++++++-- 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 609504ffc233..c0be724bcdee 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -273,6 +273,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { let string_expression = &expressions[0].0; let snippet_app = snippet_with_applicability(cx, string_expression.span, "..", &mut applicability); + let (right_snip, _) = snippet_with_context(cx, right.span, e.span.ctxt(), "..", &mut applicability); span_lint_and_sugg( cx, @@ -280,7 +281,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { e.span, "calling a slice of `as_bytes()` with `from_utf8` should be not necessary", "try", - format!("Some(&{snippet_app}[{}])", snippet(cx, right.span, "..")), + format!("Some(&{snippet_app}[{right_snip}])"), applicability, ); } diff --git a/tests/ui/string_from_utf8_as_bytes.fixed b/tests/ui/string_from_utf8_as_bytes.fixed index 193217114d88..98fa3a4fcf70 100644 --- a/tests/ui/string_from_utf8_as_bytes.fixed +++ b/tests/ui/string_from_utf8_as_bytes.fixed @@ -1,6 +1,16 @@ #![warn(clippy::string_from_utf8_as_bytes)] +macro_rules! test_range { + ($start:expr, $end:expr) => { + $start..$end + }; +} + fn main() { let _ = Some(&"Hello World!"[6..11]); //~^ string_from_utf8_as_bytes + + let s = "Hello World!"; + let _ = Some(&s[test_range!(6, 11)]); + //~^ string_from_utf8_as_bytes } diff --git a/tests/ui/string_from_utf8_as_bytes.rs b/tests/ui/string_from_utf8_as_bytes.rs index 49beb19ee40f..6354d5376ad6 100644 --- a/tests/ui/string_from_utf8_as_bytes.rs +++ b/tests/ui/string_from_utf8_as_bytes.rs @@ -1,6 +1,16 @@ #![warn(clippy::string_from_utf8_as_bytes)] +macro_rules! test_range { + ($start:expr, $end:expr) => { + $start..$end + }; +} + fn main() { let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]); //~^ string_from_utf8_as_bytes + + let s = "Hello World!"; + let _ = std::str::from_utf8(&s.as_bytes()[test_range!(6, 11)]); + //~^ string_from_utf8_as_bytes } diff --git a/tests/ui/string_from_utf8_as_bytes.stderr b/tests/ui/string_from_utf8_as_bytes.stderr index 99c8d8ae4eab..bba9ec0caf19 100644 --- a/tests/ui/string_from_utf8_as_bytes.stderr +++ b/tests/ui/string_from_utf8_as_bytes.stderr @@ -1,5 +1,5 @@ error: calling a slice of `as_bytes()` with `from_utf8` should be not necessary - --> tests/ui/string_from_utf8_as_bytes.rs:4:13 + --> tests/ui/string_from_utf8_as_bytes.rs:10:13 | LL | let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(&"Hello World!"[6..11])` @@ -7,5 +7,11 @@ LL | let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]); = note: `-D clippy::string-from-utf8-as-bytes` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::string_from_utf8_as_bytes)]` -error: aborting due to 1 previous error +error: calling a slice of `as_bytes()` with `from_utf8` should be not necessary + --> tests/ui/string_from_utf8_as_bytes.rs:14:13 + | +LL | let _ = std::str::from_utf8(&s.as_bytes()[test_range!(6, 11)]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(&s[test_range!(6, 11)])` + +error: aborting due to 2 previous errors From 2617622015f7294eead28ad6793ba04a3c16a643 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Fri, 2 Jan 2026 22:41:03 +0000 Subject: [PATCH 0352/1061] fix: `redundant_pattern_matching` wrongly unmangled macros --- .../src/matches/redundant_pattern_match.rs | 9 +++---- .../redundant_pattern_matching_result.fixed | 20 ++++++++++++++++ tests/ui/redundant_pattern_matching_result.rs | 24 +++++++++++++++++++ .../redundant_pattern_matching_result.stderr | 19 ++++++++++++++- 4 files changed, 67 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index 897e7da5a967..bf0c0c4aec3c 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -267,13 +267,14 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op if let Ok(arms) = arms.try_into() // TODO: use `slice::as_array` once stabilized && let Some((good_method, maybe_guard)) = found_good_method(cx, arms) { - let span = is_expn_of(expr.span, sym::matches).unwrap_or(expr.span.to(op.span)); + let expr_span = is_expn_of(expr.span, sym::matches).unwrap_or(expr.span); + let result_expr = match &op.kind { ExprKind::AddrOf(_, _, borrowed) => borrowed, _ => op, }; let mut app = Applicability::MachineApplicable; - let receiver_sugg = Sugg::hir_with_applicability(cx, result_expr, "_", &mut app).maybe_paren(); + let receiver_sugg = Sugg::hir_with_context(cx, result_expr, expr_span.ctxt(), "_", &mut app).maybe_paren(); let mut sugg = format!("{receiver_sugg}.{good_method}"); if let Some(guard) = maybe_guard { @@ -296,14 +297,14 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op return; } - let guard = Sugg::hir(cx, guard, ".."); + let guard = Sugg::hir_with_context(cx, guard, expr_span.ctxt(), "..", &mut app); let _ = write!(sugg, " && {}", guard.maybe_paren()); } span_lint_and_sugg( cx, REDUNDANT_PATTERN_MATCHING, - span, + expr_span, format!("redundant pattern matching, consider using `{good_method}`"), "try", sugg, diff --git a/tests/ui/redundant_pattern_matching_result.fixed b/tests/ui/redundant_pattern_matching_result.fixed index 261d82fc35c8..8754d71aa629 100644 --- a/tests/ui/redundant_pattern_matching_result.fixed +++ b/tests/ui/redundant_pattern_matching_result.fixed @@ -165,3 +165,23 @@ fn issue10803() { // Don't lint let _ = matches!(x, Err(16)); } + +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + Ok::($val) + }; + } + + let _ = test_expr!(42).is_ok(); + + macro_rules! test_guard { + ($val:expr) => { + ($val + 1) > 0 + }; + } + + let x: Result = Ok(42); + let _ = x.is_ok() && test_guard!(42); + //~^ redundant_pattern_matching +} diff --git a/tests/ui/redundant_pattern_matching_result.rs b/tests/ui/redundant_pattern_matching_result.rs index 6cae4cc4b6b0..b83b02588fb6 100644 --- a/tests/ui/redundant_pattern_matching_result.rs +++ b/tests/ui/redundant_pattern_matching_result.rs @@ -205,3 +205,27 @@ fn issue10803() { // Don't lint let _ = matches!(x, Err(16)); } + +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + Ok::($val) + }; + } + + let _ = match test_expr!(42) { + //~^ redundant_pattern_matching + Ok(_) => true, + Err(_) => false, + }; + + macro_rules! test_guard { + ($val:expr) => { + ($val + 1) > 0 + }; + } + + let x: Result = Ok(42); + let _ = matches!(x, Ok(_) if test_guard!(42)); + //~^ redundant_pattern_matching +} diff --git a/tests/ui/redundant_pattern_matching_result.stderr b/tests/ui/redundant_pattern_matching_result.stderr index 7e7d27d07a7f..dda203b753c3 100644 --- a/tests/ui/redundant_pattern_matching_result.stderr +++ b/tests/ui/redundant_pattern_matching_result.stderr @@ -209,5 +209,22 @@ error: redundant pattern matching, consider using `is_err()` LL | let _ = matches!(x, Err(_)); | ^^^^^^^^^^^^^^^^^^^ help: try: `x.is_err()` -error: aborting due to 28 previous errors +error: redundant pattern matching, consider using `is_ok()` + --> tests/ui/redundant_pattern_matching_result.rs:216:13 + | +LL | let _ = match test_expr!(42) { + | _____________^ +LL | | +LL | | Ok(_) => true, +LL | | Err(_) => false, +LL | | }; + | |_____^ help: try: `test_expr!(42).is_ok()` + +error: redundant pattern matching, consider using `is_ok()` + --> tests/ui/redundant_pattern_matching_result.rs:229:13 + | +LL | let _ = matches!(x, Ok(_) if test_guard!(42)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_ok() && test_guard!(42)` + +error: aborting due to 30 previous errors From 02e4f853efb393887dea4f481352e107e8d07998 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Fri, 2 Jan 2026 22:58:07 +0000 Subject: [PATCH 0353/1061] fix: `unnecessary_fold` wrongly unmangled macros --- clippy_lints/src/methods/unnecessary_fold.rs | 7 ++++--- tests/ui/unnecessary_fold.fixed | 11 +++++++++++ tests/ui/unnecessary_fold.rs | 11 +++++++++++ tests/ui/unnecessary_fold.stderr | 10 +++++++++- 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index 7802763ef74a..c3f031edff2e 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath, MaybeTypeckRes}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::{DefinedTy, ExprUseNode, expr_use_ctxt, peel_blocks, strip_pat_refs}; use rustc_ast::ast; use rustc_data_structures::packed::Pu128; @@ -124,11 +124,12 @@ fn check_fold_with_op( let mut applicability = replacement.default_applicability(); let turbofish = replacement.maybe_turbofish(cx.typeck_results().expr_ty_adjusted(right_expr).peel_refs()); + let (r_snippet, _) = + snippet_with_context(cx, right_expr.span, expr.span.ctxt(), "EXPR", &mut applicability); let sugg = if replacement.has_args { format!( - "{method}{turbofish}(|{second_arg_ident}| {r})", + "{method}{turbofish}(|{second_arg_ident}| {r_snippet})", method = replacement.method_name, - r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability), ) } else { format!("{method}{turbofish}()", method = replacement.method_name) diff --git a/tests/ui/unnecessary_fold.fixed b/tests/ui/unnecessary_fold.fixed index c3eeafbc39cd..d51359349cb9 100644 --- a/tests/ui/unnecessary_fold.fixed +++ b/tests/ui/unnecessary_fold.fixed @@ -178,4 +178,15 @@ fn issue10000() { } } +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($e:expr) => { + ($e + 1) > 2 + }; + } + + let _ = (0..3).any(|x| test_expr!(x)); + //~^ unnecessary_fold +} + fn main() {} diff --git a/tests/ui/unnecessary_fold.rs b/tests/ui/unnecessary_fold.rs index 6ab41a942625..c6eb7157ab12 100644 --- a/tests/ui/unnecessary_fold.rs +++ b/tests/ui/unnecessary_fold.rs @@ -178,4 +178,15 @@ fn issue10000() { } } +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($e:expr) => { + ($e + 1) > 2 + }; + } + + let _ = (0..3).fold(false, |acc: bool, x| acc || test_expr!(x)); + //~^ unnecessary_fold +} + fn main() {} diff --git a/tests/ui/unnecessary_fold.stderr b/tests/ui/unnecessary_fold.stderr index 025a2bd0048b..560427a681a9 100644 --- a/tests/ui/unnecessary_fold.stderr +++ b/tests/ui/unnecessary_fold.stderr @@ -203,5 +203,13 @@ error: this `.fold` can be written more succinctly using another method LL | (0..3).fold(1, |acc, x| acc * x) | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `product::()` -error: aborting due to 32 previous errors +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:188:20 + | +LL | let _ = (0..3).fold(false, |acc: bool, x| acc || test_expr!(x)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| test_expr!(x))` + | + = note: the `any` method is short circuiting and may change the program semantics if the iterator has side effects + +error: aborting due to 33 previous errors From 0cfbe56d0497f2210314c4101adff6bc74ea97f7 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Fri, 2 Jan 2026 23:07:31 +0000 Subject: [PATCH 0354/1061] fix: `match_as_ref` wrongly unmangled macros --- clippy_lints/src/matches/match_as_ref.rs | 5 +++-- tests/ui/match_as_ref.fixed | 10 ++++++++++ tests/ui/match_as_ref.rs | 14 ++++++++++++++ tests/ui/match_as_ref.stderr | 23 ++++++++++++++++++++++- 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/matches/match_as_ref.rs b/clippy_lints/src/matches/match_as_ref.rs index 795355f25f9e..12fe44ef2f13 100644 --- a/clippy_lints/src/matches/match_as_ref.rs +++ b/clippy_lints/src/matches/match_as_ref.rs @@ -46,6 +46,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: let cast = if input_ty == output_ty { "" } else { ".map(|x| x as _)" }; let mut applicability = Applicability::MachineApplicable; + let ctxt = expr.span.ctxt(); span_lint_and_then( cx, MATCH_AS_REF, @@ -59,7 +60,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: "use `Option::as_ref()`", format!( "{}.as_ref(){cast}", - Sugg::hir_with_applicability(cx, ex, "_", &mut applicability).maybe_paren(), + Sugg::hir_with_context(cx, ex, ctxt, "_", &mut applicability).maybe_paren(), ), applicability, ); @@ -69,7 +70,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: format!("use `Option::{method}()` directly"), format!( "{}.{method}(){cast}", - Sugg::hir_with_applicability(cx, ex, "_", &mut applicability).maybe_paren(), + Sugg::hir_with_context(cx, ex, ctxt, "_", &mut applicability).maybe_paren(), ), applicability, ); diff --git a/tests/ui/match_as_ref.fixed b/tests/ui/match_as_ref.fixed index 09a6ed169390..b1b8ffb885f5 100644 --- a/tests/ui/match_as_ref.fixed +++ b/tests/ui/match_as_ref.fixed @@ -90,3 +90,13 @@ fn issue15932() { let _: Option<&dyn std::fmt::Debug> = Some(0).as_ref().map(|x| x as _); } + +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + Some($val) + }; + } + + let _: Option<&u32> = test_expr!(42).as_ref(); +} diff --git a/tests/ui/match_as_ref.rs b/tests/ui/match_as_ref.rs index 347b6d186887..3113167957d4 100644 --- a/tests/ui/match_as_ref.rs +++ b/tests/ui/match_as_ref.rs @@ -114,3 +114,17 @@ fn issue15932() { Some(ref mut v) => Some(v), }; } + +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + Some($val) + }; + } + + let _: Option<&u32> = match test_expr!(42) { + //~^ match_as_ref + None => None, + Some(ref v) => Some(v), + }; +} diff --git a/tests/ui/match_as_ref.stderr b/tests/ui/match_as_ref.stderr index df06e358f296..3eab499fe409 100644 --- a/tests/ui/match_as_ref.stderr +++ b/tests/ui/match_as_ref.stderr @@ -127,5 +127,26 @@ LL - }; LL + let _: Option<&dyn std::fmt::Debug> = Some(0).as_ref().map(|x| x as _); | -error: aborting due to 6 previous errors +error: manual implementation of `Option::as_ref` + --> tests/ui/match_as_ref.rs:125:27 + | +LL | let _: Option<&u32> = match test_expr!(42) { + | ___________________________^ +LL | | +LL | | None => None, +LL | | Some(ref v) => Some(v), +LL | | }; + | |_____^ + | +help: use `Option::as_ref()` directly + | +LL - let _: Option<&u32> = match test_expr!(42) { +LL - +LL - None => None, +LL - Some(ref v) => Some(v), +LL - }; +LL + let _: Option<&u32> = test_expr!(42).as_ref(); + | + +error: aborting due to 7 previous errors From 9d08eb487bdac4927386bbfaaba71ef6bfd73ff1 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Fri, 2 Jan 2026 23:13:18 +0000 Subject: [PATCH 0355/1061] fix: `match_bool` wrongly unmangled macros --- clippy_lints/src/matches/match_bool.rs | 5 +++-- tests/ui/match_bool.fixed | 11 +++++++++++ tests/ui/match_bool.rs | 15 +++++++++++++++ tests/ui/match_bool.stderr | 12 +++++++++++- 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/matches/match_bool.rs b/clippy_lints/src/matches/match_bool.rs index dc3457aa7a46..3e76231b6ef1 100644 --- a/clippy_lints/src/matches/match_bool.rs +++ b/clippy_lints/src/matches/match_bool.rs @@ -25,8 +25,9 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>] "`match` on a boolean expression", move |diag| { let mut app = Applicability::MachineApplicable; + let ctxt = expr.span.ctxt(); let test_sugg = if let PatKind::Expr(arm_bool) = arms[0].pat.kind { - let test = Sugg::hir_with_applicability(cx, scrutinee, "_", &mut app); + let test = Sugg::hir_with_context(cx, scrutinee, ctxt, "_", &mut app); if let PatExprKind::Lit { lit, .. } = arm_bool.kind { match &lit.node { LitKind::Bool(true) => Some(test), @@ -36,7 +37,7 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>] .map(|test| { if let Some(guard) = &arms[0] .guard - .map(|g| Sugg::hir_with_applicability(cx, g, "_", &mut app)) + .map(|g| Sugg::hir_with_context(cx, g, ctxt, "_", &mut app)) { test.and(guard) } else { diff --git a/tests/ui/match_bool.fixed b/tests/ui/match_bool.fixed index 876ae935afde..3d5d0a0d532c 100644 --- a/tests/ui/match_bool.fixed +++ b/tests/ui/match_bool.fixed @@ -74,4 +74,15 @@ fn issue15351() { } } +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + ($val + 1) > 0 + }; + } + + let x = 5; + if test_expr!(x) { 1 } else { 0 }; +} + fn main() {} diff --git a/tests/ui/match_bool.rs b/tests/ui/match_bool.rs index a134ad8346e2..4db0aedf3260 100644 --- a/tests/ui/match_bool.rs +++ b/tests/ui/match_bool.rs @@ -126,4 +126,19 @@ fn issue15351() { } } +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + ($val + 1) > 0 + }; + } + + let x = 5; + match test_expr!(x) { + //~^ match_bool + true => 1, + false => 0, + }; +} + fn main() {} diff --git a/tests/ui/match_bool.stderr b/tests/ui/match_bool.stderr index c05742e56339..223acd17aead 100644 --- a/tests/ui/match_bool.stderr +++ b/tests/ui/match_bool.stderr @@ -183,5 +183,15 @@ LL + break 'a; LL + } } | -error: aborting due to 13 previous errors +error: `match` on a boolean expression + --> tests/ui/match_bool.rs:137:5 + | +LL | / match test_expr!(x) { +LL | | +LL | | true => 1, +LL | | false => 0, +LL | | }; + | |_____^ help: consider using an `if`/`else` expression: `if test_expr!(x) { 1 } else { 0 }` + +error: aborting due to 14 previous errors From 908860ed106e1540741bf7d2cbd5877bc62ef3ea Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Fri, 2 Jan 2026 23:20:24 +0000 Subject: [PATCH 0356/1061] fix: `match_ok_err` wrongly unmangled macros --- clippy_lints/src/matches/manual_ok_err.rs | 2 +- tests/ui/manual_ok_err.fixed | 10 ++++++++++ tests/ui/manual_ok_err.rs | 14 ++++++++++++++ tests/ui/manual_ok_err.stderr | 13 ++++++++++++- 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/matches/manual_ok_err.rs b/clippy_lints/src/matches/manual_ok_err.rs index c35c3d1f62e6..1fc8bb9acce2 100644 --- a/clippy_lints/src/matches/manual_ok_err.rs +++ b/clippy_lints/src/matches/manual_ok_err.rs @@ -135,7 +135,7 @@ fn apply_lint(cx: &LateContext<'_>, expr: &Expr<'_>, scrutinee: &Expr<'_>, is_ok } else { Applicability::MachineApplicable }; - let scrut = Sugg::hir_with_applicability(cx, scrutinee, "..", &mut app).maybe_paren(); + let scrut = Sugg::hir_with_context(cx, scrutinee, expr.span.ctxt(), "..", &mut app).maybe_paren(); let scrutinee_ty = cx.typeck_results().expr_ty(scrutinee); let (_, _, mutability) = peel_and_count_ty_refs(scrutinee_ty); diff --git a/tests/ui/manual_ok_err.fixed b/tests/ui/manual_ok_err.fixed index 9b70ce0df43a..e22f91a0155f 100644 --- a/tests/ui/manual_ok_err.fixed +++ b/tests/ui/manual_ok_err.fixed @@ -127,3 +127,13 @@ mod issue15051 { result_with_ref_mut(x).as_mut().ok() } } + +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + Ok::($val) + }; + } + + let _ = test_expr!(42).ok(); +} diff --git a/tests/ui/manual_ok_err.rs b/tests/ui/manual_ok_err.rs index dee904638245..c1355f0d4096 100644 --- a/tests/ui/manual_ok_err.rs +++ b/tests/ui/manual_ok_err.rs @@ -177,3 +177,17 @@ mod issue15051 { } } } + +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + Ok::($val) + }; + } + + let _ = match test_expr!(42) { + //~^ manual_ok_err + Ok(v) => Some(v), + Err(_) => None, + }; +} diff --git a/tests/ui/manual_ok_err.stderr b/tests/ui/manual_ok_err.stderr index 448fbffc0509..0c2ed368eb97 100644 --- a/tests/ui/manual_ok_err.stderr +++ b/tests/ui/manual_ok_err.stderr @@ -141,5 +141,16 @@ LL | | Err(_) => None, LL | | } | |_________^ help: replace with: `result_with_ref_mut(x).as_mut().ok()` -error: aborting due to 12 previous errors +error: manual implementation of `ok` + --> tests/ui/manual_ok_err.rs:188:13 + | +LL | let _ = match test_expr!(42) { + | _____________^ +LL | | +LL | | Ok(v) => Some(v), +LL | | Err(_) => None, +LL | | }; + | |_____^ help: replace with: `test_expr!(42).ok()` + +error: aborting due to 13 previous errors From 8ccfc833a03dec7f84a01abc54b8e8a7d24bd09b Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Sat, 3 Jan 2026 01:59:18 +0000 Subject: [PATCH 0357/1061] fix: `for_kv_map` wrongly unmangled macros --- clippy_lints/src/loops/for_kv_map.rs | 24 +++++++++++++++++------- clippy_lints/src/loops/mod.rs | 2 +- tests/ui/for_kv_map.fixed | 17 +++++++++++++++++ tests/ui/for_kv_map.rs | 17 +++++++++++++++++ tests/ui/for_kv_map.stderr | 14 +++++++++++++- 5 files changed, 65 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/loops/for_kv_map.rs b/clippy_lints/src/loops/for_kv_map.rs index 39b2391c98ec..7fb8e51377a2 100644 --- a/clippy_lints/src/loops/for_kv_map.rs +++ b/clippy_lints/src/loops/for_kv_map.rs @@ -1,16 +1,22 @@ use super::FOR_KV_MAP; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeDef; -use clippy_utils::source::snippet; +use clippy_utils::source::{snippet_with_applicability, walk_span_to_context}; use clippy_utils::{pat_is_wild, sugg}; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::sym; +use rustc_span::{Span, sym}; /// Checks for the `FOR_KV_MAP` lint. -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx Expr<'_>, body: &'tcx Expr<'_>) { +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + pat: &'tcx Pat<'_>, + arg: &'tcx Expr<'_>, + body: &'tcx Expr<'_>, + span: Span, +) { let pat_span = pat.span; if let PatKind::Tuple(pat, _) = pat.kind @@ -34,21 +40,25 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx _ => arg, }; - if matches!(ty.opt_diag_name(cx), Some(sym::HashMap | sym::BTreeMap)) { + if matches!(ty.opt_diag_name(cx), Some(sym::HashMap | sym::BTreeMap)) + && let Some(arg_span) = walk_span_to_context(arg_span, span.ctxt()) + { span_lint_and_then( cx, FOR_KV_MAP, arg_span, format!("you seem to want to iterate on a map's {kind}s"), |diag| { - let map = sugg::Sugg::hir(cx, arg, "map"); + let mut applicability = Applicability::MachineApplicable; + let map = sugg::Sugg::hir_with_context(cx, arg, span.ctxt(), "map", &mut applicability); + let pat = snippet_with_applicability(cx, new_pat_span, kind, &mut applicability); diag.multipart_suggestion( "use the corresponding method", vec![ - (pat_span, snippet(cx, new_pat_span, kind).into_owned()), + (pat_span, pat.to_string()), (arg_span, format!("{}.{kind}s{mutbl}()", map.maybe_paren())), ], - Applicability::MachineApplicable, + applicability, ); }, ); diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index ddc783069385..83574cab6b67 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -943,7 +943,7 @@ impl Loops { explicit_counter_loop::check(cx, pat, arg, body, expr, label); } self.check_for_loop_arg(cx, pat, arg); - for_kv_map::check(cx, pat, arg, body); + for_kv_map::check(cx, pat, arg, body, span); mut_range_bound::check(cx, arg, body); single_element_loop::check(cx, pat, arg, body, expr); same_item_push::check(cx, pat, arg, body, expr, self.msrv); diff --git a/tests/ui/for_kv_map.fixed b/tests/ui/for_kv_map.fixed index 2a68b7443fbf..6ec4cb01ffd1 100644 --- a/tests/ui/for_kv_map.fixed +++ b/tests/ui/for_kv_map.fixed @@ -69,3 +69,20 @@ fn main() { let _v = v; } } + +fn wrongly_unmangled_macros() { + use std::collections::HashMap; + + macro_rules! test_map { + ($val:expr) => { + &*$val + }; + } + + let m: HashMap = HashMap::new(); + let wrapped = Rc::new(m); + for v in test_map!(wrapped).values() { + //~^ for_kv_map + let _v = v; + } +} diff --git a/tests/ui/for_kv_map.rs b/tests/ui/for_kv_map.rs index 485a97815e3c..19e907ff10a6 100644 --- a/tests/ui/for_kv_map.rs +++ b/tests/ui/for_kv_map.rs @@ -69,3 +69,20 @@ fn main() { let _v = v; } } + +fn wrongly_unmangled_macros() { + use std::collections::HashMap; + + macro_rules! test_map { + ($val:expr) => { + &*$val + }; + } + + let m: HashMap = HashMap::new(); + let wrapped = Rc::new(m); + for (_, v) in test_map!(wrapped) { + //~^ for_kv_map + let _v = v; + } +} diff --git a/tests/ui/for_kv_map.stderr b/tests/ui/for_kv_map.stderr index 0bd474a10682..5436592f2ab6 100644 --- a/tests/ui/for_kv_map.stderr +++ b/tests/ui/for_kv_map.stderr @@ -72,5 +72,17 @@ LL - 'label: for (k, _value) in rm { LL + 'label: for k in rm.keys() { | -error: aborting due to 6 previous errors +error: you seem to want to iterate on a map's values + --> tests/ui/for_kv_map.rs:84:19 + | +LL | for (_, v) in test_map!(wrapped) { + | ^^^^^^^^^^^^^^^^^^ + | +help: use the corresponding method + | +LL - for (_, v) in test_map!(wrapped) { +LL + for v in test_map!(wrapped).values() { + | + +error: aborting due to 7 previous errors From 209e4d7d853950574dab187d360d71a479ce2402 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Sat, 3 Jan 2026 02:40:38 +0000 Subject: [PATCH 0358/1061] fix: `question_mark` wrongly unmangled macros --- clippy_lints/src/question_mark.rs | 7 ++++--- tests/ui/question_mark.fixed | 17 ++++++++++++++++- tests/ui/question_mark.rs | 22 +++++++++++++++++++++- tests/ui/question_mark.stderr | 19 ++++++++++++++++++- 4 files changed, 59 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 59d31f782bc3..e5fb3c0fa431 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -5,7 +5,7 @@ use clippy_config::types::MatchLintBehaviour; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{implements_trait, is_copy}; use clippy_utils::usage::local_used_after_expr; @@ -147,7 +147,8 @@ fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) { && !span_contains_cfg(cx, els.span) { let mut applicability = Applicability::MaybeIncorrect; - let init_expr_str = Sugg::hir_with_applicability(cx, init_expr, "..", &mut applicability).maybe_paren(); + let init_expr_str = + Sugg::hir_with_context(cx, init_expr, stmt.span.ctxt(), "..", &mut applicability).maybe_paren(); // Take care when binding is `ref` let sugg = if let PatKind::Binding( BindingMode(ByRef::Yes(_, ref_mutability), binding_mutability), @@ -295,7 +296,7 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex && (is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block)) { let mut applicability = Applicability::MachineApplicable; - let receiver_str = snippet_with_applicability(cx, caller.span, "..", &mut applicability); + let receiver_str = snippet_with_context(cx, caller.span, expr.span.ctxt(), "..", &mut applicability).0; let by_ref = !cx.type_is_copy_modulo_regions(caller_ty) && !matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)); let sugg = if let Some(else_inner) = r#else { diff --git a/tests/ui/question_mark.fixed b/tests/ui/question_mark.fixed index 2c5ee0245038..b8072932c4ea 100644 --- a/tests/ui/question_mark.fixed +++ b/tests/ui/question_mark.fixed @@ -1,5 +1,5 @@ #![feature(try_blocks)] -#![allow(clippy::unnecessary_wraps)] +#![allow(clippy::unnecessary_wraps, clippy::no_effect)] use std::sync::MutexGuard; @@ -500,3 +500,18 @@ mod issue14894 { Ok(()) } } + +fn wrongly_unmangled_macros() -> Option { + macro_rules! test_expr { + ($val:expr) => { + Some($val) + }; + } + + let x = test_expr!(42)?; + //~^^^ question_mark + Some(x); + + test_expr!(42)?; + test_expr!(42) +} diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs index b9ff9d1565b2..b320dcd4b0bc 100644 --- a/tests/ui/question_mark.rs +++ b/tests/ui/question_mark.rs @@ -1,5 +1,5 @@ #![feature(try_blocks)] -#![allow(clippy::unnecessary_wraps)] +#![allow(clippy::unnecessary_wraps, clippy::no_effect)] use std::sync::MutexGuard; @@ -615,3 +615,23 @@ mod issue14894 { Ok(()) } } + +fn wrongly_unmangled_macros() -> Option { + macro_rules! test_expr { + ($val:expr) => { + Some($val) + }; + } + + let Some(x) = test_expr!(42) else { + return None; + }; + //~^^^ question_mark + Some(x); + + if test_expr!(42).is_none() { + //~^ question_mark + return None; + } + test_expr!(42) +} diff --git a/tests/ui/question_mark.stderr b/tests/ui/question_mark.stderr index 9b2896328e66..d645c8830adc 100644 --- a/tests/ui/question_mark.stderr +++ b/tests/ui/question_mark.stderr @@ -333,5 +333,22 @@ LL | | return Err(reason); LL | | } | |_________^ help: replace it with: `result?;` -error: aborting due to 35 previous errors +error: this `let...else` may be rewritten with the `?` operator + --> tests/ui/question_mark.rs:626:5 + | +LL | / let Some(x) = test_expr!(42) else { +LL | | return None; +LL | | }; + | |______^ help: replace it with: `let x = test_expr!(42)?;` + +error: this block may be rewritten with the `?` operator + --> tests/ui/question_mark.rs:632:5 + | +LL | / if test_expr!(42).is_none() { +LL | | +LL | | return None; +LL | | } + | |_____^ help: replace it with: `test_expr!(42)?;` + +error: aborting due to 37 previous errors From 108436c6f98acc83b2a281465bc96ed505bbcb95 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Sun, 4 Jan 2026 20:57:16 +0000 Subject: [PATCH 0359/1061] fix: `iter_kv_map` wrongly unmangled macros --- clippy_lints/src/methods/iter_kv_map.rs | 7 ++++--- tests/ui/iter_kv_map.fixed | 6 ++++++ tests/ui/iter_kv_map.rs | 6 ++++++ tests/ui/iter_kv_map.stderr | 8 +++++++- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index 16db8663941e..366bfaed73d4 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -2,7 +2,7 @@ use super::ITER_KV_MAP; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeDef; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::{pat_is_wild, sym}; use rustc_hir::{Body, Expr, ExprKind, PatKind}; use rustc_lint::LateContext; @@ -58,6 +58,8 @@ pub(super) fn check<'tcx>( applicability, ); } else { + let (body_snippet, _) = + snippet_with_context(cx, body_expr.span, expr.span.ctxt(), "..", &mut applicability); span_lint_and_sugg( cx, ITER_KV_MAP, @@ -65,9 +67,8 @@ pub(super) fn check<'tcx>( format!("iterating on a map's {replacement_kind}s"), "try", format!( - "{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{}{bound_ident}| {})", + "{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{}{bound_ident}| {body_snippet})", annotation.prefix_str(), - snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability) ), applicability, ); diff --git a/tests/ui/iter_kv_map.fixed b/tests/ui/iter_kv_map.fixed index b18dda358877..189d76bc9431 100644 --- a/tests/ui/iter_kv_map.fixed +++ b/tests/ui/iter_kv_map.fixed @@ -189,3 +189,9 @@ fn issue14595() { let _ = map.as_ref().values().copied().collect::>(); //~^ iter_kv_map } + +fn issue16340() { + let hm: HashMap<&str, &str> = HashMap::new(); + let _ = hm.keys().map(|key| vec![key]); + //~^ iter_kv_map +} diff --git a/tests/ui/iter_kv_map.rs b/tests/ui/iter_kv_map.rs index 729e4e8a266c..cfc303447004 100644 --- a/tests/ui/iter_kv_map.rs +++ b/tests/ui/iter_kv_map.rs @@ -193,3 +193,9 @@ fn issue14595() { let _ = map.as_ref().iter().map(|(_, v)| v).copied().collect::>(); //~^ iter_kv_map } + +fn issue16340() { + let hm: HashMap<&str, &str> = HashMap::new(); + let _ = hm.iter().map(|(key, _)| vec![key]); + //~^ iter_kv_map +} diff --git a/tests/ui/iter_kv_map.stderr b/tests/ui/iter_kv_map.stderr index 8f73541f5033..866e69ea1922 100644 --- a/tests/ui/iter_kv_map.stderr +++ b/tests/ui/iter_kv_map.stderr @@ -269,5 +269,11 @@ error: iterating on a map's values LL | let _ = map.as_ref().iter().map(|(_, v)| v).copied().collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.as_ref().values()` -error: aborting due to 39 previous errors +error: iterating on a map's keys + --> tests/ui/iter_kv_map.rs:199:13 + | +LL | let _ = hm.iter().map(|(key, _)| vec![key]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hm.keys().map(|key| vec![key])` + +error: aborting due to 40 previous errors From 8c129e4219c21a0aafd2c8446ab57f0d76154ec7 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Mon, 5 Jan 2026 17:50:50 +0000 Subject: [PATCH 0360/1061] fix: `mutex_atomic` wrongly unmangled macros --- clippy_lints/src/mutex_atomic.rs | 2 +- tests/ui/mutex_atomic.fixed | 12 ++++++++++++ tests/ui/mutex_atomic.rs | 12 ++++++++++++ tests/ui/mutex_atomic.stderr | 10 +++++++++- 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 2fef8404f824..ad44d65b4d66 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -143,7 +143,7 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, ty_ascription: &T && new.ident.name == sym::new { let mut applicability = Applicability::MaybeIncorrect; - let arg = Sugg::hir_with_applicability(cx, arg, "_", &mut applicability); + let arg = Sugg::hir_with_context(cx, arg, expr.span.ctxt(), "_", &mut applicability); let mut suggs = vec![(expr.span, format!("std::sync::atomic::{atomic_name}::new({arg})"))]; match ty_ascription { TypeAscriptionKind::Required(ty_ascription) => { diff --git a/tests/ui/mutex_atomic.fixed b/tests/ui/mutex_atomic.fixed index e4218726019f..dc05d8a2c61f 100644 --- a/tests/ui/mutex_atomic.fixed +++ b/tests/ui/mutex_atomic.fixed @@ -65,3 +65,15 @@ fn issue13378() { let (funky_mtx) = std::sync::atomic::AtomicU64::new(0); //~^ mutex_integer } + +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + ($val > 0 && true) + }; + } + + let _ = std::sync::atomic::AtomicBool::new(test_expr!(1)); + //~^ mutex_atomic + // The suggestion should preserve the macro call: `AtomicBool::new(test_expr!(true))` +} diff --git a/tests/ui/mutex_atomic.rs b/tests/ui/mutex_atomic.rs index 95f2b135903f..33745f8fc5e1 100644 --- a/tests/ui/mutex_atomic.rs +++ b/tests/ui/mutex_atomic.rs @@ -65,3 +65,15 @@ fn issue13378() { let (funky_mtx): Mutex = Mutex::new(0); //~^ mutex_integer } + +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + ($val > 0 && true) + }; + } + + let _ = Mutex::new(test_expr!(1)); + //~^ mutex_atomic + // The suggestion should preserve the macro call: `AtomicBool::new(test_expr!(true))` +} diff --git a/tests/ui/mutex_atomic.stderr b/tests/ui/mutex_atomic.stderr index 0afc6d541dea..56d94035583c 100644 --- a/tests/ui/mutex_atomic.stderr +++ b/tests/ui/mutex_atomic.stderr @@ -130,5 +130,13 @@ LL - let (funky_mtx): Mutex = Mutex::new(0); LL + let (funky_mtx) = std::sync::atomic::AtomicU64::new(0); | -error: aborting due to 14 previous errors +error: using a `Mutex` where an atomic would do + --> tests/ui/mutex_atomic.rs:76:13 + | +LL | let _ = Mutex::new(test_expr!(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicBool::new(test_expr!(1))` + | + = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>` + +error: aborting due to 15 previous errors From 6750919d47f8150bf53381981150b8af8571d575 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 7 Jan 2026 19:36:10 +0100 Subject: [PATCH 0361/1061] add `pmaddwd` shim --- src/tools/miri/src/shims/x86/avx2.rs | 30 +------- src/tools/miri/src/shims/x86/avx512.rs | 11 ++- src/tools/miri/src/shims/x86/mod.rs | 46 ++++++++++++ src/tools/miri/src/shims/x86/sse2.rs | 30 +------- .../pass/shims/x86/intrinsics-x86-avx512.rs | 71 +++++++++++++++++++ 5 files changed, 131 insertions(+), 57 deletions(-) diff --git a/src/tools/miri/src/shims/x86/avx2.rs b/src/tools/miri/src/shims/x86/avx2.rs index 97b9f649c158..7d8e52db73d6 100644 --- a/src/tools/miri/src/shims/x86/avx2.rs +++ b/src/tools/miri/src/shims/x86/avx2.rs @@ -6,7 +6,7 @@ use rustc_target::callconv::FnAbi; use super::{ ShiftOp, horizontal_bin_op, mpsadbw, packssdw, packsswb, packusdw, packuswb, permute, pmaddbw, - pmulhrsw, psadbw, pshufb, psign, shift_simd_by_scalar, + pmaddwd, pmulhrsw, psadbw, pshufb, psign, shift_simd_by_scalar, }; use crate::*; @@ -232,33 +232,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [left, right] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let (left, left_len) = this.project_to_simd(left)?; - let (right, right_len) = this.project_to_simd(right)?; - let (dest, dest_len) = this.project_to_simd(dest)?; - - assert_eq!(left_len, right_len); - assert_eq!(dest_len.strict_mul(2), left_len); - - for i in 0..dest_len { - let j1 = i.strict_mul(2); - let left1 = this.read_scalar(&this.project_index(&left, j1)?)?.to_i16()?; - let right1 = this.read_scalar(&this.project_index(&right, j1)?)?.to_i16()?; - - let j2 = j1.strict_add(1); - let left2 = this.read_scalar(&this.project_index(&left, j2)?)?.to_i16()?; - let right2 = this.read_scalar(&this.project_index(&right, j2)?)?.to_i16()?; - - let dest = this.project_index(&dest, i)?; - - // Multiplications are i16*i16->i32, which will not overflow. - let mul1 = i32::from(left1).strict_mul(right1.into()); - let mul2 = i32::from(left2).strict_mul(right2.into()); - // However, this addition can overflow in the most extreme case - // (-0x8000)*(-0x8000)+(-0x8000)*(-0x8000) = 0x80000000 - let res = mul1.wrapping_add(mul2); - - this.write_scalar(Scalar::from_i32(res), &dest)?; - } + pmaddwd(this, left, right, dest)?; } _ => return interp_ok(EmulateItemResult::NotSupported), } diff --git a/src/tools/miri/src/shims/x86/avx512.rs b/src/tools/miri/src/shims/x86/avx512.rs index 0466ba1bd6c0..9231fc446919 100644 --- a/src/tools/miri/src/shims/x86/avx512.rs +++ b/src/tools/miri/src/shims/x86/avx512.rs @@ -3,7 +3,7 @@ use rustc_middle::ty::Ty; use rustc_span::Symbol; use rustc_target::callconv::FnAbi; -use super::{permute, pmaddbw, psadbw, pshufb}; +use super::{permute, pmaddbw, pmaddwd, psadbw, pshufb}; use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} @@ -88,6 +88,15 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { psadbw(this, left, right, dest)? } + // Used to implement the _mm512_madd_epi16 function. + "pmaddw.d.512" => { + this.expect_target_feature_for_intrinsic(link_name, "avx512bw")?; + + let [left, right] = + this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + + pmaddwd(this, left, right, dest)?; + } // Used to implement the _mm512_maddubs_epi16 function. "pmaddubs.w.512" => { let [left, right] = diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index a5164cc87ab4..dc0d8d48ac9b 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -964,6 +964,52 @@ fn psadbw<'tcx>( interp_ok(()) } +/// Multiply packed signed 16-bit integers in `left` and `right`, producing intermediate signed 32-bit integers. +/// Horizontally add adjacent pairs of intermediate 32-bit integers, and pack the results in `dest`. +/// +/// +/// +/// +fn pmaddwd<'tcx>( + ecx: &mut crate::MiriInterpCx<'tcx>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, +) -> InterpResult<'tcx, ()> { + let (left, left_len) = ecx.project_to_simd(left)?; + let (right, right_len) = ecx.project_to_simd(right)?; + let (dest, dest_len) = ecx.project_to_simd(dest)?; + + // fn pmaddwd(a: i16x8, b: i16x8) -> i32x4; + // fn pmaddwd(a: i16x16, b: i16x16) -> i32x8; + // fn vpmaddwd(a: i16x32, b: i16x32) -> i32x16; + assert_eq!(left_len, right_len); + assert_eq!(dest_len.strict_mul(2), left_len); + + for i in 0..dest_len { + let j1 = i.strict_mul(2); + let left1 = ecx.read_scalar(&ecx.project_index(&left, j1)?)?.to_i16()?; + let right1 = ecx.read_scalar(&ecx.project_index(&right, j1)?)?.to_i16()?; + + let j2 = j1.strict_add(1); + let left2 = ecx.read_scalar(&ecx.project_index(&left, j2)?)?.to_i16()?; + let right2 = ecx.read_scalar(&ecx.project_index(&right, j2)?)?.to_i16()?; + + let dest = ecx.project_index(&dest, i)?; + + // Multiplications are i16*i16->i32, which will not overflow. + let mul1 = i32::from(left1).strict_mul(right1.into()); + let mul2 = i32::from(left2).strict_mul(right2.into()); + // However, this addition can overflow in the most extreme case + // (-0x8000)*(-0x8000)+(-0x8000)*(-0x8000) = 0x80000000 + let res = mul1.wrapping_add(mul2); + + ecx.write_scalar(Scalar::from_i32(res), &dest)?; + } + + interp_ok(()) +} + /// Multiplies packed 8-bit unsigned integers from `left` and packed /// signed 8-bit integers from `right` into 16-bit signed integers. Then, /// the saturating sum of the products with indices `2*i` and `2*i+1` diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs index 3fbab9ba789e..f712814a5eda 100644 --- a/src/tools/miri/src/shims/x86/sse2.rs +++ b/src/tools/miri/src/shims/x86/sse2.rs @@ -6,7 +6,7 @@ use rustc_target::callconv::FnAbi; use super::{ FloatBinOp, ShiftOp, bin_op_simd_float_all, bin_op_simd_float_first, convert_float_to_int, - packssdw, packsswb, packuswb, psadbw, shift_simd_by_scalar, + packssdw, packsswb, packuswb, pmaddwd, psadbw, shift_simd_by_scalar, }; use crate::*; @@ -286,33 +286,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [left, right] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let (left, left_len) = this.project_to_simd(left)?; - let (right, right_len) = this.project_to_simd(right)?; - let (dest, dest_len) = this.project_to_simd(dest)?; - - assert_eq!(left_len, right_len); - assert_eq!(dest_len.strict_mul(2), left_len); - - for i in 0..dest_len { - let j1 = i.strict_mul(2); - let left1 = this.read_scalar(&this.project_index(&left, j1)?)?.to_i16()?; - let right1 = this.read_scalar(&this.project_index(&right, j1)?)?.to_i16()?; - - let j2 = j1.strict_add(1); - let left2 = this.read_scalar(&this.project_index(&left, j2)?)?.to_i16()?; - let right2 = this.read_scalar(&this.project_index(&right, j2)?)?.to_i16()?; - - let dest = this.project_index(&dest, i)?; - - // Multiplications are i16*i16->i32, which will not overflow. - let mul1 = i32::from(left1).strict_mul(right1.into()); - let mul2 = i32::from(left2).strict_mul(right2.into()); - // However, this addition can overflow in the most extreme case - // (-0x8000)*(-0x8000)+(-0x8000)*(-0x8000) = 0x80000000 - let res = mul1.wrapping_add(mul2); - - this.write_scalar(Scalar::from_i32(res), &dest)?; - } + pmaddwd(this, left, right, dest)?; } _ => return interp_ok(EmulateItemResult::NotSupported), } diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs index 42acb6c3fb37..7cc554ef5a3c 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs @@ -100,6 +100,77 @@ unsafe fn test_avx512() { } test_mm512_maddubs_epi16(); + #[target_feature(enable = "avx512bw")] + unsafe fn test_mm512_madd_epi16() { + // Input pairs + // + // - `i16::MIN * i16::MIN + i16::MIN * i16::MIN`: the 32-bit addition overflows + // - `i16::MAX * i16::MAX + i16::MAX * i16::MAX`: check that widening happens before + // arithmetic + // - `i16::MIN * i16::MAX + i16::MAX * i16::MIN`: check that large negative values are + // handled correctly + // - `3 * 1 + 4 * 2`: A sanity check, the result should be 14. + + #[rustfmt::skip] + let a = _mm512_set_epi16( + i16::MIN, i16::MIN, + i16::MAX, i16::MAX, + i16::MIN, i16::MAX, + 3, 1, + + i16::MIN, i16::MIN, + i16::MAX, i16::MAX, + i16::MIN, i16::MAX, + 3, 1, + + i16::MIN, i16::MIN, + i16::MAX, i16::MAX, + i16::MIN, i16::MAX, + 3, 1, + + i16::MIN, i16::MIN, + i16::MAX, i16::MAX, + i16::MIN, i16::MAX, + 3, 1, + ); + + #[rustfmt::skip] + let b = _mm512_set_epi16( + i16::MIN, i16::MIN, + i16::MAX, i16::MAX, + i16::MAX, i16::MIN, + 4, 2, + + i16::MIN, i16::MIN, + i16::MAX, i16::MAX, + i16::MAX, i16::MIN, + 4, 2, + + i16::MIN, i16::MIN, + i16::MAX, i16::MAX, + i16::MAX, i16::MIN, + 4, 2, + + i16::MIN, i16::MIN, + i16::MAX, i16::MAX, + i16::MAX, i16::MIN, + 4, 2, + ); + + let r = _mm512_madd_epi16(a, b); + + #[rustfmt::skip] + let e = _mm512_set_epi32( + i32::MIN, 2_147_352_578, -2_147_418_112, 14, + i32::MIN, 2_147_352_578, -2_147_418_112, 14, + i32::MIN, 2_147_352_578, -2_147_418_112, 14, + i32::MIN, 2_147_352_578, -2_147_418_112, 14, + ); + + assert_eq_m512i(r, e); + } + test_mm512_madd_epi16(); + #[target_feature(enable = "avx512f")] unsafe fn test_mm512_permutexvar_epi32() { let a = _mm512_set_epi32( From 93f2e80f4a885dd4eacce00e7a52aeeb41b7ce70 Mon Sep 17 00:00:00 2001 From: Farid Zakaria Date: Wed, 7 Jan 2026 11:25:17 -0800 Subject: [PATCH 0362/1061] Add -Z large-data-threshold This flag allows specifying the threshold size for placing static data in large data sections when using the medium code model on x86-64. When using -Ccode-model=medium, data smaller than this threshold uses RIP-relative addressing (32-bit offsets), while larger data uses absolute 64-bit addressing. This allows the compiler to generate more efficient code for smaller data while still supporting data larger than 2GB. This mirrors the -mlarge-data-threshold flag available in GCC and Clang. The default threshold is 65536 bytes (64KB) if not specified, matching LLVM's default behavior. --- .../src/back/owned_target_machine.rs | 2 + compiler/rustc_codegen_llvm/src/back/write.rs | 3 + compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 + .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 7 +- compiler/rustc_session/src/options.rs | 3 + .../compiler-flags/large-data-threshold.md | 27 +++++++ tests/assembly-llvm/large_data_threshold.rs | 73 +++++++++++++++++++ 7 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 src/doc/unstable-book/src/compiler-flags/large-data-threshold.md create mode 100644 tests/assembly-llvm/large_data_threshold.rs diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs index f88932d43d2a..65cf4cad24bd 100644 --- a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs +++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs @@ -39,6 +39,7 @@ impl OwnedTargetMachine { debug_info_compression: llvm::CompressionKind, use_emulated_tls: bool, use_wasm_eh: bool, + large_data_threshold: u64, ) -> Result> { // SAFETY: llvm::LLVMRustCreateTargetMachine copies pointed to data let tm_ptr = unsafe { @@ -65,6 +66,7 @@ impl OwnedTargetMachine { debug_info_compression, use_emulated_tls, use_wasm_eh, + large_data_threshold, ) }; diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index bcadb6f0de92..6c29d0470766 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -272,6 +272,8 @@ pub(crate) fn target_machine_factory( let use_wasm_eh = wants_wasm_eh(sess); + let large_data_threshold = sess.opts.unstable_opts.large_data_threshold.unwrap_or(0); + let prof = SelfProfilerRef::clone(&sess.prof); Arc::new(move |config: TargetMachineFactoryConfig| { // Self-profile timer for invoking a factory to create a target machine. @@ -313,6 +315,7 @@ pub(crate) fn target_machine_factory( debuginfo_compression, use_emulated_tls, use_wasm_eh, + large_data_threshold, ) }) } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index a90013801c8c..70fc62d08d5c 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2338,6 +2338,7 @@ unsafe extern "C" { DebugInfoCompression: CompressionKind, UseEmulatedTls: bool, UseWasmEH: bool, + LargeDataThreshold: u64, ) -> *mut TargetMachine; pub(crate) fn LLVMRustAddLibraryInfo<'a>( diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 733f5fd0df0a..97f95ac01e86 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -305,7 +305,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( bool EmitStackSizeSection, bool RelaxELFRelocations, bool UseInitArray, const char *SplitDwarfFile, const char *OutputObjFile, LLVMRustCompressionKind DebugInfoCompression, bool UseEmulatedTls, - bool UseWasmEH) { + bool UseWasmEH, uint64_t LargeDataThreshold) { auto OptLevel = fromRust(RustOptLevel); auto RM = fromRust(RustReloc); @@ -381,6 +381,11 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( TargetMachine *TM = TheTarget->createTargetMachine( Trip.getTriple(), CPU, Feature, Options, RM, CM, OptLevel); #endif + + if (LargeDataThreshold != 0) { + TM->setLargeDataThreshold(LargeDataThreshold); + } + return wrap(TM); } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 21fa3321a30a..0bdca21ff644 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2444,6 +2444,9 @@ options! { `=skip-entry` `=skip-exit` Multiple options can be combined with commas."), + large_data_threshold: Option = (None, parse_opt_number, [TRACKED], + "set the threshold for objects to be stored in a \"large data\" section \ + (only effective with -Ccode-model=medium, default: 65536)"), layout_seed: Option = (None, parse_opt_number, [TRACKED], "seed layout randomization"), link_directives: bool = (true, parse_bool, [TRACKED], diff --git a/src/doc/unstable-book/src/compiler-flags/large-data-threshold.md b/src/doc/unstable-book/src/compiler-flags/large-data-threshold.md new file mode 100644 index 000000000000..27c86079a6c8 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/large-data-threshold.md @@ -0,0 +1,27 @@ +# `large-data-threshold` + +----------------------- + +This flag controls the threshold for static data to be placed in large data +sections when using the `medium` code model on x86-64. + +When using `-Ccode-model=medium`, static data smaller than this threshold will +use RIP-relative addressing (32-bit offsets), while larger data will use +absolute 64-bit addressing. This allows the compiler to generate more efficient +code for smaller data while still supporting data larger than 2GB. + +The default threshold is 65536 bytes (64KB) if not specified. + +## Example + +```sh +rustc -Ccode-model=medium -Zlarge-data-threshold=1024 main.rs +``` + +This sets the threshold to 1KB, meaning only data smaller than 1024 bytes will +use RIP-relative addressing. + +## Platform Support + +This flag is only effective on x86-64 targets when using `-Ccode-model=medium`. +On other architectures or with other code models, this flag has no effect. diff --git a/tests/assembly-llvm/large_data_threshold.rs b/tests/assembly-llvm/large_data_threshold.rs new file mode 100644 index 000000000000..f3b37eb7f83d --- /dev/null +++ b/tests/assembly-llvm/large_data_threshold.rs @@ -0,0 +1,73 @@ +// Test for -Z large_data_threshold=... +// This test verifies that with the medium code model, data above the threshold +// is placed in large data sections (.ldata, .lbss, .lrodata). +//@ assembly-output: emit-asm +//@ compile-flags: -Ccode-model=medium -Zlarge-data-threshold=4 +//@ compile-flags: --target=x86_64-unknown-linux-gnu +//@ needs-llvm-components: x86 + +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + +#[lang = "sized"] +pub trait Sized: MetaSized {} + +#[lang = "drop_in_place"] +fn drop_in_place(_: *mut T) {} + +#[used] +#[no_mangle] +// U is below the threshold, should be in .data +static mut U: u16 = 123; + +#[used] +#[no_mangle] +// V is below the threshold, should be in .bss +static mut V: u16 = 0; + +#[used] +#[no_mangle] +// W is at the threshold, should be in .data +static mut W: u32 = 123; + +#[used] +#[no_mangle] +// X is at the threshold, should be in .bss +static mut X: u32 = 0; + +#[used] +#[no_mangle] +// Y is over the threshold, should be in .ldata +static mut Y: u64 = 123; + +#[used] +#[no_mangle] +// Z is over the threshold, should be in .lbss +static mut Z: u64 = 0; + +// CHECK: .section .data.U, +// CHECK-NOT: .section +// CHECK: U: +// CHECK: .section .bss.V, +// CHECK-NOT: .section +// CHECK: V: +// CHECK: .section .data.W, +// CHECK-NOT: .section +// CHECK: W: +// CHECK: .section .bss.X, +// CHECK-NOT: .section +// CHECK: X: +// CHECK: .section .ldata.Y, +// CHECK-NOT: .section +// CHECK: Y: +// CHECK: .section .lbss.Z, +// CHECK-NOT: .section +// CHECK: Z: From f82dd820a51b5b7ea20b257bce7d891269e2d2e6 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Wed, 7 Jan 2026 22:31:33 +0200 Subject: [PATCH 0363/1061] Use `rand` crate more idiomatically --- library/alloctests/benches/btree/map.rs | 4 +++- library/alloctests/tests/sort/patterns.rs | 15 +++++++-------- library/coretests/benches/num/int_bits/mod.rs | 7 ++++--- library/coretests/benches/num/int_sqrt/mod.rs | 17 +++++++++++------ 4 files changed, 25 insertions(+), 18 deletions(-) diff --git a/library/alloctests/benches/btree/map.rs b/library/alloctests/benches/btree/map.rs index 778065fd9657..c2bf43caf131 100644 --- a/library/alloctests/benches/btree/map.rs +++ b/library/alloctests/benches/btree/map.rs @@ -2,6 +2,7 @@ use std::collections::BTreeMap; use std::ops::RangeBounds; use rand::Rng; +use rand::distr::{Distribution, Uniform}; use rand::seq::SliceRandom; use test::{Bencher, black_box}; @@ -106,7 +107,8 @@ macro_rules! map_find_rand_bench { // setup let mut rng = crate::bench_rng(); - let mut keys: Vec<_> = (0..n).map(|_| rng.random::() % n).collect(); + let mut keys: Vec<_> = + Uniform::new(0, n).unwrap().sample_iter(&mut rng).take(n as usize).collect(); for &k in &keys { map.insert(k, k); diff --git a/library/alloctests/tests/sort/patterns.rs b/library/alloctests/tests/sort/patterns.rs index 0f1ec664d3d4..1ed645cf99dc 100644 --- a/library/alloctests/tests/sort/patterns.rs +++ b/library/alloctests/tests/sort/patterns.rs @@ -27,21 +27,20 @@ where { // :.:.:.:: - let mut rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); + let rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); // Abstracting over ranges in Rust :( let dist = Uniform::try_from(range).unwrap(); - (0..len).map(|_| dist.sample(&mut rng)).collect() + rng.sample_iter(dist).take(len).collect() } pub fn random_zipf(len: usize, exponent: f64) -> Vec { // https://en.wikipedia.org/wiki/Zipf's_law - let mut rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); + let rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); - // Abstracting over ranges in Rust :( let dist = ZipfDistribution::new(len, exponent).unwrap(); - (0..len).map(|_| dist.sample(&mut rng) as i32).collect() + rng.sample_iter(dist).map(|val| val as i32).take(len).collect() } pub fn random_sorted(len: usize, sorted_percent: f64) -> Vec { @@ -68,7 +67,7 @@ pub fn all_equal(len: usize) -> Vec { // ...... // :::::: - (0..len).map(|_| 66).collect::>() + vec![66; len] } pub fn ascending(len: usize) -> Vec { @@ -206,6 +205,6 @@ fn rand_root_seed() -> u64 { } fn random_vec(len: usize) -> Vec { - let mut rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); - (0..len).map(|_| rng.random::()).collect() + let rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); + rng.random_iter().take(len).collect() } diff --git a/library/coretests/benches/num/int_bits/mod.rs b/library/coretests/benches/num/int_bits/mod.rs index 43531b0b5de9..c6ec51f248ba 100644 --- a/library/coretests/benches/num/int_bits/mod.rs +++ b/library/coretests/benches/num/int_bits/mod.rs @@ -4,11 +4,12 @@ macro_rules! bench_template { ($op:path, $name:ident, $mask:expr) => { #[bench] fn $name(bench: &mut ::test::Bencher) { - use ::rand::Rng; + use ::rand::distr::{Distribution, Uniform}; let mut rng = crate::bench_rng(); let mut dst = vec![0; ITERATIONS]; - let src1: Vec = (0..ITERATIONS).map(|_| rng.random_range(0..=U::MAX)).collect(); - let mut src2: Vec = (0..ITERATIONS).map(|_| rng.random_range(0..=U::MAX)).collect(); + let distr = &Uniform::try_from(0..=U::MAX).unwrap(); + let src1: Vec = distr.sample_iter(&mut rng).take(ITERATIONS).collect(); + let mut src2: Vec = distr.sample_iter(&mut rng).take(ITERATIONS).collect(); // Fix the loop invariant mask src2[0] = U::MAX / 3; let dst = dst.first_chunk_mut().unwrap(); diff --git a/library/coretests/benches/num/int_sqrt/mod.rs b/library/coretests/benches/num/int_sqrt/mod.rs index 05cb3c5383b2..56172f71dd88 100644 --- a/library/coretests/benches/num/int_sqrt/mod.rs +++ b/library/coretests/benches/num/int_sqrt/mod.rs @@ -1,3 +1,5 @@ +use std::iter; + use rand::Rng; use test::{Bencher, black_box}; @@ -20,7 +22,9 @@ macro_rules! int_sqrt_bench { let mut rng = crate::bench_rng(); /* Exponentially distributed random numbers from the whole range of the type. */ let numbers: Vec<$t> = - (0..256).map(|_| rng.random::<$t>() >> rng.random_range(0..<$t>::BITS)).collect(); + iter::repeat_with(|| rng.random::<$t>() >> rng.random_range(0..<$t>::BITS)) + .take(256) + .collect(); bench.iter(|| { for x in &numbers { black_box(black_box(x).isqrt()); @@ -32,9 +36,10 @@ macro_rules! int_sqrt_bench { fn $random_small(bench: &mut Bencher) { let mut rng = crate::bench_rng(); /* Exponentially distributed random numbers from the range 0..256. */ - let numbers: Vec<$t> = (0..256) - .map(|_| (rng.random::() >> rng.random_range(0..u8::BITS)) as $t) - .collect(); + let numbers: Vec<$t> = + iter::repeat_with(|| (rng.random::() >> rng.random_range(0..u8::BITS)) as $t) + .take(256) + .collect(); bench.iter(|| { for x in &numbers { black_box(black_box(x).isqrt()); @@ -44,9 +49,9 @@ macro_rules! int_sqrt_bench { #[bench] fn $random_uniform(bench: &mut Bencher) { - let mut rng = crate::bench_rng(); + let rng = crate::bench_rng(); /* Exponentially distributed random numbers from the whole range of the type. */ - let numbers: Vec<$t> = (0..256).map(|_| rng.random::<$t>()).collect(); + let numbers: Vec<$t> = rng.random_iter().take(256).collect(); bench.iter(|| { for x in &numbers { black_box(black_box(x).isqrt()); From 138cc27f490aac4f98325a27853c3b0d7d25ae77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 7 Jan 2026 22:45:41 +0100 Subject: [PATCH 0364/1061] Update bors e-mail lookup --- .github/workflows/post-merge.yml | 2 +- src/build_helper/src/git.rs | 24 ++++++++++++++++++++++-- src/stage0 | 2 +- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/.github/workflows/post-merge.yml b/.github/workflows/post-merge.yml index d38cc0e8a17f..51e0a40d46f2 100644 --- a/.github/workflows/post-merge.yml +++ b/.github/workflows/post-merge.yml @@ -29,7 +29,7 @@ jobs: sleep 60 # Get closest bors merge commit - PARENT_COMMIT=`git rev-list --author='bors ' -n1 --first-parent HEAD^1` + PARENT_COMMIT=`git rev-list --author='122020455+rust-bors\[bot\]@users.noreply.github.com' -n1 --first-parent HEAD^1` echo "Parent: ${PARENT_COMMIT}" # Find PR for the current commit diff --git a/src/build_helper/src/git.rs b/src/build_helper/src/git.rs index 42d9b00f004a..1fdc2ddb4cfc 100644 --- a/src/build_helper/src/git.rs +++ b/src/build_helper/src/git.rs @@ -152,6 +152,14 @@ pub fn has_changed_since(git_dir: &Path, base: &str, paths: &[&str]) -> bool { }) } +const LEGACY_BORS_EMAIL: &str = "bors@rust-lang.org"; + +/// Escape characters from the git user e-mail, so that git commands do not interpret it as regex +/// special characters. +fn escape_email_git_regex(text: &str) -> String { + text.replace("[", "\\[").replace("]", "\\]").replace(".", "\\.") +} + /// Returns the latest upstream commit that modified `target_paths`, or `None` if no such commit /// was found. fn get_latest_upstream_commit_that_modified_files( @@ -182,9 +190,15 @@ fn get_latest_upstream_commit_that_modified_files( "-n1", &upstream, "--author", - git_config.git_merge_commit_email, + &escape_email_git_regex(git_config.git_merge_commit_email), ]); + // Also search for legacy bors account, before we accrue enough commits to + // have changes to all relevant file paths done by new bors. + if git_config.git_merge_commit_email != LEGACY_BORS_EMAIL { + git.args(["--author", LEGACY_BORS_EMAIL]); + } + if !target_paths.is_empty() { git.arg("--").args(target_paths); } @@ -229,11 +243,17 @@ pub fn get_closest_upstream_commit( git.args([ "rev-list", "--author-date-order", - &format!("--author={}", config.git_merge_commit_email), + &format!("--author={}", &escape_email_git_regex(config.git_merge_commit_email),), "-n1", base, ]); + // Also search for legacy bors account, before we accrue enough commits to + // have changes to all relevant file paths done by new bors. + if config.git_merge_commit_email != LEGACY_BORS_EMAIL { + git.args(["--author", LEGACY_BORS_EMAIL]); + } + let output = output_result(&mut git)?.trim().to_owned(); if output.is_empty() { Ok(None) } else { Ok(Some(output)) } } diff --git a/src/stage0 b/src/stage0 index 66b652a844f3..226f1d6f645e 100644 --- a/src/stage0 +++ b/src/stage0 @@ -1,7 +1,7 @@ dist_server=https://static.rust-lang.org artifacts_server=https://ci-artifacts.rust-lang.org/rustc-builds artifacts_with_llvm_assertions_server=https://ci-artifacts.rust-lang.org/rustc-builds-alt -git_merge_commit_email=bors@rust-lang.org +git_merge_commit_email=122020455+rust-bors[bot]@users.noreply.github.com nightly_branch=main # The configuration above this comment is editable, and can be changed From f2d0d52c2fe5c6719480b422578038000fcfa00a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 7 Jan 2026 22:50:35 +0100 Subject: [PATCH 0365/1061] Remove unused environment variable Its last use was removed in https://github.com/rust-lang/rust/pull/142827. --- src/ci/docker/run.sh | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index 044f5a8fff32..691b8b8deb81 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -312,16 +312,6 @@ else command=(/checkout/src/ci/run.sh) fi -if isCI; then - # Get some needed information for $BASE_COMMIT - # - # This command gets the last merge commit which we'll use as base to list - # deleted files since then. - BASE_COMMIT="$(git log --author=bors@rust-lang.org -n 2 --pretty=format:%H | tail -n 1)" -else - BASE_COMMIT="" -fi - SUMMARY_FILE=github-summary.md touch $objdir/${SUMMARY_FILE} @@ -359,7 +349,6 @@ docker \ --env RUST_CI_OVERRIDE_RELEASE_CHANNEL \ --env CI_JOB_NAME="${CI_JOB_NAME-$image}" \ --env CI_JOB_DOC_URL="${CI_JOB_DOC_URL}" \ - --env BASE_COMMIT="$BASE_COMMIT" \ --env DIST_TRY_BUILD \ --env PR_CI_JOB \ --env OBJDIR_ON_HOST="$objdir" \ From 0db25dbd9dfef774e4dcc2a00e37674b5bac87de Mon Sep 17 00:00:00 2001 From: yanglsh Date: Wed, 24 Sep 2025 08:53:48 +0800 Subject: [PATCH 0366/1061] fix: `map_unwrap_or` suggests wrongly for empty slice --- clippy_lints/src/derivable_impls.rs | 2 +- clippy_lints/src/methods/map_unwrap_or.rs | 231 ++++++++++-------- .../src/methods/map_unwrap_or_else.rs | 81 +++--- tests/ui/map_unwrap_or.rs | 8 + tests/ui/map_unwrap_or.stderr | 8 +- tests/ui/map_unwrap_or_fixable.fixed | 6 +- tests/ui/map_unwrap_or_fixable.rs | 6 +- tests/ui/map_unwrap_or_fixable.stderr | 46 ++-- 8 files changed, 211 insertions(+), 177 deletions(-) diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index 6b8a6aec92fa..992ed320ce68 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -105,7 +105,7 @@ fn check_struct<'tcx>( if let TyKind::Path(QPath::Resolved(_, p)) = self_ty.kind && let Some(PathSegment { args, .. }) = p.segments.last() { - let args = args.map(|a| a.args).unwrap_or(&[]); + let args = args.map(|a| a.args).unwrap_or_default(); // ty_args contains the generic parameters of the type declaration, while args contains the // arguments used at instantiation time. If both len are not equal, it means that some diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index f2e3cc5c0091..ac2f99180486 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::res::MaybeDef; +use clippy_utils::res::{MaybeDef as _, MaybeResPath as _}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_copy; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::intravisit::{Visitor, walk_path}; -use rustc_hir::{ExprKind, HirId, Node, PatKind, Path, QPath}; +use rustc_hir::intravisit::{Visitor, walk_expr, walk_path}; +use rustc_hir::{ExprKind, HirId, LangItem, Node, PatKind, Path, QPath}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_span::{Span, sym}; @@ -28,116 +28,131 @@ pub(super) fn check<'tcx>( msrv: Msrv, ) { let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs(); - let is_option = recv_ty.is_diag_item(cx, sym::Option); - let is_result = recv_ty.is_diag_item(cx, sym::Result); + let recv_ty_kind = match recv_ty.opt_diag_name(cx) { + Some(sym::Option) => sym::Option, + Some(sym::Result) if msrv.meets(cx, msrvs::RESULT_MAP_OR) => sym::Result, + _ => return, + }; - if is_result && !msrv.meets(cx, msrvs::RESULT_MAP_OR) { + let unwrap_arg_ty = cx.typeck_results().expr_ty(unwrap_arg); + if !is_copy(cx, unwrap_arg_ty) { + // Replacing `.map().unwrap_or()` with `.map_or(, )` can sometimes lead to + // borrowck errors, see #10579 for one such instance. + // In particular, if `a` causes a move and `f` references that moved binding, then we cannot lint: + // ``` + // let x = vec![1, 2]; + // x.get(0..1).map(|s| s.to_vec()).unwrap_or(x); + // ``` + // This compiles, but changing it to `map_or` will produce a compile error: + // ``` + // let x = vec![1, 2]; + // x.get(0..1).map_or(x, |s| s.to_vec()) + // ^ moving `x` here + // ^^^^^^^^^^^ while it is borrowed here (and later used in the closure) + // ``` + // So, we have to check that `a` is not referenced anywhere (even outside of the `.map` closure!) + // before the call to `unwrap_or`. + + let mut unwrap_visitor = UnwrapVisitor { + cx, + identifiers: FxHashSet::default(), + }; + unwrap_visitor.visit_expr(unwrap_arg); + + let mut reference_visitor = ReferenceVisitor { + cx, + identifiers: unwrap_visitor.identifiers, + unwrap_or_span: unwrap_arg.span, + }; + + let body = cx.tcx.hir_body_owned_by(cx.tcx.hir_enclosing_body_owner(expr.hir_id)); + + // Visit the body, and return if we've found a reference + if reference_visitor.visit_body(body).is_break() { + return; + } + } + + if !unwrap_arg.span.eq_ctxt(map_span) { return; } - // lint if the caller of `map()` is an `Option` - if is_option || is_result { - if !is_copy(cx, cx.typeck_results().expr_ty(unwrap_arg)) { - // Replacing `.map().unwrap_or()` with `.map_or(, )` can sometimes lead to - // borrowck errors, see #10579 for one such instance. - // In particular, if `a` causes a move and `f` references that moved binding, then we cannot lint: - // ``` - // let x = vec![1, 2]; - // x.get(0..1).map(|s| s.to_vec()).unwrap_or(x); - // ``` - // This compiles, but changing it to `map_or` will produce a compile error: - // ``` - // let x = vec![1, 2]; - // x.get(0..1).map_or(x, |s| s.to_vec()) - // ^ moving `x` here - // ^^^^^^^^^^^ while it is borrowed here (and later used in the closure) - // ``` - // So, we have to check that `a` is not referenced anywhere (even outside of the `.map` closure!) - // before the call to `unwrap_or`. + let mut applicability = Applicability::MachineApplicable; + // get snippet for unwrap_or() + let unwrap_snippet = snippet_with_applicability(cx, unwrap_arg.span, "..", &mut applicability); + // lint message - let mut unwrap_visitor = UnwrapVisitor { - cx, - identifiers: FxHashSet::default(), - }; - unwrap_visitor.visit_expr(unwrap_arg); - - let mut reference_visitor = ReferenceVisitor { - cx, - identifiers: unwrap_visitor.identifiers, - unwrap_or_span: unwrap_arg.span, - }; - - let body = cx.tcx.hir_body_owned_by(cx.tcx.hir_enclosing_body_owner(expr.hir_id)); - - // Visit the body, and return if we've found a reference - if reference_visitor.visit_body(body).is_break() { - return; - } - } - - if !unwrap_arg.span.eq_ctxt(map_span) { - return; - } - - // is_some_and is stabilised && `unwrap_or` argument is false; suggest `is_some_and` instead - let suggest_is_some_and = matches!(&unwrap_arg.kind, ExprKind::Lit(lit) - if matches!(lit.node, rustc_ast::LitKind::Bool(false))) - && msrv.meets(cx, msrvs::OPTION_RESULT_IS_VARIANT_AND); - - let mut applicability = Applicability::MachineApplicable; - // get snippet for unwrap_or() - let unwrap_snippet = snippet_with_applicability(cx, unwrap_arg.span, "..", &mut applicability); - // lint message - // comparing the snippet from source to raw text ("None") below is safe - // because we already have checked the type. - let unwrap_snippet_none = is_option && unwrap_snippet == "None"; - let arg = if unwrap_snippet_none { - "None" - } else if suggest_is_some_and { - "false" - } else { - "" - }; - let suggest = if unwrap_snippet_none { - "and_then()" - } else if suggest_is_some_and { - if is_result { - "is_ok_and()" - } else { - "is_some_and()" - } - } else { - "map_or(, )" - }; - let msg = format!( - "called `map().unwrap_or({arg})` on an `{}` value", - if is_option { "Option" } else { "Result" } - ); - - span_lint_and_then(cx, MAP_UNWRAP_OR, expr.span, msg, |diag| { - let map_arg_span = map_arg.span; - - let mut suggestion = vec![ - ( - map_span, - String::from(if unwrap_snippet_none { - "and_then" - } else if suggest_is_some_and { - if is_result { "is_ok_and" } else { "is_some_and" } - } else { - "map_or" - }), - ), - (expr.span.with_lo(unwrap_recv.span.hi()), String::new()), - ]; - - if !unwrap_snippet_none && !suggest_is_some_and { - suggestion.push((map_arg_span.with_hi(map_arg_span.lo()), format!("{unwrap_snippet}, "))); - } - - diag.multipart_suggestion(format!("use `{suggest}` instead"), suggestion, applicability); - }); + let suggest_kind = if recv_ty_kind == sym::Option + && unwrap_arg + .basic_res() + .ctor_parent(cx) + .is_lang_item(cx, LangItem::OptionNone) + { + SuggestedKind::AndThen } + // is_some_and is stabilised && `unwrap_or` argument is false; suggest `is_some_and` instead + else if matches!(&unwrap_arg.kind, ExprKind::Lit(lit) + if matches!(lit.node, rustc_ast::LitKind::Bool(false))) + && msrv.meets(cx, msrvs::OPTION_RESULT_IS_VARIANT_AND) + { + SuggestedKind::IsVariantAnd + } else { + SuggestedKind::Other + }; + + let arg = match suggest_kind { + SuggestedKind::AndThen => "None", + SuggestedKind::IsVariantAnd => "false", + SuggestedKind::Other => "", + }; + + let suggest = match (suggest_kind, recv_ty_kind) { + (SuggestedKind::AndThen, _) => "and_then()", + (SuggestedKind::IsVariantAnd, sym::Result) => "is_ok_and()", + (SuggestedKind::IsVariantAnd, sym::Option) => "is_some_and()", + _ => "map_or(, )", + }; + + let msg = format!( + "called `map().unwrap_or({arg})` on {} `{recv_ty_kind}` value", + if recv_ty_kind == sym::Option { "an" } else { "a" } + ); + + span_lint_and_then(cx, MAP_UNWRAP_OR, expr.span, msg, |diag| { + let map_arg_span = map_arg.span; + + let mut suggestion = vec![ + ( + map_span, + String::from(match (suggest_kind, recv_ty_kind) { + (SuggestedKind::AndThen, _) => "and_then", + (SuggestedKind::IsVariantAnd, sym::Result) => "is_ok_and", + (SuggestedKind::IsVariantAnd, sym::Option) => "is_some_and", + (SuggestedKind::Other, _) + if unwrap_arg_ty.peel_refs().is_array() + && cx.typeck_results().expr_ty_adjusted(unwrap_arg).peel_refs().is_slice() => + { + return; + }, + _ => "map_or", + }), + ), + (expr.span.with_lo(unwrap_recv.span.hi()), String::new()), + ]; + + if matches!(suggest_kind, SuggestedKind::Other) { + suggestion.push((map_arg_span.with_hi(map_arg_span.lo()), format!("{unwrap_snippet}, "))); + } + + diag.multipart_suggestion(format!("use `{suggest}` instead"), suggestion, applicability); + }); +} + +#[derive(Clone, Copy, PartialEq, Eq)] +enum SuggestedKind { + AndThen, + IsVariantAnd, + Other, } struct UnwrapVisitor<'a, 'tcx> { @@ -186,7 +201,7 @@ impl<'tcx> Visitor<'tcx> for ReferenceVisitor<'_, 'tcx> { { return ControlFlow::Break(()); } - rustc_hir::intravisit::walk_expr(self, expr) + walk_expr(self, expr) } fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { diff --git a/clippy_lints/src/methods/map_unwrap_or_else.rs b/clippy_lints/src/methods/map_unwrap_or_else.rs index a2f157c0cb8a..8bb532b21635 100644 --- a/clippy_lints/src/methods/map_unwrap_or_else.rs +++ b/clippy_lints/src/methods/map_unwrap_or_else.rs @@ -1,18 +1,18 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::res::MaybeDef; +use clippy_utils::res::MaybeDef as _; use clippy_utils::source::snippet; +use clippy_utils::sym; use clippy_utils::usage::mutated_variables; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::symbol::sym; use super::MAP_UNWRAP_OR; /// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s /// -/// Returns true if the lint was emitted +/// Is part of the `map_unwrap_or` lint, split into separate files for readability. pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, @@ -22,49 +22,46 @@ pub(super) fn check<'tcx>( msrv: Msrv, ) -> bool { let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs(); - let is_option = recv_ty.is_diag_item(cx, sym::Option); - let is_result = recv_ty.is_diag_item(cx, sym::Result); + let recv_ty_kind = match recv_ty.opt_diag_name(cx) { + Some(sym::Option) => sym::Option, + Some(sym::Result) if msrv.meets(cx, msrvs::RESULT_MAP_OR_ELSE) => sym::Result, + _ => return false, + }; - if is_result && !msrv.meets(cx, msrvs::RESULT_MAP_OR_ELSE) { + // Don't make a suggestion that may fail to compile due to mutably borrowing + // the same variable twice. + let Some(map_mutated_vars) = mutated_variables(recv, cx) else { + return false; + }; + let Some(unwrap_mutated_vars) = mutated_variables(unwrap_arg, cx) else { + return false; + }; + if map_mutated_vars.intersection(&unwrap_mutated_vars).next().is_some() { return false; } - if is_option || is_result { - // Don't make a suggestion that may fail to compile due to mutably borrowing - // the same variable twice. - let map_mutated_vars = mutated_variables(recv, cx); - let unwrap_mutated_vars = mutated_variables(unwrap_arg, cx); - if let (Some(map_mutated_vars), Some(unwrap_mutated_vars)) = (map_mutated_vars, unwrap_mutated_vars) { - if map_mutated_vars.intersection(&unwrap_mutated_vars).next().is_some() { - return false; - } - } else { - return false; - } - - // lint message - let msg = if is_option { - "called `map().unwrap_or_else()` on an `Option` value" - } else { - "called `map().unwrap_or_else()` on a `Result` value" - }; - // get snippets for args to map() and unwrap_or_else() - let map_snippet = snippet(cx, map_arg.span, ".."); - let unwrap_snippet = snippet(cx, unwrap_arg.span, ".."); - // lint, with note if both map() and unwrap_or_else() have the same span - if map_arg.span.eq_ctxt(unwrap_arg.span) { - let var_snippet = snippet(cx, recv.span, ".."); - span_lint_and_sugg( - cx, - MAP_UNWRAP_OR, - expr.span, - msg, - "try", - format!("{var_snippet}.map_or_else({unwrap_snippet}, {map_snippet})"), - Applicability::MachineApplicable, - ); - return true; - } + // lint message + let msg = if recv_ty_kind == sym::Option { + "called `map().unwrap_or_else()` on an `Option` value" + } else { + "called `map().unwrap_or_else()` on a `Result` value" + }; + // get snippets for args to map() and unwrap_or_else() + let map_snippet = snippet(cx, map_arg.span, ".."); + let unwrap_snippet = snippet(cx, unwrap_arg.span, ".."); + // lint, with note if both map() and unwrap_or_else() have the same span + if map_arg.span.eq_ctxt(unwrap_arg.span) { + let var_snippet = snippet(cx, recv.span, ".."); + span_lint_and_sugg( + cx, + MAP_UNWRAP_OR, + expr.span, + msg, + "try", + format!("{var_snippet}.map_or_else({unwrap_snippet}, {map_snippet})"), + Applicability::MachineApplicable, + ); + return true; } false diff --git a/tests/ui/map_unwrap_or.rs b/tests/ui/map_unwrap_or.rs index fba81cb493cd..dccacd7df8af 100644 --- a/tests/ui/map_unwrap_or.rs +++ b/tests/ui/map_unwrap_or.rs @@ -156,3 +156,11 @@ mod issue_10579 { println!("{y:?}"); } } + +fn issue15752() { + struct Foo<'a>(&'a [u32]); + + let x = Some(Foo(&[1, 2, 3])); + x.map(|y| y.0).unwrap_or(&[]); + //~^ map_unwrap_or +} diff --git a/tests/ui/map_unwrap_or.stderr b/tests/ui/map_unwrap_or.stderr index df0207c420e6..bd9e0eeb0bda 100644 --- a/tests/ui/map_unwrap_or.stderr +++ b/tests/ui/map_unwrap_or.stderr @@ -232,5 +232,11 @@ LL - let _ = opt.map(|x| x > 5).unwrap_or(false); LL + let _ = opt.is_some_and(|x| x > 5); | -error: aborting due to 15 previous errors +error: called `map().unwrap_or()` on an `Option` value + --> tests/ui/map_unwrap_or.rs:164:5 + | +LL | x.map(|y| y.0).unwrap_or(&[]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 16 previous errors diff --git a/tests/ui/map_unwrap_or_fixable.fixed b/tests/ui/map_unwrap_or_fixable.fixed index 1789c7f4d487..dca2536132d7 100644 --- a/tests/ui/map_unwrap_or_fixable.fixed +++ b/tests/ui/map_unwrap_or_fixable.fixed @@ -1,7 +1,11 @@ //@aux-build:option_helpers.rs #![warn(clippy::map_unwrap_or)] -#![allow(clippy::unnecessary_lazy_evaluations)] +#![allow( + clippy::unnecessary_lazy_evaluations, + clippy::manual_is_variant_and, + clippy::unnecessary_map_or +)] #[macro_use] extern crate option_helpers; diff --git a/tests/ui/map_unwrap_or_fixable.rs b/tests/ui/map_unwrap_or_fixable.rs index 309067edce4d..c60cb082ae3c 100644 --- a/tests/ui/map_unwrap_or_fixable.rs +++ b/tests/ui/map_unwrap_or_fixable.rs @@ -1,7 +1,11 @@ //@aux-build:option_helpers.rs #![warn(clippy::map_unwrap_or)] -#![allow(clippy::unnecessary_lazy_evaluations)] +#![allow( + clippy::unnecessary_lazy_evaluations, + clippy::manual_is_variant_and, + clippy::unnecessary_map_or +)] #[macro_use] extern crate option_helpers; diff --git a/tests/ui/map_unwrap_or_fixable.stderr b/tests/ui/map_unwrap_or_fixable.stderr index 696f516ee055..33a865d6769c 100644 --- a/tests/ui/map_unwrap_or_fixable.stderr +++ b/tests/ui/map_unwrap_or_fixable.stderr @@ -1,5 +1,5 @@ error: called `map().unwrap_or_else()` on an `Option` value - --> tests/ui/map_unwrap_or_fixable.rs:17:13 + --> tests/ui/map_unwrap_or_fixable.rs:21:13 | LL | let _ = opt.map(|x| x + 1) | _____________^ @@ -11,7 +11,7 @@ LL | | .unwrap_or_else(|| 0); = help: to override `-D warnings` add `#[allow(clippy::map_unwrap_or)]` error: called `map().unwrap_or_else()` on a `Result` value - --> tests/ui/map_unwrap_or_fixable.rs:48:13 + --> tests/ui/map_unwrap_or_fixable.rs:52:13 | LL | let _ = res.map(|x| x + 1) | _____________^ @@ -20,7 +20,7 @@ LL | | .unwrap_or_else(|_e| 0); | |_______________________________^ help: try: `res.map_or_else(|_e| 0, |x| x + 1)` error: called `map().unwrap_or()` on an `Option` value - --> tests/ui/map_unwrap_or_fixable.rs:65:20 + --> tests/ui/map_unwrap_or_fixable.rs:69:20 | LL | println!("{}", o.map(|y| y + 1).unwrap_or(3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,13 +32,13 @@ LL + println!("{}", o.map_or(3, |y| y + 1)); | error: called `map().unwrap_or_else()` on an `Option` value - --> tests/ui/map_unwrap_or_fixable.rs:67:20 + --> tests/ui/map_unwrap_or_fixable.rs:71:20 | LL | println!("{}", o.map(|y| y + 1).unwrap_or_else(|| 3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `o.map_or_else(|| 3, |y| y + 1)` -error: called `map().unwrap_or()` on an `Result` value - --> tests/ui/map_unwrap_or_fixable.rs:69:20 +error: called `map().unwrap_or()` on a `Result` value + --> tests/ui/map_unwrap_or_fixable.rs:73:20 | LL | println!("{}", r.map(|y| y + 1).unwrap_or(3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -50,13 +50,13 @@ LL + println!("{}", r.map_or(3, |y| y + 1)); | error: called `map().unwrap_or_else()` on a `Result` value - --> tests/ui/map_unwrap_or_fixable.rs:71:20 + --> tests/ui/map_unwrap_or_fixable.rs:75:20 | LL | println!("{}", r.map(|y| y + 1).unwrap_or_else(|()| 3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `r.map_or_else(|()| 3, |y| y + 1)` -error: called `map().unwrap_or(false)` on an `Result` value - --> tests/ui/map_unwrap_or_fixable.rs:74:20 +error: called `map().unwrap_or(false)` on a `Result` value + --> tests/ui/map_unwrap_or_fixable.rs:78:20 | LL | println!("{}", r.map(|y| y == 1).unwrap_or(false)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -68,18 +68,6 @@ LL + println!("{}", r.is_ok_and(|y| y == 1)); | error: called `map().unwrap_or()` on an `Option` value - --> tests/ui/map_unwrap_or_fixable.rs:80:20 - | -LL | println!("{}", x.map(|y| y + 1).unwrap_or(3)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: use `map_or(, )` instead - | -LL - println!("{}", x.map(|y| y + 1).unwrap_or(3)); -LL + println!("{}", x.map_or(3, |y| y + 1)); - | - -error: called `map().unwrap_or()` on an `Result` value --> tests/ui/map_unwrap_or_fixable.rs:84:20 | LL | println!("{}", x.map(|y| y + 1).unwrap_or(3)); @@ -91,14 +79,26 @@ LL - println!("{}", x.map(|y| y + 1).unwrap_or(3)); LL + println!("{}", x.map_or(3, |y| y + 1)); | -error: called `map().unwrap_or_else()` on an `Option` value +error: called `map().unwrap_or()` on a `Result` value --> tests/ui/map_unwrap_or_fixable.rs:88:20 | +LL | println!("{}", x.map(|y| y + 1).unwrap_or(3)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `map_or(, )` instead + | +LL - println!("{}", x.map(|y| y + 1).unwrap_or(3)); +LL + println!("{}", x.map_or(3, |y| y + 1)); + | + +error: called `map().unwrap_or_else()` on an `Option` value + --> tests/ui/map_unwrap_or_fixable.rs:92:20 + | LL | println!("{}", x.map(|y| y + 1).unwrap_or_else(|| 3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.map_or_else(|| 3, |y| y + 1)` error: called `map().unwrap_or_else()` on a `Result` value - --> tests/ui/map_unwrap_or_fixable.rs:92:20 + --> tests/ui/map_unwrap_or_fixable.rs:96:20 | LL | println!("{}", x.map(|y| y + 1).unwrap_or_else(|_| 3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.map_or_else(|_| 3, |y| y + 1)` From ac0b17bcf94517c301d4abd9c0278ab180c3248d Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Wed, 7 Jan 2026 22:32:16 +0000 Subject: [PATCH 0367/1061] fix: `unnecessary_to_owned` wrongly unmangled macros --- .../src/methods/unnecessary_to_owned.rs | 22 +++++++++++-------- tests/ui/unnecessary_to_owned.fixed | 9 ++++++++ tests/ui/unnecessary_to_owned.rs | 9 ++++++++ tests/ui/unnecessary_to_owned.stderr | 8 ++++++- 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index a6a39cb6ab30..74e8dbc15a6c 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -3,7 +3,7 @@ use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeDef; -use clippy_utils::source::{SpanRangeExt, snippet}; +use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_context}; use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, peel_and_count_ty_refs}; use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{fn_def_id, get_parent_expr, is_expr_temporary_value, return_ty, sym}; @@ -131,8 +131,10 @@ fn check_addr_of_expr( && (*referent_ty != receiver_ty || (matches!(referent_ty.kind(), ty::Array(..)) && is_copy(cx, *referent_ty)) || is_cow_into_owned(cx, method_name, method_parent_id)) - && let Some(receiver_snippet) = receiver.span.get_source_text(cx) { + let mut applicability = Applicability::MachineApplicable; + let (receiver_snippet, _) = snippet_with_context(cx, receiver.span, expr.span.ctxt(), "..", &mut applicability); + if receiver_ty == target_ty && n_target_refs >= n_receiver_refs { span_lint_and_sugg( cx, @@ -145,7 +147,7 @@ fn check_addr_of_expr( "", width = n_target_refs - n_receiver_refs ), - Applicability::MachineApplicable, + applicability, ); return true; } @@ -165,8 +167,8 @@ fn check_addr_of_expr( parent.span, format!("unnecessary use of `{method_name}`"), "use", - receiver_snippet.to_owned(), - Applicability::MachineApplicable, + receiver_snippet.to_string(), + applicability, ); } else { span_lint_and_sugg( @@ -176,7 +178,7 @@ fn check_addr_of_expr( format!("unnecessary use of `{method_name}`"), "remove this", String::new(), - Applicability::MachineApplicable, + applicability, ); } return true; @@ -191,7 +193,7 @@ fn check_addr_of_expr( format!("unnecessary use of `{method_name}`"), "use", format!("{receiver_snippet}.as_ref()"), - Applicability::MachineApplicable, + applicability, ); return true; } @@ -409,8 +411,10 @@ fn check_other_call_arg<'tcx>( None } && can_change_type(cx, maybe_arg, receiver_ty) - && let Some(receiver_snippet) = receiver.span.get_source_text(cx) { + let mut applicability = Applicability::MachineApplicable; + let (receiver_snippet, _) = snippet_with_context(cx, receiver.span, expr.span.ctxt(), "..", &mut applicability); + span_lint_and_sugg( cx, UNNECESSARY_TO_OWNED, @@ -418,7 +422,7 @@ fn check_other_call_arg<'tcx>( format!("unnecessary use of `{method_name}`"), "use", format!("{:&>n_refs$}{receiver_snippet}", ""), - Applicability::MachineApplicable, + applicability, ); return true; } diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index 316eac0b58b7..590359bc1ad2 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -681,3 +681,12 @@ fn issue14833() { let mut s = HashSet::<&String>::new(); s.remove(&"hello".to_owned()); } + +#[allow(clippy::redundant_clone)] +fn issue16351() { + fn take(_: impl AsRef) {} + + let dot = "."; + take(&format!("ouch{dot}")); + //~^ unnecessary_to_owned +} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index f2dbd1db3c9f..d1e3e6497c0a 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -681,3 +681,12 @@ fn issue14833() { let mut s = HashSet::<&String>::new(); s.remove(&"hello".to_owned()); } + +#[allow(clippy::redundant_clone)] +fn issue16351() { + fn take(_: impl AsRef) {} + + let dot = "."; + take(format!("ouch{dot}").to_string()); + //~^ unnecessary_to_owned +} diff --git a/tests/ui/unnecessary_to_owned.stderr b/tests/ui/unnecessary_to_owned.stderr index 6c52be839301..50e3d5eb2195 100644 --- a/tests/ui/unnecessary_to_owned.stderr +++ b/tests/ui/unnecessary_to_owned.stderr @@ -550,5 +550,11 @@ error: unnecessary use of `to_vec` LL | s.remove(&(&["b"]).to_vec()); | ^^^^^^^^^^^^^^^^^^ help: replace it with: `(&["b"]).as_slice()` -error: aborting due to 82 previous errors +error: unnecessary use of `to_string` + --> tests/ui/unnecessary_to_owned.rs:690:10 + | +LL | take(format!("ouch{dot}").to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `&format!("ouch{dot}")` + +error: aborting due to 83 previous errors From 4976fdf203b5122bf3b26acf02af5ae6ea25f138 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Wed, 7 Jan 2026 23:17:33 +0000 Subject: [PATCH 0368/1061] fix: `significant_drop_tightening` suggests wrongly for non-method usage --- .../src/significant_drop_tightening.rs | 24 ++++--- tests/ui/significant_drop_tightening.fixed | 36 ++++++++++ tests/ui/significant_drop_tightening.rs | 33 +++++++++ tests/ui/significant_drop_tightening.stderr | 71 ++++++++++++++++++- 4 files changed, 152 insertions(+), 12 deletions(-) diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index fabb21f78b9e..8557e8d18d10 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -2,6 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeResPath; use clippy_utils::source::{indent_of, snippet}; use clippy_utils::{expr_or_init, get_builtin_attr, peel_hir_expr_unary, sym}; +use rustc_ast::BindingMode; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -89,13 +90,14 @@ impl<'tcx> LateLintPass<'tcx> for SignificantDropTightening<'tcx> { |diag| { match apa.counter { 0 | 1 => {}, - 2 => { + 2 if let Some(last_method_span) = apa.last_method_span => { let indent = " ".repeat(indent_of(cx, apa.last_stmt_span).unwrap_or(0)); let init_method = snippet(cx, apa.first_method_span, ".."); - let usage_method = snippet(cx, apa.last_method_span, ".."); - let stmt = if let Some(last_bind_ident) = apa.last_bind_ident { + let usage_method = snippet(cx, last_method_span, ".."); + let stmt = if let Some((binding_mode, last_bind_ident)) = apa.last_bind_ident { format!( - "\n{indent}let {} = {init_method}.{usage_method};", + "\n{indent}let {}{} = {init_method}.{usage_method};", + binding_mode.prefix_str(), snippet(cx, last_bind_ident.span, ".."), ) } else { @@ -310,13 +312,13 @@ impl<'tcx> Visitor<'tcx> for StmtsChecker<'_, '_, '_, '_, 'tcx> { }; match self.ap.curr_stmt.kind { hir::StmtKind::Let(local) => { - if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind { - apa.last_bind_ident = Some(ident); + if let hir::PatKind::Binding(binding_mode, _, ident, _) = local.pat.kind { + apa.last_bind_ident = Some((binding_mode, ident)); } if let Some(local_init) = local.init && let hir::ExprKind::MethodCall(_, _, _, span) = local_init.kind { - apa.last_method_span = span; + apa.last_method_span = Some(span); } }, hir::StmtKind::Semi(semi_expr) => { @@ -326,7 +328,7 @@ impl<'tcx> Visitor<'tcx> for StmtsChecker<'_, '_, '_, '_, 'tcx> { return; } if let hir::ExprKind::MethodCall(_, _, _, span) = semi_expr.kind { - apa.last_method_span = span; + apa.last_method_span = Some(span); } }, _ => {}, @@ -385,9 +387,9 @@ struct AuxParamsAttr { /// The last visited binding or variable span within a block that had any referenced inner type /// marked with `#[has_significant_drop]`. - last_bind_ident: Option, + last_bind_ident: Option<(BindingMode, Ident)>, /// Similar to `last_bind_span` but encompasses the right-hand method call. - last_method_span: Span, + last_method_span: Option, /// Similar to `last_bind_span` but encompasses the whole contained statement. last_stmt_span: Span, } @@ -403,7 +405,7 @@ impl Default for AuxParamsAttr { first_method_span: DUMMY_SP, first_stmt_span: DUMMY_SP, last_bind_ident: None, - last_method_span: DUMMY_SP, + last_method_span: None, last_stmt_span: DUMMY_SP, } } diff --git a/tests/ui/significant_drop_tightening.fixed b/tests/ui/significant_drop_tightening.fixed index 3d416056226c..559c1bb94570 100644 --- a/tests/ui/significant_drop_tightening.fixed +++ b/tests/ui/significant_drop_tightening.fixed @@ -146,3 +146,39 @@ pub fn unnecessary_contention_with_single_owned_results() { pub fn do_heavy_computation_that_takes_time(_: T) {} fn main() {} + +fn issue15574() { + use std::io::{BufRead, Read, stdin}; + use std::process; + + println!("Hello, what's your name?"); + + let mut stdin = stdin().lock().take(40); + //~^ significant_drop_tightening + let mut buffer = String::with_capacity(10); + + + //~^ significant_drop_tightening + if stdin.read_line(&mut buffer).is_err() { + eprintln!("An error has occured while reading."); + return; + } + drop(stdin); + println!("Our string has a capacity of {}", buffer.capacity()); + println!("Hello {}!", buffer); +} + +fn issue16343() { + fn get_items(x: &()) -> Vec<()> { + vec![*x] + } + + let storage = Mutex::new(()); + let lock = storage.lock().unwrap(); + //~^ significant_drop_tightening + let items = get_items(&lock); + drop(lock); + for item in items { + println!("item {:?}", item); + } +} diff --git a/tests/ui/significant_drop_tightening.rs b/tests/ui/significant_drop_tightening.rs index d9c4ad543593..dff36baf383d 100644 --- a/tests/ui/significant_drop_tightening.rs +++ b/tests/ui/significant_drop_tightening.rs @@ -142,3 +142,36 @@ pub fn unnecessary_contention_with_single_owned_results() { pub fn do_heavy_computation_that_takes_time(_: T) {} fn main() {} + +fn issue15574() { + use std::io::{BufRead, Read, stdin}; + use std::process; + + println!("Hello, what's your name?"); + let stdin = stdin().lock(); + //~^ significant_drop_tightening + let mut buffer = String::with_capacity(10); + + let mut stdin = stdin.take(40); + //~^ significant_drop_tightening + if stdin.read_line(&mut buffer).is_err() { + eprintln!("An error has occured while reading."); + return; + } + println!("Our string has a capacity of {}", buffer.capacity()); + println!("Hello {}!", buffer); +} + +fn issue16343() { + fn get_items(x: &()) -> Vec<()> { + vec![*x] + } + + let storage = Mutex::new(()); + let lock = storage.lock().unwrap(); + //~^ significant_drop_tightening + let items = get_items(&lock); + for item in items { + println!("item {:?}", item); + } +} diff --git a/tests/ui/significant_drop_tightening.stderr b/tests/ui/significant_drop_tightening.stderr index 25cd9da73a10..785bee4970ec 100644 --- a/tests/ui/significant_drop_tightening.stderr +++ b/tests/ui/significant_drop_tightening.stderr @@ -83,5 +83,74 @@ LL | LL ~ | -error: aborting due to 4 previous errors +error: temporary with significant `Drop` can be early dropped + --> tests/ui/significant_drop_tightening.rs:151:9 + | +LL | fn issue15574() { + | _________________- +LL | | use std::io::{BufRead, Read, stdin}; +LL | | use std::process; +... | +LL | | let stdin = stdin().lock(); + | | ^^^^^ +... | +LL | | println!("Hello {}!", buffer); +LL | | } + | |_- temporary `stdin` is currently being dropped at the end of its contained scope + | + = note: this might lead to unnecessary resource contention +help: merge the temporary construction with its single usage + | +LL ~ +LL + let mut stdin = stdin().lock().take(40); +LL | +LL | let mut buffer = String::with_capacity(10); +LL | +LL ~ + | + +error: temporary with significant `Drop` can be early dropped + --> tests/ui/significant_drop_tightening.rs:155:13 + | +LL | fn issue15574() { + | _________________- +LL | | use std::io::{BufRead, Read, stdin}; +LL | | use std::process; +... | +LL | | let mut stdin = stdin.take(40); + | | ^^^^^ +... | +LL | | println!("Hello {}!", buffer); +LL | | } + | |_- temporary `stdin` is currently being dropped at the end of its contained scope + | + = note: this might lead to unnecessary resource contention +help: drop the temporary after the end of its last usage + | +LL ~ } +LL + drop(stdin); + | + +error: temporary with significant `Drop` can be early dropped + --> tests/ui/significant_drop_tightening.rs:171:9 + | +LL | fn issue16343() { + | _________________- +LL | | fn get_items(x: &()) -> Vec<()> { +LL | | vec![*x] +... | +LL | | let lock = storage.lock().unwrap(); + | | ^^^^ +... | +LL | | } + | |_- temporary `lock` is currently being dropped at the end of its contained scope + | + = note: this might lead to unnecessary resource contention +help: drop the temporary after the end of its last usage + | +LL ~ let items = get_items(&lock); +LL + drop(lock); + | + +error: aborting due to 7 previous errors From fb9b6bd5351c3eb4f62da83c35ca1636a3523a60 Mon Sep 17 00:00:00 2001 From: hulxv Date: Wed, 17 Dec 2025 22:57:32 +0200 Subject: [PATCH 0369/1061] Refactor socketpair tests to use utility functions for reading and writing inline byte slices for data writes Refactor socketpair tests to use utility functions for reading and writing --- .../tests/pass-dep/libc/libc-socketpair.rs | 189 ++++++------------ 1 file changed, 61 insertions(+), 128 deletions(-) diff --git a/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs b/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs index ce3927ce48ca..2031149aaf4f 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs @@ -9,6 +9,7 @@ use std::thread; #[path = "../../utils/libc.rs"] mod libc_utils; +use libc_utils::*; fn main() { test_socketpair(); @@ -21,139 +22,92 @@ fn main() { fn test_socketpair() { let mut fds = [-1, -1]; - let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }; - assert_eq!(res, 0); + errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }); // Read size == data available in buffer. - let data = "abcde".as_bytes().as_ptr(); - let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) }; - assert_eq!(res, 5); - let mut buf: [u8; 5] = [0; 5]; - let res = - unsafe { libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) }; - assert_eq!(res, 5); - assert_eq!(buf, "abcde".as_bytes()); + let data = b"abcde"; + write_all_from_slice(fds[0], data).unwrap(); + let buf = read_all_into_array::<5>(fds[1]).unwrap(); + assert_eq!(&buf, data); // Read size > data available in buffer. - let data = "abc".as_bytes(); - let res = unsafe { libc_utils::write_all(fds[0], data.as_ptr() as *const libc::c_void, 3) }; - assert_eq!(res, 3); + let data = b"abc"; + write_all_from_slice(fds[0], data).unwrap(); let mut buf2: [u8; 5] = [0; 5]; - let res = unsafe { libc::read(fds[1], buf2.as_mut_ptr().cast(), buf2.len() as libc::size_t) }; - assert!(res > 0 && res <= 3); - let res = res as usize; - assert_eq!(buf2[..res], data[..res]); - if res < 3 { - // Drain the rest from the read end. - let res = unsafe { libc_utils::read_all(fds[1], buf2[res..].as_mut_ptr().cast(), 3 - res) }; - assert!(res > 0); - } + let (read, rest) = read_into_slice(fds[1], &mut buf2).unwrap(); + assert_eq!(read[..], data[..read.len()]); + // Write 2 more bytes so we can exactly fill the `rest`. + write_all_from_slice(fds[0], b"12").unwrap(); + read_all_into_slice(fds[1], rest).unwrap(); // Test read and write from another direction. // Read size == data available in buffer. - let data = "12345".as_bytes().as_ptr(); - let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) }; - assert_eq!(res, 5); - let mut buf3: [u8; 5] = [0; 5]; - let res = unsafe { - libc_utils::read_all(fds[0], buf3.as_mut_ptr().cast(), buf3.len() as libc::size_t) - }; - assert_eq!(res, 5); - assert_eq!(buf3, "12345".as_bytes()); + let data = b"12345"; + write_all_from_slice(fds[1], data).unwrap(); + let buf3 = read_all_into_array::<5>(fds[0]).unwrap(); + assert_eq!(&buf3, data); // Read size > data available in buffer. - let data = "123".as_bytes(); - let res = unsafe { libc_utils::write_all(fds[1], data.as_ptr() as *const libc::c_void, 3) }; - assert_eq!(res, 3); + let data = b"123"; + write_all_from_slice(fds[1], data).unwrap(); let mut buf4: [u8; 5] = [0; 5]; - let res = unsafe { libc::read(fds[0], buf4.as_mut_ptr().cast(), buf4.len() as libc::size_t) }; - assert!(res > 0 && res <= 3); - let res = res as usize; - assert_eq!(buf4[..res], data[..res]); - if res < 3 { - // Drain the rest from the read end. - let res = unsafe { libc_utils::read_all(fds[0], buf4[res..].as_mut_ptr().cast(), 3 - res) }; - assert!(res > 0); - } + let (read, rest) = read_into_slice(fds[0], &mut buf4).unwrap(); + assert_eq!(read[..], data[..read.len()]); + // Write 2 more bytes so we can exactly fill the `rest`. + write_all_from_slice(fds[1], b"12").unwrap(); + read_all_into_slice(fds[0], rest).unwrap(); // Test when happens when we close one end, with some data in the buffer. - let res = unsafe { libc_utils::write_all(fds[0], data.as_ptr() as *const libc::c_void, 3) }; - assert_eq!(res, 3); - unsafe { libc::close(fds[0]) }; + write_all_from_slice(fds[0], data).unwrap(); + errno_check(unsafe { libc::close(fds[0]) }); // Reading the other end should return that data, then EOF. let mut buf: [u8; 5] = [0; 5]; - let res = - unsafe { libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) }; - assert_eq!(res, 3); - assert_eq!(&buf[0..3], "123".as_bytes()); - let res = - unsafe { libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) }; + read_all_into_slice(fds[1], &mut buf[0..3]).unwrap(); + assert_eq!(&buf[0..3], data); + let res = read_into_slice(fds[1], &mut buf[3..5]).unwrap().0.len(); assert_eq!(res, 0); // 0-sized read: EOF. // Writing the other end should emit EPIPE. - let res = unsafe { libc_utils::write_all(fds[1], data.as_ptr() as *const libc::c_void, 1) }; - assert_eq!(res, -1); + let res = write_all_from_slice(fds[1], &mut buf); + assert_eq!(res, Err(-1)); assert_eq!(std::io::Error::last_os_error().raw_os_error(), Some(libc::EPIPE)); } fn test_socketpair_threaded() { let mut fds = [-1, -1]; - let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }; - assert_eq!(res, 0); + errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }); let thread1 = thread::spawn(move || { - let mut buf: [u8; 5] = [0; 5]; - let res: i64 = unsafe { - libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) - .try_into() - .unwrap() - }; - assert_eq!(res, 5); - assert_eq!(buf, "abcde".as_bytes()); + let buf = read_all_into_array::<5>(fds[1]).unwrap(); + assert_eq!(&buf, b"abcde"); }); thread::yield_now(); - let data = "abcde".as_bytes().as_ptr(); - let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) }; - assert_eq!(res, 5); + write_all_from_slice(fds[0], b"abcde").unwrap(); thread1.join().unwrap(); // Read and write from different direction let thread2 = thread::spawn(move || { thread::yield_now(); - let data = "12345".as_bytes().as_ptr(); - let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) }; - assert_eq!(res, 5); + write_all_from_slice(fds[1], b"12345").unwrap(); }); - let mut buf: [u8; 5] = [0; 5]; - let res = - unsafe { libc_utils::read_all(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) }; - assert_eq!(res, 5); - assert_eq!(buf, "12345".as_bytes()); + let buf = read_all_into_array::<5>(fds[0]).unwrap(); + assert_eq!(&buf, b"12345"); thread2.join().unwrap(); } fn test_race() { static mut VAL: u8 = 0; let mut fds = [-1, -1]; - let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }; - assert_eq!(res, 0); + errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }); let thread1 = thread::spawn(move || { - let mut buf: [u8; 1] = [0; 1]; // write() from the main thread will occur before the read() here // because preemption is disabled and the main thread yields after write(). - let res: i32 = unsafe { - libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) - .try_into() - .unwrap() - }; - assert_eq!(res, 1); - assert_eq!(buf, "a".as_bytes()); + let buf = read_all_into_array::<1>(fds[1]).unwrap(); + assert_eq!(&buf, b"a"); // The read above establishes a happens-before so it is now safe to access this global variable. unsafe { assert_eq!(VAL, 1) }; }); unsafe { VAL = 1 }; - let data = "a".as_bytes().as_ptr(); - let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 1) }; - assert_eq!(res, 1); + write_all_from_slice(fds[0], b"a").unwrap(); thread::yield_now(); thread1.join().unwrap(); } @@ -161,22 +115,15 @@ fn test_race() { // Test the behaviour of a socketpair getting blocked on read and subsequently unblocked. fn test_blocking_read() { let mut fds = [-1, -1]; - let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }; - assert_eq!(res, 0); + errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }); let thread1 = thread::spawn(move || { // Let this thread block on read. - let mut buf: [u8; 3] = [0; 3]; - let res = unsafe { - libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) - }; - assert_eq!(res, 3); - assert_eq!(&buf, "abc".as_bytes()); + let buf = read_all_into_array::<3>(fds[1]).unwrap(); + assert_eq!(&buf, b"abc"); }); let thread2 = thread::spawn(move || { // Unblock thread1 by doing writing something. - let data = "abc".as_bytes().as_ptr(); - let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 3) }; - assert_eq!(res, 3); + write_all_from_slice(fds[0], b"abc").unwrap(); }); thread1.join().unwrap(); thread2.join().unwrap(); @@ -185,26 +132,17 @@ fn test_blocking_read() { // Test the behaviour of a socketpair getting blocked on write and subsequently unblocked. fn test_blocking_write() { let mut fds = [-1, -1]; - let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }; - assert_eq!(res, 0); + errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }); let arr1: [u8; 0x34000] = [1; 0x34000]; // Exhaust the space in the buffer so the subsequent write will block. - let res = - unsafe { libc_utils::write_all(fds[0], arr1.as_ptr() as *const libc::c_void, arr1.len()) }; - assert_eq!(res, 0x34000); + write_all_from_slice(fds[0], &arr1).unwrap(); let thread1 = thread::spawn(move || { - let data = "abc".as_bytes().as_ptr(); // The write below will be blocked because the buffer is already full. - let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 3) }; - assert_eq!(res, 3); + write_all_from_slice(fds[0], b"abc").unwrap(); }); let thread2 = thread::spawn(move || { // Unblock thread1 by freeing up some space. - let mut buf: [u8; 3] = [0; 3]; - let res = unsafe { - libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) - }; - assert_eq!(res, 3); + let buf = read_all_into_array::<3>(fds[1]).unwrap(); assert_eq!(buf, [1, 1, 1]); }); thread1.join().unwrap(); @@ -215,30 +153,25 @@ fn test_blocking_write() { fn test_socketpair_setfl_getfl() { // Initialise socketpair fds. let mut fds = [-1, -1]; - let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }; - assert_eq!(res, 0); + errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }); // Test if both sides have O_RDWR. - let res = unsafe { libc::fcntl(fds[0], libc::F_GETFL) }; - assert_eq!(res, libc::O_RDWR); - let res = unsafe { libc::fcntl(fds[1], libc::F_GETFL) }; - assert_eq!(res, libc::O_RDWR); + assert_eq!(errno_result(unsafe { libc::fcntl(fds[0], libc::F_GETFL) }).unwrap(), libc::O_RDWR); + assert_eq!(errno_result(unsafe { libc::fcntl(fds[1], libc::F_GETFL) }).unwrap(), libc::O_RDWR); // Add the O_NONBLOCK flag with F_SETFL. - let res = unsafe { libc::fcntl(fds[0], libc::F_SETFL, libc::O_NONBLOCK) }; - assert_eq!(res, 0); + errno_check(unsafe { libc::fcntl(fds[0], libc::F_SETFL, libc::O_NONBLOCK) }); // Test if the O_NONBLOCK flag is successfully added. - let res = unsafe { libc::fcntl(fds[0], libc::F_GETFL) }; - assert_eq!(res, libc::O_RDWR | libc::O_NONBLOCK); + assert_eq!( + errno_result(unsafe { libc::fcntl(fds[0], libc::F_GETFL) }).unwrap(), + libc::O_RDWR | libc::O_NONBLOCK + ); // The other side remains unchanged. - let res = unsafe { libc::fcntl(fds[1], libc::F_GETFL) }; - assert_eq!(res, libc::O_RDWR); + assert_eq!(errno_result(unsafe { libc::fcntl(fds[1], libc::F_GETFL) }).unwrap(), libc::O_RDWR); // Test if O_NONBLOCK flag can be unset. - let res = unsafe { libc::fcntl(fds[0], libc::F_SETFL, 0) }; - assert_eq!(res, 0); - let res = unsafe { libc::fcntl(fds[0], libc::F_GETFL) }; - assert_eq!(res, libc::O_RDWR); + errno_check(unsafe { libc::fcntl(fds[0], libc::F_SETFL, 0) }); + assert_eq!(errno_result(unsafe { libc::fcntl(fds[0], libc::F_GETFL) }).unwrap(), libc::O_RDWR); } From ffaf76a7cfbf29968e6a33387fc96aa7b17a88fc Mon Sep 17 00:00:00 2001 From: hulxv Date: Wed, 17 Dec 2025 23:05:49 +0200 Subject: [PATCH 0370/1061] Refactor epoll tests to use errno_result and improve notification checks --- .../pass-dep/libc/libc-epoll-blocking.rs | 162 ++++++------------ .../pass-dep/libc/libc-epoll-no-blocking.rs | 20 +-- src/tools/miri/tests/utils/libc.rs | 11 +- 3 files changed, 75 insertions(+), 118 deletions(-) diff --git a/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs b/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs index c67386b4f84c..d5a59796de02 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs @@ -7,6 +7,8 @@ use std::thread; #[path = "../../utils/libc.rs"] mod libc_utils; +use libc_utils::epoll::*; +use libc_utils::*; // This is a set of testcases for blocking epoll. @@ -20,47 +22,22 @@ fn main() { } // Using `as` cast since `EPOLLET` wraps around -const EPOLL_IN_OUT_ET: u32 = (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET) as _; - -#[track_caller] -fn check_epoll_wait( - epfd: i32, - expected_notifications: &[(u32, u64)], - timeout: i32, -) { - let epoll_event = libc::epoll_event { events: 0, u64: 0 }; - let mut array: [libc::epoll_event; N] = [epoll_event; N]; - let maxsize = N; - let array_ptr = array.as_mut_ptr(); - let res = unsafe { libc::epoll_wait(epfd, array_ptr, maxsize.try_into().unwrap(), timeout) }; - if res < 0 { - panic!("epoll_wait failed: {}", std::io::Error::last_os_error()); - } - let got_notifications = - unsafe { std::slice::from_raw_parts(array_ptr, res.try_into().unwrap()) }; - let got_notifications = got_notifications.iter().map(|e| (e.events, e.u64)).collect::>(); - assert_eq!(got_notifications, expected_notifications, "got wrong notifications"); -} +const EPOLL_IN_OUT_ET: i32 = (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET) as _; // This test allows epoll_wait to block, then unblock without notification. fn test_epoll_block_without_notification() { // Create an epoll instance. - let epfd = unsafe { libc::epoll_create1(0) }; - assert_ne!(epfd, -1); + let epfd = errno_result(unsafe { libc::epoll_create1(0) }).unwrap(); // Create an eventfd instances. let flags = libc::EFD_NONBLOCK | libc::EFD_CLOEXEC; - let fd = unsafe { libc::eventfd(0, flags) }; + let fd = errno_result(unsafe { libc::eventfd(0, flags) }).unwrap(); // Register eventfd with epoll. - let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fd as u64 }; - let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd, &mut ev) }; - assert_eq!(res, 0); + epoll_ctl_add(epfd, fd, EPOLL_IN_OUT_ET).unwrap(); // epoll_wait to clear notification. - let expected_event = u32::try_from(libc::EPOLLOUT).unwrap(); - let expected_value = fd as u64; - check_epoll_wait::<1>(epfd, &[(expected_event, expected_value)], 0); + check_epoll_wait::<1>(epfd, &[Ev { events: libc::EPOLLOUT as _, data: fd }], 0); // This epoll wait blocks, and timeout without notification. check_epoll_wait::<1>(epfd, &[], 5); @@ -69,102 +46,86 @@ fn test_epoll_block_without_notification() { // This test triggers notification and unblocks the epoll_wait before timeout. fn test_epoll_block_then_unblock() { // Create an epoll instance. - let epfd = unsafe { libc::epoll_create1(0) }; - assert_ne!(epfd, -1); + let epfd = errno_result(unsafe { libc::epoll_create1(0) }).unwrap(); // Create a socketpair instance. let mut fds = [-1, -1]; - let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }; - assert_eq!(res, 0); + errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }); // Register one side of the socketpair with epoll. - let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fds[0] as u64 }; - let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[0], &mut ev) }; - assert_eq!(res, 0); + epoll_ctl_add(epfd, fds[0], EPOLL_IN_OUT_ET).unwrap(); // epoll_wait to clear notification. - let expected_event = u32::try_from(libc::EPOLLOUT).unwrap(); - let expected_value = fds[0] as u64; - check_epoll_wait::<1>(epfd, &[(expected_event, expected_value)], 0); + check_epoll_wait::<1>(epfd, &[Ev { events: libc::EPOLLOUT as _, data: fds[0] }], 0); // epoll_wait before triggering notification so it will block then get unblocked before timeout. - let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap(); - let expected_value = fds[0] as u64; let thread1 = thread::spawn(move || { thread::yield_now(); - let data = "abcde".as_bytes().as_ptr(); - let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) }; - assert_eq!(res, 5); + write_all_from_slice(fds[1], b"abcde").unwrap(); }); - check_epoll_wait::<1>(epfd, &[(expected_event, expected_value)], 10); + check_epoll_wait::<1>( + epfd, + &[Ev { events: (libc::EPOLLIN | libc::EPOLLOUT) as _, data: fds[0] }], + 10, + ); thread1.join().unwrap(); } // This test triggers a notification after epoll_wait times out. fn test_notification_after_timeout() { // Create an epoll instance. - let epfd = unsafe { libc::epoll_create1(0) }; - assert_ne!(epfd, -1); + let epfd = errno_result(unsafe { libc::epoll_create1(0) }).unwrap(); // Create a socketpair instance. let mut fds = [-1, -1]; - let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }; - assert_eq!(res, 0); + errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }); // Register one side of the socketpair with epoll. - let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fds[0] as u64 }; - let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[0], &mut ev) }; - assert_eq!(res, 0); + epoll_ctl_add(epfd, fds[0], EPOLL_IN_OUT_ET).unwrap(); // epoll_wait to clear notification. - let expected_event = u32::try_from(libc::EPOLLOUT).unwrap(); - let expected_value = fds[0] as u64; - check_epoll_wait::<1>(epfd, &[(expected_event, expected_value)], 0); + check_epoll_wait::<1>(epfd, &[Ev { events: libc::EPOLLOUT as _, data: fds[0] }], 0); // epoll_wait timeouts without notification. check_epoll_wait::<1>(epfd, &[], 10); // Trigger epoll notification after timeout. - let data = "abcde".as_bytes().as_ptr(); - let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) }; - assert_eq!(res, 5); + write_all_from_slice(fds[1], b"abcde").unwrap(); // Check the result of the notification. - let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap(); - let expected_value = fds[0] as u64; - check_epoll_wait::<1>(epfd, &[(expected_event, expected_value)], 10); + check_epoll_wait::<1>( + epfd, + &[Ev { events: (libc::EPOLLIN | libc::EPOLLOUT) as _, data: fds[0] }], + 10, + ); } // This test shows a data_race before epoll had vector clocks added. fn test_epoll_race() { // Create an epoll instance. - let epfd = unsafe { libc::epoll_create1(0) }; - assert_ne!(epfd, -1); + let epfd = errno_result(unsafe { libc::epoll_create1(0) }).unwrap(); // Create an eventfd instance. let flags = libc::EFD_NONBLOCK | libc::EFD_CLOEXEC; - let fd = unsafe { libc::eventfd(0, flags) }; + let fd = errno_result(unsafe { libc::eventfd(0, flags) }).unwrap(); // Register eventfd with the epoll instance. - let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fd as u64 }; - let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd, &mut ev) }; - assert_eq!(res, 0); + epoll_ctl_add(epfd, fd, EPOLL_IN_OUT_ET).unwrap(); static mut VAL: u8 = 0; let thread1 = thread::spawn(move || { // Write to the static mut variable. unsafe { VAL = 1 }; // Write to the eventfd instance. - let sized_8_data: [u8; 8] = 1_u64.to_ne_bytes(); - let res = unsafe { libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8) }; - // write returns number of bytes written, which is always 8. - assert_eq!(res, 8); + write_all_from_slice(fd, &1_u64.to_ne_bytes()).unwrap(); }); thread::yield_now(); // epoll_wait for the event to happen. - let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap(); - let expected_value = u64::try_from(fd).unwrap(); - check_epoll_wait::<8>(epfd, &[(expected_event, expected_value)], -1); + check_epoll_wait::<8>( + epfd, + &[Ev { events: (libc::EPOLLIN | libc::EPOLLOUT) as _, data: fd }], + -1, + ); // Read from the static mut variable. #[allow(static_mut_refs)] unsafe { @@ -177,35 +138,28 @@ fn test_epoll_race() { /// epoll it is blocked on. fn wakeup_on_new_interest() { // Create an epoll instance. - let epfd = unsafe { libc::epoll_create1(0) }; - assert_ne!(epfd, -1); + let epfd = errno_result(unsafe { libc::epoll_create1(0) }).unwrap(); // Create a socketpair instance. let mut fds = [-1, -1]; - let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }; - assert_eq!(res, 0); + errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }); // Write to fd[0] - let data = "abcde".as_bytes().as_ptr(); - let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) }; - assert_eq!(res, 5); + write_all_from_slice(fds[0], b"abcde").unwrap(); // Block a thread on the epoll instance. let t = std::thread::spawn(move || { - let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap(); - let expected_value = u64::try_from(fds[1]).unwrap(); - check_epoll_wait::<8>(epfd, &[(expected_event, expected_value)], -1); + check_epoll_wait::<8>( + epfd, + &[Ev { events: (libc::EPOLLIN | libc::EPOLLOUT) as _, data: fds[1] }], + -1, + ); }); // Ensure the thread is blocked. std::thread::yield_now(); // Register fd[1] with EPOLLIN|EPOLLOUT|EPOLLET|EPOLLRDHUP - let mut ev = libc::epoll_event { - events: (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET | libc::EPOLLRDHUP) as _, - u64: u64::try_from(fds[1]).unwrap(), - }; - let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[1], &mut ev) }; - assert_eq!(res, 0); + epoll_ctl_add(epfd, fds[1], EPOLL_IN_OUT_ET | libc::EPOLLRDHUP as i32).unwrap(); // This should wake up the thread. t.join().unwrap(); @@ -215,25 +169,23 @@ fn wakeup_on_new_interest() { /// to consume them all. fn multiple_events_wake_multiple_threads() { // Create an epoll instance. - let epfd = unsafe { libc::epoll_create1(0) }; - assert_ne!(epfd, -1); + let epfd = errno_result(unsafe { libc::epoll_create1(0) }).unwrap(); // Create an eventfd instance. let flags = libc::EFD_NONBLOCK | libc::EFD_CLOEXEC; - let fd1 = unsafe { libc::eventfd(0, flags) }; + let fd1 = errno_result(unsafe { libc::eventfd(0, flags) }).unwrap(); // Make a duplicate so that we have two file descriptors for the same file description. - let fd2 = unsafe { libc::dup(fd1) }; + let fd2 = errno_result(unsafe { libc::dup(fd1) }).unwrap(); // Register both with epoll. - let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fd1 as u64 }; - let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd1, &mut ev) }; - assert_eq!(res, 0); - let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fd2 as u64 }; - let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd2, &mut ev) }; - assert_eq!(res, 0); + epoll_ctl_add(epfd, fd1, EPOLL_IN_OUT_ET).unwrap(); + epoll_ctl_add(epfd, fd2, EPOLL_IN_OUT_ET).unwrap(); // Consume the initial events. - let expected = [(libc::EPOLLOUT as u32, fd1 as u64), (libc::EPOLLOUT as u32, fd2 as u64)]; + let expected = [ + Ev { events: libc::EPOLLOUT as _, data: fd1 }, + Ev { events: libc::EPOLLOUT as _, data: fd2 }, + ]; check_epoll_wait::<8>(epfd, &expected, -1); // Block two threads on the epoll, both wanting to get just one event. @@ -241,19 +193,19 @@ fn multiple_events_wake_multiple_threads() { let mut e = libc::epoll_event { events: 0, u64: 0 }; let res = unsafe { libc::epoll_wait(epfd, &raw mut e, 1, -1) }; assert!(res == 1); - (e.events, e.u64) + Ev { events: e.events.cast_signed(), data: e.u64.try_into().unwrap() } }); let t2 = thread::spawn(move || { let mut e = libc::epoll_event { events: 0, u64: 0 }; let res = unsafe { libc::epoll_wait(epfd, &raw mut e, 1, -1) }; assert!(res == 1); - (e.events, e.u64) + Ev { events: e.events.cast_signed(), data: e.u64.try_into().unwrap() } }); // Yield so both threads are waiting now. thread::yield_now(); // Trigger the eventfd. This triggers two events at once! - libc_utils::write_all_from_slice(fd1, &0_u64.to_ne_bytes()).unwrap(); + write_all_from_slice(fd1, &0_u64.to_ne_bytes()).unwrap(); // Both threads should have been woken up so that both events can be consumed. let e1 = t1.join().unwrap(); diff --git a/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs b/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs index c2789eb2f6c6..490895c8541b 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs @@ -60,7 +60,7 @@ fn test_epoll_socketpair() { errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }); // Write to fd[0] - write_all_from_slice(fds[0], "abcde".as_bytes()).unwrap(); + write_all_from_slice(fds[0], b"abcde").unwrap(); // Register fd[1] with EPOLLIN|EPOLLOUT|EPOLLET|EPOLLRDHUP epoll_ctl_add(epfd, fds[1], EPOLLIN | EPOLLOUT | EPOLLET | EPOLLRDHUP).unwrap(); @@ -72,7 +72,7 @@ fn test_epoll_socketpair() { check_epoll_wait_noblock::<8>(epfd, &[]); // Write some more to fd[0]. - write_all_from_slice(fds[0], "abcde".as_bytes()).unwrap(); + write_all_from_slice(fds[0], b"abcde").unwrap(); // This did not change the readiness of fd[1], so we should get no event. // However, Linux seems to always deliver spurious events to the peer on each write, @@ -140,7 +140,7 @@ fn test_epoll_ctl_del() { errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }); // Write to fd[0] - let data = "abcde".as_bytes().as_ptr(); + let data = b"abcde".as_ptr(); let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) }; assert_eq!(res, 5); @@ -168,7 +168,7 @@ fn test_two_epoll_instance() { errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }); // Write to the socketpair. - let data = "abcde".as_bytes().as_ptr(); + let data = b"abcde".as_ptr(); let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) }; assert_eq!(res, 5); @@ -208,7 +208,7 @@ fn test_two_same_fd_in_same_epoll_instance() { assert_eq!(res, 0); // Write to the socketpair. - let data = "abcde".as_bytes().as_ptr(); + let data = b"abcde".as_ptr(); let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) }; assert_eq!(res, 5); @@ -288,7 +288,7 @@ fn test_epoll_socketpair_both_sides() { // Write to fds[1]. // (We do the write after the register here, unlike in `test_epoll_socketpair`, to ensure // we cover both orders in which this could be done.) - let data = "abcde".as_bytes().as_ptr(); + let data = b"abcde".as_ptr(); let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) }; assert_eq!(res, 5); @@ -307,7 +307,7 @@ fn test_epoll_socketpair_both_sides() { let res = unsafe { libc_utils::read_all(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) }; assert_eq!(res, 5); - assert_eq!(buf, "abcde".as_bytes()); + assert_eq!(buf, *b"abcde"); // The state of fds[1] does not change (was writable, is writable). // However, we force a spurious wakeup as the read buffer just got emptied. @@ -500,7 +500,7 @@ fn test_no_notification_for_unregister_flag() { assert_eq!(res, 0); // Write to fd[1]. - let data = "abcde".as_bytes().as_ptr(); + let data = b"abcde".as_ptr(); let res: i32 = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5).try_into().unwrap() }; @@ -534,7 +534,7 @@ fn test_socketpair_epollerr() { errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }); // Write to fd[0] - let data = "abcde".as_bytes().as_ptr(); + let data = b"abcde".as_ptr(); let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) }; assert_eq!(res, 5); @@ -747,7 +747,7 @@ fn test_issue_4374_reads() { assert_eq!(unsafe { libc::fcntl(fds[1], libc::F_SETFL, libc::O_NONBLOCK) }, 0); // Write to fds[1] so that fds[0] becomes readable. - let data = "abcde".as_bytes().as_ptr(); + let data = b"abcde".as_ptr(); let res: i32 = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5).try_into().unwrap() }; diff --git a/src/tools/miri/tests/utils/libc.rs b/src/tools/miri/tests/utils/libc.rs index 0765bacb6bd8..4492f5080180 100644 --- a/src/tools/miri/tests/utils/libc.rs +++ b/src/tools/miri/tests/utils/libc.rs @@ -113,7 +113,7 @@ pub mod epoll { /// The libc epoll_event type doesn't fit to the EPOLLIN etc constants, so we have our /// own type. We also make the data field an int since we typically want to store FDs there. - #[derive(PartialEq, Debug)] + #[derive(PartialEq, Debug, Clone, Copy)] pub struct Ev { pub events: c_int, pub data: c_int, @@ -138,10 +138,10 @@ pub mod epoll { } #[track_caller] - pub fn check_epoll_wait_noblock(epfd: i32, expected: &[Ev]) { + pub fn check_epoll_wait(epfd: i32, expected: &[Ev], timeout: i32) { let mut array: [libc::epoll_event; N] = [libc::epoll_event { events: 0, u64: 0 }; N]; let num = errno_result(unsafe { - libc::epoll_wait(epfd, array.as_mut_ptr(), N.try_into().unwrap(), 0) + libc::epoll_wait(epfd, array.as_mut_ptr(), N.try_into().unwrap(), timeout) }) .expect("epoll_wait returned an error"); let got = &mut array[..num.try_into().unwrap()]; @@ -151,4 +151,9 @@ pub mod epoll { .collect::>(); assert_eq!(got, expected, "got wrong notifications"); } + + #[track_caller] + pub fn check_epoll_wait_noblock(epfd: i32, expected: &[Ev]) { + check_epoll_wait::(epfd, expected, 0); + } } From b0e65da2af8f3e12015d78a1828fceed6360642a Mon Sep 17 00:00:00 2001 From: Usman Akinyemi Date: Wed, 7 Jan 2026 19:01:19 +0530 Subject: [PATCH 0371/1061] rustc_parse_format: improve error for missing `:` before `?` in format args MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Detect the `{ident?}` pattern where `?` is immediately followed by `}` and emit a clearer diagnostic explaining that `:` is required for Debug formatting. This avoids falling back to a generic “invalid format string” error and adds a targeted UI test for the case. Signed-off-by: Usman Akinyemi --- compiler/rustc_builtin_macros/messages.ftl | 2 ++ compiler/rustc_builtin_macros/src/errors.rs | 9 +++++++ compiler/rustc_builtin_macros/src/format.rs | 4 +++ compiler/rustc_parse_format/src/lib.rs | 29 ++++++++++++++++++--- tests/ui/fmt/format-string-error-2.rs | 3 +++ tests/ui/fmt/format-string-error-2.stderr | 13 ++++++++- 6 files changed, 55 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index f0f6f2dcf82c..e4fded0cb01e 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -182,6 +182,8 @@ builtin_macros_expected_other = expected operand, {$is_inline_asm -> builtin_macros_export_macro_rules = cannot export macro_rules! macros from a `proc-macro` crate type currently +builtin_macros_format_add_missing_colon = add a colon before the format specifier + builtin_macros_format_duplicate_arg = duplicate argument named `{$ident}` .label1 = previously here .label2 = duplicate argument diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index ad31eae10f60..e673ad3f8a64 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -643,6 +643,15 @@ pub(crate) enum InvalidFormatStringSuggestion { span: Span, replacement: String, }, + #[suggestion( + builtin_macros_format_add_missing_colon, + code = ":?", + applicability = "machine-applicable" + )] + AddMissingColon { + #[primary_span] + span: Span, + }, } #[derive(Diagnostic)] diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index a0ee7ac19899..12cb2cd00694 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -329,6 +329,10 @@ fn make_format_args( replacement, }); } + parse::Suggestion::AddMissingColon(span) => { + let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end)); + e.sugg_ = Some(errors::InvalidFormatStringSuggestion::AddMissingColon { span }); + } } let guar = ecx.dcx().emit_err(e); return ExpandResult::Ready(Err(guar)); diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 86326fc6536c..143fd0c4436c 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -184,6 +184,9 @@ pub enum Suggestion { /// `format!("{foo:?x}")` -> `format!("{foo:x?}")` /// `format!("{foo:?X}")` -> `format!("{foo:X?}")` ReorderFormatParameter(Range, String), + /// Add missing colon: + /// `format!("{foo?}")` -> `format!("{foo:?}")` + AddMissingColon(Range), } /// The parser structure for interpreting the input format string. This is @@ -453,10 +456,11 @@ impl<'input> Parser<'input> { suggestion: Suggestion::None, }); - if let Some((_, _, c)) = self.peek() { - match c { - '?' => self.suggest_format_debug(), - '<' | '^' | '>' => self.suggest_format_align(c), + if let (Some((_, _, c)), Some((_, _, nc))) = (self.peek(), self.peek_ahead()) { + match (c, nc) { + ('?', '}') => self.missing_colon_before_debug_formatter(), + ('?', _) => self.suggest_format_debug(), + ('<' | '^' | '>', _) => self.suggest_format_align(c), _ => self.suggest_positional_arg_instead_of_captured_arg(arg), } } @@ -849,6 +853,23 @@ impl<'input> Parser<'input> { } } + fn missing_colon_before_debug_formatter(&mut self) { + if let Some((range, _)) = self.consume_pos('?') { + let span = range.clone(); + self.errors.insert( + 0, + ParseError { + description: "expected `}`, found `?`".to_owned(), + note: Some(format!("to print `{{`, you can escape it using `{{{{`",)), + label: "expected `:` before `?` to format with `Debug`".to_owned(), + span: range, + secondary_label: None, + suggestion: Suggestion::AddMissingColon(span), + }, + ); + } + } + fn suggest_format_align(&mut self, alignment: char) { if let Some((range, _)) = self.consume_pos(alignment) { self.errors.insert( diff --git a/tests/ui/fmt/format-string-error-2.rs b/tests/ui/fmt/format-string-error-2.rs index 357dd7b10a3e..e14a4064aa83 100644 --- a/tests/ui/fmt/format-string-error-2.rs +++ b/tests/ui/fmt/format-string-error-2.rs @@ -83,4 +83,7 @@ raw { \n println!(r#"\x7B}\u8 {"#, 1); //~^ ERROR invalid format string: unmatched `}` found + + println!("{x?}, world!",); + //~^ ERROR invalid format string: expected `}`, found `?` } diff --git a/tests/ui/fmt/format-string-error-2.stderr b/tests/ui/fmt/format-string-error-2.stderr index 6d8c34fdb709..b117fb57cf07 100644 --- a/tests/ui/fmt/format-string-error-2.stderr +++ b/tests/ui/fmt/format-string-error-2.stderr @@ -177,5 +177,16 @@ LL | println!(r#"\x7B}\u8 {"#, 1); | = note: if you intended to print `}`, you can escape it using `}}` -error: aborting due to 18 previous errors +error: invalid format string: expected `}`, found `?` + --> $DIR/format-string-error-2.rs:87:17 + | +LL | println!("{x?}, world!",); + | ^ + | | + | expected `:` before `?` to format with `Debug` in format string + | help: add a colon before the format specifier: `:?` + | + = note: to print `{`, you can escape it using `{{` + +error: aborting due to 19 previous errors From 600102c09b4e2a65969b1a1c1e857552fe1b83c2 Mon Sep 17 00:00:00 2001 From: Aelin Reidel Date: Thu, 8 Jan 2026 02:12:49 +0100 Subject: [PATCH 0372/1061] Add myself as co-maintainer for s390x-unknown-linux-musl Having two dedicated target maintainers is a prerequisite for promoting this target to tier 2. I've been in contact with Ulrich and he's agreed to having me as a co-maintainer in preparation for a MCP to promote it to tier 2. --- src/doc/rustc/src/platform-support/s390x-unknown-linux-musl.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/rustc/src/platform-support/s390x-unknown-linux-musl.md b/src/doc/rustc/src/platform-support/s390x-unknown-linux-musl.md index b8bee11055fe..cb7d05515453 100644 --- a/src/doc/rustc/src/platform-support/s390x-unknown-linux-musl.md +++ b/src/doc/rustc/src/platform-support/s390x-unknown-linux-musl.md @@ -7,6 +7,7 @@ IBM z/Architecture (s390x) targets (including IBM Z and LinuxONE) running Linux. ## Target maintainers [@uweigand](https://github.com/uweigand) +[@Gelbpunkt](https://github.com/Gelbpunkt) ## Requirements From a3b72d3de584a524d677bbaedf440f9223d439c0 Mon Sep 17 00:00:00 2001 From: Peter Todd Date: Thu, 8 Jan 2026 02:06:20 +0000 Subject: [PATCH 0373/1061] Fix copy-n-paste error in `vtable_for` docs This is a safe function, which doesn't take a `ptr` parameter. --- library/core/src/intrinsics/mod.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 0ae8d3d4a4ce..27e1673c51de 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2738,10 +2738,6 @@ pub unsafe fn vtable_align(ptr: *const ()) -> usize; /// Determining whether `T` can be coerced to the trait object type `U` requires trait resolution by the compiler. /// In some cases, that resolution can exceed the recursion limit, /// and compilation will fail instead of this function returning `None`. -/// -/// # Safety -/// -/// `ptr` must point to a vtable. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] From e2c73b806e629b4fb5a7f082643d602ca541f7b5 Mon Sep 17 00:00:00 2001 From: xonx <119700621+xonx4l@users.noreply.github.com> Date: Thu, 8 Jan 2026 02:32:51 +0000 Subject: [PATCH 0374/1061] docs:improve const generics --- src/doc/rustc-dev-guide/src/const-generics.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/const-generics.md b/src/doc/rustc-dev-guide/src/const-generics.md index cb8c7adc07f4..4c2a0ddbabd5 100644 --- a/src/doc/rustc-dev-guide/src/const-generics.md +++ b/src/doc/rustc-dev-guide/src/const-generics.md @@ -111,14 +111,15 @@ The third point is also somewhat subtle, by not inheriting any of the where clau This also makes it much more likely that the compiler will ICE or atleast incidentally emit some kind of error if we *do* accidentally allow generic parameters in an anon const, as the anon const will have none of the necessary information in its environment to properly handle the generic parameters. +#### Array repeat expressions +The one exception to all of the above is repeat counts of array expressions. As a *backwards compatibility hack* we allow the repeat count const argument to use generic parameters. + ```rust fn foo() { - let a = [1_u8; size_of::<*mut T>()]; + let a = [1_u8; size_of::()]; } ``` -The one exception to all of the above is repeat counts of array expressions. As a *backwards compatibility hack* we allow the repeat count const argument to use generic parameters. - However, to avoid most of the problems involved in allowing generic parameters in anon const const arguments we require that the constant be evaluated before monomorphization (e.g. during type checking). In some sense we only allow generic parameters here when they are semantically unused. In the previous example the anon const can be evaluated for any type parameter `T` because raw pointers to sized types always have the same size (e.g. `8` on 64bit platforms). From a4da8e8cefd95b8b5e7c0cea97a9f6331e578276 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 7 Jan 2026 11:23:48 +1100 Subject: [PATCH 0375/1061] Remove some unnecessary braces in patterns. --- .../rustc_next_trait_solver/src/canonical/canonicalizer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index 9162284422d0..289538a6163b 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -417,7 +417,7 @@ impl, I: Interner> TypeFolder for Canonicaliz // We don't canonicalize `ReStatic` in the `param_env` as we use it // when checking whether a `ParamEnv` candidate is global. ty::ReStatic => match self.canonicalize_mode { - CanonicalizeMode::Input(CanonicalizeInputKind::Predicate { .. }) => { + CanonicalizeMode::Input(CanonicalizeInputKind::Predicate) => { CanonicalVarKind::Region(ty::UniverseIndex::ROOT) } CanonicalizeMode::Input(CanonicalizeInputKind::ParamEnv) @@ -545,7 +545,7 @@ impl, I: Interner> TypeFolder for Canonicaliz match self.canonicalize_mode { CanonicalizeMode::Input(CanonicalizeInputKind::ParamEnv) | CanonicalizeMode::Response { max_input_universe: _ } => {} - CanonicalizeMode::Input(CanonicalizeInputKind::Predicate { .. }) => { + CanonicalizeMode::Input(CanonicalizeInputKind::Predicate) => { panic!("erasing 'static in env") } } From 5ca112fb9712d260d1aa5214a116663971fc770d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 5 Jan 2026 17:48:51 +1100 Subject: [PATCH 0376/1061] Factor out duplicated code in `Canonicalizer::finalize`. --- .../src/canonical/canonicalizer.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index 289538a6163b..6c114d601157 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -109,6 +109,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { let (max_universe, variables) = canonicalizer.finalize(); Canonical { max_universe, variables, value } } + fn canonicalize_param_env( delegate: &'a D, variables: &'a mut Vec, @@ -280,15 +281,14 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { let mut var_kinds = self.var_kinds; // See the rustc-dev-guide section about how we deal with universes // during canonicalization in the new solver. - match self.canonicalize_mode { + let max_universe = match self.canonicalize_mode { // All placeholders and vars are canonicalized in the root universe. CanonicalizeMode::Input { .. } => { debug_assert!( var_kinds.iter().all(|var| var.universe() == ty::UniverseIndex::ROOT), "expected all vars to be canonicalized in root universe: {var_kinds:#?}" ); - let var_kinds = self.delegate.cx().mk_canonical_var_kinds(&var_kinds); - (ty::UniverseIndex::ROOT, var_kinds) + ty::UniverseIndex::ROOT } // When canonicalizing a response we map a universes already entered // by the caller to the root universe and only return useful universe @@ -302,15 +302,15 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { ); *var = var.with_updated_universe(new_uv); } - let max_universe = var_kinds + var_kinds .iter() .map(|kind| kind.universe()) .max() - .unwrap_or(ty::UniverseIndex::ROOT); - let var_kinds = self.delegate.cx().mk_canonical_var_kinds(&var_kinds); - (max_universe, var_kinds) + .unwrap_or(ty::UniverseIndex::ROOT) } - } + }; + let var_kinds = self.delegate.cx().mk_canonical_var_kinds(&var_kinds); + (max_universe, var_kinds) } fn inner_fold_ty(&mut self, t: I::Ty) -> I::Ty { From 0ad7701b04f03602ef1cd86ebbae09d4a0f5a2b1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 5 Jan 2026 16:34:41 +1100 Subject: [PATCH 0377/1061] Remove `variables` arg from `Canonicalizer::canonicalize_response`. It's an empty `Vec` at both call sites, and so is unnecessary. --- .../rustc_next_trait_solver/src/canonical/canonicalizer.rs | 4 ++-- compiler/rustc_next_trait_solver/src/canonical/mod.rs | 7 ++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index 6c114d601157..c2a7414911ff 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -84,14 +84,14 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { pub(super) fn canonicalize_response>( delegate: &'a D, max_input_universe: ty::UniverseIndex, - variables: &'a mut Vec, value: T, ) -> ty::Canonical { + let mut variables = Vec::new(); let mut canonicalizer = Canonicalizer { delegate, canonicalize_mode: CanonicalizeMode::Response { max_input_universe }, - variables, + variables: &mut variables, variable_lookup_table: Default::default(), sub_root_lookup_table: Default::default(), var_kinds: Vec::new(), diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index b4cea8701d82..d562b8fac4c4 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -82,10 +82,7 @@ where I: Interner, T: TypeFoldable, { - let mut orig_values = Default::default(); - let canonical = - Canonicalizer::canonicalize_response(delegate, max_input_universe, &mut orig_values, value); - canonical + Canonicalizer::canonicalize_response(delegate, max_input_universe, value) } /// After calling a canonical query, we apply the constraints returned @@ -308,7 +305,7 @@ where let var_values = CanonicalVarValues { var_values: delegate.cx().mk_args(var_values) }; let state = inspect::State { var_values, data }; let state = eager_resolve_vars(delegate, state); - Canonicalizer::canonicalize_response(delegate, max_input_universe, &mut vec![], state) + Canonicalizer::canonicalize_response(delegate, max_input_universe, state) } // FIXME: needs to be pub to be accessed by downstream From 4ae3c85a5ef8597aa11d1a547581312ebf56e3b1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 7 Jan 2026 13:10:22 +1100 Subject: [PATCH 0378/1061] Use the name `var_kinds` more. Variables that are collections of `CanonicalVarKind` are sometimes called `var_kinds` and sometimes called `variables`. The former is much better, because `variables` is (a) non-descript, and (b) often used nearby for collections of `I::GenericArg`. I found the inconsistency made the canonicalization code harder to understand. This commit renames various `variables` things as `var_kinds`. --- .../src/infer/canonical/canonicalizer.rs | 38 ++++++------ .../src/infer/canonical/instantiate.rs | 2 +- .../rustc_infer/src/infer/canonical/mod.rs | 2 +- .../src/infer/canonical/query_response.rs | 8 +-- compiler/rustc_middle/src/infer/canonical.rs | 2 +- .../src/canonical/canonicalizer.rs | 8 +-- .../src/canonical/mod.rs | 12 ++-- .../src/solve/eval_ctxt/mod.rs | 8 +-- .../src/solve/eval_ctxt/probe.rs | 2 +- .../src/solve/search_graph.rs | 2 +- compiler/rustc_type_ir/src/canonical.rs | 24 ++++---- ..._of_reborrow.SimplifyCfg-initial.after.mir | 60 +++++++++---------- ...ignment.main.SimplifyCfg-initial.after.mir | 4 +- .../issue_101867.main.built.after.mir | 4 +- ...ceiver_ptr_mutability.main.built.after.mir | 8 +-- ..._type_annotations.let_else.built.after.mir | 4 +- ...otations.let_else_bindless.built.after.mir | 4 +- ..._type_annotations.let_init.built.after.mir | 4 +- ...otations.let_init_bindless.built.after.mir | 4 +- ...ype_annotations.let_uninit.built.after.mir | 2 +- ...ations.let_uninit_bindless.built.after.mir | 2 +- ...otations.match_assoc_const.built.after.mir | 4 +- ...ns.match_assoc_const_range.built.after.mir | 8 +-- .../issue_72181_1.main.built.after.mir | 4 +- .../issue_99325.main.built.after.32bit.mir | 4 +- .../issue_99325.main.built.after.64bit.mir | 4 +- 26 files changed, 114 insertions(+), 114 deletions(-) diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index c07b41b56caa..23f6fee406a5 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -289,7 +289,7 @@ struct Canonicalizer<'cx, 'tcx> { /// Set to `None` to disable the resolution of inference variables. infcx: Option<&'cx InferCtxt<'tcx>>, tcx: TyCtxt<'tcx>, - variables: SmallVec<[CanonicalVarKind<'tcx>; 8]>, + var_kinds: SmallVec<[CanonicalVarKind<'tcx>; 8]>, query_state: &'cx mut OriginalQueryValues<'tcx>, // Note that indices is only used once `var_values` is big enough to be // heap-allocated. @@ -507,7 +507,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { { let base = Canonical { max_universe: ty::UniverseIndex::ROOT, - variables: List::empty(), + var_kinds: List::empty(), value: (), }; Canonicalizer::canonicalize_with_base( @@ -548,7 +548,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { tcx, canonicalize_mode: canonicalize_region_mode, needs_canonical_flags, - variables: SmallVec::from_slice(base.variables), + var_kinds: SmallVec::from_slice(base.var_kinds), query_state, indices: FxHashMap::default(), sub_root_lookup_table: Default::default(), @@ -569,16 +569,16 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { // anymore. debug_assert!(!out_value.has_infer() && !out_value.has_placeholders()); - let canonical_variables = - tcx.mk_canonical_var_kinds(&canonicalizer.universe_canonicalized_variables()); + let canonical_var_kinds = + tcx.mk_canonical_var_kinds(&canonicalizer.universe_canonicalized_var_kinds()); - let max_universe = canonical_variables + let max_universe = canonical_var_kinds .iter() .map(|cvar| cvar.universe()) .max() .unwrap_or(ty::UniverseIndex::ROOT); - Canonical { max_universe, variables: canonical_variables, value: (base.value, out_value) } + Canonical { max_universe, var_kinds: canonical_var_kinds, value: (base.value, out_value) } } /// Creates a canonical variable replacing `kind` from the input, @@ -590,7 +590,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { var_kind: CanonicalVarKind<'tcx>, value: GenericArg<'tcx>, ) -> BoundVar { - let Canonicalizer { variables, query_state, indices, .. } = self; + let Canonicalizer { var_kinds, query_state, indices, .. } = self; let var_values = &mut query_state.var_values; @@ -607,7 +607,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { } } - // This code is hot. `variables` and `var_values` are usually small + // This code is hot. `var_kinds` and `var_values` are usually small // (fewer than 8 elements ~95% of the time). They are SmallVec's to // avoid allocations in those cases. We also don't use `indices` to // determine if a kind has been seen before until the limit of 8 has @@ -620,10 +620,10 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { BoundVar::new(idx) } else { // `kind` isn't present in `var_values`. Append it. Likewise - // for `var_kind` and `variables`. - variables.push(var_kind); + // for `var_kind` and `var_kinds`. + var_kinds.push(var_kind); var_values.push(value); - assert_eq!(variables.len(), var_values.len()); + assert_eq!(var_kinds.len(), var_values.len()); // If `var_values` has become big enough to be heap-allocated, // fill up `indices` to facilitate subsequent lookups. @@ -641,10 +641,10 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { } else { // `var_values` is large. Do a hashmap search via `indices`. *indices.entry(value).or_insert_with(|| { - variables.push(var_kind); + var_kinds.push(var_kind); var_values.push(value); - assert_eq!(variables.len(), var_values.len()); - BoundVar::new(variables.len() - 1) + assert_eq!(var_kinds.len(), var_values.len()); + BoundVar::new(var_kinds.len() - 1) }) } } @@ -652,16 +652,16 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { fn get_or_insert_sub_root(&mut self, vid: ty::TyVid) -> ty::BoundVar { let root_vid = self.infcx.unwrap().sub_unification_table_root_var(vid); let idx = - *self.sub_root_lookup_table.entry(root_vid).or_insert_with(|| self.variables.len()); + *self.sub_root_lookup_table.entry(root_vid).or_insert_with(|| self.var_kinds.len()); ty::BoundVar::from(idx) } /// Replaces the universe indexes used in `var_values` with their index in /// `query_state.universe_map`. This minimizes the maximum universe used in /// the canonicalized value. - fn universe_canonicalized_variables(self) -> SmallVec<[CanonicalVarKind<'tcx>; 8]> { + fn universe_canonicalized_var_kinds(self) -> SmallVec<[CanonicalVarKind<'tcx>; 8]> { if self.query_state.universe_map.len() == 1 { - return self.variables; + return self.var_kinds; } let reverse_universe_map: FxHashMap = self @@ -672,7 +672,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { .map(|(idx, universe)| (*universe, ty::UniverseIndex::from_usize(idx))) .collect(); - self.variables + self.var_kinds .iter() .map(|&kind| match kind { CanonicalVarKind::Int | CanonicalVarKind::Float => { diff --git a/compiler/rustc_infer/src/infer/canonical/instantiate.rs b/compiler/rustc_infer/src/infer/canonical/instantiate.rs index c215a9db2a0a..66a7bd2fc636 100644 --- a/compiler/rustc_infer/src/infer/canonical/instantiate.rs +++ b/compiler/rustc_infer/src/infer/canonical/instantiate.rs @@ -43,7 +43,7 @@ impl<'tcx, V> Canonical<'tcx, V> { where T: TypeFoldable>, { - assert_eq!(self.variables.len(), var_values.len()); + assert_eq!(self.var_kinds.len(), var_values.len()); let value = projection_fn(&self.value); instantiate_value(tcx, var_values, value) } diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index 9af0e17be4e2..c6826d774216 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -68,7 +68,7 @@ impl<'tcx> InferCtxt<'tcx> { .collect(); let var_values = - CanonicalVarValues::instantiate(self.tcx, &canonical.variables, |var_values, info| { + CanonicalVarValues::instantiate(self.tcx, &canonical.var_kinds, |var_values, info| { self.instantiate_canonical_var(span, info, &var_values, |ui| universes[ui]) }); let result = canonical.instantiate(self.tcx, &var_values); diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index b4952e7bfe15..65b0f8211432 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -430,7 +430,7 @@ impl<'tcx> InferCtxt<'tcx> { // result, then we can type the corresponding value from the // input. See the example above. let mut opt_values: IndexVec>> = - IndexVec::from_elem_n(None, query_response.variables.len()); + IndexVec::from_elem_n(None, query_response.var_kinds.len()); for (original_value, result_value) in iter::zip(&original_values.var_values, result_values) { @@ -442,7 +442,7 @@ impl<'tcx> InferCtxt<'tcx> { // more involved. They are also a lot rarer than region variables. if let ty::Bound(index_kind, b) = *result_value.kind() && !matches!( - query_response.variables[b.var.as_usize()], + query_response.var_kinds[b.var.as_usize()], CanonicalVarKind::Ty { .. } ) { @@ -472,8 +472,8 @@ impl<'tcx> InferCtxt<'tcx> { // given variable in the loop above, use that. Otherwise, use // a fresh inference variable. let tcx = self.tcx; - let variables = query_response.variables; - let var_values = CanonicalVarValues::instantiate(tcx, variables, |var_values, kind| { + let var_kinds = query_response.var_kinds; + let var_values = CanonicalVarValues::instantiate(tcx, var_kinds, |var_values, kind| { if kind.universe() != ty::UniverseIndex::ROOT { // A variable from inside a binder of the query. While ideally these shouldn't // exist at all, we have to deal with them for now. diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 153605ee7f81..32c6b6e9c0ba 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -169,7 +169,7 @@ impl<'tcx> CanonicalParamEnvCache<'tcx> { ) { return Canonical { max_universe: ty::UniverseIndex::ROOT, - variables: List::empty(), + var_kinds: List::empty(), value: key, }; } diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index c2a7414911ff..5349b5657d51 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -106,8 +106,8 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { }; debug_assert!(!value.has_infer(), "unexpected infer in {value:?}"); debug_assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}"); - let (max_universe, variables) = canonicalizer.finalize(); - Canonical { max_universe, variables, value } + let (max_universe, var_kinds) = canonicalizer.finalize(); + Canonical { max_universe, var_kinds, value } } fn canonicalize_param_env( @@ -235,8 +235,8 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { debug_assert!(!value.has_infer(), "unexpected infer in {value:?}"); debug_assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}"); - let (max_universe, variables) = rest_canonicalizer.finalize(); - Canonical { max_universe, variables, value } + let (max_universe, var_kinds) = rest_canonicalizer.finalize(); + Canonical { max_universe, var_kinds, value } } fn get_or_insert_bound_var( diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index d562b8fac4c4..ffc666e36179 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -154,7 +154,7 @@ where // // We therefore instantiate the existential variable in the canonical response with the // inference variable of the input right away, which is more performant. - let mut opt_values = IndexVec::from_elem_n(None, response.variables.len()); + let mut opt_values = IndexVec::from_elem_n(None, response.var_kinds.len()); for (original_value, result_value) in iter::zip(original_values, var_values.var_values.iter()) { match result_value.kind() { ty::GenericArgKind::Type(t) => { @@ -164,7 +164,7 @@ where // more involved. They are also a lot rarer than region variables. if let ty::Bound(index_kind, b) = t.kind() && !matches!( - response.variables.get(b.var().as_usize()).unwrap(), + response.var_kinds.get(b.var().as_usize()).unwrap(), CanonicalVarKind::Ty { .. } ) { @@ -186,7 +186,7 @@ where } } } - CanonicalVarValues::instantiate(delegate.cx(), response.variables, |var_values, kind| { + CanonicalVarValues::instantiate(delegate.cx(), response.var_kinds, |var_values, kind| { if kind.universe() != ty::UniverseIndex::ROOT { // A variable from inside a binder of the query. While ideally these shouldn't // exist at all (see the FIXME at the start of this method), we have to deal with @@ -342,14 +342,14 @@ where pub fn response_no_constraints_raw( cx: I, max_universe: ty::UniverseIndex, - variables: I::CanonicalVarKinds, + var_kinds: I::CanonicalVarKinds, certainty: Certainty, ) -> CanonicalResponse { ty::Canonical { max_universe, - variables, + var_kinds, value: Response { - var_values: ty::CanonicalVarValues::make_identity(cx, variables), + var_values: ty::CanonicalVarValues::make_identity(cx, var_kinds), // FIXME: maybe we should store the "no response" version in cx, like // we do for cx.types and stuff. external_constraints: cx.mk_external_constraints(ExternalConstraintsData::default()), diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 8d0a3ac94d5a..2fd79f593a5f 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -97,7 +97,7 @@ where /// The variable info for the `var_values`, only used to make an ambiguous response /// with no constraints. - variables: I::CanonicalVarKinds, + var_kinds: I::CanonicalVarKinds, /// What kind of goal we're currently computing, see the enum definition /// for more info. @@ -325,7 +325,7 @@ where // which we don't do within this evaluation context. max_input_universe: ty::UniverseIndex::ROOT, initial_opaque_types_storage_num_entries: Default::default(), - variables: Default::default(), + var_kinds: Default::default(), var_values: CanonicalVarValues::dummy(), current_goal_kind: CurrentGoalKind::Misc, origin_span, @@ -376,7 +376,7 @@ where let initial_opaque_types_storage_num_entries = delegate.opaque_types_storage_num_entries(); let mut ecx = EvalCtxt { delegate, - variables: canonical_input.canonical.variables, + var_kinds: canonical_input.canonical.var_kinds, var_values, current_goal_kind: CurrentGoalKind::from_query_input(cx, input), max_input_universe: canonical_input.canonical.max_universe, @@ -1323,7 +1323,7 @@ where response_no_constraints_raw( self.cx(), self.max_input_universe, - self.variables, + self.var_kinds, Certainty::Maybe { cause, opaque_types_jank }, ) } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs index e5658ba32ff6..edf2a5d1ba8d 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs @@ -47,7 +47,7 @@ where let max_input_universe = outer.max_input_universe; let mut nested = EvalCtxt { delegate, - variables: outer.variables, + var_kinds: outer.var_kinds, var_values: outer.var_values, current_goal_kind: outer.current_goal_kind, max_input_universe, diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index ea45d5096990..73044b7943ae 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -143,7 +143,7 @@ fn response_no_constraints( Ok(response_no_constraints_raw( cx, input.canonical.max_universe, - input.canonical.variables, + input.canonical.var_kinds, certainty, )) } diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index 47e753d78731..12d222258b0c 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -38,7 +38,7 @@ impl Eq for CanonicalQueryInput {} pub struct Canonical { pub value: V, pub max_universe: UniverseIndex, - pub variables: I::CanonicalVarKinds, + pub var_kinds: I::CanonicalVarKinds, } impl Eq for Canonical {} @@ -68,17 +68,17 @@ impl Canonical { /// let b: Canonical)> = a.unchecked_map(|v| (v, ty)); /// ``` pub fn unchecked_map(self, map_op: impl FnOnce(V) -> W) -> Canonical { - let Canonical { max_universe, variables, value } = self; - Canonical { max_universe, variables, value: map_op(value) } + let Canonical { max_universe, var_kinds, value } = self; + Canonical { max_universe, var_kinds, value: map_op(value) } } } impl fmt::Display for Canonical { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { value, max_universe, variables } = self; + let Self { value, max_universe, var_kinds } = self; write!( f, - "Canonical {{ value: {value}, max_universe: {max_universe:?}, variables: {variables:?} }}", + "Canonical {{ value: {value}, max_universe: {max_universe:?}, var_kinds: {var_kinds:?} }}", ) } } @@ -311,30 +311,30 @@ impl CanonicalVarValues { pub fn instantiate( cx: I, - variables: I::CanonicalVarKinds, + var_kinds: I::CanonicalVarKinds, mut f: impl FnMut(&[I::GenericArg], CanonicalVarKind) -> I::GenericArg, ) -> CanonicalVarValues { // Instantiating `CanonicalVarValues` is really hot, but limited to less than // 4 most of the time. Avoid creating a `Vec` here. - if variables.len() <= 4 { + if var_kinds.len() <= 4 { let mut var_values = ArrayVec::<_, 4>::new(); - for info in variables.iter() { + for info in var_kinds.iter() { var_values.push(f(&var_values, info)); } CanonicalVarValues { var_values: cx.mk_args(&var_values) } } else { - CanonicalVarValues::instantiate_cold(cx, variables, f) + CanonicalVarValues::instantiate_cold(cx, var_kinds, f) } } #[cold] fn instantiate_cold( cx: I, - variables: I::CanonicalVarKinds, + var_kinds: I::CanonicalVarKinds, mut f: impl FnMut(&[I::GenericArg], CanonicalVarKind) -> I::GenericArg, ) -> CanonicalVarValues { - let mut var_values = Vec::with_capacity(variables.len()); - for info in variables.iter() { + let mut var_values = Vec::with_capacity(var_kinds.len()); + for info in var_kinds.iter() { var_values.push(f(&var_values, info)); } CanonicalVarValues { var_values: cx.mk_args(&var_values) } diff --git a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir index a1fe278c6520..40527446e5dd 100644 --- a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir @@ -1,36 +1,36 @@ // MIR for `address_of_reborrow` after SimplifyCfg-initial | User Type Annotations -| 0: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:8:10: 8:18, inferred_ty: *const [i32; 10] -| 1: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:10:10: 10:25, inferred_ty: *const dyn std::marker::Send -| 2: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] -| 3: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] -| 4: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10] -| 5: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10] -| 6: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send -| 7: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send -| 8: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32] -| 9: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32] -| 10: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:19:10: 19:18, inferred_ty: *const [i32; 10] -| 11: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:21:10: 21:25, inferred_ty: *const dyn std::marker::Send -| 12: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] -| 13: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] -| 14: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10] -| 15: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10] -| 16: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send -| 17: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send -| 18: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32] -| 19: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32] -| 20: user_ty: Canonical { value: Ty(*mut ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:29:10: 29:16, inferred_ty: *mut [i32; 10] -| 21: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:31:10: 31:23, inferred_ty: *mut dyn std::marker::Send -| 22: user_ty: Canonical { value: Ty(*mut ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] -| 23: user_ty: Canonical { value: Ty(*mut ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] -| 24: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10] -| 25: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10] -| 26: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send -| 27: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send -| 28: user_ty: Canonical { value: Ty(*mut [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:37:12: 37:22, inferred_ty: *mut [i32] -| 29: user_ty: Canonical { value: Ty(*mut [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:37:12: 37:22, inferred_ty: *mut [i32] +| 0: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, var_kinds: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:8:10: 8:18, inferred_ty: *const [i32; 10] +| 1: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, var_kinds: [Region(U0)] }, span: $DIR/address_of.rs:10:10: 10:25, inferred_ty: *const dyn std::marker::Send +| 2: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, var_kinds: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] +| 3: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, var_kinds: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] +| 4: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, var_kinds: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10] +| 5: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, var_kinds: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10] +| 6: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, var_kinds: [Region(U0)] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send +| 7: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, var_kinds: [Region(U0)] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send +| 8: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, var_kinds: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32] +| 9: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, var_kinds: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32] +| 10: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, var_kinds: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:19:10: 19:18, inferred_ty: *const [i32; 10] +| 11: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, var_kinds: [Region(U0)] }, span: $DIR/address_of.rs:21:10: 21:25, inferred_ty: *const dyn std::marker::Send +| 12: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, var_kinds: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] +| 13: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, var_kinds: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] +| 14: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, var_kinds: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10] +| 15: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, var_kinds: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10] +| 16: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, var_kinds: [Region(U0)] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send +| 17: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, var_kinds: [Region(U0)] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send +| 18: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, var_kinds: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32] +| 19: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, var_kinds: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32] +| 20: user_ty: Canonical { value: Ty(*mut ^c_0), max_universe: U0, var_kinds: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:29:10: 29:16, inferred_ty: *mut [i32; 10] +| 21: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, var_kinds: [Region(U0)] }, span: $DIR/address_of.rs:31:10: 31:23, inferred_ty: *mut dyn std::marker::Send +| 22: user_ty: Canonical { value: Ty(*mut ^c_0), max_universe: U0, var_kinds: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] +| 23: user_ty: Canonical { value: Ty(*mut ^c_0), max_universe: U0, var_kinds: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] +| 24: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, var_kinds: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10] +| 25: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, var_kinds: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10] +| 26: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, var_kinds: [Region(U0)] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send +| 27: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, var_kinds: [Region(U0)] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send +| 28: user_ty: Canonical { value: Ty(*mut [i32]), max_universe: U0, var_kinds: [] }, span: $DIR/address_of.rs:37:12: 37:22, inferred_ty: *mut [i32] +| 29: user_ty: Canonical { value: Ty(*mut [i32]), max_universe: U0, var_kinds: [] }, span: $DIR/address_of.rs:37:12: 37:22, inferred_ty: *mut [i32] | fn address_of_reborrow() -> () { let mut _0: (); diff --git a/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir b/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir index b9d26c67538e..aa7d75242b40 100644 --- a/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir @@ -1,8 +1,8 @@ // MIR for `main` after SimplifyCfg-initial | User Type Annotations -| 0: user_ty: Canonical { value: Ty(std::option::Option>), max_universe: U0, variables: [] }, span: $DIR/basic_assignment.rs:38:17: 38:33, inferred_ty: std::option::Option> -| 1: user_ty: Canonical { value: Ty(std::option::Option>), max_universe: U0, variables: [] }, span: $DIR/basic_assignment.rs:38:17: 38:33, inferred_ty: std::option::Option> +| 0: user_ty: Canonical { value: Ty(std::option::Option>), max_universe: U0, var_kinds: [] }, span: $DIR/basic_assignment.rs:38:17: 38:33, inferred_ty: std::option::Option> +| 1: user_ty: Canonical { value: Ty(std::option::Option>), max_universe: U0, var_kinds: [] }, span: $DIR/basic_assignment.rs:38:17: 38:33, inferred_ty: std::option::Option> | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/issue_101867.main.built.after.mir b/tests/mir-opt/building/issue_101867.main.built.after.mir index fa35658a16d4..83281dea44db 100644 --- a/tests/mir-opt/building/issue_101867.main.built.after.mir +++ b/tests/mir-opt/building/issue_101867.main.built.after.mir @@ -1,8 +1,8 @@ // MIR for `main` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty(std::option::Option), max_universe: U0, variables: [] }, span: $DIR/issue_101867.rs:5:12: 5:22, inferred_ty: std::option::Option -| 1: user_ty: Canonical { value: Ty(std::option::Option), max_universe: U0, variables: [] }, span: $DIR/issue_101867.rs:5:12: 5:22, inferred_ty: std::option::Option +| 0: user_ty: Canonical { value: Ty(std::option::Option), max_universe: U0, var_kinds: [] }, span: $DIR/issue_101867.rs:5:12: 5:22, inferred_ty: std::option::Option +| 1: user_ty: Canonical { value: Ty(std::option::Option), max_universe: U0, var_kinds: [] }, span: $DIR/issue_101867.rs:5:12: 5:22, inferred_ty: std::option::Option | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir b/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir index 5cf182c21c31..0c73bd8ac654 100644 --- a/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir +++ b/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir @@ -1,10 +1,10 @@ // MIR for `main` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, variables: [] }, span: $DIR/receiver_ptr_mutability.rs:16:14: 16:23, inferred_ty: *mut Test -| 1: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, variables: [] }, span: $DIR/receiver_ptr_mutability.rs:16:14: 16:23, inferred_ty: *mut Test -| 2: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [Region(U0), Region(U0), Region(U0), Region(U0)] }, span: $DIR/receiver_ptr_mutability.rs:20:18: 20:31, inferred_ty: &&&&*mut Test -| 3: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [Region(U0), Region(U0), Region(U0), Region(U0)] }, span: $DIR/receiver_ptr_mutability.rs:20:18: 20:31, inferred_ty: &&&&*mut Test +| 0: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, var_kinds: [] }, span: $DIR/receiver_ptr_mutability.rs:16:14: 16:23, inferred_ty: *mut Test +| 1: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, var_kinds: [] }, span: $DIR/receiver_ptr_mutability.rs:16:14: 16:23, inferred_ty: *mut Test +| 2: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, var_kinds: [Region(U0), Region(U0), Region(U0), Region(U0)] }, span: $DIR/receiver_ptr_mutability.rs:20:18: 20:31, inferred_ty: &&&&*mut Test +| 3: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, var_kinds: [Region(U0), Region(U0), Region(U0), Region(U0)] }, span: $DIR/receiver_ptr_mutability.rs:20:18: 20:31, inferred_ty: &&&&*mut Test | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir index bbf504d311f6..4b6aa46129a4 100644 --- a/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir @@ -1,8 +1,8 @@ // MIR for `let_else` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:36:20: 36:45, inferred_ty: (u32, u64, &char) -| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:36:20: 36:45, inferred_ty: (u32, u64, &char) +| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:36:20: 36:45, inferred_ty: (u32, u64, &char) +| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:36:20: 36:45, inferred_ty: (u32, u64, &char) | fn let_else() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/user_type_annotations.let_else_bindless.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_else_bindless.built.after.mir index 7bf2551e99f2..3814980b4306 100644 --- a/tests/mir-opt/building/user_type_annotations.let_else_bindless.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.let_else_bindless.built.after.mir @@ -1,8 +1,8 @@ // MIR for `let_else_bindless` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:41:20: 41:45, inferred_ty: (u32, u64, &char) -| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:41:20: 41:45, inferred_ty: (u32, u64, &char) +| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:41:20: 41:45, inferred_ty: (u32, u64, &char) +| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:41:20: 41:45, inferred_ty: (u32, u64, &char) | fn let_else_bindless() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/user_type_annotations.let_init.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_init.built.after.mir index 0cf681d8ab2c..dd05ef37de3c 100644 --- a/tests/mir-opt/building/user_type_annotations.let_init.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.let_init.built.after.mir @@ -1,8 +1,8 @@ // MIR for `let_init` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:26:20: 26:45, inferred_ty: (u32, u64, &char) -| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:26:20: 26:45, inferred_ty: (u32, u64, &char) +| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:26:20: 26:45, inferred_ty: (u32, u64, &char) +| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:26:20: 26:45, inferred_ty: (u32, u64, &char) | fn let_init() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/user_type_annotations.let_init_bindless.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_init_bindless.built.after.mir index 968813c826e4..d949e1945339 100644 --- a/tests/mir-opt/building/user_type_annotations.let_init_bindless.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.let_init_bindless.built.after.mir @@ -1,8 +1,8 @@ // MIR for `let_init_bindless` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:31:20: 31:45, inferred_ty: (u32, u64, &char) -| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:31:20: 31:45, inferred_ty: (u32, u64, &char) +| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:31:20: 31:45, inferred_ty: (u32, u64, &char) +| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:31:20: 31:45, inferred_ty: (u32, u64, &char) | fn let_init_bindless() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/user_type_annotations.let_uninit.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_uninit.built.after.mir index b6fdc4ff46dc..22bf17bd7898 100644 --- a/tests/mir-opt/building/user_type_annotations.let_uninit.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.let_uninit.built.after.mir @@ -1,7 +1,7 @@ // MIR for `let_uninit` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:16:20: 16:45, inferred_ty: (u32, u64, &char) +| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:16:20: 16:45, inferred_ty: (u32, u64, &char) | fn let_uninit() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/user_type_annotations.let_uninit_bindless.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_uninit_bindless.built.after.mir index 472dbfb63043..aad2de0e7d6e 100644 --- a/tests/mir-opt/building/user_type_annotations.let_uninit_bindless.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.let_uninit_bindless.built.after.mir @@ -1,7 +1,7 @@ // MIR for `let_uninit_bindless` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:21:20: 21:45, inferred_ty: (u32, u64, &char) +| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:21:20: 21:45, inferred_ty: (u32, u64, &char) | fn let_uninit_bindless() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/user_type_annotations.match_assoc_const.built.after.mir b/tests/mir-opt/building/user_type_annotations.match_assoc_const.built.after.mir index ff4b0bf7600d..8ec5028250b0 100644 --- a/tests/mir-opt/building/user_type_annotations.match_assoc_const.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.match_assoc_const.built.after.mir @@ -1,8 +1,8 @@ // MIR for `match_assoc_const` after built | User Type Annotations -| 0: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:55:9: 55:44, inferred_ty: u32 -| 1: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:55:9: 55:44, inferred_ty: u32 +| 0: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:55:9: 55:44, inferred_ty: u32 +| 1: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:55:9: 55:44, inferred_ty: u32 | fn match_assoc_const() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/user_type_annotations.match_assoc_const_range.built.after.mir b/tests/mir-opt/building/user_type_annotations.match_assoc_const_range.built.after.mir index 4cc433f475f6..61e5d9b459d0 100644 --- a/tests/mir-opt/building/user_type_annotations.match_assoc_const_range.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.match_assoc_const_range.built.after.mir @@ -1,10 +1,10 @@ // MIR for `match_assoc_const_range` after built | User Type Annotations -| 0: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:63:11: 63:46, inferred_ty: u32 -| 1: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:63:11: 63:46, inferred_ty: u32 -| 2: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:64:9: 64:44, inferred_ty: u32 -| 3: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:64:9: 64:44, inferred_ty: u32 +| 0: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:63:11: 63:46, inferred_ty: u32 +| 1: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:63:11: 63:46, inferred_ty: u32 +| 2: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:64:9: 64:44, inferred_ty: u32 +| 3: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:64:9: 64:44, inferred_ty: u32 | fn match_assoc_const_range() -> () { let mut _0: (); diff --git a/tests/mir-opt/issue_72181_1.main.built.after.mir b/tests/mir-opt/issue_72181_1.main.built.after.mir index 79eaf9668330..398a4bcb3ab3 100644 --- a/tests/mir-opt/issue_72181_1.main.built.after.mir +++ b/tests/mir-opt/issue_72181_1.main.built.after.mir @@ -1,8 +1,8 @@ // MIR for `main` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty(Void), max_universe: U0, variables: [] }, span: $DIR/issue_72181_1.rs:17:12: 17:16, inferred_ty: Void -| 1: user_ty: Canonical { value: Ty(Void), max_universe: U0, variables: [] }, span: $DIR/issue_72181_1.rs:17:12: 17:16, inferred_ty: Void +| 0: user_ty: Canonical { value: Ty(Void), max_universe: U0, var_kinds: [] }, span: $DIR/issue_72181_1.rs:17:12: 17:16, inferred_ty: Void +| 1: user_ty: Canonical { value: Ty(Void), max_universe: U0, var_kinds: [] }, span: $DIR/issue_72181_1.rs:17:12: 17:16, inferred_ty: Void | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/issue_99325.main.built.after.32bit.mir b/tests/mir-opt/issue_99325.main.built.after.32bit.mir index 48a399eb39ce..9e48cf038bf2 100644 --- a/tests/mir-opt/issue_99325.main.built.after.32bit.mir +++ b/tests/mir-opt/issue_99325.main.built.after.32bit.mir @@ -1,8 +1,8 @@ // MIR for `main` after built | User Type Annotations -| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} -| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, var_kinds: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }], user_self_ty: None }), max_universe: U0, var_kinds: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/issue_99325.main.built.after.64bit.mir b/tests/mir-opt/issue_99325.main.built.after.64bit.mir index 48a399eb39ce..9e48cf038bf2 100644 --- a/tests/mir-opt/issue_99325.main.built.after.64bit.mir +++ b/tests/mir-opt/issue_99325.main.built.after.64bit.mir @@ -1,8 +1,8 @@ // MIR for `main` after built | User Type Annotations -| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} -| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, var_kinds: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }], user_self_ty: None }), max_universe: U0, var_kinds: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} | fn main() -> () { let mut _0: (); From 65756bed80e0ce759cb5b6fa9fe80578e18d6981 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 8 Jan 2026 14:54:26 +1100 Subject: [PATCH 0379/1061] Remove out of date FIXME comment. In #127273 I added a test and a FIXME comment pointing out how it does the wrong thing. In the next commit I fixed the problem but forgot to remove the FIXME comment, whoops. --- compiler/rustc_parse/src/parser/tests.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index a46fcd30fef4..62e97c0c308c 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -2666,7 +2666,6 @@ fn look_ahead_non_outermost_stream() { }); } -// FIXME(nnethercote) All the output is currently wrong. #[test] fn debug_lookahead() { create_default_session_globals_then(|| { From f8240839704855d24823c5b2daf398144bcc7f43 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 7 Jan 2026 13:14:23 +1100 Subject: [PATCH 0380/1061] Make `Canonicalizer::variables` owned. Currently it's a mutable reference, but it doesn't need to be, because what's passed in is always a mutable reference to an empty `Vec`. This requires returning variables in a few extra places, which is fine. It makes the handling of `variables` the same as the handling of `var_kinds` and `variable_lookup_table`. --- .../src/canonical/canonicalizer.rs | 48 +++++++++---------- .../src/canonical/mod.rs | 4 +- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index 5349b5657d51..f71c8b122007 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -64,7 +64,7 @@ pub(super) struct Canonicalizer<'a, D: SolverDelegate, I: Interner canonicalize_mode: CanonicalizeMode, // Mutable fields. - variables: &'a mut Vec, + variables: Vec, var_kinds: Vec>, variable_lookup_table: HashMap, /// Maps each `sub_unification_table_root_var` to the index of the first @@ -86,12 +86,11 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { max_input_universe: ty::UniverseIndex, value: T, ) -> ty::Canonical { - let mut variables = Vec::new(); let mut canonicalizer = Canonicalizer { delegate, canonicalize_mode: CanonicalizeMode::Response { max_input_universe }, - variables: &mut variables, + variables: Vec::new(), variable_lookup_table: Default::default(), sub_root_lookup_table: Default::default(), var_kinds: Vec::new(), @@ -106,17 +105,17 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { }; debug_assert!(!value.has_infer(), "unexpected infer in {value:?}"); debug_assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}"); - let (max_universe, var_kinds) = canonicalizer.finalize(); + let (max_universe, _variables, var_kinds) = canonicalizer.finalize(); Canonical { max_universe, var_kinds, value } } fn canonicalize_param_env( delegate: &'a D, - variables: &'a mut Vec, param_env: I::ParamEnv, - ) -> (I::ParamEnv, HashMap, Vec>) { + ) -> (I::ParamEnv, Vec, Vec>, HashMap) + { if !param_env.has_type_flags(NEEDS_CANONICAL) { - return (param_env, Default::default(), Vec::new()); + return (param_env, Vec::new(), Vec::new(), Default::default()); } // Check whether we can use the global cache for this param_env. As we only use @@ -130,12 +129,11 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { delegate.cx().canonical_param_env_cache_get_or_insert( param_env, || { - let mut variables = Vec::new(); let mut env_canonicalizer = Canonicalizer { delegate, canonicalize_mode: CanonicalizeMode::Input(CanonicalizeInputKind::ParamEnv), - variables: &mut variables, + variables: Vec::new(), variable_lookup_table: Default::default(), sub_root_lookup_table: Default::default(), var_kinds: Vec::new(), @@ -148,18 +146,16 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { param_env, variable_lookup_table: env_canonicalizer.variable_lookup_table, var_kinds: env_canonicalizer.var_kinds, - variables, + variables: env_canonicalizer.variables, } }, |&CanonicalParamEnvCacheEntry { param_env, - variables: ref cache_variables, + ref variables, ref variable_lookup_table, ref var_kinds, }| { - debug_assert!(variables.is_empty()); - variables.extend(cache_variables.iter().copied()); - (param_env, variable_lookup_table.clone(), var_kinds.clone()) + (param_env, variables.clone(), var_kinds.clone(), variable_lookup_table.clone()) }, ) } else { @@ -167,7 +163,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { delegate, canonicalize_mode: CanonicalizeMode::Input(CanonicalizeInputKind::ParamEnv), - variables, + variables: Vec::new(), variable_lookup_table: Default::default(), sub_root_lookup_table: Default::default(), var_kinds: Vec::new(), @@ -176,7 +172,12 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { }; let param_env = param_env.fold_with(&mut env_canonicalizer); debug_assert!(env_canonicalizer.sub_root_lookup_table.is_empty()); - (param_env, env_canonicalizer.variable_lookup_table, env_canonicalizer.var_kinds) + ( + param_env, + env_canonicalizer.variables, + env_canonicalizer.var_kinds, + env_canonicalizer.variable_lookup_table, + ) } } @@ -190,12 +191,11 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { /// variable in the future by changing the way we detect global where-bounds. pub(super) fn canonicalize_input>( delegate: &'a D, - variables: &'a mut Vec, input: QueryInput, - ) -> ty::Canonical> { + ) -> (Vec, ty::Canonical>) { // First canonicalize the `param_env` while keeping `'static` - let (param_env, variable_lookup_table, var_kinds) = - Canonicalizer::canonicalize_param_env(delegate, variables, input.goal.param_env); + let (param_env, variables, var_kinds, variable_lookup_table) = + Canonicalizer::canonicalize_param_env(delegate, input.goal.param_env); // Then canonicalize the rest of the input without keeping `'static` // while *mostly* reusing the canonicalizer from above. let mut rest_canonicalizer = Canonicalizer { @@ -235,8 +235,8 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { debug_assert!(!value.has_infer(), "unexpected infer in {value:?}"); debug_assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}"); - let (max_universe, var_kinds) = rest_canonicalizer.finalize(); - Canonical { max_universe, var_kinds, value } + let (max_universe, variables, var_kinds) = rest_canonicalizer.finalize(); + (variables, Canonical { max_universe, var_kinds, value }) } fn get_or_insert_bound_var( @@ -277,7 +277,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { ty::BoundVar::from(idx) } - fn finalize(self) -> (ty::UniverseIndex, I::CanonicalVarKinds) { + fn finalize(self) -> (ty::UniverseIndex, Vec, I::CanonicalVarKinds) { let mut var_kinds = self.var_kinds; // See the rustc-dev-guide section about how we deal with universes // during canonicalization in the new solver. @@ -310,7 +310,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { } }; let var_kinds = self.delegate.cx().mk_canonical_var_kinds(&var_kinds); - (max_universe, var_kinds) + (max_universe, self.variables, var_kinds) } fn inner_fold_ty(&mut self, t: I::Ty) -> I::Ty { diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index ffc666e36179..96fea09013a1 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -59,10 +59,8 @@ where D: SolverDelegate, I: Interner, { - let mut orig_values = Default::default(); - let canonical = Canonicalizer::canonicalize_input( + let (orig_values, canonical) = Canonicalizer::canonicalize_input( delegate, - &mut orig_values, QueryInput { goal, predefined_opaques_in_body: delegate.cx().mk_predefined_opaques_in_body(opaque_types), From e4bbfe88566c5e06066809558ae655455777d151 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 7 Jan 2026 14:00:04 +1100 Subject: [PATCH 0381/1061] Avoid using `to_vec` to clone `Vec`s. It's weird. `clone` is better. --- compiler/rustc_trait_selection/src/solve/inspect/analyse.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index cdbf2b0aeb83..944d57bf95d1 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -144,7 +144,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { pub fn instantiate_nested_goals(&self, span: Span) -> Vec> { let infcx = self.goal.infcx; let param_env = self.goal.goal.param_env; - let mut orig_values = self.goal.orig_values.to_vec(); + let mut orig_values = self.goal.orig_values.clone(); let mut instantiated_goals = vec![]; for step in &self.steps { @@ -186,7 +186,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { pub fn instantiate_impl_args(&self, span: Span) -> ty::GenericArgsRef<'tcx> { let infcx = self.goal.infcx; let param_env = self.goal.goal.param_env; - let mut orig_values = self.goal.orig_values.to_vec(); + let mut orig_values = self.goal.orig_values.clone(); for step in &self.steps { match **step { From eb1645653b0993fa699c23bfbab94249be15bf1d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 7 Jan 2026 15:05:53 +1100 Subject: [PATCH 0382/1061] Update a comment. I did some measurements. The current choice of 16 is fine. --- .../rustc_next_trait_solver/src/canonical/canonicalizer.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index f71c8b122007..f6ec0dd09c57 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -244,8 +244,9 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { arg: impl Into, kind: CanonicalVarKind, ) -> ty::BoundVar { - // FIXME: 16 is made up and arbitrary. We should look at some - // perf data here. + // The exact value of 16 here doesn't matter that much (8 and 32 give extremely similar + // results). So long as we have protection against the rare cases where the length reaches + // 1000+ (e.g. `wg-grammar`). let arg = arg.into(); let idx = if self.variables.len() > 16 { if self.variable_lookup_table.is_empty() { From a07f71704adc575d56c353f5f08febda4af7fc3b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 7 Jan 2026 17:19:36 +1100 Subject: [PATCH 0383/1061] Add comments about predicate folding. This explains why the predicate folding code looks different to the ty/const folding code, something I was wondering. --- compiler/rustc_middle/src/ty/structural_impls.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 1a5a3f3965fa..314d2ba39632 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -586,11 +586,18 @@ impl<'tcx> TypeSuperFoldable> for ty::Predicate<'tcx> { self, folder: &mut F, ) -> Result { + // This method looks different to `Ty::try_super_fold_with` and `Const::super_fold_with`. + // Why is that? `PredicateKind` provides little scope for optimized folding, unlike + // `TyKind` and `ConstKind` (which have common variants that don't require recursive + // `fold_with` calls on their fields). So we just derive the `TypeFoldable` impl for + // `PredicateKind` and call it here because the derived code is as fast as hand-written + // code would be. let new = self.kind().try_fold_with(folder)?; Ok(folder.cx().reuse_or_mk_predicate(self, new)) } fn super_fold_with>>(self, folder: &mut F) -> Self { + // See comment in `Predicate::try_super_fold_with`. let new = self.kind().fold_with(folder); folder.cx().reuse_or_mk_predicate(self, new) } @@ -598,6 +605,7 @@ impl<'tcx> TypeSuperFoldable> for ty::Predicate<'tcx> { impl<'tcx> TypeSuperVisitable> for ty::Predicate<'tcx> { fn super_visit_with>>(&self, visitor: &mut V) -> V::Result { + // See comment in `Predicate::try_super_fold_with`. self.kind().visit_with(visitor) } } From b222cf3874eb8d3c1a881206f037f0aad1befede Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 8 Jan 2026 15:03:41 +1100 Subject: [PATCH 0384/1061] Tweak variable cloning. --- .../src/canonical/canonicalizer.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index f6ec0dd09c57..8dfa875ca6f9 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -151,11 +151,16 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { }, |&CanonicalParamEnvCacheEntry { param_env, - ref variables, + variables: ref cache_variables, ref variable_lookup_table, ref var_kinds, }| { - (param_env, variables.clone(), var_kinds.clone(), variable_lookup_table.clone()) + // FIXME(nnethercote): for reasons I don't understand, this `new`+`extend` + // combination is faster than `variables.clone()`, because it somehow avoids + // some allocations. + let mut variables = Vec::new(); + variables.extend(cache_variables.iter().copied()); + (param_env, variables, var_kinds.clone(), variable_lookup_table.clone()) }, ) } else { From e454835eef0df5c920377bba45b115e896f3bff9 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 8 Jan 2026 10:25:58 +0300 Subject: [PATCH 0385/1061] resolve: Factor out and document the glob binding overwriting logic --- compiler/rustc_resolve/src/imports.rs | 116 ++++++++++++++++++-------- 1 file changed, 81 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index a8bb53cc7f27..3f998b8c8aa0 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -295,6 +295,24 @@ fn pub_use_of_private_extern_crate_hack(import: Import<'_>, decl: Decl<'_>) -> O } } +/// Removes identical import layers from two declarations. +fn remove_same_import<'ra>(d1: Decl<'ra>, d2: Decl<'ra>) -> (Decl<'ra>, Decl<'ra>) { + if let DeclKind::Import { import: import1, source_decl: d1_next } = d1.kind + && let DeclKind::Import { import: import2, source_decl: d2_next } = d2.kind + && import1 == import2 + && d1.ambiguity == d2.ambiguity + { + assert!(d1.ambiguity.is_none()); + assert_eq!(d1.warn_ambiguity, d2.warn_ambiguity); + assert_eq!(d1.expansion, d2.expansion); + assert_eq!(d1.span, d2.span); + assert_eq!(d1.vis, d2.vis); + remove_same_import(d1_next, d2_next) + } else { + (d1, d2) + } +} + impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Given an import and the declaration that it points to, /// create the corresponding import declaration. @@ -325,6 +343,61 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }) } + /// If `glob_decl` attempts to overwrite `old_glob_decl` in a module, + /// decide which one to keep. + fn select_glob_decl( + &self, + glob_decl: Decl<'ra>, + old_glob_decl: Decl<'ra>, + warn_ambiguity: bool, + ) -> Decl<'ra> { + assert!(glob_decl.is_glob_import()); + assert!(old_glob_decl.is_glob_import()); + assert_ne!(glob_decl, old_glob_decl); + // `best_decl` with a given key in a module may be overwritten in a + // number of cases (all of them can be seen below in the `match` in `try_define_local`), + // all these overwrites will be re-fetched by glob imports importing + // from that module without generating new ambiguities. + // - A glob decl is overwritten by a non-glob decl arriving later. + // - A glob decl is overwritten by an ambiguous glob decl. + // FIXME: avoid this by putting `DeclData::ambiguity` under a + // cell and updating it in place. + // - A glob decl is overwritten by the same decl with `warn_ambiguity == true`. + // FIXME: avoid this by putting `DeclData::warn_ambiguity` under a + // cell and updating it in place. + // - A glob decl is overwritten by a glob decl with larger visibility. + // FIXME: avoid this by putting `DeclData::vis` under a cell + // and updating it in place. + // - A glob decl is overwritten by a glob decl re-fetching an + // overwritten decl from other module (the recursive case). + // Here we are detecting all such re-fetches and overwrite old decls + // with the re-fetched decls. + // This is probably incorrect in corner cases, and the outdated decls still get + // propagated to other places and get stuck there, but that's what we have at the moment. + let (deep_decl, old_deep_decl) = remove_same_import(glob_decl, old_glob_decl); + if deep_decl != glob_decl { + // Some import layers have been removed, need to overwrite. + assert_ne!(old_deep_decl, old_glob_decl); + assert_ne!(old_deep_decl, deep_decl); + assert!(old_deep_decl.is_glob_import()); + if glob_decl.is_ambiguity_recursive() { + self.new_decl_with_warn_ambiguity(glob_decl) + } else { + glob_decl + } + } else if glob_decl.res() != old_glob_decl.res() { + self.new_decl_with_ambiguity(old_glob_decl, glob_decl, warn_ambiguity) + } else if !old_glob_decl.vis.is_at_least(glob_decl.vis, self.tcx) { + // We are glob-importing the same item but with greater visibility. + glob_decl + } else if glob_decl.is_ambiguity_recursive() { + // Overwriting with an ambiguous glob import. + self.new_decl_with_warn_ambiguity(glob_decl) + } else { + old_glob_decl + } + } + /// Attempt to put the declaration with the given name and namespace into the module, /// and return existing declaration if there is a collision. pub(crate) fn try_plant_decl_into_local_module( @@ -347,52 +420,25 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }); self.update_local_resolution(module, key, warn_ambiguity, |this, resolution| { if let Some(old_decl) = resolution.best_decl() { + assert_ne!(decl, old_decl); if res == Res::Err && old_decl.res() != Res::Err { // Do not override real declarations with `Res::Err`s from error recovery. return Ok(()); } match (old_decl.is_glob_import(), decl.is_glob_import()) { (true, true) => { - let (glob_decl, old_glob_decl) = (decl, old_decl); - // FIXME: remove `!decl.is_ambiguity_recursive()` after delete the warning ambiguity. - if !decl.is_ambiguity_recursive() - && let DeclKind::Import { import: old_import, .. } = old_glob_decl.kind - && let DeclKind::Import { import, .. } = glob_decl.kind - && old_import == import - { - // When imported from the same glob-import statement, we should replace - // `old_glob_decl` with `glob_decl`, regardless of whether - // they have the same resolution or not. - resolution.glob_decl = Some(glob_decl); - } else if res != old_glob_decl.res() { - resolution.glob_decl = Some(this.new_decl_with_ambiguity( - old_glob_decl, - glob_decl, - warn_ambiguity, - )); - } else if !old_decl.vis.is_at_least(decl.vis, this.tcx) { - // We are glob-importing the same item but with greater visibility. - resolution.glob_decl = Some(glob_decl); - } else if decl.is_ambiguity_recursive() { - resolution.glob_decl = - Some(this.new_decl_with_warn_ambiguity(glob_decl)); - } + resolution.glob_decl = + Some(this.select_glob_decl(decl, old_decl, warn_ambiguity)); } (old_glob @ true, false) | (old_glob @ false, true) => { let (glob_decl, non_glob_decl) = if old_glob { (old_decl, decl) } else { (decl, old_decl) }; resolution.non_glob_decl = Some(non_glob_decl); - if let Some(old_glob_decl) = resolution.glob_decl { - assert!(old_glob_decl.is_glob_import()); - if glob_decl.res() != old_glob_decl.res() { - resolution.glob_decl = Some(this.new_decl_with_ambiguity( - old_glob_decl, - glob_decl, - false, - )); - } else if !old_glob_decl.vis.is_at_least(decl.vis, this.tcx) { - resolution.glob_decl = Some(glob_decl); - } + if let Some(old_glob_decl) = resolution.glob_decl + && old_glob_decl != glob_decl + { + resolution.glob_decl = + Some(this.select_glob_decl(glob_decl, old_glob_decl, false)); } else { resolution.glob_decl = Some(glob_decl); } From 32cf3a96d7d2695f16f00e594e291ae18c00dc32 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 29 Dec 2025 22:12:56 +0300 Subject: [PATCH 0386/1061] resolve: Update `NameBindingData::warn_ambiguity` in place instead of creating fresh bindings. --- .../rustc_resolve/src/build_reduced_graph.rs | 2 +- .../src/effective_visibilities.rs | 4 ++-- compiler/rustc_resolve/src/imports.rs | 21 +++++++------------ compiler/rustc_resolve/src/lib.rs | 12 +++++------ 4 files changed, 16 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index d56ca7c079cb..0159e9c9eda4 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -91,7 +91,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { kind: DeclKind::Def(res), ambiguity, // External ambiguities always report the `AMBIGUOUS_GLOB_IMPORTS` lint at the moment. - warn_ambiguity: true, + warn_ambiguity: CmCell::new(true), vis, span, expansion, diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index e5144332f2b7..eee12922e511 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -127,7 +127,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { // lint. For all bindings added to the table this way `is_ambiguity` returns true. let is_ambiguity = |decl: Decl<'ra>, warn: bool| decl.ambiguity.is_some() && !warn; let mut parent_id = ParentId::Def(module_id); - let mut warn_ambiguity = decl.warn_ambiguity; + let mut warn_ambiguity = decl.warn_ambiguity.get(); while let DeclKind::Import { source_decl, .. } = decl.kind { self.update_import(decl, parent_id); @@ -140,7 +140,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { parent_id = ParentId::Import(decl); decl = source_decl; - warn_ambiguity |= source_decl.warn_ambiguity; + warn_ambiguity |= source_decl.warn_ambiguity.get(); } if !is_ambiguity(decl, warn_ambiguity) && let Some(def_id) = decl.res().opt_def_id().and_then(|id| id.as_local()) diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 3f998b8c8aa0..7f28ac29ac1d 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -303,7 +303,7 @@ fn remove_same_import<'ra>(d1: Decl<'ra>, d2: Decl<'ra>) -> (Decl<'ra>, Decl<'ra && d1.ambiguity == d2.ambiguity { assert!(d1.ambiguity.is_none()); - assert_eq!(d1.warn_ambiguity, d2.warn_ambiguity); + assert_eq!(d1.warn_ambiguity.get(), d2.warn_ambiguity.get()); assert_eq!(d1.expansion, d2.expansion); assert_eq!(d1.span, d2.span); assert_eq!(d1.vis, d2.vis); @@ -336,7 +336,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.arenas.alloc_decl(DeclData { kind: DeclKind::Import { source_decl: decl, import }, ambiguity: None, - warn_ambiguity: false, + warn_ambiguity: CmCell::new(false), span: import.span, vis, expansion: import.parent_scope.expansion, @@ -362,9 +362,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // - A glob decl is overwritten by an ambiguous glob decl. // FIXME: avoid this by putting `DeclData::ambiguity` under a // cell and updating it in place. - // - A glob decl is overwritten by the same decl with `warn_ambiguity == true`. - // FIXME: avoid this by putting `DeclData::warn_ambiguity` under a - // cell and updating it in place. // - A glob decl is overwritten by a glob decl with larger visibility. // FIXME: avoid this by putting `DeclData::vis` under a cell // and updating it in place. @@ -381,10 +378,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { assert_ne!(old_deep_decl, deep_decl); assert!(old_deep_decl.is_glob_import()); if glob_decl.is_ambiguity_recursive() { - self.new_decl_with_warn_ambiguity(glob_decl) - } else { - glob_decl + glob_decl.warn_ambiguity.set_unchecked(true); } + glob_decl } else if glob_decl.res() != old_glob_decl.res() { self.new_decl_with_ambiguity(old_glob_decl, glob_decl, warn_ambiguity) } else if !old_glob_decl.vis.is_at_least(glob_decl.vis, self.tcx) { @@ -392,7 +388,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { glob_decl } else if glob_decl.is_ambiguity_recursive() { // Overwriting with an ambiguous glob import. - self.new_decl_with_warn_ambiguity(glob_decl) + glob_decl.warn_ambiguity.set_unchecked(true); + glob_decl } else { old_glob_decl } @@ -466,15 +463,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { warn_ambiguity: bool, ) -> Decl<'ra> { let ambiguity = Some(secondary_decl); + let warn_ambiguity = CmCell::new(warn_ambiguity); let data = DeclData { ambiguity, warn_ambiguity, ..*primary_decl }; self.arenas.alloc_decl(data) } - fn new_decl_with_warn_ambiguity(&self, decl: Decl<'ra>) -> Decl<'ra> { - assert!(decl.is_ambiguity_recursive()); - self.arenas.alloc_decl(DeclData { warn_ambiguity: true, ..*decl }) - } - // Use `f` to mutate the resolution of the name in the module. // If the resolution becomes a success, define it in the module's glob importers. fn update_local_resolution( diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 063b6b4058f0..cf8d1952d4a0 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -802,13 +802,13 @@ impl<'ra> fmt::Debug for Module<'ra> { } /// Data associated with any name declaration. -#[derive(Clone, Copy, Debug)] +#[derive(Debug)] struct DeclData<'ra> { kind: DeclKind<'ra>, ambiguity: Option>, /// Produce a warning instead of an error when reporting ambiguities inside this binding. /// May apply to indirect ambiguities under imports, so `ambiguity.is_some()` is not required. - warn_ambiguity: bool, + warn_ambiguity: CmCell, expansion: LocalExpnId, span: Span, vis: Visibility, @@ -956,7 +956,7 @@ impl<'ra> DeclData<'ra> { } fn warn_ambiguity_recursive(&self) -> bool { - self.warn_ambiguity + self.warn_ambiguity.get() || match self.kind { DeclKind::Import { source_decl, .. } => source_decl.warn_ambiguity_recursive(), _ => false, @@ -1343,7 +1343,7 @@ impl<'ra> ResolverArenas<'ra> { self.alloc_decl(DeclData { kind: DeclKind::Def(res), ambiguity: None, - warn_ambiguity: false, + warn_ambiguity: CmCell::new(false), vis, span, expansion, @@ -2041,7 +2041,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } fn record_use(&mut self, ident: Ident, used_decl: Decl<'ra>, used: Used) { - self.record_use_inner(ident, used_decl, used, used_decl.warn_ambiguity); + self.record_use_inner(ident, used_decl, used, used_decl.warn_ambiguity.get()); } fn record_use_inner( @@ -2112,7 +2112,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, source_decl, Used::Other, - warn_ambiguity || source_decl.warn_ambiguity, + warn_ambiguity || source_decl.warn_ambiguity.get(), ); } } From 227e7bd48b5a7f3479bc4b231cf042e092fadd89 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 30 Dec 2025 01:47:50 +0300 Subject: [PATCH 0387/1061] resolve: Update `NameBindingData::vis` in place instead of overwriting bindings in modules. --- .../rustc_resolve/src/build_reduced_graph.rs | 26 +++++++------- compiler/rustc_resolve/src/diagnostics.rs | 8 ++--- .../src/effective_visibilities.rs | 4 +-- compiler/rustc_resolve/src/ident.rs | 11 +++--- compiler/rustc_resolve/src/imports.rs | 35 +++++++++---------- .../rustc_resolve/src/late/diagnostics.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 8 +++-- 7 files changed, 49 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 0159e9c9eda4..0167b8038649 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -92,7 +92,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ambiguity, // External ambiguities always report the `AMBIGUOUS_GLOB_IMPORTS` lint at the moment. warn_ambiguity: CmCell::new(true), - vis, + vis: CmCell::new(vis), span, expansion, }); @@ -1158,18 +1158,18 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.potentially_unused_imports.push(import); module.for_each_child_mut(self, |this, ident, ns, binding| { if ns == MacroNS { - let import = if this.r.is_accessible_from(binding.vis, this.parent_scope.module) - { - import - } else { - // FIXME: This branch is used for reporting the `private_macro_use` lint - // and should eventually be removed. - if this.r.macro_use_prelude.contains_key(&ident.name) { - // Do not override already existing entries with compatibility entries. - return; - } - macro_use_import(this, span, true) - }; + let import = + if this.r.is_accessible_from(binding.vis(), this.parent_scope.module) { + import + } else { + // FIXME: This branch is used for reporting the `private_macro_use` lint + // and should eventually be removed. + if this.r.macro_use_prelude.contains_key(&ident.name) { + // Do not override already existing entries with compatibility entries. + return; + } + macro_use_import(this, span, true) + }; let import_decl = this.r.new_import_decl(binding, import); this.add_macro_use_decl(ident.name, import_decl, span, allow_shadowing); } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 7c86ed91a07a..d704280f3fa2 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1338,7 +1338,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let child_accessible = - accessible && this.is_accessible_from(name_binding.vis, parent_scope.module); + accessible && this.is_accessible_from(name_binding.vis(), parent_scope.module); // do not venture inside inaccessible items of other crates if in_module_is_extern && !child_accessible { @@ -1358,8 +1358,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // #90113: Do not count an inaccessible reexported item as a candidate. if let DeclKind::Import { source_decl, .. } = name_binding.kind - && this.is_accessible_from(source_decl.vis, parent_scope.module) - && !this.is_accessible_from(name_binding.vis, parent_scope.module) + && this.is_accessible_from(source_decl.vis(), parent_scope.module) + && !this.is_accessible_from(name_binding.vis(), parent_scope.module) { return; } @@ -2243,7 +2243,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let first = binding == first_binding; let def_span = self.tcx.sess.source_map().guess_head_span(binding.span); let mut note_span = MultiSpan::from_span(def_span); - if !first && binding.vis.is_public() { + if !first && binding.vis().is_public() { let desc = match binding.kind { DeclKind::Import { .. } => "re-export", _ => "directly", diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index eee12922e511..7272314b9aa7 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -145,7 +145,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { if !is_ambiguity(decl, warn_ambiguity) && let Some(def_id) = decl.res().opt_def_id().and_then(|id| id.as_local()) { - self.update_def(def_id, decl.vis.expect_local(), parent_id); + self.update_def(def_id, decl.vis().expect_local(), parent_id); } } } @@ -188,7 +188,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { } fn update_import(&mut self, decl: Decl<'ra>, parent_id: ParentId<'ra>) { - let nominal_vis = decl.vis.expect_local(); + let nominal_vis = decl.vis().expect_local(); let Some(cheap_private_vis) = self.may_update(nominal_vis, parent_id) else { return }; let inherited_eff_vis = self.effective_vis_or_private(parent_id); let tcx = self.r.tcx; diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index e0acf043ffcf..f47bb28d3fa1 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1017,7 +1017,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Items and single imports are not shadowable, if we have one, then it's determined. if let Some(binding) = binding { - let accessible = self.is_accessible_from(binding.vis, parent_scope.module); + let accessible = self.is_accessible_from(binding.vis(), parent_scope.module); return if accessible { Ok(binding) } else { Err(ControlFlow::Break(Determined)) }; } @@ -1103,7 +1103,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // shadowing is enabled, see `macro_expanded_macro_export_errors`). if let Some(binding) = binding { return if binding.determined() || ns == MacroNS || shadowing == Shadowing::Restricted { - let accessible = self.is_accessible_from(binding.vis, parent_scope.module); + let accessible = self.is_accessible_from(binding.vis(), parent_scope.module); if accessible { Ok(binding) } else { Err(ControlFlow::Break(Determined)) } } else { Err(ControlFlow::Break(Undetermined)) @@ -1160,7 +1160,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { match result { Err(Determined) => continue, Ok(binding) - if !self.is_accessible_from(binding.vis, glob_import.parent_scope.module) => + if !self.is_accessible_from(binding.vis(), glob_import.parent_scope.module) => { continue; } @@ -1187,7 +1187,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return Err(ControlFlow::Continue(Determined)); }; - if !self.is_accessible_from(binding.vis, parent_scope.module) { + if !self.is_accessible_from(binding.vis(), parent_scope.module) { if report_private { self.privacy_errors.push(PrivacyError { ident, @@ -1304,7 +1304,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) { Err(Determined) => continue, Ok(binding) - if !self.is_accessible_from(binding.vis, single_import.parent_scope.module) => + if !self + .is_accessible_from(binding.vis(), single_import.parent_scope.module) => { continue; } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 7f28ac29ac1d..5b0755dbde25 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -306,7 +306,7 @@ fn remove_same_import<'ra>(d1: Decl<'ra>, d2: Decl<'ra>) -> (Decl<'ra>, Decl<'ra assert_eq!(d1.warn_ambiguity.get(), d2.warn_ambiguity.get()); assert_eq!(d1.expansion, d2.expansion); assert_eq!(d1.span, d2.span); - assert_eq!(d1.vis, d2.vis); + assert_eq!(d1.vis(), d2.vis()); remove_same_import(d1_next, d2_next) } else { (d1, d2) @@ -318,12 +318,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// create the corresponding import declaration. pub(crate) fn new_import_decl(&self, decl: Decl<'ra>, import: Import<'ra>) -> Decl<'ra> { let import_vis = import.vis.to_def_id(); - let vis = if decl.vis.is_at_least(import_vis, self.tcx) + let vis = if decl.vis().is_at_least(import_vis, self.tcx) || pub_use_of_private_extern_crate_hack(import, decl).is_some() { import_vis } else { - decl.vis + decl.vis() }; if let ImportKind::Glob { ref max_vis, .. } = import.kind @@ -338,7 +338,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ambiguity: None, warn_ambiguity: CmCell::new(false), span: import.span, - vis, + vis: CmCell::new(vis), expansion: import.parent_scope.expansion, }) } @@ -362,9 +362,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // - A glob decl is overwritten by an ambiguous glob decl. // FIXME: avoid this by putting `DeclData::ambiguity` under a // cell and updating it in place. - // - A glob decl is overwritten by a glob decl with larger visibility. - // FIXME: avoid this by putting `DeclData::vis` under a cell - // and updating it in place. // - A glob decl is overwritten by a glob decl re-fetching an // overwritten decl from other module (the recursive case). // Here we are detecting all such re-fetches and overwrite old decls @@ -383,9 +380,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { glob_decl } else if glob_decl.res() != old_glob_decl.res() { self.new_decl_with_ambiguity(old_glob_decl, glob_decl, warn_ambiguity) - } else if !old_glob_decl.vis.is_at_least(glob_decl.vis, self.tcx) { + } else if !old_glob_decl.vis().is_at_least(glob_decl.vis(), self.tcx) { // We are glob-importing the same item but with greater visibility. - glob_decl + old_glob_decl.vis.set_unchecked(glob_decl.vis()); + old_glob_decl } else if glob_decl.is_ambiguity_recursive() { // Overwriting with an ambiguous glob import. glob_decl.warn_ambiguity.set_unchecked(true); @@ -464,7 +462,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) -> Decl<'ra> { let ambiguity = Some(secondary_decl); let warn_ambiguity = CmCell::new(warn_ambiguity); - let data = DeclData { ambiguity, warn_ambiguity, ..*primary_decl }; + let vis = primary_decl.vis.clone(); + let data = DeclData { ambiguity, warn_ambiguity, vis, ..*primary_decl }; self.arenas.alloc_decl(data) } @@ -509,7 +508,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Some(None) => import.parent_scope.module, None => continue, }; - if self.is_accessible_from(binding.vis, scope) { + if self.is_accessible_from(binding.vis(), scope) { let import_decl = self.new_import_decl(binding, *import); let _ = self.try_plant_decl_into_local_module( import.parent_scope.module, @@ -699,8 +698,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && let Some(glob_import_id) = glob_import.id() && let glob_import_def_id = self.local_def_id(glob_import_id) && self.effective_visibilities.is_exported(glob_import_def_id) - && glob_decl.vis.is_public() - && !binding.vis.is_public() + && glob_decl.vis().is_public() + && !binding.vis().is_public() { let binding_id = match binding.kind { DeclKind::Def(res) => { @@ -1330,9 +1329,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return; }; - if !binding.vis.is_at_least(import.vis, this.tcx) { + if !binding.vis().is_at_least(import.vis, this.tcx) { reexport_error = Some((ns, binding)); - if let Visibility::Restricted(binding_def_id) = binding.vis + if let Visibility::Restricted(binding_def_id) = binding.vis() && binding_def_id.is_top_level_module() { crate_private_reexport = true; @@ -1535,7 +1534,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Some(None) => import.parent_scope.module, None => continue, }; - if self.is_accessible_from(binding.vis, scope) { + if self.is_accessible_from(binding.vis(), scope) { let import_decl = self.new_import_decl(binding, import); let warn_ambiguity = self .resolution(import.parent_scope.module, key) @@ -1577,7 +1576,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let child = |reexport_chain| ModChild { ident: ident.0, res, - vis: binding.vis, + vis: binding.vis(), reexport_chain, }; if let Some((ambig_binding1, ambig_binding2)) = binding.descent_to_ambiguity() { @@ -1585,7 +1584,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let second = ModChild { ident: ident.0, res: ambig_binding2.res().expect_non_local(), - vis: ambig_binding2.vis, + vis: ambig_binding2.vis(), reexport_chain: ambig_binding2.reexport_chain(this), }; ambig_children.push(AmbigModChild { main, second }) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 73e1a8f0c3bc..a2805497e796 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2793,7 +2793,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { in_module.for_each_child(self.r, |r, ident, _, name_binding| { // abort if the module is already found or if name_binding is private external - if result.is_some() || !name_binding.vis.is_visible_locally() { + if result.is_some() || !name_binding.vis().is_visible_locally() { return; } if let Some(module_def_id) = name_binding.res().module_like_def_id() { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index cf8d1952d4a0..bce14f5376d7 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -811,7 +811,7 @@ struct DeclData<'ra> { warn_ambiguity: CmCell, expansion: LocalExpnId, span: Span, - vis: Visibility, + vis: CmCell>, } /// All name declarations are unique and allocated on a same arena, @@ -923,6 +923,10 @@ struct AmbiguityError<'ra> { } impl<'ra> DeclData<'ra> { + fn vis(&self) -> Visibility { + self.vis.get() + } + fn res(&self) -> Res { match self.kind { DeclKind::Def(res) => res, @@ -1344,7 +1348,7 @@ impl<'ra> ResolverArenas<'ra> { kind: DeclKind::Def(res), ambiguity: None, warn_ambiguity: CmCell::new(false), - vis, + vis: CmCell::new(vis), span, expansion, }) From c2379717a2e9f2befdbea2795fea696d7c86d82c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 30 Dec 2025 02:49:14 +0300 Subject: [PATCH 0388/1061] resolve: Tweak overwriting with ambiguous globs Do not overwrite unless necessary, and combine both globs instead of losing the first one. --- compiler/rustc_resolve/src/imports.rs | 7 +++---- tests/ui/imports/ambiguous-14.stderr | 12 ++++++------ tests/ui/imports/duplicate.stderr | 12 ++++++------ 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 5b0755dbde25..76aeb7ba85b8 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -384,10 +384,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // We are glob-importing the same item but with greater visibility. old_glob_decl.vis.set_unchecked(glob_decl.vis()); old_glob_decl - } else if glob_decl.is_ambiguity_recursive() { - // Overwriting with an ambiguous glob import. - glob_decl.warn_ambiguity.set_unchecked(true); - glob_decl + } else if glob_decl.is_ambiguity_recursive() && !old_glob_decl.is_ambiguity_recursive() { + // Overwriting a non-ambiguous glob import with an ambiguous glob import. + self.new_decl_with_ambiguity(old_glob_decl, glob_decl, true) } else { old_glob_decl } diff --git a/tests/ui/imports/ambiguous-14.stderr b/tests/ui/imports/ambiguous-14.stderr index 4efa31c61e32..2a3557c31f12 100644 --- a/tests/ui/imports/ambiguous-14.stderr +++ b/tests/ui/imports/ambiguous-14.stderr @@ -8,15 +8,15 @@ LL | g::foo(); = note: for more information, see issue #114095 = note: ambiguous because of multiple glob imports of a name in the same module note: `foo` could refer to the function imported here - --> $DIR/ambiguous-14.rs:13:13 + --> $DIR/ambiguous-14.rs:18:13 | LL | pub use a::*; | ^^^^ = help: consider adding an explicit import of `foo` to disambiguate note: `foo` could also refer to the function imported here - --> $DIR/ambiguous-14.rs:14:13 + --> $DIR/ambiguous-14.rs:19:13 | -LL | pub use b::*; +LL | pub use f::*; | ^^^^ = help: consider adding an explicit import of `foo` to disambiguate = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default @@ -34,15 +34,15 @@ LL | g::foo(); = note: for more information, see issue #114095 = note: ambiguous because of multiple glob imports of a name in the same module note: `foo` could refer to the function imported here - --> $DIR/ambiguous-14.rs:13:13 + --> $DIR/ambiguous-14.rs:18:13 | LL | pub use a::*; | ^^^^ = help: consider adding an explicit import of `foo` to disambiguate note: `foo` could also refer to the function imported here - --> $DIR/ambiguous-14.rs:14:13 + --> $DIR/ambiguous-14.rs:19:13 | -LL | pub use b::*; +LL | pub use f::*; | ^^^^ = help: consider adding an explicit import of `foo` to disambiguate = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default diff --git a/tests/ui/imports/duplicate.stderr b/tests/ui/imports/duplicate.stderr index 5cd3b0c2c8a5..74829fc21e22 100644 --- a/tests/ui/imports/duplicate.stderr +++ b/tests/ui/imports/duplicate.stderr @@ -78,15 +78,15 @@ LL | g::foo(); = note: for more information, see issue #114095 = note: ambiguous because of multiple glob imports of a name in the same module note: `foo` could refer to the function imported here - --> $DIR/duplicate.rs:24:13 + --> $DIR/duplicate.rs:29:13 | LL | pub use crate::a::*; | ^^^^^^^^^^^ = help: consider adding an explicit import of `foo` to disambiguate note: `foo` could also refer to the function imported here - --> $DIR/duplicate.rs:25:13 + --> $DIR/duplicate.rs:30:13 | -LL | pub use crate::b::*; +LL | pub use crate::f::*; | ^^^^^^^^^^^ = help: consider adding an explicit import of `foo` to disambiguate = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default @@ -106,15 +106,15 @@ LL | g::foo(); = note: for more information, see issue #114095 = note: ambiguous because of multiple glob imports of a name in the same module note: `foo` could refer to the function imported here - --> $DIR/duplicate.rs:24:13 + --> $DIR/duplicate.rs:29:13 | LL | pub use crate::a::*; | ^^^^^^^^^^^ = help: consider adding an explicit import of `foo` to disambiguate note: `foo` could also refer to the function imported here - --> $DIR/duplicate.rs:25:13 + --> $DIR/duplicate.rs:30:13 | -LL | pub use crate::b::*; +LL | pub use crate::f::*; | ^^^^^^^^^^^ = help: consider adding an explicit import of `foo` to disambiguate = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default From a251ae2615bd92b90e4c850a8026bff47e4786bf Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 30 Dec 2025 02:54:43 +0300 Subject: [PATCH 0389/1061] resolve: Update `NameBindingData::ambiguity` in place instead of creating fresh bindings, except in one case. --- .../rustc_resolve/src/build_reduced_graph.rs | 2 +- .../src/effective_visibilities.rs | 7 ++- compiler/rustc_resolve/src/imports.rs | 51 ++++++++++--------- compiler/rustc_resolve/src/lib.rs | 12 ++--- tests/ui/imports/issue-55884-1.rs | 2 +- tests/ui/imports/issue-55884-1.stderr | 22 +++++++- 6 files changed, 60 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 0167b8038649..6bface926edc 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -89,7 +89,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) { let decl = self.arenas.alloc_decl(DeclData { kind: DeclKind::Def(res), - ambiguity, + ambiguity: CmCell::new(ambiguity), // External ambiguities always report the `AMBIGUOUS_GLOB_IMPORTS` lint at the moment. warn_ambiguity: CmCell::new(true), vis: CmCell::new(vis), diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 7272314b9aa7..ebdb0060e1b9 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -100,7 +100,9 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { if let Some(node_id) = import.id() { r.effective_visibilities.update_eff_vis(r.local_def_id(node_id), eff_vis, r.tcx) } - } else if decl.ambiguity.is_some() && eff_vis.is_public_at_level(Level::Reexported) { + } else if decl.ambiguity.get().is_some() + && eff_vis.is_public_at_level(Level::Reexported) + { exported_ambiguities.insert(*decl); } } @@ -125,7 +127,8 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { // If the binding is ambiguous, put the root ambiguity binding and all reexports // leading to it into the table. They are used by the `ambiguous_glob_reexports` // lint. For all bindings added to the table this way `is_ambiguity` returns true. - let is_ambiguity = |decl: Decl<'ra>, warn: bool| decl.ambiguity.is_some() && !warn; + let is_ambiguity = + |decl: Decl<'ra>, warn: bool| decl.ambiguity.get().is_some() && !warn; let mut parent_id = ParentId::Def(module_id); let mut warn_ambiguity = decl.warn_ambiguity.get(); while let DeclKind::Import { source_decl, .. } = decl.kind { diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 76aeb7ba85b8..68f042c6e041 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -300,10 +300,10 @@ fn remove_same_import<'ra>(d1: Decl<'ra>, d2: Decl<'ra>) -> (Decl<'ra>, Decl<'ra if let DeclKind::Import { import: import1, source_decl: d1_next } = d1.kind && let DeclKind::Import { import: import2, source_decl: d2_next } = d2.kind && import1 == import2 - && d1.ambiguity == d2.ambiguity + && d1.warn_ambiguity.get() == d2.warn_ambiguity.get() { - assert!(d1.ambiguity.is_none()); - assert_eq!(d1.warn_ambiguity.get(), d2.warn_ambiguity.get()); + assert_eq!(d1.ambiguity.get(), d2.ambiguity.get()); + assert!(!d1.warn_ambiguity.get()); assert_eq!(d1.expansion, d2.expansion); assert_eq!(d1.span, d2.span); assert_eq!(d1.vis(), d2.vis()); @@ -335,7 +335,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.arenas.alloc_decl(DeclData { kind: DeclKind::Import { source_decl: decl, import }, - ambiguity: None, + ambiguity: CmCell::new(None), warn_ambiguity: CmCell::new(false), span: import.span, vis: CmCell::new(vis), @@ -359,9 +359,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // all these overwrites will be re-fetched by glob imports importing // from that module without generating new ambiguities. // - A glob decl is overwritten by a non-glob decl arriving later. - // - A glob decl is overwritten by an ambiguous glob decl. - // FIXME: avoid this by putting `DeclData::ambiguity` under a - // cell and updating it in place. + // - A glob decl is overwritten by its clone after setting ambiguity in it. + // FIXME: avoid this by removing `warn_ambiguity`, or by triggering glob re-fetch + // with the same decl in some way. // - A glob decl is overwritten by a glob decl re-fetching an // overwritten decl from other module (the recursive case). // Here we are detecting all such re-fetches and overwrite old decls @@ -372,21 +372,34 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if deep_decl != glob_decl { // Some import layers have been removed, need to overwrite. assert_ne!(old_deep_decl, old_glob_decl); - assert_ne!(old_deep_decl, deep_decl); - assert!(old_deep_decl.is_glob_import()); + // FIXME: reenable the asserts when `warn_ambiguity` is removed (#149195). + // assert_ne!(old_deep_decl, deep_decl); + // assert!(old_deep_decl.is_glob_import()); + assert!(!deep_decl.is_glob_import()); if glob_decl.is_ambiguity_recursive() { glob_decl.warn_ambiguity.set_unchecked(true); } glob_decl } else if glob_decl.res() != old_glob_decl.res() { - self.new_decl_with_ambiguity(old_glob_decl, glob_decl, warn_ambiguity) + old_glob_decl.ambiguity.set_unchecked(Some(glob_decl)); + old_glob_decl.warn_ambiguity.set_unchecked(warn_ambiguity); + if warn_ambiguity { + old_glob_decl + } else { + // Need a fresh decl so other glob imports importing it could re-fetch it + // and set their own `warn_ambiguity` to true. + // FIXME: remove this when `warn_ambiguity` is removed (#149195). + self.arenas.alloc_decl((*old_glob_decl).clone()) + } } else if !old_glob_decl.vis().is_at_least(glob_decl.vis(), self.tcx) { // We are glob-importing the same item but with greater visibility. old_glob_decl.vis.set_unchecked(glob_decl.vis()); old_glob_decl } else if glob_decl.is_ambiguity_recursive() && !old_glob_decl.is_ambiguity_recursive() { // Overwriting a non-ambiguous glob import with an ambiguous glob import. - self.new_decl_with_ambiguity(old_glob_decl, glob_decl, true) + old_glob_decl.ambiguity.set_unchecked(Some(glob_decl)); + old_glob_decl.warn_ambiguity.set_unchecked(true); + old_glob_decl } else { old_glob_decl } @@ -415,6 +428,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.update_local_resolution(module, key, warn_ambiguity, |this, resolution| { if let Some(old_decl) = resolution.best_decl() { assert_ne!(decl, old_decl); + assert!(!decl.warn_ambiguity.get()); if res == Res::Err && old_decl.res() != Res::Err { // Do not override real declarations with `Res::Err`s from error recovery. return Ok(()); @@ -453,19 +467,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }) } - fn new_decl_with_ambiguity( - &self, - primary_decl: Decl<'ra>, - secondary_decl: Decl<'ra>, - warn_ambiguity: bool, - ) -> Decl<'ra> { - let ambiguity = Some(secondary_decl); - let warn_ambiguity = CmCell::new(warn_ambiguity); - let vis = primary_decl.vis.clone(); - let data = DeclData { ambiguity, warn_ambiguity, vis, ..*primary_decl }; - self.arenas.alloc_decl(data) - } - // Use `f` to mutate the resolution of the name in the module. // If the resolution becomes a success, define it in the module's glob importers. fn update_local_resolution( @@ -671,7 +672,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let Some(binding) = resolution.best_decl() else { continue }; if let DeclKind::Import { import, .. } = binding.kind - && let Some(amb_binding) = binding.ambiguity + && let Some(amb_binding) = binding.ambiguity.get() && binding.res() != Res::Err && exported_ambiguities.contains(&binding) { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index bce14f5376d7..311efb3e881b 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -802,10 +802,10 @@ impl<'ra> fmt::Debug for Module<'ra> { } /// Data associated with any name declaration. -#[derive(Debug)] +#[derive(Clone, Debug)] struct DeclData<'ra> { kind: DeclKind<'ra>, - ambiguity: Option>, + ambiguity: CmCell>>, /// Produce a warning instead of an error when reporting ambiguities inside this binding. /// May apply to indirect ambiguities under imports, so `ambiguity.is_some()` is not required. warn_ambiguity: CmCell, @@ -942,7 +942,7 @@ impl<'ra> DeclData<'ra> { } fn descent_to_ambiguity(self: Decl<'ra>) -> Option<(Decl<'ra>, Decl<'ra>)> { - match self.ambiguity { + match self.ambiguity.get() { Some(ambig_binding) => Some((self, ambig_binding)), None => match self.kind { DeclKind::Import { source_decl, .. } => source_decl.descent_to_ambiguity(), @@ -952,7 +952,7 @@ impl<'ra> DeclData<'ra> { } fn is_ambiguity_recursive(&self) -> bool { - self.ambiguity.is_some() + self.ambiguity.get().is_some() || match self.kind { DeclKind::Import { source_decl, .. } => source_decl.is_ambiguity_recursive(), _ => false, @@ -1346,7 +1346,7 @@ impl<'ra> ResolverArenas<'ra> { ) -> Decl<'ra> { self.alloc_decl(DeclData { kind: DeclKind::Def(res), - ambiguity: None, + ambiguity: CmCell::new(None), warn_ambiguity: CmCell::new(false), vis: CmCell::new(vis), span, @@ -2055,7 +2055,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { used: Used, warn_ambiguity: bool, ) { - if let Some(b2) = used_decl.ambiguity { + if let Some(b2) = used_decl.ambiguity.get() { let ambiguity_error = AmbiguityError { kind: AmbiguityKind::GlobVsGlob, ident, diff --git a/tests/ui/imports/issue-55884-1.rs b/tests/ui/imports/issue-55884-1.rs index 21744aa5d7bf..3c9c033c158e 100644 --- a/tests/ui/imports/issue-55884-1.rs +++ b/tests/ui/imports/issue-55884-1.rs @@ -17,5 +17,5 @@ mod m { fn main() { use m::S; //~ ERROR `S` is ambiguous - let s = S {}; + let s = S {}; //~ ERROR `S` is ambiguous } diff --git a/tests/ui/imports/issue-55884-1.stderr b/tests/ui/imports/issue-55884-1.stderr index ae8edb049564..a0b63ddc9108 100644 --- a/tests/ui/imports/issue-55884-1.stderr +++ b/tests/ui/imports/issue-55884-1.stderr @@ -18,6 +18,26 @@ LL | pub use self::m2::*; | ^^^^^^^^^^^ = help: consider adding an explicit import of `S` to disambiguate -error: aborting due to 1 previous error +error[E0659]: `S` is ambiguous + --> $DIR/issue-55884-1.rs:20:13 + | +LL | let s = S {}; + | ^ ambiguous name + | + = note: ambiguous because of multiple glob imports of a name in the same module +note: `S` could refer to the struct imported here + --> $DIR/issue-55884-1.rs:14:13 + | +LL | pub use self::m1::*; + | ^^^^^^^^^^^ + = help: consider adding an explicit import of `S` to disambiguate +note: `S` could also refer to the struct imported here + --> $DIR/issue-55884-1.rs:15:13 + | +LL | pub use self::m2::*; + | ^^^^^^^^^^^ + = help: consider adding an explicit import of `S` to disambiguate + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0659`. From 69bedd10d203edfd6559da629c78013345fa0d4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Wed, 7 Jan 2026 14:27:27 +0100 Subject: [PATCH 0390/1061] compiler-builtins: Enable AArch64 `__chkstk` for MinGW Similarly to i686 and X86_64 MinGW targets, Rust needs to provide the right chkstk symbol for AArch64 to avoid relying on the linker to provide it. CC https://github.com/rust-lang/rust/issues/150725 --- library/compiler-builtins/compiler-builtins/src/aarch64.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-builtins/src/aarch64.rs b/library/compiler-builtins/compiler-builtins/src/aarch64.rs index 039fab2061c5..1b230a214eef 100644 --- a/library/compiler-builtins/compiler-builtins/src/aarch64.rs +++ b/library/compiler-builtins/compiler-builtins/src/aarch64.rs @@ -4,7 +4,7 @@ use core::intrinsics; intrinsics! { #[unsafe(naked)] - #[cfg(target_os = "uefi")] + #[cfg(any(all(windows, target_env = "gnu"), target_os = "uefi"))] pub unsafe extern "custom" fn __chkstk() { core::arch::naked_asm!( ".p2align 2", From 64c78f6e74b885a0afaa4d6ad7d53e44033d714f Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 5 Jan 2026 19:30:41 +0100 Subject: [PATCH 0391/1061] make `MarkdownItemInfo` a field struct --- src/librustdoc/html/markdown.rs | 17 ++++++++++++----- src/librustdoc/html/markdown/tests.rs | 2 +- src/librustdoc/html/render/mod.rs | 2 +- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index a4d377432c91..834c0cb669c0 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -111,7 +111,10 @@ pub(crate) struct MarkdownWithToc<'a> { } /// A tuple struct like `Markdown` that renders the markdown escaping HTML tags /// and includes no paragraph tags. -pub(crate) struct MarkdownItemInfo<'a>(pub(crate) &'a str, pub(crate) &'a mut IdMap); +pub(crate) struct MarkdownItemInfo<'a> { + pub(crate) content: &'a str, + pub(crate) ids: &'a mut IdMap, +} /// A tuple struct like `Markdown` that renders only the first paragraph. pub(crate) struct MarkdownSummaryLine<'a>(pub &'a str, pub &'a [RenderedLink]); @@ -1459,15 +1462,19 @@ impl MarkdownWithToc<'_> { } } -impl MarkdownItemInfo<'_> { +impl<'a> MarkdownItemInfo<'a> { + pub(crate) fn new(content: &'a str, ids: &'a mut IdMap) -> Self { + Self { content, ids } + } + pub(crate) fn write_into(self, mut f: impl fmt::Write) -> fmt::Result { - let MarkdownItemInfo(md, ids) = self; + let MarkdownItemInfo { content, ids } = self; // This is actually common enough to special-case - if md.is_empty() { + if content.is_empty() { return Ok(()); } - let p = Parser::new_ext(md, main_body_opts()).into_offset_iter(); + let p = Parser::new_ext(content, main_body_opts()).into_offset_iter(); // Treat inline HTML as plain text. let p = p.map(|event| match event.0 { diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index 61fd42874633..14d86a8abf57 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -471,7 +471,7 @@ fn test_markdown_html_escape() { fn t(input: &str, expect: &str) { let mut idmap = IdMap::new(); let mut output = String::new(); - MarkdownItemInfo(input, &mut idmap).write_into(&mut output).unwrap(); + MarkdownItemInfo::new(input, &mut idmap).write_into(&mut output).unwrap(); assert_eq!(output, expect, "original: {}", input); } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 4529f5a8c016..de5c8a765275 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -877,7 +877,7 @@ fn short_item_info( if let Some(note) = note { let note = note.as_str(); let mut id_map = cx.id_map.borrow_mut(); - let html = MarkdownItemInfo(note, &mut id_map); + let html = MarkdownItemInfo::new(note, &mut id_map); message.push_str(": "); html.write_into(&mut message).unwrap(); } From 3be74a744114ed8cdfd9dcd0bada5e17ff35e662 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 6 Jan 2026 12:04:38 +0100 Subject: [PATCH 0392/1061] render intra-doc links in the `#[deprectated]` note --- compiler/rustc_ast/src/attr/mod.rs | 34 ++++++++++++++ compiler/rustc_hir/src/hir.rs | 8 ++++ compiler/rustc_resolve/src/rustdoc.rs | 13 +++++- src/librustdoc/clean/types.rs | 10 +++++ src/librustdoc/html/markdown.rs | 21 ++++++--- src/librustdoc/html/markdown/tests.rs | 2 +- src/librustdoc/html/render/mod.rs | 3 +- .../passes/collect_intra_doc_links.rs | 45 +++++++++++++------ tests/rustdoc-html/intra-doc/deprecated.rs | 12 +++++ tests/rustdoc-ui/intra-doc/deprecated.rs | 10 +++++ tests/rustdoc-ui/intra-doc/deprecated.stderr | 43 ++++++++++++++++++ 11 files changed, 179 insertions(+), 22 deletions(-) create mode 100644 tests/rustdoc-html/intra-doc/deprecated.rs create mode 100644 tests/rustdoc-ui/intra-doc/deprecated.rs create mode 100644 tests/rustdoc-ui/intra-doc/deprecated.stderr diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 6ecba865c815..0a2a34d932f6 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -235,6 +235,34 @@ impl AttributeExt for Attribute { } } + fn deprecation_note(&self) -> Option { + match &self.kind { + AttrKind::Normal(normal) if normal.item.path == sym::deprecated => { + let meta = &normal.item; + + // #[deprecated = "..."] + if let Some(s) = meta.value_str() { + return Some(s); + } + + // #[deprecated(note = "...")] + if let Some(list) = meta.meta_item_list() { + for nested in list { + if let Some(mi) = nested.meta_item() + && mi.path == sym::note + && let Some(s) = mi.value_str() + { + return Some(s); + } + } + } + + None + } + _ => None, + } + } + fn doc_resolution_scope(&self) -> Option { match &self.kind { AttrKind::DocComment(..) => Some(self.style), @@ -277,6 +305,7 @@ impl Attribute { pub fn may_have_doc_links(&self) -> bool { self.doc_str().is_some_and(|s| comments::may_have_doc_links(s.as_str())) + || self.deprecation_note().is_some_and(|s| comments::may_have_doc_links(s.as_str())) } /// Extracts the MetaItem from inside this Attribute. @@ -873,6 +902,11 @@ pub trait AttributeExt: Debug { /// * `#[doc(...)]` returns `None`. fn doc_str(&self) -> Option; + /// Returns the deprecation note if this is deprecation attribute. + /// * `#[deprecated = "note"]` returns `Some("note")`. + /// * `#[deprecated(note = "note", ...)]` returns `Some("note")`. + fn deprecation_note(&self) -> Option; + fn is_proc_macro_attr(&self) -> bool { [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive] .iter() diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index aacd6324bb03..883ba23ca214 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1400,6 +1400,14 @@ impl AttributeExt for Attribute { } } + #[inline] + fn deprecation_note(&self) -> Option { + match &self { + Attribute::Parsed(AttributeKind::Deprecation { deprecation, .. }) => deprecation.note, + _ => None, + } + } + fn is_automatically_derived_attr(&self) -> bool { matches!(self, Attribute::Parsed(AttributeKind::AutomaticallyDerived(..))) } diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 7f7c423acb40..9f74a7801d2e 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -410,8 +410,17 @@ pub fn may_be_doc_link(link_type: LinkType) -> bool { /// Simplified version of `preprocessed_markdown_links` from rustdoc. /// Must return at least the same links as it, but may add some more links on top of that. pub(crate) fn attrs_to_preprocessed_links(attrs: &[A]) -> Vec> { - let (doc_fragments, _) = attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), true); - let doc = prepare_to_doc_link_resolution(&doc_fragments).into_values().next().unwrap(); + let (doc_fragments, other_attrs) = + attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), false); + let mut doc = + prepare_to_doc_link_resolution(&doc_fragments).into_values().next().unwrap_or_default(); + + for attr in other_attrs { + if let Some(note) = attr.deprecation_note() { + doc += note.as_str(); + doc += "\n"; + } + } parse_links(&doc) } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index a390a03ff114..c3bafd3db13a 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -7,6 +7,7 @@ use std::{fmt, iter}; use arrayvec::ArrayVec; use itertools::Either; use rustc_abi::{ExternAbi, VariantIdx}; +use rustc_ast::attr::AttributeExt; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::thin_vec::ThinVec; use rustc_hir::attrs::{AttributeKind, DeprecatedSince, Deprecation, DocAttribute}; @@ -450,7 +451,16 @@ impl Item { } pub(crate) fn attr_span(&self, tcx: TyCtxt<'_>) -> rustc_span::Span { + let deprecation_notes = self + .attrs + .other_attrs + .iter() + .filter_map(|attr| attr.deprecation_note().map(|_| attr.span())); + span_of_fragments(&self.attrs.doc_strings) + .into_iter() + .chain(deprecation_notes) + .reduce(|a, b| a.to(b)) .unwrap_or_else(|| self.span(tcx).map_or(DUMMY_SP, |span| span.inner())) } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 834c0cb669c0..c472c20a7dc7 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -113,6 +113,7 @@ pub(crate) struct MarkdownWithToc<'a> { /// and includes no paragraph tags. pub(crate) struct MarkdownItemInfo<'a> { pub(crate) content: &'a str, + pub(crate) links: &'a [RenderedLink], pub(crate) ids: &'a mut IdMap, } /// A tuple struct like `Markdown` that renders only the first paragraph. @@ -1463,18 +1464,27 @@ impl MarkdownWithToc<'_> { } impl<'a> MarkdownItemInfo<'a> { - pub(crate) fn new(content: &'a str, ids: &'a mut IdMap) -> Self { - Self { content, ids } + pub(crate) fn new(content: &'a str, links: &'a [RenderedLink], ids: &'a mut IdMap) -> Self { + Self { content, links, ids } } pub(crate) fn write_into(self, mut f: impl fmt::Write) -> fmt::Result { - let MarkdownItemInfo { content, ids } = self; + let MarkdownItemInfo { content: md, links, ids } = self; // This is actually common enough to special-case - if content.is_empty() { + if md.is_empty() { return Ok(()); } - let p = Parser::new_ext(content, main_body_opts()).into_offset_iter(); + + let replacer = move |broken_link: BrokenLink<'_>| { + links + .iter() + .find(|link| *link.original_text == *broken_link.reference) + .map(|link| (link.href.as_str().into(), link.tooltip.as_str().into())) + }; + + let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(replacer)); + let p = p.into_offset_iter(); // Treat inline HTML as plain text. let p = p.map(|event| match event.0 { @@ -1484,6 +1494,7 @@ impl<'a> MarkdownItemInfo<'a> { ids.handle_footnotes(|ids, existing_footnotes| { let p = HeadingLinks::new(p, None, ids, HeadingOffset::H1); + let p = SpannedLinkReplacer::new(p, links); let p = footnotes::Footnotes::new(p, existing_footnotes); let p = TableWrapper::new(p.map(|(ev, _)| ev)); let p = p.filter(|event| { diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index 14d86a8abf57..1c99ccc5228b 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -471,7 +471,7 @@ fn test_markdown_html_escape() { fn t(input: &str, expect: &str) { let mut idmap = IdMap::new(); let mut output = String::new(); - MarkdownItemInfo::new(input, &mut idmap).write_into(&mut output).unwrap(); + MarkdownItemInfo::new(input, &[], &mut idmap).write_into(&mut output).unwrap(); assert_eq!(output, expect, "original: {}", input); } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index de5c8a765275..63de870f07f4 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -877,7 +877,8 @@ fn short_item_info( if let Some(note) = note { let note = note.as_str(); let mut id_map = cx.id_map.borrow_mut(); - let html = MarkdownItemInfo::new(note, &mut id_map); + let links = item.links(cx); + let html = MarkdownItemInfo::new(note, &links, &mut id_map); message.push_str(": "); html.write_into(&mut message).unwrap(); } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 3abf0fee3959..07d6efaa97e1 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -7,6 +7,7 @@ use std::fmt::Display; use std::mem; use std::ops::Range; +use rustc_ast::attr::AttributeExt; use rustc_ast::util::comments::may_have_doc_links; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; @@ -1047,18 +1048,7 @@ impl LinkCollector<'_, '_> { return; } - // We want to resolve in the lexical scope of the documentation. - // In the presence of re-exports, this is not the same as the module of the item. - // Rather than merging all documentation into one, resolve it one attribute at a time - // so we know which module it came from. - for (item_id, doc) in prepare_to_doc_link_resolution(&item.attrs.doc_strings) { - if !may_have_doc_links(&doc) { - continue; - } - debug!("combined_docs={doc}"); - // NOTE: if there are links that start in one crate and end in another, this will not resolve them. - // This is a degenerate case and it's not supported by rustdoc. - let item_id = item_id.unwrap_or_else(|| item.item_id.expect_def_id()); + let mut insert_links = |item_id, doc: &str| { let module_id = match self.cx.tcx.def_kind(item_id) { DefKind::Mod if item.inner_docs(self.cx.tcx) => item_id, _ => find_nearest_parent_module(self.cx.tcx, item_id).unwrap(), @@ -1074,6 +1064,35 @@ impl LinkCollector<'_, '_> { .insert(link); } } + }; + + // We want to resolve in the lexical scope of the documentation. + // In the presence of re-exports, this is not the same as the module of the item. + // Rather than merging all documentation into one, resolve it one attribute at a time + // so we know which module it came from. + for (item_id, doc) in prepare_to_doc_link_resolution(&item.attrs.doc_strings) { + if !may_have_doc_links(&doc) { + continue; + } + + debug!("combined_docs={doc}"); + // NOTE: if there are links that start in one crate and end in another, this will not resolve them. + // This is a degenerate case and it's not supported by rustdoc. + let item_id = item_id.unwrap_or_else(|| item.item_id.expect_def_id()); + insert_links(item_id, &doc) + } + + // Also resolve links in the note text of `#[deprecated]`. + for attr in &item.attrs.other_attrs { + let Some(note_sym) = attr.deprecation_note() else { continue }; + let note = note_sym.as_str(); + + if !may_have_doc_links(note) { + continue; + } + + debug!("deprecated_note={note}"); + insert_links(item.item_id.expect_def_id(), note) } } @@ -1086,7 +1105,7 @@ impl LinkCollector<'_, '_> { /// FIXME(jynelson): this is way too many arguments fn resolve_link( &mut self, - dox: &String, + dox: &str, item: &Item, item_id: DefId, module_id: DefId, diff --git a/tests/rustdoc-html/intra-doc/deprecated.rs b/tests/rustdoc-html/intra-doc/deprecated.rs new file mode 100644 index 000000000000..6f8639593a2d --- /dev/null +++ b/tests/rustdoc-html/intra-doc/deprecated.rs @@ -0,0 +1,12 @@ +//@ has deprecated/struct.A.html '//a[@href="{{channel}}/core/ops/range/struct.Range.html#structfield.start"]' 'start' +//@ has deprecated/struct.B1.html '//a[@href="{{channel}}/std/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found' +//@ has deprecated/struct.B2.html '//a[@href="{{channel}}/std/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found' + +#[deprecated = "[start][std::ops::Range::start]"] +pub struct A; + +#[deprecated(since = "0.0.0", note = "[not_found][std::io::ErrorKind::NotFound]")] +pub struct B1; + +#[deprecated(note = "[not_found][std::io::ErrorKind::NotFound]", since = "0.0.0")] +pub struct B2; diff --git a/tests/rustdoc-ui/intra-doc/deprecated.rs b/tests/rustdoc-ui/intra-doc/deprecated.rs new file mode 100644 index 000000000000..37c27dcde598 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/deprecated.rs @@ -0,0 +1,10 @@ +#![deny(rustdoc::broken_intra_doc_links)] + +#[deprecated = "[broken cross-reference](TypeAlias::hoge)"] //~ ERROR +pub struct A; + +#[deprecated(since = "0.0.0", note = "[broken cross-reference](TypeAlias::hoge)")] //~ ERROR +pub struct B1; + +#[deprecated(note = "[broken cross-reference](TypeAlias::hoge)", since = "0.0.0")] //~ ERROR +pub struct B2; diff --git a/tests/rustdoc-ui/intra-doc/deprecated.stderr b/tests/rustdoc-ui/intra-doc/deprecated.stderr new file mode 100644 index 000000000000..9bd64544eef8 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/deprecated.stderr @@ -0,0 +1,43 @@ +error: unresolved link to `TypeAlias::hoge` + --> $DIR/deprecated.rs:3:1 + | +LL | #[deprecated = "[broken cross-reference](TypeAlias::hoge)"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the link appears in this line: + + [broken cross-reference](TypeAlias::hoge) + ^^^^^^^^^^^^^^^ + = note: no item named `TypeAlias` in scope +note: the lint level is defined here + --> $DIR/deprecated.rs:1:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unresolved link to `TypeAlias::hoge` + --> $DIR/deprecated.rs:6:1 + | +LL | #[deprecated(since = "0.0.0", note = "[broken cross-reference](TypeAlias::hoge)")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the link appears in this line: + + [broken cross-reference](TypeAlias::hoge) + ^^^^^^^^^^^^^^^ + = note: no item named `TypeAlias` in scope + +error: unresolved link to `TypeAlias::hoge` + --> $DIR/deprecated.rs:9:1 + | +LL | #[deprecated(note = "[broken cross-reference](TypeAlias::hoge)", since = "0.0.0")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the link appears in this line: + + [broken cross-reference](TypeAlias::hoge) + ^^^^^^^^^^^^^^^ + = note: no item named `TypeAlias` in scope + +error: aborting due to 3 previous errors + From aec8b698784311402bd193497a26357297d105bc Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 7 Jan 2026 16:26:52 +0000 Subject: [PATCH 0393/1061] Minor cleanups to fn_abi_new_uncached --- compiler/rustc_target/src/callconv/mod.rs | 11 +++++------ compiler/rustc_ty_utils/src/abi.rs | 12 +++--------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 092d99e91118..6faa57252ca2 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -381,15 +381,14 @@ impl<'a, Ty> ArgAbi<'a, Ty> { pub fn new( cx: &impl HasDataLayout, layout: TyAndLayout<'a, Ty>, - scalar_attrs: impl Fn(&TyAndLayout<'a, Ty>, Scalar, Size) -> ArgAttributes, + scalar_attrs: impl Fn(Scalar, Size) -> ArgAttributes, ) -> Self { let mode = match layout.backend_repr { - BackendRepr::Scalar(scalar) => { - PassMode::Direct(scalar_attrs(&layout, scalar, Size::ZERO)) - } + _ if layout.is_zst() => PassMode::Ignore, + BackendRepr::Scalar(scalar) => PassMode::Direct(scalar_attrs(scalar, Size::ZERO)), BackendRepr::ScalarPair(a, b) => PassMode::Pair( - scalar_attrs(&layout, a, Size::ZERO), - scalar_attrs(&layout, b, a.size(cx).align_to(b.align(cx).abi)), + scalar_attrs(a, Size::ZERO), + scalar_attrs(b, a.size(cx).align_to(b.align(cx).abi)), ), BackendRepr::SimdVector { .. } => PassMode::Direct(ArgAttributes::new()), BackendRepr::Memory { .. } => Self::indirect_pass_mode(&layout), diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 0676fa99d826..ad621c67772c 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -549,15 +549,9 @@ fn fn_abi_new_uncached<'tcx>( layout }; - let mut arg = ArgAbi::new(cx, layout, |layout, scalar, offset| { - arg_attrs_for_rust_scalar(*cx, scalar, *layout, offset, is_return, drop_target_pointee) - }); - - if arg.layout.is_zst() { - arg.mode = PassMode::Ignore; - } - - Ok(arg) + Ok(ArgAbi::new(cx, layout, |scalar, offset| { + arg_attrs_for_rust_scalar(*cx, scalar, layout, offset, is_return, drop_target_pointee) + })) }; let mut fn_abi = FnAbi { From a3359bdd4f117b6f315fce15e1d97d02c7bad015 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 12 Mar 2025 10:26:37 +0000 Subject: [PATCH 0394/1061] Compile-Time Reflection MVP: tuples --- .../src/const_eval/machine.rs | 9 +- .../rustc_const_eval/src/const_eval/mod.rs | 1 + .../src/const_eval/type_info.rs | 158 ++++++++++++++++++ .../src/interpret/intrinsics.rs | 5 +- compiler/rustc_hir/src/lang_items.rs | 1 + .../rustc_hir_analysis/src/check/intrinsic.rs | 18 +- compiler/rustc_span/src/symbol.rs | 5 + library/core/src/intrinsics/mod.rs | 9 + library/core/src/lib.rs | 1 + library/core/src/mem/mod.rs | 3 + library/core/src/mem/type_info.rs | 69 ++++++++ src/tools/clippy/clippy_utils/src/sym.rs | 1 - .../abi/issues/issue-22565-rust-call.stderr | 4 +- tests/ui/error-codes/E0059.stderr | 4 +- tests/ui/impl-trait/where-allowed.stderr | 6 +- ...rust-call-abi-not-a-tuple-ice-81974.stderr | 16 +- .../overloaded-calls-nontuple.stderr | 12 +- tests/ui/reflection/dump.rs | 30 ++++ tests/ui/reflection/dump.run.stdout | 23 +++ tests/ui/reflection/feature_gate.rs | 8 + tests/ui/reflection/feature_gate.stderr | 33 ++++ tests/ui/reflection/tuples.rs | 36 ++++ .../resolve/resolve-assoc-suggestions.stderr | 4 + tests/ui/suggestions/fn-trait-notation.stderr | 4 +- tests/ui/thir-print/offset_of.stdout | 18 +- tests/ui/traits/ignore-err-impls.stderr | 6 +- .../next-solver/well-formed-in-relate.stderr | 6 +- tests/ui/tuple/builtin-fail.stderr | 8 +- tests/ui/typeck/issue-57404.stderr | 2 +- .../non-tupled-arg-mismatch.stderr | 2 +- triagebot.toml | 7 + 31 files changed, 456 insertions(+), 53 deletions(-) create mode 100644 compiler/rustc_const_eval/src/const_eval/type_info.rs create mode 100644 library/core/src/mem/type_info.rs create mode 100644 tests/ui/reflection/dump.rs create mode 100644 tests/ui/reflection/dump.run.stdout create mode 100644 tests/ui/reflection/feature_gate.rs create mode 100644 tests/ui/reflection/feature_gate.stderr create mode 100644 tests/ui/reflection/tuples.rs diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 7538130e9d92..719187b99012 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -8,7 +8,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, CRATE_HIR_ID, LangItem}; use rustc_middle::mir::AssertMessage; -use rustc_middle::mir::interpret::ReportedErrorInfo; +use rustc_middle::mir::interpret::{Pointer, ReportedErrorInfo}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout, ValidityRequirement}; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -22,7 +22,7 @@ use crate::errors::{LongRunning, LongRunningWarn}; use crate::fluent_generated as fluent; use crate::interpret::{ self, AllocId, AllocInit, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame, - GlobalAlloc, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, Pointer, RangeSet, Scalar, + GlobalAlloc, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, RangeSet, Scalar, compile_time_machine, err_inval, interp_ok, throw_exhaust, throw_inval, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format, }; @@ -586,6 +586,11 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { } } + sym::type_of => { + let ty = ecx.read_type_id(&args[0])?; + ecx.write_type_info(ty, dest)?; + } + _ => { // We haven't handled the intrinsic, let's see if we can use a fallback body. if ecx.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden { diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index 624ca1dd2da0..e70488b81c4c 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -13,6 +13,7 @@ mod error; mod eval_queries; mod fn_queries; mod machine; +mod type_info; mod valtrees; pub use self::dummy_machine::*; diff --git a/compiler/rustc_const_eval/src/const_eval/type_info.rs b/compiler/rustc_const_eval/src/const_eval/type_info.rs new file mode 100644 index 000000000000..a94ef580027b --- /dev/null +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -0,0 +1,158 @@ +use rustc_abi::FieldIdx; +use rustc_hir::LangItem; +use rustc_middle::mir::interpret::CtfeProvenance; +use rustc_middle::span_bug; +use rustc_middle::ty::layout::TyAndLayout; +use rustc_middle::ty::{self, ScalarInt, Ty}; +use rustc_span::{Symbol, sym}; + +use crate::const_eval::CompileTimeMachine; +use crate::interpret::{ + Immediate, InterpCx, InterpResult, MPlaceTy, MemoryKind, Writeable, interp_ok, +}; + +impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { + /// Writes a `core::mem::type_info::TypeInfo` for a given type, `ty` to the given place. + pub(crate) fn write_type_info( + &mut self, + ty: Ty<'tcx>, + dest: &impl Writeable<'tcx, CtfeProvenance>, + ) -> InterpResult<'tcx> { + let ty_struct = self.tcx.require_lang_item(LangItem::Type, self.tcx.span); + let ty_struct = self.tcx.type_of(ty_struct).no_bound_vars().unwrap(); + assert_eq!(ty_struct, dest.layout().ty); + let ty_struct = ty_struct.ty_adt_def().unwrap().non_enum_variant(); + // Fill all fields of the `TypeInfo` struct. + for (idx, field) in ty_struct.fields.iter_enumerated() { + let field_dest = self.project_field(dest, idx)?; + let downcast = |name: Symbol| { + let variants = field_dest.layout().ty.ty_adt_def().unwrap().variants(); + let variant_id = variants + .iter_enumerated() + .find(|(_idx, var)| var.name == name) + .unwrap_or_else(|| panic!("got {name} but expected one of {variants:#?}")) + .0; + + interp_ok((variant_id, self.project_downcast(&field_dest, variant_id)?)) + }; + match field.name { + sym::kind => { + let variant_index = match ty.kind() { + ty::Tuple(fields) => { + let (variant, variant_place) = downcast(sym::Tuple)?; + // project to the single tuple variant field of `type_info::Tuple` struct type + let tuple_place = self.project_field(&variant_place, FieldIdx::ZERO)?; + assert_eq!( + 1, + tuple_place + .layout() + .ty + .ty_adt_def() + .unwrap() + .non_enum_variant() + .fields + .len() + ); + self.write_tuple_fields(tuple_place, fields, ty)?; + variant + } + // For now just merge all primitives into one `Leaf` variant with no data + ty::Uint(_) | ty::Int(_) | ty::Float(_) | ty::Char | ty::Bool => { + downcast(sym::Leaf)?.0 + } + ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Pat(_, _) + | ty::Slice(_) + | ty::RawPtr(..) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::UnsafeBinder(..) + | ty::Dynamic(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Never + | ty::Alias(..) + | ty::Param(_) + | ty::Bound(..) + | ty::Placeholder(_) + | ty::Infer(..) + | ty::Error(_) => downcast(sym::Other)?.0, + }; + self.write_discriminant(variant_index, &field_dest)? + } + other => span_bug!(self.tcx.span, "unknown `Type` field {other}"), + } + } + + interp_ok(()) + } + + pub(crate) fn write_tuple_fields( + &mut self, + tuple_place: impl Writeable<'tcx, CtfeProvenance>, + fields: &[Ty<'tcx>], + tuple_ty: Ty<'tcx>, + ) -> InterpResult<'tcx> { + // project into the `type_info::Tuple::fields` field + let fields_slice_place = self.project_field(&tuple_place, FieldIdx::ZERO)?; + // get the `type_info::Field` type from `fields: &[Field]` + let field_type = fields_slice_place + .layout() + .ty + .builtin_deref(false) + .unwrap() + .sequence_element_type(self.tcx.tcx); + // Create an array with as many elements as the number of fields in the inspected tuple + let fields_layout = + self.layout_of(Ty::new_array(self.tcx.tcx, field_type, fields.len() as u64))?; + let fields_place = self.allocate(fields_layout, MemoryKind::Stack)?; + let mut fields_places = self.project_array_fields(&fields_place)?; + + let tuple_layout = self.layout_of(tuple_ty)?; + + while let Some((i, place)) = fields_places.next(self)? { + let field_ty = fields[i as usize]; + self.write_field(field_ty, place, tuple_layout, i)?; + } + + let fields_place = fields_place.map_provenance(CtfeProvenance::as_immutable); + + let ptr = Immediate::new_slice(fields_place.ptr(), fields.len() as u64, self); + + self.write_immediate(ptr, &fields_slice_place) + } + + fn write_field( + &mut self, + field_ty: Ty<'tcx>, + place: MPlaceTy<'tcx>, + layout: TyAndLayout<'tcx>, + idx: u64, + ) -> InterpResult<'tcx> { + for (field_idx, field_ty_field) in + place.layout.ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated() + { + let field_place = self.project_field(&place, field_idx)?; + match field_ty_field.name { + sym::ty => self.write_type_id(field_ty, &field_place)?, + sym::offset => { + let offset = layout.fields.offset(idx as usize); + self.write_scalar( + ScalarInt::try_from_target_usize(offset.bytes(), self.tcx.tcx).unwrap(), + &field_place, + )?; + } + other => { + span_bug!(self.tcx.def_span(field_ty_field.did), "unimplemented field {other}") + } + } + } + interp_ok(()) + } +} diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index d70d157d8808..94832c0c2577 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -27,6 +27,7 @@ use super::{ throw_ub_custom, throw_ub_format, }; use crate::fluent_generated as fluent; +use crate::interpret::Writeable; #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum MulAddType { @@ -68,10 +69,10 @@ pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> (AllocId } impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Generates a value of `TypeId` for `ty` in-place. - fn write_type_id( + pub(crate) fn write_type_id( &mut self, ty: Ty<'tcx>, - dest: &PlaceTy<'tcx, M::Provenance>, + dest: &impl Writeable<'tcx, M::Provenance>, ) -> InterpResult<'tcx, ()> { let tcx = self.tcx; let type_id_hash = tcx.type_id_hash(ty).as_u128(); diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 4ac3e4e83e80..557f76208bfe 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -278,6 +278,7 @@ language_item_table! { PartialOrd, sym::partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1); CVoid, sym::c_void, c_void, Target::Enum, GenericRequirement::None; + Type, sym::type_info, type_struct, Target::Struct, GenericRequirement::None; TypeId, sym::type_id, type_id, Target::Struct, GenericRequirement::None; // A number of panic-related lang items. The `panic` item corresponds to divide-by-zero and diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 9eaf5319cb04..c84c1a8ca16d 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -213,6 +213,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::type_id | sym::type_id_eq | sym::type_name + | sym::type_of | sym::ub_checks | sym::variant_count | sym::vtable_for @@ -308,13 +309,22 @@ pub(crate) fn check_intrinsic_type( sym::needs_drop => (1, 0, vec![], tcx.types.bool), sym::type_name => (1, 0, vec![], Ty::new_static_str(tcx)), - sym::type_id => { - (1, 0, vec![], tcx.type_of(tcx.lang_items().type_id().unwrap()).instantiate_identity()) - } + sym::type_id => ( + 1, + 0, + vec![], + tcx.type_of(tcx.lang_items().type_id().unwrap()).no_bound_vars().unwrap(), + ), sym::type_id_eq => { - let type_id = tcx.type_of(tcx.lang_items().type_id().unwrap()).instantiate_identity(); + let type_id = tcx.type_of(tcx.lang_items().type_id().unwrap()).no_bound_vars().unwrap(); (0, 0, vec![type_id, type_id], tcx.types.bool) } + sym::type_of => ( + 0, + 0, + vec![tcx.type_of(tcx.lang_items().type_id().unwrap()).no_bound_vars().unwrap()], + tcx.type_of(tcx.lang_items().type_struct().unwrap()).no_bound_vars().unwrap(), + ), sym::offload => ( 3, 0, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 72709753b1df..1e288adc11cb 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -284,6 +284,7 @@ symbols! { IteratorItem, IteratorMap, Layout, + Leaf, Left, LinkedList, LintDiagnostic, @@ -302,6 +303,7 @@ symbols! { Ordering, OsStr, OsString, + Other, Output, Param, ParamSet, @@ -380,6 +382,7 @@ symbols! { TryCapturePrintable, TryFrom, TryInto, + Tuple, Ty, TyCtxt, TyKind, @@ -2317,6 +2320,7 @@ symbols! { type_const, type_id, type_id_eq, + type_info, type_ir, type_ir_infer_ctxt_like, type_ir_inherent, @@ -2324,6 +2328,7 @@ symbols! { type_length_limit, type_macros, type_name, + type_of, type_privacy_lints, typed_swap_nonoverlapping, u8, diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 0ae8d3d4a4ce..e8e0cda38e9b 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2849,6 +2849,15 @@ pub const unsafe fn size_of_val(ptr: *const T) -> usize; #[rustc_intrinsic_const_stable_indirect] pub const unsafe fn align_of_val(ptr: *const T) -> usize; +/// Compute the type information of a concrete type. +/// It can only be called at compile time, the backends do +/// not implement it. +#[rustc_intrinsic] +#[unstable(feature = "core_intrinsics", issue = "none")] +pub const fn type_of(_id: crate::any::TypeId) -> crate::mem::type_info::Type { + panic!("`TypeId::info` can only be called at compile-time") +} + /// Gets a static string slice containing the name of a type. /// /// Note that, unlike most intrinsics, this can only be called at compile-time diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 962b0cea4a4f..dfc9a7b5dbc3 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -124,6 +124,7 @@ #![feature(str_internals)] #![feature(str_split_inclusive_remainder)] #![feature(str_split_remainder)] +#![feature(type_info)] #![feature(ub_checks)] #![feature(unsafe_pinned)] #![feature(utf16_extra)] diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 4f7edce1e977..1671c8219de1 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -37,6 +37,9 @@ pub use drop_guard::DropGuard; #[doc(inline)] pub use crate::intrinsics::transmute; +#[unstable(feature = "type_info", issue = "146922")] +pub mod type_info; + /// Takes ownership and "forgets" about the value **without running its destructor**. /// /// Any resources the value manages, such as heap memory or a file handle, will linger diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs new file mode 100644 index 000000000000..b188504f76d9 --- /dev/null +++ b/library/core/src/mem/type_info.rs @@ -0,0 +1,69 @@ +//! MVP for exposing compile-time information about types in a +//! runtime or const-eval processable way. + +use crate::any::TypeId; +use crate::intrinsics::type_of; + +/// Compile-time type information. +#[derive(Debug)] +#[non_exhaustive] +#[lang = "type_info"] +#[unstable(feature = "type_info", issue = "146922")] +pub struct Type { + /// Per-type information + pub kind: TypeKind, +} + +impl TypeId { + /// Compute the type information of a concrete type. + /// It can only be called at compile time. + #[unstable(feature = "type_info", issue = "146922")] + #[rustc_const_unstable(feature = "type_info", issue = "146922")] + pub const fn info(self) -> Type { + type_of(self) + } +} + +impl Type { + /// Returns the type information of the generic type parameter. + #[unstable(feature = "type_info", issue = "146922")] + #[rustc_const_unstable(feature = "type_info", issue = "146922")] + // FIXME(reflection): don't require the 'static bound + pub const fn of() -> Self { + const { TypeId::of::().info() } + } +} + +/// Compile-time type information. +#[derive(Debug)] +#[non_exhaustive] +#[unstable(feature = "type_info", issue = "146922")] +pub enum TypeKind { + /// Tuples. + Tuple(Tuple), + /// Primitives + /// FIXME(#146922): disambiguate further + Leaf, + /// FIXME(#146922): add all the common types + Other, +} + +/// Compile-time type information about tuples. +#[derive(Debug)] +#[non_exhaustive] +#[unstable(feature = "type_info", issue = "146922")] +pub struct Tuple { + /// All fields of a tuple. + pub fields: &'static [Field], +} + +/// Compile-time type information about fields of tuples, structs and enum variants. +#[derive(Debug)] +#[non_exhaustive] +#[unstable(feature = "type_info", issue = "146922")] +pub struct Field { + /// The field's type. + pub ty: TypeId, + /// Offset in bytes from the parent type + pub offset: usize, +} diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs index a0d2e8673fe6..74f89cfc6811 100644 --- a/src/tools/clippy/clippy_utils/src/sym.rs +++ b/src/tools/clippy/clippy_utils/src/sym.rs @@ -62,7 +62,6 @@ generate! { MsrvStack, Octal, OpenOptions, - Other, PathLookup, Regex, RegexBuilder, diff --git a/tests/ui/abi/issues/issue-22565-rust-call.stderr b/tests/ui/abi/issues/issue-22565-rust-call.stderr index 0fd3285cd3a5..3e296bdaea41 100644 --- a/tests/ui/abi/issues/issue-22565-rust-call.stderr +++ b/tests/ui/abi/issues/issue-22565-rust-call.stderr @@ -2,7 +2,7 @@ error[E0277]: functions with the "rust-call" ABI must take a single non-self tup --> $DIR/issue-22565-rust-call.rs:3:1 | LL | extern "rust-call" fn b(_i: i32) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `i32` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `i32` error: functions with the "rust-call" ABI must take a single non-self tuple argument --> $DIR/issue-22565-rust-call.rs:17:5 @@ -32,7 +32,7 @@ error[E0277]: functions with the "rust-call" ABI must take a single non-self tup --> $DIR/issue-22565-rust-call.rs:27:7 | LL | b(10); - | ^^ the trait `Tuple` is not implemented for `i32` + | ^^ the trait `std::marker::Tuple` is not implemented for `i32` error: functions with the "rust-call" ABI must take a single non-self tuple argument --> $DIR/issue-22565-rust-call.rs:29:5 diff --git a/tests/ui/error-codes/E0059.stderr b/tests/ui/error-codes/E0059.stderr index d26fadcdbfa7..698ee0a2a902 100644 --- a/tests/ui/error-codes/E0059.stderr +++ b/tests/ui/error-codes/E0059.stderr @@ -2,7 +2,7 @@ error[E0059]: type parameter to bare `Fn` trait must be a tuple --> $DIR/E0059.rs:3:11 | LL | fn foo>(f: F) -> F::Output { f(3) } - | ^^^^^^^ the trait `Tuple` is not implemented for `i32` + | ^^^^^^^ the trait `std::marker::Tuple` is not implemented for `i32` | note: required by a bound in `Fn` --> $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -11,7 +11,7 @@ error[E0277]: `i32` is not a tuple --> $DIR/E0059.rs:3:41 | LL | fn foo>(f: F) -> F::Output { f(3) } - | ^^^^ the trait `Tuple` is not implemented for `i32` + | ^^^^ the trait `std::marker::Tuple` is not implemented for `i32` error[E0059]: cannot use call notation; the first type parameter for the function trait is neither a tuple nor unit --> $DIR/E0059.rs:3:41 diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr index 6cab4fabb1ff..1a8d6509e137 100644 --- a/tests/ui/impl-trait/where-allowed.stderr +++ b/tests/ui/impl-trait/where-allowed.stderr @@ -384,11 +384,11 @@ LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { pani | = note: multiple `impl`s satisfying `_: Fn()` found in the following crates: `alloc`, `core`: - impl Fn for &F - where A: Tuple, F: Fn, F: ?Sized; + where A: std::marker::Tuple, F: Fn, F: ?Sized; - impl Fn for Box - where Args: Tuple, F: Fn, A: Allocator, F: ?Sized; + where Args: std::marker::Tuple, F: Fn, A: Allocator, F: ?Sized; - impl Fn for Exclusive - where F: Sync, F: Fn, Args: Tuple; + where F: Sync, F: Fn, Args: std::marker::Tuple; error[E0118]: no nominal type found for inherent implementation --> $DIR/where-allowed.rs:241:1 diff --git a/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.stderr b/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.stderr index 75ee936d9e8b..e7cb82687fa7 100644 --- a/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.stderr +++ b/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.stderr @@ -2,7 +2,7 @@ error[E0059]: type parameter to bare `FnOnce` trait must be a tuple --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:31:5 | LL | extern "rust-call" fn call_once(mut self, a: A) -> Self::Output { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `A` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `A` | note: required by a bound in `FnOnce` --> $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -15,7 +15,7 @@ error[E0059]: type parameter to bare `FnOnce` trait must be a tuple --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:24:12 | LL | impl FnOnce for CachedFun - | ^^^^^^^^^ the trait `Tuple` is not implemented for `A` + | ^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `A` | note: required by a bound in `FnOnce` --> $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -28,7 +28,7 @@ error[E0059]: type parameter to bare `FnOnce` trait must be a tuple --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:45:5 | LL | extern "rust-call" fn call_mut(&mut self, a: A) -> Self::Output { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `A` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `A` | note: required by a bound in `FnOnce` --> $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -41,7 +41,7 @@ error[E0059]: type parameter to bare `FnMut` trait must be a tuple --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:39:12 | LL | impl FnMut for CachedFun - | ^^^^^^^^ the trait `Tuple` is not implemented for `A` + | ^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `A` | note: required by a bound in `FnMut` --> $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -54,7 +54,7 @@ error[E0277]: functions with the "rust-call" ABI must take a single non-self tup --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:31:5 | LL | extern "rust-call" fn call_once(mut self, a: A) -> Self::Output { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `A` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `A` | help: consider further restricting type parameter `A` with unstable trait `Tuple` | @@ -65,7 +65,7 @@ error[E0277]: functions with the "rust-call" ABI must take a single non-self tup --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:45:5 | LL | extern "rust-call" fn call_mut(&mut self, a: A) -> Self::Output { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `A` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `A` | help: consider further restricting type parameter `A` with unstable trait `Tuple` | @@ -76,7 +76,7 @@ error[E0277]: `A` is not a tuple --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:34:19 | LL | self.call_mut(a) - | -------- ^ the trait `Tuple` is not implemented for `A` + | -------- ^ the trait `std::marker::Tuple` is not implemented for `A` | | | required by a bound introduced by this call | @@ -91,7 +91,7 @@ error[E0277]: `i32` is not a tuple --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:59:26 | LL | cachedcoso.call_once(1); - | --------- ^ the trait `Tuple` is not implemented for `i32` + | --------- ^ the trait `std::marker::Tuple` is not implemented for `i32` | | | required by a bound introduced by this call | diff --git a/tests/ui/overloaded/overloaded-calls-nontuple.stderr b/tests/ui/overloaded/overloaded-calls-nontuple.stderr index 22598f3a3901..54a9d1f09b52 100644 --- a/tests/ui/overloaded/overloaded-calls-nontuple.stderr +++ b/tests/ui/overloaded/overloaded-calls-nontuple.stderr @@ -2,7 +2,7 @@ error[E0059]: type parameter to bare `FnMut` trait must be a tuple --> $DIR/overloaded-calls-nontuple.rs:10:6 | LL | impl FnMut for S { - | ^^^^^^^^^^^^ the trait `Tuple` is not implemented for `isize` + | ^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `isize` | note: required by a bound in `FnMut` --> $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -11,7 +11,7 @@ error[E0059]: type parameter to bare `FnOnce` trait must be a tuple --> $DIR/overloaded-calls-nontuple.rs:18:6 | LL | impl FnOnce for S { - | ^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `isize` + | ^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `isize` | note: required by a bound in `FnOnce` --> $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -20,19 +20,19 @@ error[E0277]: functions with the "rust-call" ABI must take a single non-self tup --> $DIR/overloaded-calls-nontuple.rs:12:5 | LL | extern "rust-call" fn call_mut(&mut self, z: isize) -> isize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `isize` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `isize` error[E0277]: functions with the "rust-call" ABI must take a single non-self tuple argument --> $DIR/overloaded-calls-nontuple.rs:21:5 | LL | extern "rust-call" fn call_once(mut self, z: isize) -> isize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `isize` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `isize` error[E0277]: `isize` is not a tuple --> $DIR/overloaded-calls-nontuple.rs:23:23 | LL | self.call_mut(z) - | -------- ^ the trait `Tuple` is not implemented for `isize` + | -------- ^ the trait `std::marker::Tuple` is not implemented for `isize` | | | required by a bound introduced by this call | @@ -53,7 +53,7 @@ error[E0277]: `isize` is not a tuple --> $DIR/overloaded-calls-nontuple.rs:29:10 | LL | drop(s(3)) - | ^^^^ the trait `Tuple` is not implemented for `isize` + | ^^^^ the trait `std::marker::Tuple` is not implemented for `isize` error: aborting due to 7 previous errors diff --git a/tests/ui/reflection/dump.rs b/tests/ui/reflection/dump.rs new file mode 100644 index 000000000000..3bf4f32b6641 --- /dev/null +++ b/tests/ui/reflection/dump.rs @@ -0,0 +1,30 @@ +#![feature(type_info)] +//@ run-pass +//@ check-run-results +#![allow(dead_code)] + +use std::mem::type_info::Type; + +struct Foo { + a: u32, +} + +enum Bar { + Some(u32), + None, + Foomp { a: (), b: &'static str }, +} + +struct Unsized { + x: u16, + s: str, +} + +fn main() { + println!("{:#?}", const { Type::of::<(u8, u8, ())>() }.kind); + println!("{:#?}", const { Type::of::() }.kind); + println!("{:#?}", const { Type::of::() }.kind); + println!("{:#?}", const { Type::of::<&Unsized>() }.kind); + println!("{:#?}", const { Type::of::<&str>() }.kind); + println!("{:#?}", const { Type::of::<&[u8]>() }.kind); +} diff --git a/tests/ui/reflection/dump.run.stdout b/tests/ui/reflection/dump.run.stdout new file mode 100644 index 000000000000..71fd80b46658 --- /dev/null +++ b/tests/ui/reflection/dump.run.stdout @@ -0,0 +1,23 @@ +Tuple( + Tuple { + fields: [ + Field { + ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), + offset: 0, + }, + Field { + ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), + offset: 1, + }, + Field { + ty: TypeId(0x41223169ff28813ba79b7268a2a968d9), + offset: 2, + }, + ], + }, +) +Other +Other +Other +Other +Other diff --git a/tests/ui/reflection/feature_gate.rs b/tests/ui/reflection/feature_gate.rs new file mode 100644 index 000000000000..2dde26809793 --- /dev/null +++ b/tests/ui/reflection/feature_gate.rs @@ -0,0 +1,8 @@ +use std::mem::type_info::Type; +//~^ ERROR: use of unstable library feature `type_info` + +fn main() { + let ty = std::mem::type_info::Type::of::<()>(); + //~^ ERROR: use of unstable library feature `type_info` + //~| ERROR: use of unstable library feature `type_info` +} diff --git a/tests/ui/reflection/feature_gate.stderr b/tests/ui/reflection/feature_gate.stderr new file mode 100644 index 000000000000..76ad18ffb0ba --- /dev/null +++ b/tests/ui/reflection/feature_gate.stderr @@ -0,0 +1,33 @@ +error[E0658]: use of unstable library feature `type_info` + --> $DIR/feature_gate.rs:1:5 + | +LL | use std::mem::type_info::Type; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #146922 for more information + = help: add `#![feature(type_info)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature `type_info` + --> $DIR/feature_gate.rs:5:14 + | +LL | let ty = std::mem::type_info::Type::of::<()>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #146922 for more information + = help: add `#![feature(type_info)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature `type_info` + --> $DIR/feature_gate.rs:5:14 + | +LL | let ty = std::mem::type_info::Type::of::<()>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #146922 for more information + = help: add `#![feature(type_info)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/reflection/tuples.rs b/tests/ui/reflection/tuples.rs new file mode 100644 index 000000000000..eab25a691efe --- /dev/null +++ b/tests/ui/reflection/tuples.rs @@ -0,0 +1,36 @@ +#![feature(type_info)] + +//@ run-pass + +use std::mem::type_info::{Type, TypeKind}; + +fn assert_tuple_arity() { + const { + match &Type::of::().kind { + TypeKind::Tuple(tup) => { + assert!(tup.fields.len() == N); + } + _ => unreachable!(), + } + } +} + +fn main() { + assert_tuple_arity::<(), 0>(); + assert_tuple_arity::<(u8,), 1>(); + assert_tuple_arity::<(u8, u8), 2>(); + const { + match &Type::of::<(u8, u8)>().kind { + TypeKind::Tuple(tup) => { + let [a, b] = tup.fields else { unreachable!() }; + assert!(a.offset == 0); + assert!(b.offset == 1); + match (&a.ty.info().kind, &b.ty.info().kind) { + (TypeKind::Leaf, TypeKind::Leaf) => {} + _ => unreachable!(), + } + } + _ => unreachable!(), + } + } +} diff --git a/tests/ui/resolve/resolve-assoc-suggestions.stderr b/tests/ui/resolve/resolve-assoc-suggestions.stderr index ef519ac0d921..7d94fb5ca35f 100644 --- a/tests/ui/resolve/resolve-assoc-suggestions.stderr +++ b/tests/ui/resolve/resolve-assoc-suggestions.stderr @@ -31,6 +31,10 @@ help: you might have meant to use the associated type | LL | let _: Self::Type; | ++++++ +help: consider importing this struct + | +LL + use std::mem::type_info::Type; + | error[E0531]: cannot find tuple struct or tuple variant `Type` in this scope --> $DIR/resolve-assoc-suggestions.rs:25:13 diff --git a/tests/ui/suggestions/fn-trait-notation.stderr b/tests/ui/suggestions/fn-trait-notation.stderr index 9b47c8c02a78..9d0845478527 100644 --- a/tests/ui/suggestions/fn-trait-notation.stderr +++ b/tests/ui/suggestions/fn-trait-notation.stderr @@ -32,7 +32,7 @@ error[E0059]: type parameter to bare `Fn` trait must be a tuple --> $DIR/fn-trait-notation.rs:4:8 | LL | F: Fn, - | ^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `i32` + | ^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `i32` | note: required by a bound in `Fn` --> $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -47,7 +47,7 @@ error[E0277]: `i32` is not a tuple --> $DIR/fn-trait-notation.rs:9:5 | LL | f(3); - | ^^^^ the trait `Tuple` is not implemented for `i32` + | ^^^^ the trait `std::marker::Tuple` is not implemented for `i32` error[E0308]: mismatched types --> $DIR/fn-trait-notation.rs:17:5 diff --git a/tests/ui/thir-print/offset_of.stdout b/tests/ui/thir-print/offset_of.stdout index ab924091ba7a..dcf60a86af9b 100644 --- a/tests/ui/thir-print/offset_of.stdout +++ b/tests/ui/thir-print/offset_of.stdout @@ -68,7 +68,7 @@ body: ) else_block: None lint_level: Explicit(HirId(DefId(offset_of::concrete).10)) - span: $DIR/offset_of.rs:37:5: 1437:57 (#0) + span: $DIR/offset_of.rs:37:5: 1440:57 (#0) } } Stmt { @@ -117,7 +117,7 @@ body: ) else_block: None lint_level: Explicit(HirId(DefId(offset_of::concrete).20)) - span: $DIR/offset_of.rs:38:5: 1437:57 (#0) + span: $DIR/offset_of.rs:38:5: 1440:57 (#0) } } Stmt { @@ -166,7 +166,7 @@ body: ) else_block: None lint_level: Explicit(HirId(DefId(offset_of::concrete).30)) - span: $DIR/offset_of.rs:39:5: 1437:57 (#0) + span: $DIR/offset_of.rs:39:5: 1440:57 (#0) } } Stmt { @@ -215,7 +215,7 @@ body: ) else_block: None lint_level: Explicit(HirId(DefId(offset_of::concrete).40)) - span: $DIR/offset_of.rs:40:5: 1437:57 (#0) + span: $DIR/offset_of.rs:40:5: 1440:57 (#0) } } Stmt { @@ -264,7 +264,7 @@ body: ) else_block: None lint_level: Explicit(HirId(DefId(offset_of::concrete).50)) - span: $DIR/offset_of.rs:41:5: 1437:57 (#0) + span: $DIR/offset_of.rs:41:5: 1440:57 (#0) } } ] @@ -864,7 +864,7 @@ body: ) else_block: None lint_level: Explicit(HirId(DefId(offset_of::generic).12)) - span: $DIR/offset_of.rs:45:5: 1437:57 (#0) + span: $DIR/offset_of.rs:45:5: 1440:57 (#0) } } Stmt { @@ -913,7 +913,7 @@ body: ) else_block: None lint_level: Explicit(HirId(DefId(offset_of::generic).24)) - span: $DIR/offset_of.rs:46:5: 1437:57 (#0) + span: $DIR/offset_of.rs:46:5: 1440:57 (#0) } } Stmt { @@ -962,7 +962,7 @@ body: ) else_block: None lint_level: Explicit(HirId(DefId(offset_of::generic).36)) - span: $DIR/offset_of.rs:47:5: 1437:57 (#0) + span: $DIR/offset_of.rs:47:5: 1440:57 (#0) } } Stmt { @@ -1011,7 +1011,7 @@ body: ) else_block: None lint_level: Explicit(HirId(DefId(offset_of::generic).48)) - span: $DIR/offset_of.rs:48:5: 1437:57 (#0) + span: $DIR/offset_of.rs:48:5: 1440:57 (#0) } } ] diff --git a/tests/ui/traits/ignore-err-impls.stderr b/tests/ui/traits/ignore-err-impls.stderr index 68077c435135..46a2a7d55a2e 100644 --- a/tests/ui/traits/ignore-err-impls.stderr +++ b/tests/ui/traits/ignore-err-impls.stderr @@ -4,10 +4,10 @@ error[E0425]: cannot find type `Type` in this scope LL | impl Generic for S {} | ^^^^ not found in this scope | -help: you might be missing a type parameter +help: consider importing this struct + | +LL + use std::mem::type_info::Type; | -LL | impl Generic for S {} - | ++++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/next-solver/well-formed-in-relate.stderr b/tests/ui/traits/next-solver/well-formed-in-relate.stderr index d79e465b3e38..264ab9bebbb9 100644 --- a/tests/ui/traits/next-solver/well-formed-in-relate.stderr +++ b/tests/ui/traits/next-solver/well-formed-in-relate.stderr @@ -9,11 +9,11 @@ LL | x = unconstrained_map(); | = note: multiple `impl`s satisfying `_: Fn()` found in the following crates: `alloc`, `core`: - impl Fn for &F - where A: Tuple, F: Fn, F: ?Sized; + where A: std::marker::Tuple, F: Fn, F: ?Sized; - impl Fn for Box - where Args: Tuple, F: Fn, A: Allocator, F: ?Sized; + where Args: std::marker::Tuple, F: Fn, A: Allocator, F: ?Sized; - impl Fn for Exclusive - where F: Sync, F: Fn, Args: Tuple; + where F: Sync, F: Fn, Args: std::marker::Tuple; note: required by a bound in `unconstrained_map` --> $DIR/well-formed-in-relate.rs:21:25 | diff --git a/tests/ui/tuple/builtin-fail.stderr b/tests/ui/tuple/builtin-fail.stderr index 44e79578f4c9..0dec88ded7ce 100644 --- a/tests/ui/tuple/builtin-fail.stderr +++ b/tests/ui/tuple/builtin-fail.stderr @@ -2,7 +2,7 @@ error[E0277]: `T` is not a tuple --> $DIR/builtin-fail.rs:8:23 | LL | assert_is_tuple::(); - | ^ the trait `Tuple` is not implemented for `T` + | ^ the trait `std::marker::Tuple` is not implemented for `T` | note: required by a bound in `assert_is_tuple` --> $DIR/builtin-fail.rs:3:23 @@ -18,7 +18,7 @@ error[E0277]: `i32` is not a tuple --> $DIR/builtin-fail.rs:13:23 | LL | assert_is_tuple::(); - | ^^^ the trait `Tuple` is not implemented for `i32` + | ^^^ the trait `std::marker::Tuple` is not implemented for `i32` | note: required by a bound in `assert_is_tuple` --> $DIR/builtin-fail.rs:3:23 @@ -30,7 +30,7 @@ error[E0277]: `i32` is not a tuple --> $DIR/builtin-fail.rs:15:24 | LL | assert_is_tuple::<(i32)>(); - | ^^^ the trait `Tuple` is not implemented for `i32` + | ^^^ the trait `std::marker::Tuple` is not implemented for `i32` | note: required by a bound in `assert_is_tuple` --> $DIR/builtin-fail.rs:3:23 @@ -44,7 +44,7 @@ error[E0277]: `TupleStruct` is not a tuple LL | assert_is_tuple::(); | ^^^^^^^^^^^ unsatisfied trait bound | -help: the trait `Tuple` is not implemented for `TupleStruct` +help: the trait `std::marker::Tuple` is not implemented for `TupleStruct` --> $DIR/builtin-fail.rs:5:1 | LL | struct TupleStruct(i32, i32); diff --git a/tests/ui/typeck/issue-57404.stderr b/tests/ui/typeck/issue-57404.stderr index 4c1bfc0cbf77..f1d28e475a07 100644 --- a/tests/ui/typeck/issue-57404.stderr +++ b/tests/ui/typeck/issue-57404.stderr @@ -2,7 +2,7 @@ error[E0277]: `&mut ()` is not a tuple --> $DIR/issue-57404.rs:6:41 | LL | handlers.unwrap().as_mut().call_mut(&mut ()); - | -------- ^^^^^^^ the trait `Tuple` is not implemented for `&mut ()` + | -------- ^^^^^^^ the trait `std::marker::Tuple` is not implemented for `&mut ()` | | | required by a bound introduced by this call | diff --git a/tests/ui/unboxed-closures/non-tupled-arg-mismatch.stderr b/tests/ui/unboxed-closures/non-tupled-arg-mismatch.stderr index 0d4265ddf8bd..621a533dd1c5 100644 --- a/tests/ui/unboxed-closures/non-tupled-arg-mismatch.stderr +++ b/tests/ui/unboxed-closures/non-tupled-arg-mismatch.stderr @@ -2,7 +2,7 @@ error[E0059]: type parameter to bare `Fn` trait must be a tuple --> $DIR/non-tupled-arg-mismatch.rs:3:9 | LL | fn a>(f: F) {} - | ^^^^^^^^^ the trait `Tuple` is not implemented for `usize` + | ^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `usize` | note: required by a bound in `Fn` --> $SRC_DIR/core/src/ops/function.rs:LL:COL diff --git a/triagebot.toml b/triagebot.toml index fb6660b9dd03..9afe66c24717 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1003,6 +1003,13 @@ cc = ["@lcnr"] message = "HIR ty lowering was modified" cc = ["@fmease"] +[mentions."library/core/src/mem/type_info.rs"] +message = """ +The reflection data structures are tied exactly to the implementation +in the compiler. Make sure to also adjust `rustc_const_eval/src/const_eval/type_info.rs +""" +cc = ["@oli-obk"] + [mentions."compiler/rustc_error_codes/src/lib.rs"] message = "Some changes occurred in diagnostic error codes" cc = ["@GuillaumeGomez"] From 72f1ac9fbdbff5b432519891ac3d826a0333cf34 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 12 Mar 2025 10:26:37 +0000 Subject: [PATCH 0395/1061] Compile-Time Reflection MVP: tuples --- clippy_utils/src/sym.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index a0d2e8673fe6..74f89cfc6811 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -62,7 +62,6 @@ generate! { MsrvStack, Octal, OpenOptions, - Other, PathLookup, Regex, RegexBuilder, From 2afe5b1a837b5e4d1cb27f675218de4c800d2b80 Mon Sep 17 00:00:00 2001 From: Jamie Cunliffe Date: Thu, 8 Jan 2026 11:59:41 +0000 Subject: [PATCH 0396/1061] Fix ICE in inline always warning emission. The calls to `def_path_str` were outside the decorate callback in `node_span_lint` which caused an ICE when the warning was an allowed warning due to the call to `def_path_str` being executed but the warning not actually being emitted. --- compiler/rustc_mir_transform/src/errors.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index ee21d4fbcead..21a6c4d653bc 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -19,14 +19,14 @@ pub(crate) fn emit_inline_always_target_feature_diagnostic<'a, 'tcx>( caller_def_id: DefId, callee_only: &[&'a str], ) { - let callee = tcx.def_path_str(callee_def_id); - let caller = tcx.def_path_str(caller_def_id); - tcx.node_span_lint( lint::builtin::INLINE_ALWAYS_MISMATCHING_TARGET_FEATURES, tcx.local_def_id_to_hir_id(caller_def_id.as_local().unwrap()), call_span, |lint| { + let callee = tcx.def_path_str(callee_def_id); + let caller = tcx.def_path_str(caller_def_id); + lint.primary_message(format!( "call to `#[inline(always)]`-annotated `{callee}` \ requires the same target features to be inlined" From 82028b0f9a9695edd3f70d54234df0bb61e4184d Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 14 Mar 2025 14:39:58 +0000 Subject: [PATCH 0397/1061] Add size information --- .../src/const_eval/type_info.rs | 17 +++++++++++++++++ library/core/src/mem/type_info.rs | 2 ++ 2 files changed, 19 insertions(+) diff --git a/compiler/rustc_const_eval/src/const_eval/type_info.rs b/compiler/rustc_const_eval/src/const_eval/type_info.rs index a94ef580027b..f932b198b426 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -86,6 +86,23 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { }; self.write_discriminant(variant_index, &field_dest)? } + sym::size => { + let layout = self.layout_of(ty)?; + let variant_index = if layout.is_sized() { + let (variant, variant_place) = downcast(sym::Some)?; + let size_field_place = + self.project_field(&variant_place, FieldIdx::ZERO)?; + self.write_scalar( + ScalarInt::try_from_target_usize(layout.size.bytes(), self.tcx.tcx) + .unwrap(), + &size_field_place, + )?; + variant + } else { + downcast(sym::None)?.0 + }; + self.write_discriminant(variant_index, &field_dest)?; + } other => span_bug!(self.tcx.span, "unknown `Type` field {other}"), } } diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index b188504f76d9..7938e2b52ed0 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -12,6 +12,8 @@ use crate::intrinsics::type_of; pub struct Type { /// Per-type information pub kind: TypeKind, + /// Size of the type. `None` if it is unsized + pub size: Option, } impl TypeId { From d41191958a87e483de72fd73fc4470b0f9b9e6f2 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 8 Jan 2026 12:35:30 +0000 Subject: [PATCH 0398/1061] rename the `derive_{eq, clone_copy}` features to `*_internals` --- library/core/src/clone.rs | 6 +++--- library/core/src/cmp.rs | 8 ++++++-- library/core/src/marker.rs | 2 +- .../{derive-eq.md => derive-clone-copy-internals.md} | 2 +- .../{derive-clone-copy.md => derive-eq-internals.md} | 2 +- 5 files changed, 12 insertions(+), 8 deletions(-) rename src/doc/unstable-book/src/library-features/{derive-eq.md => derive-clone-copy-internals.md} (77%) rename src/doc/unstable-book/src/library-features/{derive-clone-copy.md => derive-eq-internals.md} (82%) diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index e3d4b5c3331c..85b09ee06f1f 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -285,7 +285,7 @@ pub const unsafe trait TrivialClone: [const] Clone {} /// Derive macro generating an impl of the trait `Clone`. #[rustc_builtin_macro] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -#[allow_internal_unstable(core_intrinsics, derive_clone_copy, trivial_clone)] +#[allow_internal_unstable(core_intrinsics, derive_clone_copy_internals, trivial_clone)] pub macro Clone($item:item) { /* compiler built-in */ } @@ -350,7 +350,7 @@ impl_use_cloned! { #[doc(hidden)] #[allow(missing_debug_implementations)] #[unstable( - feature = "derive_clone_copy", + feature = "derive_clone_copy_internals", reason = "deriving hack, should not be public", issue = "none" )] @@ -360,7 +360,7 @@ pub struct AssertParamIsClone { #[doc(hidden)] #[allow(missing_debug_implementations)] #[unstable( - feature = "derive_clone_copy", + feature = "derive_clone_copy_internals", reason = "deriving hack, should not be public", issue = "none" )] diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index feb9c4319604..2f2477008206 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -351,7 +351,7 @@ pub const trait Eq: [const] PartialEq + PointeeSized { /// Derive macro generating an impl of the trait [`Eq`]. #[rustc_builtin_macro] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -#[allow_internal_unstable(core_intrinsics, derive_eq, structural_match)] +#[allow_internal_unstable(core_intrinsics, derive_eq_internals, structural_match)] #[allow_internal_unstable(coverage_attribute)] pub macro Eq($item:item) { /* compiler built-in */ @@ -363,7 +363,11 @@ pub macro Eq($item:item) { // This struct should never appear in user code. #[doc(hidden)] #[allow(missing_debug_implementations)] -#[unstable(feature = "derive_eq", reason = "deriving hack, should not be public", issue = "none")] +#[unstable( + feature = "derive_eq_internals", + reason = "deriving hack, should not be public", + issue = "none" +)] pub struct AssertParamIsEq { _field: crate::marker::PhantomData, } diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 5ecc2a63ea83..68f5649210de 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -466,7 +466,7 @@ pub trait Copy: Clone { /// Derive macro generating an impl of the trait `Copy`. #[rustc_builtin_macro] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -#[allow_internal_unstable(core_intrinsics, derive_clone_copy)] +#[allow_internal_unstable(core_intrinsics, derive_clone_copy_internals)] pub macro Copy($item:item) { /* compiler built-in */ } diff --git a/src/doc/unstable-book/src/library-features/derive-eq.md b/src/doc/unstable-book/src/library-features/derive-clone-copy-internals.md similarity index 77% rename from src/doc/unstable-book/src/library-features/derive-eq.md rename to src/doc/unstable-book/src/library-features/derive-clone-copy-internals.md index 68a275f5419d..c53a55132de5 100644 --- a/src/doc/unstable-book/src/library-features/derive-eq.md +++ b/src/doc/unstable-book/src/library-features/derive-clone-copy-internals.md @@ -1,4 +1,4 @@ -# `derive_eq` +# `derive_clone_copy_internals` This feature is internal to the Rust compiler and is not intended for general use. diff --git a/src/doc/unstable-book/src/library-features/derive-clone-copy.md b/src/doc/unstable-book/src/library-features/derive-eq-internals.md similarity index 82% rename from src/doc/unstable-book/src/library-features/derive-clone-copy.md rename to src/doc/unstable-book/src/library-features/derive-eq-internals.md index cc603911cbd2..3f334b5ad3b6 100644 --- a/src/doc/unstable-book/src/library-features/derive-clone-copy.md +++ b/src/doc/unstable-book/src/library-features/derive-eq-internals.md @@ -1,4 +1,4 @@ -# `derive_clone_copy` +# `derive_eq_internals` This feature is internal to the Rust compiler and is not intended for general use. From 27b1083a96ab1bcc8b511882b31534e333a8e5c9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 8 Jan 2026 14:10:33 +0100 Subject: [PATCH 0399/1061] Update `literal-escaper` version to `0.0.7` --- Cargo.lock | 4 ++-- compiler/rustc_ast/Cargo.toml | 2 +- compiler/rustc_parse/Cargo.toml | 2 +- compiler/rustc_parse_format/Cargo.toml | 2 +- compiler/rustc_proc_macro/Cargo.toml | 2 +- library/Cargo.lock | 5 ++--- library/proc_macro/Cargo.toml | 2 +- src/tools/clippy/clippy_dev/Cargo.toml | 2 +- src/tools/lint-docs/Cargo.toml | 2 +- 9 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 427e93e56cd8..4c1697ec4d0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3412,9 +3412,9 @@ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustc-literal-escaper" -version = "0.0.5" +version = "0.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ee29da77c5a54f42697493cd4c9b9f31b74df666a6c04dfc4fde77abe0438b" +checksum = "8be87abb9e40db7466e0681dc8ecd9dcfd40360cb10b4c8fe24a7c4c3669b198" [[package]] name = "rustc-main" diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index 34d90adf5cb3..471a6bf1df13 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -7,7 +7,7 @@ edition = "2024" # tidy-alphabetical-start bitflags = "2.4.1" memchr = "2.7.6" -rustc-literal-escaper = "0.0.5" +rustc-literal-escaper = "0.0.7" rustc_ast_ir = { path = "../rustc_ast_ir" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_index = { path = "../rustc_index" } diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index 04a51c905661..f0c84e07a56f 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" -rustc-literal-escaper = "0.0.5" +rustc-literal-escaper = "0.0.7" rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_parse_format/Cargo.toml b/compiler/rustc_parse_format/Cargo.toml index d178fcda1fb9..10b41a39c3bf 100644 --- a/compiler/rustc_parse_format/Cargo.toml +++ b/compiler/rustc_parse_format/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -rustc-literal-escaper = "0.0.5" +rustc-literal-escaper = "0.0.7" rustc_lexer = { path = "../rustc_lexer" } # tidy-alphabetical-end diff --git a/compiler/rustc_proc_macro/Cargo.toml b/compiler/rustc_proc_macro/Cargo.toml index beb95aa3b52f..54c765075113 100644 --- a/compiler/rustc_proc_macro/Cargo.toml +++ b/compiler/rustc_proc_macro/Cargo.toml @@ -16,7 +16,7 @@ doctest = false [dependencies] # tidy-alphabetical-start -rustc-literal-escaper = "0.0.5" +rustc-literal-escaper = "0.0.7" # tidy-alphabetical-end [features] diff --git a/library/Cargo.lock b/library/Cargo.lock index 5e49843dae06..f6c14bc58a04 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -283,12 +283,11 @@ dependencies = [ [[package]] name = "rustc-literal-escaper" -version = "0.0.5" +version = "0.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ee29da77c5a54f42697493cd4c9b9f31b74df666a6c04dfc4fde77abe0438b" +checksum = "8be87abb9e40db7466e0681dc8ecd9dcfd40360cb10b4c8fe24a7c4c3669b198" dependencies = [ "rustc-std-workspace-core", - "rustc-std-workspace-std", ] [[package]] diff --git a/library/proc_macro/Cargo.toml b/library/proc_macro/Cargo.toml index 3a4840a57334..1e5046ca61c3 100644 --- a/library/proc_macro/Cargo.toml +++ b/library/proc_macro/Cargo.toml @@ -9,7 +9,7 @@ std = { path = "../std" } # `core` when resolving doc links. Without this line a different `core` will be # loaded from sysroot causing duplicate lang items and other similar errors. core = { path = "../core" } -rustc-literal-escaper = { version = "0.0.5", features = ["rustc-dep-of-std"] } +rustc-literal-escaper = { version = "0.0.7", features = ["rustc-dep-of-std"] } [features] default = ["rustc-dep-of-std"] diff --git a/src/tools/clippy/clippy_dev/Cargo.toml b/src/tools/clippy/clippy_dev/Cargo.toml index c2abbac37535..238465210ee2 100644 --- a/src/tools/clippy/clippy_dev/Cargo.toml +++ b/src/tools/clippy/clippy_dev/Cargo.toml @@ -10,7 +10,7 @@ clap = { version = "4.4", features = ["derive"] } indoc = "1.0" itertools = "0.12" opener = "0.7" -rustc-literal-escaper = "0.0.5" +rustc-literal-escaper = "0.0.7" walkdir = "2.3" [package.metadata.rust-analyzer] diff --git a/src/tools/lint-docs/Cargo.toml b/src/tools/lint-docs/Cargo.toml index 6e1ab84ed18d..ab99eb8ea3b7 100644 --- a/src/tools/lint-docs/Cargo.toml +++ b/src/tools/lint-docs/Cargo.toml @@ -7,7 +7,7 @@ description = "A script to extract the lint documentation for the rustc book." # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rustc-literal-escaper = "0.0.5" +rustc-literal-escaper = "0.0.7" serde_json = "1.0.57" tempfile = "3.1.0" walkdir = "2.3.1" From 21f6afca40cb423b4920fbc571490f801aa95d16 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 8 Jan 2026 14:10:33 +0100 Subject: [PATCH 0400/1061] Update `literal-escaper` version to `0.0.7` --- clippy_dev/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_dev/Cargo.toml b/clippy_dev/Cargo.toml index c2abbac37535..238465210ee2 100644 --- a/clippy_dev/Cargo.toml +++ b/clippy_dev/Cargo.toml @@ -10,7 +10,7 @@ clap = { version = "4.4", features = ["derive"] } indoc = "1.0" itertools = "0.12" opener = "0.7" -rustc-literal-escaper = "0.0.5" +rustc-literal-escaper = "0.0.7" walkdir = "2.3" [package.metadata.rust-analyzer] From 0051e31f6f8000c6bf2fab1549a55a26d4d455ff Mon Sep 17 00:00:00 2001 From: dianqk Date: Tue, 23 Dec 2025 22:25:11 +0800 Subject: [PATCH 0401/1061] New MIR Pass: SsaRangePropagation --- compiler/rustc_middle/src/mir/statement.rs | 6 + compiler/rustc_mir_transform/src/lib.rs | 4 + .../rustc_mir_transform/src/ssa_range_prop.rs | 203 ++++++++++++++++++ ...a_range.on_assert.SsaRangePropagation.diff | 69 ++++++ .../ssa_range.on_if.SsaRangePropagation.diff | 63 ++++++ ...ssa_range.on_if_2.SsaRangePropagation.diff | 20 ++ ...sa_range.on_match.SsaRangePropagation.diff | 33 +++ ..._range.on_match_2.SsaRangePropagation.diff | 26 +++ tests/mir-opt/range/ssa_range.rs | 70 ++++++ 9 files changed, 494 insertions(+) create mode 100644 compiler/rustc_mir_transform/src/ssa_range_prop.rs create mode 100644 tests/mir-opt/range/ssa_range.on_assert.SsaRangePropagation.diff create mode 100644 tests/mir-opt/range/ssa_range.on_if.SsaRangePropagation.diff create mode 100644 tests/mir-opt/range/ssa_range.on_if_2.SsaRangePropagation.diff create mode 100644 tests/mir-opt/range/ssa_range.on_match.SsaRangePropagation.diff create mode 100644 tests/mir-opt/range/ssa_range.on_match_2.SsaRangePropagation.diff create mode 100644 tests/mir-opt/range/ssa_range.rs diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 1ba1ae3e1531..2ee1d53cabd5 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -374,6 +374,12 @@ impl<'tcx> Place<'tcx> { self.projection.iter().any(|elem| elem.is_indirect()) } + /// Returns `true` if the `Place` always refers to the same memory region + /// whatever the state of the program. + pub fn is_stable_offset(&self) -> bool { + self.projection.iter().all(|elem| elem.is_stable_offset()) + } + /// Returns `true` if this `Place`'s first projection is `Deref`. /// /// This is useful because for MIR phases `AnalysisPhase::PostCleanup` and later, diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 701d7ff854a7..24ea4a5cd6df 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -198,6 +198,7 @@ declare_passes! { mod single_use_consts : SingleUseConsts; mod sroa : ScalarReplacementOfAggregates; mod strip_debuginfo : StripDebugInfo; + mod ssa_range_prop: SsaRangePropagation; mod unreachable_enum_branching : UnreachableEnumBranching; mod unreachable_prop : UnreachablePropagation; mod validate : Validator; @@ -741,6 +742,9 @@ pub(crate) fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<' &dead_store_elimination::DeadStoreElimination::Initial, &gvn::GVN, &simplify::SimplifyLocals::AfterGVN, + // This pass does attempt to track assignments. + // Keep it close to GVN which merges identical values into the same local. + &ssa_range_prop::SsaRangePropagation, &match_branches::MatchBranchSimplification, &dataflow_const_prop::DataflowConstProp, &single_use_consts::SingleUseConsts, diff --git a/compiler/rustc_mir_transform/src/ssa_range_prop.rs b/compiler/rustc_mir_transform/src/ssa_range_prop.rs new file mode 100644 index 000000000000..47e17de0560b --- /dev/null +++ b/compiler/rustc_mir_transform/src/ssa_range_prop.rs @@ -0,0 +1,203 @@ +//! A pass that propagates the known ranges of SSA locals. +//! We can know the ranges of SSA locals in certain locations for the following code: +//! ``` +//! fn foo(a: u32) { +//! let b = a < 9; // the integer representation of b is within the full range [0, 2). +//! if b { +//! let c = b; // c is true since b is within the range [1, 2). +//! let d = a < 8; // d is true since a is within the range [0, 9). +//! } +//! } +//! ``` +use rustc_abi::WrappingRange; +use rustc_const_eval::interpret::Scalar; +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::graph::dominators::Dominators; +use rustc_index::bit_set::DenseBitSet; +use rustc_middle::mir::visit::MutVisitor; +use rustc_middle::mir::{BasicBlock, Body, Location, Operand, Place, TerminatorKind, *}; +use rustc_middle::ty::{TyCtxt, TypingEnv}; +use rustc_span::DUMMY_SP; + +use crate::ssa::SsaLocals; + +pub(super) struct SsaRangePropagation; + +impl<'tcx> crate::MirPass<'tcx> for SsaRangePropagation { + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.mir_opt_level() > 1 + } + + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let typing_env = body.typing_env(tcx); + let ssa = SsaLocals::new(tcx, body, typing_env); + // Clone dominators because we need them while mutating the body. + let dominators = body.basic_blocks.dominators().clone(); + let mut range_set = + RangeSet::new(tcx, typing_env, body, &ssa, &body.local_decls, dominators); + + let reverse_postorder = body.basic_blocks.reverse_postorder().to_vec(); + for bb in reverse_postorder { + let data = &mut body.basic_blocks.as_mut_preserves_cfg()[bb]; + range_set.visit_basic_block_data(bb, data); + } + } + + fn is_required(&self) -> bool { + false + } +} + +struct RangeSet<'tcx, 'body, 'a> { + tcx: TyCtxt<'tcx>, + typing_env: TypingEnv<'tcx>, + ssa: &'a SsaLocals, + local_decls: &'body LocalDecls<'tcx>, + dominators: Dominators, + /// Known ranges at each locations. + ranges: FxHashMap, Vec<(Location, WrappingRange)>>, + /// Determines if the basic block has a single unique predecessor. + unique_predecessors: DenseBitSet, +} + +impl<'tcx, 'body, 'a> RangeSet<'tcx, 'body, 'a> { + fn new( + tcx: TyCtxt<'tcx>, + typing_env: TypingEnv<'tcx>, + body: &Body<'tcx>, + ssa: &'a SsaLocals, + local_decls: &'body LocalDecls<'tcx>, + dominators: Dominators, + ) -> Self { + let predecessors = body.basic_blocks.predecessors(); + let mut unique_predecessors = DenseBitSet::new_empty(body.basic_blocks.len()); + for bb in body.basic_blocks.indices() { + if predecessors[bb].len() == 1 { + unique_predecessors.insert(bb); + } + } + RangeSet { + tcx, + typing_env, + ssa, + local_decls, + dominators, + ranges: FxHashMap::default(), + unique_predecessors, + } + } + + /// Create a new known range at the location. + fn insert_range(&mut self, place: Place<'tcx>, location: Location, range: WrappingRange) { + assert!(self.is_ssa(place)); + self.ranges.entry(place).or_default().push((location, range)); + } + + /// Get the known range at the location. + fn get_range(&self, place: &Place<'tcx>, location: Location) -> Option { + let Some(ranges) = self.ranges.get(place) else { + return None; + }; + // FIXME: This should use the intersection of all valid ranges. + let (_, range) = + ranges.iter().find(|(range_loc, _)| range_loc.dominates(location, &self.dominators))?; + Some(*range) + } + + fn try_as_constant( + &mut self, + place: Place<'tcx>, + location: Location, + ) -> Option> { + if let Some(range) = self.get_range(&place, location) + && range.start == range.end + { + let ty = place.ty(self.local_decls, self.tcx).ty; + let layout = self.tcx.layout_of(self.typing_env.as_query_input(ty)).ok()?; + let value = ConstValue::Scalar(Scalar::from_uint(range.start, layout.size)); + let const_ = Const::Val(value, ty); + return Some(ConstOperand { span: DUMMY_SP, user_ty: None, const_ }); + } + None + } + + fn is_ssa(&self, place: Place<'tcx>) -> bool { + self.ssa.is_ssa(place.local) && place.is_stable_offset() + } +} + +impl<'tcx> MutVisitor<'tcx> for RangeSet<'tcx, '_, '_> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) { + // Attempts to simplify an operand to a constant value. + if let Some(place) = operand.place() + && let Some(const_) = self.try_as_constant(place, location) + { + *operand = Operand::Constant(Box::new(const_)); + }; + } + + fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) { + self.super_terminator(terminator, location); + match &terminator.kind { + TerminatorKind::Assert { cond, expected, target, .. } => { + if let Some(place) = cond.place() + && self.is_ssa(place) + { + let successor = Location { block: *target, statement_index: 0 }; + if location.dominates(successor, &self.dominators) { + assert_ne!(location.block, successor.block); + let val = *expected as u128; + let range = WrappingRange { start: val, end: val }; + self.insert_range(place, successor, range); + } + } + } + TerminatorKind::SwitchInt { discr, targets } => { + if let Some(place) = discr.place() + && self.is_ssa(place) + // Reduce the potential compile-time overhead. + && targets.all_targets().len() < 16 + { + let mut distinct_targets: FxHashMap = FxHashMap::default(); + for (_, target) in targets.iter() { + let targets = distinct_targets.entry(target).or_default(); + *targets += 1; + } + for (val, target) in targets.iter() { + if distinct_targets[&target] != 1 { + // FIXME: For multiple targets, the range can be the union of their values. + continue; + } + let successor = Location { block: target, statement_index: 0 }; + if self.unique_predecessors.contains(successor.block) { + assert_ne!(location.block, successor.block); + let range = WrappingRange { start: val, end: val }; + self.insert_range(place, successor, range); + } + } + + // FIXME: The range for the otherwise target be extend to more types. + // For instance, `val` is within the range [4, 1) at the otherwise target of `matches!(val, 1 | 2 | 3)`. + let otherwise = Location { block: targets.otherwise(), statement_index: 0 }; + if place.ty(self.local_decls, self.tcx).ty.is_bool() + && let [val] = targets.all_values() + && self.unique_predecessors.contains(otherwise.block) + { + assert_ne!(location.block, otherwise.block); + let range = if val.get() == 0 { + WrappingRange { start: 1, end: 1 } + } else { + WrappingRange { start: 0, end: 0 } + }; + self.insert_range(place, otherwise, range); + } + } + } + _ => {} + } + } +} diff --git a/tests/mir-opt/range/ssa_range.on_assert.SsaRangePropagation.diff b/tests/mir-opt/range/ssa_range.on_assert.SsaRangePropagation.diff new file mode 100644 index 000000000000..ae3f49a8847b --- /dev/null +++ b/tests/mir-opt/range/ssa_range.on_assert.SsaRangePropagation.diff @@ -0,0 +1,69 @@ +- // MIR for `on_assert` before SsaRangePropagation ++ // MIR for `on_assert` after SsaRangePropagation + + fn on_assert(_1: usize, _2: &[u8]) -> u8 { + debug i => _1; + debug v => _2; + let mut _0: u8; + let _3: (); + let mut _4: bool; + let mut _5: usize; + let mut _6: usize; + let mut _7: &[u8]; + let mut _8: !; + let _9: usize; + let mut _10: usize; + let mut _11: bool; + scope 1 (inlined core::slice::::len) { + scope 2 (inlined std::ptr::metadata::<[u8]>) { + } + } + + bb0: { + StorageLive(_3); + nop; + StorageLive(_5); + _5 = copy _1; + nop; + StorageLive(_7); + _7 = &(*_2); + _6 = PtrMetadata(copy _2); + StorageDead(_7); + _4 = Lt(copy _1, copy _6); + switchInt(copy _4) -> [0: bb2, otherwise: bb1]; + } + + bb1: { + nop; + StorageDead(_5); + _3 = const (); + nop; + StorageDead(_3); + StorageLive(_9); + _9 = copy _1; + _10 = copy _6; +- _11 = copy _4; +- assert(copy _4, "index out of bounds: the length is {} but the index is {}", copy _6, copy _1) -> [success: bb3, unwind unreachable]; ++ _11 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", copy _6, copy _1) -> [success: bb3, unwind unreachable]; + } + + bb2: { + nop; + StorageDead(_5); + StorageLive(_8); + _8 = panic(const "assertion failed: i < v.len()") -> unwind unreachable; + } + + bb3: { + _0 = copy (*_2)[_1]; + StorageDead(_9); + return; + } + } + + ALLOC0 (size: 29, align: 1) { + 0x00 │ 61 73 73 65 72 74 69 6f 6e 20 66 61 69 6c 65 64 │ assertion failed + 0x10 │ 3a 20 69 20 3c 20 76 2e 6c 65 6e 28 29 │ : i < v.len() + } + diff --git a/tests/mir-opt/range/ssa_range.on_if.SsaRangePropagation.diff b/tests/mir-opt/range/ssa_range.on_if.SsaRangePropagation.diff new file mode 100644 index 000000000000..2493e069edd4 --- /dev/null +++ b/tests/mir-opt/range/ssa_range.on_if.SsaRangePropagation.diff @@ -0,0 +1,63 @@ +- // MIR for `on_if` before SsaRangePropagation ++ // MIR for `on_if` after SsaRangePropagation + + fn on_if(_1: usize, _2: &[u8]) -> u8 { + debug i => _1; + debug v => _2; + let mut _0: u8; + let mut _3: bool; + let mut _4: usize; + let mut _5: usize; + let mut _6: &[u8]; + let _7: usize; + let mut _8: usize; + let mut _9: bool; + scope 1 (inlined core::slice::::len) { + scope 2 (inlined std::ptr::metadata::<[u8]>) { + } + } + + bb0: { + nop; + StorageLive(_4); + _4 = copy _1; + nop; + StorageLive(_6); + _6 = &(*_2); + _5 = PtrMetadata(copy _2); + StorageDead(_6); + _3 = Lt(copy _1, copy _5); + switchInt(copy _3) -> [0: bb3, otherwise: bb1]; + } + + bb1: { + nop; + StorageDead(_4); + StorageLive(_7); + _7 = copy _1; + _8 = copy _5; +- _9 = copy _3; +- assert(copy _3, "index out of bounds: the length is {} but the index is {}", copy _5, copy _1) -> [success: bb2, unwind unreachable]; ++ _9 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", copy _5, copy _1) -> [success: bb2, unwind unreachable]; + } + + bb2: { + _0 = copy (*_2)[_1]; + StorageDead(_7); + goto -> bb4; + } + + bb3: { + nop; + StorageDead(_4); + _0 = const 0_u8; + goto -> bb4; + } + + bb4: { + nop; + return; + } + } + diff --git a/tests/mir-opt/range/ssa_range.on_if_2.SsaRangePropagation.diff b/tests/mir-opt/range/ssa_range.on_if_2.SsaRangePropagation.diff new file mode 100644 index 000000000000..8a957238c845 --- /dev/null +++ b/tests/mir-opt/range/ssa_range.on_if_2.SsaRangePropagation.diff @@ -0,0 +1,20 @@ +- // MIR for `on_if_2` before SsaRangePropagation ++ // MIR for `on_if_2` after SsaRangePropagation + + fn on_if_2(_1: bool) -> bool { + let mut _0: bool; + + bb0: { + switchInt(copy _1) -> [1: bb2, otherwise: bb1]; + } + + bb1: { + goto -> bb2; + } + + bb2: { + _0 = copy _1; + return; + } + } + diff --git a/tests/mir-opt/range/ssa_range.on_match.SsaRangePropagation.diff b/tests/mir-opt/range/ssa_range.on_match.SsaRangePropagation.diff new file mode 100644 index 000000000000..f91ac7090dde --- /dev/null +++ b/tests/mir-opt/range/ssa_range.on_match.SsaRangePropagation.diff @@ -0,0 +1,33 @@ +- // MIR for `on_match` before SsaRangePropagation ++ // MIR for `on_match` after SsaRangePropagation + + fn on_match(_1: u8) -> u8 { + debug i => _1; + let mut _0: u8; + + bb0: { + switchInt(copy _1) -> [1: bb3, 2: bb2, otherwise: bb1]; + } + + bb1: { + _0 = const 0_u8; + goto -> bb4; + } + + bb2: { +- _0 = copy _1; ++ _0 = const 2_u8; + goto -> bb4; + } + + bb3: { +- _0 = copy _1; ++ _0 = const 1_u8; + goto -> bb4; + } + + bb4: { + return; + } + } + diff --git a/tests/mir-opt/range/ssa_range.on_match_2.SsaRangePropagation.diff b/tests/mir-opt/range/ssa_range.on_match_2.SsaRangePropagation.diff new file mode 100644 index 000000000000..53433d9fe4ba --- /dev/null +++ b/tests/mir-opt/range/ssa_range.on_match_2.SsaRangePropagation.diff @@ -0,0 +1,26 @@ +- // MIR for `on_match_2` before SsaRangePropagation ++ // MIR for `on_match_2` after SsaRangePropagation + + fn on_match_2(_1: u8) -> u8 { + debug i => _1; + let mut _0: u8; + + bb0: { + switchInt(copy _1) -> [1: bb2, 2: bb2, otherwise: bb1]; + } + + bb1: { + _0 = const 0_u8; + goto -> bb3; + } + + bb2: { + _0 = copy _1; + goto -> bb3; + } + + bb3: { + return; + } + } + diff --git a/tests/mir-opt/range/ssa_range.rs b/tests/mir-opt/range/ssa_range.rs new file mode 100644 index 000000000000..964d9b97cf92 --- /dev/null +++ b/tests/mir-opt/range/ssa_range.rs @@ -0,0 +1,70 @@ +//@ test-mir-pass: SsaRangePropagation +//@ compile-flags: -Zmir-enable-passes=+GVN,+Inline --crate-type=lib -Cpanic=abort + +#![feature(custom_mir, core_intrinsics)] + +use std::intrinsics::mir::*; + +// EMIT_MIR ssa_range.on_if.SsaRangePropagation.diff +pub fn on_if(i: usize, v: &[u8]) -> u8 { + // CHECK-LABEL: fn on_if( + // CHECK: assert(const true + if i < v.len() { v[i] } else { 0 } +} + +// EMIT_MIR ssa_range.on_assert.SsaRangePropagation.diff +pub fn on_assert(i: usize, v: &[u8]) -> u8 { + // CHECK-LABEL: fn on_assert( + // CHECK: assert(const true + assert!(i < v.len()); + v[i] +} + +// EMIT_MIR ssa_range.on_match.SsaRangePropagation.diff +pub fn on_match(i: u8) -> u8 { + // CHECK-LABEL: fn on_match( + // CHECK: switchInt(copy _1) -> [1: [[BB_V1:bb.*]], 2: [[BB_V2:bb.*]], + // CHECK: [[BB_V2]]: { + // CHECK-NEXT: _0 = const 2_u8; + // CHECK: [[BB_V1]]: { + // CHECK-NEXT: _0 = const 1_u8; + match i { + 1 => i, + 2 => i, + _ => 0, + } +} + +// EMIT_MIR ssa_range.on_match_2.SsaRangePropagation.diff +pub fn on_match_2(i: u8) -> u8 { + // CHECK-LABEL: fn on_match_2( + // CHECK: switchInt(copy _1) -> [1: [[BB:bb.*]], 2: [[BB]], + // CHECK: [[BB]]: { + // CHECK-NEXT: _0 = copy _1; + match i { + 1 | 2 => i, + _ => 0, + } +} + +// EMIT_MIR ssa_range.on_if_2.SsaRangePropagation.diff +#[custom_mir(dialect = "runtime", phase = "post-cleanup")] +pub fn on_if_2(a: bool) -> bool { + // CHECK-LABEL: fn on_if_2( + // CHECK: _0 = copy _1; + mir! { + { + match a { + true => bb2, + _ => bb1 + } + } + bb1 = { + Goto(bb2) + } + bb2 = { + RET = a; + Return() + } + } +} From e9a67c74720911c531290c8ebc330e0fb5dc34d9 Mon Sep 17 00:00:00 2001 From: dianqk Date: Fri, 2 Jan 2026 22:15:40 +0800 Subject: [PATCH 0402/1061] Propagates assume --- .../rustc_mir_transform/src/ssa_range_prop.rs | 16 ++++++ ...a_range.on_assume.SsaRangePropagation.diff | 56 +++++++++++++++++++ tests/mir-opt/range/ssa_range.rs | 10 ++++ 3 files changed, 82 insertions(+) create mode 100644 tests/mir-opt/range/ssa_range.on_assume.SsaRangePropagation.diff diff --git a/compiler/rustc_mir_transform/src/ssa_range_prop.rs b/compiler/rustc_mir_transform/src/ssa_range_prop.rs index 47e17de0560b..7a8be8efdfd1 100644 --- a/compiler/rustc_mir_transform/src/ssa_range_prop.rs +++ b/compiler/rustc_mir_transform/src/ssa_range_prop.rs @@ -140,6 +140,22 @@ impl<'tcx> MutVisitor<'tcx> for RangeSet<'tcx, '_, '_> { }; } + fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { + self.super_statement(statement, location); + match &statement.kind { + StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(operand)) => { + if let Some(place) = operand.place() + && self.is_ssa(place) + { + let successor = location.successor_within_block(); + let range = WrappingRange { start: 1, end: 1 }; + self.insert_range(place, successor, range); + } + } + _ => {} + } + } + fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) { self.super_terminator(terminator, location); match &terminator.kind { diff --git a/tests/mir-opt/range/ssa_range.on_assume.SsaRangePropagation.diff b/tests/mir-opt/range/ssa_range.on_assume.SsaRangePropagation.diff new file mode 100644 index 000000000000..3be6f083604d --- /dev/null +++ b/tests/mir-opt/range/ssa_range.on_assume.SsaRangePropagation.diff @@ -0,0 +1,56 @@ +- // MIR for `on_assume` before SsaRangePropagation ++ // MIR for `on_assume` after SsaRangePropagation + + fn on_assume(_1: usize, _2: &[u8]) -> u8 { + debug i => _1; + debug v => _2; + let mut _0: u8; + let _3: (); + let _4: (); + let mut _5: bool; + let mut _6: usize; + let mut _7: usize; + let mut _8: &[u8]; + let _9: usize; + let mut _10: usize; + let mut _11: bool; + scope 1 (inlined core::slice::::len) { + scope 2 (inlined std::ptr::metadata::<[u8]>) { + } + } + + bb0: { + StorageLive(_3); + StorageLive(_4); + nop; + StorageLive(_6); + _6 = copy _1; + nop; + StorageLive(_8); + _8 = &(*_2); + _7 = PtrMetadata(copy _2); + StorageDead(_8); + _5 = Lt(copy _1, copy _7); + nop; + StorageDead(_6); + assume(copy _5); + nop; + StorageDead(_4); + _3 = const (); + StorageDead(_3); + StorageLive(_9); + _9 = copy _1; + _10 = copy _7; +- _11 = copy _5; +- assert(copy _5, "index out of bounds: the length is {} but the index is {}", copy _7, copy _1) -> [success: bb1, unwind unreachable]; ++ _11 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", copy _7, copy _1) -> [success: bb1, unwind unreachable]; + } + + bb1: { + _0 = copy (*_2)[_1]; + StorageDead(_9); + return; + } + } + diff --git a/tests/mir-opt/range/ssa_range.rs b/tests/mir-opt/range/ssa_range.rs index 964d9b97cf92..c8440a10a408 100644 --- a/tests/mir-opt/range/ssa_range.rs +++ b/tests/mir-opt/range/ssa_range.rs @@ -20,6 +20,16 @@ pub fn on_assert(i: usize, v: &[u8]) -> u8 { v[i] } +// EMIT_MIR ssa_range.on_assume.SsaRangePropagation.diff +pub fn on_assume(i: usize, v: &[u8]) -> u8 { + // CHECK-LABEL: fn on_assume( + // CHECK: assert(const true + unsafe { + std::intrinsics::assume(i < v.len()); + } + v[i] +} + // EMIT_MIR ssa_range.on_match.SsaRangePropagation.diff pub fn on_match(i: u8) -> u8 { // CHECK-LABEL: fn on_match( From 665770ec84032d2ce7e5c90fa116764c0d9c61cf Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 8 Jan 2026 12:03:56 +0000 Subject: [PATCH 0403/1061] Remove std_detect_file_io and std_detect_dlsym_getauxval features They were introduced back when std_detect was a standalone crate published to crates.io. The motivation for std_detect_dlsym_getauxval was to allow using getauxval without dlopen when statically linking musl, which we now unconditionally do for musl. And for std_detect_file_io to allow no_std usage, which std_detect now supports even with that feature enabled as it directly uses libc. This also prevents accidentally disabling runtime feature detection when using cargo build -Zbuild-std -Zbuild-std-features= --- library/std/Cargo.toml | 4 -- library/std_detect/Cargo.toml | 7 +-- library/std_detect/README.md | 26 ----------- library/std_detect/src/detect/mod.rs | 8 ++-- .../src/detect/os/linux/aarch64/tests.rs | 1 - .../std_detect/src/detect/os/linux/auxvec.rs | 44 +++++++------------ .../src/detect/os/linux/auxvec/tests.rs | 3 -- library/std_detect/src/detect/os/linux/mod.rs | 4 +- library/std_detect/src/lib.rs | 3 +- library/sysroot/Cargo.toml | 4 +- 10 files changed, 24 insertions(+), 80 deletions(-) diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 43caf7734fdb..5c9ae52d9e6c 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -128,10 +128,6 @@ debug_refcell = ["core/debug_refcell"] llvm_enzyme = ["core/llvm_enzyme"] -# Enable std_detect features: -std_detect_file_io = ["std_detect/std_detect_file_io"] -std_detect_dlsym_getauxval = ["std_detect/std_detect_dlsym_getauxval"] - # Enable using raw-dylib for Windows imports. # This will eventually be the default. windows_raw_dylib = ["windows-targets/windows_raw_dylib"] diff --git a/library/std_detect/Cargo.toml b/library/std_detect/Cargo.toml index 2739bb592300..bcfdb3901957 100644 --- a/library/std_detect/Cargo.toml +++ b/library/std_detect/Cargo.toml @@ -25,10 +25,7 @@ core = { version = "1.0.0", package = 'rustc-std-workspace-core' } alloc = { version = "1.0.0", package = 'rustc-std-workspace-alloc' } [target.'cfg(not(windows))'.dependencies] -libc = { version = "0.2.0", optional = true, default-features = false } +libc = { version = "0.2.0", default-features = false } [features] -default = [] -std_detect_file_io = [ "libc" ] -std_detect_dlsym_getauxval = [ "libc" ] -std_detect_env_override = [ "libc" ] +std_detect_env_override = [] diff --git a/library/std_detect/README.md b/library/std_detect/README.md index 177848dec104..895f3426d049 100644 --- a/library/std_detect/README.md +++ b/library/std_detect/README.md @@ -21,32 +21,6 @@ run-time feature detection support than the one offered by Rust's standard library. We intend to make `std_detect` more flexible and configurable in this regard to better serve the needs of `#[no_std]` targets. -# Features - -* `std_detect_dlsym_getauxval` (enabled by default, requires `libc`): Enable to -use `libc::dlsym` to query whether [`getauxval`] is linked into the binary. When -this is not the case, this feature allows other fallback methods to perform -run-time feature detection. When this feature is disabled, `std_detect` assumes -that [`getauxval`] is linked to the binary. If that is not the case the behavior -is undefined. - - Note: This feature is ignored on `*-linux-{gnu,musl,ohos}*` and `*-android*` targets - because we can safely assume `getauxval` is linked to the binary. - * `*-linux-gnu*` targets ([since Rust 1.64](https://blog.rust-lang.org/2022/08/01/Increasing-glibc-kernel-requirements.html)) - have glibc requirements higher than [glibc 2.16 that added `getauxval`](https://sourceware.org/legacy-ml/libc-announce/2012/msg00000.html). - * `*-linux-musl*` targets ([at least since Rust 1.15](https://github.com/rust-lang/rust/blob/1.15.0/src/ci/docker/x86_64-musl/build-musl.sh#L15)) - use musl newer than [musl 1.1.0 that added `getauxval`](https://git.musl-libc.org/cgit/musl/tree/WHATSNEW?h=v1.1.0#n1197) - * `*-linux-ohos*` targets use a [fork of musl 1.2](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/native-lib/musl.md) - * `*-android*` targets ([since Rust 1.68](https://blog.rust-lang.org/2023/01/09/android-ndk-update-r25.html)) - have the minimum supported API level higher than [Android 4.3 (API level 18) that added `getauxval`](https://github.com/aosp-mirror/platform_bionic/blob/d3ebc2f7c49a9893b114124d4a6b315f3a328764/libc/include/sys/auxv.h#L49). - -* `std_detect_file_io` (enabled by default, requires `std`): Enable to perform run-time feature -detection using file APIs (e.g. `/proc/self/auxv`, etc.) if other more performant -methods fail. This feature requires `libstd` as a dependency, preventing the -crate from working on applications in which `std` is not available. - -[`getauxval`]: https://man7.org/linux/man-pages/man3/getauxval.3.html - # Platform support * All `x86`/`x86_64` targets are supported on all platforms by querying the diff --git a/library/std_detect/src/detect/mod.rs b/library/std_detect/src/detect/mod.rs index ae6fb2ab3727..c888dd34d9db 100644 --- a/library/std_detect/src/detect/mod.rs +++ b/library/std_detect/src/detect/mod.rs @@ -47,21 +47,21 @@ cfg_select! { #[path = "os/x86.rs"] mod os; } - all(any(target_os = "linux", target_os = "android"), feature = "libc") => { + any(target_os = "linux", target_os = "android") => { #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] #[path = "os/riscv.rs"] mod riscv; #[path = "os/linux/mod.rs"] mod os; } - all(target_os = "freebsd", feature = "libc") => { + target_os = "freebsd" => { #[cfg(target_arch = "aarch64")] #[path = "os/aarch64.rs"] mod aarch64; #[path = "os/freebsd/mod.rs"] mod os; } - all(target_os = "openbsd", feature = "libc") => { + target_os = "openbsd" => { #[allow(dead_code)] // we don't use code that calls the mrs instruction. #[cfg(target_arch = "aarch64")] #[path = "os/aarch64.rs"] @@ -73,7 +73,7 @@ cfg_select! { #[path = "os/windows/aarch64.rs"] mod os; } - all(target_vendor = "apple", target_arch = "aarch64", feature = "libc") => { + all(target_vendor = "apple", target_arch = "aarch64") => { #[path = "os/darwin/aarch64.rs"] mod os; } diff --git a/library/std_detect/src/detect/os/linux/aarch64/tests.rs b/library/std_detect/src/detect/os/linux/aarch64/tests.rs index a3562f2fd936..912d116d57b8 100644 --- a/library/std_detect/src/detect/os/linux/aarch64/tests.rs +++ b/library/std_detect/src/detect/os/linux/aarch64/tests.rs @@ -1,6 +1,5 @@ use super::*; -#[cfg(feature = "std_detect_file_io")] mod auxv_from_file { use super::auxvec::auxv_from_file; use super::*; diff --git a/library/std_detect/src/detect/os/linux/auxvec.rs b/library/std_detect/src/detect/os/linux/auxvec.rs index 75e01bdc4499..c0bbc7d4efa8 100644 --- a/library/std_detect/src/detect/os/linux/auxvec.rs +++ b/library/std_detect/src/detect/os/linux/auxvec.rs @@ -44,20 +44,16 @@ pub(crate) struct AuxVec { /// /// There is no perfect way of reading the auxiliary vector. /// -/// - If the `std_detect_dlsym_getauxval` cargo feature is enabled, this will use -/// `getauxval` if its linked to the binary, and otherwise proceed to a fallback implementation. -/// When `std_detect_dlsym_getauxval` is disabled, this will assume that `getauxval` is -/// linked to the binary - if that is not the case the behavior is undefined. -/// - Otherwise, if the `std_detect_file_io` cargo feature is enabled, it will +/// - If [`getauxval`] is linked to the binary we use it, and otherwise it will /// try to read `/proc/self/auxv`. /// - If that fails, this function returns an error. /// /// Note that run-time feature detection is not invoked for features that can /// be detected at compile-time. /// -/// Note: The `std_detect_dlsym_getauxval` cargo feature is ignored on -/// `*-linux-{gnu,musl,ohos}*` and `*-android*` targets because we can safely assume `getauxval` -/// is linked to the binary. +/// Note: We always directly use `getauxval` on `*-linux-{gnu,musl,ohos}*` and +/// `*-android*` targets rather than `dlsym` it because we can safely assume +/// `getauxval` is linked to the binary. /// - `*-linux-gnu*` targets ([since Rust 1.64](https://blog.rust-lang.org/2022/08/01/Increasing-glibc-kernel-requirements.html)) /// have glibc requirements higher than [glibc 2.16 that added `getauxval`](https://sourceware.org/legacy-ml/libc-announce/2012/msg00000.html). /// - `*-linux-musl*` targets ([at least since Rust 1.15](https://github.com/rust-lang/rust/blob/1.15.0/src/ci/docker/x86_64-musl/build-musl.sh#L15)) @@ -71,6 +67,7 @@ pub(crate) struct AuxVec { /// /// [auxvec_h]: https://github.com/torvalds/linux/blob/master/include/uapi/linux/auxvec.h /// [auxv_docs]: https://docs.rs/auxv/0.3.3/auxv/ +/// [`getauxval`]: https://man7.org/linux/man-pages/man3/getauxval.3.html pub(crate) fn auxv() -> Result { // Try to call a getauxval function. if let Ok(hwcap) = getauxval(AT_HWCAP) { @@ -115,16 +112,9 @@ pub(crate) fn auxv() -> Result { let _ = hwcap; } - #[cfg(feature = "std_detect_file_io")] - { - // If calling getauxval fails, try to read the auxiliary vector from - // its file: - auxv_from_file("/proc/self/auxv").map_err(|_| ()) - } - #[cfg(not(feature = "std_detect_file_io"))] - { - Err(()) - } + // If calling getauxval fails, try to read the auxiliary vector from + // its file: + auxv_from_file("/proc/self/auxv").map_err(|_| ()) } /// Tries to read the `key` from the auxiliary vector by calling the @@ -132,14 +122,16 @@ pub(crate) fn auxv() -> Result { fn getauxval(key: usize) -> Result { type F = unsafe extern "C" fn(libc::c_ulong) -> libc::c_ulong; cfg_select! { - all( - feature = "std_detect_dlsym_getauxval", - not(all( + any( + all( target_os = "linux", any(target_env = "gnu", target_env = "musl", target_env = "ohos"), - )), - not(target_os = "android"), + ), + target_os = "android", ) => { + let ffi_getauxval: F = libc::getauxval; + } + _ => { let ffi_getauxval: F = unsafe { let ptr = libc::dlsym(libc::RTLD_DEFAULT, c"getauxval".as_ptr()); if ptr.is_null() { @@ -148,23 +140,18 @@ fn getauxval(key: usize) -> Result { core::mem::transmute(ptr) }; } - _ => { - let ffi_getauxval: F = libc::getauxval; - } } Ok(unsafe { ffi_getauxval(key as libc::c_ulong) as usize }) } /// Tries to read the auxiliary vector from the `file`. If this fails, this /// function returns `Err`. -#[cfg(feature = "std_detect_file_io")] pub(super) fn auxv_from_file(file: &str) -> Result { let file = super::read_file(file)?; auxv_from_file_bytes(&file) } /// Read auxiliary vector from a slice of bytes. -#[cfg(feature = "std_detect_file_io")] pub(super) fn auxv_from_file_bytes(bytes: &[u8]) -> Result { // See . // @@ -181,7 +168,6 @@ pub(super) fn auxv_from_file_bytes(bytes: &[u8]) -> Result Result { // Targets with only AT_HWCAP: #[cfg(any( diff --git a/library/std_detect/src/detect/os/linux/auxvec/tests.rs b/library/std_detect/src/detect/os/linux/auxvec/tests.rs index 631a3e5e9ef1..88f0d6d49337 100644 --- a/library/std_detect/src/detect/os/linux/auxvec/tests.rs +++ b/library/std_detect/src/detect/os/linux/auxvec/tests.rs @@ -41,7 +41,6 @@ fn auxv_dump() { } } -#[cfg(feature = "std_detect_file_io")] cfg_select! { target_arch = "arm" => { // The tests below can be executed under qemu, where we do not have access to the test @@ -86,7 +85,6 @@ cfg_select! { } #[test] -#[cfg(feature = "std_detect_file_io")] fn auxv_dump_procfs() { if let Ok(auxvec) = auxv_from_file("/proc/self/auxv") { println!("{:?}", auxvec); @@ -103,7 +101,6 @@ fn auxv_dump_procfs() { target_arch = "s390x", ))] #[test] -#[cfg(feature = "std_detect_file_io")] fn auxv_crate_procfs() { if let Ok(procfs_auxv) = auxv_from_file("/proc/self/auxv") { assert_eq!(auxv().unwrap(), procfs_auxv); diff --git a/library/std_detect/src/detect/os/linux/mod.rs b/library/std_detect/src/detect/os/linux/mod.rs index 5273c16c0893..aec94f963f5c 100644 --- a/library/std_detect/src/detect/os/linux/mod.rs +++ b/library/std_detect/src/detect/os/linux/mod.rs @@ -1,11 +1,9 @@ //! Run-time feature detection on Linux -//! -#[cfg(feature = "std_detect_file_io")] + use alloc::vec::Vec; mod auxvec; -#[cfg(feature = "std_detect_file_io")] fn read_file(orig_path: &str) -> Result, alloc::string::String> { use alloc::format; diff --git a/library/std_detect/src/lib.rs b/library/std_detect/src/lib.rs index 73e2f5dd9644..5e1d21bbfd17 100644 --- a/library/std_detect/src/lib.rs +++ b/library/std_detect/src/lib.rs @@ -27,8 +27,7 @@ extern crate std; // rust-lang/rust#83888: removing `extern crate` gives an error that `vec_spare> -#[cfg_attr(feature = "std_detect_file_io", allow(unused_extern_crates))] -#[cfg(feature = "std_detect_file_io")] +#[allow(unused_extern_crates)] extern crate alloc; #[doc(hidden)] diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml index eec8c461b6db..a18868082916 100644 --- a/library/sysroot/Cargo.toml +++ b/library/sysroot/Cargo.toml @@ -20,7 +20,7 @@ test = { path = "../test", public = true } # Forward features to the `std` crate as necessary [features] -default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind"] +default = ["panic-unwind"] backtrace = ["std/backtrace"] backtrace-trace-only = ["std/backtrace-trace-only"] compiler-builtins-c = ["std/compiler-builtins-c"] @@ -32,7 +32,5 @@ system-llvm-libunwind = ["std/system-llvm-libunwind"] optimize_for_size = ["std/optimize_for_size"] panic-unwind = ["std/panic-unwind"] profiler = ["dep:profiler_builtins"] -std_detect_file_io = ["std/std_detect_file_io"] -std_detect_dlsym_getauxval = ["std/std_detect_dlsym_getauxval"] windows_raw_dylib = ["std/windows_raw_dylib"] llvm_enzyme = ["std/llvm_enzyme"] From 3fed6e67ef0af1da28254cfc4d8078f0ba222c24 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 8 Jan 2026 12:14:18 +0000 Subject: [PATCH 0404/1061] Remove a couple of outdated fields in std_detect Cargo.toml It is no longer a part of the stdarch repo and the rest is not necessary anymore due to no longer publishing to crates.io. --- library/std_detect/Cargo.toml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/library/std_detect/Cargo.toml b/library/std_detect/Cargo.toml index bcfdb3901957..a6785bb20555 100644 --- a/library/std_detect/Cargo.toml +++ b/library/std_detect/Cargo.toml @@ -7,11 +7,6 @@ authors = [ "Gonzalo Brito Gadeschi ", ] description = "`std::detect` - Rust's standard library run-time CPU feature detection." -homepage = "https://github.com/rust-lang/stdarch" -repository = "https://github.com/rust-lang/stdarch" -readme = "README.md" -keywords = ["std", "run-time", "feature", "detection"] -categories = ["hardware-support"] license = "MIT OR Apache-2.0" edition = "2024" From c873d163239a000bb0d3c29a15a24a98f6f6adf3 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 8 Jan 2026 15:02:42 +0000 Subject: [PATCH 0405/1061] Remove unnecessary module --- .../src/detect/os/linux/aarch64/tests.rs | 140 +++++++++--------- 1 file changed, 67 insertions(+), 73 deletions(-) diff --git a/library/std_detect/src/detect/os/linux/aarch64/tests.rs b/library/std_detect/src/detect/os/linux/aarch64/tests.rs index 912d116d57b8..4d7c9a419d38 100644 --- a/library/std_detect/src/detect/os/linux/aarch64/tests.rs +++ b/library/std_detect/src/detect/os/linux/aarch64/tests.rs @@ -1,76 +1,70 @@ +use super::auxvec::auxv_from_file; use super::*; - -mod auxv_from_file { - use super::auxvec::auxv_from_file; - use super::*; - // The baseline hwcaps used in the (artificial) auxv test files. - fn baseline_hwcaps() -> AtHwcap { - AtHwcap { - fp: true, - asimd: true, - aes: true, - pmull: true, - sha1: true, - sha2: true, - crc32: true, - atomics: true, - fphp: true, - asimdhp: true, - asimdrdm: true, - lrcpc: true, - dcpop: true, - asimddp: true, - ssbs: true, - ..AtHwcap::default() - } - } - - #[test] - fn linux_empty_hwcap2_aarch64() { - let file = concat!( - env!("CARGO_MANIFEST_DIR"), - "/src/detect/test_data/linux-empty-hwcap2-aarch64.auxv" - ); - println!("file: {file}"); - let v = auxv_from_file(file).unwrap(); - println!("HWCAP : 0x{:0x}", v.hwcap); - println!("HWCAP2: 0x{:0x}", v.hwcap2); - assert_eq!(AtHwcap::from(v), baseline_hwcaps()); - } - #[test] - fn linux_no_hwcap2_aarch64() { - let file = concat!( - env!("CARGO_MANIFEST_DIR"), - "/src/detect/test_data/linux-no-hwcap2-aarch64.auxv" - ); - println!("file: {file}"); - let v = auxv_from_file(file).unwrap(); - println!("HWCAP : 0x{:0x}", v.hwcap); - println!("HWCAP2: 0x{:0x}", v.hwcap2); - assert_eq!(AtHwcap::from(v), baseline_hwcaps()); - } - #[test] - fn linux_hwcap2_aarch64() { - let file = - concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-hwcap2-aarch64.auxv"); - println!("file: {file}"); - let v = auxv_from_file(file).unwrap(); - println!("HWCAP : 0x{:0x}", v.hwcap); - println!("HWCAP2: 0x{:0x}", v.hwcap2); - assert_eq!( - AtHwcap::from(v), - AtHwcap { - // Some other HWCAP bits. - paca: true, - pacg: true, - // HWCAP2-only bits. - dcpodp: true, - frint: true, - rng: true, - bti: true, - mte: true, - ..baseline_hwcaps() - } - ); +// The baseline hwcaps used in the (artificial) auxv test files. +fn baseline_hwcaps() -> AtHwcap { + AtHwcap { + fp: true, + asimd: true, + aes: true, + pmull: true, + sha1: true, + sha2: true, + crc32: true, + atomics: true, + fphp: true, + asimdhp: true, + asimdrdm: true, + lrcpc: true, + dcpop: true, + asimddp: true, + ssbs: true, + ..AtHwcap::default() } } + +#[test] +fn linux_empty_hwcap2_aarch64() { + let file = concat!( + env!("CARGO_MANIFEST_DIR"), + "/src/detect/test_data/linux-empty-hwcap2-aarch64.auxv" + ); + println!("file: {file}"); + let v = auxv_from_file(file).unwrap(); + println!("HWCAP : 0x{:0x}", v.hwcap); + println!("HWCAP2: 0x{:0x}", v.hwcap2); + assert_eq!(AtHwcap::from(v), baseline_hwcaps()); +} +#[test] +fn linux_no_hwcap2_aarch64() { + let file = + concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-no-hwcap2-aarch64.auxv"); + println!("file: {file}"); + let v = auxv_from_file(file).unwrap(); + println!("HWCAP : 0x{:0x}", v.hwcap); + println!("HWCAP2: 0x{:0x}", v.hwcap2); + assert_eq!(AtHwcap::from(v), baseline_hwcaps()); +} +#[test] +fn linux_hwcap2_aarch64() { + let file = + concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-hwcap2-aarch64.auxv"); + println!("file: {file}"); + let v = auxv_from_file(file).unwrap(); + println!("HWCAP : 0x{:0x}", v.hwcap); + println!("HWCAP2: 0x{:0x}", v.hwcap2); + assert_eq!( + AtHwcap::from(v), + AtHwcap { + // Some other HWCAP bits. + paca: true, + pacg: true, + // HWCAP2-only bits. + dcpodp: true, + frint: true, + rng: true, + bti: true, + mte: true, + ..baseline_hwcaps() + } + ); +} From 6b88c6b7c2a8322de6ff2211bd3f683e4fb1edbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 8 Jan 2026 16:25:03 +0100 Subject: [PATCH 0406/1061] store defids instead of symbol names in the aliases list --- compiler/rustc_codegen_llvm/src/mono_item.rs | 7 ++++--- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 8 +++----- compiler/rustc_middle/src/middle/codegen_fn_attrs.rs | 3 ++- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 41cf92390b0d..3ce28612ddfc 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -10,7 +10,6 @@ use rustc_middle::mir::mono::Visibility; use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv, LayoutOf}; use rustc_middle::ty::{self, Instance, TypeVisitableExt}; use rustc_session::config::CrateType; -use rustc_span::Symbol; use rustc_target::spec::{Arch, RelocModel}; use tracing::debug; @@ -92,17 +91,19 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { } impl CodegenCx<'_, '_> { - fn add_aliases(&self, aliasee: &llvm::Value, aliases: &[(Symbol, Linkage, Visibility)]) { + fn add_aliases(&self, aliasee: &llvm::Value, aliases: &[(DefId, Linkage, Visibility)]) { let ty = self.get_type_of_global(aliasee); for (alias, linkage, visibility) in aliases { + let symbol_name = self.tcx.symbol_name(Instance::mono(self.tcx, *alias)); + tracing::debug!("ALIAS: {alias:?} {linkage:?} {visibility:?}"); let lldecl = llvm::add_alias( self.llmod, ty, AddressSpace::ZERO, aliasee, - &CString::new(alias.as_str()).unwrap(), + &CString::new(symbol_name.name).unwrap(), ); llvm::set_visibility(lldecl, base::visibility_to_llvm(*visibility)); diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 94dc3f44a68b..74f4662118b6 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -13,10 +13,10 @@ use rustc_middle::middle::codegen_fn_attrs::{ use rustc_middle::mir::mono::Visibility; use rustc_middle::query::Providers; use rustc_middle::span_bug; -use rustc_middle::ty::{self as ty, Instance, TyCtxt}; +use rustc_middle::ty::{self as ty, TyCtxt}; use rustc_session::lint; use rustc_session::parse::feature_err; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, sym}; use rustc_target::spec::Os; use crate::errors; @@ -291,8 +291,6 @@ fn process_builtin_attrs( ) .expect("eii should have declaration macro with extern target attribute"); - let symbol_name = tcx.symbol_name(Instance::mono(tcx, extern_item)); - // this is to prevent a bug where a single crate defines both the default and explicit implementation // for an EII. In that case, both of them may be part of the same final object file. I'm not 100% sure // what happens, either rustc deduplicates the symbol or llvm, or it's random/order-dependent. @@ -310,7 +308,7 @@ fn process_builtin_attrs( } codegen_fn_attrs.foreign_item_symbol_aliases.push(( - Symbol::intern(symbol_name.name), + extern_item, if i.is_default { Linkage::LinkOnceAny } else { Linkage::External }, Visibility::Default, )); diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 9033d9c46d54..4f600af0cbfc 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -2,6 +2,7 @@ use std::borrow::Cow; use rustc_abi::Align; use rustc_hir::attrs::{InlineAttr, InstructionSetAttr, Linkage, OptimizeAttr, RtsanSetting}; +use rustc_hir::def_id::DefId; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_span::Symbol; use rustc_target::spec::SanitizerSet; @@ -72,7 +73,7 @@ pub struct CodegenFnAttrs { /// generate this function under its real name, /// but *also* under the same name as this foreign function so that the foreign function has an implementation. // FIXME: make "SymbolName<'tcx>" - pub foreign_item_symbol_aliases: Vec<(Symbol, Linkage, Visibility)>, + pub foreign_item_symbol_aliases: Vec<(DefId, Linkage, Visibility)>, /// The `#[link_ordinal = "..."]` attribute, indicating an ordinal an /// imported function has in the dynamic library. Note that this must not /// be set when `link_name` is set. This is for foreign items with the From 9f3956f37863800fa6dd325607adf8e43bd66196 Mon Sep 17 00:00:00 2001 From: human9000 Date: Mon, 5 Jan 2026 18:14:12 +0500 Subject: [PATCH 0407/1061] MGCA: literals support --- compiler/rustc_ast_lowering/src/lib.rs | 10 ++++++++++ compiler/rustc_hir/src/hir.rs | 1 + compiler/rustc_hir/src/intravisit.rs | 1 + .../rustc_hir_analysis/src/hir_ty_lowering/mod.rs | 15 +++++++++++++++ compiler/rustc_hir_pretty/src/lib.rs | 6 +++++- compiler/rustc_metadata/src/rmeta/encoder.rs | 1 + src/librustdoc/clean/mod.rs | 6 +++++- src/tools/clippy/clippy_lints/src/utils/author.rs | 1 + src/tools/clippy/clippy_utils/src/consts.rs | 2 +- src/tools/clippy/clippy_utils/src/hir_utils.rs | 5 +++++ .../mgca/explicit_anon_consts_literals_hack.rs | 8 ++------ .../explicit_anon_consts_literals_hack.stderr | 8 -------- 12 files changed, 47 insertions(+), 17 deletions(-) delete mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.stderr diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index a81d2297ef85..fd7c3360b05e 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2536,6 +2536,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { overly_complex_const(self) } + ExprKind::Lit(literal) => { + let span = expr.span; + let literal = self.lower_lit(literal, span); + + ConstArg { + hir_id: self.lower_node_id(expr.id), + kind: hir::ConstArgKind::Literal(literal.node), + span, + } + } _ => overly_complex_const(self), } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index aacd6324bb03..666987860d50 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -518,6 +518,7 @@ pub enum ConstArgKind<'hir, Unambig = ()> { /// This variant is not always used to represent inference consts, sometimes /// [`GenericArg::Infer`] is used instead. Infer(Unambig), + Literal(LitKind), } #[derive(Clone, Copy, Debug, HashStable_Generic)] diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 59db60fdc55c..e5e6fc7b1d8d 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1104,6 +1104,7 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>( ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, qpath.span()), ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon), ConstArgKind::Error(_) => V::Result::output(), // errors and spans are not important + ConstArgKind::Literal(..) => V::Result::output(), // FIXME(mcga) } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index aaa566760013..1dd9bff42575 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -22,6 +22,7 @@ pub mod generics; use std::assert_matches::assert_matches; use std::slice; +use rustc_ast::LitKind; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ @@ -2391,6 +2392,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::ConstArgKind::Anon(anon) => self.lower_const_arg_anon(anon), hir::ConstArgKind::Infer(()) => self.ct_infer(None, const_arg.span), hir::ConstArgKind::Error(e) => ty::Const::new_error(tcx, e), + hir::ConstArgKind::Literal(kind) if let FeedConstTy::WithTy(anon_const_type) = feed => { + self.lower_const_arg_literal(&kind, anon_const_type, const_arg.span) + } + hir::ConstArgKind::Literal(..) => { + let e = self.dcx().span_err(const_arg.span, "literal of unknown type"); + ty::Const::new_error(tcx, e) + } } } @@ -2773,6 +2781,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } + #[instrument(skip(self), level = "debug")] + fn lower_const_arg_literal(&self, kind: &LitKind, ty: Ty<'tcx>, span: Span) -> Const<'tcx> { + let tcx = self.tcx(); + let input = LitToConstInput { lit: *kind, ty, neg: false }; + tcx.at(span).lit_to_const(input) + } + #[instrument(skip(self), level = "debug")] fn try_lower_anon_const_lit( &self, diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 2c160ccef2b6..37fa18c00887 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -21,7 +21,7 @@ use rustc_hir::{ GenericParam, GenericParamKind, HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, TyPatKind, }; -use rustc_span::source_map::SourceMap; +use rustc_span::source_map::{SourceMap, Spanned}; use rustc_span::{DUMMY_SP, FileName, Ident, Span, Symbol, kw, sym}; use {rustc_ast as ast, rustc_hir as hir}; @@ -1157,6 +1157,10 @@ impl<'a> State<'a> { ConstArgKind::Anon(anon) => self.print_anon_const(anon), ConstArgKind::Error(_) => self.word("/*ERROR*/"), ConstArgKind::Infer(..) => self.word("_"), + ConstArgKind::Literal(node) => { + let span = const_arg.span; + self.print_literal(&Spanned { span, node: *node }) + } } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index d0e8bc50c495..c85327dc3db1 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1444,6 +1444,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { | hir::ConstArgKind::TupleCall(..) | hir::ConstArgKind::Tup(..) | hir::ConstArgKind::Path(..) + | hir::ConstArgKind::Literal(..) | hir::ConstArgKind::Infer(..) => true, hir::ConstArgKind::Anon(..) => false, }, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e05d3e416430..817eda4c52ec 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -332,6 +332,9 @@ pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg<'tcx>) -> ConstantKind } hir::ConstArgKind::Anon(anon) => ConstantKind::Anonymous { body: anon.body }, hir::ConstArgKind::Infer(..) | hir::ConstArgKind::Error(..) => ConstantKind::Infer, + hir::ConstArgKind::Literal(..) => { + ConstantKind::Path { path: "/* LITERAL */".to_string().into() } + } } } @@ -1814,7 +1817,8 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T hir::ConstArgKind::Struct(..) | hir::ConstArgKind::Path(..) | hir::ConstArgKind::TupleCall(..) - | hir::ConstArgKind::Tup(..) => { + | hir::ConstArgKind::Tup(..) + | hir::ConstArgKind::Literal(..) => { let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, FeedConstTy::No); print_const(cx, ct) } diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 455f76edc904..7a54ba7a8fe1 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -324,6 +324,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { ConstArgKind::Tup(..) => chain!(self, "let ConstArgKind::Tup(..) = {const_arg}.kind"), ConstArgKind::Infer(..) => chain!(self, "let ConstArgKind::Infer(..) = {const_arg}.kind"), ConstArgKind::Error(..) => chain!(self, "let ConstArgKind::Error(..) = {const_arg}.kind"), + ConstArgKind::Literal(..) => chain!(self, "let ConstArgKind::Literal(..) = {const_arg}.kind") } } diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 46b87fd5df96..5f4b87590dc1 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -1140,7 +1140,7 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx ConstItemRhs::Body(body_id) => Some(tcx.hir_body(body_id).value), ConstItemRhs::TypeConst(const_arg) => match const_arg.kind { ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value), - ConstArgKind::Struct(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Tup(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => { + ConstArgKind::Struct(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Tup(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) | ConstArgKind::Literal(..) => { None }, }, diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 57c896c97172..b4e483ea8072 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -689,6 +689,9 @@ impl HirEqInterExpr<'_, '_, '_> { .zip(*args_b) .all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b)) } + (ConstArgKind::Literal(kind_l), ConstArgKind::Literal(kind_r)) => { + kind_l == kind_r + }, // Use explicit match for now since ConstArg is undergoing flux. ( ConstArgKind::Path(..) @@ -697,6 +700,7 @@ impl HirEqInterExpr<'_, '_, '_> { | ConstArgKind::Tup(..) | ConstArgKind::Infer(..) | ConstArgKind::Struct(..) + | ConstArgKind::Literal(..) | ConstArgKind::Error(..), _, ) => false, @@ -1577,6 +1581,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } }, ConstArgKind::Infer(..) | ConstArgKind::Error(..) => {}, + ConstArgKind::Literal(lit) => lit.hash(&mut self.s) } } diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs b/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs index eb8f04b8b24b..8131a5b72343 100644 --- a/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs +++ b/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs @@ -1,8 +1,4 @@ -// We allow for literals to implicitly be anon consts still regardless -// of whether a const block is placed around them or not -// -// However, we don't allow so for const arguments in field init positions. -// This is just harder to implement so we did not do so. +//@ check-pass #![feature(min_generic_const_args, adt_const_params)] #![expect(incomplete_features)] @@ -27,7 +23,7 @@ fn struct_expr() { fn takes_n() {} takes_n::<{ ADT { field: 1 } }>(); - //~^ ERROR: complex const arguments must be placed inside of a `const` block + takes_n::<{ ADT { field: const { 1 } } }>(); } diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.stderr deleted file mode 100644 index 02647fd808cc..000000000000 --- a/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts_literals_hack.rs:29:30 - | -LL | takes_n::<{ ADT { field: 1 } }>(); - | ^ - -error: aborting due to 1 previous error - From fb5c85071b47a7d1c1c5db9381c0e8722507d350 Mon Sep 17 00:00:00 2001 From: human9000 Date: Mon, 5 Jan 2026 18:14:12 +0500 Subject: [PATCH 0408/1061] MGCA: literals support --- clippy_lints/src/utils/author.rs | 1 + clippy_utils/src/consts.rs | 2 +- clippy_utils/src/hir_utils.rs | 5 +++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 455f76edc904..7a54ba7a8fe1 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -324,6 +324,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { ConstArgKind::Tup(..) => chain!(self, "let ConstArgKind::Tup(..) = {const_arg}.kind"), ConstArgKind::Infer(..) => chain!(self, "let ConstArgKind::Infer(..) = {const_arg}.kind"), ConstArgKind::Error(..) => chain!(self, "let ConstArgKind::Error(..) = {const_arg}.kind"), + ConstArgKind::Literal(..) => chain!(self, "let ConstArgKind::Literal(..) = {const_arg}.kind") } } diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 46b87fd5df96..5f4b87590dc1 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -1140,7 +1140,7 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx ConstItemRhs::Body(body_id) => Some(tcx.hir_body(body_id).value), ConstItemRhs::TypeConst(const_arg) => match const_arg.kind { ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value), - ConstArgKind::Struct(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Tup(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => { + ConstArgKind::Struct(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Tup(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) | ConstArgKind::Literal(..) => { None }, }, diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 57c896c97172..b4e483ea8072 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -689,6 +689,9 @@ impl HirEqInterExpr<'_, '_, '_> { .zip(*args_b) .all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b)) } + (ConstArgKind::Literal(kind_l), ConstArgKind::Literal(kind_r)) => { + kind_l == kind_r + }, // Use explicit match for now since ConstArg is undergoing flux. ( ConstArgKind::Path(..) @@ -697,6 +700,7 @@ impl HirEqInterExpr<'_, '_, '_> { | ConstArgKind::Tup(..) | ConstArgKind::Infer(..) | ConstArgKind::Struct(..) + | ConstArgKind::Literal(..) | ConstArgKind::Error(..), _, ) => false, @@ -1577,6 +1581,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } }, ConstArgKind::Infer(..) | ConstArgKind::Error(..) => {}, + ConstArgKind::Literal(lit) => lit.hash(&mut self.s) } } From 331f75f4a773fadba135664190905457946ea98e Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Thu, 8 Jan 2026 16:37:55 +0100 Subject: [PATCH 0409/1061] Do not warn on arithmetic side effect for `String`+`String` The previous fix only handled `String`+`str`. --- .../src/operators/arithmetic_side_effects.rs | 5 +- tests/ui/arithmetic_side_effects.rs | 1 - tests/ui/arithmetic_side_effects.stderr | 266 +++++++++--------- 3 files changed, 134 insertions(+), 138 deletions(-) diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs index 91a069559f7b..106286d16d18 100644 --- a/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -33,7 +33,10 @@ impl ArithmeticSideEffects { allowed_binary.extend([ ("f32", FxHashSet::from_iter(["f32"])), ("f64", FxHashSet::from_iter(["f64"])), - ("std::string::String", FxHashSet::from_iter(["str"])), + ( + "std::string::String", + FxHashSet::from_iter(["str", "std::string::String"]), + ), ]); for (lhs, rhs) in &conf.arithmetic_side_effects_allowed_binary { allowed_binary.entry(lhs).or_default().insert(rhs); diff --git a/tests/ui/arithmetic_side_effects.rs b/tests/ui/arithmetic_side_effects.rs index b7ed596d811e..87397a549bf4 100644 --- a/tests/ui/arithmetic_side_effects.rs +++ b/tests/ui/arithmetic_side_effects.rs @@ -174,7 +174,6 @@ pub fn hard_coded_allowed() { let _ = Saturating(0u32) + Saturating(0u32); let _ = String::new() + ""; let _ = String::new() + &String::new(); - //~^ arithmetic_side_effects let _ = Wrapping(0u32) + Wrapping(0u32); let saturating: Saturating = Saturating(0u32); diff --git a/tests/ui/arithmetic_side_effects.stderr b/tests/ui/arithmetic_side_effects.stderr index 22742a82601a..2767a051786e 100644 --- a/tests/ui/arithmetic_side_effects.stderr +++ b/tests/ui/arithmetic_side_effects.stderr @@ -14,784 +14,778 @@ LL | let _ = 1f128 + 1f128; | ^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:176:13 - | -LL | let _ = String::new() + &String::new(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:312:5 + --> tests/ui/arithmetic_side_effects.rs:311:5 | LL | _n += 1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:314:5 + --> tests/ui/arithmetic_side_effects.rs:313:5 | LL | _n += &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:316:5 + --> tests/ui/arithmetic_side_effects.rs:315:5 | LL | _n -= 1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:318:5 + --> tests/ui/arithmetic_side_effects.rs:317:5 | LL | _n -= &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:320:5 + --> tests/ui/arithmetic_side_effects.rs:319:5 | LL | _n /= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:322:5 + --> tests/ui/arithmetic_side_effects.rs:321:5 | LL | _n /= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:324:5 + --> tests/ui/arithmetic_side_effects.rs:323:5 | LL | _n %= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:326:5 + --> tests/ui/arithmetic_side_effects.rs:325:5 | LL | _n %= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:328:5 + --> tests/ui/arithmetic_side_effects.rs:327:5 | LL | _n *= 2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:330:5 + --> tests/ui/arithmetic_side_effects.rs:329:5 | LL | _n *= &2; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:332:5 + --> tests/ui/arithmetic_side_effects.rs:331:5 | LL | _n += -1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:334:5 + --> tests/ui/arithmetic_side_effects.rs:333:5 | LL | _n += &-1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:336:5 + --> tests/ui/arithmetic_side_effects.rs:335:5 | LL | _n -= -1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:338:5 + --> tests/ui/arithmetic_side_effects.rs:337:5 | LL | _n -= &-1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:340:5 + --> tests/ui/arithmetic_side_effects.rs:339:5 | LL | _n /= -0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:342:5 + --> tests/ui/arithmetic_side_effects.rs:341:5 | LL | _n /= &-0; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:344:5 + --> tests/ui/arithmetic_side_effects.rs:343:5 | LL | _n %= -0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:346:5 + --> tests/ui/arithmetic_side_effects.rs:345:5 | LL | _n %= &-0; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:348:5 + --> tests/ui/arithmetic_side_effects.rs:347:5 | LL | _n *= -2; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:350:5 + --> tests/ui/arithmetic_side_effects.rs:349:5 | LL | _n *= &-2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:352:5 + --> tests/ui/arithmetic_side_effects.rs:351:5 | LL | _custom += Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:354:5 + --> tests/ui/arithmetic_side_effects.rs:353:5 | LL | _custom += &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:356:5 + --> tests/ui/arithmetic_side_effects.rs:355:5 | LL | _custom -= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:358:5 + --> tests/ui/arithmetic_side_effects.rs:357:5 | LL | _custom -= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:360:5 + --> tests/ui/arithmetic_side_effects.rs:359:5 | LL | _custom /= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:362:5 + --> tests/ui/arithmetic_side_effects.rs:361:5 | LL | _custom /= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:364:5 + --> tests/ui/arithmetic_side_effects.rs:363:5 | LL | _custom %= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:366:5 + --> tests/ui/arithmetic_side_effects.rs:365:5 | LL | _custom %= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:368:5 + --> tests/ui/arithmetic_side_effects.rs:367:5 | LL | _custom *= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:370:5 + --> tests/ui/arithmetic_side_effects.rs:369:5 | LL | _custom *= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:372:5 + --> tests/ui/arithmetic_side_effects.rs:371:5 | LL | _custom >>= Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:374:5 + --> tests/ui/arithmetic_side_effects.rs:373:5 | LL | _custom >>= &Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:376:5 + --> tests/ui/arithmetic_side_effects.rs:375:5 | LL | _custom <<= Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:378:5 + --> tests/ui/arithmetic_side_effects.rs:377:5 | LL | _custom <<= &Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:380:5 + --> tests/ui/arithmetic_side_effects.rs:379:5 | LL | _custom += -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:382:5 + --> tests/ui/arithmetic_side_effects.rs:381:5 | LL | _custom += &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:384:5 + --> tests/ui/arithmetic_side_effects.rs:383:5 | LL | _custom -= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:386:5 + --> tests/ui/arithmetic_side_effects.rs:385:5 | LL | _custom -= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:388:5 + --> tests/ui/arithmetic_side_effects.rs:387:5 | LL | _custom /= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:390:5 + --> tests/ui/arithmetic_side_effects.rs:389:5 | LL | _custom /= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:392:5 + --> tests/ui/arithmetic_side_effects.rs:391:5 | LL | _custom %= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:394:5 + --> tests/ui/arithmetic_side_effects.rs:393:5 | LL | _custom %= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:396:5 + --> tests/ui/arithmetic_side_effects.rs:395:5 | LL | _custom *= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:398:5 + --> tests/ui/arithmetic_side_effects.rs:397:5 | LL | _custom *= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:400:5 + --> tests/ui/arithmetic_side_effects.rs:399:5 | LL | _custom >>= -Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:402:5 + --> tests/ui/arithmetic_side_effects.rs:401:5 | LL | _custom >>= &-Custom; | ^^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:404:5 + --> tests/ui/arithmetic_side_effects.rs:403:5 | LL | _custom <<= -Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:406:5 + --> tests/ui/arithmetic_side_effects.rs:405:5 | LL | _custom <<= &-Custom; | ^^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:410:10 + --> tests/ui/arithmetic_side_effects.rs:409:10 | LL | _n = _n + 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:412:10 + --> tests/ui/arithmetic_side_effects.rs:411:10 | LL | _n = _n + &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:414:10 + --> tests/ui/arithmetic_side_effects.rs:413:10 | LL | _n = 1 + _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:416:10 + --> tests/ui/arithmetic_side_effects.rs:415:10 | LL | _n = &1 + _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:418:10 + --> tests/ui/arithmetic_side_effects.rs:417:10 | LL | _n = _n - 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:420:10 + --> tests/ui/arithmetic_side_effects.rs:419:10 | LL | _n = _n - &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:422:10 + --> tests/ui/arithmetic_side_effects.rs:421:10 | LL | _n = 1 - _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:424:10 + --> tests/ui/arithmetic_side_effects.rs:423:10 | LL | _n = &1 - _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:426:10 + --> tests/ui/arithmetic_side_effects.rs:425:10 | LL | _n = _n / 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:428:10 + --> tests/ui/arithmetic_side_effects.rs:427:10 | LL | _n = _n / &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:430:10 + --> tests/ui/arithmetic_side_effects.rs:429:10 | LL | _n = _n % 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:432:10 + --> tests/ui/arithmetic_side_effects.rs:431:10 | LL | _n = _n % &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:434:10 + --> tests/ui/arithmetic_side_effects.rs:433:10 | LL | _n = _n * 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:436:10 + --> tests/ui/arithmetic_side_effects.rs:435:10 | LL | _n = _n * &2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:438:10 + --> tests/ui/arithmetic_side_effects.rs:437:10 | LL | _n = 2 * _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:440:10 + --> tests/ui/arithmetic_side_effects.rs:439:10 | LL | _n = &2 * _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:442:10 + --> tests/ui/arithmetic_side_effects.rs:441:10 | LL | _n = 23 + &85; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:444:10 + --> tests/ui/arithmetic_side_effects.rs:443:10 | LL | _n = &23 + 85; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:446:10 + --> tests/ui/arithmetic_side_effects.rs:445:10 | LL | _n = &23 + &85; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:448:15 + --> tests/ui/arithmetic_side_effects.rs:447:15 | LL | _custom = _custom + _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:450:15 + --> tests/ui/arithmetic_side_effects.rs:449:15 | LL | _custom = _custom + &_custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:452:15 + --> tests/ui/arithmetic_side_effects.rs:451:15 | LL | _custom = Custom + _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:454:15 + --> tests/ui/arithmetic_side_effects.rs:453:15 | LL | _custom = &Custom + _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:456:15 + --> tests/ui/arithmetic_side_effects.rs:455:15 | LL | _custom = _custom - Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:458:15 + --> tests/ui/arithmetic_side_effects.rs:457:15 | LL | _custom = _custom - &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:460:15 + --> tests/ui/arithmetic_side_effects.rs:459:15 | LL | _custom = Custom - _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:462:15 + --> tests/ui/arithmetic_side_effects.rs:461:15 | LL | _custom = &Custom - _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:464:15 + --> tests/ui/arithmetic_side_effects.rs:463:15 | LL | _custom = _custom / Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:466:15 + --> tests/ui/arithmetic_side_effects.rs:465:15 | LL | _custom = _custom / &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:468:15 + --> tests/ui/arithmetic_side_effects.rs:467:15 | LL | _custom = _custom % Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:470:15 + --> tests/ui/arithmetic_side_effects.rs:469:15 | LL | _custom = _custom % &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:472:15 + --> tests/ui/arithmetic_side_effects.rs:471:15 | LL | _custom = _custom * Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:474:15 + --> tests/ui/arithmetic_side_effects.rs:473:15 | LL | _custom = _custom * &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:476:15 + --> tests/ui/arithmetic_side_effects.rs:475:15 | LL | _custom = Custom * _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:478:15 + --> tests/ui/arithmetic_side_effects.rs:477:15 | LL | _custom = &Custom * _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:480:15 + --> tests/ui/arithmetic_side_effects.rs:479:15 | LL | _custom = Custom + &Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:482:15 + --> tests/ui/arithmetic_side_effects.rs:481:15 | LL | _custom = &Custom + Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:484:15 + --> tests/ui/arithmetic_side_effects.rs:483:15 | LL | _custom = &Custom + &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:486:15 + --> tests/ui/arithmetic_side_effects.rs:485:15 | LL | _custom = _custom >> _custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:488:15 + --> tests/ui/arithmetic_side_effects.rs:487:15 | LL | _custom = _custom >> &_custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:490:15 + --> tests/ui/arithmetic_side_effects.rs:489:15 | LL | _custom = Custom << _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:492:15 + --> tests/ui/arithmetic_side_effects.rs:491:15 | LL | _custom = &Custom << _custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:496:23 + --> tests/ui/arithmetic_side_effects.rs:495:23 | LL | _n.saturating_div(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:498:21 + --> tests/ui/arithmetic_side_effects.rs:497:21 | LL | _n.wrapping_div(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:500:21 + --> tests/ui/arithmetic_side_effects.rs:499:21 | LL | _n.wrapping_rem(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:502:28 + --> tests/ui/arithmetic_side_effects.rs:501:28 | LL | _n.wrapping_rem_euclid(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:505:23 + --> tests/ui/arithmetic_side_effects.rs:504:23 | LL | _n.saturating_div(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:507:21 + --> tests/ui/arithmetic_side_effects.rs:506:21 | LL | _n.wrapping_div(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:509:21 + --> tests/ui/arithmetic_side_effects.rs:508:21 | LL | _n.wrapping_rem(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:511:28 + --> tests/ui/arithmetic_side_effects.rs:510:28 | LL | _n.wrapping_rem_euclid(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:514:23 + --> tests/ui/arithmetic_side_effects.rs:513:23 | LL | _n.saturating_div(*Box::new(_n)); | ^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:518:10 + --> tests/ui/arithmetic_side_effects.rs:517:10 | LL | _n = -_n; | ^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:520:10 + --> tests/ui/arithmetic_side_effects.rs:519:10 | LL | _n = -&_n; | ^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:522:15 + --> tests/ui/arithmetic_side_effects.rs:521:15 | LL | _custom = -_custom; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:524:15 + --> tests/ui/arithmetic_side_effects.rs:523:15 | LL | _custom = -&_custom; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:526:9 + --> tests/ui/arithmetic_side_effects.rs:525:9 | LL | _ = -*Box::new(_n); | ^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:536:5 + --> tests/ui/arithmetic_side_effects.rs:535:5 | LL | 1 + i; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:538:5 + --> tests/ui/arithmetic_side_effects.rs:537:5 | LL | i * 2; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:540:5 + --> tests/ui/arithmetic_side_effects.rs:539:5 | LL | 1 % i / 2; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:542:5 + --> tests/ui/arithmetic_side_effects.rs:541:5 | LL | i - 2 + 2 - i; | ^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:544:5 + --> tests/ui/arithmetic_side_effects.rs:543:5 | LL | -i; | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:556:5 + --> tests/ui/arithmetic_side_effects.rs:555:5 | LL | i += 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:558:5 + --> tests/ui/arithmetic_side_effects.rs:557:5 | LL | i -= 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:560:5 + --> tests/ui/arithmetic_side_effects.rs:559:5 | LL | i *= 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:563:5 + --> tests/ui/arithmetic_side_effects.rs:562:5 | LL | i /= 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:566:5 + --> tests/ui/arithmetic_side_effects.rs:565:5 | LL | i /= var1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:568:5 + --> tests/ui/arithmetic_side_effects.rs:567:5 | LL | i /= var2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:571:5 + --> tests/ui/arithmetic_side_effects.rs:570:5 | LL | i %= 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:574:5 + --> tests/ui/arithmetic_side_effects.rs:573:5 | LL | i %= var1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:576:5 + --> tests/ui/arithmetic_side_effects.rs:575:5 | LL | i %= var2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:587:5 + --> tests/ui/arithmetic_side_effects.rs:586:5 | LL | 10 / a | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:642:9 + --> tests/ui/arithmetic_side_effects.rs:641:9 | LL | x / maybe_zero | ^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:647:9 + --> tests/ui/arithmetic_side_effects.rs:646:9 | LL | x % maybe_zero | ^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:659:5 + --> tests/ui/arithmetic_side_effects.rs:658:5 | LL | one.add_assign(1); | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:664:5 + --> tests/ui/arithmetic_side_effects.rs:663:5 | LL | one.sub_assign(1); | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:685:5 + --> tests/ui/arithmetic_side_effects.rs:684:5 | LL | one.add(&one); | ^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:687:5 + --> tests/ui/arithmetic_side_effects.rs:686:5 | LL | Box::new(one).add(one); | ^^^^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:696:13 + --> tests/ui/arithmetic_side_effects.rs:695:13 | LL | let _ = u128::MAX + u128::from(1u8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:713:13 + --> tests/ui/arithmetic_side_effects.rs:712:13 | LL | let _ = u128::MAX * u128::from(1u8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:736:33 + --> tests/ui/arithmetic_side_effects.rs:735:33 | LL | let _ = Duration::from_secs(86400 * Foo::from(1)); | ^^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:742:33 + --> tests/ui/arithmetic_side_effects.rs:741:33 | LL | let _ = Duration::from_secs(86400 * shift(1)); | ^^^^^^^^^^^^^^^^ -error: aborting due to 132 previous errors +error: aborting due to 131 previous errors From 20a94d65e5e6ea1c187fe14e5ae79a7078dcd206 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Thu, 8 Jan 2026 23:55:57 +0800 Subject: [PATCH 0410/1061] Bump `diesel` to the most recent commit in `cargotest` `cargotest` can only detect the worst offenders (like tests failing, or hard compiler errors / ICEs), but regardless, bumping `diesel` to a way more recent version hopefully contributes slightly towards helping us not break `diesel` if at all possible. --- src/tools/cargotest/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs index 4c57683806e6..5bbed35e2068 100644 --- a/src/tools/cargotest/main.rs +++ b/src/tools/cargotest/main.rs @@ -84,7 +84,7 @@ const TEST_REPOS: &[Test] = &[ Test { name: "diesel", repo: "https://github.com/diesel-rs/diesel", - sha: "91493fe47175076f330ce5fc518f0196c0476f56", + sha: "3db7c17c5b069656ed22750e84d6498c8ab5b81d", lock: None, packages: &[], // Test the embedded sqlite variant of diesel From 80dedb601aababe989be488a18f14a4d3c4b7234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 31 Dec 2025 14:11:32 +0100 Subject: [PATCH 0411/1061] Add a dist step for GCC --- src/bootstrap/src/core/build_steps/compile.rs | 29 ++++--- src/bootstrap/src/core/build_steps/dist.rs | 84 ++++++++++++++++++- src/bootstrap/src/core/builder/mod.rs | 3 +- src/bootstrap/src/utils/tarball.rs | 10 +++ 4 files changed, 114 insertions(+), 12 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 02be3f2cc735..79a564cfb1ff 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1612,26 +1612,35 @@ impl GccDylibSet { "Trying to install libgccjit ({target_pair}) to a compiler with a different host ({})", compiler.host ); - let libgccjit = libgccjit.libgccjit(); - let target_filename = libgccjit.file_name().unwrap().to_str().unwrap(); + let libgccjit_path = libgccjit.libgccjit(); // If we build libgccjit ourselves, then `libgccjit` can actually be a symlink. // In that case, we have to resolve it first, otherwise we'd create a symlink to a // symlink, which wouldn't work. - let actual_libgccjit_path = t!( - libgccjit.canonicalize(), - format!("Cannot find libgccjit at {}", libgccjit.display()) + let libgccjit_path = t!( + libgccjit_path.canonicalize(), + format!("Cannot find libgccjit at {}", libgccjit_path.display()) ); - // /lib//libgccjit.so - let dest_dir = cg_sysroot.join("lib").join(target_pair.target()); - t!(fs::create_dir_all(&dest_dir)); - let dst = dest_dir.join(target_filename); - builder.copy_link(&actual_libgccjit_path, &dst, FileType::NativeLibrary); + let dst = cg_sysroot.join(libgccjit_path_relative_to_cg_dir(target_pair, libgccjit)); + t!(std::fs::create_dir_all(dst.parent().unwrap())); + builder.copy_link(&libgccjit_path, &dst, FileType::NativeLibrary); } } } +/// Returns a path where libgccjit.so should be stored, **relative** to the +/// **codegen backend directory**. +pub fn libgccjit_path_relative_to_cg_dir( + target_pair: &GccTargetPair, + libgccjit: &GccOutput, +) -> PathBuf { + let target_filename = libgccjit.libgccjit().file_name().unwrap().to_str().unwrap(); + + // /lib//libgccjit.so + Path::new("lib").join(target_pair.target()).join(target_filename) +} + /// Output of the `compile::GccCodegenBackend` step. /// /// It contains a build stamp with the path to the built cg_gcc dylib. diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index f47b0c0b0072..cfcb144e0993 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -19,7 +19,9 @@ use object::read::archive::ArchiveFile; #[cfg(feature = "tracing")] use tracing::instrument; -use crate::core::build_steps::compile::{get_codegen_backend_file, normalize_codegen_backend_name}; +use crate::core::build_steps::compile::{ + get_codegen_backend_file, libgccjit_path_relative_to_cg_dir, normalize_codegen_backend_name, +}; use crate::core::build_steps::doc::DocumentationFormat; use crate::core::build_steps::gcc::GccTargetPair; use crate::core::build_steps::tool::{ @@ -2992,3 +2994,83 @@ impl Step for GccDev { Some(StepMetadata::dist("gcc-dev", self.target)) } } + +/// Tarball containing a libgccjit dylib, +/// needed as a dependency for the GCC codegen backend (similarly to the LLVM +/// backend needing a prebuilt libLLVM). +/// +/// This component is used for distribution through rustup. +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct Gcc { + host: TargetSelection, + target: TargetSelection, +} + +impl Step for Gcc { + type Output = Option; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.alias("gcc") + } + + fn make_run(run: RunConfig<'_>) { + // GCC is always built for a target pair, (host, target). + // We do not yet support cross-compilation here, so the host target is always inferred to + // be the bootstrap host target. + run.builder.ensure(Gcc { host: run.builder.host_target, target: run.target }); + } + + fn run(self, builder: &Builder<'_>) -> Self::Output { + // This prevents gcc from being built for "dist" + // or "install" on the stable/beta channels. It is not yet stable and + // should not be included. + if !builder.build.unstable_features() { + return None; + } + + let host = self.host; + let target = self.target; + if host != "x86_64-unknown-linux-gnu" { + builder.info(&format!("host target `{host}` not supported by gcc. skipping")); + return None; + } + + // We need the GCC sources to build GCC and also to add its license and README + // files to the tarball + builder.require_submodule( + "src/gcc", + Some("The src/gcc submodule is required for disting libgccjit"), + ); + + let target_pair = GccTargetPair::for_target_pair(host, target); + let libgccjit = builder.ensure(super::gcc::Gcc { target_pair }); + + // We have to include the target name in the component name, so that rustup can somehow + // distinguish that there are multiple gcc components on a given host target. + // So the tarball includes the target name. + let mut tarball = Tarball::new(builder, &format!("gcc-{target}"), &host.triple); + tarball.set_overlay(OverlayKind::Gcc); + tarball.is_preview(true); + tarball.add_legal_and_readme_to("share/doc/gcc"); + + // The path where to put libgccjit is determined by GccDylibSet. + // However, it requires a Compiler to figure out the path to the codegen backend sysroot. + // We don't really have any compiler here, because we just build libgccjit. + // So we duplicate the logic for determining the CG sysroot here. + let cg_dir = PathBuf::from(format!("lib/rustlib/{host}/codegen-backends")); + + // This returns the path to the actual file, but here we need its parent + let rel_libgccjit_path = libgccjit_path_relative_to_cg_dir(&target_pair, &libgccjit); + let path = cg_dir.join(rel_libgccjit_path.parent().unwrap()); + + tarball.add_file(libgccjit.libgccjit(), path, FileType::NativeLibrary); + Some(tarball.generate()) + } + + fn metadata(&self) -> Option { + Some(StepMetadata::dist( + "gcc", + TargetSelection::from_user(&format!("({}, {})", self.host, self.target)), + )) + } +} diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 4a04b97c549a..f63b8e044550 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -990,7 +990,8 @@ impl<'a> Builder<'a> { dist::PlainSourceTarballGpl, dist::BuildManifest, dist::ReproducibleArtifacts, - dist::GccDev + dist::GccDev, + dist::Gcc ), Kind::Install => describe!( install::Docs, diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index 7db06dcc3e9a..cd6a03c84870 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -26,6 +26,7 @@ pub(crate) enum OverlayKind { RustAnalyzer, RustcCodegenCranelift, RustcCodegenGcc, + Gcc, LlvmBitcodeLinker, } @@ -78,6 +79,14 @@ impl OverlayKind { "LICENSE-MIT", "src/tools/llvm-bitcode-linker/README.md", ], + OverlayKind::Gcc => &[ + "src/gcc/README", + "src/gcc/COPYING", + "src/gcc/COPYING.LIB", + "src/gcc/COPYING.RUNTIME", + "src/gcc/COPYING3", + "src/gcc/COPYING3.LIB", + ], } } @@ -101,6 +110,7 @@ impl OverlayKind { OverlayKind::RustcCodegenCranelift => builder.rust_version(), OverlayKind::RustcCodegenGcc => builder.rust_version(), OverlayKind::LlvmBitcodeLinker => builder.rust_version(), + OverlayKind::Gcc => builder.rust_version(), } } } From b0aa77a0267040b6155d75487e8ecc7be7790bf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 31 Dec 2025 14:12:17 +0100 Subject: [PATCH 0412/1061] Build GCC on CI --- src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh index f77a0d562f03..c78b76a53f44 100755 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh @@ -14,5 +14,7 @@ python3 ../x.py build --set rust.debug=true opt-dist # Use GCC for building GCC components, as it seems to behave badly when built with Clang # Only build GCC on full builds, not try builds if [ "${DIST_TRY_BUILD:-0}" == "0" ]; then - CC=/rustroot/bin/cc CXX=/rustroot/bin/c++ python3 ../x.py dist gcc-dev + CC=/rustroot/bin/cc CXX=/rustroot/bin/c++ python3 ../x.py dist \ + gcc-dev \ + gcc fi From 308c6076ec614ce401f77e38670391fb0b5c7ff6 Mon Sep 17 00:00:00 2001 From: dianne Date: Thu, 8 Jan 2026 08:44:04 -0800 Subject: [PATCH 0413/1061] remove borrowck handling for inline const patterns --- compiler/rustc_borrowck/src/type_check/mod.rs | 67 +++---------------- 1 file changed, 9 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index e5aad4cdbd06..d2464c7e99ee 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -19,6 +19,7 @@ use rustc_infer::infer::{ BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, }; use rustc_infer::traits::PredicateObligations; +use rustc_middle::bug; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::traits::query::NoSolution; @@ -28,7 +29,6 @@ use rustc_middle::ty::{ self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CoroutineArgsExt, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, UserArgs, UserTypeAnnotationIndex, fold_regions, }; -use rustc_middle::{bug, span_bug}; use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::points::DenseLocationMap; use rustc_span::def_id::CRATE_DEF_ID; @@ -387,18 +387,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { #[instrument(skip(self), level = "debug")] fn check_user_type_annotations(&mut self) { debug!(?self.user_type_annotations); - let tcx = self.tcx(); for user_annotation in self.user_type_annotations { let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation; let annotation = self.instantiate_canonical(span, user_ty); - if let ty::UserTypeKind::TypeOf(def, args) = annotation.kind - && let DefKind::InlineConst = tcx.def_kind(def) - { - assert!(annotation.bounds.is_empty()); - self.check_inline_const(inferred_ty, def.expect_local(), args, span); - } else { - self.ascribe_user_type(inferred_ty, annotation, span); - } + self.ascribe_user_type(inferred_ty, annotation, span); } } @@ -560,36 +552,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.constraints.liveness_constraints.add_location(region, location); } } - - fn check_inline_const( - &mut self, - inferred_ty: Ty<'tcx>, - def_id: LocalDefId, - args: UserArgs<'tcx>, - span: Span, - ) { - assert!(args.user_self_ty.is_none()); - let tcx = self.tcx(); - let const_ty = tcx.type_of(def_id).instantiate(tcx, args.args); - if let Err(terr) = - self.eq_types(const_ty, inferred_ty, Locations::All(span), ConstraintCategory::Boring) - { - span_bug!( - span, - "bad inline const pattern: ({:?} = {:?}) {:?}", - const_ty, - inferred_ty, - terr - ); - } - let args = self.infcx.resolve_vars_if_possible(args.args); - let predicates = self.prove_closure_bounds(tcx, def_id, args, Locations::All(span)); - self.normalize_and_prove_instantiated_predicates( - def_id.to_def_id(), - predicates, - Locations::All(span), - ); - } } impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { @@ -1731,12 +1693,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let def_id = uv.def; if tcx.def_kind(def_id) == DefKind::InlineConst { let def_id = def_id.expect_local(); - let predicates = self.prove_closure_bounds( - tcx, - def_id, - uv.args, - location.to_locations(), - ); + let predicates = self.prove_closure_bounds(tcx, def_id, uv.args, location); self.normalize_and_prove_instantiated_predicates( def_id.to_def_id(), predicates, @@ -2519,15 +2476,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // clauses on the struct. AggregateKind::Closure(def_id, args) | AggregateKind::CoroutineClosure(def_id, args) - | AggregateKind::Coroutine(def_id, args) => ( - def_id, - self.prove_closure_bounds( - tcx, - def_id.expect_local(), - args, - location.to_locations(), - ), - ), + | AggregateKind::Coroutine(def_id, args) => { + (def_id, self.prove_closure_bounds(tcx, def_id.expect_local(), args, location)) + } AggregateKind::Array(_) | AggregateKind::Tuple | AggregateKind::RawPtr(..) => { (CRATE_DEF_ID.to_def_id(), ty::InstantiatedPredicates::empty()) @@ -2546,12 +2497,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { tcx: TyCtxt<'tcx>, def_id: LocalDefId, args: GenericArgsRef<'tcx>, - locations: Locations, + location: Location, ) -> ty::InstantiatedPredicates<'tcx> { let root_def_id = self.root_cx.root_def_id(); // We will have to handle propagated closure requirements for this closure, // but need to defer this until the nested body has been fully borrow checked. - self.deferred_closure_requirements.push((def_id, args, locations)); + self.deferred_closure_requirements.push((def_id, args, location.to_locations())); // Equate closure args to regions inherited from `root_def_id`. Fixes #98589. let typeck_root_args = ty::GenericArgs::identity_for_item(tcx, root_def_id); @@ -2575,7 +2526,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if let Err(_) = self.eq_args( typeck_root_args, parent_args, - locations, + location.to_locations(), ConstraintCategory::BoringNoLocation, ) { span_mirbug!( From 5356be04a8c8ee194e200c66b6c5eeb34c0543ca Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 8 Jan 2026 18:36:51 +0100 Subject: [PATCH 0414/1061] Bump nightly version -> 2026-01-08 --- clippy_utils/README.md | 2 +- rust-toolchain.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_utils/README.md b/clippy_utils/README.md index 69bb6a2d6669..ecd36b157571 100644 --- a/clippy_utils/README.md +++ b/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: ``` -nightly-2025-12-25 +nightly-2026-01-08 ``` diff --git a/rust-toolchain.toml b/rust-toolchain.toml index dbec79e111fb..0755e1d29c69 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2025-12-25" +channel = "nightly-2026-01-08" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" From 6ed95301410f592c97b4a7499fb22ea087148291 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Thu, 8 Jan 2026 18:21:54 +0100 Subject: [PATCH 0415/1061] tests/ui/borrowck/issue-92157.rs: Remove (bug not fixed) --- src/tools/tidy/src/issues.txt | 1 - tests/ui/borrowck/issue-92157.rs | 20 -------------------- tests/ui/borrowck/issue-92157.stderr | 12 ------------ 3 files changed, 33 deletions(-) delete mode 100644 tests/ui/borrowck/issue-92157.rs delete mode 100644 tests/ui/borrowck/issue-92157.stderr diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 45187a0b6450..b3e17b73237d 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -379,7 +379,6 @@ ui/borrowck/issue-88434-minimal-example.rs ui/borrowck/issue-88434-removal-index-should-be-less.rs ui/borrowck/issue-91206.rs ui/borrowck/issue-92015.rs -ui/borrowck/issue-92157.rs ui/borrowck/issue-93078.rs ui/borrowck/issue-93093.rs ui/borrowck/issue-95079-missing-move-in-nested-closure.rs diff --git a/tests/ui/borrowck/issue-92157.rs b/tests/ui/borrowck/issue-92157.rs deleted file mode 100644 index 3dbcb4ad8b7f..000000000000 --- a/tests/ui/borrowck/issue-92157.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ add-minicore -#![feature(no_core)] -#![feature(lang_items)] - -#![no_core] - -#[cfg(target_os = "linux")] -#[link(name = "c")] -extern "C" {} - -#[lang = "start"] -fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize { - //~^ ERROR lang item `start` function has wrong type [E0308] - 40+2 -} - -extern crate minicore; -use minicore::*; - -fn main() {} diff --git a/tests/ui/borrowck/issue-92157.stderr b/tests/ui/borrowck/issue-92157.stderr deleted file mode 100644 index 248d700ab4b9..000000000000 --- a/tests/ui/borrowck/issue-92157.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0308]: lang item `start` function has wrong type - --> $DIR/issue-92157.rs:12:1 - | -LL | fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters - | - = note: expected signature `fn(fn() -> T, isize, *const *const u8, u8) -> _` - found signature `fn(fn() -> T, isize, *const *const u8) -> _` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0308`. From 8e3d60447cfe78a7467a61a509032b45dca66c0b Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Thu, 1 Jan 2026 10:47:22 +0100 Subject: [PATCH 0416/1061] Finish transition from `semitransparent` to `semiopaque` for `rustc_macro_transparency` --- compiler/rustc_arena/src/lib.rs | 2 +- .../src/attributes/transparency.rs | 6 +++--- .../rustc_codegen_cranelift/example/mini_core.rs | 14 +++++++------- compiler/rustc_codegen_cranelift/src/global_asm.rs | 2 +- compiler/rustc_codegen_gcc/example/mini_core.rs | 8 ++++---- compiler/rustc_span/src/symbol.rs | 1 - library/core/src/macros/mod.rs | 4 ++-- library/core/src/panic.rs | 8 ++++---- library/core/src/pin.rs | 2 +- library/core/src/ptr/mod.rs | 4 ++-- library/core/src/task/ready.rs | 2 +- library/std/src/io/error.rs | 2 +- library/std/src/panic.rs | 2 +- library/std/src/sys/thread_local/native/mod.rs | 4 ++-- library/std/src/sys/thread_local/no_threads.rs | 4 ++-- library/std/src/sys/thread_local/os.rs | 4 ++-- library/std/src/thread/local.rs | 2 +- tests/rustdoc-html/macro/macro_pub_in_module.rs | 2 +- tests/ui/attributes/malformed-attrs.stderr | 4 ++-- tests/ui/hygiene/duplicate_lifetimes.rs | 2 +- tests/ui/hygiene/generic_params.rs | 6 +++--- tests/ui/hygiene/rustc-macro-transparency.rs | 2 +- tests/ui/single-use-lifetime/issue-104440.rs | 6 +++--- 23 files changed, 46 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index a0350dd6ff31..5e81ec28ee35 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -618,7 +618,7 @@ impl DroplessArena { /// - Types that are `!Copy` and `Drop`: these must be specified in the /// arguments. The `TypedArena` will be used for them. /// -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { #[derive(Default)] pub struct Arena<'tcx> { diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index 52aa42b1085a..7db84f8f2d95 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -15,7 +15,7 @@ impl SingleAttributeParser for TransparencyParser { }); const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]); const TEMPLATE: AttributeTemplate = - template!(NameValueStr: ["transparent", "semitransparent", "opaque"]); + template!(NameValueStr: ["transparent", "semiopaque", "opaque"]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(nv) = args.name_value() else { @@ -24,12 +24,12 @@ impl SingleAttributeParser for TransparencyParser { }; match nv.value_as_str() { Some(sym::transparent) => Some(Transparency::Transparent), - Some(sym::semiopaque | sym::semitransparent) => Some(Transparency::SemiOpaque), + Some(sym::semiopaque) => Some(Transparency::SemiOpaque), Some(sym::opaque) => Some(Transparency::Opaque), Some(_) => { cx.expected_specific_argument_strings( nv.value_span, - &[sym::transparent, sym::semitransparent, sym::opaque], + &[sym::transparent, sym::semiopaque, sym::opaque], ); None } diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index b522ea193716..301547cadaf7 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -744,43 +744,43 @@ unsafe extern "C" { pub struct VaList<'a>(&'a mut VaListImpl); #[rustc_builtin_macro] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro stringify($($t:tt)*) { /* compiler built-in */ } #[rustc_builtin_macro] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro file() { /* compiler built-in */ } #[rustc_builtin_macro] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro line() { /* compiler built-in */ } #[rustc_builtin_macro] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro cfg() { /* compiler built-in */ } #[rustc_builtin_macro] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro asm() { /* compiler built-in */ } #[rustc_builtin_macro] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro global_asm() { /* compiler built-in */ } #[rustc_builtin_macro] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro naked_asm() { /* compiler built-in */ } diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs index 8d8cdb14dbc6..97d6cecf6848 100644 --- a/compiler/rustc_codegen_cranelift/src/global_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs @@ -233,7 +233,7 @@ pub(crate) fn compile_global_asm( #![allow(internal_features)] #![no_core] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] + #[rustc_macro_transparency = "semiopaque"] macro global_asm() { /* compiler built-in */ } global_asm!(r###" "####, diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs index 64a5b431bd07..0aba44a88c5a 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core.rs @@ -748,25 +748,25 @@ extern "C" { pub struct VaList<'a>(&'a mut VaListImpl); #[rustc_builtin_macro] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro stringify($($t:tt)*) { /* compiler built-in */ } #[rustc_builtin_macro] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro file() { /* compiler built-in */ } #[rustc_builtin_macro] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro line() { /* compiler built-in */ } #[rustc_builtin_macro] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro cfg() { /* compiler built-in */ } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index c7ff28ccaffb..1b868a933af8 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2041,7 +2041,6 @@ symbols! { self_in_typedefs, self_struct_ctor, semiopaque, - semitransparent, sha2, sha3, sha512_sm_x86, diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index a12ee60277f0..338c5688bf10 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -168,7 +168,7 @@ macro_rules! assert_ne { /// ``` #[unstable(feature = "assert_matches", issue = "82775")] #[allow_internal_unstable(panic_internals)] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro assert_matches { ($left:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => { match $left { @@ -401,7 +401,7 @@ macro_rules! debug_assert_ne { /// ``` #[unstable(feature = "assert_matches", issue = "82775")] #[allow_internal_unstable(assert_matches)] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro debug_assert_matches($($arg:tt)*) { if $crate::cfg!(debug_assertions) { $crate::assert_matches::assert_matches!($($arg)*); diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index 81520c3ecd1b..cf0750446680 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -20,7 +20,7 @@ use crate::any::Any; #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] #[allow_internal_unstable(panic_internals, const_format_args)] #[rustc_diagnostic_item = "core_panic_2015_macro"] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro panic_2015 { () => ( $crate::panicking::panic("explicit panic") @@ -47,7 +47,7 @@ pub macro panic_2015 { #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] #[allow_internal_unstable(panic_internals, const_format_args)] #[rustc_diagnostic_item = "core_panic_2021_macro"] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro panic_2021 { () => ( $crate::panicking::panic("explicit panic") @@ -67,7 +67,7 @@ pub macro panic_2021 { #[unstable(feature = "edition_panic", issue = "none", reason = "use unreachable!() instead")] #[allow_internal_unstable(panic_internals)] #[rustc_diagnostic_item = "unreachable_2015_macro"] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro unreachable_2015 { () => ( $crate::panicking::panic("internal error: entered unreachable code") @@ -85,7 +85,7 @@ pub macro unreachable_2015 { #[doc(hidden)] #[unstable(feature = "edition_panic", issue = "none", reason = "use unreachable!() instead")] #[allow_internal_unstable(panic_internals)] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro unreachable_2021 { () => ( $crate::panicking::panic("internal error: entered unreachable code") diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 74ecb5ee4946..4791f5612bfa 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -2027,7 +2027,7 @@ unsafe impl PinCoerceUnsized for *mut T {} /// /// [`Box::pin`]: ../../std/boxed/struct.Box.html#method.pin #[stable(feature = "pin_macro", since = "1.68.0")] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] #[allow_internal_unstable(super_let)] #[rustc_diagnostic_item = "pin_macro"] // `super` gets removed by rustfmt diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 335c5c6ee944..ad74a8628c61 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -2662,7 +2662,7 @@ impl fmt::Debug for F { /// same requirements apply to field projections, even inside `addr_of!`. (In particular, it makes /// no difference whether the pointer is null or dangling.) #[stable(feature = "raw_ref_macros", since = "1.51.0")] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro addr_of($place:expr) { &raw const $place } @@ -2752,7 +2752,7 @@ pub macro addr_of($place:expr) { /// same requirements apply to field projections, even inside `addr_of_mut!`. (In particular, it /// makes no difference whether the pointer is null or dangling.) #[stable(feature = "raw_ref_macros", since = "1.51.0")] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro addr_of_mut($place:expr) { &raw mut $place } diff --git a/library/core/src/task/ready.rs b/library/core/src/task/ready.rs index 495d72fd14be..468b3b4e528e 100644 --- a/library/core/src/task/ready.rs +++ b/library/core/src/task/ready.rs @@ -46,7 +46,7 @@ /// # } /// ``` #[stable(feature = "ready_macro", since = "1.64.0")] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro ready($e:expr) { match $e { $crate::task::Poll::Ready(t) => t, diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 528eb185df08..898ed0f7469c 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -187,7 +187,7 @@ pub struct SimpleMessage { /// Err(FAIL) /// } /// ``` -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] #[unstable(feature = "io_const_error", issue = "133448")] #[allow_internal_unstable(hint_must_use, io_const_error_internals)] pub macro const_error($kind:expr, $message:expr $(,)?) { diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index beddc328582c..658026a8020f 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -212,7 +212,7 @@ impl fmt::Display for PanicHookInfo<'_> { #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] #[allow_internal_unstable(libstd_sys_internals, const_format_args, panic_internals, rt)] #[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_2015_macro")] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro panic_2015 { () => ({ $crate::rt::begin_panic("explicit panic") diff --git a/library/std/src/sys/thread_local/native/mod.rs b/library/std/src/sys/thread_local/native/mod.rs index 38b373be56c9..4dad81685a94 100644 --- a/library/std/src/sys/thread_local/native/mod.rs +++ b/library/std/src/sys/thread_local/native/mod.rs @@ -47,7 +47,7 @@ pub use lazy::Storage as LazyStorage; )] #[allow_internal_unsafe] #[unstable(feature = "thread_local_internals", issue = "none")] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro thread_local_inner { // NOTE: we cannot import `LocalKey`, `LazyStorage` or `EagerStorage` with a `use` because that // can shadow user provided type or type alias with a matching name. Please update the shadowing @@ -110,7 +110,7 @@ pub macro thread_local_inner { }}, } -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub(crate) macro local_pointer { () => {}, ($vis:vis static $name:ident; $($rest:tt)*) => { diff --git a/library/std/src/sys/thread_local/no_threads.rs b/library/std/src/sys/thread_local/no_threads.rs index 936d464be9f1..27a589a4a76a 100644 --- a/library/std/src/sys/thread_local/no_threads.rs +++ b/library/std/src/sys/thread_local/no_threads.rs @@ -9,7 +9,7 @@ use crate::ptr; #[allow_internal_unstable(thread_local_internals)] #[allow_internal_unsafe] #[unstable(feature = "thread_local_internals", issue = "none")] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro thread_local_inner { // used to generate the `LocalKey` value for const-initialized thread locals (@key $t:ty, $(#[$align_attr:meta])*, const $init:expr) => {{ @@ -119,7 +119,7 @@ impl LazyStorage { // SAFETY: the target doesn't have threads. unsafe impl Sync for LazyStorage {} -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub(crate) macro local_pointer { () => {}, ($vis:vis static $name:ident; $($rest:tt)*) => { diff --git a/library/std/src/sys/thread_local/os.rs b/library/std/src/sys/thread_local/os.rs index 07b93a2cbbc3..3f06c9bd1d77 100644 --- a/library/std/src/sys/thread_local/os.rs +++ b/library/std/src/sys/thread_local/os.rs @@ -12,7 +12,7 @@ use crate::ptr::{self, NonNull}; #[allow_internal_unstable(thread_local_internals)] #[allow_internal_unsafe] #[unstable(feature = "thread_local_internals", issue = "none")] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro thread_local_inner { // NOTE: we cannot import `Storage` or `LocalKey` with a `use` because that can shadow user // provided type or type alias with a matching name. Please update the shadowing test in @@ -261,7 +261,7 @@ unsafe extern "C" fn destroy_value(ptr: *mut u8) }); } -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub(crate) macro local_pointer { () => {}, ($vis:vis static $name:ident; $($rest:tt)*) => { diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 06e4b252fc8f..1318d8dc2780 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -140,7 +140,7 @@ impl fmt::Debug for LocalKey { #[doc(hidden)] #[allow_internal_unstable(thread_local_internals)] #[unstable(feature = "thread_local_internals", issue = "none")] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro thread_local_process_attrs { // Parse `cfg_attr` to figure out whether it's a `rustc_align_static`. diff --git a/tests/rustdoc-html/macro/macro_pub_in_module.rs b/tests/rustdoc-html/macro/macro_pub_in_module.rs index 2dce73c2cf26..a4b39e20d126 100644 --- a/tests/rustdoc-html/macro/macro_pub_in_module.rs +++ b/tests/rustdoc-html/macro/macro_pub_in_module.rs @@ -33,7 +33,7 @@ pub mod inner { // Make sure the logic is not affected by re-exports. mod unrenamed { //@ !has krate/macro.unrenamed.html - #[rustc_macro_transparency = "semitransparent"] + #[rustc_macro_transparency = "semiopaque"] pub macro unrenamed() {} } //@ has krate/inner/macro.unrenamed.html diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 7027328bc27b..fd6f34fb45e2 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -223,8 +223,8 @@ help: try changing it to one of the following valid forms of the attribute | LL | #[rustc_macro_transparency = "opaque"] | ++++++++++ -LL | #[rustc_macro_transparency = "semitransparent"] - | +++++++++++++++++++ +LL | #[rustc_macro_transparency = "semiopaque"] + | ++++++++++++++ LL | #[rustc_macro_transparency = "transparent"] | +++++++++++++++ diff --git a/tests/ui/hygiene/duplicate_lifetimes.rs b/tests/ui/hygiene/duplicate_lifetimes.rs index 8971fb62626c..4d128da7fdbf 100644 --- a/tests/ui/hygiene/duplicate_lifetimes.rs +++ b/tests/ui/hygiene/duplicate_lifetimes.rs @@ -3,7 +3,7 @@ #![feature(decl_macro, rustc_attrs)] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] macro m($a:lifetime) { fn g<$a, 'a>() {} //~ ERROR the name `'a` is already used for a generic parameter } diff --git a/tests/ui/hygiene/generic_params.rs b/tests/ui/hygiene/generic_params.rs index def9be3a1b64..bb0de15d9a0a 100644 --- a/tests/ui/hygiene/generic_params.rs +++ b/tests/ui/hygiene/generic_params.rs @@ -11,7 +11,7 @@ mod type_params { } } - #[rustc_macro_transparency = "semitransparent"] + #[rustc_macro_transparency = "semiopaque"] macro n($T:ident) { fn g<$T: Clone>(t1: $T, t2: T) -> (T, $T) { (t1.clone(), t2.clone()) @@ -43,7 +43,7 @@ mod lifetime_params { } } - #[rustc_macro_transparency = "semitransparent"] + #[rustc_macro_transparency = "semiopaque"] macro n($a:lifetime) { fn g<$a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) { (t1, t2) @@ -75,7 +75,7 @@ mod const_params { } } - #[rustc_macro_transparency = "semitransparent"] + #[rustc_macro_transparency = "semiopaque"] macro n($C:ident) { fn g(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) { (t1, t2) diff --git a/tests/ui/hygiene/rustc-macro-transparency.rs b/tests/ui/hygiene/rustc-macro-transparency.rs index 1a78a7543cfd..0c680abb4153 100644 --- a/tests/ui/hygiene/rustc-macro-transparency.rs +++ b/tests/ui/hygiene/rustc-macro-transparency.rs @@ -5,7 +5,7 @@ macro transparent() { struct Transparent; let transparent = 0; } -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] macro semiopaque() { struct SemiOpaque; let semiopaque = 0; diff --git a/tests/ui/single-use-lifetime/issue-104440.rs b/tests/ui/single-use-lifetime/issue-104440.rs index 0795e95303a1..cecd17fb930b 100644 --- a/tests/ui/single-use-lifetime/issue-104440.rs +++ b/tests/ui/single-use-lifetime/issue-104440.rs @@ -8,7 +8,7 @@ mod type_params { } } - #[rustc_macro_transparency = "semitransparent"] + #[rustc_macro_transparency = "semiopaque"] macro n($T:ident) { fn g<$T: Clone>(t1: $T, t2: T) -> (T, $T) { (t1.clone(), t2.clone()) @@ -40,7 +40,7 @@ mod lifetime_params { } } - #[rustc_macro_transparency = "semitransparent"] + #[rustc_macro_transparency = "semiopaque"] macro n($a:lifetime) { fn g<$a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) { (t1, t2) @@ -72,7 +72,7 @@ mod const_params { } } - #[rustc_macro_transparency = "semitransparent"] + #[rustc_macro_transparency = "semiopaque"] macro n($C:ident) { fn g(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) { (t1, t2) From 9e00663d73301dbc0482526f9019deaa14f348e1 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Thu, 1 Jan 2026 10:58:23 +0100 Subject: [PATCH 0417/1061] rust-analyzer: Also use `semiopaque` instead of `semitransparent` Like in rustc. --- .../crates/hir-def/src/expr_store/expander.rs | 2 +- .../crates/hir-def/src/expr_store/lower.rs | 2 +- .../crates/hir-def/src/resolver.rs | 2 +- .../crates/hir-expand/src/declarative.rs | 5 +++-- .../crates/hir-expand/src/hygiene.rs | 14 +++++++------- .../crates/hir-expand/src/inert_attr_macro.rs | 2 +- .../crates/hir-expand/src/mod_path.rs | 4 ++-- .../crates/hir-ty/src/tests/simple.rs | 2 +- .../crates/hir/src/source_analyzer.rs | 2 +- .../crates/intern/src/symbol/symbols.rs | 1 - .../rust-analyzer/crates/span/src/hygiene.rs | 18 +++++++++--------- .../crates/test-utils/src/minicore.rs | 4 ++-- 12 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs index de5974fff1ad..d34ec9bbc182 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs @@ -61,7 +61,7 @@ impl Expander { pub(super) fn hygiene_for_range(&self, db: &dyn DefDatabase, range: TextRange) -> HygieneId { match self.span_map.as_ref() { hir_expand::span_map::SpanMapRef::ExpansionSpanMap(span_map) => { - HygieneId::new(span_map.span_at(range.start()).ctx.opaque_and_semitransparent(db)) + HygieneId::new(span_map.span_at(range.start()).ctx.opaque_and_semiopaque(db)) } hir_expand::span_map::SpanMapRef::RealSpanMap(_) => HygieneId::ROOT, } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs index d3774ded39dc..4ae4271b92f5 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs @@ -2546,7 +2546,7 @@ impl<'db> ExprCollector<'db> { // Therefore, if we got to the rib of its declaration, give up its hygiene // and use its parent expansion. - hygiene_id = HygieneId::new(parent_ctx.opaque_and_semitransparent(self.db)); + hygiene_id = HygieneId::new(parent_ctx.opaque_and_semiopaque(self.db)); hygiene_info = parent_ctx.outer_expn(self.db).map(|expansion| { let expansion = self.db.lookup_intern_macro_call(expansion.into()); (parent_ctx.parent(self.db), expansion.def) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index f643ed31ad53..2ac0f90fb209 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -936,7 +936,7 @@ fn handle_macro_def_scope( // A macro is allowed to refer to variables from before its declaration. // Therefore, if we got to the rib of its declaration, give up its hygiene // and use its parent expansion. - *hygiene_id = HygieneId::new(parent_ctx.opaque_and_semitransparent(db)); + *hygiene_id = HygieneId::new(parent_ctx.opaque_and_semiopaque(db)); *hygiene_info = parent_ctx.outer_expn(db).map(|expansion| { let expansion = db.lookup_intern_macro_call(expansion.into()); (parent_ctx.parent(db), expansion.def) diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs index d2df9a1ff6b2..d10e122a5deb 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs @@ -100,7 +100,8 @@ impl DeclarativeMacroExpander { { match &*value { "transparent" => ControlFlow::Break(Transparency::Transparent), - "semitransparent" => ControlFlow::Break(Transparency::SemiTransparent), + // "semitransparent" is for old rustc versions. + "semiopaque" | "semitransparent" => ControlFlow::Break(Transparency::SemiOpaque), "opaque" => ControlFlow::Break(Transparency::Opaque), _ => ControlFlow::Continue(()), } @@ -140,7 +141,7 @@ impl DeclarativeMacroExpander { )), }, transparency(ast::AnyHasAttrs::from(macro_rules)) - .unwrap_or(Transparency::SemiTransparent), + .unwrap_or(Transparency::SemiOpaque), ), ast::Macro::MacroDef(macro_def) => ( match macro_def.body() { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs index bd6f7e4f2b77..ce7650d07711 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs @@ -54,7 +54,7 @@ pub fn span_with_mixed_site_ctxt( expn_id: MacroCallId, edition: Edition, ) -> Span { - span_with_ctxt_from_mark(db, span, expn_id, Transparency::SemiTransparent, edition) + span_with_ctxt_from_mark(db, span, expn_id, Transparency::SemiOpaque, edition) } fn span_with_ctxt_from_mark( @@ -82,7 +82,7 @@ pub(super) fn apply_mark( } let call_site_ctxt = db.lookup_intern_macro_call(call_id.into()).ctxt; - let mut call_site_ctxt = if transparency == Transparency::SemiTransparent { + let mut call_site_ctxt = if transparency == Transparency::SemiOpaque { call_site_ctxt.normalize_to_macros_2_0(db) } else { call_site_ctxt.normalize_to_macro_rules(db) @@ -117,16 +117,16 @@ fn apply_mark_internal( let call_id = Some(call_id); let mut opaque = ctxt.opaque(db); - let mut opaque_and_semitransparent = ctxt.opaque_and_semitransparent(db); + let mut opaque_and_semiopaque = ctxt.opaque_and_semiopaque(db); if transparency >= Transparency::Opaque { let parent = opaque; opaque = SyntaxContext::new(db, call_id, transparency, edition, parent, identity, identity); } - if transparency >= Transparency::SemiTransparent { - let parent = opaque_and_semitransparent; - opaque_and_semitransparent = + if transparency >= Transparency::SemiOpaque { + let parent = opaque_and_semiopaque; + opaque_and_semiopaque = SyntaxContext::new(db, call_id, transparency, edition, parent, |_| opaque, identity); } @@ -138,6 +138,6 @@ fn apply_mark_internal( edition, parent, |_| opaque, - |_| opaque_and_semitransparent, + |_| opaque_and_semiopaque, ) } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs index 385c98ef8778..b49190237776 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs @@ -429,7 +429,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE), rustc_attr!( rustc_macro_transparency, Normal, - template!(NameValueStr: "transparent|semitransparent|opaque"), ErrorFollowing, + template!(NameValueStr: "transparent|semiopaque|opaque"), ErrorFollowing, "used internally for testing macro hygiene", ), diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs index 51e449fe5085..1712c28aa8ab 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs @@ -401,8 +401,8 @@ pub fn resolve_crate_root(db: &dyn ExpandDatabase, mut ctxt: SyntaxContext) -> O result_mark = Some(mark); iter.next(); } - // Then find the last semi-transparent mark from the end if it exists. - while let Some((mark, Transparency::SemiTransparent)) = iter.next() { + // Then find the last semi-opaque mark from the end if it exists. + while let Some((mark, Transparency::SemiOpaque)) = iter.next() { result_mark = Some(mark); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs index 6367521841ab..a9a5e96f75cc 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs @@ -3708,7 +3708,7 @@ fn main() { } #[test] -fn macro_semitransparent_hygiene() { +fn macro_semiopaque_hygiene() { check_types( r#" macro_rules! m { diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index bf123e13f94d..6ba7a42c1946 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -1808,5 +1808,5 @@ pub(crate) fn name_hygiene(db: &dyn HirDatabase, name: InFile<&SyntaxNode>) -> H }; let span_map = db.expansion_span_map(macro_file); let ctx = span_map.span_at(name.value.text_range().start()).ctx; - HygieneId::new(ctx.opaque_and_semitransparent(db)) + HygieneId::new(ctx.opaque_and_semiopaque(db)) } diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index b6efc599f181..6181413a46db 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -442,7 +442,6 @@ define_symbols! { rustc_skip_array_during_method_dispatch, rustc_skip_during_method_dispatch, rustc_force_inline, - semitransparent, shl_assign, shl, shr_assign, diff --git a/src/tools/rust-analyzer/crates/span/src/hygiene.rs b/src/tools/rust-analyzer/crates/span/src/hygiene.rs index ea4f4c5efb42..fdfa94dfee4e 100644 --- a/src/tools/rust-analyzer/crates/span/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/span/src/hygiene.rs @@ -46,7 +46,7 @@ const _: () = { edition: Edition, parent: SyntaxContext, opaque: SyntaxContext, - opaque_and_semitransparent: SyntaxContext, + opaque_and_semiopaque: SyntaxContext, } impl PartialEq for SyntaxContextData { @@ -214,7 +214,7 @@ const _: () = { edition: T2, parent: T3, opaque: impl FnOnce(SyntaxContext) -> SyntaxContext, - opaque_and_semitransparent: impl FnOnce(SyntaxContext) -> SyntaxContext, + opaque_and_semiopaque: impl FnOnce(SyntaxContext) -> SyntaxContext, ) -> Self where Db: ?Sized + salsa::Database, @@ -241,7 +241,7 @@ const _: () = { edition: zalsa_::interned::Lookup::into_owned(data.2), parent: zalsa_::interned::Lookup::into_owned(data.3), opaque: opaque(zalsa_::FromId::from_id(id)), - opaque_and_semitransparent: opaque_and_semitransparent( + opaque_and_semiopaque: opaque_and_semiopaque( zalsa_::FromId::from_id(id), ), }, @@ -301,7 +301,7 @@ const _: () = { } } - /// This context, but with all transparent and semi-transparent expansions filtered away. + /// This context, but with all transparent and semi-opaque expansions filtered away. pub fn opaque(self, db: &'db Db) -> SyntaxContext where Db: ?Sized + zalsa_::Database, @@ -317,7 +317,7 @@ const _: () = { } /// This context, but with all transparent expansions filtered away. - pub fn opaque_and_semitransparent(self, db: &'db Db) -> SyntaxContext + pub fn opaque_and_semiopaque(self, db: &'db Db) -> SyntaxContext where Db: ?Sized + zalsa_::Database, { @@ -325,7 +325,7 @@ const _: () = { Some(id) => { let zalsa = db.zalsa(); let fields = SyntaxContext::ingredient(zalsa).data(zalsa, id); - fields.opaque_and_semitransparent + fields.opaque_and_semiopaque } None => self, } @@ -405,7 +405,7 @@ impl<'db> SyntaxContext { #[inline] pub fn normalize_to_macro_rules(self, db: &'db dyn salsa::Database) -> SyntaxContext { - self.opaque_and_semitransparent(db) + self.opaque_and_semiopaque(db) } pub fn is_opaque(self, db: &'db dyn salsa::Database) -> bool { @@ -476,13 +476,13 @@ pub enum Transparency { /// Identifier produced by a transparent expansion is always resolved at call-site. /// Call-site spans in procedural macros, hygiene opt-out in `macro` should use this. Transparent, - /// Identifier produced by a semi-transparent expansion may be resolved + /// Identifier produced by a semi-opaque expansion may be resolved /// either at call-site or at definition-site. /// If it's a local variable, label or `$crate` then it's resolved at def-site. /// Otherwise it's resolved at call-site. /// `macro_rules` macros behave like this, built-in macros currently behave like this too, /// but that's an implementation detail. - SemiTransparent, + SemiOpaque, /// Identifier produced by an opaque expansion is always resolved at definition-site. /// Def-site spans in procedural macros, identifiers from `macro` by default use this. Opaque, diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index 01274a9835f4..c3429356d9e5 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -546,11 +546,11 @@ pub mod ptr { // endregion:non_null // region:addr_of - #[rustc_macro_transparency = "semitransparent"] + #[rustc_macro_transparency = "semiopaque"] pub macro addr_of($place:expr) { &raw const $place } - #[rustc_macro_transparency = "semitransparent"] + #[rustc_macro_transparency = "semiopaque"] pub macro addr_of_mut($place:expr) { &raw mut $place } From a4f0937a9a28b4e1faacfc3ae1281e568d0ad59c Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Wed, 7 Jan 2026 11:03:40 +0100 Subject: [PATCH 0418/1061] clean-up --- .../src/methods/unnecessary_sort_by.rs | 71 ++++++++----------- 1 file changed, 29 insertions(+), 42 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs index 4a3e4c092f3b..dbaa801eaf50 100644 --- a/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -9,7 +9,7 @@ use rustc_lint::LateContext; use rustc_middle::ty; use rustc_middle::ty::GenericArgKind; use rustc_span::sym; -use rustc_span::symbol::Ident; +use rustc_span::symbol::{Ident, Symbol}; use std::iter; use super::UNNECESSARY_SORT_BY; @@ -20,29 +20,29 @@ enum LintTrigger { } struct SortDetection { - vec_name: String, + vec_name: Sugg<'static>, } struct SortByKeyDetection { - vec_name: String, - closure_arg: String, - closure_body: String, + vec_name: Sugg<'static>, + closure_arg: Symbol, + closure_body: Sugg<'static>, reverse: bool, } /// Detect if the two expressions are mirrored (identical, except one /// contains a and the other replaces it with b) -fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident: &Ident) -> bool { - match (&a_expr.kind, &b_expr.kind) { +fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: Ident, b_expr: &Expr<'_>, b_ident: Ident) -> bool { + match (a_expr.kind, b_expr.kind) { // Two arrays with mirrored contents (ExprKind::Array(left_exprs), ExprKind::Array(right_exprs)) => { - iter::zip(*left_exprs, *right_exprs).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident)) + iter::zip(left_exprs, right_exprs).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident)) }, // The two exprs are function calls. // Check to see that the function itself and its arguments are mirrored (ExprKind::Call(left_expr, left_args), ExprKind::Call(right_expr, right_args)) => { mirrored_exprs(left_expr, a_ident, right_expr, b_ident) - && iter::zip(*left_args, *right_args).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident)) + && iter::zip(left_args, right_args).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident)) }, // The two exprs are method calls. // Check to see that the function is the same and the arguments and receivers are mirrored @@ -51,12 +51,12 @@ fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident ExprKind::MethodCall(right_segment, right_receiver, right_args, _), ) => { left_segment.ident == right_segment.ident - && iter::zip(*left_args, *right_args).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident)) + && iter::zip(left_args, right_args).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident)) && mirrored_exprs(left_receiver, a_ident, right_receiver, b_ident) }, // Two tuples with mirrored contents (ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => { - iter::zip(*left_exprs, *right_exprs).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident)) + iter::zip(left_exprs, right_exprs).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident)) }, // Two binary ops, which are the same operation and which have mirrored arguments (ExprKind::Binary(left_op, left_left, left_right), ExprKind::Binary(right_op, right_left, right_right)) => { @@ -81,27 +81,27 @@ fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident ( ExprKind::Path(QPath::Resolved( _, - Path { + &Path { segments: left_segments, .. }, )), ExprKind::Path(QPath::Resolved( _, - Path { + &Path { segments: right_segments, .. }, )), ) => { - (iter::zip(*left_segments, *right_segments).all(|(left, right)| left.ident == right.ident) + (iter::zip(left_segments, right_segments).all(|(left, right)| left.ident == right.ident) && left_segments .iter() - .all(|seg| &seg.ident != a_ident && &seg.ident != b_ident)) + .all(|seg| seg.ident != a_ident && seg.ident != b_ident)) || (left_segments.len() == 1 - && &left_segments[0].ident == a_ident + && left_segments[0].ident == a_ident && right_segments.len() == 1 - && &right_segments[0].ident == b_ident) + && right_segments[0].ident == b_ident) }, // Matching expressions, but one or both is borrowed ( @@ -123,7 +123,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp && let &[ Param { pat: - Pat { + &Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, @@ -131,36 +131,26 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp }, Param { pat: - Pat { + &Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. }, - ] = &closure_body.params + ] = closure_body.params && let ExprKind::MethodCall(method_path, left_expr, [right_expr], _) = closure_body.value.kind && method_path.ident.name == sym::cmp - && cx - .ty_based_def(closure_body.value) - .opt_parent(cx) - .is_diag_item(cx, sym::Ord) + && let Some(ord_trait) = cx.tcx.get_diagnostic_item(sym::Ord) + && cx.ty_based_def(closure_body.value).opt_parent(cx).opt_def_id() == Some(ord_trait) { let (closure_body, closure_arg, reverse) = if mirrored_exprs(left_expr, left_ident, right_expr, right_ident) { - ( - Sugg::hir(cx, left_expr, "..").to_string(), - left_ident.name.to_string(), - false, - ) + (Sugg::hir(cx, left_expr, "_"), left_ident.name, false) } else if mirrored_exprs(left_expr, right_ident, right_expr, left_ident) { - ( - Sugg::hir(cx, left_expr, "..").to_string(), - right_ident.name.to_string(), - true, - ) + (Sugg::hir(cx, left_expr, "_"), right_ident.name, true) } else { return None; }; - let vec_name = Sugg::hir(cx, recv, "..").to_string(); + let vec_name = Sugg::hir(cx, recv, "(_)"); if let ExprKind::Path(QPath::Resolved( _, @@ -168,12 +158,9 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp segments: [PathSegment { ident: left_name, .. }], .. }, - )) = &left_expr.kind - && left_name == left_ident - && cx - .tcx - .get_diagnostic_item(sym::Ord) - .is_some_and(|id| implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[])) + )) = left_expr.kind + && *left_name == left_ident + && implements_trait(cx, cx.typeck_results().expr_ty(left_expr), ord_trait, &[]) { return Some(LintTrigger::Sort(SortDetection { vec_name })); } @@ -226,7 +213,7 @@ pub(super) fn check<'tcx>( { format!("{}::cmp::Reverse({})", std_or_core, trigger.closure_body) } else { - trigger.closure_body + trigger.closure_body.to_string() }, ), if trigger.reverse { From 0cfc4ee541d819e7cf93cdebb1c43fd0d9eb444b Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Wed, 7 Jan 2026 16:25:41 +0100 Subject: [PATCH 0419/1061] fix: respect applicability reduction due to `Sugg` By postponing the creation of `Sugg`s, we can properly account for their effect on applicability --- .../src/methods/unnecessary_sort_by.rs | 83 ++++++++++--------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs index dbaa801eaf50..c8cb85c05156 100644 --- a/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; use clippy_utils::std_or_core; use clippy_utils::sugg::Sugg; @@ -14,19 +14,14 @@ use std::iter; use super::UNNECESSARY_SORT_BY; -enum LintTrigger { - Sort(SortDetection), - SortByKey(SortByKeyDetection), +enum LintTrigger<'tcx> { + Sort, + SortByKey(SortByKeyDetection<'tcx>), } -struct SortDetection { - vec_name: Sugg<'static>, -} - -struct SortByKeyDetection { - vec_name: Sugg<'static>, +struct SortByKeyDetection<'tcx> { closure_arg: Symbol, - closure_body: Sugg<'static>, + closure_body: &'tcx Expr<'tcx>, reverse: bool, } @@ -114,7 +109,7 @@ fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: Ident, b_expr: &Expr<'_>, b_ident: } } -fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) -> Option { +fn detect_lint<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, arg: &Expr<'_>) -> Option> { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) && let Some(impl_id) = cx.tcx.impl_of_assoc(method_id) && cx.tcx.type_of(impl_id).instantiate_identity().is_slice() @@ -144,13 +139,12 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp && cx.ty_based_def(closure_body.value).opt_parent(cx).opt_def_id() == Some(ord_trait) { let (closure_body, closure_arg, reverse) = if mirrored_exprs(left_expr, left_ident, right_expr, right_ident) { - (Sugg::hir(cx, left_expr, "_"), left_ident.name, false) + (left_expr, left_ident.name, false) } else if mirrored_exprs(left_expr, right_ident, right_expr, left_ident) { - (Sugg::hir(cx, left_expr, "_"), right_ident.name, true) + (left_expr, right_ident.name, true) } else { return None; }; - let vec_name = Sugg::hir(cx, recv, "(_)"); if let ExprKind::Path(QPath::Resolved( _, @@ -162,12 +156,11 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp && *left_name == left_ident && implements_trait(cx, cx.typeck_results().expr_ty(left_expr), ord_trait, &[]) { - return Some(LintTrigger::Sort(SortDetection { vec_name })); + return Some(LintTrigger::Sort); } if !expr_borrows(cx, left_expr) { return Some(LintTrigger::SortByKey(SortByKeyDetection { - vec_name, closure_arg, closure_body, reverse, @@ -190,49 +183,57 @@ pub(super) fn check<'tcx>( arg: &'tcx Expr<'_>, is_unstable: bool, ) { - match detect_lint(cx, expr, recv, arg) { + match detect_lint(cx, expr, arg) { Some(LintTrigger::SortByKey(trigger)) => { let method = if is_unstable { "sort_unstable_by_key" } else { "sort_by_key" }; - span_lint_and_sugg( + span_lint_and_then( cx, UNNECESSARY_SORT_BY, expr.span, format!("consider using `{method}`"), - "try", - format!( - "{}.{}(|{}| {})", - trigger.vec_name, - method, - trigger.closure_arg, - if let Some(std_or_core) = std_or_core(cx) - && trigger.reverse - { - format!("{}::cmp::Reverse({})", std_or_core, trigger.closure_body) + |diag| { + let mut app = if trigger.reverse { + Applicability::MaybeIncorrect } else { - trigger.closure_body.to_string() - }, - ), - if trigger.reverse { - Applicability::MaybeIncorrect - } else { - Applicability::MachineApplicable + Applicability::MachineApplicable + }; + let recv = Sugg::hir_with_applicability(cx, recv, "(_)", &mut app); + let closure_body = Sugg::hir_with_applicability(cx, trigger.closure_body, "_", &mut app); + diag.span_suggestion( + expr.span, + "try", + format!( + "{recv}.{method}(|{}| {})", + trigger.closure_arg, + if let Some(std_or_core) = std_or_core(cx) + && trigger.reverse + { + format!("{std_or_core}::cmp::Reverse({closure_body})") + } else { + closure_body.to_string() + }, + ), + app, + ); }, ); }, - Some(LintTrigger::Sort(trigger)) => { + Some(LintTrigger::Sort) => { let method = if is_unstable { "sort_unstable" } else { "sort" }; - span_lint_and_sugg( + span_lint_and_then( cx, UNNECESSARY_SORT_BY, expr.span, format!("consider using `{method}`"), - "try", - format!("{}.{}()", trigger.vec_name, method), - Applicability::MachineApplicable, + |diag| { + let mut app = Applicability::MachineApplicable; + let recv = Sugg::hir_with_applicability(cx, recv, "(_)", &mut app); + diag.span_suggestion(expr.span, "try", format!("{recv}.{method}()"), app); + }, ); }, None => {}, From 1eb605f6346055b91acbb23cdaa81284abe4aa70 Mon Sep 17 00:00:00 2001 From: Clara Engler Date: Thu, 8 Jan 2026 19:41:24 +0100 Subject: [PATCH 0420/1061] Query associated_item_def_ids when needed This commit moves a query to `associated_item_defs` from above an error condition caused independently of it to below it. It looks generally cleaner and might potentially save some runtime in case the error condition is met, rendering `items` to be left unused, yet still queried. --- compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index 38ae7852ca99..984a812246eb 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -79,13 +79,12 @@ impl<'tcx> InherentCollect<'tcx> { } if self.tcx.features().rustc_attrs() { - let items = self.tcx.associated_item_def_ids(impl_def_id); - if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) { let impl_span = self.tcx.def_span(impl_def_id); return Err(self.tcx.dcx().emit_err(errors::InherentTyOutside { span: impl_span })); } + let items = self.tcx.associated_item_def_ids(impl_def_id); for &impl_item in items { if !find_attr!( self.tcx.get_all_attrs(impl_item), From 68365697b3ab5e57c7a4e1cc4878e9a77ef002ae Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Thu, 8 Jan 2026 19:33:24 +0100 Subject: [PATCH 0421/1061] A `return` in an iterator closure should not trigger `never_loop` The iterator never loops when the closure used in, e.g., `.any()`, panics, not when it diverges as a regular `return` lets the iterator continue. --- clippy_lints/src/loops/never_loop.rs | 4 ++-- tests/ui/never_loop_iterator_reduction.rs | 9 ++++++++- tests/ui/never_loop_iterator_reduction.stderr | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index a037af3433c3..e7b9b1cd3881 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -4,8 +4,8 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::ForLoop; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::source::{snippet, snippet_with_context}; -use clippy_utils::sym; use clippy_utils::visitors::{Descend, for_each_expr_without_closures}; +use clippy_utils::{contains_return, sym}; use rustc_errors::Applicability; use rustc_hir::{ Block, Closure, Destination, Expr, ExprKind, HirId, InlineAsm, InlineAsmOperand, Node, Pat, Stmt, StmtKind, @@ -82,7 +82,7 @@ pub(super) fn check_iterator_reduction<'tcx>( ) { let closure_body = cx.tcx.hir_body(closure.body).value; let body_ty = cx.typeck_results().expr_ty(closure_body); - if body_ty.is_never() { + if body_ty.is_never() && !contains_return(closure_body) { span_lint_and_then( cx, NEVER_LOOP, diff --git a/tests/ui/never_loop_iterator_reduction.rs b/tests/ui/never_loop_iterator_reduction.rs index 6b07b91db29a..27f1766b841d 100644 --- a/tests/ui/never_loop_iterator_reduction.rs +++ b/tests/ui/never_loop_iterator_reduction.rs @@ -1,8 +1,9 @@ //@no-rustfix #![warn(clippy::never_loop)] +#![expect(clippy::needless_return)] fn main() { - // diverging closure: should trigger + // diverging closure with no `return`: should trigger [0, 1].into_iter().for_each(|x| { //~^ never_loop @@ -14,4 +15,10 @@ fn main() { [0, 1].into_iter().for_each(|x| { let _ = x + 1; }); + + // `return` should NOT trigger even though it is diverging + [0, 1].into_iter().for_each(|x| { + println!("x = {x}"); + return; + }); } diff --git a/tests/ui/never_loop_iterator_reduction.stderr b/tests/ui/never_loop_iterator_reduction.stderr index b76ee283146c..92483c85432d 100644 --- a/tests/ui/never_loop_iterator_reduction.stderr +++ b/tests/ui/never_loop_iterator_reduction.stderr @@ -1,5 +1,5 @@ error: this iterator reduction never loops (closure always diverges) - --> tests/ui/never_loop_iterator_reduction.rs:6:5 + --> tests/ui/never_loop_iterator_reduction.rs:7:5 | LL | / [0, 1].into_iter().for_each(|x| { LL | | From bdb1050a0f433be29982de0668102ec15a2c9b96 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Wed, 7 Jan 2026 16:42:15 +0100 Subject: [PATCH 0422/1061] fix: don't lint if `std` or `core` are required for a suggestion but unavailable --- .../src/methods/unnecessary_sort_by.rs | 23 ++++++++-------- tests/ui/unnecessary_sort_by_no_core.rs | 26 +++++++++++++++++++ 2 files changed, 38 insertions(+), 11 deletions(-) create mode 100644 tests/ui/unnecessary_sort_by_no_core.rs diff --git a/clippy_lints/src/methods/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs index c8cb85c05156..9dddbe814317 100644 --- a/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -190,6 +190,12 @@ pub(super) fn check<'tcx>( } else { "sort_by_key" }; + let Some(std_or_core) = std_or_core(cx) else { + // To make it this far the crate has to reference diagnostic items defined in core. Either this is + // the `core` crate, there's an `extern crate core` somewhere, or another crate is defining the + // diagnostic items. It's fine to not lint in all those cases even if we might be able to. + return; + }; span_lint_and_then( cx, UNNECESSARY_SORT_BY, @@ -203,20 +209,15 @@ pub(super) fn check<'tcx>( }; let recv = Sugg::hir_with_applicability(cx, recv, "(_)", &mut app); let closure_body = Sugg::hir_with_applicability(cx, trigger.closure_body, "_", &mut app); + let closure_body = if trigger.reverse { + format!("{std_or_core}::cmp::Reverse({closure_body})") + } else { + closure_body.to_string() + }; diag.span_suggestion( expr.span, "try", - format!( - "{recv}.{method}(|{}| {})", - trigger.closure_arg, - if let Some(std_or_core) = std_or_core(cx) - && trigger.reverse - { - format!("{std_or_core}::cmp::Reverse({closure_body})") - } else { - closure_body.to_string() - }, - ), + format!("{recv}.{method}(|{}| {})", trigger.closure_arg, closure_body), app, ); }, diff --git a/tests/ui/unnecessary_sort_by_no_core.rs b/tests/ui/unnecessary_sort_by_no_core.rs new file mode 100644 index 000000000000..cb0da6339cb3 --- /dev/null +++ b/tests/ui/unnecessary_sort_by_no_core.rs @@ -0,0 +1,26 @@ +//@check-pass +#![feature(no_core)] +#![no_std] +#![no_core] +extern crate alloc; +extern crate core as mycore; +use alloc::vec; +use alloc::vec::Vec; +use mycore::cmp::Ord as _; + +fn issue_11524() -> Vec { + let mut vec = vec![1, 2, 3]; + + // We could lint and suggest `vec.sort_by_key(|a| a + 1);`, but we don't bother to -- see the + // comment in the lint at line 194 + vec.sort_by(|a, b| (a + 1).cmp(&(b + 1))); + vec +} + +fn issue_11524_2() -> Vec { + let mut vec = vec![1, 2, 3]; + + // Should not lint, as even `vec.sort_by_key(|b| core::cmp::Reverse(b + 1));` would not compile + vec.sort_by(|a, b| (b + 1).cmp(&(a + 1))); + vec +} From a9749be514923d929a75f8d0a16013ac0e68c887 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Mon, 5 Jan 2026 10:47:04 -0800 Subject: [PATCH 0423/1061] mgca: Type-check fields of ADT constructor expr const args --- .../rustc_trait_selection/src/traits/wf.rs | 26 ++++++++++- .../mgca/adt_expr_arg_simple.rs | 2 +- .../mgca/adt_expr_fields_type_check.rs | 35 ++++++++++++--- .../mgca/adt_expr_fields_type_check.stderr | 45 +++++++++++++++++++ .../printing_valtrees_supports_non_values.rs | 4 +- ...inting_valtrees_supports_non_values.stderr | 10 ++--- 6 files changed, 106 insertions(+), 16 deletions(-) create mode 100644 tests/ui/const-generics/mgca/adt_expr_fields_type_check.stderr diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 394095508393..58a35bb9ad8c 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -1051,7 +1051,31 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { | ty::ConstKind::Placeholder(..) => { // These variants are trivially WF, so nothing to do here. } - ty::ConstKind::Value(..) => { + ty::ConstKind::Value(val) => { + // FIXME(mgca): no need to feature-gate once valtree lifetimes are not erased + if tcx.features().min_generic_const_args() + && let ty::Adt(adt_def, args) = val.ty.kind() + { + let adt_val = val.destructure_adt_const(); + let variant_def = adt_def.variant(adt_val.variant); + let cause = self.cause(ObligationCauseCode::WellFormed(None)); + self.out.extend(variant_def.fields.iter().zip(adt_val.fields).map( + |(field_def, &field_val)| { + let field_ty = tcx.type_of(field_def.did).instantiate(tcx, args); + let predicate = ty::PredicateKind::Clause( + ty::ClauseKind::ConstArgHasType(field_val, field_ty), + ); + traits::Obligation::with_depth( + tcx, + cause.clone(), + self.recursion_depth, + self.param_env, + predicate, + ) + }, + )); + } + // FIXME: Enforce that values are structurally-matchable. } } diff --git a/tests/ui/const-generics/mgca/adt_expr_arg_simple.rs b/tests/ui/const-generics/mgca/adt_expr_arg_simple.rs index ffb763da325c..16479ba3f64f 100644 --- a/tests/ui/const-generics/mgca/adt_expr_arg_simple.rs +++ b/tests/ui/const-generics/mgca/adt_expr_arg_simple.rs @@ -12,7 +12,7 @@ fn foo>() {} trait Trait { #[type_const] - const ASSOC: usize; + const ASSOC: u32; } fn bar() { diff --git a/tests/ui/const-generics/mgca/adt_expr_fields_type_check.rs b/tests/ui/const-generics/mgca/adt_expr_fields_type_check.rs index eafc8382966b..496a424bac65 100644 --- a/tests/ui/const-generics/mgca/adt_expr_fields_type_check.rs +++ b/tests/ui/const-generics/mgca/adt_expr_fields_type_check.rs @@ -1,17 +1,38 @@ -//@ check-pass -// FIXME(mgca): This should error - #![feature(min_generic_const_args, adt_const_params)] #![expect(incomplete_features)] #[derive(Eq, PartialEq, std::marker::ConstParamTy)] -struct Foo { field: T } +struct S1 { + f1: T, + f2: isize, +} -fn accepts>() {} +#[derive(Eq, PartialEq, std::marker::ConstParamTy)] +struct S2(T, isize); + +#[derive(Eq, PartialEq, std::marker::ConstParamTy)] +enum En { + Var1(bool, T), + Var2 { field: i64 }, +} + +fn accepts_1>() {} +fn accepts_2>() {} +fn accepts_3>() {} fn bar() { - // `N` is not of type `u8` but we don't actually check this anywhere yet - accepts::<{ Foo:: { field: N }}>(); + accepts_1::<{ S1:: { f1: N, f2: N } }>(); + //~^ ERROR the constant `N` is not of type `u8` + //~| ERROR the constant `N` is not of type `isize` + accepts_2::<{ S2::(N, N) }>(); + //~^ ERROR the constant `N` is not of type `u8` + //~| ERROR the constant `N` is not of type `isize` + accepts_3::<{ En::Var1::(N, N) }>(); + //~^ ERROR the constant `N` is not of type `u8` + accepts_3::<{ En::Var2:: { field: N } }>(); + //~^ ERROR the constant `N` is not of type `i64` + accepts_3::<{ En::Var2:: { field: const { false } } }>(); + //~^ ERROR mismatched types } fn main() {} diff --git a/tests/ui/const-generics/mgca/adt_expr_fields_type_check.stderr b/tests/ui/const-generics/mgca/adt_expr_fields_type_check.stderr new file mode 100644 index 000000000000..81f7c5366b46 --- /dev/null +++ b/tests/ui/const-generics/mgca/adt_expr_fields_type_check.stderr @@ -0,0 +1,45 @@ +error: the constant `N` is not of type `u8` + --> $DIR/adt_expr_fields_type_check.rs:24:19 + | +LL | accepts_1::<{ S1:: { f1: N, f2: N } }>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `bool` + +error: the constant `N` is not of type `isize` + --> $DIR/adt_expr_fields_type_check.rs:24:19 + | +LL | accepts_1::<{ S1:: { f1: N, f2: N } }>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `bool` + +error: the constant `N` is not of type `u8` + --> $DIR/adt_expr_fields_type_check.rs:27:19 + | +LL | accepts_2::<{ S2::(N, N) }>(); + | ^^^^^^^^^^^^^^ expected `u8`, found `bool` + +error: the constant `N` is not of type `isize` + --> $DIR/adt_expr_fields_type_check.rs:27:19 + | +LL | accepts_2::<{ S2::(N, N) }>(); + | ^^^^^^^^^^^^^^ expected `isize`, found `bool` + +error: the constant `N` is not of type `u8` + --> $DIR/adt_expr_fields_type_check.rs:30:19 + | +LL | accepts_3::<{ En::Var1::(N, N) }>(); + | ^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `bool` + +error: the constant `N` is not of type `i64` + --> $DIR/adt_expr_fields_type_check.rs:32:19 + | +LL | accepts_3::<{ En::Var2:: { field: N } }>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i64`, found `bool` + +error[E0308]: mismatched types + --> $DIR/adt_expr_fields_type_check.rs:34:51 + | +LL | accepts_3::<{ En::Var2:: { field: const { false } } }>(); + | ^^^^^ expected `i64`, found `bool` + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.rs b/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.rs index 484d6f14a82a..819323d9cbec 100644 --- a/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.rs +++ b/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.rs @@ -9,7 +9,7 @@ struct Foo; trait Trait { #[type_const] - const ASSOC: usize; + const ASSOC: u32; } fn foo() {} @@ -27,7 +27,7 @@ fn baz() { fn main() {} fn test_ice_missing_bound() { - foo::<{Option::Some::{0: ::ASSOC}}>(); + foo::<{ Option::Some:: { 0: ::ASSOC } }>(); //~^ ERROR the trait bound `T: Trait` is not satisfied //~| ERROR the constant `Option::::Some(_)` is not of type `Foo` } diff --git a/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.stderr b/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.stderr index bd2162468944..0184aebf157a 100644 --- a/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.stderr +++ b/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.stderr @@ -25,8 +25,8 @@ LL | fn foo() {} error[E0277]: the trait bound `T: Trait` is not satisfied --> $DIR/printing_valtrees_supports_non_values.rs:30:5 | -LL | foo::<{Option::Some::{0: ::ASSOC}}>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` +LL | foo::<{ Option::Some:: { 0: ::ASSOC } }>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` | help: consider restricting type parameter `T` with trait `Trait` | @@ -34,10 +34,10 @@ LL | fn test_ice_missing_bound() { | +++++++ error: the constant `Option::::Some(_)` is not of type `Foo` - --> $DIR/printing_valtrees_supports_non_values.rs:30:12 + --> $DIR/printing_valtrees_supports_non_values.rs:30:13 | -LL | foo::<{Option::Some::{0: ::ASSOC}}>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option` +LL | foo::<{ Option::Some:: { 0: ::ASSOC } }>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option` | note: required by a const generic parameter in `foo` --> $DIR/printing_valtrees_supports_non_values.rs:15:8 From 156b08184ebeadfc2968bfc454defaab44df20cd Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Thu, 8 Jan 2026 20:04:50 +0100 Subject: [PATCH 0424/1061] fix(single_range_in_vec_init): don't apply the suggestion automatically --- clippy_lints/src/single_range_in_vec_init.rs | 2 +- tests/ui/single_range_in_vec_init_unfixable.rs | 12 ++++++++++++ .../ui/single_range_in_vec_init_unfixable.stderr | 16 ++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 tests/ui/single_range_in_vec_init_unfixable.rs create mode 100644 tests/ui/single_range_in_vec_init_unfixable.stderr diff --git a/clippy_lints/src/single_range_in_vec_init.rs b/clippy_lints/src/single_range_in_vec_init.rs index 92d1b112198f..e4906eb0c777 100644 --- a/clippy_lints/src/single_range_in_vec_init.rs +++ b/clippy_lints/src/single_range_in_vec_init.rs @@ -98,7 +98,7 @@ impl LateLintPass<'_> for SingleRangeInVecInit { && snippet.starts_with(suggested_type.starts_with()) && snippet.ends_with(suggested_type.ends_with()) { - let mut applicability = Applicability::MachineApplicable; + let mut applicability = Applicability::MaybeIncorrect; let (start_snippet, _) = snippet_with_context(cx, start.expr.span, span.ctxt(), "..", &mut applicability); let (end_snippet, _) = snippet_with_context(cx, end.expr.span, span.ctxt(), "..", &mut applicability); diff --git a/tests/ui/single_range_in_vec_init_unfixable.rs b/tests/ui/single_range_in_vec_init_unfixable.rs new file mode 100644 index 000000000000..33378b386f34 --- /dev/null +++ b/tests/ui/single_range_in_vec_init_unfixable.rs @@ -0,0 +1,12 @@ +//@no-rustfix +#![warn(clippy::single_range_in_vec_init)] + +use std::ops::Range; + +fn issue16306(v: &[i32]) { + fn takes_range_slice(_: &[Range]) {} + + let len = v.len(); + takes_range_slice(&[0..len as i64]); + //~^ single_range_in_vec_init +} diff --git a/tests/ui/single_range_in_vec_init_unfixable.stderr b/tests/ui/single_range_in_vec_init_unfixable.stderr new file mode 100644 index 000000000000..b10af21ed21c --- /dev/null +++ b/tests/ui/single_range_in_vec_init_unfixable.stderr @@ -0,0 +1,16 @@ +error: an array of `Range` that is only one element + --> tests/ui/single_range_in_vec_init_unfixable.rs:10:24 + | +LL | takes_range_slice(&[0..len as i64]); + | ^^^^^^^^^^^^^^^ + | + = note: `-D clippy::single-range-in-vec-init` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::single_range_in_vec_init)]` +help: if you wanted a `Vec` that contains the entire range, try + | +LL - takes_range_slice(&[0..len as i64]); +LL + takes_range_slice(&(0..len as i64).collect::>()); + | + +error: aborting due to 1 previous error + From 1c2cb16e8232843004ee277c1819d2d5e1c03e11 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 8 Jan 2026 11:09:07 -0800 Subject: [PATCH 0425/1061] mgca: Type-check fields of tuple expr const args --- .../rustc_middle/src/ty/consts/valtree.rs | 3 +- .../rustc_trait_selection/src/traits/wf.rs | 64 +++++++++++++------ .../mgca/adt_expr_arg_tuple_expr_fail.rs | 26 ++++++++ .../mgca/adt_expr_arg_tuple_expr_fail.stderr | 38 +++++++++++ .../mgca/adt_expr_arg_tuple_expr_simple.rs | 2 +- 5 files changed, 109 insertions(+), 24 deletions(-) create mode 100644 tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_fail.rs create mode 100644 tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_fail.stderr diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 6501ddeed6fa..5a5bf7d38ea4 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -191,8 +191,7 @@ impl<'tcx> Value<'tcx> { } } - /// Destructures array, ADT or tuple constants into the constants - /// of their fields. + /// Destructures ADT constants into the constants of their fields. pub fn destructure_adt_const(&self) -> ty::DestructuredAdtConst<'tcx> { let fields = self.to_branch(); diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 58a35bb9ad8c..d383cb9d91dd 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -1053,27 +1053,49 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { } ty::ConstKind::Value(val) => { // FIXME(mgca): no need to feature-gate once valtree lifetimes are not erased - if tcx.features().min_generic_const_args() - && let ty::Adt(adt_def, args) = val.ty.kind() - { - let adt_val = val.destructure_adt_const(); - let variant_def = adt_def.variant(adt_val.variant); - let cause = self.cause(ObligationCauseCode::WellFormed(None)); - self.out.extend(variant_def.fields.iter().zip(adt_val.fields).map( - |(field_def, &field_val)| { - let field_ty = tcx.type_of(field_def.did).instantiate(tcx, args); - let predicate = ty::PredicateKind::Clause( - ty::ClauseKind::ConstArgHasType(field_val, field_ty), - ); - traits::Obligation::with_depth( - tcx, - cause.clone(), - self.recursion_depth, - self.param_env, - predicate, - ) - }, - )); + if tcx.features().min_generic_const_args() { + match val.ty.kind() { + ty::Adt(adt_def, args) => { + let adt_val = val.destructure_adt_const(); + let variant_def = adt_def.variant(adt_val.variant); + let cause = self.cause(ObligationCauseCode::WellFormed(None)); + self.out.extend(variant_def.fields.iter().zip(adt_val.fields).map( + |(field_def, &field_val)| { + let field_ty = + tcx.type_of(field_def.did).instantiate(tcx, args); + let predicate = ty::PredicateKind::Clause( + ty::ClauseKind::ConstArgHasType(field_val, field_ty), + ); + traits::Obligation::with_depth( + tcx, + cause.clone(), + self.recursion_depth, + self.param_env, + predicate, + ) + }, + )); + } + ty::Tuple(field_tys) => { + let field_vals = val.to_branch(); + let cause = self.cause(ObligationCauseCode::WellFormed(None)); + self.out.extend(field_tys.iter().zip(field_vals).map( + |(field_ty, &field_val)| { + let predicate = ty::PredicateKind::Clause( + ty::ClauseKind::ConstArgHasType(field_val, field_ty), + ); + traits::Obligation::with_depth( + tcx, + cause.clone(), + self.recursion_depth, + self.param_env, + predicate, + ) + }, + )); + } + _ => {} + } } // FIXME: Enforce that values are structurally-matchable. diff --git a/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_fail.rs b/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_fail.rs new file mode 100644 index 000000000000..5f0d6c924bd1 --- /dev/null +++ b/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_fail.rs @@ -0,0 +1,26 @@ +#![feature(min_generic_const_args, adt_const_params, unsized_const_params)] +#![expect(incomplete_features)] + +trait Trait { + #[type_const] + const ASSOC: usize; +} + +fn takes_tuple() {} +fn takes_nested_tuple() {} + +fn generic_caller() { + takes_tuple::<{ (N, N2) }>(); + //~^ ERROR the constant `N` is not of type `u32` + takes_tuple::<{ (N, T::ASSOC) }>(); + //~^ ERROR the constant `N` is not of type `u32` + //~| ERROR the constant `::ASSOC` is not of type `u32` + + takes_nested_tuple::<{ (N, (N, N2)) }>(); + //~^ ERROR the constant `N` is not of type `u32` + takes_nested_tuple::<{ (N, (N, T::ASSOC)) }>(); + //~^ ERROR the constant `N` is not of type `u32` + //~| ERROR the constant `::ASSOC` is not of type `u32` +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_fail.stderr b/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_fail.stderr new file mode 100644 index 000000000000..9d80ebeaa680 --- /dev/null +++ b/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_fail.stderr @@ -0,0 +1,38 @@ +error: the constant `N` is not of type `u32` + --> $DIR/adt_expr_arg_tuple_expr_fail.rs:13:21 + | +LL | takes_tuple::<{ (N, N2) }>(); + | ^^^^^^^ expected `u32`, found `usize` + +error: the constant `N` is not of type `u32` + --> $DIR/adt_expr_arg_tuple_expr_fail.rs:15:21 + | +LL | takes_tuple::<{ (N, T::ASSOC) }>(); + | ^^^^^^^^^^^^^ expected `u32`, found `usize` + +error: the constant `::ASSOC` is not of type `u32` + --> $DIR/adt_expr_arg_tuple_expr_fail.rs:15:21 + | +LL | takes_tuple::<{ (N, T::ASSOC) }>(); + | ^^^^^^^^^^^^^ expected `u32`, found `usize` + +error: the constant `N` is not of type `u32` + --> $DIR/adt_expr_arg_tuple_expr_fail.rs:19:28 + | +LL | takes_nested_tuple::<{ (N, (N, N2)) }>(); + | ^^^^^^^^^^^^ expected `u32`, found `usize` + +error: the constant `N` is not of type `u32` + --> $DIR/adt_expr_arg_tuple_expr_fail.rs:21:28 + | +LL | takes_nested_tuple::<{ (N, (N, T::ASSOC)) }>(); + | ^^^^^^^^^^^^^^^^^^ expected `u32`, found `usize` + +error: the constant `::ASSOC` is not of type `u32` + --> $DIR/adt_expr_arg_tuple_expr_fail.rs:21:28 + | +LL | takes_nested_tuple::<{ (N, (N, T::ASSOC)) }>(); + | ^^^^^^^^^^^^^^^^^^ expected `u32`, found `usize` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_simple.rs b/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_simple.rs index 60c4c6e952cf..3fde431e27e2 100644 --- a/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_simple.rs +++ b/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_simple.rs @@ -5,7 +5,7 @@ trait Trait { #[type_const] - const ASSOC: usize; + const ASSOC: u32; } fn takes_tuple() {} From 98d3026c416a2a588bf271414a4695436cd7ef25 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 1 Jan 2026 20:19:21 -0800 Subject: [PATCH 0426/1061] Resolve intra-doc links to variant fields behind type aliases Previously, these failed to resolve, despite them working for struct fields or enum variants that were behind aliases. However, there is now an inconsistency where enum variant fields behind an alias resolve to the entry on the alias's page, while enum variants and struct fields resolve to the page of the backing ADT. --- .../passes/collect_intra_doc_links.rs | 35 ++++++++++--------- .../intra-doc/adt-through-alias.rs | 25 +++++++++++++ 2 files changed, 44 insertions(+), 16 deletions(-) create mode 100644 tests/rustdoc-html/intra-doc/adt-through-alias.rs diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 3abf0fee3959..44affba9a8c0 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -308,24 +308,27 @@ impl<'tcx> LinkCollector<'_, 'tcx> { let ty_res = self.resolve_path(path, TypeNS, item_id, module_id).ok_or_else(no_res)?; match ty_res { - Res::Def(DefKind::Enum, did) => match tcx.type_of(did).instantiate_identity().kind() { - ty::Adt(def, _) if def.is_enum() => { - if let Some(variant) = def.variants().iter().find(|v| v.name == variant_name) - && let Some(field) = - variant.fields.iter().find(|f| f.name == variant_field_name) - { - Ok((ty_res, field.did)) - } else { - Err(UnresolvedPath { - item_id, - module_id, - partial_res: Some(Res::Def(DefKind::Enum, def.did())), - unresolved: variant_field_name.to_string().into(), - }) + Res::Def(DefKind::Enum | DefKind::TyAlias, did) => { + match tcx.type_of(did).instantiate_identity().kind() { + ty::Adt(def, _) if def.is_enum() => { + if let Some(variant) = + def.variants().iter().find(|v| v.name == variant_name) + && let Some(field) = + variant.fields.iter().find(|f| f.name == variant_field_name) + { + Ok((ty_res, field.did)) + } else { + Err(UnresolvedPath { + item_id, + module_id, + partial_res: Some(Res::Def(DefKind::Enum, def.did())), + unresolved: variant_field_name.to_string().into(), + }) + } } + _ => unreachable!(), } - _ => unreachable!(), - }, + } _ => Err(UnresolvedPath { item_id, module_id, diff --git a/tests/rustdoc-html/intra-doc/adt-through-alias.rs b/tests/rustdoc-html/intra-doc/adt-through-alias.rs new file mode 100644 index 000000000000..58e0f37edbab --- /dev/null +++ b/tests/rustdoc-html/intra-doc/adt-through-alias.rs @@ -0,0 +1,25 @@ +#![crate_name = "foo"] + +//! [`TheStructAlias::the_field`] +//! [`TheEnumAlias::TheVariant`] +//! [`TheEnumAlias::TheVariant::the_field`] + +// FIXME: this should resolve to the alias's version +//@ has foo/index.html '//a[@href="struct.TheStruct.html#structfield.the_field"]' 'TheStructAlias::the_field' +// FIXME: this should resolve to the alias's version +//@ has foo/index.html '//a[@href="enum.TheEnum.html#variant.TheVariant"]' 'TheEnumAlias::TheVariant' +//@ has foo/index.html '//a[@href="type.TheEnumAlias.html#variant.TheVariant.field.the_field"]' 'TheEnumAlias::TheVariant::the_field' + +pub struct TheStruct { + pub the_field: i32, +} + +pub type TheStructAlias = TheStruct; + +pub enum TheEnum { + TheVariant { the_field: i32 }, +} + +pub type TheEnumAlias = TheEnum; + +fn main() {} From a90e0418c69e2f46000e918c404d4490cd5f2b4e Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 1 Jan 2026 20:29:43 -0800 Subject: [PATCH 0427/1061] rustdoc: Refactor `def_id_to_res` as `ty_to_res` The old name and API were confusing. In my opinion, looking up the type at the call site is clearer. --- src/librustdoc/passes/collect_intra_doc_links.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 44affba9a8c0..512f0f418702 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -384,7 +384,7 @@ impl<'tcx> LinkCollector<'_, 'tcx> { }; match tcx.def_kind(self_id) { - DefKind::Impl { .. } => self.def_id_to_res(self_id), + DefKind::Impl { .. } => self.ty_to_res(tcx.type_of(self_id).instantiate_identity()), DefKind::Use => None, def_kind => Some(Res::Def(def_kind, self_id)), } @@ -506,12 +506,12 @@ impl<'tcx> LinkCollector<'_, 'tcx> { } } - /// Convert a DefId to a Res, where possible. + /// Convert a Ty to a Res, where possible. /// /// This is used for resolving type aliases. - fn def_id_to_res(&self, ty_id: DefId) -> Option { + fn ty_to_res(&self, ty: Ty<'tcx>) -> Option { use PrimitiveType::*; - Some(match *self.cx.tcx.type_of(ty_id).instantiate_identity().kind() { + Some(match *ty.kind() { ty::Bool => Res::Primitive(Bool), ty::Char => Res::Primitive(Char), ty::Int(ity) => Res::Primitive(ity.into()), @@ -614,7 +614,7 @@ impl<'tcx> LinkCollector<'_, 'tcx> { // Resolve the link on the type the alias points to. // FIXME: if the associated item is defined directly on the type alias, // it will show up on its documentation page, we should link there instead. - let Some(res) = self.def_id_to_res(did) else { return Vec::new() }; + let Some(res) = self.ty_to_res(tcx.type_of(did).instantiate_identity()) else { return Vec::new() }; self.resolve_associated_item(res, item_name, ns, disambiguator, module_id) } Res::Def( From 945f3f91712b2ccbfce0bde5c1d0f4ad36a69876 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 1 Jan 2026 23:46:46 -0800 Subject: [PATCH 0428/1061] rustdoc: Use trait as root `Res` instead of assoc item All the other parts of this function return the Res for the containing page, but for some reason, this returns the associated item itself. It doesn't seem to affect the behavior of rustdoc because e.g. the href functions use the parent if the DefId is for an assoc item. But it's clearer and simpler to be consistent. --- src/librustdoc/passes/collect_intra_doc_links.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 512f0f418702..4233f0903b23 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -614,7 +614,9 @@ impl<'tcx> LinkCollector<'_, 'tcx> { // Resolve the link on the type the alias points to. // FIXME: if the associated item is defined directly on the type alias, // it will show up on its documentation page, we should link there instead. - let Some(res) = self.ty_to_res(tcx.type_of(did).instantiate_identity()) else { return Vec::new() }; + let Some(res) = self.ty_to_res(tcx.type_of(did).instantiate_identity()) else { + return Vec::new(); + }; self.resolve_associated_item(res, item_name, ns, disambiguator, module_id) } Res::Def( @@ -720,10 +722,7 @@ impl<'tcx> LinkCollector<'_, 'tcx> { Ident::with_dummy_span(item_name), ns, ) - .map(|item| { - let res = Res::Def(item.as_def_kind(), item.def_id); - (res, item.def_id) - }) + .map(|item| (root_res, item.def_id)) .collect::>(), _ => Vec::new(), } From f503b894e912532299fd7669844efbdebaedcfd7 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 1 Jan 2026 23:54:43 -0800 Subject: [PATCH 0429/1061] rustdoc: Extract helper function for resolving assoc items on ADTs --- .../passes/collect_intra_doc_links.rs | 200 ++++++++++-------- 1 file changed, 106 insertions(+), 94 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 4233f0903b23..cb3fd72bc196 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -622,100 +622,7 @@ impl<'tcx> LinkCollector<'_, 'tcx> { Res::Def( def_kind @ (DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::ForeignTy), did, - ) => { - debug!("looking for associated item named {item_name} for item {did:?}"); - // Checks if item_name is a variant of the `SomeItem` enum - if ns == TypeNS && def_kind == DefKind::Enum { - match tcx.type_of(did).instantiate_identity().kind() { - ty::Adt(adt_def, _) => { - for variant in adt_def.variants() { - if variant.name == item_name { - return vec![(root_res, variant.def_id)]; - } - } - } - _ => unreachable!(), - } - } - - let search_for_field = || { - let (DefKind::Struct | DefKind::Union) = def_kind else { return vec![] }; - debug!("looking for fields named {item_name} for {did:?}"); - // FIXME: this doesn't really belong in `associated_item` (maybe `variant_field` is better?) - // NOTE: it's different from variant_field because it only resolves struct fields, - // not variant fields (2 path segments, not 3). - // - // We need to handle struct (and union) fields in this code because - // syntactically their paths are identical to associated item paths: - // `module::Type::field` and `module::Type::Assoc`. - // - // On the other hand, variant fields can't be mistaken for associated - // items because they look like this: `module::Type::Variant::field`. - // - // Variants themselves don't need to be handled here, even though - // they also look like associated items (`module::Type::Variant`), - // because they are real Rust syntax (unlike the intra-doc links - // field syntax) and are handled by the compiler's resolver. - let ty::Adt(def, _) = tcx.type_of(did).instantiate_identity().kind() else { - unreachable!() - }; - def.non_enum_variant() - .fields - .iter() - .filter(|field| field.name == item_name) - .map(|field| (root_res, field.did)) - .collect::>() - }; - - if let Some(Disambiguator::Kind(DefKind::Field)) = disambiguator { - return search_for_field(); - } - - // Checks if item_name belongs to `impl SomeItem` - let mut assoc_items: Vec<_> = tcx - .inherent_impls(did) - .iter() - .flat_map(|&imp| { - filter_assoc_items_by_name_and_namespace( - tcx, - imp, - Ident::with_dummy_span(item_name), - ns, - ) - }) - .map(|item| (root_res, item.def_id)) - .collect(); - - if assoc_items.is_empty() { - // Check if item_name belongs to `impl SomeTrait for SomeItem` - // FIXME(#74563): This gives precedence to `impl SomeItem`: - // Although having both would be ambiguous, use impl version for compatibility's sake. - // To handle that properly resolve() would have to support - // something like [`ambi_fn`](::ambi_fn) - assoc_items = resolve_associated_trait_item( - tcx.type_of(did).instantiate_identity(), - module_id, - item_name, - ns, - self.cx, - ) - .into_iter() - .map(|item| (root_res, item.def_id)) - .collect::>(); - } - - debug!("got associated item {assoc_items:?}"); - - if !assoc_items.is_empty() { - return assoc_items; - } - - if ns != Namespace::ValueNS { - return Vec::new(); - } - - search_for_field() - } + ) => self.resolve_assoc_on_adt(), Res::Def(DefKind::Trait, did) => filter_assoc_items_by_name_and_namespace( tcx, did, @@ -727,6 +634,111 @@ impl<'tcx> LinkCollector<'_, 'tcx> { _ => Vec::new(), } } + + fn resolve_assoc_on_adt( + &mut self, + adt_def_kind: DefKind, + adt_def_id: DefId, + item_name: Symbol, + ns: Namespace, + disambiguator: Option, + module_id: DefId, + ) -> Vec<(Res, DefId)> { + let tcx = self.cx.tcx; + let root_res = Res::Def(adt_def_kind, adt_def_id); + debug!("looking for associated item named {item_name} for item {adt_def_id:?}"); + // Checks if item_name is a variant of the `SomeItem` enum + if ns == TypeNS && adt_def_kind == DefKind::Enum { + match tcx.type_of(adt_def_id).instantiate_identity().kind() { + ty::Adt(adt_def, _) => { + for variant in adt_def.variants() { + if variant.name == item_name { + return vec![(root_res, variant.def_id)]; + } + } + } + _ => unreachable!(), + } + } + + let search_for_field = || { + let (DefKind::Struct | DefKind::Union) = adt_def_kind else { return vec![] }; + debug!("looking for fields named {item_name} for {adt_def_id:?}"); + // FIXME: this doesn't really belong in `associated_item` (maybe `variant_field` is better?) + // NOTE: it's different from variant_field because it only resolves struct fields, + // not variant fields (2 path segments, not 3). + // + // We need to handle struct (and union) fields in this code because + // syntactically their paths are identical to associated item paths: + // `module::Type::field` and `module::Type::Assoc`. + // + // On the other hand, variant fields can't be mistaken for associated + // items because they look like this: `module::Type::Variant::field`. + // + // Variants themselves don't need to be handled here, even though + // they also look like associated items (`module::Type::Variant`), + // because they are real Rust syntax (unlike the intra-doc links + // field syntax) and are handled by the compiler's resolver. + let ty::Adt(def, _) = tcx.type_of(adt_def_id).instantiate_identity().kind() else { + unreachable!() + }; + def.non_enum_variant() + .fields + .iter() + .filter(|field| field.name == item_name) + .map(|field| (root_res, field.did)) + .collect::>() + }; + + if let Some(Disambiguator::Kind(DefKind::Field)) = disambiguator { + return search_for_field(); + } + + // Checks if item_name belongs to `impl SomeItem` + let mut assoc_items: Vec<_> = tcx + .inherent_impls(adt_def_id) + .iter() + .flat_map(|&imp| { + filter_assoc_items_by_name_and_namespace( + tcx, + imp, + Ident::with_dummy_span(item_name), + ns, + ) + }) + .map(|item| (root_res, item.def_id)) + .collect(); + + if assoc_items.is_empty() { + // Check if item_name belongs to `impl SomeTrait for SomeItem` + // FIXME(#74563): This gives precedence to `impl SomeItem`: + // Although having both would be ambiguous, use impl version for compatibility's sake. + // To handle that properly resolve() would have to support + // something like [`ambi_fn`](::ambi_fn) + assoc_items = resolve_associated_trait_item( + tcx.type_of(adt_def_id).instantiate_identity(), + module_id, + item_name, + ns, + self.cx, + ) + .into_iter() + .map(|item| (root_res, item.def_id)) + .collect::>(); + } + + debug!("got associated item {assoc_items:?}"); + + if !assoc_items.is_empty() { + return assoc_items; + } + + if ns != Namespace::ValueNS { + return Vec::new(); + } + + search_for_field() + } } fn full_res(tcx: TyCtxt<'_>, (base, assoc_item): (Res, Option)) -> Res { From 2c98517faea2f0dc5b96282c2677cdb4628abd34 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Fri, 2 Jan 2026 00:36:30 -0800 Subject: [PATCH 0430/1061] Refactor out many free functions from intra-doc link code --- .../passes/collect_intra_doc_links.rs | 602 +++++++++--------- 1 file changed, 291 insertions(+), 311 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index cb3fd72bc196..553d8636c85b 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -338,58 +338,6 @@ impl<'tcx> LinkCollector<'_, 'tcx> { } } - /// Given a primitive type, try to resolve an associated item. - fn resolve_primitive_associated_item( - &self, - prim_ty: PrimitiveType, - ns: Namespace, - item_name: Symbol, - ) -> Vec<(Res, DefId)> { - let tcx = self.cx.tcx; - - prim_ty - .impls(tcx) - .flat_map(|impl_| { - filter_assoc_items_by_name_and_namespace( - tcx, - impl_, - Ident::with_dummy_span(item_name), - ns, - ) - .map(|item| (Res::Primitive(prim_ty), item.def_id)) - }) - .collect::>() - } - - fn resolve_self_ty(&self, path_str: &str, ns: Namespace, item_id: DefId) -> Option { - if ns != TypeNS || path_str != "Self" { - return None; - } - - let tcx = self.cx.tcx; - let self_id = match tcx.def_kind(item_id) { - def_kind @ (DefKind::AssocFn - | DefKind::AssocConst - | DefKind::AssocTy - | DefKind::Variant - | DefKind::Field) => { - let parent_def_id = tcx.parent(item_id); - if def_kind == DefKind::Field && tcx.def_kind(parent_def_id) == DefKind::Variant { - tcx.parent(parent_def_id) - } else { - parent_def_id - } - } - _ => item_id, - }; - - match tcx.def_kind(self_id) { - DefKind::Impl { .. } => self.ty_to_res(tcx.type_of(self_id).instantiate_identity()), - DefKind::Use => None, - def_kind => Some(Res::Def(def_kind, self_id)), - } - } - /// Convenience wrapper around `doc_link_resolutions`. /// /// This also handles resolving `true` and `false` as booleans. @@ -402,7 +350,7 @@ impl<'tcx> LinkCollector<'_, 'tcx> { item_id: DefId, module_id: DefId, ) -> Option { - if let res @ Some(..) = self.resolve_self_ty(path_str, ns, item_id) { + if let res @ Some(..) = resolve_self_ty(self.cx.tcx, path_str, ns, item_id) { return res; } @@ -432,13 +380,15 @@ impl<'tcx> LinkCollector<'_, 'tcx> { /// Resolves a string as a path within a particular namespace. Returns an /// optional URL fragment in the case of variants and methods. fn resolve<'path>( - &mut self, + &self, path_str: &'path str, ns: Namespace, disambiguator: Option, item_id: DefId, module_id: DefId, ) -> Result)>, UnresolvedPath<'path>> { + let tcx = self.cx.tcx; + if let Some(res) = self.resolve_path(path_str, ns, item_id, module_id) { return Ok(match res { Res::Def( @@ -484,7 +434,7 @@ impl<'tcx> LinkCollector<'_, 'tcx> { match resolve_primitive(path_root, TypeNS) .or_else(|| self.resolve_path(path_root, TypeNS, item_id, module_id)) .map(|ty_res| { - self.resolve_associated_item(ty_res, item_name, ns, disambiguator, module_id) + resolve_associated_item(tcx, ty_res, item_name, ns, disambiguator, module_id) .into_iter() .map(|(res, def_id)| (res, Some(def_id))) .collect::>() @@ -505,257 +455,293 @@ impl<'tcx> LinkCollector<'_, 'tcx> { } } } - - /// Convert a Ty to a Res, where possible. - /// - /// This is used for resolving type aliases. - fn ty_to_res(&self, ty: Ty<'tcx>) -> Option { - use PrimitiveType::*; - Some(match *ty.kind() { - ty::Bool => Res::Primitive(Bool), - ty::Char => Res::Primitive(Char), - ty::Int(ity) => Res::Primitive(ity.into()), - ty::Uint(uty) => Res::Primitive(uty.into()), - ty::Float(fty) => Res::Primitive(fty.into()), - ty::Str => Res::Primitive(Str), - ty::Tuple(tys) if tys.is_empty() => Res::Primitive(Unit), - ty::Tuple(_) => Res::Primitive(Tuple), - ty::Pat(..) => Res::Primitive(Pat), - ty::Array(..) => Res::Primitive(Array), - ty::Slice(_) => Res::Primitive(Slice), - ty::RawPtr(_, _) => Res::Primitive(RawPointer), - ty::Ref(..) => Res::Primitive(Reference), - ty::FnDef(..) => panic!("type alias to a function definition"), - ty::FnPtr(..) => Res::Primitive(Fn), - ty::Never => Res::Primitive(Never), - ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did, .. }, _)), _) | ty::Foreign(did) => { - Res::from_def_id(self.cx.tcx, did) - } - ty::Alias(..) - | ty::Closure(..) - | ty::CoroutineClosure(..) - | ty::Coroutine(..) - | ty::CoroutineWitness(..) - | ty::Dynamic(..) - | ty::UnsafeBinder(_) - | ty::Param(_) - | ty::Bound(..) - | ty::Placeholder(_) - | ty::Infer(_) - | ty::Error(_) => return None, - }) - } - - /// Convert a PrimitiveType to a Ty, where possible. - /// - /// This is used for resolving trait impls for primitives - fn primitive_type_to_ty(&mut self, prim: PrimitiveType) -> Option> { - use PrimitiveType::*; - let tcx = self.cx.tcx; - - // FIXME: Only simple types are supported here, see if we can support - // other types such as Tuple, Array, Slice, etc. - // See https://github.com/rust-lang/rust/issues/90703#issuecomment-1004263455 - Some(match prim { - Bool => tcx.types.bool, - Str => tcx.types.str_, - Char => tcx.types.char, - Never => tcx.types.never, - I8 => tcx.types.i8, - I16 => tcx.types.i16, - I32 => tcx.types.i32, - I64 => tcx.types.i64, - I128 => tcx.types.i128, - Isize => tcx.types.isize, - F16 => tcx.types.f16, - F32 => tcx.types.f32, - F64 => tcx.types.f64, - F128 => tcx.types.f128, - U8 => tcx.types.u8, - U16 => tcx.types.u16, - U32 => tcx.types.u32, - U64 => tcx.types.u64, - U128 => tcx.types.u128, - Usize => tcx.types.usize, - _ => return None, - }) - } - - /// Resolve an associated item, returning its containing page's `Res` - /// and the fragment targeting the associated item on its page. - fn resolve_associated_item( - &mut self, - root_res: Res, - item_name: Symbol, - ns: Namespace, - disambiguator: Option, - module_id: DefId, - ) -> Vec<(Res, DefId)> { - let tcx = self.cx.tcx; - - match root_res { - Res::Primitive(prim) => { - let items = self.resolve_primitive_associated_item(prim, ns, item_name); - if !items.is_empty() { - items - // Inherent associated items take precedence over items that come from trait impls. - } else { - self.primitive_type_to_ty(prim) - .map(|ty| { - resolve_associated_trait_item(ty, module_id, item_name, ns, self.cx) - .iter() - .map(|item| (root_res, item.def_id)) - .collect::>() - }) - .unwrap_or_default() - } - } - Res::Def(DefKind::TyAlias, did) => { - // Resolve the link on the type the alias points to. - // FIXME: if the associated item is defined directly on the type alias, - // it will show up on its documentation page, we should link there instead. - let Some(res) = self.ty_to_res(tcx.type_of(did).instantiate_identity()) else { - return Vec::new(); - }; - self.resolve_associated_item(res, item_name, ns, disambiguator, module_id) - } - Res::Def( - def_kind @ (DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::ForeignTy), - did, - ) => self.resolve_assoc_on_adt(), - Res::Def(DefKind::Trait, did) => filter_assoc_items_by_name_and_namespace( - tcx, - did, - Ident::with_dummy_span(item_name), - ns, - ) - .map(|item| (root_res, item.def_id)) - .collect::>(), - _ => Vec::new(), - } - } - - fn resolve_assoc_on_adt( - &mut self, - adt_def_kind: DefKind, - adt_def_id: DefId, - item_name: Symbol, - ns: Namespace, - disambiguator: Option, - module_id: DefId, - ) -> Vec<(Res, DefId)> { - let tcx = self.cx.tcx; - let root_res = Res::Def(adt_def_kind, adt_def_id); - debug!("looking for associated item named {item_name} for item {adt_def_id:?}"); - // Checks if item_name is a variant of the `SomeItem` enum - if ns == TypeNS && adt_def_kind == DefKind::Enum { - match tcx.type_of(adt_def_id).instantiate_identity().kind() { - ty::Adt(adt_def, _) => { - for variant in adt_def.variants() { - if variant.name == item_name { - return vec![(root_res, variant.def_id)]; - } - } - } - _ => unreachable!(), - } - } - - let search_for_field = || { - let (DefKind::Struct | DefKind::Union) = adt_def_kind else { return vec![] }; - debug!("looking for fields named {item_name} for {adt_def_id:?}"); - // FIXME: this doesn't really belong in `associated_item` (maybe `variant_field` is better?) - // NOTE: it's different from variant_field because it only resolves struct fields, - // not variant fields (2 path segments, not 3). - // - // We need to handle struct (and union) fields in this code because - // syntactically their paths are identical to associated item paths: - // `module::Type::field` and `module::Type::Assoc`. - // - // On the other hand, variant fields can't be mistaken for associated - // items because they look like this: `module::Type::Variant::field`. - // - // Variants themselves don't need to be handled here, even though - // they also look like associated items (`module::Type::Variant`), - // because they are real Rust syntax (unlike the intra-doc links - // field syntax) and are handled by the compiler's resolver. - let ty::Adt(def, _) = tcx.type_of(adt_def_id).instantiate_identity().kind() else { - unreachable!() - }; - def.non_enum_variant() - .fields - .iter() - .filter(|field| field.name == item_name) - .map(|field| (root_res, field.did)) - .collect::>() - }; - - if let Some(Disambiguator::Kind(DefKind::Field)) = disambiguator { - return search_for_field(); - } - - // Checks if item_name belongs to `impl SomeItem` - let mut assoc_items: Vec<_> = tcx - .inherent_impls(adt_def_id) - .iter() - .flat_map(|&imp| { - filter_assoc_items_by_name_and_namespace( - tcx, - imp, - Ident::with_dummy_span(item_name), - ns, - ) - }) - .map(|item| (root_res, item.def_id)) - .collect(); - - if assoc_items.is_empty() { - // Check if item_name belongs to `impl SomeTrait for SomeItem` - // FIXME(#74563): This gives precedence to `impl SomeItem`: - // Although having both would be ambiguous, use impl version for compatibility's sake. - // To handle that properly resolve() would have to support - // something like [`ambi_fn`](::ambi_fn) - assoc_items = resolve_associated_trait_item( - tcx.type_of(adt_def_id).instantiate_identity(), - module_id, - item_name, - ns, - self.cx, - ) - .into_iter() - .map(|item| (root_res, item.def_id)) - .collect::>(); - } - - debug!("got associated item {assoc_items:?}"); - - if !assoc_items.is_empty() { - return assoc_items; - } - - if ns != Namespace::ValueNS { - return Vec::new(); - } - - search_for_field() - } } fn full_res(tcx: TyCtxt<'_>, (base, assoc_item): (Res, Option)) -> Res { assoc_item.map_or(base, |def_id| Res::from_def_id(tcx, def_id)) } +/// Given a primitive type, try to resolve an associated item. +fn resolve_primitive_associated_item<'tcx>( + tcx: TyCtxt<'tcx>, + prim_ty: PrimitiveType, + ns: Namespace, + item_ident: Ident, +) -> Vec<(Res, DefId)> { + prim_ty + .impls(tcx) + .flat_map(|impl_| { + filter_assoc_items_by_name_and_namespace(tcx, impl_, item_ident, ns) + .map(|item| (Res::Primitive(prim_ty), item.def_id)) + }) + .collect::>() +} + +fn resolve_self_ty<'tcx>( + tcx: TyCtxt<'tcx>, + path_str: &str, + ns: Namespace, + item_id: DefId, +) -> Option { + if ns != TypeNS || path_str != "Self" { + return None; + } + + let self_id = match tcx.def_kind(item_id) { + def_kind @ (DefKind::AssocFn + | DefKind::AssocConst + | DefKind::AssocTy + | DefKind::Variant + | DefKind::Field) => { + let parent_def_id = tcx.parent(item_id); + if def_kind == DefKind::Field && tcx.def_kind(parent_def_id) == DefKind::Variant { + tcx.parent(parent_def_id) + } else { + parent_def_id + } + } + _ => item_id, + }; + + match tcx.def_kind(self_id) { + DefKind::Impl { .. } => ty_to_res(tcx, tcx.type_of(self_id).instantiate_identity()), + DefKind::Use => None, + def_kind => Some(Res::Def(def_kind, self_id)), + } +} + +/// Convert a Ty to a Res, where possible. +/// +/// This is used for resolving type aliases. +fn ty_to_res<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option { + use PrimitiveType::*; + Some(match *ty.kind() { + ty::Bool => Res::Primitive(Bool), + ty::Char => Res::Primitive(Char), + ty::Int(ity) => Res::Primitive(ity.into()), + ty::Uint(uty) => Res::Primitive(uty.into()), + ty::Float(fty) => Res::Primitive(fty.into()), + ty::Str => Res::Primitive(Str), + ty::Tuple(tys) if tys.is_empty() => Res::Primitive(Unit), + ty::Tuple(_) => Res::Primitive(Tuple), + ty::Pat(..) => Res::Primitive(Pat), + ty::Array(..) => Res::Primitive(Array), + ty::Slice(_) => Res::Primitive(Slice), + ty::RawPtr(_, _) => Res::Primitive(RawPointer), + ty::Ref(..) => Res::Primitive(Reference), + ty::FnDef(..) => panic!("type alias to a function definition"), + ty::FnPtr(..) => Res::Primitive(Fn), + ty::Never => Res::Primitive(Never), + ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did, .. }, _)), _) | ty::Foreign(did) => { + Res::from_def_id(tcx, did) + } + ty::Alias(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Dynamic(..) + | ty::UnsafeBinder(_) + | ty::Param(_) + | ty::Bound(..) + | ty::Placeholder(_) + | ty::Infer(_) + | ty::Error(_) => return None, + }) +} + +/// Convert a PrimitiveType to a Ty, where possible. +/// +/// This is used for resolving trait impls for primitives +fn primitive_type_to_ty<'tcx>(tcx: TyCtxt<'tcx>, prim: PrimitiveType) -> Option> { + use PrimitiveType::*; + + // FIXME: Only simple types are supported here, see if we can support + // other types such as Tuple, Array, Slice, etc. + // See https://github.com/rust-lang/rust/issues/90703#issuecomment-1004263455 + Some(match prim { + Bool => tcx.types.bool, + Str => tcx.types.str_, + Char => tcx.types.char, + Never => tcx.types.never, + I8 => tcx.types.i8, + I16 => tcx.types.i16, + I32 => tcx.types.i32, + I64 => tcx.types.i64, + I128 => tcx.types.i128, + Isize => tcx.types.isize, + F16 => tcx.types.f16, + F32 => tcx.types.f32, + F64 => tcx.types.f64, + F128 => tcx.types.f128, + U8 => tcx.types.u8, + U16 => tcx.types.u16, + U32 => tcx.types.u32, + U64 => tcx.types.u64, + U128 => tcx.types.u128, + Usize => tcx.types.usize, + _ => return None, + }) +} + +/// Resolve an associated item, returning its containing page's `Res` +/// and the fragment targeting the associated item on its page. +fn resolve_associated_item<'tcx>( + tcx: TyCtxt<'tcx>, + root_res: Res, + item_name: Symbol, + ns: Namespace, + disambiguator: Option, + module_id: DefId, +) -> Vec<(Res, DefId)> { + let item_ident = Ident::with_dummy_span(item_name); + + match root_res { + Res::Primitive(prim) => { + let items = resolve_primitive_associated_item(tcx, prim, ns, item_ident); + if !items.is_empty() { + items + // Inherent associated items take precedence over items that come from trait impls. + } else { + primitive_type_to_ty(tcx, prim) + .map(|ty| { + resolve_associated_trait_item(ty, module_id, item_ident, ns, tcx) + .iter() + .map(|item| (root_res, item.def_id)) + .collect::>() + }) + .unwrap_or_default() + } + } + Res::Def(DefKind::TyAlias, did) => { + // Resolve the link on the type the alias points to. + // FIXME: if the associated item is defined directly on the type alias, + // it will show up on its documentation page, we should link there instead. + let Some(res) = ty_to_res(tcx, tcx.type_of(did).instantiate_identity()) else { + return Vec::new(); + }; + resolve_associated_item(tcx, res, item_name, ns, disambiguator, module_id) + } + Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum, did) => { + resolve_assoc_on_adt(tcx, did, item_name, ns, disambiguator, module_id) + } + Res::Def(DefKind::ForeignTy, did) => { + resolve_assoc_on_simple_type(tcx, did, item_ident, ns, module_id) + } + Res::Def(DefKind::Trait, did) => filter_assoc_items_by_name_and_namespace( + tcx, + did, + Ident::with_dummy_span(item_name), + ns, + ) + .map(|item| (root_res, item.def_id)) + .collect::>(), + _ => Vec::new(), + } +} + +fn resolve_assoc_on_adt<'tcx>( + tcx: TyCtxt<'tcx>, + adt_def_id: DefId, + item_name: Symbol, + ns: Namespace, + disambiguator: Option, + module_id: DefId, +) -> Vec<(Res, DefId)> { + debug!("looking for associated item named {item_name} for item {adt_def_id:?}"); + let root_res = Res::from_def_id(tcx, adt_def_id); + let adt_ty = tcx.type_of(adt_def_id).instantiate_identity(); + let adt_def = adt_ty.ty_adt_def().expect("must be ADT"); + let item_ident = Ident::with_dummy_span(item_name); + // Checks if item_name is a variant of the `SomeItem` enum + if ns == TypeNS && adt_def.is_enum() { + for variant in adt_def.variants() { + if variant.name == item_name { + return vec![(root_res, variant.def_id)]; + } + } + } + + if let Some(Disambiguator::Kind(DefKind::Field)) = disambiguator + && (adt_def.is_struct() || adt_def.is_union()) + { + return resolve_structfield(adt_def, item_name) + .into_iter() + .map(|did| (root_res, did)) + .collect(); + } + + let assoc_items = resolve_assoc_on_simple_type(tcx, adt_def_id, item_ident, ns, module_id); + if !assoc_items.is_empty() { + return assoc_items; + } + + if ns == Namespace::ValueNS && (adt_def.is_struct() || adt_def.is_union()) { + return resolve_structfield(adt_def, item_name) + .into_iter() + .map(|did| (root_res, did)) + .collect(); + } + + vec![] +} + +/// "Simple" i.e. an ADT, foreign type, etc. -- not a type alias, primitive type, or other trickier type. +fn resolve_assoc_on_simple_type<'tcx>( + tcx: TyCtxt<'tcx>, + ty_def_id: DefId, + item_ident: Ident, + ns: Namespace, + module_id: DefId, +) -> Vec<(Res, DefId)> { + let root_res = Res::from_def_id(tcx, ty_def_id); + // Checks if item_name belongs to `impl SomeItem` + let inherent_assoc_items: Vec<_> = tcx + .inherent_impls(ty_def_id) + .iter() + .flat_map(|&imp| filter_assoc_items_by_name_and_namespace(tcx, imp, item_ident, ns)) + .map(|item| (root_res, item.def_id)) + .collect(); + debug!("got inherent assoc items {inherent_assoc_items:?}"); + if !inherent_assoc_items.is_empty() { + return inherent_assoc_items; + } + + // Check if item_name belongs to `impl SomeTrait for SomeItem` + // FIXME(#74563): This gives precedence to `impl SomeItem`: + // Although having both would be ambiguous, use impl version for compatibility's sake. + // To handle that properly resolve() would have to support + // something like [`ambi_fn`](::ambi_fn) + let ty = tcx.type_of(ty_def_id).instantiate_identity(); + let trait_assoc_items = resolve_associated_trait_item(ty, module_id, item_ident, ns, tcx) + .into_iter() + .map(|item| (root_res, item.def_id)) + .collect::>(); + debug!("got trait assoc items {trait_assoc_items:?}"); + trait_assoc_items +} + +fn resolve_structfield<'tcx>(adt_def: ty::AdtDef<'tcx>, item_name: Symbol) -> Option { + debug!("looking for fields named {item_name} for {adt_def:?}"); + adt_def + .non_enum_variant() + .fields + .iter() + .find(|field| field.name == item_name) + .map(|field| field.did) +} + /// Look to see if a resolved item has an associated item named `item_name`. /// /// Given `[std::io::Error::source]`, where `source` is unresolved, this would /// find `std::error::Error::source` and return /// `::source`. -fn resolve_associated_trait_item<'a>( - ty: Ty<'a>, +fn resolve_associated_trait_item<'tcx>( + ty: Ty<'tcx>, module: DefId, - item_name: Symbol, + item_ident: Ident, ns: Namespace, - cx: &mut DocContext<'a>, + tcx: TyCtxt<'tcx>, ) -> Vec { // FIXME: this should also consider blanket impls (`impl X for T`). Unfortunately // `get_auto_trait_and_blanket_impls` is broken because the caching behavior is wrong. In the @@ -763,22 +749,17 @@ fn resolve_associated_trait_item<'a>( // Next consider explicit impls: `impl MyTrait for MyType` // Give precedence to inherent impls. - let traits = trait_impls_for(cx, ty, module); - let tcx = cx.tcx; + let traits = trait_impls_for(tcx, ty, module); debug!("considering traits {traits:?}"); let candidates = traits .iter() .flat_map(|&(impl_, trait_)| { - filter_assoc_items_by_name_and_namespace( - tcx, - trait_, - Ident::with_dummy_span(item_name), - ns, + filter_assoc_items_by_name_and_namespace(tcx, trait_, item_ident, ns).map( + move |trait_assoc| { + trait_assoc_to_impl_assoc_item(tcx, impl_, trait_assoc.def_id) + .unwrap_or(*trait_assoc) + }, ) - .map(move |trait_assoc| { - trait_assoc_to_impl_assoc_item(tcx, impl_, trait_assoc.def_id) - .unwrap_or(*trait_assoc) - }) }) .collect::>(); // FIXME(#74563): warn about ambiguity @@ -813,13 +794,12 @@ fn trait_assoc_to_impl_assoc_item<'tcx>( /// /// NOTE: this cannot be a query because more traits could be available when more crates are compiled! /// So it is not stable to serialize cross-crate. -#[instrument(level = "debug", skip(cx))] -fn trait_impls_for<'a>( - cx: &mut DocContext<'a>, - ty: Ty<'a>, +#[instrument(level = "debug", skip(tcx))] +fn trait_impls_for<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, module: DefId, ) -> FxIndexSet<(DefId, DefId)> { - let tcx = cx.tcx; let mut impls = FxIndexSet::default(); for &trait_ in tcx.doc_link_traits_in_scope(module) { @@ -1535,7 +1515,7 @@ impl LinkCollector<'_, '_> { } None => { // Try everything! - let mut candidate = |ns| { + let candidate = |ns| { self.resolve(path_str, ns, None, item_id, module_id) .map_err(ResolutionFailure::NotResolved) }; @@ -1921,7 +1901,7 @@ fn report_diagnostic( /// handled earlier. For example, if passed `Item::Crate(std)` and `path_str` /// `std::io::Error::x`, this will resolve `std::io::Error`. fn resolution_failure( - collector: &mut LinkCollector<'_, '_>, + collector: &LinkCollector<'_, '_>, diag_info: DiagnosticInfo<'_>, path_str: &str, disambiguator: Option, From 742d276dc1d9f21c2196a057e2ac4bcaf70e3cc5 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Thu, 8 Jan 2026 20:24:49 +0100 Subject: [PATCH 0431/1061] make attrs actually use `Target::GenericParam` --- compiler/rustc_ast_lowering/src/lib.rs | 9 ++++--- .../src/attributes/stability.rs | 3 ++- .../rustc_attr_parsing/src/target_checking.rs | 24 +++++++++++++++++++ compiler/rustc_hir/src/lib.rs | 2 +- ...id-attributes-on-const-params-78957.stderr | 12 +++++----- tests/ui/force-inlining/invalid.stderr | 2 +- .../unused/unused_attributes-must_use.stderr | 2 +- tests/ui/pin-ergonomics/pin_v2-attr.rs | 4 ++-- tests/ui/pin-ergonomics/pin_v2-attr.stderr | 4 ++-- tests/ui/scalable-vectors/invalid.rs | 2 +- tests/ui/scalable-vectors/invalid.stderr | 2 +- 11 files changed, 47 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index a81d2297ef85..6f8dab21e2b6 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1986,8 +1986,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let (name, kind) = self.lower_generic_param_kind(param, source); let hir_id = self.lower_node_id(param.id); - self.lower_attrs(hir_id, ¶m.attrs, param.span(), Target::Param); - hir::GenericParam { + let param_attrs = ¶m.attrs; + let param_span = param.span(); + let param = hir::GenericParam { hir_id, def_id: self.local_def_id(param.id), name, @@ -1996,7 +1997,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { kind, colon_span: param.colon_span.map(|s| self.lower_span(s)), source, - } + }; + self.lower_attrs(hir_id, param_attrs, param_span, Target::from_generic_param(¶m)); + param } fn lower_generic_param_kind( diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index 6d4f77ef1751..8d27e2e276dd 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -1,6 +1,7 @@ use std::num::NonZero; use rustc_errors::ErrorGuaranteed; +use rustc_hir::target::GenericParamKind; use rustc_hir::{ DefaultBodyStability, MethodKind, PartialConstStability, Stability, StabilityLevel, StableSince, Target, UnstableReason, VERSION_PLACEHOLDER, @@ -43,7 +44,7 @@ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ Allow(Target::TyAlias), Allow(Target::Variant), Allow(Target::Field), - Allow(Target::Param), + Allow(Target::GenericParam { kind: GenericParamKind::Type, has_default: true }), Allow(Target::Static), Allow(Target::ForeignFn), Allow(Target::ForeignStatic), diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index e86ecb451fc2..88fa3e436292 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -310,5 +310,29 @@ pub(crate) const ALL_TARGETS: &'static [Policy] = { Allow(Target::Crate), Allow(Target::Delegation { mac: false }), Allow(Target::Delegation { mac: true }), + Allow(Target::GenericParam { + kind: rustc_hir::target::GenericParamKind::Const, + has_default: false, + }), + Allow(Target::GenericParam { + kind: rustc_hir::target::GenericParamKind::Const, + has_default: true, + }), + Allow(Target::GenericParam { + kind: rustc_hir::target::GenericParamKind::Lifetime, + has_default: false, + }), + Allow(Target::GenericParam { + kind: rustc_hir::target::GenericParamKind::Lifetime, + has_default: true, + }), + Allow(Target::GenericParam { + kind: rustc_hir::target::GenericParamKind::Type, + has_default: false, + }), + Allow(Target::GenericParam { + kind: rustc_hir::target::GenericParamKind::Type, + has_default: true, + }), ] }; diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index fa46c0f085a2..9c2fec867785 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -32,7 +32,7 @@ pub mod lints; pub mod pat_util; mod stability; mod stable_hash_impls; -mod target; +pub mod target; pub mod weak_lang_items; #[cfg(test)] diff --git a/tests/ui/const-generics/invalid-attributes-on-const-params-78957.stderr b/tests/ui/const-generics/invalid-attributes-on-const-params-78957.stderr index f8010b4ea687..5fc7e7fef75d 100644 --- a/tests/ui/const-generics/invalid-attributes-on-const-params-78957.stderr +++ b/tests/ui/const-generics/invalid-attributes-on-const-params-78957.stderr @@ -1,4 +1,4 @@ -error: `#[inline]` attribute cannot be used on function params +error: `#[inline]` attribute cannot be used on const parameters --> $DIR/invalid-attributes-on-const-params-78957.rs:6:16 | LL | pub struct Foo<#[inline] const N: usize>; @@ -6,7 +6,7 @@ LL | pub struct Foo<#[inline] const N: usize>; | = help: `#[inline]` can only be applied to functions -error: `#[inline]` attribute cannot be used on function params +error: `#[inline]` attribute cannot be used on lifetime parameters --> $DIR/invalid-attributes-on-const-params-78957.rs:14:17 | LL | pub struct Foo2<#[inline] 'a>(PhantomData<&'a ()>); @@ -14,7 +14,7 @@ LL | pub struct Foo2<#[inline] 'a>(PhantomData<&'a ()>); | = help: `#[inline]` can only be applied to functions -error: `#[inline]` attribute cannot be used on function params +error: `#[inline]` attribute cannot be used on type parameters --> $DIR/invalid-attributes-on-const-params-78957.rs:22:17 | LL | pub struct Foo3<#[inline] T>(PhantomData); @@ -40,7 +40,7 @@ error[E0517]: attribute should be applied to a struct, enum, or union LL | pub struct Baz3<#[repr(C)] T>(PhantomData); | ^ - not a struct, enum, or union -error: `#[cold]` attribute cannot be used on function params +error: `#[cold]` attribute cannot be used on const parameters --> $DIR/invalid-attributes-on-const-params-78957.rs:8:16 | LL | pub struct Bar<#[cold] const N: usize>; @@ -54,7 +54,7 @@ note: the lint level is defined here LL | #![deny(unused_attributes)] | ^^^^^^^^^^^^^^^^^ -error: `#[cold]` attribute cannot be used on function params +error: `#[cold]` attribute cannot be used on lifetime parameters --> $DIR/invalid-attributes-on-const-params-78957.rs:16:17 | LL | pub struct Bar2<#[cold] 'a>(PhantomData<&'a ()>); @@ -63,7 +63,7 @@ LL | pub struct Bar2<#[cold] 'a>(PhantomData<&'a ()>); = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = help: `#[cold]` can only be applied to functions -error: `#[cold]` attribute cannot be used on function params +error: `#[cold]` attribute cannot be used on type parameters --> $DIR/invalid-attributes-on-const-params-78957.rs:24:17 | LL | pub struct Bar3<#[cold] T>(PhantomData); diff --git a/tests/ui/force-inlining/invalid.stderr b/tests/ui/force-inlining/invalid.stderr index df3b646b6cec..ce4f1d77ad2d 100644 --- a/tests/ui/force-inlining/invalid.stderr +++ b/tests/ui/force-inlining/invalid.stderr @@ -152,7 +152,7 @@ LL | #[rustc_force_inline] | = help: `#[rustc_force_inline]` can only be applied to functions -error: `#[rustc_force_inline]` attribute cannot be used on function params +error: `#[rustc_force_inline]` attribute cannot be used on type parameters --> $DIR/invalid.rs:72:10 | LL | enum Bar<#[rustc_force_inline] T> { diff --git a/tests/ui/lint/unused/unused_attributes-must_use.stderr b/tests/ui/lint/unused/unused_attributes-must_use.stderr index 9b9a6a9c9f3d..3192c0994548 100644 --- a/tests/ui/lint/unused/unused_attributes-must_use.stderr +++ b/tests/ui/lint/unused/unused_attributes-must_use.stderr @@ -93,7 +93,7 @@ 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! = help: `#[must_use]` can be applied to data types, functions, traits, and unions -error: `#[must_use]` attribute cannot be used on function params +error: `#[must_use]` attribute cannot be used on type parameters --> $DIR/unused_attributes-must_use.rs:77:8 | LL | fn qux<#[must_use] T>(_: T) {} diff --git a/tests/ui/pin-ergonomics/pin_v2-attr.rs b/tests/ui/pin-ergonomics/pin_v2-attr.rs index cfafe4b0b899..ba25d3587edd 100644 --- a/tests/ui/pin-ergonomics/pin_v2-attr.rs +++ b/tests/ui/pin-ergonomics/pin_v2-attr.rs @@ -25,8 +25,8 @@ union Union { // disallowed enum Foo<#[pin_v2] T, #[pin_v2] U = ()> { - //~^ ERROR `#[pin_v2]` attribute cannot be used on function params - //~| ERROR `#[pin_v2]` attribute cannot be used on function params + //~^ ERROR `#[pin_v2]` attribute cannot be used on type parameters + //~| ERROR `#[pin_v2]` attribute cannot be used on type parameters #[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on enum variants UnitVariant, TupleVariant(#[pin_v2] T), //~ ERROR `#[pin_v2]` attribute cannot be used on struct fields diff --git a/tests/ui/pin-ergonomics/pin_v2-attr.stderr b/tests/ui/pin-ergonomics/pin_v2-attr.stderr index 81e086f5a7ef..c297afa87a73 100644 --- a/tests/ui/pin-ergonomics/pin_v2-attr.stderr +++ b/tests/ui/pin-ergonomics/pin_v2-attr.stderr @@ -20,7 +20,7 @@ LL | #![pin_v2] | = help: `#[pin_v2]` can be applied to data types and unions -error: `#[pin_v2]` attribute cannot be used on function params +error: `#[pin_v2]` attribute cannot be used on type parameters --> $DIR/pin_v2-attr.rs:27:10 | LL | enum Foo<#[pin_v2] T, #[pin_v2] U = ()> { @@ -28,7 +28,7 @@ LL | enum Foo<#[pin_v2] T, #[pin_v2] U = ()> { | = help: `#[pin_v2]` can be applied to data types and unions -error: `#[pin_v2]` attribute cannot be used on function params +error: `#[pin_v2]` attribute cannot be used on type parameters --> $DIR/pin_v2-attr.rs:27:23 | LL | enum Foo<#[pin_v2] T, #[pin_v2] U = ()> { diff --git a/tests/ui/scalable-vectors/invalid.rs b/tests/ui/scalable-vectors/invalid.rs index beb3ad66b78b..90e9839c9e11 100644 --- a/tests/ui/scalable-vectors/invalid.rs +++ b/tests/ui/scalable-vectors/invalid.rs @@ -48,7 +48,7 @@ type Foo = u32; #[rustc_scalable_vector(4)] //~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on enums enum Bar<#[rustc_scalable_vector(4)] T> { -//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on function params +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on type parameters #[rustc_scalable_vector(4)] //~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on enum variants Baz(std::marker::PhantomData), diff --git a/tests/ui/scalable-vectors/invalid.stderr b/tests/ui/scalable-vectors/invalid.stderr index 43be84a8b005..d73b5abf7030 100644 --- a/tests/ui/scalable-vectors/invalid.stderr +++ b/tests/ui/scalable-vectors/invalid.stderr @@ -92,7 +92,7 @@ LL | #[rustc_scalable_vector(4)] | = help: `#[rustc_scalable_vector]` can only be applied to structs -error: `#[rustc_scalable_vector]` attribute cannot be used on function params +error: `#[rustc_scalable_vector]` attribute cannot be used on type parameters --> $DIR/invalid.rs:50:10 | LL | enum Bar<#[rustc_scalable_vector(4)] T> { From dc505a51a4adea72efe1f1b08af6bf75b45ffdca Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Thu, 1 Jan 2026 19:24:41 +0100 Subject: [PATCH 0432/1061] Hash all spans relatively to their parent Co-authored-by: Camille Gillot --- .../rustc_middle/src/query/on_disk_cache.rs | 46 +++++++++++-------- compiler/rustc_query_system/src/ich/hcx.rs | 6 +-- .../rustc_span/src/caching_source_map_view.rs | 8 ++-- compiler/rustc_span/src/lib.rs | 37 ++++++++++----- 4 files changed, 58 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index c882d5d499bd..29cceb708850 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -20,8 +20,8 @@ use rustc_span::hygiene::{ }; use rustc_span::source_map::Spanned; use rustc_span::{ - BlobDecoder, BytePos, ByteSymbol, CachingSourceMapView, ExpnData, ExpnHash, Pos, - RelativeBytePos, SourceFile, Span, SpanDecoder, SpanEncoder, StableSourceFileId, Symbol, + BlobDecoder, BytePos, ByteSymbol, CachingSourceMapView, ExpnData, ExpnHash, RelativeBytePos, + SourceFile, Span, SpanDecoder, SpanEncoder, StableSourceFileId, Symbol, }; use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; @@ -652,7 +652,10 @@ impl<'a, 'tcx> SpanDecoder for CacheDecoder<'a, 'tcx> { let dto = u32::decode(self); let enclosing = self.tcx.source_span_untracked(parent.unwrap()).data_untracked(); - (enclosing.lo + BytePos::from_u32(dlo), enclosing.lo + BytePos::from_u32(dto)) + ( + BytePos(enclosing.lo.0.wrapping_add(dlo)), + BytePos(enclosing.lo.0.wrapping_add(dto)), + ) } TAG_FULL_SPAN => { let file_lo_index = SourceFileIndex::decode(self); @@ -894,30 +897,33 @@ impl<'a, 'tcx> SpanEncoder for CacheEncoder<'a, 'tcx> { return TAG_PARTIAL_SPAN.encode(self); } - if let Some(parent) = span_data.parent { - let enclosing = self.tcx.source_span_untracked(parent).data_untracked(); - if enclosing.contains(span_data) { - TAG_RELATIVE_SPAN.encode(self); - (span_data.lo - enclosing.lo).to_u32().encode(self); - (span_data.hi - enclosing.lo).to_u32().encode(self); - return; - } + let parent = + span_data.parent.map(|parent| self.tcx.source_span_untracked(parent).data_untracked()); + if let Some(parent) = parent + && parent.contains(span_data) + { + TAG_RELATIVE_SPAN.encode(self); + (span_data.lo.0.wrapping_sub(parent.lo.0)).encode(self); + (span_data.hi.0.wrapping_sub(parent.lo.0)).encode(self); + return; } - let pos = self.source_map.byte_pos_to_line_and_col(span_data.lo); - let partial_span = match &pos { - Some((file_lo, _, _)) => !file_lo.contains(span_data.hi), - None => true, + let Some((file_lo, line_lo, col_lo)) = + self.source_map.byte_pos_to_line_and_col(span_data.lo) + else { + return TAG_PARTIAL_SPAN.encode(self); }; - if partial_span { - return TAG_PARTIAL_SPAN.encode(self); + if let Some(parent) = parent + && file_lo.contains(parent.lo) + { + TAG_RELATIVE_SPAN.encode(self); + (span_data.lo.0.wrapping_sub(parent.lo.0)).encode(self); + (span_data.hi.0.wrapping_sub(parent.lo.0)).encode(self); + return; } - let (file_lo, line_lo, col_lo) = pos.unwrap(); - let len = span_data.hi - span_data.lo; - let source_file_index = self.source_file_index(file_lo); TAG_FULL_SPAN.encode(self); diff --git a/compiler/rustc_query_system/src/ich/hcx.rs b/compiler/rustc_query_system/src/ich/hcx.rs index be838f689e53..840f0b35266d 100644 --- a/compiler/rustc_query_system/src/ich/hcx.rs +++ b/compiler/rustc_query_system/src/ich/hcx.rs @@ -5,9 +5,7 @@ use rustc_hir::definitions::DefPathHash; use rustc_session::Session; use rustc_session::cstore::Untracked; use rustc_span::source_map::SourceMap; -use rustc_span::{ - BytePos, CachingSourceMapView, DUMMY_SP, Span, SpanData, StableSourceFileId, Symbol, -}; +use rustc_span::{BytePos, CachingSourceMapView, DUMMY_SP, SourceFile, Span, SpanData, Symbol}; use crate::ich; @@ -118,7 +116,7 @@ impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> { fn span_data_to_lines_and_cols( &mut self, span: &SpanData, - ) -> Option<(StableSourceFileId, usize, BytePos, usize, BytePos)> { + ) -> Option<(&SourceFile, usize, BytePos, usize, BytePos)> { self.source_map().span_data_to_lines_and_cols(span) } diff --git a/compiler/rustc_span/src/caching_source_map_view.rs b/compiler/rustc_span/src/caching_source_map_view.rs index 41cfaa3ee34e..11507a3d9e45 100644 --- a/compiler/rustc_span/src/caching_source_map_view.rs +++ b/compiler/rustc_span/src/caching_source_map_view.rs @@ -2,7 +2,7 @@ use std::ops::Range; use std::sync::Arc; use crate::source_map::SourceMap; -use crate::{BytePos, Pos, RelativeBytePos, SourceFile, SpanData, StableSourceFileId}; +use crate::{BytePos, Pos, RelativeBytePos, SourceFile, SpanData}; #[derive(Clone)] struct CacheEntry { @@ -114,7 +114,7 @@ impl<'sm> CachingSourceMapView<'sm> { pub fn span_data_to_lines_and_cols( &mut self, span_data: &SpanData, - ) -> Option<(StableSourceFileId, usize, BytePos, usize, BytePos)> { + ) -> Option<(&SourceFile, usize, BytePos, usize, BytePos)> { self.time_stamp += 1; // Check if lo and hi are in the cached lines. @@ -136,7 +136,7 @@ impl<'sm> CachingSourceMapView<'sm> { let lo = &self.line_cache[lo_cache_idx as usize]; let hi = &self.line_cache[hi_cache_idx as usize]; return Some(( - lo.file.stable_id, + &lo.file, lo.line_number, span_data.lo - lo.line.start, hi.line_number, @@ -224,7 +224,7 @@ impl<'sm> CachingSourceMapView<'sm> { assert_eq!(lo.file_index, hi.file_index); Some(( - lo.file.stable_id, + &lo.file, lo.line_number, span_data.lo - lo.line.start, hi.line_number, diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index d3e0e303d0c6..1c430099835b 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -2831,7 +2831,7 @@ pub trait HashStableContext { fn span_data_to_lines_and_cols( &mut self, span: &SpanData, - ) -> Option<(StableSourceFileId, usize, BytePos, usize, BytePos)>; + ) -> Option<(&SourceFile, usize, BytePos, usize, BytePos)>; fn hashing_controls(&self) -> HashingControls; } @@ -2849,6 +2849,8 @@ where /// codepoint offsets. For the purpose of the hash that's sufficient. /// Also, hashing filenames is expensive so we avoid doing it twice when the /// span starts and ends in the same file, which is almost always the case. + /// + /// IMPORTANT: changes to this method should be reflected in implementations of `SpanEncoder`. fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { const TAG_VALID_SPAN: u8 = 0; const TAG_INVALID_SPAN: u8 = 1; @@ -2867,15 +2869,17 @@ where return; } - if let Some(parent) = span.parent { - let def_span = ctx.def_span(parent).data_untracked(); - if def_span.contains(span) { - // This span is enclosed in a definition: only hash the relative position. - Hash::hash(&TAG_RELATIVE_SPAN, hasher); - (span.lo - def_span.lo).to_u32().hash_stable(ctx, hasher); - (span.hi - def_span.lo).to_u32().hash_stable(ctx, hasher); - return; - } + let parent = span.parent.map(|parent| ctx.def_span(parent).data_untracked()); + if let Some(parent) = parent + && parent.contains(span) + { + // This span is enclosed in a definition: only hash the relative position. + // This catches a subset of the cases from the `file.contains(parent.lo)`, + // But we can do this check cheaply without the expensive `span_data_to_lines_and_cols` query. + Hash::hash(&TAG_RELATIVE_SPAN, hasher); + (span.lo - parent.lo).to_u32().hash_stable(ctx, hasher); + (span.hi - parent.lo).to_u32().hash_stable(ctx, hasher); + return; } // If this is not an empty or invalid span, we want to hash the last @@ -2887,8 +2891,19 @@ where return; }; + if let Some(parent) = parent + && file.contains(parent.lo) + { + // This span is relative to another span in the same file, + // only hash the relative position. + Hash::hash(&TAG_RELATIVE_SPAN, hasher); + Hash::hash(&(span.lo.0.wrapping_sub(parent.lo.0)), hasher); + Hash::hash(&(span.hi.0.wrapping_sub(parent.lo.0)), hasher); + return; + } + Hash::hash(&TAG_VALID_SPAN, hasher); - Hash::hash(&file, hasher); + Hash::hash(&file.stable_id, hasher); // Hash both the length and the end location (line/column) of a span. If we // hash only the length, for example, then two otherwise equal spans with From c502d7fce0e057eee00bfab471360ea751ef3762 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 8 Jan 2026 16:53:50 +0100 Subject: [PATCH 0433/1061] Fix trait method anchor disappearing before user can click on it --- src/librustdoc/html/static/css/rustdoc.css | 4 +++- tests/rustdoc-gui/anchor-navigable.goml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index b93e921dd5b7..b770a0e2a0e4 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1200,9 +1200,11 @@ nav.sub { display: initial; } .anchor { + --anchor-link-shift: 0.5em; display: none; position: absolute; - left: -0.5em; + left: calc(var(--anchor-link-shift) * -1); + padding-right: var(--anchor-link-shift); background: none !important; } .anchor.field { diff --git a/tests/rustdoc-gui/anchor-navigable.goml b/tests/rustdoc-gui/anchor-navigable.goml index 61d7c89d434f..db7fc3bbf182 100644 --- a/tests/rustdoc-gui/anchor-navigable.goml +++ b/tests/rustdoc-gui/anchor-navigable.goml @@ -7,5 +7,5 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" // We check that ".item-info" is bigger than its content. move-cursor-to: ".impl" -assert-property: (".impl > a.anchor", {"offsetWidth": "8"}) +assert-property: (".impl > a.anchor", {"offsetWidth": "16"}) assert-css: (".impl > a.anchor", {"left": "-8px"}) From bfb117ac744d6e1dd73b25eb46066bf3a36380c7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 8 Jan 2026 17:09:07 +0100 Subject: [PATCH 0434/1061] Clean up `tests/rustdoc-gui/anchors.goml` test code --- tests/rustdoc-gui/anchors.goml | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/tests/rustdoc-gui/anchors.goml b/tests/rustdoc-gui/anchors.goml index 0e8c834a7a77..371a4583c7b2 100644 --- a/tests/rustdoc-gui/anchors.goml +++ b/tests/rustdoc-gui/anchors.goml @@ -14,9 +14,9 @@ define-function: ( assert-css: ("#toggle-all-docs", {"color": |main_color|}) assert-css: (".main-heading h1 span", {"color": |main_heading_type_color|}) assert-css: ( - ".rightside a.src", - {"color": |src_link_color|, "text-decoration": "none"}, - ALL, + ".rightside a.src", + {"color": |src_link_color|, "text-decoration": "none"}, + ALL, ) compare-elements-css: ( ".rightside a.src", @@ -31,25 +31,23 @@ define-function: ( move-cursor-to: ".main-heading a.src" assert-css: ( - ".main-heading a.src", - {"color": |src_link_color|, "text-decoration": "underline"}, + ".main-heading a.src", + {"color": |src_link_color|, "text-decoration": "underline"}, ) move-cursor-to: ".impl-items .rightside a.src" assert-css: ( - ".impl-items .rightside a.src", - {"color": |src_link_color|, "text-decoration": "none"}, + ".impl-items .rightside a.src", + {"color": |src_link_color|, "text-decoration": "none"}, ) move-cursor-to: ".impl-items a.rightside.src" assert-css: ( - ".impl-items a.rightside.src", - {"color": |src_link_color|, "text-decoration": "none"}, + ".impl-items a.rightside.src", + {"color": |src_link_color|, "text-decoration": "none"}, ) go-to: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html" // Since we changed page, we need to set the theme again. - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - // We reload the page so the local storage settings are being used. - reload: + call-function: ("switch-theme", {"theme": |theme|}) assert-css: ("#top-doc-prose-title", {"color": |title_color|}) From 16fbf6a27b5962b818f4c6ca14d391c6911ed6a8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 8 Jan 2026 17:41:42 +0100 Subject: [PATCH 0435/1061] Add check for trait impl method anchor --- tests/rustdoc-gui/anchors.goml | 16 ++++++++++++++++ tests/rustdoc-gui/src/staged_api/lib.rs | 8 ++++++++ 2 files changed, 24 insertions(+) diff --git a/tests/rustdoc-gui/anchors.goml b/tests/rustdoc-gui/anchors.goml index 371a4583c7b2..eaec73f50e97 100644 --- a/tests/rustdoc-gui/anchors.goml +++ b/tests/rustdoc-gui/anchors.goml @@ -45,6 +45,22 @@ define-function: ( {"color": |src_link_color|, "text-decoration": "none"}, ) + // Now we ensure that the `§` anchor is "reachable" for users on trait methods. + // To ensure the anchor is not hovered, we move the cursor to another item. + move-cursor-to: "#search-button" + // By default, the anchor is not displayed. + wait-for-css: ("#method\.vroum .anchor", {"display": "none"}) + // Once we move the cursor to the method, the anchor should appear. + move-cursor-to: "#method\.vroum .code-header" + assert-css-false: ("#method\.vroum .anchor", {"display": "none"}) + // Now we move the cursor to the anchor to check there is no gap between the method and the + // anchor, making the anchor disappear and preventing users to click on it. + // To make it work, we need to first move it between the method and the anchor. + store-position: ("#method\.vroum .code-header", {"x": method_x, "y": method_y}) + move-cursor-to: (|method_x| - 2, |method_y|) + // Anchor should still be displayed. + assert-css-false: ("#method\.vroum .anchor", {"display": "none"}) + go-to: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html" // Since we changed page, we need to set the theme again. call-function: ("switch-theme", {"theme": |theme|}) diff --git a/tests/rustdoc-gui/src/staged_api/lib.rs b/tests/rustdoc-gui/src/staged_api/lib.rs index 9b5ad1c5ff32..7304d2f02ab1 100644 --- a/tests/rustdoc-gui/src/staged_api/lib.rs +++ b/tests/rustdoc-gui/src/staged_api/lib.rs @@ -4,6 +4,10 @@ #![stable(feature = "some_feature", since = "1.3.5")] #![doc(rust_logo)] +pub trait X { + fn vroum(); +} + #[stable(feature = "some_feature", since = "1.3.5")] pub struct Foo {} @@ -13,3 +17,7 @@ impl Foo { #[stable(feature = "some_other_feature", since = "1.3.6")] pub fn yo() {} } + +impl X for Foo { + fn vroum() {} +} From 945e7c78d2624e9647c8c608284f23e7a2fea32e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 7 Jan 2026 13:56:16 +0100 Subject: [PATCH 0436/1061] Use functions more in rustdoc GUI tests --- tests/rustdoc-gui/copy-code.goml | 11 +++-- tests/rustdoc-gui/font-serif-change.goml | 7 ++- tests/rustdoc-gui/notable-trait.goml | 11 ++--- tests/rustdoc-gui/search-filter.goml | 6 +-- ...setting-auto-hide-content-large-items.goml | 5 +- .../setting-auto-hide-item-methods-docs.goml | 5 +- ...tting-auto-hide-trait-implementations.goml | 5 +- .../setting-go-to-only-result.goml | 11 +++-- tests/rustdoc-gui/settings.goml | 14 ++---- tests/rustdoc-gui/sidebar-mobile.goml | 13 +---- .../sidebar-resize-close-popover.goml | 7 ++- tests/rustdoc-gui/sidebar-resize-setting.goml | 4 +- tests/rustdoc-gui/source-code-wrapping.goml | 7 ++- tests/rustdoc-gui/theme-change.goml | 10 +--- tests/rustdoc-gui/theme-defaults.goml | 7 ++- tests/rustdoc-gui/utils.goml | 49 +++++++++++-------- 16 files changed, 78 insertions(+), 94 deletions(-) diff --git a/tests/rustdoc-gui/copy-code.goml b/tests/rustdoc-gui/copy-code.goml index 14421ab746f5..eb003ef5e1ca 100644 --- a/tests/rustdoc-gui/copy-code.goml +++ b/tests/rustdoc-gui/copy-code.goml @@ -1,5 +1,6 @@ // Checks that the "copy code" button is not triggering JS error and its display // isn't broken. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html" define-function: ( @@ -47,15 +48,15 @@ assert: |copy_height| > 0 && |copy_width| > 0 // First we ensure that the clipboard is empty. assert-clipboard: "" + // We make the line numbers appear. -click: "rustdoc-toolbar .settings-menu" -wait-for-css: ("#settings", {"display": "block"}) -// We make the line numbers appear. +call-function: ("open-settings-menu", {}) click: "#line-numbers" wait-for-local-storage: {"rustdoc-line-numbers": "true" } + // We close the settings menu. -click: "rustdoc-toolbar .settings-menu" -wait-for-css-false: ("#settings", {"display": "block"}) +call-function: ("close-settings-menu", {}) + // We ensure that there are actually line numbers generated in the DOM. assert-text: (".example-wrap pre.rust code span[data-nosnippet]", "1") // We make the copy button appear. diff --git a/tests/rustdoc-gui/font-serif-change.goml b/tests/rustdoc-gui/font-serif-change.goml index 1e9f21c35416..32e95cdc6ee1 100644 --- a/tests/rustdoc-gui/font-serif-change.goml +++ b/tests/rustdoc-gui/font-serif-change.goml @@ -1,4 +1,5 @@ // Ensures that the font serif change is working as expected. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" // By default, it should be the serif fonts. @@ -8,8 +9,7 @@ assert-css: ("body", {"font-family": |serif_font|}) assert-css: ("p code", {"font-family": |serif_code_font|}) // We now switch to the sans serif font -click: "main .settings-menu" -wait-for: "#sans-serif-fonts" +call-function: ("open-settings-menu", {}) click: "#sans-serif-fonts" store-value: (font, '"Fira Sans", sans-serif') @@ -23,8 +23,7 @@ assert-css: ("body", {"font-family": |font|}) assert-css: ("p code", {"font-family": |code_font|}) // We switch back to the serif font -click: "main .settings-menu" -wait-for: "#sans-serif-fonts" +call-function: ("open-settings-menu", {}) click: "#sans-serif-fonts" assert-css: ("body", {"font-family": |serif_font|}) diff --git a/tests/rustdoc-gui/notable-trait.goml b/tests/rustdoc-gui/notable-trait.goml index 6bd4661ac8f4..839988021fce 100644 --- a/tests/rustdoc-gui/notable-trait.goml +++ b/tests/rustdoc-gui/notable-trait.goml @@ -82,15 +82,15 @@ call-function: ("check-notable-tooltip-position", { "i_x": 528, }) +go-to: "file://" + |DOC_PATH| + "/test_docs/struct.NotableStructWithLongName.html" +// This is needed to ensure that the text color is computed. +show-text: true + // Now check the colors. define-function: ( "check-colors", [theme, header_color, content_color, type_color, trait_color, link_color], block { - go-to: "file://" + |DOC_PATH| + "/test_docs/struct.NotableStructWithLongName.html" - // This is needed to ensure that the text color is computed. - show-text: true - call-function: ("switch-theme", {"theme": |theme|}) assert-css: ( @@ -251,7 +251,6 @@ reload: assert-count: ("//*[@class='tooltip popover']", 0) click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" assert-count: ("//*[@class='tooltip popover']", 1) -click: "rustdoc-toolbar .settings-menu a" -wait-for: "#settings" +call-function: ("open-settings-menu", {}) assert-count: ("//*[@class='tooltip popover']", 0) assert-false: "#method\.create_an_iterator_from_read .tooltip:focus" diff --git a/tests/rustdoc-gui/search-filter.goml b/tests/rustdoc-gui/search-filter.goml index d92d522c119d..6bd7eaa92063 100644 --- a/tests/rustdoc-gui/search-filter.goml +++ b/tests/rustdoc-gui/search-filter.goml @@ -70,9 +70,7 @@ assert-css: ("#crate-search", { }) // We now check the dark theme. -click: "rustdoc-toolbar .settings-menu" -wait-for: "#settings" -click: "#theme-dark" +call-function: ("switch-theme", {"theme": "dark"}) wait-for-css: ("#crate-search", { "border": "1px solid #e0e0e0", "color": "#ddd", @@ -80,7 +78,7 @@ wait-for-css: ("#crate-search", { }) // And finally we check the ayu theme. -click: "#theme-ayu" +call-function: ("switch-theme", {"theme": "ayu"}) wait-for-css: ("#crate-search", { "border": "1px solid #5c6773", "color": "#c5c5c5", diff --git a/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml b/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml index 342bd726694e..dbf80ae34912 100644 --- a/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml +++ b/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml @@ -1,6 +1,8 @@ // This test ensures that the "Auto-hide item contents for large items" setting is working as // expected. +include: "utils.goml" + // We need to disable this check because `trait.impl/test_docs/trait.Iterator.js` doesn't exist. fail-on-request-error: false @@ -9,8 +11,7 @@ define-function: ( [storage_value, setting_attribute_value, toggle_attribute_value], block { assert-local-storage: {"rustdoc-auto-hide-large-items": |storage_value|} - click: "rustdoc-toolbar .settings-menu" - wait-for: "#settings" + call-function: ("open-settings-menu", {}) assert-property: ("#auto-hide-large-items", {"checked": |setting_attribute_value|}) assert-attribute: (".item-decl .type-contents-toggle", {"open": |toggle_attribute_value|}) } diff --git a/tests/rustdoc-gui/setting-auto-hide-item-methods-docs.goml b/tests/rustdoc-gui/setting-auto-hide-item-methods-docs.goml index 02d4ce8855fd..89c1a8b0e98e 100644 --- a/tests/rustdoc-gui/setting-auto-hide-item-methods-docs.goml +++ b/tests/rustdoc-gui/setting-auto-hide-item-methods-docs.goml @@ -1,13 +1,14 @@ // This test ensures that the "Auto-hide item methods' documentation" setting is working as // expected. +include: "utils.goml" + define-function: ( "check-setting", [storage_value, setting_attribute_value, toggle_attribute_value], block { assert-local-storage: {"rustdoc-auto-hide-method-docs": |storage_value|} - click: "rustdoc-toolbar .settings-menu" - wait-for: "#settings" + call-function: ("open-settings-menu", {}) assert-property: ("#auto-hide-method-docs", {"checked": |setting_attribute_value|}) assert-attribute: (".toggle.method-toggle", {"open": |toggle_attribute_value|}) } diff --git a/tests/rustdoc-gui/setting-auto-hide-trait-implementations.goml b/tests/rustdoc-gui/setting-auto-hide-trait-implementations.goml index 4af1e829b31c..81c26bfb7f3a 100644 --- a/tests/rustdoc-gui/setting-auto-hide-trait-implementations.goml +++ b/tests/rustdoc-gui/setting-auto-hide-trait-implementations.goml @@ -1,12 +1,13 @@ // Checks that the setting "auto hide trait implementations" is working as expected. +include: "utils.goml" + define-function: ( "check-setting", [storage_value, setting_attribute_value, toggle_attribute_value], block { assert-local-storage: {"rustdoc-auto-hide-trait-implementations": |storage_value|} - click: "rustdoc-toolbar .settings-menu" - wait-for: "#settings" + call-function: ("open-settings-menu", {}) assert-property: ("#auto-hide-trait-implementations", {"checked": |setting_attribute_value|}) assert-attribute: ("#trait-implementations-list > details", {"open": |toggle_attribute_value|}, ALL) } diff --git a/tests/rustdoc-gui/setting-go-to-only-result.goml b/tests/rustdoc-gui/setting-go-to-only-result.goml index 5a9c81e0b836..72c1e2bf59ca 100644 --- a/tests/rustdoc-gui/setting-go-to-only-result.goml +++ b/tests/rustdoc-gui/setting-go-to-only-result.goml @@ -1,12 +1,14 @@ -// Checks that the setting "Directly go to item in search if there is only one result " is working as expected. +// Checks that the setting "Directly go to item in search if there is only one result " is working +// as expected. + +include: "utils.goml" define-function: ( "check-setting", [storage_value, setting_attribute_value], block { assert-local-storage: {"rustdoc-go-to-only-result": |storage_value|} - click: "rustdoc-toolbar .settings-menu" - wait-for: "#settings" + call-function: ("open-settings-menu", {}) assert-property: ("#go-to-only-result", {"checked": |setting_attribute_value|}) } ) @@ -25,8 +27,7 @@ wait-for: "#search" assert-document-property: ({"URL": "/lib2/index.html"}, CONTAINS) // Now we change its value. -click: "rustdoc-toolbar .settings-menu" -wait-for: "#settings" +call-function: ("open-settings-menu", {}) click: "#go-to-only-result" assert-local-storage: {"rustdoc-go-to-only-result": "true"} diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml index 7a163103b5ab..85994be468d3 100644 --- a/tests/rustdoc-gui/settings.goml +++ b/tests/rustdoc-gui/settings.goml @@ -1,20 +1,18 @@ // This test ensures that the settings menu display is working as expected and that // the settings page is also rendered as expected. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" show-text: true // needed when we check for colors below. // First, we check that the settings page doesn't exist. assert-false: "#settings" -// We now click on the settings button. -click: "rustdoc-toolbar .settings-menu" -wait-for: "#settings" +call-function: ("open-settings-menu", {}) assert-css: ("#settings", {"display": "block"}) // Store the line margin to compare with the settings.html later. store-css: (".setting-line", {"margin": setting_line_margin}) // Let's close it by clicking on the same button. -click: "rustdoc-toolbar .settings-menu" -wait-for-css: ("#settings", {"display": "none"}) +call-function: ("close-settings-menu", {}) // Let's check that pressing "ESCAPE" is closing it. click: "rustdoc-toolbar .settings-menu" @@ -28,8 +26,7 @@ write: "test" // To be SURE that the search will be run. press-key: 'Enter' wait-for: "#alternative-display #search" -click: "rustdoc-toolbar .settings-menu" -wait-for-css: ("#settings", {"display": "block"}) +call-function: ("open-settings-menu", {}) // Ensure that the search is still displayed. wait-for: "#alternative-display #search" assert: "#main-content.hidden" @@ -41,8 +38,7 @@ set-local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false" // We reload the page so the local storage settings are being used. reload: -click: "rustdoc-toolbar .settings-menu" -wait-for: "#settings" +call-function: ("open-settings-menu", {}) // We check that the "Use system theme" is disabled. assert-property: ("#theme-system-preference", {"checked": "false"}) diff --git a/tests/rustdoc-gui/sidebar-mobile.goml b/tests/rustdoc-gui/sidebar-mobile.goml index 1fa5521baac9..3183650b555a 100644 --- a/tests/rustdoc-gui/sidebar-mobile.goml +++ b/tests/rustdoc-gui/sidebar-mobile.goml @@ -65,8 +65,7 @@ define-function: ( "check-colors", [theme, color, background], block { - call-function: ("switch-theme-mobile", {"theme": |theme|}) - reload: + call-function: ("switch-theme", {"theme": |theme|}) // Open the sidebar menu. click: ".sidebar-menu-toggle" @@ -86,13 +85,3 @@ call-function: ("check-colors", { "color": "#c5c5c5", "background": "#14191f", }) -call-function: ("check-colors", { - "theme": "dark", - "color": "#ddd", - "background": "#505050", -}) -call-function: ("check-colors", { - "theme": "light", - "color": "black", - "background": "#F5F5F5", -}) diff --git a/tests/rustdoc-gui/sidebar-resize-close-popover.goml b/tests/rustdoc-gui/sidebar-resize-close-popover.goml index d3fea9b0f400..ac8f7e9c65fa 100644 --- a/tests/rustdoc-gui/sidebar-resize-close-popover.goml +++ b/tests/rustdoc-gui/sidebar-resize-close-popover.goml @@ -1,9 +1,9 @@ // Checks sidebar resizing close the Settings popover +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" assert-property: (".sidebar", {"clientWidth": "199"}) show-text: true -click: "rustdoc-toolbar .settings-menu" -wait-for: "#settings" +call-function: ("open-settings-menu", {}) assert-css: ("#settings", {"display": "block"}) // normal resizing drag-and-drop: ((205, 100), (185, 100)) @@ -12,8 +12,7 @@ assert-css: ("#settings", {"display": "none"}) // Now same thing, but for source code go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html" -click: "rustdoc-toolbar .settings-menu" -wait-for: "#settings" +call-function: ("open-settings-menu", {}) assert-css: ("#settings", {"display": "block"}) assert-property: (".sidebar", {"clientWidth": "49"}) drag-and-drop: ((52, 100), (185, 100)) diff --git a/tests/rustdoc-gui/sidebar-resize-setting.goml b/tests/rustdoc-gui/sidebar-resize-setting.goml index a4572c670f81..132f5f387b29 100644 --- a/tests/rustdoc-gui/sidebar-resize-setting.goml +++ b/tests/rustdoc-gui/sidebar-resize-setting.goml @@ -1,11 +1,11 @@ // Checks sidebar resizing stays synced with the setting +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" assert-property: (".sidebar", {"clientWidth": "199"}) show-text: true // Verify that the "hide" option is unchecked -click: "rustdoc-toolbar .settings-menu" -wait-for: "#settings" +call-function: ("open-settings-menu", {}) assert-css: ("#settings", {"display": "block"}) assert-property: ("#hide-sidebar", {"checked": "false"}) press-key: "Escape" diff --git a/tests/rustdoc-gui/source-code-wrapping.goml b/tests/rustdoc-gui/source-code-wrapping.goml index c1fc2835c89a..6dc56672da80 100644 --- a/tests/rustdoc-gui/source-code-wrapping.goml +++ b/tests/rustdoc-gui/source-code-wrapping.goml @@ -1,4 +1,5 @@ // Checks that the interactions with the source code pages are working as expected. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html" show-text: true set-window-size: (1000, 1000) @@ -13,8 +14,7 @@ define-function: ( ) store-size: (".rust code", {"width": width, "height": height}) -click: "main .settings-menu" -wait-for: "#settings" +call-function: ("open-settings-menu", {}) call-function: ("click-code-wrapping", {"expected": "true"}) wait-for-size-false: (".rust code", {"width": |width|, "height": |height|}) store-size: (".rust code", {"width": new_width, "height": new_height}) @@ -28,8 +28,7 @@ assert-size: (".rust code", {"width": |width|, "height": |height|}) // Now let's check in docs code examples. go-to: "file://" + |DOC_PATH| + "/test_docs/trait_bounds/index.html" -click: "main .settings-menu" -wait-for: "#settings" +call-function: ("open-settings-menu", {}) store-property: (".example-wrap .rust code", {"scrollWidth": rust_width, "scrollHeight": rust_height}) store-property: (".example-wrap .language-text code", {"scrollWidth": txt_width, "scrollHeight": txt_height}) diff --git a/tests/rustdoc-gui/theme-change.goml b/tests/rustdoc-gui/theme-change.goml index 3860596e3433..14b32baac57e 100644 --- a/tests/rustdoc-gui/theme-change.goml +++ b/tests/rustdoc-gui/theme-change.goml @@ -7,8 +7,7 @@ store-value: (background_light, "white") store-value: (background_dark, "#353535") store-value: (background_ayu, "#0f1419") -click: "rustdoc-toolbar .settings-menu" -wait-for: "#theme-ayu" +call-function: ("open-settings-menu", {}) click: "#theme-ayu" // should be the ayu theme so let's check the color. wait-for-css: ("body", { "background-color": |background_ayu| }) @@ -22,10 +21,6 @@ click: "#theme-dark" wait-for-css: ("body", { "background-color": |background_dark| }) assert-local-storage: { "rustdoc-theme": "dark" } -set-local-storage: { - "rustdoc-preferred-light-theme": "light", - "rustdoc-preferred-dark-theme": "light", -} go-to: "file://" + |DOC_PATH| + "/settings.html" wait-for: "#settings" @@ -75,8 +70,7 @@ store-value: (background_dark, "#353535") store-value: (background_ayu, "#0f1419") store-value: (background_custom_theme, "red") -click: "rustdoc-toolbar .settings-menu" -wait-for: "#theme-ayu" +call-function: ("open-settings-menu", {}) click: "#theme-ayu" // should be the ayu theme so let's check the color. wait-for-css: ("body", { "background-color": |background_ayu| }) diff --git a/tests/rustdoc-gui/theme-defaults.goml b/tests/rustdoc-gui/theme-defaults.goml index 12c17166e874..b7ba64a4adaa 100644 --- a/tests/rustdoc-gui/theme-defaults.goml +++ b/tests/rustdoc-gui/theme-defaults.goml @@ -1,7 +1,7 @@ // Ensure that the theme picker always starts with the actual defaults. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" -click: "rustdoc-toolbar .settings-menu" -wait-for: "#theme-system-preference" +call-function: ("open-settings-menu", {}) assert: "#theme-system-preference:checked" assert: "#preferred-light-theme-light:checked" assert: "#preferred-dark-theme-dark:checked" @@ -16,8 +16,7 @@ set-local-storage: { "rustdoc-theme": "ayu" } go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" -click: "rustdoc-toolbar .settings-menu" -wait-for: "#theme-system-preference" +call-function: ("open-settings-menu", {}) assert: "#theme-system-preference:checked" assert: "#preferred-light-theme-light:checked" assert-false: "#preferred-dark-theme-dark:checked" diff --git a/tests/rustdoc-gui/utils.goml b/tests/rustdoc-gui/utils.goml index a40f9fc6fdd7..c0625ead2f1a 100644 --- a/tests/rustdoc-gui/utils.goml +++ b/tests/rustdoc-gui/utils.goml @@ -1,11 +1,35 @@ // This file contains code to be re-used by other tests. +define-function: ( + "click-settings-button", + [], + block { + store-count: ("rustdoc-topbar", __topbar_count) + store-value: (__topbar_display, "none") + // The `rustdoc-topbar` element is created with JS when the window size is below a given + // size, however if the window size gets bigger again, the element isn't deleted, just + // hidden, so we need to check for both that it exists and is visible. + if: (|__topbar_count| != 0, block { + store-css: ("rustdoc-topbar", {"display": __topbar_display}) + }) + + // Open the settings menu. + if: (|__topbar_display| != "none", block { + // In mobile mode, this is instead the "topbar" the settings button is located into. + click: "rustdoc-topbar .settings-menu" + }) + else: block { + // We're not in mobile mode so clicking on the "normal" sidebar. + click: "rustdoc-toolbar .settings-menu" + } + } +) + define-function: ( "open-settings-menu", [], block { - // Open the settings menu. - click: "rustdoc-toolbar .settings-menu" + call-function: ("click-settings-button", {}) // Wait for the popover to appear... wait-for-css: ("#settings", {"display": "block"}) } @@ -15,7 +39,8 @@ define-function: ( "close-settings-menu", [], block { - click: "rustdoc-toolbar .settings-menu" + call-function: ("click-settings-button", {}) + // Wait for the popover to disappear... wait-for-css-false: ("#settings", {"display": "block"}) } ) @@ -34,24 +59,6 @@ define-function: ( }, ) -// FIXME: To be removed once `browser-ui-test` has conditions. -define-function: ( - "switch-theme-mobile", - [theme], - block { - // Open the settings menu. - click: "rustdoc-topbar .settings-menu" - // Wait for the popover to appear... - wait-for-css: ("#settings", {"display": "block"}) - // Change the setting. - click: "#theme-"+ |theme| - click: "rustdoc-topbar .settings-menu" - wait-for-css-false: ("#settings", {"display": "block"}) - // Ensure that the local storage was correctly updated. - assert-local-storage: {"rustdoc-theme": |theme|} - }, -) - define-function: ( "perform-search", [query], From 5466c6b25506f16fb6f030481d0e02a180c54a07 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Thu, 8 Jan 2026 14:48:56 -0600 Subject: [PATCH 0437/1061] Move feature(multiple_supertrait_upcastable) to the actual feature gates section (from the internal feature gates section) and give it a tracking issue. --- compiler/rustc_feature/src/unstable.rs | 4 ++-- .../feature-gate-multiple_supertrait_upcastable.stderr | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 387a01967ae5..8959bc586af7 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -233,8 +233,6 @@ declare_features! ( (internal, link_cfg, "1.14.0", None), /// Allows using `?Trait` trait bounds in more contexts. (internal, more_maybe_bounds, "1.82.0", None), - /// Allows the `multiple_supertrait_upcastable` lint. - (unstable, multiple_supertrait_upcastable, "1.69.0", None), /// Allow negative trait bounds. This is an internal-only feature for testing the trait solver! (internal, negative_bounds, "1.71.0", None), /// Set the maximum pattern complexity allowed (not limited by default). @@ -569,6 +567,8 @@ declare_features! ( (unstable, more_qualified_paths, "1.54.0", Some(86935)), /// The `movrs` target feature on x86. (unstable, movrs_target_feature, "1.88.0", Some(137976)), + /// Allows the `multiple_supertrait_upcastable` lint. + (unstable, multiple_supertrait_upcastable, "1.69.0", Some(150833)), /// Allows the `#[must_not_suspend]` attribute. (unstable, must_not_suspend, "1.57.0", Some(83310)), /// Allows `mut ref` and `mut ref mut` identifier patterns. diff --git a/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.stderr b/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.stderr index 0c7e68a599cd..0fd987e40289 100644 --- a/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.stderr +++ b/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.stderr @@ -5,6 +5,7 @@ LL | #![deny(multiple_supertrait_upcastable)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the `multiple_supertrait_upcastable` lint is unstable + = note: see issue #150833 for more information = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: `#[warn(unknown_lints)]` on by default @@ -16,6 +17,7 @@ LL | #![warn(multiple_supertrait_upcastable)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the `multiple_supertrait_upcastable` lint is unstable + = note: see issue #150833 for more information = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date From 291d0a9a4b175b61b7c499551751ad5023b38bbc Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Tue, 6 Jan 2026 16:08:10 -0500 Subject: [PATCH 0438/1061] diagnostics: make implicit Sized bounds explicit in E0277 When a trait parameter depends upon Sized, the error message only referred to the full trait itself and didn't mention Sized. This makes the failure to implement Sized explicit. It also notes when the Sized trait bound is explicit or implicit. --- .../src/error_reporting/traits/suggestions.rs | 57 +++++++++++--- .../substs-ppaux.normal.stderr | 2 +- .../substs-ppaux.verbose.stderr | 2 +- tests/ui/error-codes/E0277-4.rs | 50 ++++++++++++ tests/ui/error-codes/E0277-4.stderr | 77 +++++++++++++++++++ tests/ui/recursion/issue-23122-2.stderr | 2 +- tests/ui/suggestions/slice-issue-87994.stderr | 10 +-- ...-iterator-deref-in-for-loop.current.stderr | 4 +- ...dyn-iterator-deref-in-for-loop.next.stderr | 4 +- tests/ui/traits/issue-18400.stderr | 2 +- 10 files changed, 186 insertions(+), 24 deletions(-) create mode 100644 tests/ui/error-codes/E0277-4.rs create mode 100644 tests/ui/error-codes/E0277-4.stderr diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 511e9e85b5f6..08a3fd4a0bb3 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -1391,25 +1391,45 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // return early in the caller. let mut label = || { + // Special case `Sized` as `old_pred` will be the trait itself instead of + // `Sized` when the trait bound is the source of the error. + let is_sized = match obligation.predicate.kind().skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => { + self.tcx.is_lang_item(trait_pred.def_id(), LangItem::Sized) + } + _ => false, + }; + let msg = format!( "the trait bound `{}` is not satisfied", self.tcx.short_string(old_pred, err.long_ty_path()), ); - let self_ty_str = - self.tcx.short_string(old_pred.self_ty().skip_binder(), err.long_ty_path()); + let self_ty_str = self.tcx.short_string(old_pred.self_ty(), err.long_ty_path()); let trait_path = self .tcx .short_string(old_pred.print_modifiers_and_trait_path(), err.long_ty_path()); if has_custom_message { + let msg = if is_sized { + "the trait bound `Sized` is not satisfied".into() + } else { + msg + }; err.note(msg); } else { err.messages = vec![(rustc_errors::DiagMessage::from(msg), Style::NoStyle)]; } - err.span_label( - span, - format!("the trait `{trait_path}` is not implemented for `{self_ty_str}`"), - ); + if is_sized { + err.span_label( + span, + format!("the trait `Sized` is not implemented for `{self_ty_str}`"), + ); + } else { + err.span_label( + span, + format!("the trait `{trait_path}` is not implemented for `{self_ty_str}`"), + ); + } }; let mut sugg_prefixes = vec![]; @@ -3578,10 +3598,27 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { "unsatisfied trait bound introduced in this `derive` macro", ); } else if !data.span.is_dummy() && !data.span.overlaps(self_ty.span) { - spans.push_span_label( - data.span, - "unsatisfied trait bound introduced here", - ); + // `Sized` may be an explicit or implicit trait bound. If it is + // implicit, mention it as such. + if let Some(pred) = predicate.as_trait_clause() + && self.tcx.is_lang_item(pred.def_id(), LangItem::Sized) + && self + .tcx + .generics_of(data.impl_or_alias_def_id) + .own_params + .iter() + .any(|param| self.tcx.def_span(param.def_id) == data.span) + { + spans.push_span_label( + data.span, + "unsatisfied trait bound implicitly introduced here", + ); + } else { + spans.push_span_label( + data.span, + "unsatisfied trait bound introduced here", + ); + } } err.span_note(spans, msg); point_at_assoc_type_restriction( diff --git a/tests/ui/associated-types/substs-ppaux.normal.stderr b/tests/ui/associated-types/substs-ppaux.normal.stderr index aa2aca7426e1..b1c9ce3f22b6 100644 --- a/tests/ui/associated-types/substs-ppaux.normal.stderr +++ b/tests/ui/associated-types/substs-ppaux.normal.stderr @@ -88,7 +88,7 @@ note: required for `str` to implement `Foo<'_, '_, u8>` LL | impl<'a, 'b, T, S> Foo<'a, 'b, S> for T {} | - ^^^^^^^^^^^^^^ ^ | | - | unsatisfied trait bound introduced here + | unsatisfied trait bound implicitly introduced here error: aborting due to 5 previous errors diff --git a/tests/ui/associated-types/substs-ppaux.verbose.stderr b/tests/ui/associated-types/substs-ppaux.verbose.stderr index 23cf222a1d37..46cae5db56fd 100644 --- a/tests/ui/associated-types/substs-ppaux.verbose.stderr +++ b/tests/ui/associated-types/substs-ppaux.verbose.stderr @@ -88,7 +88,7 @@ note: required for `str` to implement `Foo<'?0, '?1, u8>` LL | impl<'a, 'b, T, S> Foo<'a, 'b, S> for T {} | - ^^^^^^^^^^^^^^ ^ | | - | unsatisfied trait bound introduced here + | unsatisfied trait bound implicitly introduced here error: aborting due to 5 previous errors diff --git a/tests/ui/error-codes/E0277-4.rs b/tests/ui/error-codes/E0277-4.rs new file mode 100644 index 000000000000..ead57f00dde5 --- /dev/null +++ b/tests/ui/error-codes/E0277-4.rs @@ -0,0 +1,50 @@ +use std::fmt::Display; + +trait ImplicitTrait { + fn foo(&self); +} + +trait ExplicitTrait { + fn foo(&self); +} + +trait DisplayTrait { + fn foo(&self); +} + +trait UnimplementedTrait { + fn foo(&self); +} + +// Implicitly requires `T: Sized`. +impl ImplicitTrait for T { + fn foo(&self) {} +} + +// Explicitly requires `T: Sized`. +impl ExplicitTrait for T { + fn foo(&self) {} +} + +// Requires `T: Display`. +impl DisplayTrait for T { + fn foo(&self) {} +} + +fn main() { + // `[u8]` does not implement `Sized`. + let x: &[u8] = &[]; + ImplicitTrait::foo(x); + //~^ ERROR: the trait bound `[u8]: ImplicitTrait` is not satisfied [E0277] + ExplicitTrait::foo(x); + //~^ ERROR: the trait bound `[u8]: ExplicitTrait` is not satisfied [E0277] + + // `UnimplementedTrait` has no implementations. + UnimplementedTrait::foo(x); + //~^ ERROR: the trait bound `[u8]: UnimplementedTrait` is not satisfied [E0277] + + // `[u8; 0]` implements `Sized` but not `Display`. + let x: &[u8; 0] = &[]; + DisplayTrait::foo(x); + //~^ ERROR: the trait bound `[u8; 0]: DisplayTrait` is not satisfied [E0277] +} diff --git a/tests/ui/error-codes/E0277-4.stderr b/tests/ui/error-codes/E0277-4.stderr new file mode 100644 index 000000000000..f38b8146a63d --- /dev/null +++ b/tests/ui/error-codes/E0277-4.stderr @@ -0,0 +1,77 @@ +error[E0277]: the trait bound `[u8]: ImplicitTrait` is not satisfied + --> $DIR/E0277-4.rs:37:24 + | +LL | ImplicitTrait::foo(x); + | ------------------ ^ the trait `Sized` is not implemented for `[u8]` + | | + | required by a bound introduced by this call + | +note: required for `[u8]` to implement `ImplicitTrait` + --> $DIR/E0277-4.rs:20:9 + | +LL | impl ImplicitTrait for T { + | - ^^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound implicitly introduced here +help: consider borrowing here + | +LL | ImplicitTrait::foo(&x); + | + +LL | ImplicitTrait::foo(&mut x); + | ++++ + +error[E0277]: the trait bound `[u8]: ExplicitTrait` is not satisfied + --> $DIR/E0277-4.rs:39:24 + | +LL | ExplicitTrait::foo(x); + | ------------------ ^ the trait `Sized` is not implemented for `[u8]` + | | + | required by a bound introduced by this call + | +note: required for `[u8]` to implement `ExplicitTrait` + --> $DIR/E0277-4.rs:25:16 + | +LL | impl ExplicitTrait for T { + | ----- ^^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here +help: consider borrowing here + | +LL | ExplicitTrait::foo(&x); + | + +LL | ExplicitTrait::foo(&mut x); + | ++++ + +error[E0277]: the trait bound `[u8]: UnimplementedTrait` is not satisfied + --> $DIR/E0277-4.rs:43:29 + | +LL | UnimplementedTrait::foo(x); + | ----------------------- ^ the trait `UnimplementedTrait` is not implemented for `[u8]` + | | + | required by a bound introduced by this call + | +help: this trait has no implementations, consider adding one + --> $DIR/E0277-4.rs:15:1 + | +LL | trait UnimplementedTrait { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `[u8; 0]: DisplayTrait` is not satisfied + --> $DIR/E0277-4.rs:48:23 + | +LL | DisplayTrait::foo(x); + | ----------------- ^ the trait `std::fmt::Display` is not implemented for `[u8; 0]` + | | + | required by a bound introduced by this call + | +note: required for `[u8; 0]` to implement `DisplayTrait` + --> $DIR/E0277-4.rs:30:18 + | +LL | impl DisplayTrait for T { + | ------- ^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/recursion/issue-23122-2.stderr b/tests/ui/recursion/issue-23122-2.stderr index de402d65e6d6..39cd0eb35a63 100644 --- a/tests/ui/recursion/issue-23122-2.stderr +++ b/tests/ui/recursion/issue-23122-2.stderr @@ -11,7 +11,7 @@ note: required for `GetNext<<<<... as Next>::Next as Next>::Next as Next>::Next> LL | impl Next for GetNext { | - ^^^^ ^^^^^^^^^^ | | - | unsatisfied trait bound introduced here + | unsatisfied trait bound implicitly introduced here = note: the full name for the type has been written to '$TEST_BUILD_DIR/issue-23122-2.long-type-$LONG_TYPE_HASH.txt' = note: consider using `--verbose` to print the full type name to the console diff --git a/tests/ui/suggestions/slice-issue-87994.stderr b/tests/ui/suggestions/slice-issue-87994.stderr index 22ad5d352120..dd5c00af90b2 100644 --- a/tests/ui/suggestions/slice-issue-87994.stderr +++ b/tests/ui/suggestions/slice-issue-87994.stderr @@ -17,11 +17,10 @@ error[E0277]: `[i32]` is not an iterator --> $DIR/slice-issue-87994.rs:3:12 | LL | for _ in v[1..] { - | ^^^^^^ the trait `IntoIterator` is not implemented for `[i32]` + | ^^^^^^ the trait `Sized` is not implemented for `[i32]` | - = note: the trait bound `[i32]: IntoIterator` is not satisfied + = note: the trait bound `Sized` is not satisfied = note: required for `[i32]` to implement `IntoIterator` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider borrowing here | LL | for _ in &v[1..] { @@ -48,11 +47,10 @@ error[E0277]: `[K]` is not an iterator --> $DIR/slice-issue-87994.rs:11:13 | LL | for i2 in v2[1..] { - | ^^^^^^^ the trait `IntoIterator` is not implemented for `[K]` + | ^^^^^^^ the trait `Sized` is not implemented for `[K]` | - = note: the trait bound `[K]: IntoIterator` is not satisfied + = note: the trait bound `Sized` is not satisfied = note: required for `[K]` to implement `IntoIterator` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider borrowing here | LL | for i2 in &v2[1..] { diff --git a/tests/ui/traits/dyn-iterator-deref-in-for-loop.current.stderr b/tests/ui/traits/dyn-iterator-deref-in-for-loop.current.stderr index b5a9b82a93a3..0dd2ffffdfea 100644 --- a/tests/ui/traits/dyn-iterator-deref-in-for-loop.current.stderr +++ b/tests/ui/traits/dyn-iterator-deref-in-for-loop.current.stderr @@ -2,9 +2,9 @@ error[E0277]: `dyn Iterator` is not an iterator --> $DIR/dyn-iterator-deref-in-for-loop.rs:9:17 | LL | for item in *things { - | ^^^^^^^ the trait `IntoIterator` is not implemented for `dyn Iterator` + | ^^^^^^^ the trait `Sized` is not implemented for `dyn Iterator` | - = note: the trait bound `dyn Iterator: IntoIterator` is not satisfied + = note: the trait bound `Sized` is not satisfied = note: required for `dyn Iterator` to implement `IntoIterator` help: consider mutably borrowing here | diff --git a/tests/ui/traits/dyn-iterator-deref-in-for-loop.next.stderr b/tests/ui/traits/dyn-iterator-deref-in-for-loop.next.stderr index b5a9b82a93a3..0dd2ffffdfea 100644 --- a/tests/ui/traits/dyn-iterator-deref-in-for-loop.next.stderr +++ b/tests/ui/traits/dyn-iterator-deref-in-for-loop.next.stderr @@ -2,9 +2,9 @@ error[E0277]: `dyn Iterator` is not an iterator --> $DIR/dyn-iterator-deref-in-for-loop.rs:9:17 | LL | for item in *things { - | ^^^^^^^ the trait `IntoIterator` is not implemented for `dyn Iterator` + | ^^^^^^^ the trait `Sized` is not implemented for `dyn Iterator` | - = note: the trait bound `dyn Iterator: IntoIterator` is not satisfied + = note: the trait bound `Sized` is not satisfied = note: required for `dyn Iterator` to implement `IntoIterator` help: consider mutably borrowing here | diff --git a/tests/ui/traits/issue-18400.stderr b/tests/ui/traits/issue-18400.stderr index 146ba16397a2..af5519a15c23 100644 --- a/tests/ui/traits/issue-18400.stderr +++ b/tests/ui/traits/issue-18400.stderr @@ -11,7 +11,7 @@ note: required for `{integer}` to implement `Set<&[_]>` LL | impl<'a, T, S> Set<&'a [T]> for S where | - ^^^^^^^^^^^^ ^ | | - | unsatisfied trait bound introduced here + | unsatisfied trait bound implicitly introduced here = note: 128 redundant requirements hidden = note: required for `{integer}` to implement `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` From 2b618ed6da5f0e55b2c00e32c767ba3dec6d7951 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Fri, 2 Jan 2026 00:57:49 -0800 Subject: [PATCH 0439/1061] rustdoc: Correctly resolve variant and struct fields on alias --- .../passes/collect_intra_doc_links.rs | 86 +++++++++++++------ .../intra-doc/adt-through-alias.rs | 54 +++++++++++- .../intra-doc/associated-items.rs | 9 +- 3 files changed, 113 insertions(+), 36 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 553d8636c85b..9e86781224d3 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -462,7 +462,7 @@ fn full_res(tcx: TyCtxt<'_>, (base, assoc_item): (Res, Option)) -> Res { } /// Given a primitive type, try to resolve an associated item. -fn resolve_primitive_associated_item<'tcx>( +fn resolve_primitive_inherent_assoc_item<'tcx>( tcx: TyCtxt<'tcx>, prim_ty: PrimitiveType, ns: Namespace, @@ -597,33 +597,30 @@ fn resolve_associated_item<'tcx>( let item_ident = Ident::with_dummy_span(item_name); match root_res { - Res::Primitive(prim) => { - let items = resolve_primitive_associated_item(tcx, prim, ns, item_ident); - if !items.is_empty() { - items - // Inherent associated items take precedence over items that come from trait impls. - } else { - primitive_type_to_ty(tcx, prim) - .map(|ty| { - resolve_associated_trait_item(ty, module_id, item_ident, ns, tcx) - .iter() - .map(|item| (root_res, item.def_id)) - .collect::>() - }) - .unwrap_or_default() - } - } - Res::Def(DefKind::TyAlias, did) => { + Res::Def(DefKind::TyAlias, alias_did) => { // Resolve the link on the type the alias points to. // FIXME: if the associated item is defined directly on the type alias, // it will show up on its documentation page, we should link there instead. - let Some(res) = ty_to_res(tcx, tcx.type_of(did).instantiate_identity()) else { - return Vec::new(); + let Some(aliased_res) = ty_to_res(tcx, tcx.type_of(alias_did).instantiate_identity()) + else { + return vec![]; }; - resolve_associated_item(tcx, res, item_name, ns, disambiguator, module_id) + let aliased_items = + resolve_associated_item(tcx, aliased_res, item_name, ns, disambiguator, module_id); + aliased_items + .into_iter() + .map(|(res, assoc_did)| { + if is_assoc_item_on_alias_page(tcx, assoc_did) { + (root_res, assoc_did) + } else { + (res, assoc_did) + } + }) + .collect() } + Res::Primitive(prim) => resolve_assoc_on_primitive(tcx, prim, ns, item_ident, module_id), Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum, did) => { - resolve_assoc_on_adt(tcx, did, item_name, ns, disambiguator, module_id) + resolve_assoc_on_adt(tcx, did, item_ident, ns, disambiguator, module_id) } Res::Def(DefKind::ForeignTy, did) => { resolve_assoc_on_simple_type(tcx, did, item_ident, ns, module_id) @@ -640,23 +637,56 @@ fn resolve_associated_item<'tcx>( } } +// FIXME: make this fully complete by also including ALL inherent impls +// and trait impls BUT ONLY if on alias directly +fn is_assoc_item_on_alias_page<'tcx>(tcx: TyCtxt<'tcx>, assoc_did: DefId) -> bool { + match tcx.def_kind(assoc_did) { + // Variants and fields always have docs on the alias page. + DefKind::Variant | DefKind::Field => true, + _ => false, + } +} + +fn resolve_assoc_on_primitive<'tcx>( + tcx: TyCtxt<'tcx>, + prim: PrimitiveType, + ns: Namespace, + item_ident: Ident, + module_id: DefId, +) -> Vec<(Res, DefId)> { + let root_res = Res::Primitive(prim); + let items = resolve_primitive_inherent_assoc_item(tcx, prim, ns, item_ident); + if !items.is_empty() { + items + // Inherent associated items take precedence over items that come from trait impls. + } else { + primitive_type_to_ty(tcx, prim) + .map(|ty| { + resolve_associated_trait_item(ty, module_id, item_ident, ns, tcx) + .iter() + .map(|item| (root_res, item.def_id)) + .collect::>() + }) + .unwrap_or_default() + } +} + fn resolve_assoc_on_adt<'tcx>( tcx: TyCtxt<'tcx>, adt_def_id: DefId, - item_name: Symbol, + item_ident: Ident, ns: Namespace, disambiguator: Option, module_id: DefId, ) -> Vec<(Res, DefId)> { - debug!("looking for associated item named {item_name} for item {adt_def_id:?}"); + debug!("looking for associated item named {item_ident} for item {adt_def_id:?}"); let root_res = Res::from_def_id(tcx, adt_def_id); let adt_ty = tcx.type_of(adt_def_id).instantiate_identity(); let adt_def = adt_ty.ty_adt_def().expect("must be ADT"); - let item_ident = Ident::with_dummy_span(item_name); // Checks if item_name is a variant of the `SomeItem` enum if ns == TypeNS && adt_def.is_enum() { for variant in adt_def.variants() { - if variant.name == item_name { + if variant.name == item_ident.name { return vec![(root_res, variant.def_id)]; } } @@ -665,7 +695,7 @@ fn resolve_assoc_on_adt<'tcx>( if let Some(Disambiguator::Kind(DefKind::Field)) = disambiguator && (adt_def.is_struct() || adt_def.is_union()) { - return resolve_structfield(adt_def, item_name) + return resolve_structfield(adt_def, item_ident.name) .into_iter() .map(|did| (root_res, did)) .collect(); @@ -677,7 +707,7 @@ fn resolve_assoc_on_adt<'tcx>( } if ns == Namespace::ValueNS && (adt_def.is_struct() || adt_def.is_union()) { - return resolve_structfield(adt_def, item_name) + return resolve_structfield(adt_def, item_ident.name) .into_iter() .map(|did| (root_res, did)) .collect(); diff --git a/tests/rustdoc-html/intra-doc/adt-through-alias.rs b/tests/rustdoc-html/intra-doc/adt-through-alias.rs index 58e0f37edbab..6d5454bbaf20 100644 --- a/tests/rustdoc-html/intra-doc/adt-through-alias.rs +++ b/tests/rustdoc-html/intra-doc/adt-through-alias.rs @@ -3,12 +3,35 @@ //! [`TheStructAlias::the_field`] //! [`TheEnumAlias::TheVariant`] //! [`TheEnumAlias::TheVariant::the_field`] +//! [`TheUnionAlias::f1`] +//! +//! [`TheStruct::trait_`] +//! [`TheStructAlias::trait_`] +//! [`TheEnum::trait_`] +//! [`TheEnumAlias::trait_`] +//! +//! [`TheStruct::inherent`] +//! [`TheStructAlias::inherent`] +//! [`TheEnum::inherent`] +//! [`TheEnumAlias::inherent`] -// FIXME: this should resolve to the alias's version -//@ has foo/index.html '//a[@href="struct.TheStruct.html#structfield.the_field"]' 'TheStructAlias::the_field' -// FIXME: this should resolve to the alias's version -//@ has foo/index.html '//a[@href="enum.TheEnum.html#variant.TheVariant"]' 'TheEnumAlias::TheVariant' +//@ has foo/index.html '//a[@href="type.TheStructAlias.html#structfield.the_field"]' 'TheStructAlias::the_field' +//@ has foo/index.html '//a[@href="type.TheEnumAlias.html#variant.TheVariant"]' 'TheEnumAlias::TheVariant' //@ has foo/index.html '//a[@href="type.TheEnumAlias.html#variant.TheVariant.field.the_field"]' 'TheEnumAlias::TheVariant::the_field' +//@ has foo/index.html '//a[@href="type.TheUnionAlias.html#structfield.f1"]' 'TheUnionAlias::f1' + +//@ has foo/index.html '//a[@href="struct.TheStruct.html#method.trait_"]' 'TheStruct::trait_' +//@ has foo/index.html '//a[@href="struct.TheStruct.html#method.trait_"]' 'TheStructAlias::trait_' +//@ has foo/index.html '//a[@href="enum.TheEnum.html#method.trait_"]' 'TheEnum::trait_' +// FIXME: this one should resolve to alias since it's impl Trait for TheEnumAlias +//@ has foo/index.html '//a[@href="enum.TheEnum.html#method.trait_"]' 'TheEnumAlias::trait_' + +//@ has foo/index.html '//a[@href="struct.TheStruct.html#method.inherent"]' 'TheStruct::inherent' +// FIXME: this one should resolve to alias +//@ has foo/index.html '//a[@href="struct.TheStruct.html#method.inherent"]' 'TheStructAlias::inherent' +//@ has foo/index.html '//a[@href="enum.TheEnum.html#method.inherent"]' 'TheEnum::inherent' +// FIXME: this one should resolve to alias +//@ has foo/index.html '//a[@href="enum.TheEnum.html#method.inherent"]' 'TheEnumAlias::inherent' pub struct TheStruct { pub the_field: i32, @@ -22,4 +45,27 @@ pub enum TheEnum { pub type TheEnumAlias = TheEnum; +pub trait Trait { + fn trait_() {} +} + +impl Trait for TheStruct {} + +impl Trait for TheEnumAlias {} + +impl TheStruct { + pub fn inherent() {} +} + +impl TheEnumAlias { + pub fn inherent() {} +} + +pub union TheUnion { + pub f1: usize, + pub f2: isize, +} + +pub type TheUnionAlias = TheUnion; + fn main() {} diff --git a/tests/rustdoc-html/intra-doc/associated-items.rs b/tests/rustdoc-html/intra-doc/associated-items.rs index 84cfd06111df..b3bed196aded 100644 --- a/tests/rustdoc-html/intra-doc/associated-items.rs +++ b/tests/rustdoc-html/intra-doc/associated-items.rs @@ -13,7 +13,9 @@ pub fn foo() {} //@ has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#method.method"]' 'link from struct' //@ has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#method.clone"]' 'MyStruct::clone' //@ has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#associatedtype.Input"]' 'MyStruct::Input' -pub struct MyStruct { foo: () } +pub struct MyStruct { + foo: (), +} impl Clone for MyStruct { fn clone(&self) -> Self { @@ -31,8 +33,7 @@ impl T for MyStruct { /// [link from method][MyStruct::method] on method //@ has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#method.method"]' 'link from method' - fn method(i: usize) { - } + fn method(i: usize) {} } /// Ambiguity between which trait to use @@ -57,7 +58,7 @@ impl T2 for S { fn ambiguous_method() {} } -//@ has associated_items/enum.MyEnum.html '//a/@href' 'enum.MyEnum.html#variant.MyVariant' +//@ has associated_items/enum.MyEnum.html '//a/@href' 'type.MyEnumAlias.html#variant.MyVariant' /// Link to [MyEnumAlias::MyVariant] pub enum MyEnum { MyVariant, From d0d725133fb501ffb9f4572d2ea59454e68bb75a Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Thu, 8 Jan 2026 21:08:15 +0100 Subject: [PATCH 0440/1061] clean-up --- clippy_lints/src/floating_point_arithmetic.rs | 202 +++++++++--------- 1 file changed, 101 insertions(+), 101 deletions(-) diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 5f022ba307ff..0a8f6c6ebf6b 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -1,6 +1,6 @@ use clippy_utils::consts::Constant::{F32, F64, Int}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; use clippy_utils::{ eq_expr_value, get_parent_expr, has_ambiguous_literal_in_expr, higher, is_in_const_context, is_no_std_crate, @@ -128,16 +128,16 @@ fn get_specialized_log_method(cx: &LateContext<'_>, base: &Expr<'_>, ctxt: Synta // Adds type suffixes and parenthesis to method receivers if necessary fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Sugg<'a> { - let mut suggestion = Sugg::hir(cx, expr, ".."); + let mut suggestion = Sugg::hir(cx, expr, "_"); - if let ExprKind::Unary(UnOp::Neg, inner_expr) = &expr.kind { + if let ExprKind::Unary(UnOp::Neg, inner_expr) = expr.kind { expr = inner_expr; } if let ty::Float(float_ty) = cx.typeck_results().expr_ty(expr).kind() // if the expression is a float literal and it is unsuffixed then // add a suffix so the suggestion is valid and unambiguous - && let ExprKind::Lit(lit) = &expr.kind + && let ExprKind::Lit(lit) = expr.kind && let ast::LitKind::Float(sym, ast::LitFloatType::Unsuffixed) = lit.node { let op = format!( @@ -166,7 +166,7 @@ fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, ar expr.span, "logarithm for bases 2, 10 and e can be computed more accurately", "consider using", - format!("{}.{method}()", Sugg::hir(cx, receiver, "..").maybe_paren()), + format!("{}.{method}()", Sugg::hir(cx, receiver, "_").maybe_paren()), Applicability::MachineApplicable, ); } @@ -251,25 +251,25 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: // Check argument if let Some(value) = ConstEvalCtxt::new(cx).eval(&args[0]) { + let recv = Sugg::hir(cx, receiver, "_").maybe_paren(); let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value { ( SUBOPTIMAL_FLOPS, "square-root of a number can be computed more efficiently and accurately", - format!("{}.sqrt()", Sugg::hir(cx, receiver, "..").maybe_paren()), + format!("{recv}.sqrt()"), ) } else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value { ( IMPRECISE_FLOPS, "cube-root of a number can be computed more accurately", - format!("{}.cbrt()", Sugg::hir(cx, receiver, "..").maybe_paren()), + format!("{recv}.cbrt()"), ) } else if let Some(exponent) = get_integer_from_float_constant(&value) { ( SUBOPTIMAL_FLOPS, "exponentiation with integer powers can be computed more efficiently", format!( - "{}.powi({})", - Sugg::hir(cx, receiver, "..").maybe_paren(), + "{recv}.powi({})", numeric_literal::format(&exponent.to_string(), None, false) ), ) @@ -311,31 +311,36 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: rhs, ) = parent.kind { - let other_addend = if lhs.hir_id == expr.hir_id { rhs } else { lhs }; - - // Negate expr if original code has subtraction and expr is on the right side - let maybe_neg_sugg = |expr, hir_id| { - let sugg = Sugg::hir(cx, expr, ".."); - if matches!(op, BinOpKind::Sub) && hir_id == rhs.hir_id { - -sugg - } else { - sugg - } - }; - - span_lint_and_sugg( + span_lint_and_then( cx, SUBOPTIMAL_FLOPS, parent.span, "multiply and add expressions can be calculated more efficiently and accurately", - "consider using", - format!( - "{}.mul_add({}, {})", - Sugg::hir(cx, receiver, "..").maybe_paren(), - maybe_neg_sugg(receiver, expr.hir_id), - maybe_neg_sugg(other_addend, other_addend.hir_id), - ), - Applicability::MachineApplicable, + |diag| { + let other_addend = if lhs.hir_id == expr.hir_id { rhs } else { lhs }; + + // Negate expr if original code has subtraction and expr is on the right side + let maybe_neg_sugg = |expr, hir_id| { + let sugg = Sugg::hir(cx, expr, "_"); + if matches!(op, BinOpKind::Sub) && hir_id == rhs.hir_id { + -sugg + } else { + sugg + } + }; + + diag.span_suggestion( + parent.span, + "consider using", + format!( + "{}.mul_add({}, {})", + Sugg::hir(cx, receiver, "_").maybe_paren(), + maybe_neg_sugg(receiver, expr.hir_id), + maybe_neg_sugg(other_addend, other_addend.hir_id), + ), + Applicability::MachineApplicable, + ); + }, ); } } @@ -370,14 +375,14 @@ fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option { { return Some(format!( "{}.hypot({})", - Sugg::hir(cx, lmul_lhs, "..").maybe_paren(), - Sugg::hir(cx, rmul_lhs, "..") + Sugg::hir(cx, lmul_lhs, "_").maybe_paren(), + Sugg::hir(cx, rmul_lhs, "_") )); } // check if expression of the form x.powi(2) + y.powi(2) - if let ExprKind::MethodCall(PathSegment { ident: lmethod, .. }, largs_0, [largs_1, ..], _) = &add_lhs.kind - && let ExprKind::MethodCall(PathSegment { ident: rmethod, .. }, rargs_0, [rargs_1, ..], _) = &add_rhs.kind + if let ExprKind::MethodCall(PathSegment { ident: lmethod, .. }, largs_0, [largs_1, ..], _) = add_lhs.kind + && let ExprKind::MethodCall(PathSegment { ident: rmethod, .. }, rargs_0, [rargs_1, ..], _) = add_rhs.kind && lmethod.name == sym::powi && rmethod.name == sym::powi && let ecx = ConstEvalCtxt::new(cx) @@ -388,8 +393,8 @@ fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option { { return Some(format!( "{}.hypot({})", - Sugg::hir(cx, largs_0, "..").maybe_paren(), - Sugg::hir(cx, rargs_0, "..") + Sugg::hir(cx, largs_0, "_").maybe_paren(), + Sugg::hir(cx, rargs_0, "_") )); } } @@ -421,7 +426,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) { lhs, rhs, ) = expr.kind - && let ExprKind::MethodCall(path, self_arg, [], _) = &lhs.kind + && let ExprKind::MethodCall(path, self_arg, [], _) = lhs.kind && path.ident.name == sym::exp && cx.typeck_results().expr_ty(lhs).is_floating_point() && let Some(value) = ConstEvalCtxt::new(cx).eval(rhs) @@ -434,7 +439,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) { expr.span, "(e.pow(x) - 1) can be computed more accurately", "consider using", - format!("{}.exp_m1()", Sugg::hir(cx, self_arg, "..").maybe_paren()), + format!("{}.exp_m1()", Sugg::hir(cx, self_arg, "_").maybe_paren()), Applicability::MachineApplicable, ); } @@ -447,7 +452,7 @@ fn is_float_mul_expr<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(&' }, lhs, rhs, - ) = &expr.kind + ) = expr.kind && cx.typeck_results().expr_ty(lhs).is_floating_point() && cx.typeck_results().expr_ty(rhs).is_floating_point() { @@ -476,18 +481,18 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) { } let maybe_neg_sugg = |expr| { - let sugg = Sugg::hir(cx, expr, ".."); + let sugg = Sugg::hir(cx, expr, "_"); if let BinOpKind::Sub = op { -sugg } else { sugg } }; let (recv, arg1, arg2) = if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, lhs) && cx.typeck_results().expr_ty(rhs).is_floating_point() { - (inner_lhs, Sugg::hir(cx, inner_rhs, ".."), maybe_neg_sugg(rhs)) + (inner_lhs, Sugg::hir(cx, inner_rhs, "_"), maybe_neg_sugg(rhs)) } else if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, rhs) && cx.typeck_results().expr_ty(lhs).is_floating_point() { - (inner_lhs, maybe_neg_sugg(inner_rhs), Sugg::hir(cx, lhs, "..")) + (inner_lhs, maybe_neg_sugg(inner_rhs), Sugg::hir(cx, lhs, "_")) } else { return; }; @@ -558,12 +563,12 @@ fn is_zero(cx: &LateContext<'_>, expr: &Expr<'_>, ctxt: SyntaxContext) -> bool { /// If the two expressions are not negations of each other, then it /// returns None. fn are_negated<'a>(cx: &LateContext<'_>, expr1: &'a Expr<'a>, expr2: &'a Expr<'a>) -> Option<(bool, &'a Expr<'a>)> { - if let ExprKind::Unary(UnOp::Neg, expr1_negated) = &expr1.kind + if let ExprKind::Unary(UnOp::Neg, expr1_negated) = expr1.kind && eq_expr_value(cx, expr1_negated, expr2) { return Some((false, expr2)); } - if let ExprKind::Unary(UnOp::Neg, expr2_negated) = &expr2.kind + if let ExprKind::Unary(UnOp::Neg, expr2_negated) = expr2.kind && eq_expr_value(cx, expr1, expr2_negated) { return Some((true, expr1)); @@ -581,29 +586,20 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) { && let else_body_expr = peel_blocks(r#else) && let Some((if_expr_positive, body)) = are_negated(cx, if_body_expr, else_body_expr) { - let positive_abs_sugg = ( - "manual implementation of `abs` method", - format!("{}.abs()", Sugg::hir(cx, body, "..").maybe_paren()), - ); - let negative_abs_sugg = ( - "manual implementation of negation of `abs` method", - format!("-{}.abs()", Sugg::hir(cx, body, "..").maybe_paren()), - ); - let sugg = if is_testing_positive(cx, cond, body) { - if if_expr_positive { - positive_abs_sugg - } else { - negative_abs_sugg - } + let sugg_positive_abs = if is_testing_positive(cx, cond, body) { + if_expr_positive } else if is_testing_negative(cx, cond, body) { - if if_expr_positive { - negative_abs_sugg - } else { - positive_abs_sugg - } + !if_expr_positive } else { return; }; + let body = Sugg::hir(cx, body, "_").maybe_paren(); + let sugg = if sugg_positive_abs { + ("manual implementation of `abs` method", format!("{body}.abs()")) + } else { + #[rustfmt::skip] + ("manual implementation of negation of `abs` method", format!("-{body}.abs()")) + }; span_lint_and_sugg( cx, SUBOPTIMAL_FLOPS, @@ -637,10 +633,10 @@ fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) { }, lhs, rhs, - ) = &expr.kind + ) = expr.kind && are_same_base_logs(cx, lhs, rhs) - && let ExprKind::MethodCall(_, largs_self, ..) = &lhs.kind - && let ExprKind::MethodCall(_, rargs_self, ..) = &rhs.kind + && let ExprKind::MethodCall(_, largs_self, ..) = lhs.kind + && let ExprKind::MethodCall(_, rargs_self, ..) = rhs.kind { span_lint_and_sugg( cx, @@ -650,8 +646,8 @@ fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) { "consider using", format!( "{}.log({})", - Sugg::hir(cx, largs_self, "..").maybe_paren(), - Sugg::hir(cx, rargs_self, ".."), + Sugg::hir(cx, largs_self, "_").maybe_paren(), + Sugg::hir(cx, rargs_self, "_"), ), Applicability::MachineApplicable, ); @@ -665,14 +661,14 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { }, div_lhs, div_rhs, - ) = &expr.kind + ) = expr.kind && let ExprKind::Binary( Spanned { node: BinOpKind::Mul, .. }, mul_lhs, mul_rhs, - ) = &div_lhs.kind + ) = div_lhs.kind && let ecx = ConstEvalCtxt::new(cx) && let Some(rvalue) = ecx.eval(div_rhs) && let Some(lvalue) = ecx.eval(mul_rhs) @@ -681,48 +677,52 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) && (F32(180_f32) == lvalue || F64(180_f64) == lvalue) { - let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..").maybe_paren()); - if let ExprKind::Lit(literal) = mul_lhs.kind - && let ast::LitKind::Float(ref value, float_type) = literal.node - && float_type == ast::LitFloatType::Unsuffixed - { - if value.as_str().ends_with('.') { - proposal = format!("{}0_f64.to_degrees()", Sugg::hir(cx, mul_lhs, "..")); - } else { - proposal = format!("{}_f64.to_degrees()", Sugg::hir(cx, mul_lhs, "..")); - } - } - span_lint_and_sugg( + span_lint_and_then( cx, SUBOPTIMAL_FLOPS, expr.span, "conversion to degrees can be done more accurately", - "consider using", - proposal, - Applicability::MachineApplicable, + |diag| { + let recv = Sugg::hir(cx, mul_lhs, "num"); + let proposal = if let ExprKind::Lit(literal) = mul_lhs.kind + && let ast::LitKind::Float(ref value, float_type) = literal.node + && float_type == ast::LitFloatType::Unsuffixed + { + if value.as_str().ends_with('.') { + format!("{recv}0_f64.to_degrees()") + } else { + format!("{recv}_f64.to_degrees()") + } + } else { + format!("{}.to_degrees()", recv.maybe_paren()) + }; + diag.span_suggestion(expr.span, "consider using", proposal, Applicability::MachineApplicable); + }, ); } else if (F32(180_f32) == rvalue || F64(180_f64) == rvalue) && (F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue) { - let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..").maybe_paren()); - if let ExprKind::Lit(literal) = mul_lhs.kind - && let ast::LitKind::Float(ref value, float_type) = literal.node - && float_type == ast::LitFloatType::Unsuffixed - { - if value.as_str().ends_with('.') { - proposal = format!("{}0_f64.to_radians()", Sugg::hir(cx, mul_lhs, "..")); - } else { - proposal = format!("{}_f64.to_radians()", Sugg::hir(cx, mul_lhs, "..")); - } - } - span_lint_and_sugg( + span_lint_and_then( cx, SUBOPTIMAL_FLOPS, expr.span, "conversion to radians can be done more accurately", - "consider using", - proposal, - Applicability::MachineApplicable, + |diag| { + let recv = Sugg::hir(cx, mul_lhs, "num"); + let proposal = if let ExprKind::Lit(literal) = mul_lhs.kind + && let ast::LitKind::Float(ref value, float_type) = literal.node + && float_type == ast::LitFloatType::Unsuffixed + { + if value.as_str().ends_with('.') { + format!("{recv}0_f64.to_radians()") + } else { + format!("{recv}_f64.to_radians()") + } + } else { + format!("{}.to_radians()", recv.maybe_paren()) + }; + diag.span_suggestion(expr.span, "consider using", proposal, Applicability::MachineApplicable); + }, ); } } @@ -735,7 +735,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic { return; } - if let ExprKind::MethodCall(path, receiver, args, _) = &expr.kind { + if let ExprKind::MethodCall(path, receiver, args, _) = expr.kind { let recv_ty = cx.typeck_results().expr_ty(receiver); if recv_ty.is_floating_point() && !is_no_std_crate(cx) && cx.ty_based_def(expr).opt_parent(cx).is_impl(cx) { From eb101b1d2a2b7ee1407935ba8c5bee36ac9ee31d Mon Sep 17 00:00:00 2001 From: Paul Mabileau Date: Thu, 18 Dec 2025 12:55:04 +0100 Subject: [PATCH 0441/1061] Fix(lib/win/thread): Ensure `Sleep`'s usage passes over the requested duration under Win7 Fixes #149935. See the added comment for more details. Signed-off-by: Paul Mabileau --- library/std/src/sys/thread/windows.rs | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys/thread/windows.rs b/library/std/src/sys/thread/windows.rs index 6a21b11e0312..ea18572489ee 100644 --- a/library/std/src/sys/thread/windows.rs +++ b/library/std/src/sys/thread/windows.rs @@ -8,7 +8,7 @@ use crate::sys::pal::time::WaitableTimer; use crate::sys::pal::{dur2timeout, to_u16s}; use crate::sys::{FromInner, c, stack_overflow}; use crate::thread::ThreadInit; -use crate::time::Duration; +use crate::time::{Duration, Instant}; use crate::{io, ptr}; pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024; @@ -120,11 +120,28 @@ pub fn sleep(dur: Duration) { timer.set(dur)?; timer.wait() } + // Directly forward to `Sleep` for its zero duration behavior when indeed + // zero in order to skip the `Instant::now` calls, useless in this case. + if dur.is_zero() { + unsafe { c::Sleep(0) }; // Attempt to use high-precision sleep (Windows 10, version 1803+). - // On error fallback to the standard `Sleep` function. - // Also preserves the zero duration behavior of `Sleep`. - if dur.is_zero() || high_precision_sleep(dur).is_err() { - unsafe { c::Sleep(dur2timeout(dur)) } + // On error, fallback to the standard `Sleep` function. + } else if high_precision_sleep(dur).is_err() { + let start = Instant::now(); + unsafe { c::Sleep(dur2timeout(dur)) }; + + // See #149935: `Sleep` under Windows 7 and probably 8 as well seems a + // bit buggy for us as it can last less than the requested time while + // our API is meant to guarantee that. This is fixed by measuring the + // effective time difference and if needed, sleeping a bit more in + // order to ensure the duration is always exceeded. A fixed single + // millisecond works because `Sleep` operates based on a system-wide + // (until Windows 10 2004 that makes it process-local) interrupt timer + // that counts in "tick" units of ~15ms by default: a 1ms timeout + // therefore passes the next tick boundary. + if start.elapsed() < dur { + unsafe { c::Sleep(1) }; + } } } From cb9a079f608e6fed49a9303ff68ecca322e5b06b Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Thu, 8 Jan 2026 21:24:50 +0100 Subject: [PATCH 0442/1061] fix(float_point_arithmetic): respect reduced applicability --- clippy_lints/src/floating_point_arithmetic.rs | 142 ++++++++++-------- 1 file changed, 76 insertions(+), 66 deletions(-) diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 0a8f6c6ebf6b..64a2af38a108 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -127,8 +127,8 @@ fn get_specialized_log_method(cx: &LateContext<'_>, base: &Expr<'_>, ctxt: Synta } // Adds type suffixes and parenthesis to method receivers if necessary -fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Sugg<'a> { - let mut suggestion = Sugg::hir(cx, expr, "_"); +fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>, app: &mut Applicability) -> Sugg<'a> { + let mut suggestion = Sugg::hir_with_applicability(cx, expr, "_", app); if let ExprKind::Unary(UnOp::Neg, inner_expr) = expr.kind { expr = inner_expr; @@ -160,14 +160,16 @@ fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Su fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) { if let Some(method) = get_specialized_log_method(cx, &args[0], expr.span.ctxt()) { - span_lint_and_sugg( + span_lint_and_then( cx, SUBOPTIMAL_FLOPS, expr.span, "logarithm for bases 2, 10 and e can be computed more accurately", - "consider using", - format!("{}.{method}()", Sugg::hir(cx, receiver, "_").maybe_paren()), - Applicability::MachineApplicable, + |diag| { + let mut app = Applicability::MachineApplicable; + let recv = Sugg::hir_with_applicability(cx, receiver, "_", &mut app).maybe_paren(); + diag.span_suggestion(expr.span, "consider using", format!("{recv}.{method}()"), app); + }, ); } } @@ -190,14 +192,16 @@ fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) { _ => return, }; - span_lint_and_sugg( + span_lint_and_then( cx, IMPRECISE_FLOPS, expr.span, "ln(1 + x) can be computed more accurately", - "consider using", - format!("{}.ln_1p()", prepare_receiver_sugg(cx, recv)), - Applicability::MachineApplicable, + |diag| { + let mut app = Applicability::MachineApplicable; + let recv = prepare_receiver_sugg(cx, recv, &mut app); + diag.span_suggestion(expr.span, "consider using", format!("{recv}.ln_1p()"), app); + }, ); } } @@ -238,20 +242,23 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: None } { - span_lint_and_sugg( + span_lint_and_then( cx, SUBOPTIMAL_FLOPS, expr.span, "exponent for bases 2 and e can be computed more accurately", - "consider using", - format!("{}.{method}()", prepare_receiver_sugg(cx, &args[0])), - Applicability::MachineApplicable, + |diag| { + let mut app = Applicability::MachineApplicable; + let recv = prepare_receiver_sugg(cx, &args[0], &mut app); + diag.span_suggestion(expr.span, "consider using", format!("{recv}.{method}()"), app); + }, ); } // Check argument if let Some(value) = ConstEvalCtxt::new(cx).eval(&args[0]) { - let recv = Sugg::hir(cx, receiver, "_").maybe_paren(); + let mut app = Applicability::MachineApplicable; + let recv = Sugg::hir_with_applicability(cx, receiver, "_", &mut app).maybe_paren(); let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value { ( SUBOPTIMAL_FLOPS, @@ -277,15 +284,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: return; }; - span_lint_and_sugg( - cx, - lint, - expr.span, - help, - "consider using", - suggestion, - Applicability::MachineApplicable, - ); + span_lint_and_sugg(cx, lint, expr.span, help, "consider using", suggestion, app); } } @@ -297,7 +296,8 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: if let Some(grandparent) = get_parent_expr(cx, parent) && let ExprKind::MethodCall(PathSegment { ident: method, .. }, receiver, ..) = grandparent.kind && method.name == sym::sqrt - && detect_hypot(cx, receiver).is_some() + // we don't care about the applicability as this is an early-return condition + && detect_hypot(cx, receiver, &mut Applicability::Unspecified).is_some() { return; } @@ -320,8 +320,8 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: let other_addend = if lhs.hir_id == expr.hir_id { rhs } else { lhs }; // Negate expr if original code has subtraction and expr is on the right side - let maybe_neg_sugg = |expr, hir_id| { - let sugg = Sugg::hir(cx, expr, "_"); + let maybe_neg_sugg = |expr, hir_id, app: &mut _| { + let sugg = Sugg::hir_with_applicability(cx, expr, "_", app); if matches!(op, BinOpKind::Sub) && hir_id == rhs.hir_id { -sugg } else { @@ -329,16 +329,17 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: } }; + let mut app = Applicability::MachineApplicable; diag.span_suggestion( parent.span, "consider using", format!( "{}.mul_add({}, {})", - Sugg::hir(cx, receiver, "_").maybe_paren(), - maybe_neg_sugg(receiver, expr.hir_id), - maybe_neg_sugg(other_addend, other_addend.hir_id), + Sugg::hir_with_applicability(cx, receiver, "_", &mut app).maybe_paren(), + maybe_neg_sugg(receiver, expr.hir_id, &mut app), + maybe_neg_sugg(other_addend, other_addend.hir_id, &mut app), ), - Applicability::MachineApplicable, + app, ); }, ); @@ -346,7 +347,7 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: } } -fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option { +fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>, app: &mut Applicability) -> Option { if let ExprKind::Binary( Spanned { node: BinOpKind::Add, .. @@ -375,8 +376,8 @@ fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option { { return Some(format!( "{}.hypot({})", - Sugg::hir(cx, lmul_lhs, "_").maybe_paren(), - Sugg::hir(cx, rmul_lhs, "_") + Sugg::hir_with_applicability(cx, lmul_lhs, "_", app).maybe_paren(), + Sugg::hir_with_applicability(cx, rmul_lhs, "_", app) )); } @@ -393,8 +394,8 @@ fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option { { return Some(format!( "{}.hypot({})", - Sugg::hir(cx, largs_0, "_").maybe_paren(), - Sugg::hir(cx, rargs_0, "_") + Sugg::hir_with_applicability(cx, largs_0, "_", app).maybe_paren(), + Sugg::hir_with_applicability(cx, rargs_0, "_", app) )); } } @@ -403,7 +404,8 @@ fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option { } fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) { - if let Some(message) = detect_hypot(cx, receiver) { + let mut app = Applicability::MachineApplicable; + if let Some(message) = detect_hypot(cx, receiver, &mut app) { span_lint_and_sugg( cx, IMPRECISE_FLOPS, @@ -411,7 +413,7 @@ fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) { "hypotenuse can be computed more accurately", "consider using", message, - Applicability::MachineApplicable, + app, ); } } @@ -433,14 +435,16 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) { && (F32(1.0) == value || F64(1.0) == value) && cx.typeck_results().expr_ty(self_arg).is_floating_point() { - span_lint_and_sugg( + span_lint_and_then( cx, IMPRECISE_FLOPS, expr.span, "(e.pow(x) - 1) can be computed more accurately", - "consider using", - format!("{}.exp_m1()", Sugg::hir(cx, self_arg, "_").maybe_paren()), - Applicability::MachineApplicable, + |diag| { + let mut app = Applicability::MachineApplicable; + let recv = Sugg::hir_with_applicability(cx, self_arg, "_", &mut app).maybe_paren(); + diag.span_suggestion(expr.span, "consider using", format!("{recv}.exp_m1()"), app); + }, ); } } @@ -475,24 +479,34 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) { if let Some(parent) = get_parent_expr(cx, expr) && let ExprKind::MethodCall(PathSegment { ident: method, .. }, receiver, ..) = parent.kind && method.name == sym::sqrt - && detect_hypot(cx, receiver).is_some() + // we don't care about the applicability as this is an early-return condition + && detect_hypot(cx, receiver, &mut Applicability::Unspecified).is_some() { return; } - let maybe_neg_sugg = |expr| { - let sugg = Sugg::hir(cx, expr, "_"); + let maybe_neg_sugg = |expr, app: &mut _| { + let sugg = Sugg::hir_with_applicability(cx, expr, "_", app); if let BinOpKind::Sub = op { -sugg } else { sugg } }; + let mut app = Applicability::MachineApplicable; let (recv, arg1, arg2) = if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, lhs) && cx.typeck_results().expr_ty(rhs).is_floating_point() { - (inner_lhs, Sugg::hir(cx, inner_rhs, "_"), maybe_neg_sugg(rhs)) + ( + inner_lhs, + Sugg::hir_with_applicability(cx, inner_rhs, "_", &mut app), + maybe_neg_sugg(rhs, &mut app), + ) } else if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, rhs) && cx.typeck_results().expr_ty(lhs).is_floating_point() { - (inner_lhs, maybe_neg_sugg(inner_rhs), Sugg::hir(cx, lhs, "_")) + ( + inner_lhs, + maybe_neg_sugg(inner_rhs, &mut app), + Sugg::hir_with_applicability(cx, lhs, "_", &mut app), + ) } else { return; }; @@ -511,8 +525,8 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) { expr.span, "multiply and add expressions can be calculated more efficiently and accurately", "consider using", - format!("{}.mul_add({arg1}, {arg2})", prepare_receiver_sugg(cx, recv)), - Applicability::MachineApplicable, + format!("{}.mul_add({arg1}, {arg2})", prepare_receiver_sugg(cx, recv, &mut app)), + app, ); } } @@ -593,22 +607,15 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) { } else { return; }; - let body = Sugg::hir(cx, body, "_").maybe_paren(); + let mut app = Applicability::MachineApplicable; + let body = Sugg::hir_with_applicability(cx, body, "_", &mut app).maybe_paren(); let sugg = if sugg_positive_abs { ("manual implementation of `abs` method", format!("{body}.abs()")) } else { #[rustfmt::skip] ("manual implementation of negation of `abs` method", format!("-{body}.abs()")) }; - span_lint_and_sugg( - cx, - SUBOPTIMAL_FLOPS, - expr.span, - sugg.0, - "try", - sugg.1, - Applicability::MachineApplicable, - ); + span_lint_and_sugg(cx, SUBOPTIMAL_FLOPS, expr.span, sugg.0, "try", sugg.1, app); } } @@ -638,6 +645,7 @@ fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) { && let ExprKind::MethodCall(_, largs_self, ..) = lhs.kind && let ExprKind::MethodCall(_, rargs_self, ..) = rhs.kind { + let mut app = Applicability::MachineApplicable; span_lint_and_sugg( cx, SUBOPTIMAL_FLOPS, @@ -646,10 +654,10 @@ fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) { "consider using", format!( "{}.log({})", - Sugg::hir(cx, largs_self, "_").maybe_paren(), - Sugg::hir(cx, rargs_self, "_"), + Sugg::hir_with_applicability(cx, largs_self, "_", &mut app).maybe_paren(), + Sugg::hir_with_applicability(cx, rargs_self, "_", &mut app), ), - Applicability::MachineApplicable, + app, ); } } @@ -683,7 +691,8 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { expr.span, "conversion to degrees can be done more accurately", |diag| { - let recv = Sugg::hir(cx, mul_lhs, "num"); + let mut app = Applicability::MachineApplicable; + let recv = Sugg::hir_with_applicability(cx, mul_lhs, "num", &mut app); let proposal = if let ExprKind::Lit(literal) = mul_lhs.kind && let ast::LitKind::Float(ref value, float_type) = literal.node && float_type == ast::LitFloatType::Unsuffixed @@ -696,7 +705,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { } else { format!("{}.to_degrees()", recv.maybe_paren()) }; - diag.span_suggestion(expr.span, "consider using", proposal, Applicability::MachineApplicable); + diag.span_suggestion(expr.span, "consider using", proposal, app); }, ); } else if (F32(180_f32) == rvalue || F64(180_f64) == rvalue) @@ -708,7 +717,8 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { expr.span, "conversion to radians can be done more accurately", |diag| { - let recv = Sugg::hir(cx, mul_lhs, "num"); + let mut app = Applicability::MachineApplicable; + let recv = Sugg::hir_with_applicability(cx, mul_lhs, "num", &mut app); let proposal = if let ExprKind::Lit(literal) = mul_lhs.kind && let ast::LitKind::Float(ref value, float_type) = literal.node && float_type == ast::LitFloatType::Unsuffixed @@ -721,7 +731,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { } else { format!("{}.to_radians()", recv.maybe_paren()) }; - diag.span_suggestion(expr.span, "consider using", proposal, Applicability::MachineApplicable); + diag.span_suggestion(expr.span, "consider using", proposal, app); }, ); } From 7a377d66727e441c8472c18cb7aab3a597be1639 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Thu, 8 Jan 2026 22:03:26 +0100 Subject: [PATCH 0443/1061] move `floating_point_arithmetic.rs` to `floating_point_arithmetic/mod.rs` --- .../mod.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename clippy_lints/src/{floating_point_arithmetic.rs => floating_point_arithmetic/mod.rs} (100%) diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic/mod.rs similarity index 100% rename from clippy_lints/src/floating_point_arithmetic.rs rename to clippy_lints/src/floating_point_arithmetic/mod.rs From 44a41041fcb00f6fd1f76beeef53db936d39e31d Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Thu, 8 Jan 2026 22:46:58 +0100 Subject: [PATCH 0444/1061] extract each check into a separate module --- .../floating_point_arithmetic/custom_abs.rs | 100 +++ .../src/floating_point_arithmetic/expm1.rs | 42 ++ .../src/floating_point_arithmetic/hypot.rs | 82 +++ .../src/floating_point_arithmetic/lib.rs | 42 ++ .../src/floating_point_arithmetic/ln1p.rs | 41 ++ .../src/floating_point_arithmetic/log_base.rs | 44 ++ .../floating_point_arithmetic/log_division.rs | 52 ++ .../src/floating_point_arithmetic/mod.rs | 678 +----------------- .../src/floating_point_arithmetic/mul_add.rs | 94 +++ .../src/floating_point_arithmetic/powf.rs | 94 +++ .../src/floating_point_arithmetic/powi.rs | 70 ++ .../src/floating_point_arithmetic/radians.rs | 89 +++ 12 files changed, 774 insertions(+), 654 deletions(-) create mode 100644 clippy_lints/src/floating_point_arithmetic/custom_abs.rs create mode 100644 clippy_lints/src/floating_point_arithmetic/expm1.rs create mode 100644 clippy_lints/src/floating_point_arithmetic/hypot.rs create mode 100644 clippy_lints/src/floating_point_arithmetic/lib.rs create mode 100644 clippy_lints/src/floating_point_arithmetic/ln1p.rs create mode 100644 clippy_lints/src/floating_point_arithmetic/log_base.rs create mode 100644 clippy_lints/src/floating_point_arithmetic/log_division.rs create mode 100644 clippy_lints/src/floating_point_arithmetic/mul_add.rs create mode 100644 clippy_lints/src/floating_point_arithmetic/powf.rs create mode 100644 clippy_lints/src/floating_point_arithmetic/powi.rs create mode 100644 clippy_lints/src/floating_point_arithmetic/radians.rs diff --git a/clippy_lints/src/floating_point_arithmetic/custom_abs.rs b/clippy_lints/src/floating_point_arithmetic/custom_abs.rs new file mode 100644 index 000000000000..d12a32e15881 --- /dev/null +++ b/clippy_lints/src/floating_point_arithmetic/custom_abs.rs @@ -0,0 +1,100 @@ +use clippy_utils::consts::ConstEvalCtxt; +use clippy_utils::consts::Constant::{F32, F64, Int}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::sugg::Sugg; +use clippy_utils::{eq_expr_value, higher, peel_blocks}; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; +use rustc_lint::LateContext; +use rustc_span::SyntaxContext; +use rustc_span::source_map::Spanned; + +use super::SUBOPTIMAL_FLOPS; + +/// Returns true iff expr is an expression which tests whether or not +/// test is positive or an expression which tests whether or not test +/// is nonnegative. +/// Used for check-custom-abs function below +fn is_testing_positive(cx: &LateContext<'_>, expr: &Expr<'_>, test: &Expr<'_>) -> bool { + if let ExprKind::Binary(Spanned { node: op, .. }, left, right) = expr.kind { + match op { + BinOpKind::Gt | BinOpKind::Ge => is_zero(cx, right, expr.span.ctxt()) && eq_expr_value(cx, left, test), + BinOpKind::Lt | BinOpKind::Le => is_zero(cx, left, expr.span.ctxt()) && eq_expr_value(cx, right, test), + _ => false, + } + } else { + false + } +} + +/// See [`is_testing_positive`] +fn is_testing_negative(cx: &LateContext<'_>, expr: &Expr<'_>, test: &Expr<'_>) -> bool { + if let ExprKind::Binary(Spanned { node: op, .. }, left, right) = expr.kind { + match op { + BinOpKind::Gt | BinOpKind::Ge => is_zero(cx, left, expr.span.ctxt()) && eq_expr_value(cx, right, test), + BinOpKind::Lt | BinOpKind::Le => is_zero(cx, right, expr.span.ctxt()) && eq_expr_value(cx, left, test), + _ => false, + } + } else { + false + } +} + +/// Returns true iff expr is some zero literal +fn is_zero(cx: &LateContext<'_>, expr: &Expr<'_>, ctxt: SyntaxContext) -> bool { + match ConstEvalCtxt::new(cx).eval_local(expr, ctxt) { + Some(Int(i)) => i == 0, + Some(F32(f)) => f == 0.0, + Some(F64(f)) => f == 0.0, + _ => false, + } +} + +/// If the two expressions are negations of each other, then it returns +/// a tuple, in which the first element is true iff expr1 is the +/// positive expressions, and the second element is the positive +/// one of the two expressions +/// If the two expressions are not negations of each other, then it +/// returns None. +fn are_negated<'a>(cx: &LateContext<'_>, expr1: &'a Expr<'a>, expr2: &'a Expr<'a>) -> Option<(bool, &'a Expr<'a>)> { + if let ExprKind::Unary(UnOp::Neg, expr1_negated) = expr1.kind + && eq_expr_value(cx, expr1_negated, expr2) + { + return Some((false, expr2)); + } + if let ExprKind::Unary(UnOp::Neg, expr2_negated) = expr2.kind + && eq_expr_value(cx, expr1, expr2_negated) + { + return Some((true, expr1)); + } + None +} + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { + if let Some(higher::If { + cond, + then, + r#else: Some(r#else), + }) = higher::If::hir(expr) + && let if_body_expr = peel_blocks(then) + && let else_body_expr = peel_blocks(r#else) + && let Some((if_expr_positive, body)) = are_negated(cx, if_body_expr, else_body_expr) + { + let sugg_positive_abs = if is_testing_positive(cx, cond, body) { + if_expr_positive + } else if is_testing_negative(cx, cond, body) { + !if_expr_positive + } else { + return; + }; + let mut app = Applicability::MachineApplicable; + let body = Sugg::hir_with_applicability(cx, body, "_", &mut app).maybe_paren(); + let sugg = if sugg_positive_abs { + ("manual implementation of `abs` method", format!("{body}.abs()")) + } else { + #[rustfmt::skip] + ("manual implementation of negation of `abs` method", format!("-{body}.abs()")) + }; + span_lint_and_sugg(cx, SUBOPTIMAL_FLOPS, expr.span, sugg.0, "try", sugg.1, app); + } +} diff --git a/clippy_lints/src/floating_point_arithmetic/expm1.rs b/clippy_lints/src/floating_point_arithmetic/expm1.rs new file mode 100644 index 000000000000..9a4c97569308 --- /dev/null +++ b/clippy_lints/src/floating_point_arithmetic/expm1.rs @@ -0,0 +1,42 @@ +use clippy_utils::consts::ConstEvalCtxt; +use clippy_utils::consts::Constant::{F32, F64}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg::Sugg; +use clippy_utils::sym; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::source_map::Spanned; + +use super::IMPRECISE_FLOPS; + +// TODO: Lint expressions of the form `x.exp() - y` where y > 1 +// and suggest usage of `x.exp_m1() - (y - 1)` instead +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Sub, .. + }, + lhs, + rhs, + ) = expr.kind + && let ExprKind::MethodCall(path, self_arg, [], _) = lhs.kind + && path.ident.name == sym::exp + && cx.typeck_results().expr_ty(lhs).is_floating_point() + && let Some(value) = ConstEvalCtxt::new(cx).eval(rhs) + && (F32(1.0) == value || F64(1.0) == value) + && cx.typeck_results().expr_ty(self_arg).is_floating_point() + { + span_lint_and_then( + cx, + IMPRECISE_FLOPS, + expr.span, + "(e.pow(x) - 1) can be computed more accurately", + |diag| { + let mut app = Applicability::MachineApplicable; + let recv = Sugg::hir_with_applicability(cx, self_arg, "_", &mut app).maybe_paren(); + diag.span_suggestion(expr.span, "consider using", format!("{recv}.exp_m1()"), app); + }, + ); + } +} diff --git a/clippy_lints/src/floating_point_arithmetic/hypot.rs b/clippy_lints/src/floating_point_arithmetic/hypot.rs new file mode 100644 index 000000000000..49f8ba4bf825 --- /dev/null +++ b/clippy_lints/src/floating_point_arithmetic/hypot.rs @@ -0,0 +1,82 @@ +use clippy_utils::consts::ConstEvalCtxt; +use clippy_utils::consts::Constant::Int; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::sugg::Sugg; +use clippy_utils::{eq_expr_value, sym}; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment}; +use rustc_lint::LateContext; +use rustc_span::source_map::Spanned; + +use super::IMPRECISE_FLOPS; + +pub(super) fn detect(cx: &LateContext<'_>, receiver: &Expr<'_>, app: &mut Applicability) -> Option { + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Add, .. + }, + add_lhs, + add_rhs, + ) = receiver.kind + { + // check if expression of the form x * x + y * y + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Mul, .. + }, + lmul_lhs, + lmul_rhs, + ) = add_lhs.kind + && let ExprKind::Binary( + Spanned { + node: BinOpKind::Mul, .. + }, + rmul_lhs, + rmul_rhs, + ) = add_rhs.kind + && eq_expr_value(cx, lmul_lhs, lmul_rhs) + && eq_expr_value(cx, rmul_lhs, rmul_rhs) + { + return Some(format!( + "{}.hypot({})", + Sugg::hir_with_applicability(cx, lmul_lhs, "_", app).maybe_paren(), + Sugg::hir_with_applicability(cx, rmul_lhs, "_", app) + )); + } + + // check if expression of the form x.powi(2) + y.powi(2) + if let ExprKind::MethodCall(PathSegment { ident: lmethod, .. }, largs_0, [largs_1, ..], _) = add_lhs.kind + && let ExprKind::MethodCall(PathSegment { ident: rmethod, .. }, rargs_0, [rargs_1, ..], _) = add_rhs.kind + && lmethod.name == sym::powi + && rmethod.name == sym::powi + && let ecx = ConstEvalCtxt::new(cx) + && let Some(lvalue) = ecx.eval(largs_1) + && let Some(rvalue) = ecx.eval(rargs_1) + && Int(2) == lvalue + && Int(2) == rvalue + { + return Some(format!( + "{}.hypot({})", + Sugg::hir_with_applicability(cx, largs_0, "_", app).maybe_paren(), + Sugg::hir_with_applicability(cx, rargs_0, "_", app) + )); + } + } + + None +} + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) { + let mut app = Applicability::MachineApplicable; + if let Some(message) = detect(cx, receiver, &mut app) { + span_lint_and_sugg( + cx, + IMPRECISE_FLOPS, + expr.span, + "hypotenuse can be computed more accurately", + "consider using", + message, + app, + ); + } +} diff --git a/clippy_lints/src/floating_point_arithmetic/lib.rs b/clippy_lints/src/floating_point_arithmetic/lib.rs new file mode 100644 index 000000000000..3fa041f97802 --- /dev/null +++ b/clippy_lints/src/floating_point_arithmetic/lib.rs @@ -0,0 +1,42 @@ +use clippy_utils::sugg::Sugg; +use rustc_ast::ast; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, UnOp}; +use rustc_lint::LateContext; +use rustc_middle::ty; + +// Adds type suffixes and parenthesis to method receivers if necessary +pub(super) fn prepare_receiver_sugg<'a>( + cx: &LateContext<'_>, + mut expr: &'a Expr<'a>, + app: &mut Applicability, +) -> Sugg<'a> { + let mut suggestion = Sugg::hir_with_applicability(cx, expr, "_", app); + + if let ExprKind::Unary(UnOp::Neg, inner_expr) = expr.kind { + expr = inner_expr; + } + + if let ty::Float(float_ty) = cx.typeck_results().expr_ty(expr).kind() + // if the expression is a float literal and it is unsuffixed then + // add a suffix so the suggestion is valid and unambiguous + && let ExprKind::Lit(lit) = expr.kind + && let ast::LitKind::Float(sym, ast::LitFloatType::Unsuffixed) = lit.node + { + let op = format!( + "{suggestion}{}{}", + // Check for float literals without numbers following the decimal + // separator such as `2.` and adds a trailing zero + if sym.as_str().ends_with('.') { "0" } else { "" }, + float_ty.name_str() + ) + .into(); + + suggestion = match suggestion { + Sugg::MaybeParen(_) | Sugg::UnOp(UnOp::Neg, _) => Sugg::MaybeParen(op), + _ => Sugg::NonParen(op), + }; + } + + suggestion.maybe_paren() +} diff --git a/clippy_lints/src/floating_point_arithmetic/ln1p.rs b/clippy_lints/src/floating_point_arithmetic/ln1p.rs new file mode 100644 index 000000000000..4c9aa96b5042 --- /dev/null +++ b/clippy_lints/src/floating_point_arithmetic/ln1p.rs @@ -0,0 +1,41 @@ +use clippy_utils::consts::ConstEvalCtxt; +use clippy_utils::consts::Constant::{F32, F64}; +use clippy_utils::diagnostics::span_lint_and_then; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::source_map::Spanned; + +use super::IMPRECISE_FLOPS; + +// TODO: Lint expressions of the form `(x + y).ln()` where y > 1 and +// suggest usage of `(x + (y - 1)).ln_1p()` instead +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) { + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Add, .. + }, + lhs, + rhs, + ) = receiver.kind + { + let ecx = ConstEvalCtxt::new(cx); + let recv = match (ecx.eval(lhs), ecx.eval(rhs)) { + (Some(value), _) if F32(1.0) == value || F64(1.0) == value => rhs, + (_, Some(value)) if F32(1.0) == value || F64(1.0) == value => lhs, + _ => return, + }; + + span_lint_and_then( + cx, + IMPRECISE_FLOPS, + expr.span, + "ln(1 + x) can be computed more accurately", + |diag| { + let mut app = Applicability::MachineApplicable; + let recv = super::lib::prepare_receiver_sugg(cx, recv, &mut app); + diag.span_suggestion(expr.span, "consider using", format!("{recv}.ln_1p()"), app); + }, + ); + } +} diff --git a/clippy_lints/src/floating_point_arithmetic/log_base.rs b/clippy_lints/src/floating_point_arithmetic/log_base.rs new file mode 100644 index 000000000000..4ccc784655ed --- /dev/null +++ b/clippy_lints/src/floating_point_arithmetic/log_base.rs @@ -0,0 +1,44 @@ +use clippy_utils::consts::ConstEvalCtxt; +use clippy_utils::consts::Constant::{F32, F64}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg::Sugg; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_span::SyntaxContext; +use std::f32::consts as f32_consts; +use std::f64::consts as f64_consts; + +use super::SUBOPTIMAL_FLOPS; + +// Returns the specialized log method for a given base if base is constant +// and is one of 2, 10 and e +fn get_specialized_log_method(cx: &LateContext<'_>, base: &Expr<'_>, ctxt: SyntaxContext) -> Option<&'static str> { + if let Some(value) = ConstEvalCtxt::new(cx).eval_local(base, ctxt) { + if F32(2.0) == value || F64(2.0) == value { + return Some("log2"); + } else if F32(10.0) == value || F64(10.0) == value { + return Some("log10"); + } else if F32(f32_consts::E) == value || F64(f64_consts::E) == value { + return Some("ln"); + } + } + + None +} + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) { + if let Some(method) = get_specialized_log_method(cx, &args[0], expr.span.ctxt()) { + span_lint_and_then( + cx, + SUBOPTIMAL_FLOPS, + expr.span, + "logarithm for bases 2, 10 and e can be computed more accurately", + |diag| { + let mut app = Applicability::MachineApplicable; + let recv = Sugg::hir_with_applicability(cx, receiver, "_", &mut app).maybe_paren(); + diag.span_suggestion(expr.span, "consider using", format!("{recv}.{method}()"), app); + }, + ); + } +} diff --git a/clippy_lints/src/floating_point_arithmetic/log_division.rs b/clippy_lints/src/floating_point_arithmetic/log_division.rs new file mode 100644 index 000000000000..e3419ffad72a --- /dev/null +++ b/clippy_lints/src/floating_point_arithmetic/log_division.rs @@ -0,0 +1,52 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::sugg::Sugg; +use clippy_utils::{eq_expr_value, sym}; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment}; +use rustc_lint::LateContext; +use rustc_span::source_map::Spanned; + +use super::SUBOPTIMAL_FLOPS; + +fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool { + if let ExprKind::MethodCall(PathSegment { ident: method_a, .. }, _, args_a, _) = expr_a.kind + && let ExprKind::MethodCall(PathSegment { ident: method_b, .. }, _, args_b, _) = expr_b.kind + { + return method_a.name == method_b.name + && args_a.len() == args_b.len() + && (matches!(method_a.name, sym::ln | sym::log2 | sym::log10) + || method_a.name == sym::log && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0])); + } + + false +} + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { + // check if expression of the form x.logN() / y.logN() + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Div, .. + }, + lhs, + rhs, + ) = expr.kind + && are_same_base_logs(cx, lhs, rhs) + && let ExprKind::MethodCall(_, largs_self, ..) = lhs.kind + && let ExprKind::MethodCall(_, rargs_self, ..) = rhs.kind + { + let mut app = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + SUBOPTIMAL_FLOPS, + expr.span, + "log base can be expressed more clearly", + "consider using", + format!( + "{}.log({})", + Sugg::hir_with_applicability(cx, largs_self, "_", &mut app).maybe_paren(), + Sugg::hir_with_applicability(cx, rargs_self, "_", &mut app), + ), + app, + ); + } +} diff --git a/clippy_lints/src/floating_point_arithmetic/mod.rs b/clippy_lints/src/floating_point_arithmetic/mod.rs index 64a2af38a108..edc638c96bbf 100644 --- a/clippy_lints/src/floating_point_arithmetic/mod.rs +++ b/clippy_lints/src/floating_point_arithmetic/mod.rs @@ -1,22 +1,20 @@ -use clippy_utils::consts::Constant::{F32, F64, Int}; -use clippy_utils::consts::{ConstEvalCtxt, Constant}; -use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; -use clippy_utils::{ - eq_expr_value, get_parent_expr, has_ambiguous_literal_in_expr, higher, is_in_const_context, is_no_std_crate, - numeric_literal, peel_blocks, sugg, sym, -}; -use rustc_ast::ast; -use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp}; +use clippy_utils::{is_in_const_context, is_no_std_crate, sym}; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::SyntaxContext; -use rustc_span::source_map::Spanned; -use std::f32::consts as f32_consts; -use std::f64::consts as f64_consts; -use sugg::Sugg; + +mod custom_abs; +mod expm1; +mod hypot; +mod lib; +mod ln1p; +mod log_base; +mod log_division; +mod mul_add; +mod powf; +mod powi; +mod radians; declare_clippy_lint! { /// ### What it does @@ -110,634 +108,6 @@ declare_lint_pass!(FloatingPointArithmetic => [ SUBOPTIMAL_FLOPS ]); -// Returns the specialized log method for a given base if base is constant -// and is one of 2, 10 and e -fn get_specialized_log_method(cx: &LateContext<'_>, base: &Expr<'_>, ctxt: SyntaxContext) -> Option<&'static str> { - if let Some(value) = ConstEvalCtxt::new(cx).eval_local(base, ctxt) { - if F32(2.0) == value || F64(2.0) == value { - return Some("log2"); - } else if F32(10.0) == value || F64(10.0) == value { - return Some("log10"); - } else if F32(f32_consts::E) == value || F64(f64_consts::E) == value { - return Some("ln"); - } - } - - None -} - -// Adds type suffixes and parenthesis to method receivers if necessary -fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>, app: &mut Applicability) -> Sugg<'a> { - let mut suggestion = Sugg::hir_with_applicability(cx, expr, "_", app); - - if let ExprKind::Unary(UnOp::Neg, inner_expr) = expr.kind { - expr = inner_expr; - } - - if let ty::Float(float_ty) = cx.typeck_results().expr_ty(expr).kind() - // if the expression is a float literal and it is unsuffixed then - // add a suffix so the suggestion is valid and unambiguous - && let ExprKind::Lit(lit) = expr.kind - && let ast::LitKind::Float(sym, ast::LitFloatType::Unsuffixed) = lit.node - { - let op = format!( - "{suggestion}{}{}", - // Check for float literals without numbers following the decimal - // separator such as `2.` and adds a trailing zero - if sym.as_str().ends_with('.') { "0" } else { "" }, - float_ty.name_str() - ) - .into(); - - suggestion = match suggestion { - Sugg::MaybeParen(_) | Sugg::UnOp(UnOp::Neg, _) => Sugg::MaybeParen(op), - _ => Sugg::NonParen(op), - }; - } - - suggestion.maybe_paren() -} - -fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) { - if let Some(method) = get_specialized_log_method(cx, &args[0], expr.span.ctxt()) { - span_lint_and_then( - cx, - SUBOPTIMAL_FLOPS, - expr.span, - "logarithm for bases 2, 10 and e can be computed more accurately", - |diag| { - let mut app = Applicability::MachineApplicable; - let recv = Sugg::hir_with_applicability(cx, receiver, "_", &mut app).maybe_paren(); - diag.span_suggestion(expr.span, "consider using", format!("{recv}.{method}()"), app); - }, - ); - } -} - -// TODO: Lint expressions of the form `(x + y).ln()` where y > 1 and -// suggest usage of `(x + (y - 1)).ln_1p()` instead -fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) { - if let ExprKind::Binary( - Spanned { - node: BinOpKind::Add, .. - }, - lhs, - rhs, - ) = receiver.kind - { - let ecx = ConstEvalCtxt::new(cx); - let recv = match (ecx.eval(lhs), ecx.eval(rhs)) { - (Some(value), _) if F32(1.0) == value || F64(1.0) == value => rhs, - (_, Some(value)) if F32(1.0) == value || F64(1.0) == value => lhs, - _ => return, - }; - - span_lint_and_then( - cx, - IMPRECISE_FLOPS, - expr.span, - "ln(1 + x) can be computed more accurately", - |diag| { - let mut app = Applicability::MachineApplicable; - let recv = prepare_receiver_sugg(cx, recv, &mut app); - diag.span_suggestion(expr.span, "consider using", format!("{recv}.ln_1p()"), app); - }, - ); - } -} - -// Returns an integer if the float constant is a whole number and it can be -// converted to an integer without loss of precision. For now we only check -// ranges [-16777215, 16777216) for type f32 as whole number floats outside -// this range are lossy and ambiguous. -#[expect(clippy::cast_possible_truncation)] -fn get_integer_from_float_constant(value: &Constant) -> Option { - match value { - F32(num) if num.fract() == 0.0 => { - if (-16_777_215.0..16_777_216.0).contains(num) { - Some(num.round() as i32) - } else { - None - } - }, - F64(num) if num.fract() == 0.0 => { - if (-2_147_483_648.0..2_147_483_648.0).contains(num) { - Some(num.round() as i32) - } else { - None - } - }, - _ => None, - } -} - -fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) { - // Check receiver - if let Some(value) = ConstEvalCtxt::new(cx).eval(receiver) - && let Some(method) = if F32(f32_consts::E) == value || F64(f64_consts::E) == value { - Some("exp") - } else if F32(2.0) == value || F64(2.0) == value { - Some("exp2") - } else { - None - } - { - span_lint_and_then( - cx, - SUBOPTIMAL_FLOPS, - expr.span, - "exponent for bases 2 and e can be computed more accurately", - |diag| { - let mut app = Applicability::MachineApplicable; - let recv = prepare_receiver_sugg(cx, &args[0], &mut app); - diag.span_suggestion(expr.span, "consider using", format!("{recv}.{method}()"), app); - }, - ); - } - - // Check argument - if let Some(value) = ConstEvalCtxt::new(cx).eval(&args[0]) { - let mut app = Applicability::MachineApplicable; - let recv = Sugg::hir_with_applicability(cx, receiver, "_", &mut app).maybe_paren(); - let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value { - ( - SUBOPTIMAL_FLOPS, - "square-root of a number can be computed more efficiently and accurately", - format!("{recv}.sqrt()"), - ) - } else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value { - ( - IMPRECISE_FLOPS, - "cube-root of a number can be computed more accurately", - format!("{recv}.cbrt()"), - ) - } else if let Some(exponent) = get_integer_from_float_constant(&value) { - ( - SUBOPTIMAL_FLOPS, - "exponentiation with integer powers can be computed more efficiently", - format!( - "{recv}.powi({})", - numeric_literal::format(&exponent.to_string(), None, false) - ), - ) - } else { - return; - }; - - span_lint_and_sugg(cx, lint, expr.span, help, "consider using", suggestion, app); - } -} - -fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) { - if let Some(value) = ConstEvalCtxt::new(cx).eval(&args[0]) - && value == Int(2) - && let Some(parent) = get_parent_expr(cx, expr) - { - if let Some(grandparent) = get_parent_expr(cx, parent) - && let ExprKind::MethodCall(PathSegment { ident: method, .. }, receiver, ..) = grandparent.kind - && method.name == sym::sqrt - // we don't care about the applicability as this is an early-return condition - && detect_hypot(cx, receiver, &mut Applicability::Unspecified).is_some() - { - return; - } - - if let ExprKind::Binary( - Spanned { - node: op @ (BinOpKind::Add | BinOpKind::Sub), - .. - }, - lhs, - rhs, - ) = parent.kind - { - span_lint_and_then( - cx, - SUBOPTIMAL_FLOPS, - parent.span, - "multiply and add expressions can be calculated more efficiently and accurately", - |diag| { - let other_addend = if lhs.hir_id == expr.hir_id { rhs } else { lhs }; - - // Negate expr if original code has subtraction and expr is on the right side - let maybe_neg_sugg = |expr, hir_id, app: &mut _| { - let sugg = Sugg::hir_with_applicability(cx, expr, "_", app); - if matches!(op, BinOpKind::Sub) && hir_id == rhs.hir_id { - -sugg - } else { - sugg - } - }; - - let mut app = Applicability::MachineApplicable; - diag.span_suggestion( - parent.span, - "consider using", - format!( - "{}.mul_add({}, {})", - Sugg::hir_with_applicability(cx, receiver, "_", &mut app).maybe_paren(), - maybe_neg_sugg(receiver, expr.hir_id, &mut app), - maybe_neg_sugg(other_addend, other_addend.hir_id, &mut app), - ), - app, - ); - }, - ); - } - } -} - -fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>, app: &mut Applicability) -> Option { - if let ExprKind::Binary( - Spanned { - node: BinOpKind::Add, .. - }, - add_lhs, - add_rhs, - ) = receiver.kind - { - // check if expression of the form x * x + y * y - if let ExprKind::Binary( - Spanned { - node: BinOpKind::Mul, .. - }, - lmul_lhs, - lmul_rhs, - ) = add_lhs.kind - && let ExprKind::Binary( - Spanned { - node: BinOpKind::Mul, .. - }, - rmul_lhs, - rmul_rhs, - ) = add_rhs.kind - && eq_expr_value(cx, lmul_lhs, lmul_rhs) - && eq_expr_value(cx, rmul_lhs, rmul_rhs) - { - return Some(format!( - "{}.hypot({})", - Sugg::hir_with_applicability(cx, lmul_lhs, "_", app).maybe_paren(), - Sugg::hir_with_applicability(cx, rmul_lhs, "_", app) - )); - } - - // check if expression of the form x.powi(2) + y.powi(2) - if let ExprKind::MethodCall(PathSegment { ident: lmethod, .. }, largs_0, [largs_1, ..], _) = add_lhs.kind - && let ExprKind::MethodCall(PathSegment { ident: rmethod, .. }, rargs_0, [rargs_1, ..], _) = add_rhs.kind - && lmethod.name == sym::powi - && rmethod.name == sym::powi - && let ecx = ConstEvalCtxt::new(cx) - && let Some(lvalue) = ecx.eval(largs_1) - && let Some(rvalue) = ecx.eval(rargs_1) - && Int(2) == lvalue - && Int(2) == rvalue - { - return Some(format!( - "{}.hypot({})", - Sugg::hir_with_applicability(cx, largs_0, "_", app).maybe_paren(), - Sugg::hir_with_applicability(cx, rargs_0, "_", app) - )); - } - } - - None -} - -fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) { - let mut app = Applicability::MachineApplicable; - if let Some(message) = detect_hypot(cx, receiver, &mut app) { - span_lint_and_sugg( - cx, - IMPRECISE_FLOPS, - expr.span, - "hypotenuse can be computed more accurately", - "consider using", - message, - app, - ); - } -} - -// TODO: Lint expressions of the form `x.exp() - y` where y > 1 -// and suggest usage of `x.exp_m1() - (y - 1)` instead -fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) { - if let ExprKind::Binary( - Spanned { - node: BinOpKind::Sub, .. - }, - lhs, - rhs, - ) = expr.kind - && let ExprKind::MethodCall(path, self_arg, [], _) = lhs.kind - && path.ident.name == sym::exp - && cx.typeck_results().expr_ty(lhs).is_floating_point() - && let Some(value) = ConstEvalCtxt::new(cx).eval(rhs) - && (F32(1.0) == value || F64(1.0) == value) - && cx.typeck_results().expr_ty(self_arg).is_floating_point() - { - span_lint_and_then( - cx, - IMPRECISE_FLOPS, - expr.span, - "(e.pow(x) - 1) can be computed more accurately", - |diag| { - let mut app = Applicability::MachineApplicable; - let recv = Sugg::hir_with_applicability(cx, self_arg, "_", &mut app).maybe_paren(); - diag.span_suggestion(expr.span, "consider using", format!("{recv}.exp_m1()"), app); - }, - ); - } -} - -fn is_float_mul_expr<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> { - if let ExprKind::Binary( - Spanned { - node: BinOpKind::Mul, .. - }, - lhs, - rhs, - ) = expr.kind - && cx.typeck_results().expr_ty(lhs).is_floating_point() - && cx.typeck_results().expr_ty(rhs).is_floating_point() - { - return Some((lhs, rhs)); - } - - None -} - -fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) { - if let ExprKind::Binary( - Spanned { - node: op @ (BinOpKind::Add | BinOpKind::Sub), - .. - }, - lhs, - rhs, - ) = &expr.kind - { - if let Some(parent) = get_parent_expr(cx, expr) - && let ExprKind::MethodCall(PathSegment { ident: method, .. }, receiver, ..) = parent.kind - && method.name == sym::sqrt - // we don't care about the applicability as this is an early-return condition - && detect_hypot(cx, receiver, &mut Applicability::Unspecified).is_some() - { - return; - } - - let maybe_neg_sugg = |expr, app: &mut _| { - let sugg = Sugg::hir_with_applicability(cx, expr, "_", app); - if let BinOpKind::Sub = op { -sugg } else { sugg } - }; - - let mut app = Applicability::MachineApplicable; - let (recv, arg1, arg2) = if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, lhs) - && cx.typeck_results().expr_ty(rhs).is_floating_point() - { - ( - inner_lhs, - Sugg::hir_with_applicability(cx, inner_rhs, "_", &mut app), - maybe_neg_sugg(rhs, &mut app), - ) - } else if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, rhs) - && cx.typeck_results().expr_ty(lhs).is_floating_point() - { - ( - inner_lhs, - maybe_neg_sugg(inner_rhs, &mut app), - Sugg::hir_with_applicability(cx, lhs, "_", &mut app), - ) - } else { - return; - }; - - // Check if any variable in the expression has an ambiguous type (could be f32 or f64) - // see: https://github.com/rust-lang/rust-clippy/issues/14897 - if (matches!(recv.kind, ExprKind::Path(_)) || matches!(recv.kind, ExprKind::Call(_, _))) - && has_ambiguous_literal_in_expr(cx, recv) - { - return; - } - - span_lint_and_sugg( - cx, - SUBOPTIMAL_FLOPS, - expr.span, - "multiply and add expressions can be calculated more efficiently and accurately", - "consider using", - format!("{}.mul_add({arg1}, {arg2})", prepare_receiver_sugg(cx, recv, &mut app)), - app, - ); - } -} - -/// Returns true iff expr is an expression which tests whether or not -/// test is positive or an expression which tests whether or not test -/// is nonnegative. -/// Used for check-custom-abs function below -fn is_testing_positive(cx: &LateContext<'_>, expr: &Expr<'_>, test: &Expr<'_>) -> bool { - if let ExprKind::Binary(Spanned { node: op, .. }, left, right) = expr.kind { - match op { - BinOpKind::Gt | BinOpKind::Ge => is_zero(cx, right, expr.span.ctxt()) && eq_expr_value(cx, left, test), - BinOpKind::Lt | BinOpKind::Le => is_zero(cx, left, expr.span.ctxt()) && eq_expr_value(cx, right, test), - _ => false, - } - } else { - false - } -} - -/// See [`is_testing_positive`] -fn is_testing_negative(cx: &LateContext<'_>, expr: &Expr<'_>, test: &Expr<'_>) -> bool { - if let ExprKind::Binary(Spanned { node: op, .. }, left, right) = expr.kind { - match op { - BinOpKind::Gt | BinOpKind::Ge => is_zero(cx, left, expr.span.ctxt()) && eq_expr_value(cx, right, test), - BinOpKind::Lt | BinOpKind::Le => is_zero(cx, right, expr.span.ctxt()) && eq_expr_value(cx, left, test), - _ => false, - } - } else { - false - } -} - -/// Returns true iff expr is some zero literal -fn is_zero(cx: &LateContext<'_>, expr: &Expr<'_>, ctxt: SyntaxContext) -> bool { - match ConstEvalCtxt::new(cx).eval_local(expr, ctxt) { - Some(Int(i)) => i == 0, - Some(F32(f)) => f == 0.0, - Some(F64(f)) => f == 0.0, - _ => false, - } -} - -/// If the two expressions are negations of each other, then it returns -/// a tuple, in which the first element is true iff expr1 is the -/// positive expressions, and the second element is the positive -/// one of the two expressions -/// If the two expressions are not negations of each other, then it -/// returns None. -fn are_negated<'a>(cx: &LateContext<'_>, expr1: &'a Expr<'a>, expr2: &'a Expr<'a>) -> Option<(bool, &'a Expr<'a>)> { - if let ExprKind::Unary(UnOp::Neg, expr1_negated) = expr1.kind - && eq_expr_value(cx, expr1_negated, expr2) - { - return Some((false, expr2)); - } - if let ExprKind::Unary(UnOp::Neg, expr2_negated) = expr2.kind - && eq_expr_value(cx, expr1, expr2_negated) - { - return Some((true, expr1)); - } - None -} - -fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) { - if let Some(higher::If { - cond, - then, - r#else: Some(r#else), - }) = higher::If::hir(expr) - && let if_body_expr = peel_blocks(then) - && let else_body_expr = peel_blocks(r#else) - && let Some((if_expr_positive, body)) = are_negated(cx, if_body_expr, else_body_expr) - { - let sugg_positive_abs = if is_testing_positive(cx, cond, body) { - if_expr_positive - } else if is_testing_negative(cx, cond, body) { - !if_expr_positive - } else { - return; - }; - let mut app = Applicability::MachineApplicable; - let body = Sugg::hir_with_applicability(cx, body, "_", &mut app).maybe_paren(); - let sugg = if sugg_positive_abs { - ("manual implementation of `abs` method", format!("{body}.abs()")) - } else { - #[rustfmt::skip] - ("manual implementation of negation of `abs` method", format!("-{body}.abs()")) - }; - span_lint_and_sugg(cx, SUBOPTIMAL_FLOPS, expr.span, sugg.0, "try", sugg.1, app); - } -} - -fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool { - if let ExprKind::MethodCall(PathSegment { ident: method_a, .. }, _, args_a, _) = expr_a.kind - && let ExprKind::MethodCall(PathSegment { ident: method_b, .. }, _, args_b, _) = expr_b.kind - { - return method_a.name == method_b.name - && args_a.len() == args_b.len() - && (matches!(method_a.name, sym::ln | sym::log2 | sym::log10) - || method_a.name == sym::log && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0])); - } - - false -} - -fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) { - // check if expression of the form x.logN() / y.logN() - if let ExprKind::Binary( - Spanned { - node: BinOpKind::Div, .. - }, - lhs, - rhs, - ) = expr.kind - && are_same_base_logs(cx, lhs, rhs) - && let ExprKind::MethodCall(_, largs_self, ..) = lhs.kind - && let ExprKind::MethodCall(_, rargs_self, ..) = rhs.kind - { - let mut app = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - SUBOPTIMAL_FLOPS, - expr.span, - "log base can be expressed more clearly", - "consider using", - format!( - "{}.log({})", - Sugg::hir_with_applicability(cx, largs_self, "_", &mut app).maybe_paren(), - Sugg::hir_with_applicability(cx, rargs_self, "_", &mut app), - ), - app, - ); - } -} - -fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { - if let ExprKind::Binary( - Spanned { - node: BinOpKind::Div, .. - }, - div_lhs, - div_rhs, - ) = expr.kind - && let ExprKind::Binary( - Spanned { - node: BinOpKind::Mul, .. - }, - mul_lhs, - mul_rhs, - ) = div_lhs.kind - && let ecx = ConstEvalCtxt::new(cx) - && let Some(rvalue) = ecx.eval(div_rhs) - && let Some(lvalue) = ecx.eval(mul_rhs) - { - // TODO: also check for constant values near PI/180 or 180/PI - if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) - && (F32(180_f32) == lvalue || F64(180_f64) == lvalue) - { - span_lint_and_then( - cx, - SUBOPTIMAL_FLOPS, - expr.span, - "conversion to degrees can be done more accurately", - |diag| { - let mut app = Applicability::MachineApplicable; - let recv = Sugg::hir_with_applicability(cx, mul_lhs, "num", &mut app); - let proposal = if let ExprKind::Lit(literal) = mul_lhs.kind - && let ast::LitKind::Float(ref value, float_type) = literal.node - && float_type == ast::LitFloatType::Unsuffixed - { - if value.as_str().ends_with('.') { - format!("{recv}0_f64.to_degrees()") - } else { - format!("{recv}_f64.to_degrees()") - } - } else { - format!("{}.to_degrees()", recv.maybe_paren()) - }; - diag.span_suggestion(expr.span, "consider using", proposal, app); - }, - ); - } else if (F32(180_f32) == rvalue || F64(180_f64) == rvalue) - && (F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue) - { - span_lint_and_then( - cx, - SUBOPTIMAL_FLOPS, - expr.span, - "conversion to radians can be done more accurately", - |diag| { - let mut app = Applicability::MachineApplicable; - let recv = Sugg::hir_with_applicability(cx, mul_lhs, "num", &mut app); - let proposal = if let ExprKind::Lit(literal) = mul_lhs.kind - && let ast::LitKind::Float(ref value, float_type) = literal.node - && float_type == ast::LitFloatType::Unsuffixed - { - if value.as_str().ends_with('.') { - format!("{recv}0_f64.to_radians()") - } else { - format!("{recv}_f64.to_radians()") - } - } else { - format!("{}.to_radians()", recv.maybe_paren()) - }; - diag.span_suggestion(expr.span, "consider using", proposal, app); - }, - ); - } - } -} - impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { // All of these operations are currently not const and are in std. @@ -750,22 +120,22 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic { if recv_ty.is_floating_point() && !is_no_std_crate(cx) && cx.ty_based_def(expr).opt_parent(cx).is_impl(cx) { match path.ident.name { - sym::ln => check_ln1p(cx, expr, receiver), - sym::log => check_log_base(cx, expr, receiver, args), - sym::powf => check_powf(cx, expr, receiver, args), - sym::powi => check_powi(cx, expr, receiver, args), - sym::sqrt => check_hypot(cx, expr, receiver), + sym::ln => ln1p::check(cx, expr, receiver), + sym::log => log_base::check(cx, expr, receiver, args), + sym::powf => powf::check(cx, expr, receiver, args), + sym::powi => powi::check(cx, expr, receiver, args), + sym::sqrt => hypot::check(cx, expr, receiver), _ => {}, } } } else { if !is_no_std_crate(cx) { - check_expm1(cx, expr); - check_mul_add(cx, expr); - check_custom_abs(cx, expr); - check_log_division(cx, expr); + expm1::check(cx, expr); + mul_add::check(cx, expr); + custom_abs::check(cx, expr); + log_division::check(cx, expr); } - check_radians(cx, expr); + radians::check(cx, expr); } } } diff --git a/clippy_lints/src/floating_point_arithmetic/mul_add.rs b/clippy_lints/src/floating_point_arithmetic/mul_add.rs new file mode 100644 index 000000000000..03a9d3b05f88 --- /dev/null +++ b/clippy_lints/src/floating_point_arithmetic/mul_add.rs @@ -0,0 +1,94 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::sugg::Sugg; +use clippy_utils::{get_parent_expr, has_ambiguous_literal_in_expr, sym}; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment}; +use rustc_lint::LateContext; +use rustc_span::source_map::Spanned; + +use super::SUBOPTIMAL_FLOPS; + +fn is_float_mul_expr<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> { + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Mul, .. + }, + lhs, + rhs, + ) = expr.kind + && cx.typeck_results().expr_ty(lhs).is_floating_point() + && cx.typeck_results().expr_ty(rhs).is_floating_point() + { + return Some((lhs, rhs)); + } + + None +} + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { + if let ExprKind::Binary( + Spanned { + node: op @ (BinOpKind::Add | BinOpKind::Sub), + .. + }, + lhs, + rhs, + ) = &expr.kind + { + if let Some(parent) = get_parent_expr(cx, expr) + && let ExprKind::MethodCall(PathSegment { ident: method, .. }, receiver, ..) = parent.kind + && method.name == sym::sqrt + // we don't care about the applicability as this is an early-return condition + && super::hypot::detect(cx, receiver, &mut Applicability::Unspecified).is_some() + { + return; + } + + let maybe_neg_sugg = |expr, app: &mut _| { + let sugg = Sugg::hir_with_applicability(cx, expr, "_", app); + if let BinOpKind::Sub = op { -sugg } else { sugg } + }; + + let mut app = Applicability::MachineApplicable; + let (recv, arg1, arg2) = if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, lhs) + && cx.typeck_results().expr_ty(rhs).is_floating_point() + { + ( + inner_lhs, + Sugg::hir_with_applicability(cx, inner_rhs, "_", &mut app), + maybe_neg_sugg(rhs, &mut app), + ) + } else if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, rhs) + && cx.typeck_results().expr_ty(lhs).is_floating_point() + { + ( + inner_lhs, + maybe_neg_sugg(inner_rhs, &mut app), + Sugg::hir_with_applicability(cx, lhs, "_", &mut app), + ) + } else { + return; + }; + + // Check if any variable in the expression has an ambiguous type (could be f32 or f64) + // see: https://github.com/rust-lang/rust-clippy/issues/14897 + if (matches!(recv.kind, ExprKind::Path(_)) || matches!(recv.kind, ExprKind::Call(_, _))) + && has_ambiguous_literal_in_expr(cx, recv) + { + return; + } + + span_lint_and_sugg( + cx, + SUBOPTIMAL_FLOPS, + expr.span, + "multiply and add expressions can be calculated more efficiently and accurately", + "consider using", + format!( + "{}.mul_add({arg1}, {arg2})", + super::lib::prepare_receiver_sugg(cx, recv, &mut app) + ), + app, + ); + } +} diff --git a/clippy_lints/src/floating_point_arithmetic/powf.rs b/clippy_lints/src/floating_point_arithmetic/powf.rs new file mode 100644 index 000000000000..8e4a7388e784 --- /dev/null +++ b/clippy_lints/src/floating_point_arithmetic/powf.rs @@ -0,0 +1,94 @@ +use clippy_utils::consts::Constant::{F32, F64}; +use clippy_utils::consts::{ConstEvalCtxt, Constant}; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::numeric_literal; +use clippy_utils::sugg::Sugg; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use std::f32::consts as f32_consts; +use std::f64::consts as f64_consts; + +use super::{IMPRECISE_FLOPS, SUBOPTIMAL_FLOPS}; + +// Returns an integer if the float constant is a whole number and it can be +// converted to an integer without loss of precision. For now we only check +// ranges [-16777215, 16777216) for type f32 as whole number floats outside +// this range are lossy and ambiguous. +#[expect(clippy::cast_possible_truncation)] +fn get_integer_from_float_constant(value: &Constant) -> Option { + match value { + F32(num) if num.fract() == 0.0 => { + if (-16_777_215.0..16_777_216.0).contains(num) { + Some(num.round() as i32) + } else { + None + } + }, + F64(num) if num.fract() == 0.0 => { + if (-2_147_483_648.0..2_147_483_648.0).contains(num) { + Some(num.round() as i32) + } else { + None + } + }, + _ => None, + } +} + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) { + // Check receiver + if let Some(value) = ConstEvalCtxt::new(cx).eval(receiver) + && let Some(method) = if F32(f32_consts::E) == value || F64(f64_consts::E) == value { + Some("exp") + } else if F32(2.0) == value || F64(2.0) == value { + Some("exp2") + } else { + None + } + { + span_lint_and_then( + cx, + SUBOPTIMAL_FLOPS, + expr.span, + "exponent for bases 2 and e can be computed more accurately", + |diag| { + let mut app = Applicability::MachineApplicable; + let recv = super::lib::prepare_receiver_sugg(cx, &args[0], &mut app); + diag.span_suggestion(expr.span, "consider using", format!("{recv}.{method}()"), app); + }, + ); + } + + // Check argument + if let Some(value) = ConstEvalCtxt::new(cx).eval(&args[0]) { + let mut app = Applicability::MachineApplicable; + let recv = Sugg::hir_with_applicability(cx, receiver, "_", &mut app).maybe_paren(); + let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value { + ( + SUBOPTIMAL_FLOPS, + "square-root of a number can be computed more efficiently and accurately", + format!("{recv}.sqrt()"), + ) + } else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value { + ( + IMPRECISE_FLOPS, + "cube-root of a number can be computed more accurately", + format!("{recv}.cbrt()"), + ) + } else if let Some(exponent) = get_integer_from_float_constant(&value) { + ( + SUBOPTIMAL_FLOPS, + "exponentiation with integer powers can be computed more efficiently", + format!( + "{recv}.powi({})", + numeric_literal::format(&exponent.to_string(), None, false) + ), + ) + } else { + return; + }; + + span_lint_and_sugg(cx, lint, expr.span, help, "consider using", suggestion, app); + } +} diff --git a/clippy_lints/src/floating_point_arithmetic/powi.rs b/clippy_lints/src/floating_point_arithmetic/powi.rs new file mode 100644 index 000000000000..a61a2a82c023 --- /dev/null +++ b/clippy_lints/src/floating_point_arithmetic/powi.rs @@ -0,0 +1,70 @@ +use clippy_utils::consts::ConstEvalCtxt; +use clippy_utils::consts::Constant::Int; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg::Sugg; +use clippy_utils::{get_parent_expr, sym}; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment}; +use rustc_lint::LateContext; +use rustc_span::source_map::Spanned; + +use super::SUBOPTIMAL_FLOPS; + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) { + if let Some(value) = ConstEvalCtxt::new(cx).eval(&args[0]) + && value == Int(2) + && let Some(parent) = get_parent_expr(cx, expr) + { + if let Some(grandparent) = get_parent_expr(cx, parent) + && let ExprKind::MethodCall(PathSegment { ident: method, .. }, receiver, ..) = grandparent.kind + && method.name == sym::sqrt + // we don't care about the applicability as this is an early-return condition + && super::hypot::detect(cx, receiver, &mut Applicability::Unspecified).is_some() + { + return; + } + + if let ExprKind::Binary( + Spanned { + node: op @ (BinOpKind::Add | BinOpKind::Sub), + .. + }, + lhs, + rhs, + ) = parent.kind + { + span_lint_and_then( + cx, + SUBOPTIMAL_FLOPS, + parent.span, + "multiply and add expressions can be calculated more efficiently and accurately", + |diag| { + let other_addend = if lhs.hir_id == expr.hir_id { rhs } else { lhs }; + + // Negate expr if original code has subtraction and expr is on the right side + let maybe_neg_sugg = |expr, hir_id, app: &mut _| { + let sugg = Sugg::hir_with_applicability(cx, expr, "_", app); + if matches!(op, BinOpKind::Sub) && hir_id == rhs.hir_id { + -sugg + } else { + sugg + } + }; + + let mut app = Applicability::MachineApplicable; + diag.span_suggestion( + parent.span, + "consider using", + format!( + "{}.mul_add({}, {})", + Sugg::hir_with_applicability(cx, receiver, "_", &mut app).maybe_paren(), + maybe_neg_sugg(receiver, expr.hir_id, &mut app), + maybe_neg_sugg(other_addend, other_addend.hir_id, &mut app), + ), + app, + ); + }, + ); + } + } +} diff --git a/clippy_lints/src/floating_point_arithmetic/radians.rs b/clippy_lints/src/floating_point_arithmetic/radians.rs new file mode 100644 index 000000000000..2021f00a97e8 --- /dev/null +++ b/clippy_lints/src/floating_point_arithmetic/radians.rs @@ -0,0 +1,89 @@ +use clippy_utils::consts::ConstEvalCtxt; +use clippy_utils::consts::Constant::{F32, F64}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg::Sugg; +use rustc_ast::ast; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::source_map::Spanned; +use std::f32::consts as f32_consts; +use std::f64::consts as f64_consts; + +use super::SUBOPTIMAL_FLOPS; + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Div, .. + }, + div_lhs, + div_rhs, + ) = expr.kind + && let ExprKind::Binary( + Spanned { + node: BinOpKind::Mul, .. + }, + mul_lhs, + mul_rhs, + ) = div_lhs.kind + && let ecx = ConstEvalCtxt::new(cx) + && let Some(rvalue) = ecx.eval(div_rhs) + && let Some(lvalue) = ecx.eval(mul_rhs) + { + // TODO: also check for constant values near PI/180 or 180/PI + if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) + && (F32(180_f32) == lvalue || F64(180_f64) == lvalue) + { + span_lint_and_then( + cx, + SUBOPTIMAL_FLOPS, + expr.span, + "conversion to degrees can be done more accurately", + |diag| { + let mut app = Applicability::MachineApplicable; + let recv = Sugg::hir_with_applicability(cx, mul_lhs, "num", &mut app); + let proposal = if let ExprKind::Lit(literal) = mul_lhs.kind + && let ast::LitKind::Float(ref value, float_type) = literal.node + && float_type == ast::LitFloatType::Unsuffixed + { + if value.as_str().ends_with('.') { + format!("{recv}0_f64.to_degrees()") + } else { + format!("{recv}_f64.to_degrees()") + } + } else { + format!("{}.to_degrees()", recv.maybe_paren()) + }; + diag.span_suggestion(expr.span, "consider using", proposal, app); + }, + ); + } else if (F32(180_f32) == rvalue || F64(180_f64) == rvalue) + && (F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue) + { + span_lint_and_then( + cx, + SUBOPTIMAL_FLOPS, + expr.span, + "conversion to radians can be done more accurately", + |diag| { + let mut app = Applicability::MachineApplicable; + let recv = Sugg::hir_with_applicability(cx, mul_lhs, "num", &mut app); + let proposal = if let ExprKind::Lit(literal) = mul_lhs.kind + && let ast::LitKind::Float(ref value, float_type) = literal.node + && float_type == ast::LitFloatType::Unsuffixed + { + if value.as_str().ends_with('.') { + format!("{recv}0_f64.to_radians()") + } else { + format!("{recv}_f64.to_radians()") + } + } else { + format!("{}.to_radians()", recv.maybe_paren()) + }; + diag.span_suggestion(expr.span, "consider using", proposal, app); + }, + ); + } + } +} From 092e522fa8f1de4fff005782ba198e6dcb8ce353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 7 Jan 2026 18:28:12 +0100 Subject: [PATCH 0445/1061] Move tests for assoc const bindings into dedicated directory --- src/tools/tidy/src/issues.txt | 7 +++--- .../const-projection-err.stock.stderr | 17 -------------- .../associated-const-bindings/ambiguity.rs} | 0 .../ambiguity.stderr} | 4 ++-- .../assoc-const-ty-mismatch.rs | 0 .../assoc-const-ty-mismatch.stderr | 0 .../associated-const-bindings}/assoc-const.rs | 0 .../bound-var-in-ty-not-wf.rs} | 0 .../bound-var-in-ty-not-wf.stderr} | 4 ++-- .../bound-var-in-ty.rs} | 0 .../coexisting-with-type-binding.rs} | 0 .../coherence.rs | 0 .../coherence.stderr | 0 .../const-bound-to-assoc-ty-99828.rs} | 0 .../const-bound-to-assoc-ty-99828.stderr} | 6 ++--- .../const-projection-err.rs | 0 .../const-projection-err.stderr | 0 .../const_evaluatable_unchecked.rs} | 0 .../equality-unused-issue-126729.rs | 0 .../equality_bound_with_infer.rs | 0 .../esc-bound-var-in-ty.rs} | 0 .../esc-bound-var-in-ty.stderr} | 2 +- .../issue-102335-const.rs | 0 .../issue-102335-const.stderr | 0 .../issue-105330.rs | 0 .../issue-105330.stderr | 0 .../associated-const-bindings}/issue-93835.rs | 0 .../issue-93835.stderr | 0 ...pes-with-generic-in-ace-no-feature-gate.rs | 0 ...with-generic-in-ace-no-feature-gate.stderr | 0 .../mismatched-types-with-generic-in-ace.rs | 0 ...ismatched-types-with-generic-in-ace.stderr | 0 .../associated-const-bindings/missing.rs} | 0 .../associated-const-bindings/missing.stderr} | 6 ++--- .../associated-const-bindings/param-in-ty.rs} | 0 .../param-in-ty.stderr} | 22 +++++++++---------- .../projection-unspecified-but-bounded.rs | 0 .../projection-unspecified-but-bounded.stderr | 0 .../associated-const-bindings/supertraits.rs} | 0 .../unbraced-enum-variant.rs} | 0 .../unbraced-enum-variant.stderr} | 16 +++++++------- .../unconstrained_impl_param.rs | 0 .../unconstrained_impl_param.stderr | 0 .../using-fnptr-as-type_const.rs | 0 .../using-fnptr-as-type_const.stderr | 0 45 files changed, 33 insertions(+), 51 deletions(-) delete mode 100644 tests/ui/associated-type-bounds/const-projection-err.stock.stderr rename tests/ui/{associated-consts/assoc-const-eq-ambiguity.rs => const-generics/associated-const-bindings/ambiguity.rs} (100%) rename tests/ui/{associated-consts/assoc-const-eq-ambiguity.stderr => const-generics/associated-const-bindings/ambiguity.stderr} (92%) rename tests/ui/{associated-consts => const-generics/associated-const-bindings}/assoc-const-ty-mismatch.rs (100%) rename tests/ui/{associated-consts => const-generics/associated-const-bindings}/assoc-const-ty-mismatch.stderr (100%) rename tests/ui/{associated-consts => const-generics/associated-const-bindings}/assoc-const.rs (100%) rename tests/ui/{associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs => const-generics/associated-const-bindings/bound-var-in-ty-not-wf.rs} (100%) rename tests/ui/{associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr => const-generics/associated-const-bindings/bound-var-in-ty-not-wf.stderr} (73%) rename tests/ui/{associated-consts/assoc-const-eq-bound-var-in-ty.rs => const-generics/associated-const-bindings/bound-var-in-ty.rs} (100%) rename tests/ui/{associated-consts/assoc-const-eq-ty-alias-noninteracting.rs => const-generics/associated-const-bindings/coexisting-with-type-binding.rs} (100%) rename tests/ui/const-generics/{associated_const_equality => associated-const-bindings}/coherence.rs (100%) rename tests/ui/const-generics/{associated_const_equality => associated-const-bindings}/coherence.stderr (100%) rename tests/ui/{associated-type-bounds/issue-99828.rs => const-generics/associated-const-bindings/const-bound-to-assoc-ty-99828.rs} (100%) rename tests/ui/{associated-type-bounds/issue-99828.stderr => const-generics/associated-const-bindings/const-bound-to-assoc-ty-99828.stderr} (91%) rename tests/ui/{associated-type-bounds => const-generics/associated-const-bindings}/const-projection-err.rs (100%) rename tests/ui/{associated-type-bounds => const-generics/associated-const-bindings}/const-projection-err.stderr (100%) rename tests/ui/{associated-consts/assoc-const-eq-const_evaluatable_unchecked.rs => const-generics/associated-const-bindings/const_evaluatable_unchecked.rs} (100%) rename tests/ui/{associated-consts => const-generics/associated-const-bindings}/equality-unused-issue-126729.rs (100%) rename tests/ui/const-generics/{associated_const_equality => associated-const-bindings}/equality_bound_with_infer.rs (100%) rename tests/ui/{associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs => const-generics/associated-const-bindings/esc-bound-var-in-ty.rs} (100%) rename tests/ui/{associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr => const-generics/associated-const-bindings/esc-bound-var-in-ty.stderr} (89%) rename tests/ui/{associated-consts => const-generics/associated-const-bindings}/issue-102335-const.rs (100%) rename tests/ui/{associated-consts => const-generics/associated-const-bindings}/issue-102335-const.stderr (100%) rename tests/ui/{associated-consts => const-generics/associated-const-bindings}/issue-105330.rs (100%) rename tests/ui/{associated-consts => const-generics/associated-const-bindings}/issue-105330.stderr (100%) rename tests/ui/{associated-consts => const-generics/associated-const-bindings}/issue-93835.rs (100%) rename tests/ui/{associated-consts => const-generics/associated-const-bindings}/issue-93835.stderr (100%) rename tests/ui/const-generics/{associated_const_equality => associated-const-bindings}/mismatched-types-with-generic-in-ace-no-feature-gate.rs (100%) rename tests/ui/const-generics/{associated_const_equality => associated-const-bindings}/mismatched-types-with-generic-in-ace-no-feature-gate.stderr (100%) rename tests/ui/const-generics/{associated_const_equality => associated-const-bindings}/mismatched-types-with-generic-in-ace.rs (100%) rename tests/ui/const-generics/{associated_const_equality => associated-const-bindings}/mismatched-types-with-generic-in-ace.stderr (100%) rename tests/ui/{associated-consts/assoc-const-eq-missing.rs => const-generics/associated-const-bindings/missing.rs} (100%) rename tests/ui/{associated-consts/assoc-const-eq-missing.stderr => const-generics/associated-const-bindings/missing.stderr} (82%) rename tests/ui/{associated-consts/assoc-const-eq-param-in-ty.rs => const-generics/associated-const-bindings/param-in-ty.rs} (100%) rename tests/ui/{associated-consts/assoc-const-eq-param-in-ty.stderr => const-generics/associated-const-bindings/param-in-ty.stderr} (89%) rename tests/ui/{associated-consts => const-generics/associated-const-bindings}/projection-unspecified-but-bounded.rs (100%) rename tests/ui/{associated-consts => const-generics/associated-const-bindings}/projection-unspecified-but-bounded.stderr (100%) rename tests/ui/{associated-consts/assoc-const-eq-supertraits.rs => const-generics/associated-const-bindings/supertraits.rs} (100%) rename tests/ui/const-generics/{assoc_const_eq_diagnostic.rs => associated-const-bindings/unbraced-enum-variant.rs} (100%) rename tests/ui/const-generics/{assoc_const_eq_diagnostic.stderr => associated-const-bindings/unbraced-enum-variant.stderr} (87%) rename tests/ui/const-generics/{associated_const_equality => associated-const-bindings}/unconstrained_impl_param.rs (100%) rename tests/ui/const-generics/{associated_const_equality => associated-const-bindings}/unconstrained_impl_param.stderr (100%) rename tests/ui/const-generics/{mgca => associated-const-bindings}/using-fnptr-as-type_const.rs (100%) rename tests/ui/const-generics/{mgca => associated-const-bindings}/using-fnptr-as-type_const.stderr (100%) diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 45187a0b6450..0b7fbad2a8a4 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -33,8 +33,6 @@ ui/asm/issue-99122.rs ui/asm/x86_64/issue-82869.rs ui/asm/x86_64/issue-89875.rs ui/asm/x86_64/issue-96797.rs -ui/associated-consts/issue-102335-const.rs -ui/associated-consts/issue-105330.rs ui/associated-consts/issue-110933.rs ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.rs ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.rs @@ -45,7 +43,6 @@ ui/associated-consts/issue-63496.rs ui/associated-consts/issue-69020-assoc-const-arith-overflow.rs ui/associated-consts/issue-88599-ref-self.rs ui/associated-consts/issue-93775.rs -ui/associated-consts/issue-93835.rs ui/associated-inherent-types/issue-104260.rs ui/associated-inherent-types/issue-109071.rs ui/associated-inherent-types/issue-109299-1.rs @@ -70,7 +67,6 @@ ui/associated-type-bounds/issue-73818.rs ui/associated-type-bounds/issue-79949.rs ui/associated-type-bounds/issue-81193.rs ui/associated-type-bounds/issue-83017.rs -ui/associated-type-bounds/issue-99828.rs ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.rs ui/associated-types/issue-18655.rs ui/associated-types/issue-19081.rs @@ -499,6 +495,9 @@ ui/confuse-field-and-method/issue-18343.rs ui/confuse-field-and-method/issue-2392.rs ui/confuse-field-and-method/issue-32128.rs ui/confuse-field-and-method/issue-33784.rs +ui/const-generics/associated-const-bindings/issue-102335-const.rs +ui/const-generics/associated-const-bindings/issue-105330.rs +ui/const-generics/associated-const-bindings/issue-93835.rs ui/const-generics/generic_arg_infer/issue-91614.rs ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.rs ui/const-generics/generic_const_exprs/issue-100217.rs diff --git a/tests/ui/associated-type-bounds/const-projection-err.stock.stderr b/tests/ui/associated-type-bounds/const-projection-err.stock.stderr deleted file mode 100644 index 0cacec26aaee..000000000000 --- a/tests/ui/associated-type-bounds/const-projection-err.stock.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0271]: type mismatch resolving `::A == 1` - --> $DIR/const-projection-err.rs:16:11 - | -LL | foo::(); - | ^ expected `1`, found `0` - | - = note: expected constant `1` - found constant `0` -note: required by a bound in `foo` - --> $DIR/const-projection-err.rs:13:28 - | -LL | fn foo>() {} - | ^^^^^ required by this bound in `foo` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/associated-consts/assoc-const-eq-ambiguity.rs b/tests/ui/const-generics/associated-const-bindings/ambiguity.rs similarity index 100% rename from tests/ui/associated-consts/assoc-const-eq-ambiguity.rs rename to tests/ui/const-generics/associated-const-bindings/ambiguity.rs diff --git a/tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr b/tests/ui/const-generics/associated-const-bindings/ambiguity.stderr similarity index 92% rename from tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr rename to tests/ui/const-generics/associated-const-bindings/ambiguity.stderr index cf4805aaf592..a14afe9d6923 100644 --- a/tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr +++ b/tests/ui/const-generics/associated-const-bindings/ambiguity.stderr @@ -1,5 +1,5 @@ error[E0222]: ambiguous associated constant `K` in bounds of `Trait0` - --> $DIR/assoc-const-eq-ambiguity.rs:13:25 + --> $DIR/ambiguity.rs:13:25 | LL | const K: (); | ----------- @@ -17,7 +17,7 @@ LL | fn take0(_: impl Trait0) {} T: Parent0::K = const { } error[E0222]: ambiguous associated constant `C` in bounds of `Trait1` - --> $DIR/assoc-const-eq-ambiguity.rs:26:25 + --> $DIR/ambiguity.rs:26:25 | LL | const C: i32; | ------------ ambiguous `C` from `Parent1` diff --git a/tests/ui/associated-consts/assoc-const-ty-mismatch.rs b/tests/ui/const-generics/associated-const-bindings/assoc-const-ty-mismatch.rs similarity index 100% rename from tests/ui/associated-consts/assoc-const-ty-mismatch.rs rename to tests/ui/const-generics/associated-const-bindings/assoc-const-ty-mismatch.rs diff --git a/tests/ui/associated-consts/assoc-const-ty-mismatch.stderr b/tests/ui/const-generics/associated-const-bindings/assoc-const-ty-mismatch.stderr similarity index 100% rename from tests/ui/associated-consts/assoc-const-ty-mismatch.stderr rename to tests/ui/const-generics/associated-const-bindings/assoc-const-ty-mismatch.stderr diff --git a/tests/ui/associated-consts/assoc-const.rs b/tests/ui/const-generics/associated-const-bindings/assoc-const.rs similarity index 100% rename from tests/ui/associated-consts/assoc-const.rs rename to tests/ui/const-generics/associated-const-bindings/assoc-const.rs diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs b/tests/ui/const-generics/associated-const-bindings/bound-var-in-ty-not-wf.rs similarity index 100% rename from tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs rename to tests/ui/const-generics/associated-const-bindings/bound-var-in-ty-not-wf.rs diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr b/tests/ui/const-generics/associated-const-bindings/bound-var-in-ty-not-wf.stderr similarity index 73% rename from tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr rename to tests/ui/const-generics/associated-const-bindings/bound-var-in-ty-not-wf.stderr index 76868715b861..a4f97525b515 100644 --- a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr +++ b/tests/ui/const-generics/associated-const-bindings/bound-var-in-ty-not-wf.stderr @@ -1,11 +1,11 @@ error: higher-ranked subtype error - --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:13 + --> $DIR/bound-var-in-ty-not-wf.rs:21:13 | LL | K = const { () } | ^^^^^^^^^^^^ error: higher-ranked subtype error - --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:13 + --> $DIR/bound-var-in-ty-not-wf.rs:21:13 | LL | K = const { () } | ^^^^^^^^^^^^ diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty.rs b/tests/ui/const-generics/associated-const-bindings/bound-var-in-ty.rs similarity index 100% rename from tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty.rs rename to tests/ui/const-generics/associated-const-bindings/bound-var-in-ty.rs diff --git a/tests/ui/associated-consts/assoc-const-eq-ty-alias-noninteracting.rs b/tests/ui/const-generics/associated-const-bindings/coexisting-with-type-binding.rs similarity index 100% rename from tests/ui/associated-consts/assoc-const-eq-ty-alias-noninteracting.rs rename to tests/ui/const-generics/associated-const-bindings/coexisting-with-type-binding.rs diff --git a/tests/ui/const-generics/associated_const_equality/coherence.rs b/tests/ui/const-generics/associated-const-bindings/coherence.rs similarity index 100% rename from tests/ui/const-generics/associated_const_equality/coherence.rs rename to tests/ui/const-generics/associated-const-bindings/coherence.rs diff --git a/tests/ui/const-generics/associated_const_equality/coherence.stderr b/tests/ui/const-generics/associated-const-bindings/coherence.stderr similarity index 100% rename from tests/ui/const-generics/associated_const_equality/coherence.stderr rename to tests/ui/const-generics/associated-const-bindings/coherence.stderr diff --git a/tests/ui/associated-type-bounds/issue-99828.rs b/tests/ui/const-generics/associated-const-bindings/const-bound-to-assoc-ty-99828.rs similarity index 100% rename from tests/ui/associated-type-bounds/issue-99828.rs rename to tests/ui/const-generics/associated-const-bindings/const-bound-to-assoc-ty-99828.rs diff --git a/tests/ui/associated-type-bounds/issue-99828.stderr b/tests/ui/const-generics/associated-const-bindings/const-bound-to-assoc-ty-99828.stderr similarity index 91% rename from tests/ui/associated-type-bounds/issue-99828.stderr rename to tests/ui/const-generics/associated-const-bindings/const-bound-to-assoc-ty-99828.stderr index e1dc1f07d9cb..692e511fb469 100644 --- a/tests/ui/associated-type-bounds/issue-99828.stderr +++ b/tests/ui/const-generics/associated-const-bindings/const-bound-to-assoc-ty-99828.stderr @@ -1,5 +1,5 @@ error[E0658]: associated const equality is incomplete - --> $DIR/issue-99828.rs:1:43 + --> $DIR/const-bound-to-assoc-ty-99828.rs:1:43 | LL | fn get_iter(vec: &[i32]) -> impl Iterator + '_ { | ^^^^^^^^^ @@ -9,7 +9,7 @@ LL | fn get_iter(vec: &[i32]) -> impl Iterator + '_ { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: expected type, found constant - --> $DIR/issue-99828.rs:1:50 + --> $DIR/const-bound-to-assoc-ty-99828.rs:1:50 | LL | fn get_iter(vec: &[i32]) -> impl Iterator + '_ { | ---- ^^ unexpected constant @@ -20,7 +20,7 @@ note: the associated type is defined here --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL error: expected type, found constant - --> $DIR/issue-99828.rs:1:50 + --> $DIR/const-bound-to-assoc-ty-99828.rs:1:50 | LL | fn get_iter(vec: &[i32]) -> impl Iterator + '_ { | ---- ^^ unexpected constant diff --git a/tests/ui/associated-type-bounds/const-projection-err.rs b/tests/ui/const-generics/associated-const-bindings/const-projection-err.rs similarity index 100% rename from tests/ui/associated-type-bounds/const-projection-err.rs rename to tests/ui/const-generics/associated-const-bindings/const-projection-err.rs diff --git a/tests/ui/associated-type-bounds/const-projection-err.stderr b/tests/ui/const-generics/associated-const-bindings/const-projection-err.stderr similarity index 100% rename from tests/ui/associated-type-bounds/const-projection-err.stderr rename to tests/ui/const-generics/associated-const-bindings/const-projection-err.stderr diff --git a/tests/ui/associated-consts/assoc-const-eq-const_evaluatable_unchecked.rs b/tests/ui/const-generics/associated-const-bindings/const_evaluatable_unchecked.rs similarity index 100% rename from tests/ui/associated-consts/assoc-const-eq-const_evaluatable_unchecked.rs rename to tests/ui/const-generics/associated-const-bindings/const_evaluatable_unchecked.rs diff --git a/tests/ui/associated-consts/equality-unused-issue-126729.rs b/tests/ui/const-generics/associated-const-bindings/equality-unused-issue-126729.rs similarity index 100% rename from tests/ui/associated-consts/equality-unused-issue-126729.rs rename to tests/ui/const-generics/associated-const-bindings/equality-unused-issue-126729.rs diff --git a/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.rs b/tests/ui/const-generics/associated-const-bindings/equality_bound_with_infer.rs similarity index 100% rename from tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.rs rename to tests/ui/const-generics/associated-const-bindings/equality_bound_with_infer.rs diff --git a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs b/tests/ui/const-generics/associated-const-bindings/esc-bound-var-in-ty.rs similarity index 100% rename from tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs rename to tests/ui/const-generics/associated-const-bindings/esc-bound-var-in-ty.rs diff --git a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr b/tests/ui/const-generics/associated-const-bindings/esc-bound-var-in-ty.stderr similarity index 89% rename from tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr rename to tests/ui/const-generics/associated-const-bindings/esc-bound-var-in-ty.stderr index ef861cb7f49a..122893662933 100644 --- a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr +++ b/tests/ui/const-generics/associated-const-bindings/esc-bound-var-in-ty.stderr @@ -1,5 +1,5 @@ error: the type of the associated constant `K` cannot capture late-bound generic parameters - --> $DIR/assoc-const-eq-esc-bound-var-in-ty.rs:15:35 + --> $DIR/esc-bound-var-in-ty.rs:15:35 | LL | fn take(_: impl for<'r> Trait<'r, K = const { &() }>) {} | -- ^ its type cannot capture the late-bound lifetime parameter `'r` diff --git a/tests/ui/associated-consts/issue-102335-const.rs b/tests/ui/const-generics/associated-const-bindings/issue-102335-const.rs similarity index 100% rename from tests/ui/associated-consts/issue-102335-const.rs rename to tests/ui/const-generics/associated-const-bindings/issue-102335-const.rs diff --git a/tests/ui/associated-consts/issue-102335-const.stderr b/tests/ui/const-generics/associated-const-bindings/issue-102335-const.stderr similarity index 100% rename from tests/ui/associated-consts/issue-102335-const.stderr rename to tests/ui/const-generics/associated-const-bindings/issue-102335-const.stderr diff --git a/tests/ui/associated-consts/issue-105330.rs b/tests/ui/const-generics/associated-const-bindings/issue-105330.rs similarity index 100% rename from tests/ui/associated-consts/issue-105330.rs rename to tests/ui/const-generics/associated-const-bindings/issue-105330.rs diff --git a/tests/ui/associated-consts/issue-105330.stderr b/tests/ui/const-generics/associated-const-bindings/issue-105330.stderr similarity index 100% rename from tests/ui/associated-consts/issue-105330.stderr rename to tests/ui/const-generics/associated-const-bindings/issue-105330.stderr diff --git a/tests/ui/associated-consts/issue-93835.rs b/tests/ui/const-generics/associated-const-bindings/issue-93835.rs similarity index 100% rename from tests/ui/associated-consts/issue-93835.rs rename to tests/ui/const-generics/associated-const-bindings/issue-93835.rs diff --git a/tests/ui/associated-consts/issue-93835.stderr b/tests/ui/const-generics/associated-const-bindings/issue-93835.stderr similarity index 100% rename from tests/ui/associated-consts/issue-93835.stderr rename to tests/ui/const-generics/associated-const-bindings/issue-93835.stderr diff --git a/tests/ui/const-generics/associated_const_equality/mismatched-types-with-generic-in-ace-no-feature-gate.rs b/tests/ui/const-generics/associated-const-bindings/mismatched-types-with-generic-in-ace-no-feature-gate.rs similarity index 100% rename from tests/ui/const-generics/associated_const_equality/mismatched-types-with-generic-in-ace-no-feature-gate.rs rename to tests/ui/const-generics/associated-const-bindings/mismatched-types-with-generic-in-ace-no-feature-gate.rs diff --git a/tests/ui/const-generics/associated_const_equality/mismatched-types-with-generic-in-ace-no-feature-gate.stderr b/tests/ui/const-generics/associated-const-bindings/mismatched-types-with-generic-in-ace-no-feature-gate.stderr similarity index 100% rename from tests/ui/const-generics/associated_const_equality/mismatched-types-with-generic-in-ace-no-feature-gate.stderr rename to tests/ui/const-generics/associated-const-bindings/mismatched-types-with-generic-in-ace-no-feature-gate.stderr diff --git a/tests/ui/const-generics/associated_const_equality/mismatched-types-with-generic-in-ace.rs b/tests/ui/const-generics/associated-const-bindings/mismatched-types-with-generic-in-ace.rs similarity index 100% rename from tests/ui/const-generics/associated_const_equality/mismatched-types-with-generic-in-ace.rs rename to tests/ui/const-generics/associated-const-bindings/mismatched-types-with-generic-in-ace.rs diff --git a/tests/ui/const-generics/associated_const_equality/mismatched-types-with-generic-in-ace.stderr b/tests/ui/const-generics/associated-const-bindings/mismatched-types-with-generic-in-ace.stderr similarity index 100% rename from tests/ui/const-generics/associated_const_equality/mismatched-types-with-generic-in-ace.stderr rename to tests/ui/const-generics/associated-const-bindings/mismatched-types-with-generic-in-ace.stderr diff --git a/tests/ui/associated-consts/assoc-const-eq-missing.rs b/tests/ui/const-generics/associated-const-bindings/missing.rs similarity index 100% rename from tests/ui/associated-consts/assoc-const-eq-missing.rs rename to tests/ui/const-generics/associated-const-bindings/missing.rs diff --git a/tests/ui/associated-consts/assoc-const-eq-missing.stderr b/tests/ui/const-generics/associated-const-bindings/missing.stderr similarity index 82% rename from tests/ui/associated-consts/assoc-const-eq-missing.stderr rename to tests/ui/const-generics/associated-const-bindings/missing.stderr index 318c85dcfd6f..cbcfcf4c62d1 100644 --- a/tests/ui/associated-consts/assoc-const-eq-missing.stderr +++ b/tests/ui/const-generics/associated-const-bindings/missing.stderr @@ -1,17 +1,17 @@ error[E0220]: associated constant `Z` not found for `Foo` - --> $DIR/assoc-const-eq-missing.rs:14:16 + --> $DIR/missing.rs:14:16 | LL | fn foo1>() {} | ^ help: there is an associated constant with a similar name: `N` error[E0220]: associated type `Z` not found for `Foo` - --> $DIR/assoc-const-eq-missing.rs:16:16 + --> $DIR/missing.rs:16:16 | LL | fn foo2>() {} | ^ associated type `Z` not found error[E0220]: associated constant `Z` not found for `Foo` - --> $DIR/assoc-const-eq-missing.rs:18:16 + --> $DIR/missing.rs:18:16 | LL | fn foo3>() {} | ^ help: there is an associated constant with a similar name: `N` diff --git a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs b/tests/ui/const-generics/associated-const-bindings/param-in-ty.rs similarity index 100% rename from tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs rename to tests/ui/const-generics/associated-const-bindings/param-in-ty.rs diff --git a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr b/tests/ui/const-generics/associated-const-bindings/param-in-ty.stderr similarity index 89% rename from tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr rename to tests/ui/const-generics/associated-const-bindings/param-in-ty.stderr index b742e68044b0..719dad816a6f 100644 --- a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr +++ b/tests/ui/const-generics/associated-const-bindings/param-in-ty.stderr @@ -1,5 +1,5 @@ error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:22:29 + --> $DIR/param-in-ty.rs:22:29 | LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( | -- the lifetime parameter `'r` is defined here @@ -10,7 +10,7 @@ LL | _: impl Trait<'r, A, Q, K = const { loop {} }> = note: `K` has type `&'r [A; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:22:29 + --> $DIR/param-in-ty.rs:22:29 | LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( | - the type parameter `A` is defined here @@ -21,7 +21,7 @@ LL | _: impl Trait<'r, A, Q, K = const { loop {} }> = note: `K` has type `&'r [A; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:22:29 + --> $DIR/param-in-ty.rs:22:29 | LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( | - the const parameter `Q` is defined here @@ -32,7 +32,7 @@ LL | _: impl Trait<'r, A, Q, K = const { loop {} }> = note: `K` has type `&'r [A; Q]` error: the type of the associated constant `SELF` must not depend on `impl Trait` - --> $DIR/assoc-const-eq-param-in-ty.rs:39:26 + --> $DIR/param-in-ty.rs:39:26 | LL | fn take1(_: impl Project) {} | -------------^^^^------------ @@ -41,7 +41,7 @@ LL | fn take1(_: impl Project) {} | the `impl Trait` is specified here error: the type of the associated constant `SELF` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:44:21 + --> $DIR/param-in-ty.rs:44:21 | LL | fn take2>(_: P) {} | - ^^^^ its type must not depend on the type parameter `P` @@ -51,7 +51,7 @@ LL | fn take2>(_: P) {} = note: `SELF` has type `P` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 + --> $DIR/param-in-ty.rs:53:52 | LL | trait Iface<'r>: ConstParamTy_ { | -- the lifetime parameter `'r` is defined here @@ -62,7 +62,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> = note: `K` has type `&'r [Self; Q]` error: the type of the associated constant `K` must not depend on `Self` - --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 + --> $DIR/param-in-ty.rs:53:52 | LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | ^ its type must not depend on `Self` @@ -70,7 +70,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> = note: `K` has type `&'r [Self; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 + --> $DIR/param-in-ty.rs:53:52 | LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | - ^ its type must not depend on the const parameter `Q` @@ -80,7 +80,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> = note: `K` has type `&'r [Self; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 + --> $DIR/param-in-ty.rs:53:52 | LL | trait Iface<'r>: ConstParamTy_ { | -- the lifetime parameter `'r` is defined here @@ -92,7 +92,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: the type of the associated constant `K` must not depend on `Self` - --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 + --> $DIR/param-in-ty.rs:53:52 | LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | ^ its type must not depend on `Self` @@ -101,7 +101,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 + --> $DIR/param-in-ty.rs:53:52 | LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | - ^ its type must not depend on the const parameter `Q` diff --git a/tests/ui/associated-consts/projection-unspecified-but-bounded.rs b/tests/ui/const-generics/associated-const-bindings/projection-unspecified-but-bounded.rs similarity index 100% rename from tests/ui/associated-consts/projection-unspecified-but-bounded.rs rename to tests/ui/const-generics/associated-const-bindings/projection-unspecified-but-bounded.rs diff --git a/tests/ui/associated-consts/projection-unspecified-but-bounded.stderr b/tests/ui/const-generics/associated-const-bindings/projection-unspecified-but-bounded.stderr similarity index 100% rename from tests/ui/associated-consts/projection-unspecified-but-bounded.stderr rename to tests/ui/const-generics/associated-const-bindings/projection-unspecified-but-bounded.stderr diff --git a/tests/ui/associated-consts/assoc-const-eq-supertraits.rs b/tests/ui/const-generics/associated-const-bindings/supertraits.rs similarity index 100% rename from tests/ui/associated-consts/assoc-const-eq-supertraits.rs rename to tests/ui/const-generics/associated-const-bindings/supertraits.rs diff --git a/tests/ui/const-generics/assoc_const_eq_diagnostic.rs b/tests/ui/const-generics/associated-const-bindings/unbraced-enum-variant.rs similarity index 100% rename from tests/ui/const-generics/assoc_const_eq_diagnostic.rs rename to tests/ui/const-generics/associated-const-bindings/unbraced-enum-variant.rs diff --git a/tests/ui/const-generics/assoc_const_eq_diagnostic.stderr b/tests/ui/const-generics/associated-const-bindings/unbraced-enum-variant.stderr similarity index 87% rename from tests/ui/const-generics/assoc_const_eq_diagnostic.stderr rename to tests/ui/const-generics/associated-const-bindings/unbraced-enum-variant.stderr index 05e0ec93d494..6608df2ebfbc 100644 --- a/tests/ui/const-generics/assoc_const_eq_diagnostic.stderr +++ b/tests/ui/const-generics/associated-const-bindings/unbraced-enum-variant.stderr @@ -1,5 +1,5 @@ error[E0573]: expected type, found variant `Mode::Cool` - --> $DIR/assoc_const_eq_diagnostic.rs:13:35 + --> $DIR/unbraced-enum-variant.rs:13:35 | LL | pub trait CoolStuff: Parse {} | ^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | pub trait CoolStuff: Parse {} | help: try using the variant's enum: `Mode` error[E0573]: expected type, found variant `Mode::Cool` - --> $DIR/assoc_const_eq_diagnostic.rs:19:17 + --> $DIR/unbraced-enum-variant.rs:19:17 | LL | fn no_help() -> Mode::Cool {} | ^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | fn no_help() -> Mode::Cool {} | help: try using the variant's enum: `Mode` error: expected constant, found type - --> $DIR/assoc_const_eq_diagnostic.rs:13:35 + --> $DIR/unbraced-enum-variant.rs:13:35 | LL | pub trait CoolStuff: Parse {} | ---- ^^^^^^^^^^ unexpected type @@ -25,7 +25,7 @@ LL | pub trait CoolStuff: Parse {} | expected a constant because of this associated constant | note: the associated constant is defined here - --> $DIR/assoc_const_eq_diagnostic.rs:10:5 + --> $DIR/unbraced-enum-variant.rs:10:5 | LL | const MODE: Mode; | ^^^^^^^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | pub trait CoolStuff: Parse {} | + + error: expected constant, found type - --> $DIR/assoc_const_eq_diagnostic.rs:13:35 + --> $DIR/unbraced-enum-variant.rs:13:35 | LL | pub trait CoolStuff: Parse {} | ---- ^^^^^^^^^^ unexpected type @@ -43,7 +43,7 @@ LL | pub trait CoolStuff: Parse {} | expected a constant because of this associated constant | note: the associated constant is defined here - --> $DIR/assoc_const_eq_diagnostic.rs:10:5 + --> $DIR/unbraced-enum-variant.rs:10:5 | LL | const MODE: Mode; | ^^^^^^^^^^^^^^^^ @@ -54,7 +54,7 @@ LL | pub trait CoolStuff: Parse {} | + + error: expected constant, found type - --> $DIR/assoc_const_eq_diagnostic.rs:13:35 + --> $DIR/unbraced-enum-variant.rs:13:35 | LL | pub trait CoolStuff: Parse {} | ---- ^^^^^^^^^^ unexpected type @@ -62,7 +62,7 @@ LL | pub trait CoolStuff: Parse {} | expected a constant because of this associated constant | note: the associated constant is defined here - --> $DIR/assoc_const_eq_diagnostic.rs:10:5 + --> $DIR/unbraced-enum-variant.rs:10:5 | LL | const MODE: Mode; | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs b/tests/ui/const-generics/associated-const-bindings/unconstrained_impl_param.rs similarity index 100% rename from tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs rename to tests/ui/const-generics/associated-const-bindings/unconstrained_impl_param.rs diff --git a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr b/tests/ui/const-generics/associated-const-bindings/unconstrained_impl_param.stderr similarity index 100% rename from tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr rename to tests/ui/const-generics/associated-const-bindings/unconstrained_impl_param.stderr diff --git a/tests/ui/const-generics/mgca/using-fnptr-as-type_const.rs b/tests/ui/const-generics/associated-const-bindings/using-fnptr-as-type_const.rs similarity index 100% rename from tests/ui/const-generics/mgca/using-fnptr-as-type_const.rs rename to tests/ui/const-generics/associated-const-bindings/using-fnptr-as-type_const.rs diff --git a/tests/ui/const-generics/mgca/using-fnptr-as-type_const.stderr b/tests/ui/const-generics/associated-const-bindings/using-fnptr-as-type_const.stderr similarity index 100% rename from tests/ui/const-generics/mgca/using-fnptr-as-type_const.stderr rename to tests/ui/const-generics/associated-const-bindings/using-fnptr-as-type_const.stderr From b144a11d2cefaac358ea2e7f103893197fe58b67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 7 Jan 2026 13:20:18 +0100 Subject: [PATCH 0446/1061] Replace more mentions of `associated_const_equality` --- compiler/rustc_ast/src/ast.rs | 2 +- compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs | 3 +-- compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs | 3 +-- .../{associated-const-equality.rs => assoc-const-bindings.rs} | 0 5 files changed, 4 insertions(+), 6 deletions(-) rename tests/ui/generic-const-items/{associated-const-equality.rs => assoc-const-bindings.rs} (100%) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 7c922417ee29..4ad32d7c9fd9 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2394,7 +2394,7 @@ impl FnSig { /// * the `G = Ty` in `Trait = Ty>` /// * the `A: Bound` in `Trait` /// * the `RetTy` in `Trait(ArgTy, ArgTy) -> RetTy` -/// * the `C = { Ct }` in `Trait` (feature `associated_const_equality`) +/// * the `C = { Ct }` in `Trait` (feature `min_generic_const_args`) /// * the `f(..): Bound` in `Trait` (feature `return_type_notation`) #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct AssocItemConstraint { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e13782282891..1f3831243139 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3298,7 +3298,7 @@ pub enum ImplItemKind<'hir> { /// * the `G = Ty` in `Trait = Ty>` /// * the `A: Bound` in `Trait` /// * the `RetTy` in `Trait(ArgTy, ArgTy) -> RetTy` -/// * the `C = { Ct }` in `Trait` (feature `associated_const_equality`) +/// * the `C = { Ct }` in `Trait` (feature `min_generic_const_args`) /// * the `f(..): Bound` in `Trait` (feature `return_type_notation`) #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct AssocItemConstraint<'hir> { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 9ae6a9fac504..72d21371f66c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -575,8 +575,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // FIXME: point at the type params that don't have appropriate lifetimes: // struct S1 Fn(&i32, &i32) -> &'a i32>(F); // ---- ---- ^^^^^^^ - // NOTE(associated_const_equality): This error should be impossible to trigger - // with associated const equality constraints. + // NOTE(mgca): This error should be impossible to trigger with assoc const bindings. self.validate_late_bound_regions( late_bound_in_projection_ty, late_bound_in_term, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index edb79592e6c5..2aed66d27e96 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -503,8 +503,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // FIXME: point at the type params that don't have appropriate lifetimes: // struct S1 Fn(&i32, &i32) -> &'a i32>(F); // ---- ---- ^^^^^^^ - // NOTE(associated_const_equality): This error should be impossible to trigger - // with associated const equality constraints. + // NOTE(mgca): This error should be impossible to trigger with assoc const bindings. self.validate_late_bound_regions( late_bound_in_projection_term, late_bound_in_term, diff --git a/tests/ui/generic-const-items/associated-const-equality.rs b/tests/ui/generic-const-items/assoc-const-bindings.rs similarity index 100% rename from tests/ui/generic-const-items/associated-const-equality.rs rename to tests/ui/generic-const-items/assoc-const-bindings.rs From 3c136cc9e18c0f0bb848ff0a147aeb8ffa4ce20d Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Fri, 9 Jan 2026 00:40:31 +0000 Subject: [PATCH 0447/1061] Fix broken documentation links to SipHash The documentation of `SipHasher` previously linked to a page about SipHash on https://131002.net, a domain registered to Jean-Philippe Aumasson, one of the co-authors of the original SipHash paper (alongside Daniel J Bernstein). That domain now redirects to another of Mr Aumasson's domains, https://www.aumasson.jp, but which does not host a similar page dedicated to SipHash. Instead, his site links to a GitHub repository containing a C implementation together with links to the original research paper. Mr Bernstein's own site, https://cr.yp.to, only hosts a copy of the research paper. Therefore the GitHub repository appears to be the most official and complete reference to which we can link. --- library/core/src/hash/sip.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/core/src/hash/sip.rs b/library/core/src/hash/sip.rs index 780e522c48eb..4f2e8a22d180 100644 --- a/library/core/src/hash/sip.rs +++ b/library/core/src/hash/sip.rs @@ -10,7 +10,7 @@ use crate::{cmp, ptr}; /// This is currently the default hashing function used by standard library /// (e.g., `collections::HashMap` uses it by default). /// -/// See: +/// See: #[unstable(feature = "hashmap_internals", issue = "none")] #[deprecated(since = "1.13.0", note = "use `std::hash::DefaultHasher` instead")] #[derive(Debug, Clone, Default)] @@ -21,7 +21,7 @@ pub struct SipHasher13 { /// An implementation of SipHash 2-4. /// -/// See: +/// See: #[unstable(feature = "hashmap_internals", issue = "none")] #[deprecated(since = "1.13.0", note = "use `std::hash::DefaultHasher` instead")] #[derive(Debug, Clone, Default)] @@ -31,7 +31,7 @@ struct SipHasher24 { /// An implementation of SipHash 2-4. /// -/// See: +/// See: /// /// SipHash is a general-purpose hashing function: it runs at a good /// speed (competitive with Spooky and City) and permits strong _keyed_ From 5932078c79d7171d23dcf892e129ef5154410b62 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Mon, 22 Dec 2025 04:31:14 -0800 Subject: [PATCH 0448/1061] =?UTF-8?q?Stop=20emitting=20UbChecks=20on=20eve?= =?UTF-8?q?ry=20Vec=E2=86=92Slice?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Spotted this in PR148766's test changes. It doesn't seem like this ubcheck would catch anything useful; let's see if skipping it helps perf. --- library/alloc/src/vec/mod.rs | 12 +- library/core/src/slice/cmp.rs | 13 +- ...ng_operand.test.GVN.64bit.panic-abort.diff | 22 +- ..._conditions.JumpThreading.panic-abort.diff | 458 +++++------------- ...conditions.JumpThreading.panic-unwind.diff | 458 +++++------------- ...ace.PreCodegen.after.64bit.panic-abort.mir | 26 +- ...d_constant.main.GVN.64bit.panic-abort.diff | 72 ++- ..._to_slice.PreCodegen.after.panic-abort.mir | 33 +- ...to_slice.PreCodegen.after.panic-unwind.mir | 33 +- 9 files changed, 310 insertions(+), 817 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index d3da7efe4ddf..379e964f0a0c 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1747,7 +1747,11 @@ impl Vec { // * We only construct `&mut` references to `self.buf` through `&mut self` methods; borrow- // check ensures that it is not possible to mutably alias `self.buf` within the // returned lifetime. - unsafe { slice::from_raw_parts(self.as_ptr(), self.len) } + unsafe { + // normally this would use `slice::from_raw_parts`, but it's + // instantiated often enough that avoiding the UB check is worth it + &*core::intrinsics::aggregate_raw_ptr::<*const [T], _, _>(self.as_ptr(), self.len) + } } /// Extracts a mutable slice of the entire vector. @@ -1779,7 +1783,11 @@ impl Vec { // * We only construct references to `self.buf` through `&self` and `&mut self` methods; // borrow-check ensures that it is not possible to construct a reference to `self.buf` // within the returned lifetime. - unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) } + unsafe { + // normally this would use `slice::from_raw_parts_mut`, but it's + // instantiated often enough that avoiding the UB check is worth it + &mut *core::intrinsics::aggregate_raw_ptr::<*mut [T], _, _>(self.as_mut_ptr(), self.len) + } } /// Returns a raw pointer to the vector's buffer, or a dangling raw pointer diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs index fd1ca23fb79c..dfc0b565195e 100644 --- a/library/core/src/slice/cmp.rs +++ b/library/core/src/slice/cmp.rs @@ -13,13 +13,14 @@ impl const PartialEq<[U]> for [T] where T: [const] PartialEq, { + // It's not worth trying to inline the loops underneath here *in MIR*, + // and preventing it encourages more useful inlining upstream, + // such as in `::eq`. + // The codegen backend can still inline it later if needed. + #[rustc_no_mir_inline] fn eq(&self, other: &[U]) -> bool { SlicePartialEq::equal(self, other) } - - fn ne(&self, other: &[U]) -> bool { - SlicePartialEq::not_equal(self, other) - } } #[stable(feature = "rust1", since = "1.0.0")] @@ -99,10 +100,6 @@ impl PartialOrd for [T] { #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] const trait SlicePartialEq { fn equal(&self, other: &[B]) -> bool; - - fn not_equal(&self, other: &[B]) -> bool { - !self.equal(other) - } } // Generic slice equality diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff index 408ff60712e1..1b75a2bcba8b 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff @@ -26,12 +26,12 @@ scope 4 { debug _x => _8; } - scope 18 (inlined foo) { + scope 19 (inlined foo) { let mut _27: *const [()]; } } - scope 16 (inlined slice_from_raw_parts::<()>) { - scope 17 (inlined std::ptr::from_raw_parts::<[()], ()>) { + scope 17 (inlined slice_from_raw_parts::<()>) { + scope 18 (inlined std::ptr::from_raw_parts::<[()], ()>) { } } } @@ -49,19 +49,21 @@ scope 7 { let _21: std::ptr::NonNull<[u8]>; scope 8 { - scope 11 (inlined NonNull::<[u8]>::as_mut_ptr) { - scope 12 (inlined NonNull::<[u8]>::as_non_null_ptr) { - scope 13 (inlined NonNull::<[u8]>::cast::) { + scope 12 (inlined NonNull::<[u8]>::as_mut_ptr) { + scope 13 (inlined NonNull::<[u8]>::as_non_null_ptr) { + scope 14 (inlined NonNull::<[u8]>::cast::) { let mut _25: *mut [u8]; - scope 14 (inlined NonNull::<[u8]>::as_ptr) { + scope 15 (inlined NonNull::<[u8]>::as_ptr) { } } } - scope 15 (inlined NonNull::::as_ptr) { + scope 16 (inlined NonNull::::as_ptr) { } } } scope 10 (inlined ::allocate) { + scope 11 (inlined std::alloc::Global::alloc_impl) { + } } } scope 9 (inlined #[track_caller] Layout::from_size_align_unchecked) { @@ -192,8 +194,8 @@ + _18 = const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}; StorageDead(_24); StorageLive(_19); -- _19 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], copy _18, const false) -> [return: bb7, unwind unreachable]; -+ _19 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}, const false) -> [return: bb7, unwind unreachable]; +- _19 = std::alloc::Global::alloc_impl_runtime(copy _18, const false) -> [return: bb7, unwind unreachable]; ++ _19 = std::alloc::Global::alloc_impl_runtime(const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}, const false) -> [return: bb7, unwind unreachable]; } bb7: { diff --git a/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff index 8777ac426d78..0875d437296d 100644 --- a/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff @@ -48,8 +48,8 @@ let _29: &str; scope 7 (inlined String::as_str) { let _30: &[u8]; - let mut _31: &std::vec::Vec; scope 8 (inlined Vec::::as_slice) { + let _31: *const [u8]; let mut _32: *const u8; let mut _33: usize; scope 9 (inlined Vec::::as_ptr) { @@ -71,161 +71,83 @@ } } } - scope 18 (inlined #[track_caller] std::slice::from_raw_parts::<'_, u8>) { - let _35: (); - let mut _36: *mut (); - let _37: *const [u8]; - scope 19 (inlined ub_checks::check_language_ub) { - scope 20 (inlined ub_checks::check_language_ub::runtime) { - } - } - scope 21 (inlined std::mem::size_of::) { - } - scope 22 (inlined std::mem::align_of::) { - } - scope 23 (inlined slice_from_raw_parts::) { - scope 24 (inlined std::ptr::from_raw_parts::<[u8], u8>) { - } - } - } } - scope 25 (inlined from_utf8_unchecked) { + scope 18 (inlined from_utf8_unchecked) { } } - scope 26 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + scope 19 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { } } - scope 27 (inlined #[track_caller] core::str::traits:: for str>::index) { - scope 28 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + scope 20 (inlined #[track_caller] core::str::traits:: for str>::index) { + scope 21 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { } } - scope 29 (inlined core::str::traits::::eq) { - let mut _38: &&[u8]; - let _39: &[u8]; - let mut _40: &&[u8]; - let _41: &[u8]; - scope 30 (inlined core::str::::as_bytes) { + scope 22 (inlined core::str::traits::::eq) { + let mut _35: &&[u8]; + let _36: &[u8]; + let mut _37: &&[u8]; + let _38: &[u8]; + scope 23 (inlined core::str::::as_bytes) { } - scope 31 (inlined core::str::::as_bytes) { + scope 24 (inlined core::str::::as_bytes) { } - scope 32 (inlined std::cmp::impls::::eq) { - scope 33 (inlined core::slice::cmp::::eq) { - scope 34 (inlined <[u8] as core::slice::cmp::SlicePartialEq>::equal) { - let mut _42: bool; - let mut _43: usize; - let mut _44: usize; - let _45: usize; - let mut _46: i32; - let mut _47: *const u8; - let mut _48: *const u8; - scope 35 { - scope 37 (inlined core::slice::::as_ptr) { - let mut _50: *const [u8]; - } - scope 38 (inlined core::slice::::as_ptr) { - let mut _51: *const [u8]; - } - } - scope 36 (inlined std::mem::size_of_val::<[u8]>) { - let mut _49: *const [u8]; - } - } - } + scope 25 (inlined std::cmp::impls::::eq) { } } } } - scope 39 (inlined std::cmp::impls:: for &String>::eq) { - let mut _52: &std::string::String; - let mut _53: &str; - scope 40 (inlined >::eq) { - scope 41 (inlined #[track_caller] >::index) { - let _54: &str; - scope 42 (inlined String::as_str) { - let _55: &[u8]; - let mut _56: &std::vec::Vec; - scope 43 (inlined Vec::::as_slice) { - let mut _57: *const u8; - let mut _58: usize; - scope 44 (inlined Vec::::as_ptr) { - scope 45 (inlined alloc::raw_vec::RawVec::::ptr) { - scope 46 (inlined alloc::raw_vec::RawVecInner::ptr::) { - scope 47 (inlined alloc::raw_vec::RawVecInner::non_null::) { - let mut _59: std::ptr::NonNull; - scope 48 (inlined Unique::::cast::) { - scope 49 (inlined NonNull::::cast::) { - scope 50 (inlined NonNull::::as_ptr) { + scope 26 (inlined std::cmp::impls:: for &String>::eq) { + let mut _39: &std::string::String; + let mut _40: &str; + scope 27 (inlined >::eq) { + scope 28 (inlined #[track_caller] >::index) { + let _41: &str; + scope 29 (inlined String::as_str) { + let _42: &[u8]; + scope 30 (inlined Vec::::as_slice) { + let _43: *const [u8]; + let mut _44: *const u8; + let mut _45: usize; + scope 31 (inlined Vec::::as_ptr) { + scope 32 (inlined alloc::raw_vec::RawVec::::ptr) { + scope 33 (inlined alloc::raw_vec::RawVecInner::ptr::) { + scope 34 (inlined alloc::raw_vec::RawVecInner::non_null::) { + let mut _46: std::ptr::NonNull; + scope 35 (inlined Unique::::cast::) { + scope 36 (inlined NonNull::::cast::) { + scope 37 (inlined NonNull::::as_ptr) { } } } - scope 51 (inlined Unique::::as_non_null_ptr) { + scope 38 (inlined Unique::::as_non_null_ptr) { } } - scope 52 (inlined NonNull::::as_ptr) { + scope 39 (inlined NonNull::::as_ptr) { } } } } - scope 53 (inlined #[track_caller] std::slice::from_raw_parts::<'_, u8>) { - let _60: (); - let mut _61: *mut (); - let _62: *const [u8]; - scope 54 (inlined ub_checks::check_language_ub) { - scope 55 (inlined ub_checks::check_language_ub::runtime) { - } - } - scope 56 (inlined std::mem::size_of::) { - } - scope 57 (inlined std::mem::align_of::) { - } - scope 58 (inlined slice_from_raw_parts::) { - scope 59 (inlined std::ptr::from_raw_parts::<[u8], u8>) { - } - } - } } - scope 60 (inlined from_utf8_unchecked) { + scope 40 (inlined from_utf8_unchecked) { } } - scope 61 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + scope 41 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { } } - scope 62 (inlined #[track_caller] core::str::traits:: for str>::index) { - scope 63 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + scope 42 (inlined #[track_caller] core::str::traits:: for str>::index) { + scope 43 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { } } - scope 64 (inlined core::str::traits::::eq) { - let mut _63: &&[u8]; - let _64: &[u8]; - let mut _65: &&[u8]; - let _66: &[u8]; - scope 65 (inlined core::str::::as_bytes) { + scope 44 (inlined core::str::traits::::eq) { + let mut _47: &&[u8]; + let _48: &[u8]; + let mut _49: &&[u8]; + let _50: &[u8]; + scope 45 (inlined core::str::::as_bytes) { } - scope 66 (inlined core::str::::as_bytes) { + scope 46 (inlined core::str::::as_bytes) { } - scope 67 (inlined std::cmp::impls::::eq) { - scope 68 (inlined core::slice::cmp::::eq) { - scope 69 (inlined <[u8] as core::slice::cmp::SlicePartialEq>::equal) { - let mut _67: bool; - let mut _68: usize; - let mut _69: usize; - let _70: usize; - let mut _71: i32; - let mut _72: *const u8; - let mut _73: *const u8; - scope 70 { - scope 72 (inlined core::slice::::as_ptr) { - let mut _75: *const [u8]; - } - scope 73 (inlined core::slice::::as_ptr) { - let mut _76: *const [u8]; - } - } - scope 71 (inlined std::mem::size_of_val::<[u8]>) { - let mut _74: *const [u8]; - } - } - } + scope 47 (inlined std::cmp::impls::::eq) { } } } @@ -253,7 +175,7 @@ bb3: { _1 = chained_conditions::BacktraceStyle::Off; - goto -> bb18; -+ goto -> bb37; ++ goto -> bb23; } bb4: { @@ -272,15 +194,27 @@ _27 = copy (*_8); _28 = copy (*_10); StorageLive(_29); - StorageLive(_35); StorageLive(_30); - StorageLive(_34); + StorageLive(_31); StorageLive(_32); + StorageLive(_34); _34 = copy ((((((*_27).0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); _32 = copy _34 as *const u8 (Transmute); + StorageDead(_34); StorageLive(_33); _33 = copy (((*_27).0: std::vec::Vec).1: usize); - switchInt(UbChecks) -> [0: bb21, otherwise: bb19]; + _31 = *const [u8] from (copy _32, move _33); + StorageDead(_33); + StorageDead(_32); + _30 = &(*_31); + StorageDead(_31); + _29 = copy _30 as &str (Transmute); + StorageDead(_30); + StorageLive(_36); + StorageLive(_38); + _36 = copy _29 as &[u8] (Transmute); + _38 = copy _28 as &[u8] (Transmute); + _7 = <[u8] as PartialEq>::eq(move _36, move _38) -> [return: bb19, unwind unreachable]; } bb5: { @@ -311,27 +245,39 @@ StorageLive(_17); _20 = const chained_conditions::promoted[0]; _17 = &(*_20); - StorageLive(_52); - StorageLive(_53); - _52 = copy (*_15); - _53 = copy (*_17); - StorageLive(_54); - StorageLive(_60); - StorageLive(_55); - StorageLive(_59); - StorageLive(_57); - _59 = copy ((((((*_52).0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); - _57 = copy _59 as *const u8 (Transmute); - StorageLive(_58); - _58 = copy (((*_52).0: std::vec::Vec).1: usize); - switchInt(UbChecks) -> [0: bb29, otherwise: bb27]; + StorageLive(_39); + StorageLive(_40); + _39 = copy (*_15); + _40 = copy (*_17); + StorageLive(_41); + StorageLive(_42); + StorageLive(_43); + StorageLive(_44); + StorageLive(_46); + _46 = copy ((((((*_39).0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); + _44 = copy _46 as *const u8 (Transmute); + StorageDead(_46); + StorageLive(_45); + _45 = copy (((*_39).0: std::vec::Vec).1: usize); + _43 = *const [u8] from (copy _44, move _45); + StorageDead(_45); + StorageDead(_44); + _42 = &(*_43); + StorageDead(_43); + _41 = copy _42 as &str (Transmute); + StorageDead(_42); + StorageLive(_48); + StorageLive(_50); + _48 = copy _41 as &[u8] (Transmute); + _50 = copy _40 as &[u8] (Transmute); + _14 = <[u8] as PartialEq>::eq(move _48, move _50) -> [return: bb20, unwind unreachable]; } bb7: { StorageDead(_5); StorageDead(_6); - goto -> bb18; -+ goto -> bb39; ++ goto -> bb21; } bb8: { @@ -354,14 +300,14 @@ StorageDead(_13); _1 = chained_conditions::BacktraceStyle::Short; - goto -> bb18; -+ goto -> bb37; ++ goto -> bb23; } bb10: { StorageDead(_12); StorageDead(_13); - goto -> bb18; -+ goto -> bb39; ++ goto -> bb21; } bb11: { @@ -406,223 +352,39 @@ } bb19: { - StorageLive(_36); - _36 = copy _34 as *mut () (Transmute); - _35 = std::slice::from_raw_parts::precondition_check(move _36, const ::SIZE, const ::ALIGN, copy _33) -> [return: bb20, unwind unreachable]; - } - - bb20: { + StorageDead(_38); StorageDead(_36); - goto -> bb21; - } - - bb21: { - StorageLive(_37); - _37 = *const [u8] from (copy _32, copy _33); - _30 = &(*_37); - StorageDead(_37); - StorageDead(_33); - StorageDead(_32); - StorageDead(_34); - _29 = copy _30 as &str (Transmute); - StorageDead(_30); - StorageLive(_39); - StorageLive(_41); - _39 = copy _29 as &[u8] (Transmute); - _41 = copy _28 as &[u8] (Transmute); - StorageLive(_45); - StorageLive(_50); - StorageLive(_51); - StorageLive(_42); - StorageLive(_43); - _43 = PtrMetadata(copy _39); - StorageLive(_44); - _44 = PtrMetadata(copy _41); - _42 = Ne(move _43, move _44); - switchInt(move _42) -> [0: bb24, otherwise: bb23]; - } - - bb22: { - StorageDead(_51); - StorageDead(_50); - StorageDead(_45); - StorageDead(_41); - StorageDead(_39); - StorageDead(_35); StorageDead(_29); StorageDead(_28); StorageDead(_27); switchInt(move _7) -> [0: bb6, otherwise: bb5]; } - bb23: { - StorageDead(_44); - StorageDead(_43); - _7 = const false; - StorageDead(_42); -- goto -> bb22; -+ goto -> bb35; - } - - bb24: { - StorageDead(_44); - StorageDead(_43); - StorageDead(_42); - StorageLive(_49); - _49 = &raw const (*_39); - _45 = std::intrinsics::size_of_val::<[u8]>(move _49) -> [return: bb26, unwind unreachable]; - } - - bb25: { + bb20: { + StorageDead(_50); StorageDead(_48); - StorageDead(_47); - _7 = Eq(move _46, const 0_i32); - StorageDead(_46); - goto -> bb22; - } - - bb26: { - StorageDead(_49); - StorageLive(_46); - StorageLive(_47); - _50 = &raw const (*_39); - _47 = copy _50 as *const u8 (PtrToPtr); - StorageLive(_48); - _51 = &raw const (*_41); - _48 = copy _51 as *const u8 (PtrToPtr); - _46 = compare_bytes(move _47, move _48, move _45) -> [return: bb25, unwind unreachable]; - } - - bb27: { - StorageLive(_61); - _61 = copy _59 as *mut () (Transmute); - _60 = std::slice::from_raw_parts::precondition_check(move _61, const ::SIZE, const ::ALIGN, copy _58) -> [return: bb28, unwind unreachable]; - } - - bb28: { - StorageDead(_61); - goto -> bb29; - } - - bb29: { - StorageLive(_62); - _62 = *const [u8] from (copy _57, copy _58); - _55 = &(*_62); - StorageDead(_62); - StorageDead(_58); - StorageDead(_57); - StorageDead(_59); - _54 = copy _55 as &str (Transmute); - StorageDead(_55); - StorageLive(_64); - StorageLive(_66); - _64 = copy _54 as &[u8] (Transmute); - _66 = copy _53 as &[u8] (Transmute); - StorageLive(_70); - StorageLive(_75); - StorageLive(_76); - StorageLive(_67); - StorageLive(_68); - _68 = PtrMetadata(copy _64); - StorageLive(_69); - _69 = PtrMetadata(copy _66); - _67 = Ne(move _68, move _69); - switchInt(move _67) -> [0: bb32, otherwise: bb31]; - } - - bb30: { - StorageDead(_76); - StorageDead(_75); - StorageDead(_70); - StorageDead(_66); - StorageDead(_64); - StorageDead(_60); - StorageDead(_54); - StorageDead(_53); - StorageDead(_52); + StorageDead(_41); + StorageDead(_40); + StorageDead(_39); switchInt(move _14) -> [0: bb9, otherwise: bb8]; - } - - bb31: { - StorageDead(_69); - StorageDead(_68); - _14 = const false; - StorageDead(_67); -- goto -> bb30; -+ goto -> bb36; - } - - bb32: { - StorageDead(_69); - StorageDead(_68); - StorageDead(_67); - StorageLive(_74); - _74 = &raw const (*_64); - _70 = std::intrinsics::size_of_val::<[u8]>(move _74) -> [return: bb34, unwind unreachable]; - } - - bb33: { - StorageDead(_73); - StorageDead(_72); - _14 = Eq(move _71, const 0_i32); - StorageDead(_71); - goto -> bb30; - } - - bb34: { - StorageDead(_74); - StorageLive(_71); - StorageLive(_72); - _75 = &raw const (*_64); - _72 = copy _75 as *const u8 (PtrToPtr); - StorageLive(_73); - _76 = &raw const (*_66); - _73 = copy _76 as *const u8 (PtrToPtr); - _71 = compare_bytes(move _72, move _73, move _70) -> [return: bb33, unwind unreachable]; + } + -+ bb35: { -+ StorageDead(_51); -+ StorageDead(_50); -+ StorageDead(_45); -+ StorageDead(_41); -+ StorageDead(_39); -+ StorageDead(_35); -+ StorageDead(_29); -+ StorageDead(_28); -+ StorageDead(_27); -+ goto -> bb6; -+ } -+ -+ bb36: { -+ StorageDead(_76); -+ StorageDead(_75); -+ StorageDead(_70); -+ StorageDead(_66); -+ StorageDead(_64); -+ StorageDead(_60); -+ StorageDead(_54); -+ StorageDead(_53); -+ StorageDead(_52); -+ goto -> bb9; -+ } -+ -+ bb37: { ++ bb21: { + _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb38, otherwise: bb15]; ++ switchInt(move _24) -> [1: bb22, otherwise: bb15]; + } + -+ bb38: { -+ goto -> bb17; -+ } -+ -+ bb39: { -+ _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb40, otherwise: bb15]; -+ } -+ -+ bb40: { ++ bb22: { + goto -> bb15; ++ } ++ ++ bb23: { ++ _24 = discriminant(_2); ++ switchInt(move _24) -> [1: bb24, otherwise: bb15]; ++ } ++ ++ bb24: { ++ goto -> bb17; } } diff --git a/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff index 822d33c89391..b942eeed37e0 100644 --- a/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff @@ -48,8 +48,8 @@ let _29: &str; scope 7 (inlined String::as_str) { let _30: &[u8]; - let mut _31: &std::vec::Vec; scope 8 (inlined Vec::::as_slice) { + let _31: *const [u8]; let mut _32: *const u8; let mut _33: usize; scope 9 (inlined Vec::::as_ptr) { @@ -71,161 +71,83 @@ } } } - scope 18 (inlined #[track_caller] std::slice::from_raw_parts::<'_, u8>) { - let _35: (); - let mut _36: *mut (); - let _37: *const [u8]; - scope 19 (inlined ub_checks::check_language_ub) { - scope 20 (inlined ub_checks::check_language_ub::runtime) { - } - } - scope 21 (inlined std::mem::size_of::) { - } - scope 22 (inlined std::mem::align_of::) { - } - scope 23 (inlined slice_from_raw_parts::) { - scope 24 (inlined std::ptr::from_raw_parts::<[u8], u8>) { - } - } - } } - scope 25 (inlined from_utf8_unchecked) { + scope 18 (inlined from_utf8_unchecked) { } } - scope 26 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + scope 19 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { } } - scope 27 (inlined #[track_caller] core::str::traits:: for str>::index) { - scope 28 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + scope 20 (inlined #[track_caller] core::str::traits:: for str>::index) { + scope 21 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { } } - scope 29 (inlined core::str::traits::::eq) { - let mut _38: &&[u8]; - let _39: &[u8]; - let mut _40: &&[u8]; - let _41: &[u8]; - scope 30 (inlined core::str::::as_bytes) { + scope 22 (inlined core::str::traits::::eq) { + let mut _35: &&[u8]; + let _36: &[u8]; + let mut _37: &&[u8]; + let _38: &[u8]; + scope 23 (inlined core::str::::as_bytes) { } - scope 31 (inlined core::str::::as_bytes) { + scope 24 (inlined core::str::::as_bytes) { } - scope 32 (inlined std::cmp::impls::::eq) { - scope 33 (inlined core::slice::cmp::::eq) { - scope 34 (inlined <[u8] as core::slice::cmp::SlicePartialEq>::equal) { - let mut _42: bool; - let mut _43: usize; - let mut _44: usize; - let _45: usize; - let mut _46: i32; - let mut _47: *const u8; - let mut _48: *const u8; - scope 35 { - scope 37 (inlined core::slice::::as_ptr) { - let mut _50: *const [u8]; - } - scope 38 (inlined core::slice::::as_ptr) { - let mut _51: *const [u8]; - } - } - scope 36 (inlined std::mem::size_of_val::<[u8]>) { - let mut _49: *const [u8]; - } - } - } + scope 25 (inlined std::cmp::impls::::eq) { } } } } - scope 39 (inlined std::cmp::impls:: for &String>::eq) { - let mut _52: &std::string::String; - let mut _53: &str; - scope 40 (inlined >::eq) { - scope 41 (inlined #[track_caller] >::index) { - let _54: &str; - scope 42 (inlined String::as_str) { - let _55: &[u8]; - let mut _56: &std::vec::Vec; - scope 43 (inlined Vec::::as_slice) { - let mut _57: *const u8; - let mut _58: usize; - scope 44 (inlined Vec::::as_ptr) { - scope 45 (inlined alloc::raw_vec::RawVec::::ptr) { - scope 46 (inlined alloc::raw_vec::RawVecInner::ptr::) { - scope 47 (inlined alloc::raw_vec::RawVecInner::non_null::) { - let mut _59: std::ptr::NonNull; - scope 48 (inlined Unique::::cast::) { - scope 49 (inlined NonNull::::cast::) { - scope 50 (inlined NonNull::::as_ptr) { + scope 26 (inlined std::cmp::impls:: for &String>::eq) { + let mut _39: &std::string::String; + let mut _40: &str; + scope 27 (inlined >::eq) { + scope 28 (inlined #[track_caller] >::index) { + let _41: &str; + scope 29 (inlined String::as_str) { + let _42: &[u8]; + scope 30 (inlined Vec::::as_slice) { + let _43: *const [u8]; + let mut _44: *const u8; + let mut _45: usize; + scope 31 (inlined Vec::::as_ptr) { + scope 32 (inlined alloc::raw_vec::RawVec::::ptr) { + scope 33 (inlined alloc::raw_vec::RawVecInner::ptr::) { + scope 34 (inlined alloc::raw_vec::RawVecInner::non_null::) { + let mut _46: std::ptr::NonNull; + scope 35 (inlined Unique::::cast::) { + scope 36 (inlined NonNull::::cast::) { + scope 37 (inlined NonNull::::as_ptr) { } } } - scope 51 (inlined Unique::::as_non_null_ptr) { + scope 38 (inlined Unique::::as_non_null_ptr) { } } - scope 52 (inlined NonNull::::as_ptr) { + scope 39 (inlined NonNull::::as_ptr) { } } } } - scope 53 (inlined #[track_caller] std::slice::from_raw_parts::<'_, u8>) { - let _60: (); - let mut _61: *mut (); - let _62: *const [u8]; - scope 54 (inlined ub_checks::check_language_ub) { - scope 55 (inlined ub_checks::check_language_ub::runtime) { - } - } - scope 56 (inlined std::mem::size_of::) { - } - scope 57 (inlined std::mem::align_of::) { - } - scope 58 (inlined slice_from_raw_parts::) { - scope 59 (inlined std::ptr::from_raw_parts::<[u8], u8>) { - } - } - } } - scope 60 (inlined from_utf8_unchecked) { + scope 40 (inlined from_utf8_unchecked) { } } - scope 61 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + scope 41 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { } } - scope 62 (inlined #[track_caller] core::str::traits:: for str>::index) { - scope 63 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + scope 42 (inlined #[track_caller] core::str::traits:: for str>::index) { + scope 43 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { } } - scope 64 (inlined core::str::traits::::eq) { - let mut _63: &&[u8]; - let _64: &[u8]; - let mut _65: &&[u8]; - let _66: &[u8]; - scope 65 (inlined core::str::::as_bytes) { + scope 44 (inlined core::str::traits::::eq) { + let mut _47: &&[u8]; + let _48: &[u8]; + let mut _49: &&[u8]; + let _50: &[u8]; + scope 45 (inlined core::str::::as_bytes) { } - scope 66 (inlined core::str::::as_bytes) { + scope 46 (inlined core::str::::as_bytes) { } - scope 67 (inlined std::cmp::impls::::eq) { - scope 68 (inlined core::slice::cmp::::eq) { - scope 69 (inlined <[u8] as core::slice::cmp::SlicePartialEq>::equal) { - let mut _67: bool; - let mut _68: usize; - let mut _69: usize; - let _70: usize; - let mut _71: i32; - let mut _72: *const u8; - let mut _73: *const u8; - scope 70 { - scope 72 (inlined core::slice::::as_ptr) { - let mut _75: *const [u8]; - } - scope 73 (inlined core::slice::::as_ptr) { - let mut _76: *const [u8]; - } - } - scope 71 (inlined std::mem::size_of_val::<[u8]>) { - let mut _74: *const [u8]; - } - } - } + scope 47 (inlined std::cmp::impls::::eq) { } } } @@ -253,7 +175,7 @@ bb3: { _1 = chained_conditions::BacktraceStyle::Off; - goto -> bb19; -+ goto -> bb41; ++ goto -> bb27; } bb4: { @@ -272,15 +194,27 @@ _27 = copy (*_8); _28 = copy (*_10); StorageLive(_29); - StorageLive(_35); StorageLive(_30); - StorageLive(_34); + StorageLive(_31); StorageLive(_32); + StorageLive(_34); _34 = copy ((((((*_27).0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); _32 = copy _34 as *const u8 (Transmute); + StorageDead(_34); StorageLive(_33); _33 = copy (((*_27).0: std::vec::Vec).1: usize); - switchInt(UbChecks) -> [0: bb25, otherwise: bb23]; + _31 = *const [u8] from (copy _32, move _33); + StorageDead(_33); + StorageDead(_32); + _30 = &(*_31); + StorageDead(_31); + _29 = copy _30 as &str (Transmute); + StorageDead(_30); + StorageLive(_36); + StorageLive(_38); + _36 = copy _29 as &[u8] (Transmute); + _38 = copy _28 as &[u8] (Transmute); + _7 = <[u8] as PartialEq>::eq(move _36, move _38) -> [return: bb23, unwind: bb22]; } bb5: { @@ -311,27 +245,39 @@ StorageLive(_17); _20 = const chained_conditions::promoted[0]; _17 = &(*_20); - StorageLive(_52); - StorageLive(_53); - _52 = copy (*_15); - _53 = copy (*_17); - StorageLive(_54); - StorageLive(_60); - StorageLive(_55); - StorageLive(_59); - StorageLive(_57); - _59 = copy ((((((*_52).0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); - _57 = copy _59 as *const u8 (Transmute); - StorageLive(_58); - _58 = copy (((*_52).0: std::vec::Vec).1: usize); - switchInt(UbChecks) -> [0: bb33, otherwise: bb31]; + StorageLive(_39); + StorageLive(_40); + _39 = copy (*_15); + _40 = copy (*_17); + StorageLive(_41); + StorageLive(_42); + StorageLive(_43); + StorageLive(_44); + StorageLive(_46); + _46 = copy ((((((*_39).0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); + _44 = copy _46 as *const u8 (Transmute); + StorageDead(_46); + StorageLive(_45); + _45 = copy (((*_39).0: std::vec::Vec).1: usize); + _43 = *const [u8] from (copy _44, move _45); + StorageDead(_45); + StorageDead(_44); + _42 = &(*_43); + StorageDead(_43); + _41 = copy _42 as &str (Transmute); + StorageDead(_42); + StorageLive(_48); + StorageLive(_50); + _48 = copy _41 as &[u8] (Transmute); + _50 = copy _40 as &[u8] (Transmute); + _14 = <[u8] as PartialEq>::eq(move _48, move _50) -> [return: bb24, unwind: bb22]; } bb7: { StorageDead(_5); StorageDead(_6); - goto -> bb19; -+ goto -> bb43; ++ goto -> bb25; } bb8: { @@ -354,14 +300,14 @@ StorageDead(_13); _1 = chained_conditions::BacktraceStyle::Short; - goto -> bb19; -+ goto -> bb41; ++ goto -> bb27; } bb10: { StorageDead(_12); StorageDead(_13); - goto -> bb19; -+ goto -> bb43; ++ goto -> bb25; } bb11: { @@ -423,223 +369,39 @@ } bb23: { - StorageLive(_36); - _36 = copy _34 as *mut () (Transmute); - _35 = std::slice::from_raw_parts::precondition_check(move _36, const ::SIZE, const ::ALIGN, copy _33) -> [return: bb24, unwind unreachable]; - } - - bb24: { + StorageDead(_38); StorageDead(_36); - goto -> bb25; - } - - bb25: { - StorageLive(_37); - _37 = *const [u8] from (copy _32, copy _33); - _30 = &(*_37); - StorageDead(_37); - StorageDead(_33); - StorageDead(_32); - StorageDead(_34); - _29 = copy _30 as &str (Transmute); - StorageDead(_30); - StorageLive(_39); - StorageLive(_41); - _39 = copy _29 as &[u8] (Transmute); - _41 = copy _28 as &[u8] (Transmute); - StorageLive(_45); - StorageLive(_50); - StorageLive(_51); - StorageLive(_42); - StorageLive(_43); - _43 = PtrMetadata(copy _39); - StorageLive(_44); - _44 = PtrMetadata(copy _41); - _42 = Ne(move _43, move _44); - switchInt(move _42) -> [0: bb28, otherwise: bb27]; - } - - bb26: { - StorageDead(_51); - StorageDead(_50); - StorageDead(_45); - StorageDead(_41); - StorageDead(_39); - StorageDead(_35); StorageDead(_29); StorageDead(_28); StorageDead(_27); switchInt(move _7) -> [0: bb6, otherwise: bb5]; } - bb27: { - StorageDead(_44); - StorageDead(_43); - _7 = const false; - StorageDead(_42); -- goto -> bb26; -+ goto -> bb39; - } - - bb28: { - StorageDead(_44); - StorageDead(_43); - StorageDead(_42); - StorageLive(_49); - _49 = &raw const (*_39); - _45 = std::intrinsics::size_of_val::<[u8]>(move _49) -> [return: bb30, unwind unreachable]; - } - - bb29: { + bb24: { + StorageDead(_50); StorageDead(_48); - StorageDead(_47); - _7 = Eq(move _46, const 0_i32); - StorageDead(_46); - goto -> bb26; - } - - bb30: { - StorageDead(_49); - StorageLive(_46); - StorageLive(_47); - _50 = &raw const (*_39); - _47 = copy _50 as *const u8 (PtrToPtr); - StorageLive(_48); - _51 = &raw const (*_41); - _48 = copy _51 as *const u8 (PtrToPtr); - _46 = compare_bytes(move _47, move _48, move _45) -> [return: bb29, unwind unreachable]; - } - - bb31: { - StorageLive(_61); - _61 = copy _59 as *mut () (Transmute); - _60 = std::slice::from_raw_parts::precondition_check(move _61, const ::SIZE, const ::ALIGN, copy _58) -> [return: bb32, unwind unreachable]; - } - - bb32: { - StorageDead(_61); - goto -> bb33; - } - - bb33: { - StorageLive(_62); - _62 = *const [u8] from (copy _57, copy _58); - _55 = &(*_62); - StorageDead(_62); - StorageDead(_58); - StorageDead(_57); - StorageDead(_59); - _54 = copy _55 as &str (Transmute); - StorageDead(_55); - StorageLive(_64); - StorageLive(_66); - _64 = copy _54 as &[u8] (Transmute); - _66 = copy _53 as &[u8] (Transmute); - StorageLive(_70); - StorageLive(_75); - StorageLive(_76); - StorageLive(_67); - StorageLive(_68); - _68 = PtrMetadata(copy _64); - StorageLive(_69); - _69 = PtrMetadata(copy _66); - _67 = Ne(move _68, move _69); - switchInt(move _67) -> [0: bb36, otherwise: bb35]; - } - - bb34: { - StorageDead(_76); - StorageDead(_75); - StorageDead(_70); - StorageDead(_66); - StorageDead(_64); - StorageDead(_60); - StorageDead(_54); - StorageDead(_53); - StorageDead(_52); + StorageDead(_41); + StorageDead(_40); + StorageDead(_39); switchInt(move _14) -> [0: bb9, otherwise: bb8]; - } - - bb35: { - StorageDead(_69); - StorageDead(_68); - _14 = const false; - StorageDead(_67); -- goto -> bb34; -+ goto -> bb40; - } - - bb36: { - StorageDead(_69); - StorageDead(_68); - StorageDead(_67); - StorageLive(_74); - _74 = &raw const (*_64); - _70 = std::intrinsics::size_of_val::<[u8]>(move _74) -> [return: bb38, unwind unreachable]; - } - - bb37: { - StorageDead(_73); - StorageDead(_72); - _14 = Eq(move _71, const 0_i32); - StorageDead(_71); - goto -> bb34; - } - - bb38: { - StorageDead(_74); - StorageLive(_71); - StorageLive(_72); - _75 = &raw const (*_64); - _72 = copy _75 as *const u8 (PtrToPtr); - StorageLive(_73); - _76 = &raw const (*_66); - _73 = copy _76 as *const u8 (PtrToPtr); - _71 = compare_bytes(move _72, move _73, move _70) -> [return: bb37, unwind unreachable]; + } + -+ bb39: { -+ StorageDead(_51); -+ StorageDead(_50); -+ StorageDead(_45); -+ StorageDead(_41); -+ StorageDead(_39); -+ StorageDead(_35); -+ StorageDead(_29); -+ StorageDead(_28); -+ StorageDead(_27); -+ goto -> bb6; -+ } -+ -+ bb40: { -+ StorageDead(_76); -+ StorageDead(_75); -+ StorageDead(_70); -+ StorageDead(_66); -+ StorageDead(_64); -+ StorageDead(_60); -+ StorageDead(_54); -+ StorageDead(_53); -+ StorageDead(_52); -+ goto -> bb9; -+ } -+ -+ bb41: { ++ bb25: { + _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb42, otherwise: bb16]; ++ switchInt(move _24) -> [1: bb26, otherwise: bb16]; + } + -+ bb42: { -+ goto -> bb18; -+ } -+ -+ bb43: { -+ _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb44, otherwise: bb16]; -+ } -+ -+ bb44: { ++ bb26: { + goto -> bb16; ++ } ++ ++ bb27: { ++ _24 = discriminant(_2); ++ switchInt(move _24) -> [1: bb28, otherwise: bb16]; ++ } ++ ++ bb28: { ++ goto -> bb18; } } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir index 791d6b71a6f7..013361d1d2fb 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir @@ -25,17 +25,21 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } } scope 18 (inlined ::deallocate) { - let mut _9: *mut u8; - scope 19 (inlined Layout::size) { - } - scope 20 (inlined NonNull::::as_ptr) { - } - scope 21 (inlined std::alloc::dealloc) { - let mut _10: usize; - scope 22 (inlined Layout::size) { - } - scope 23 (inlined Layout::align) { - scope 24 (inlined std::ptr::Alignment::as_usize) { + scope 19 (inlined std::alloc::Global::deallocate_impl) { + scope 20 (inlined std::alloc::Global::deallocate_impl_runtime) { + let mut _9: *mut u8; + scope 21 (inlined Layout::size) { + } + scope 22 (inlined NonNull::::as_ptr) { + } + scope 23 (inlined std::alloc::dealloc) { + let mut _10: usize; + scope 24 (inlined Layout::size) { + } + scope 25 (inlined Layout::align) { + scope 26 (inlined std::ptr::Alignment::as_usize) { + } + } } } } diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff index 1dbe9394e709..b45a0f4a9bdd 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff @@ -9,33 +9,33 @@ let mut _4: *mut [u8]; let mut _5: std::ptr::NonNull<[u8]>; let mut _6: std::result::Result, std::alloc::AllocError>; - let mut _7: &std::alloc::Global; - let mut _8: std::alloc::Layout; + let mut _7: std::alloc::Layout; scope 1 { debug layout => _1; - let mut _9: &std::alloc::Global; scope 2 { debug ptr => _3; } scope 5 (inlined ::allocate) { - } - scope 6 (inlined #[track_caller] Result::, std::alloc::AllocError>::unwrap) { - let mut _12: isize; - let _13: std::alloc::AllocError; - let mut _14: !; - let mut _15: &dyn std::fmt::Debug; - let _16: &std::alloc::AllocError; - scope 7 { + scope 6 (inlined std::alloc::Global::alloc_impl) { } + } + scope 7 (inlined #[track_caller] Result::, std::alloc::AllocError>::unwrap) { + let mut _10: isize; + let _11: std::alloc::AllocError; + let mut _12: !; + let mut _13: &dyn std::fmt::Debug; + let _14: &std::alloc::AllocError; scope 8 { } + scope 9 { + } } - scope 9 (inlined NonNull::<[u8]>::as_ptr) { + scope 10 (inlined NonNull::<[u8]>::as_ptr) { } } scope 3 (inlined #[track_caller] Option::::unwrap) { - let mut _10: isize; - let mut _11: !; + let mut _8: isize; + let mut _9: !; scope 4 { } } @@ -46,10 +46,10 @@ StorageLive(_2); - _2 = Option::::None; + _2 = const Option::::None; - StorageLive(_10); -- _10 = discriminant(_2); -- switchInt(move _10) -> [0: bb2, 1: bb3, otherwise: bb1]; -+ _10 = const 0_isize; + StorageLive(_8); +- _8 = discriminant(_2); +- switchInt(move _8) -> [0: bb2, 1: bb3, otherwise: bb1]; ++ _8 = const 0_isize; + switchInt(const 0_isize) -> [0: bb2, 1: bb3, otherwise: bb1]; } @@ -58,48 +58,44 @@ } bb2: { - _11 = option::unwrap_failed() -> unwind unreachable; + _9 = option::unwrap_failed() -> unwind unreachable; } bb3: { - _1 = move ((_2 as Some).0: std::alloc::Layout); + _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum) }}; - StorageDead(_10); + StorageDead(_8); StorageDead(_2); StorageLive(_3); StorageLive(_4); StorageLive(_5); StorageLive(_6); StorageLive(_7); - _9 = const main::promoted[0]; - _7 = copy _9; - StorageLive(_8); -- _8 = copy _1; -- _6 = std::alloc::Global::alloc_impl(move _7, move _8, const false) -> [return: bb4, unwind unreachable]; -+ _8 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum) }}; -+ _6 = std::alloc::Global::alloc_impl(copy _9, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum) }}, const false) -> [return: bb4, unwind unreachable]; +- _7 = copy _1; +- _6 = std::alloc::Global::alloc_impl_runtime(move _7, const false) -> [return: bb4, unwind unreachable]; ++ _7 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum) }}; ++ _6 = std::alloc::Global::alloc_impl_runtime(const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum) }}, const false) -> [return: bb4, unwind unreachable]; } bb4: { - StorageDead(_8); StorageDead(_7); - StorageLive(_12); - StorageLive(_16); - _12 = discriminant(_6); - switchInt(move _12) -> [0: bb6, 1: bb5, otherwise: bb1]; + StorageLive(_10); + StorageLive(_14); + _10 = discriminant(_6); + switchInt(move _10) -> [0: bb6, 1: bb5, otherwise: bb1]; } bb5: { - StorageLive(_15); - _16 = &_13; - _15 = copy _16 as &dyn std::fmt::Debug (PointerCoercion(Unsize, Implicit)); - _14 = result::unwrap_failed(const "called `Result::unwrap()` on an `Err` value", move _15) -> unwind unreachable; + StorageLive(_13); + _14 = &_11; + _13 = copy _14 as &dyn std::fmt::Debug (PointerCoercion(Unsize, Implicit)); + _12 = result::unwrap_failed(const "called `Result::unwrap()` on an `Err` value", move _13) -> unwind unreachable; } bb6: { _5 = move ((_6 as Ok).0: std::ptr::NonNull<[u8]>); - StorageDead(_16); - StorageDead(_12); + StorageDead(_14); + StorageDead(_10); StorageDead(_6); _4 = copy _5 as *mut [u8] (Transmute); StorageDead(_5); diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir index 2eee8a97db0d..8308ecbad716 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir @@ -9,6 +9,7 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { debug self => _1; let mut _3: *const u8; let mut _4: usize; + let _5: *const [u8]; scope 3 (inlined Vec::::as_ptr) { debug self => _1; scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { @@ -29,43 +30,23 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { } } } - scope 12 (inlined #[track_caller] std::slice::from_raw_parts::<'_, u8>) { - debug data => _3; - debug len => _4; - let _5: *const [u8]; - scope 13 (inlined core::ub_checks::check_language_ub) { - scope 14 (inlined core::ub_checks::check_language_ub::runtime) { - } - } - scope 15 (inlined std::mem::size_of::) { - } - scope 16 (inlined std::mem::align_of::) { - } - scope 17 (inlined slice_from_raw_parts::) { - debug data => _3; - debug len => _4; - scope 18 (inlined std::ptr::from_raw_parts::<[u8], u8>) { - debug data_pointer => _3; - } - } - } } } bb0: { - StorageLive(_2); + StorageLive(_5); StorageLive(_3); + StorageLive(_2); _2 = copy (((((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); _3 = copy _2 as *const u8 (Transmute); + StorageDead(_2); StorageLive(_4); _4 = copy ((*_1).1: usize); - StorageLive(_5); - _5 = *const [u8] from (copy _3, copy _4); - _0 = &(*_5); - StorageDead(_5); + _5 = *const [u8] from (copy _3, move _4); StorageDead(_4); StorageDead(_3); - StorageDead(_2); + _0 = &(*_5); + StorageDead(_5); return; } } diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir index 2eee8a97db0d..8308ecbad716 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir @@ -9,6 +9,7 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { debug self => _1; let mut _3: *const u8; let mut _4: usize; + let _5: *const [u8]; scope 3 (inlined Vec::::as_ptr) { debug self => _1; scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { @@ -29,43 +30,23 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { } } } - scope 12 (inlined #[track_caller] std::slice::from_raw_parts::<'_, u8>) { - debug data => _3; - debug len => _4; - let _5: *const [u8]; - scope 13 (inlined core::ub_checks::check_language_ub) { - scope 14 (inlined core::ub_checks::check_language_ub::runtime) { - } - } - scope 15 (inlined std::mem::size_of::) { - } - scope 16 (inlined std::mem::align_of::) { - } - scope 17 (inlined slice_from_raw_parts::) { - debug data => _3; - debug len => _4; - scope 18 (inlined std::ptr::from_raw_parts::<[u8], u8>) { - debug data_pointer => _3; - } - } - } } } bb0: { - StorageLive(_2); + StorageLive(_5); StorageLive(_3); + StorageLive(_2); _2 = copy (((((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); _3 = copy _2 as *const u8 (Transmute); + StorageDead(_2); StorageLive(_4); _4 = copy ((*_1).1: usize); - StorageLive(_5); - _5 = *const [u8] from (copy _3, copy _4); - _0 = &(*_5); - StorageDead(_5); + _5 = *const [u8] from (copy _3, move _4); StorageDead(_4); StorageDead(_3); - StorageDead(_2); + _0 = &(*_5); + StorageDead(_5); return; } } From c48df5dcf189c730edc2eb1cf93117af584cceee Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 23 Dec 2025 22:42:03 -0800 Subject: [PATCH 0449/1061] Move the `rustc_no_mir_inline` down a level --- library/core/src/slice/cmp.rs | 21 ++++++-- ..._conditions.JumpThreading.panic-abort.diff | 52 ++++++++++--------- ...conditions.JumpThreading.panic-unwind.diff | 52 ++++++++++--------- 3 files changed, 72 insertions(+), 53 deletions(-) diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs index dfc0b565195e..c3ff928a3277 100644 --- a/library/core/src/slice/cmp.rs +++ b/library/core/src/slice/cmp.rs @@ -13,11 +13,7 @@ impl const PartialEq<[U]> for [T] where T: [const] PartialEq, { - // It's not worth trying to inline the loops underneath here *in MIR*, - // and preventing it encourages more useful inlining upstream, - // such as in `::eq`. - // The codegen backend can still inline it later if needed. - #[rustc_no_mir_inline] + #[inline] fn eq(&self, other: &[U]) -> bool { SlicePartialEq::equal(self, other) } @@ -108,6 +104,11 @@ impl const SlicePartialEq for [A] where A: [const] PartialEq, { + // It's not worth trying to inline the loops underneath here *in MIR*, + // and preventing it encourages more useful inlining upstream, + // such as in `::eq`. + // The codegen backend can still inline it later if needed. + #[rustc_no_mir_inline] default fn equal(&self, other: &[B]) -> bool { if self.len() != other.len() { return false; @@ -137,6 +138,16 @@ impl const SlicePartialEq for [A] where A: [const] BytewiseEq, { + // This is usually a pretty good backend inlining candidate because the + // intrinsic tends to just be `memcmp`. However, as of 2025-12 letting + // MIR inline this makes reuse worse because it means that, for example, + // `String::eq` doesn't inline, whereas by keeping this from inling all + // the wrappers until the call to this disappear. If the heuristics have + // changed and this is no longer fruitful, though, please do remove it. + // In the mean time, it's fine to not inline it in MIR because the backend + // will still inline it if it things it's important to do so. + #[rustc_no_mir_inline] + #[inline] fn equal(&self, other: &[B]) -> bool { if self.len() != other.len() { return false; diff --git a/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff index 0875d437296d..3cf28f4b60af 100644 --- a/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff @@ -92,62 +92,66 @@ scope 24 (inlined core::str::::as_bytes) { } scope 25 (inlined std::cmp::impls::::eq) { + scope 26 (inlined core::slice::cmp::::eq) { + } } } } } - scope 26 (inlined std::cmp::impls:: for &String>::eq) { + scope 27 (inlined std::cmp::impls:: for &String>::eq) { let mut _39: &std::string::String; let mut _40: &str; - scope 27 (inlined >::eq) { - scope 28 (inlined #[track_caller] >::index) { + scope 28 (inlined >::eq) { + scope 29 (inlined #[track_caller] >::index) { let _41: &str; - scope 29 (inlined String::as_str) { + scope 30 (inlined String::as_str) { let _42: &[u8]; - scope 30 (inlined Vec::::as_slice) { + scope 31 (inlined Vec::::as_slice) { let _43: *const [u8]; let mut _44: *const u8; let mut _45: usize; - scope 31 (inlined Vec::::as_ptr) { - scope 32 (inlined alloc::raw_vec::RawVec::::ptr) { - scope 33 (inlined alloc::raw_vec::RawVecInner::ptr::) { - scope 34 (inlined alloc::raw_vec::RawVecInner::non_null::) { + scope 32 (inlined Vec::::as_ptr) { + scope 33 (inlined alloc::raw_vec::RawVec::::ptr) { + scope 34 (inlined alloc::raw_vec::RawVecInner::ptr::) { + scope 35 (inlined alloc::raw_vec::RawVecInner::non_null::) { let mut _46: std::ptr::NonNull; - scope 35 (inlined Unique::::cast::) { - scope 36 (inlined NonNull::::cast::) { - scope 37 (inlined NonNull::::as_ptr) { + scope 36 (inlined Unique::::cast::) { + scope 37 (inlined NonNull::::cast::) { + scope 38 (inlined NonNull::::as_ptr) { } } } - scope 38 (inlined Unique::::as_non_null_ptr) { + scope 39 (inlined Unique::::as_non_null_ptr) { } } - scope 39 (inlined NonNull::::as_ptr) { + scope 40 (inlined NonNull::::as_ptr) { } } } } } - scope 40 (inlined from_utf8_unchecked) { + scope 41 (inlined from_utf8_unchecked) { } } - scope 41 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + scope 42 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { } } - scope 42 (inlined #[track_caller] core::str::traits:: for str>::index) { - scope 43 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + scope 43 (inlined #[track_caller] core::str::traits:: for str>::index) { + scope 44 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { } } - scope 44 (inlined core::str::traits::::eq) { + scope 45 (inlined core::str::traits::::eq) { let mut _47: &&[u8]; let _48: &[u8]; let mut _49: &&[u8]; let _50: &[u8]; - scope 45 (inlined core::str::::as_bytes) { - } scope 46 (inlined core::str::::as_bytes) { } - scope 47 (inlined std::cmp::impls::::eq) { + scope 47 (inlined core::str::::as_bytes) { + } + scope 48 (inlined std::cmp::impls::::eq) { + scope 49 (inlined core::slice::cmp::::eq) { + } } } } @@ -214,7 +218,7 @@ StorageLive(_38); _36 = copy _29 as &[u8] (Transmute); _38 = copy _28 as &[u8] (Transmute); - _7 = <[u8] as PartialEq>::eq(move _36, move _38) -> [return: bb19, unwind unreachable]; + _7 = <[u8] as core::slice::cmp::SlicePartialEq>::equal(move _36, move _38) -> [return: bb19, unwind unreachable]; } bb5: { @@ -270,7 +274,7 @@ StorageLive(_50); _48 = copy _41 as &[u8] (Transmute); _50 = copy _40 as &[u8] (Transmute); - _14 = <[u8] as PartialEq>::eq(move _48, move _50) -> [return: bb20, unwind unreachable]; + _14 = <[u8] as core::slice::cmp::SlicePartialEq>::equal(move _48, move _50) -> [return: bb20, unwind unreachable]; } bb7: { diff --git a/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff index b942eeed37e0..2f0d83f92792 100644 --- a/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff @@ -92,62 +92,66 @@ scope 24 (inlined core::str::::as_bytes) { } scope 25 (inlined std::cmp::impls::::eq) { + scope 26 (inlined core::slice::cmp::::eq) { + } } } } } - scope 26 (inlined std::cmp::impls:: for &String>::eq) { + scope 27 (inlined std::cmp::impls:: for &String>::eq) { let mut _39: &std::string::String; let mut _40: &str; - scope 27 (inlined >::eq) { - scope 28 (inlined #[track_caller] >::index) { + scope 28 (inlined >::eq) { + scope 29 (inlined #[track_caller] >::index) { let _41: &str; - scope 29 (inlined String::as_str) { + scope 30 (inlined String::as_str) { let _42: &[u8]; - scope 30 (inlined Vec::::as_slice) { + scope 31 (inlined Vec::::as_slice) { let _43: *const [u8]; let mut _44: *const u8; let mut _45: usize; - scope 31 (inlined Vec::::as_ptr) { - scope 32 (inlined alloc::raw_vec::RawVec::::ptr) { - scope 33 (inlined alloc::raw_vec::RawVecInner::ptr::) { - scope 34 (inlined alloc::raw_vec::RawVecInner::non_null::) { + scope 32 (inlined Vec::::as_ptr) { + scope 33 (inlined alloc::raw_vec::RawVec::::ptr) { + scope 34 (inlined alloc::raw_vec::RawVecInner::ptr::) { + scope 35 (inlined alloc::raw_vec::RawVecInner::non_null::) { let mut _46: std::ptr::NonNull; - scope 35 (inlined Unique::::cast::) { - scope 36 (inlined NonNull::::cast::) { - scope 37 (inlined NonNull::::as_ptr) { + scope 36 (inlined Unique::::cast::) { + scope 37 (inlined NonNull::::cast::) { + scope 38 (inlined NonNull::::as_ptr) { } } } - scope 38 (inlined Unique::::as_non_null_ptr) { + scope 39 (inlined Unique::::as_non_null_ptr) { } } - scope 39 (inlined NonNull::::as_ptr) { + scope 40 (inlined NonNull::::as_ptr) { } } } } } - scope 40 (inlined from_utf8_unchecked) { + scope 41 (inlined from_utf8_unchecked) { } } - scope 41 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + scope 42 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { } } - scope 42 (inlined #[track_caller] core::str::traits:: for str>::index) { - scope 43 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + scope 43 (inlined #[track_caller] core::str::traits:: for str>::index) { + scope 44 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { } } - scope 44 (inlined core::str::traits::::eq) { + scope 45 (inlined core::str::traits::::eq) { let mut _47: &&[u8]; let _48: &[u8]; let mut _49: &&[u8]; let _50: &[u8]; - scope 45 (inlined core::str::::as_bytes) { - } scope 46 (inlined core::str::::as_bytes) { } - scope 47 (inlined std::cmp::impls::::eq) { + scope 47 (inlined core::str::::as_bytes) { + } + scope 48 (inlined std::cmp::impls::::eq) { + scope 49 (inlined core::slice::cmp::::eq) { + } } } } @@ -214,7 +218,7 @@ StorageLive(_38); _36 = copy _29 as &[u8] (Transmute); _38 = copy _28 as &[u8] (Transmute); - _7 = <[u8] as PartialEq>::eq(move _36, move _38) -> [return: bb23, unwind: bb22]; + _7 = <[u8] as core::slice::cmp::SlicePartialEq>::equal(move _36, move _38) -> [return: bb23, unwind: bb22]; } bb5: { @@ -270,7 +274,7 @@ StorageLive(_50); _48 = copy _41 as &[u8] (Transmute); _50 = copy _40 as &[u8] (Transmute); - _14 = <[u8] as PartialEq>::eq(move _48, move _50) -> [return: bb24, unwind: bb22]; + _14 = <[u8] as core::slice::cmp::SlicePartialEq>::equal(move _48, move _50) -> [return: bb24, unwind: bb22]; } bb7: { From 45e0fbf7c5ffa5b8d36f9708e3a735908c6f28b4 Mon Sep 17 00:00:00 2001 From: tison Date: Fri, 9 Jan 2026 09:58:08 +0800 Subject: [PATCH 0450/1061] Implement partial_sort_unstable for slice Signed-off-by: tison Co-Authored-By: Orson Peters Signed-off-by: tison --- library/alloctests/tests/lib.rs | 2 + library/alloctests/tests/sort/mod.rs | 1 + library/alloctests/tests/sort/partial.rs | 84 ++++++++ library/core/src/slice/mod.rs | 213 ++++++++++++++++++++ library/core/src/slice/sort/unstable/mod.rs | 57 +++++- 5 files changed, 355 insertions(+), 2 deletions(-) create mode 100644 library/alloctests/tests/sort/partial.rs diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index 34c65bf787c8..36eb0c3fa2c7 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -20,6 +20,8 @@ #![feature(binary_heap_into_iter_sorted)] #![feature(binary_heap_drain_sorted)] #![feature(slice_ptr_get)] +#![feature(slice_range)] +#![feature(slice_partial_sort_unstable)] #![feature(inplace_iteration)] #![feature(iter_advance_by)] #![feature(iter_next_chunk)] diff --git a/library/alloctests/tests/sort/mod.rs b/library/alloctests/tests/sort/mod.rs index 0e2494ca9d34..e2e141a02b59 100644 --- a/library/alloctests/tests/sort/mod.rs +++ b/library/alloctests/tests/sort/mod.rs @@ -12,6 +12,7 @@ pub trait Sort { mod ffi_types; mod known_good_stable_sort; +mod partial; mod patterns; mod tests; mod zipf; diff --git a/library/alloctests/tests/sort/partial.rs b/library/alloctests/tests/sort/partial.rs new file mode 100644 index 000000000000..c7248990c70c --- /dev/null +++ b/library/alloctests/tests/sort/partial.rs @@ -0,0 +1,84 @@ +use std::fmt::Debug; +use std::ops::{Range, RangeBounds}; +use std::slice; + +use super::patterns; + +fn check_is_partial_sorted>(v: &mut [T], range: R) { + let Range { start, end } = slice::range(range, ..v.len()); + v.partial_sort_unstable(start..end); + + let max_before = v[..start].iter().max().into_iter(); + let sorted_range = v[start..end].into_iter(); + let min_after = v[end..].iter().min().into_iter(); + let seq = max_before.chain(sorted_range).chain(min_after); + assert!(seq.is_sorted()); +} + +fn check_is_partial_sorted_ranges(v: &[T]) { + let len = v.len(); + + check_is_partial_sorted::(&mut v.to_vec(), ..); + check_is_partial_sorted::(&mut v.to_vec(), 0..0); + check_is_partial_sorted::(&mut v.to_vec(), len..len); + + if len > 0 { + check_is_partial_sorted::(&mut v.to_vec(), len - 1..len - 1); + check_is_partial_sorted::(&mut v.to_vec(), 0..1); + check_is_partial_sorted::(&mut v.to_vec(), len - 1..len); + + for mid in 1..len { + check_is_partial_sorted::(&mut v.to_vec(), 0..mid); + check_is_partial_sorted::(&mut v.to_vec(), mid..len); + check_is_partial_sorted::(&mut v.to_vec(), mid..mid); + check_is_partial_sorted::(&mut v.to_vec(), mid - 1..mid + 1); + check_is_partial_sorted::(&mut v.to_vec(), mid - 1..mid); + check_is_partial_sorted::(&mut v.to_vec(), mid..mid + 1); + } + + let quarters = [0, len / 4, len / 2, (3 * len) / 4, len]; + for &start in &quarters { + for &end in &quarters { + if start < end { + check_is_partial_sorted::(&mut v.to_vec(), start..end); + } + } + } + } +} + +#[test] +fn basic_impl() { + check_is_partial_sorted::(&mut [], ..); + check_is_partial_sorted::<(), _>(&mut [], ..); + check_is_partial_sorted::<(), _>(&mut [()], ..); + check_is_partial_sorted::<(), _>(&mut [(), ()], ..); + check_is_partial_sorted::<(), _>(&mut [(), (), ()], ..); + check_is_partial_sorted::(&mut [], ..); + + check_is_partial_sorted::(&mut [77], ..); + check_is_partial_sorted::(&mut [2, 3], ..); + check_is_partial_sorted::(&mut [2, 3, 6], ..); + check_is_partial_sorted::(&mut [2, 3, 99, 6], ..); + check_is_partial_sorted::(&mut [2, 7709, 400, 90932], ..); + check_is_partial_sorted::(&mut [15, -1, 3, -1, -3, -1, 7], ..); + + check_is_partial_sorted::(&mut [15, -1, 3, -1, -3, -1, 7], 0..0); + check_is_partial_sorted::(&mut [15, -1, 3, -1, -3, -1, 7], 0..1); + check_is_partial_sorted::(&mut [15, -1, 3, -1, -3, -1, 7], 0..5); + check_is_partial_sorted::(&mut [15, -1, 3, -1, -3, -1, 7], 0..7); + check_is_partial_sorted::(&mut [15, -1, 3, -1, -3, -1, 7], 7..7); + check_is_partial_sorted::(&mut [15, -1, 3, -1, -3, -1, 7], 6..7); + check_is_partial_sorted::(&mut [15, -1, 3, -1, -3, -1, 7], 5..7); + check_is_partial_sorted::(&mut [15, -1, 3, -1, -3, -1, 7], 5..5); + check_is_partial_sorted::(&mut [15, -1, 3, -1, -3, -1, 7], 4..5); + check_is_partial_sorted::(&mut [15, -1, 3, -1, -3, -1, 7], 4..6); +} + +#[test] +fn random_patterns() { + check_is_partial_sorted_ranges(&patterns::random(10)); + check_is_partial_sorted_ranges(&patterns::random(50)); + check_is_partial_sorted_ranges(&patterns::random(100)); + check_is_partial_sorted_ranges(&patterns::random(1000)); +} diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 889fd4cd65df..762921a85fc6 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3244,6 +3244,219 @@ impl [T] { sort::unstable::sort(self, &mut |a, b| f(a).lt(&f(b))); } + /// Partially sorts the slice in ascending order **without** preserving the initial order of equal elements. + /// + /// Upon completion, for the specified range `start..end`, it's guaranteed that: + /// + /// 1. Every element in `self[..start]` is smaller than or equal to + /// 2. Every element in `self[start..end]`, which is sorted, and smaller than or equal to + /// 3. Every element in `self[end..]`. + /// + /// This partial sort is unstable, meaning it may reorder equal elements in the specified range. + /// It may reorder elements outside the specified range as well, but the guarantees above still hold. + /// + /// This partial sort is in-place (i.e., does not allocate), and *O*(*n* + *k* \* log(*k*)) worst-case, + /// where *n* is the length of the slice and *k* is the length of the specified range. + /// + /// See the documentation of [`sort_unstable`] for implementation notes. + /// + /// # Panics + /// + /// May panic if the implementation of [`Ord`] for `T` does not implement a total order, or if + /// the [`Ord`] implementation panics, or if the specified range is out of bounds. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partial_sort_unstable)] + /// + /// let mut v = [4, -5, 1, -3, 2]; + /// + /// // empty range at the beginning, nothing changed + /// v.partial_sort_unstable(0..0); + /// assert_eq!(v, [4, -5, 1, -3, 2]); + /// + /// // empty range in the middle, partitioning the slice + /// v.partial_sort_unstable(2..2); + /// for i in 0..2 { + /// assert!(v[i] <= v[2]); + /// } + /// for i in 3..v.len() { + /// assert!(v[2] <= v[i]); + /// } + /// + /// // single element range, same as select_nth_unstable + /// v.partial_sort_unstable(2..3); + /// for i in 0..2 { + /// assert!(v[i] <= v[2]); + /// } + /// for i in 3..v.len() { + /// assert!(v[2] <= v[i]); + /// } + /// + /// // partial sort a subrange + /// v.partial_sort_unstable(1..4); + /// assert_eq!(&v[1..4], [-3, 1, 2]); + /// + /// // partial sort the whole range, same as sort_unstable + /// v.partial_sort_unstable(..); + /// assert_eq!(v, [-5, -3, 1, 2, 4]); + /// ``` + /// + /// [`sort_unstable`]: slice::sort_unstable + #[unstable(feature = "slice_partial_sort_unstable", issue = "149046")] + #[inline] + pub fn partial_sort_unstable(&mut self, range: R) + where + T: Ord, + R: RangeBounds, + { + sort::unstable::partial_sort(self, range, T::lt); + } + + /// Partially sorts the slice in ascending order with a comparison function, **without** + /// preserving the initial order of equal elements. + /// + /// Upon completion, for the specified range `start..end`, it's guaranteed that: + /// + /// 1. Every element in `self[..start]` is smaller than or equal to + /// 2. Every element in `self[start..end]`, which is sorted, and smaller than or equal to + /// 3. Every element in `self[end..]`. + /// + /// This partial sort is unstable, meaning it may reorder equal elements in the specified range. + /// It may reorder elements outside the specified range as well, but the guarantees above still hold. + /// + /// This partial sort is in-place (i.e., does not allocate), and *O*(*n* + *k* \* log(*k*)) worst-case, + /// where *n* is the length of the slice and *k* is the length of the specified range. + /// + /// See the documentation of [`sort_unstable_by`] for implementation notes. + /// + /// # Panics + /// + /// May panic if the `compare` does not implement a total order, or if + /// the `compare` itself panics, or if the specified range is out of bounds. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partial_sort_unstable)] + /// + /// let mut v = [4, -5, 1, -3, 2]; + /// + /// // empty range at the beginning, nothing changed + /// v.partial_sort_unstable_by(0..0, |a, b| b.cmp(a)); + /// assert_eq!(v, [4, -5, 1, -3, 2]); + /// + /// // empty range in the middle, partitioning the slice + /// v.partial_sort_unstable_by(2..2, |a, b| b.cmp(a)); + /// for i in 0..2 { + /// assert!(v[i] >= v[2]); + /// } + /// for i in 3..v.len() { + /// assert!(v[2] >= v[i]); + /// } + /// + /// // single element range, same as select_nth_unstable + /// v.partial_sort_unstable_by(2..3, |a, b| b.cmp(a)); + /// for i in 0..2 { + /// assert!(v[i] >= v[2]); + /// } + /// for i in 3..v.len() { + /// assert!(v[2] >= v[i]); + /// } + /// + /// // partial sort a subrange + /// v.partial_sort_unstable_by(1..4, |a, b| b.cmp(a)); + /// assert_eq!(&v[1..4], [2, 1, -3]); + /// + /// // partial sort the whole range, same as sort_unstable + /// v.partial_sort_unstable_by(.., |a, b| b.cmp(a)); + /// assert_eq!(v, [4, 2, 1, -3, -5]); + /// ``` + /// + /// [`sort_unstable_by`]: slice::sort_unstable_by + #[unstable(feature = "slice_partial_sort_unstable", issue = "149046")] + #[inline] + pub fn partial_sort_unstable_by(&mut self, range: R, mut compare: F) + where + F: FnMut(&T, &T) -> Ordering, + R: RangeBounds, + { + sort::unstable::partial_sort(self, range, |a, b| compare(a, b) == Less); + } + + /// Partially sorts the slice in ascending order with a key extraction function, **without** + /// preserving the initial order of equal elements. + /// + /// Upon completion, for the specified range `start..end`, it's guaranteed that: + /// + /// 1. Every element in `self[..start]` is smaller than or equal to + /// 2. Every element in `self[start..end]`, which is sorted, and smaller than or equal to + /// 3. Every element in `self[end..]`. + /// + /// This partial sort is unstable, meaning it may reorder equal elements in the specified range. + /// It may reorder elements outside the specified range as well, but the guarantees above still hold. + /// + /// This partial sort is in-place (i.e., does not allocate), and *O*(*n* + *k* \* log(*k*)) worst-case, + /// where *n* is the length of the slice and *k* is the length of the specified range. + /// + /// See the documentation of [`sort_unstable_by_key`] for implementation notes. + /// + /// # Panics + /// + /// May panic if the implementation of [`Ord`] for `K` does not implement a total order, or if + /// the [`Ord`] implementation panics, or if the specified range is out of bounds. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partial_sort_unstable)] + /// + /// let mut v = [4i32, -5, 1, -3, 2]; + /// + /// // empty range at the beginning, nothing changed + /// v.partial_sort_unstable_by_key(0..0, |k| k.abs()); + /// assert_eq!(v, [4, -5, 1, -3, 2]); + /// + /// // empty range in the middle, partitioning the slice + /// v.partial_sort_unstable_by_key(2..2, |k| k.abs()); + /// for i in 0..2 { + /// assert!(v[i].abs() <= v[2].abs()); + /// } + /// for i in 3..v.len() { + /// assert!(v[2].abs() <= v[i].abs()); + /// } + /// + /// // single element range, same as select_nth_unstable + /// v.partial_sort_unstable_by_key(2..3, |k| k.abs()); + /// for i in 0..2 { + /// assert!(v[i].abs() <= v[2].abs()); + /// } + /// for i in 3..v.len() { + /// assert!(v[2].abs() <= v[i].abs()); + /// } + /// + /// // partial sort a subrange + /// v.partial_sort_unstable_by_key(1..4, |k| k.abs()); + /// assert_eq!(&v[1..4], [2, -3, 4]); + /// + /// // partial sort the whole range, same as sort_unstable + /// v.partial_sort_unstable_by_key(.., |k| k.abs()); + /// assert_eq!(v, [1, 2, -3, 4, -5]); + /// ``` + /// + /// [`sort_unstable_by_key`]: slice::sort_unstable_by_key + #[unstable(feature = "slice_partial_sort_unstable", issue = "149046")] + #[inline] + pub fn partial_sort_unstable_by_key(&mut self, range: R, mut f: F) + where + F: FnMut(&T) -> K, + K: Ord, + R: RangeBounds, + { + sort::unstable::partial_sort(self, range, |a, b| f(a).lt(&f(b))); + } + /// Reorders the slice such that the element at `index` is at a sort-order position. All /// elements before `index` will be `<=` to this value, and all elements after will be `>=` to /// it. diff --git a/library/core/src/slice/sort/unstable/mod.rs b/library/core/src/slice/sort/unstable/mod.rs index d4df8d3a264d..7ca95a3b1b19 100644 --- a/library/core/src/slice/sort/unstable/mod.rs +++ b/library/core/src/slice/sort/unstable/mod.rs @@ -1,11 +1,13 @@ //! This module contains the entry points for `slice::sort_unstable`. use crate::mem::SizedTypeProperties; +use crate::ops::{Range, RangeBounds}; +use crate::slice::sort::select::partition_at_index; #[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] use crate::slice::sort::shared::find_existing_run; #[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] use crate::slice::sort::shared::smallsort::insertion_sort_shift_left; -use crate::{cfg_select, intrinsics}; +use crate::{cfg_select, intrinsics, slice}; pub(crate) mod heapsort; pub(crate) mod quicksort; @@ -17,7 +19,10 @@ pub(crate) mod quicksort; /// Upholds all safety properties outlined here: /// #[inline(always)] -pub fn sort bool>(v: &mut [T], is_less: &mut F) { +pub fn sort(v: &mut [T], is_less: &mut F) +where + F: FnMut(&T, &T) -> bool, +{ // Arrays of zero-sized types are always all-equal, and thus sorted. if T::IS_ZST { return; @@ -52,6 +57,54 @@ pub fn sort bool>(v: &mut [T], is_less: &mut F) { } } +/// Unstable partial sort the range `start..end`, after which it's guaranteed that: +/// +/// 1. Every element in `v[..start]` is smaller than or equal to +/// 2. Every element in `v[start..end]`, which is sorted, and smaller than or equal to +/// 3. Every element in `v[end..]`. +#[inline] +pub fn partial_sort(v: &mut [T], range: R, mut is_less: F) +where + F: FnMut(&T, &T) -> bool, + R: RangeBounds, +{ + // Arrays of zero-sized types are always all-equal, and thus sorted. + if T::IS_ZST { + return; + } + + let len = v.len(); + let Range { start, end } = slice::range(range, ..len); + + if end - start <= 1 { + // Empty range or single element. This case can be resolved in at most + // single partition_at_index call, without further sorting. + + if end == 0 || start == len { + // Do nothing if it is an empty range at start or end: all guarantees + // are already upheld. + return; + } + + partition_at_index(v, start, &mut is_less); + return; + } + + // A heuristic factor to decide whether to partition the slice or not. + // If the range bound is close to the edges of the slice, it's not worth + // partitioning first. + const PARTITION_THRESHOLD: usize = 8; + let mut v = v; + if end + PARTITION_THRESHOLD <= len { + v = partition_at_index(v, end - 1, &mut is_less).0; + } + if start >= PARTITION_THRESHOLD { + v = partition_at_index(v, start, &mut is_less).2; + } + + sort(v, &mut is_less); +} + /// See [`sort`] /// /// Deliberately don't inline the main sorting routine entrypoint to ensure the From 35ad1705ed646aa866f8cadee364cbec05ee66cd Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 6 Jan 2026 12:09:02 +1100 Subject: [PATCH 0451/1061] Optimize canonicalizer flag checks. The most important change here relates to type folding: we now check the flags up front, instead of doing it in `inner_fold_ty` after checking the cache and doing a match. This is a small perf win, and matches other similar folders (e.g. `CanonicalInstantiator`). Likewise for const folding, we now check the flags first. (There is no cache for const folding.) Elsewhere we don't check flags before folding a predicate (unnecessary, because `fold_predicate` already checks the flags itself before doing anything else), and invert the flag checks in a couple of methods to match the standard order. --- .../src/canonical/canonicalizer.rs | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index 9162284422d0..22695da5a4d7 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -109,6 +109,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { let (max_universe, variables) = canonicalizer.finalize(); Canonical { max_universe, variables, value } } + fn canonicalize_param_env( delegate: &'a D, variables: &'a mut Vec, @@ -215,16 +216,12 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { }; let predicate = input.goal.predicate; - let predicate = if predicate.has_type_flags(NEEDS_CANONICAL) { - predicate.fold_with(&mut rest_canonicalizer) - } else { - predicate - }; + let predicate = predicate.fold_with(&mut rest_canonicalizer); let goal = Goal { param_env, predicate }; let predefined_opaques_in_body = input.predefined_opaques_in_body; let predefined_opaques_in_body = - if input.predefined_opaques_in_body.has_type_flags(NEEDS_CANONICAL) { + if predefined_opaques_in_body.has_type_flags(NEEDS_CANONICAL) { predefined_opaques_in_body.fold_with(&mut rest_canonicalizer) } else { predefined_opaques_in_body @@ -391,11 +388,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { | ty::Alias(_, _) | ty::Bound(_, _) | ty::Error(_) => { - return if t.has_type_flags(NEEDS_CANONICAL) { - ensure_sufficient_stack(|| t.super_fold_with(self)) - } else { - t - }; + return ensure_sufficient_stack(|| t.super_fold_with(self)); } }; @@ -477,7 +470,9 @@ impl, I: Interner> TypeFolder for Canonicaliz } fn fold_ty(&mut self, t: I::Ty) -> I::Ty { - if let Some(&ty) = self.cache.get(&t) { + if !t.flags().intersects(NEEDS_CANONICAL) { + t + } else if let Some(&ty) = self.cache.get(&t) { ty } else { let res = self.inner_fold_ty(t); @@ -488,6 +483,10 @@ impl, I: Interner> TypeFolder for Canonicaliz } fn fold_const(&mut self, c: I::Const) -> I::Const { + if !c.flags().intersects(NEEDS_CANONICAL) { + return c; + } + let kind = match c.kind() { ty::ConstKind::Infer(i) => match i { ty::InferConst::Var(vid) => { @@ -527,9 +526,7 @@ impl, I: Interner> TypeFolder for Canonicaliz | ty::ConstKind::Unevaluated(_) | ty::ConstKind::Value(_) | ty::ConstKind::Error(_) - | ty::ConstKind::Expr(_) => { - return if c.has_type_flags(NEEDS_CANONICAL) { c.super_fold_with(self) } else { c }; - } + | ty::ConstKind::Expr(_) => return c.super_fold_with(self), }; let var = self.get_or_insert_bound_var(c, kind); @@ -538,7 +535,7 @@ impl, I: Interner> TypeFolder for Canonicaliz } fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { - if p.flags().intersects(NEEDS_CANONICAL) { p.super_fold_with(self) } else { p } + if !p.flags().intersects(NEEDS_CANONICAL) { p } else { p.super_fold_with(self) } } fn fold_clauses(&mut self, c: I::Clauses) -> I::Clauses { @@ -549,6 +546,6 @@ impl, I: Interner> TypeFolder for Canonicaliz panic!("erasing 'static in env") } } - if c.flags().intersects(NEEDS_CANONICAL) { c.super_fold_with(self) } else { c } + if !c.flags().intersects(NEEDS_CANONICAL) { c } else { c.super_fold_with(self) } } } From 484ea769d3db73b912ef05367ade53fee874e023 Mon Sep 17 00:00:00 2001 From: paradoxicalguy Date: Wed, 31 Dec 2025 06:49:53 +0000 Subject: [PATCH 0452/1061] adding minicore to test file to avoid duplicating lang error --- tests/assembly-llvm/rust-abi-arg-attr.rs | 42 ++---------------------- tests/auxiliary/minicore.rs | 18 ++++++++++ 2 files changed, 21 insertions(+), 39 deletions(-) diff --git a/tests/assembly-llvm/rust-abi-arg-attr.rs b/tests/assembly-llvm/rust-abi-arg-attr.rs index 4f3673ccfc3b..2d13feb021ba 100644 --- a/tests/assembly-llvm/rust-abi-arg-attr.rs +++ b/tests/assembly-llvm/rust-abi-arg-attr.rs @@ -1,3 +1,4 @@ +//@ add-minicore //@ assembly-output: emit-asm //@ revisions: riscv64 riscv64-zbb loongarch64 //@ compile-flags: -C opt-level=3 @@ -14,45 +15,8 @@ #![no_std] #![no_core] // FIXME: Migrate these code after PR #130693 is landed. - -#[lang = "pointee_sized"] -pub trait PointeeSized {} - -#[lang = "meta_sized"] -pub trait MetaSized: PointeeSized {} - -#[lang = "sized"] -pub trait Sized: MetaSized {} - -#[lang = "copy"] -trait Copy {} - -impl Copy for i8 {} -impl Copy for u32 {} -impl Copy for i32 {} - -#[lang = "neg"] -trait Neg { - type Output; - - fn neg(self) -> Self::Output; -} - -impl Neg for i8 { - type Output = i8; - - fn neg(self) -> Self::Output { - -self - } -} - -#[lang = "Ordering"] -#[repr(i8)] -enum Ordering { - Less = -1, - Equal = 0, - Greater = 1, -} +extern crate minicore; +use minicore::*; #[rustc_intrinsic] fn three_way_compare(lhs: T, rhs: T) -> Ordering; diff --git a/tests/auxiliary/minicore.rs b/tests/auxiliary/minicore.rs index 288a5b50dd5e..d349262b2559 100644 --- a/tests/auxiliary/minicore.rs +++ b/tests/auxiliary/minicore.rs @@ -210,6 +210,14 @@ impl Neg for isize { } } +impl Neg for i8 { + type Output = i8; + + fn neg(self) -> i8 { + loop {} + } +} + #[lang = "sync"] trait Sync {} impl_marker_trait!( @@ -280,6 +288,16 @@ pub enum c_void { __variant2, } +#[lang = "Ordering"] +#[repr(i8)] +pub enum Ordering { + Less = -1, + Equal = 0, + Greater = 1, +} + +impl Copy for Ordering {} + #[lang = "const_param_ty"] #[diagnostic::on_unimplemented(message = "`{Self}` can't be used as a const parameter type")] pub trait ConstParamTy_ {} From a97825c3f3afd60746a018628a70eea68b7890ff Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Tue, 6 Jan 2026 21:14:57 -0500 Subject: [PATCH 0453/1061] Update cargo submodule --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index b54051b15052..8c133afcd5e0 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit b54051b1505281ec7a45a250140a0ff25d33f319 +Subproject commit 8c133afcd5e0d69932fe11f5907683723f8d361d From 48ccb1f187d56a4d8626421575a47898112412b9 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 9 Jan 2026 12:57:39 +0800 Subject: [PATCH 0454/1061] Retire outdated stage0 std remarks Co-authored-by: Deadbeef --- .../src/building/new-target.md | 32 ++++--------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/building/new-target.md b/src/doc/rustc-dev-guide/src/building/new-target.md index 436aec8ee265..8465a1388870 100644 --- a/src/doc/rustc-dev-guide/src/building/new-target.md +++ b/src/doc/rustc-dev-guide/src/building/new-target.md @@ -80,32 +80,12 @@ will then add a corresponding file for your new target containing a Look for existing targets to use as examples. -After adding your target to the `rustc_target` crate you may want to add -`core`, `std`, ... with support for your new target. In that case you will -probably need access to some `target_*` cfg. Unfortunately when building with -stage0 (a precompiled compiler), you'll get an error that the target cfg is -unexpected because stage0 doesn't know about the new target specification and -we pass `--check-cfg` in order to tell it to check. - -To fix the errors you will need to manually add the unexpected value to the -different `Cargo.toml` in `library/{std,alloc,core}/Cargo.toml`. Here is an -example for adding `NEW_TARGET_ARCH` as `target_arch`: - -*`library/std/Cargo.toml`*: -```diff - [lints.rust.unexpected_cfgs] - level = "warn" - check-cfg = [ - 'cfg(bootstrap)', -- 'cfg(target_arch, values("xtensa"))', -+ # #[cfg(bootstrap)] NEW_TARGET_ARCH -+ 'cfg(target_arch, values("xtensa", "NEW_TARGET_ARCH"))', -``` - -To use this target in bootstrap, we need to explicitly add the target triple to the `STAGE0_MISSING_TARGETS` -list in `src/bootstrap/src/core/sanity.rs`. This is necessary because the default compiler bootstrap uses does -not recognize the new target we just added. Therefore, it should be added to `STAGE0_MISSING_TARGETS` so that the -bootstrap is aware that this target is not yet supported by the stage0 compiler. +To use this target in bootstrap, we need to explicitly add the target triple to +the `STAGE0_MISSING_TARGETS` list in `src/bootstrap/src/core/sanity.rs`. This +is necessary because the default bootstrap compiler (typically a beta compiler) +does not recognize the new target we just added. Therefore, it should be added to +`STAGE0_MISSING_TARGETS` so that the bootstrap is aware that this target is not +yet supported by the stage0 compiler. ```diff const STAGE0_MISSING_TARGETS: &[&str] = &[ From 97fc739602cb8e0800734a86bb40331e1bb73f20 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Fri, 9 Jan 2026 10:31:18 +0530 Subject: [PATCH 0455/1061] std: sys: fs: uefi: Implement File::tell - Just a call to get_position - Tested with OVMF on QEMU Signed-off-by: Ayush Singh --- library/std/src/sys/fs/uefi.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index b1e5f33b1b22..3b10986f17f9 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -364,7 +364,7 @@ impl File { } pub fn tell(&self) -> io::Result { - unsupported() + self.0.position() } pub fn duplicate(&self) -> io::Result { @@ -734,6 +734,14 @@ mod uefi_fs { if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } } + pub(crate) fn position(&self) -> io::Result { + let file_ptr = self.protocol.as_ptr(); + let mut pos = 0; + + let r = unsafe { ((*file_ptr).get_position)(file_ptr, &mut pos) }; + if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(pos) } + } + pub(crate) fn delete(self) -> io::Result<()> { let file_ptr = self.protocol.as_ptr(); let r = unsafe { ((*file_ptr).delete)(file_ptr) }; From 0495a7347454772a93be512cd5de7118d407a0f8 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 7 Jan 2026 13:04:10 +1100 Subject: [PATCH 0456/1061] Prepare for `thir::Pat` nodes having multiple user-type ascriptions --- .../src/builder/matches/mod.rs | 41 ++++++++++--------- .../src/builder/matches/user_ty.rs | 29 ++++++++----- 2 files changed, 41 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 9080e2ba801b..aaca6936dcd2 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -879,6 +879,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &ProjectedUserTypesNode<'_>, ), ) { + // Ascriptions correspond to user-written types like `let A::<'a>(_): A<'static> = ...;`. + // + // Caution: Pushing user types here is load-bearing even for + // patterns containing no bindings, to ensure that the type ends + // up represented in MIR _somewhere_. + let user_tys = match pattern.kind { + PatKind::AscribeUserType { ref ascription, .. } => { + let base_user_tys = std::iter::once(ascription) + .map(|thir::Ascription { annotation, variance: _ }| { + // Note that the variance doesn't apply here, as we are tracking the effect + // of user types on any bindings contained with subpattern. + self.canonical_user_type_annotations.push(annotation.clone()) + }) + .collect(); + &user_tys.push_user_types(base_user_tys) + } + _ => user_tys, + }; + // Avoid having to write the full method name at each recursive call. let visit_subpat = |this: &mut Self, subpat, user_tys: &_, f: &mut _| { this.visit_primary_bindings_special(subpat, user_tys, f) @@ -924,25 +943,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { visit_subpat(self, subpattern, &ProjectedUserTypesNode::None, f); } - PatKind::AscribeUserType { - ref subpattern, - ascription: thir::Ascription { ref annotation, variance: _ }, - } => { - // This corresponds to something like - // - // ``` - // let A::<'a>(_): A<'static> = ...; - // ``` - // - // Note that the variance doesn't apply here, as we are tracking the effect - // of `user_ty` on any bindings contained with subpattern. - - // Caution: Pushing this user type here is load-bearing even for - // patterns containing no bindings, to ensure that the type ends - // up represented in MIR _somewhere_. - let base_user_ty = self.canonical_user_type_annotations.push(annotation.clone()); - let subpattern_user_tys = user_tys.push_user_type(base_user_ty); - visit_subpat(self, subpattern, &subpattern_user_tys, f) + PatKind::AscribeUserType { ref subpattern, ascription: _ } => { + // The ascription was already handled above, so just recurse to the subpattern. + visit_subpat(self, subpattern, user_tys, f) } PatKind::ExpandedConstant { ref subpattern, .. } => { diff --git a/compiler/rustc_mir_build/src/builder/matches/user_ty.rs b/compiler/rustc_mir_build/src/builder/matches/user_ty.rs index df9f93ac328a..2dcfd3772902 100644 --- a/compiler/rustc_mir_build/src/builder/matches/user_ty.rs +++ b/compiler/rustc_mir_build/src/builder/matches/user_ty.rs @@ -8,15 +8,20 @@ use std::assert_matches::assert_matches; use std::iter; use rustc_abi::{FieldIdx, VariantIdx}; +use rustc_data_structures::smallvec::SmallVec; use rustc_middle::mir::{ProjectionElem, UserTypeProjection, UserTypeProjections}; use rustc_middle::ty::{AdtDef, UserTypeAnnotationIndex}; use rustc_span::Symbol; +/// A single `thir::Pat` node should almost never have more than 0-2 user types. +/// We can store up to 4 inline in the same size as an ordinary `Vec`. +pub(crate) type UserTypeIndices = SmallVec<[UserTypeAnnotationIndex; 4]>; + /// One of a list of "operations" that can be used to lazily build projections /// of user-specified types. -#[derive(Clone, Debug)] +#[derive(Debug)] pub(crate) enum ProjectedUserTypesOp { - PushUserType { base: UserTypeAnnotationIndex }, + PushUserTypes { base_types: UserTypeIndices }, Index, Subslice { from: u64, to: u64 }, @@ -32,9 +37,10 @@ pub(crate) enum ProjectedUserTypesNode<'a> { } impl<'a> ProjectedUserTypesNode<'a> { - pub(crate) fn push_user_type(&'a self, base: UserTypeAnnotationIndex) -> Self { - // Pushing a base user type always causes the chain to become non-empty. - Self::Chain { parent: self, op: ProjectedUserTypesOp::PushUserType { base } } + pub(crate) fn push_user_types(&'a self, base_types: UserTypeIndices) -> Self { + assert!(!base_types.is_empty()); + // Pushing one or more base user types always causes the chain to become non-empty. + Self::Chain { parent: self, op: ProjectedUserTypesOp::PushUserTypes { base_types } } } /// Push another projection op onto the chain, but only if it is already non-empty. @@ -94,16 +100,19 @@ impl<'a> ProjectedUserTypesNode<'a> { return None; } - let ops_reversed = self.iter_ops_reversed().cloned().collect::>(); + let ops_reversed = self.iter_ops_reversed().collect::>(); // The "first" op should always be `PushUserType`. // Other projections are only added if there is at least one user type. - assert_matches!(ops_reversed.last(), Some(ProjectedUserTypesOp::PushUserType { .. })); + assert_matches!(ops_reversed.last(), Some(ProjectedUserTypesOp::PushUserTypes { .. })); let mut projections = vec![]; for op in ops_reversed.into_iter().rev() { - match op { - ProjectedUserTypesOp::PushUserType { base } => { - projections.push(UserTypeProjection { base, projs: vec![] }) + match *op { + ProjectedUserTypesOp::PushUserTypes { ref base_types } => { + assert!(!base_types.is_empty()); + for &base in base_types { + projections.push(UserTypeProjection { base, projs: vec![] }) + } } ProjectedUserTypesOp::Index => { From f85b898c45bccef0142485d0d092ab66688b4641 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 6 Jan 2026 14:34:55 +1100 Subject: [PATCH 0457/1061] Prefer to return `Box` instead of `thir::PatKind` This will allow extra data to be attached to the `Pat` before it is returned. --- .../src/thir/pattern/const_to_pat.rs | 14 ++- .../rustc_mir_build/src/thir/pattern/mod.rs | 96 ++++++++++++------- 2 files changed, 69 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 2da9a43f71d8..76b742aa6e45 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -174,10 +174,10 @@ impl<'tcx> ConstToPat<'tcx> { } }; - // Convert the valtree to a const. - let inlined_const_as_pat = self.valtree_to_pat(valtree, ty); + // Lower the valtree to a THIR pattern. + let mut thir_pat = self.valtree_to_pat(valtree, ty); - if !inlined_const_as_pat.references_error() { + if !thir_pat.references_error() { // Always check for `PartialEq` if we had no other errors yet. if !type_has_partial_eq_impl(self.tcx, typing_env, ty).has_impl { let mut err = self.tcx.dcx().create_err(TypeNotPartialEq { span: self.span, ty }); @@ -188,8 +188,12 @@ 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. - let kind = PatKind::ExpandedConstant { subpattern: inlined_const_as_pat, def_id: uv.def }; - Box::new(Pat { kind, ty, span: self.span }) + thir_pat = Box::new(Pat { + ty: thir_pat.ty, + span: thir_pat.span, + kind: PatKind::ExpandedConstant { def_id: uv.def, subpattern: thir_pat }, + }); + thir_pat } fn field_pats( diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 4128508955cb..01986d946d45 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -167,9 +167,10 @@ impl<'tcx> PatCtxt<'tcx> { // Return None in that case; the caller will use NegInfinity or PosInfinity instead. let Some(expr) = expr else { return Ok(None) }; - // Lower the endpoint into a temporary `PatKind` that will then be + // Lower the endpoint into a temporary `thir::Pat` that will then be // deconstructed to obtain the constant value and other data. - let mut kind: PatKind<'tcx> = self.lower_pat_expr(pat, expr); + let endpoint_pat: Box> = self.lower_pat_expr(pat, expr); + let box Pat { mut kind, .. } = endpoint_pat; // Unpeel any ascription or inline-const wrapper nodes. loop { @@ -250,7 +251,7 @@ impl<'tcx> PatCtxt<'tcx> { lo_expr: Option<&'tcx hir::PatExpr<'tcx>>, hi_expr: Option<&'tcx hir::PatExpr<'tcx>>, end: RangeEnd, - ) -> Result, ErrorGuaranteed> { + ) -> Result>, ErrorGuaranteed> { let ty = self.typeck_results.node_type(pat.hir_id); let span = pat.span; @@ -306,27 +307,34 @@ impl<'tcx> PatCtxt<'tcx> { return Err(e); } } + let mut thir_pat = Box::new(Pat { ty, span, kind }); // If we are handling a range with associated constants (e.g. // `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated // constants somewhere. Have them on the range pattern. for ascription in ascriptions { - let subpattern = Box::new(Pat { span, ty, kind }); - kind = PatKind::AscribeUserType { ascription, subpattern }; + thir_pat = Box::new(Pat { + ty, + span, + kind: PatKind::AscribeUserType { ascription, subpattern: thir_pat }, + }); } // `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 // . - Ok(kind) + Ok(thir_pat) } #[instrument(skip(self), level = "debug")] fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box> { - let mut ty = self.typeck_results.node_type(pat.hir_id); - let mut span = pat.span; + let ty = self.typeck_results.node_type(pat.hir_id); + let span = pat.span; + // Some of these match arms return a `Box` early, while others + // evaluate to a `PatKind` that will become a `Box` at the end of + // this function. let kind = match pat.kind { hir::PatKind::Missing => PatKind::Missing, @@ -334,10 +342,13 @@ impl<'tcx> PatCtxt<'tcx> { hir::PatKind::Never => PatKind::Never, - hir::PatKind::Expr(value) => self.lower_pat_expr(pat, value), + hir::PatKind::Expr(value) => return self.lower_pat_expr(pat, value), hir::PatKind::Range(lo_expr, hi_expr, end) => { - self.lower_pattern_range(pat, lo_expr, hi_expr, end).unwrap_or_else(PatKind::Error) + match self.lower_pattern_range(pat, lo_expr, hi_expr, end) { + Ok(thir_pat) => return thir_pat, + Err(e) => PatKind::Error(e), + } } hir::PatKind::Deref(subpattern) => { @@ -360,7 +371,7 @@ impl<'tcx> PatCtxt<'tcx> { }, hir::PatKind::Slice(prefix, slice, suffix) => { - self.slice_or_array_pattern(pat, prefix, slice, suffix) + return self.slice_or_array_pattern(pat, prefix, slice, suffix); } hir::PatKind::Tuple(pats, ddpos) => { @@ -372,8 +383,9 @@ impl<'tcx> PatCtxt<'tcx> { } hir::PatKind::Binding(explicit_ba, id, ident, sub) => { + let mut thir_pat_span = span; if let Some(ident_span) = ident.span.find_ancestor_inside(span) { - span = span.with_hi(ident_span.hi()); + thir_pat_span = span.with_hi(ident_span.hi()); } let mode = *self @@ -389,22 +401,23 @@ impl<'tcx> PatCtxt<'tcx> { // A ref x pattern is the same node used for x, and as such it has // x's type, which is &T, where we want T (the type being matched). let var_ty = ty; + let mut thir_pat_ty = ty; if let hir::ByRef::Yes(pinnedness, _) = mode.0 { match pinnedness { hir::Pinnedness::Pinned if let Some(pty) = ty.pinned_ty() && let &ty::Ref(_, rty, _) = pty.kind() => { - ty = rty; + thir_pat_ty = rty; } hir::Pinnedness::Not if let &ty::Ref(_, rty, _) = ty.kind() => { - ty = rty; + thir_pat_ty = rty; } _ => bug!("`ref {}` has wrong type {}", ident, ty), } }; - PatKind::Binding { + let kind = PatKind::Binding { mode, name: ident.name, var: LocalVarId(id), @@ -412,7 +425,10 @@ impl<'tcx> PatCtxt<'tcx> { subpattern: self.lower_opt_pattern(sub), is_primary: id == pat.hir_id, is_shorthand: false, - } + }; + // We might have modified the type or span, so use the modified + // values in the THIR pattern node. + return Box::new(Pat { ty: thir_pat_ty, span: thir_pat_span, kind }); } hir::PatKind::TupleStruct(ref qpath, pats, ddpos) => { @@ -422,7 +438,7 @@ impl<'tcx> PatCtxt<'tcx> { }; let variant_def = adt_def.variant_of_res(res); let subpatterns = self.lower_tuple_subpats(pats, variant_def.fields.len(), ddpos); - self.lower_variant_or_leaf(pat, None, res, subpatterns) + return self.lower_variant_or_leaf(pat, None, res, subpatterns); } hir::PatKind::Struct(ref qpath, fields, _) => { @@ -439,7 +455,7 @@ impl<'tcx> PatCtxt<'tcx> { }) .collect(); - self.lower_variant_or_leaf(pat, None, res, subpatterns) + return self.lower_variant_or_leaf(pat, None, res, subpatterns); } hir::PatKind::Or(pats) => PatKind::Or { pats: self.lower_patterns(pats) }, @@ -450,6 +466,8 @@ impl<'tcx> PatCtxt<'tcx> { hir::PatKind::Err(guar) => PatKind::Error(guar), }; + // For pattern kinds that haven't already returned, create a `thir::Pat` + // with the HIR pattern node's type and span. Box::new(Pat { span, ty, kind }) } @@ -482,13 +500,14 @@ impl<'tcx> PatCtxt<'tcx> { prefix: &'tcx [hir::Pat<'tcx>], slice: Option<&'tcx hir::Pat<'tcx>>, suffix: &'tcx [hir::Pat<'tcx>], - ) -> PatKind<'tcx> { + ) -> Box> { let ty = self.typeck_results.node_type(pat.hir_id); + let span = pat.span; let prefix = self.lower_patterns(prefix); let slice = self.lower_opt_pattern(slice); let suffix = self.lower_patterns(suffix); - match ty.kind() { + let kind = match ty.kind() { // Matching a slice, `[T]`. ty::Slice(..) => PatKind::Slice { prefix, slice, suffix }, // Fixed-length array, `[T; len]`. @@ -499,8 +518,9 @@ impl<'tcx> PatCtxt<'tcx> { assert!(len >= prefix.len() as u64 + suffix.len() as u64); PatKind::Array { prefix, slice, suffix } } - _ => span_bug!(pat.span, "bad slice pattern type {ty:?}"), - } + _ => span_bug!(span, "bad slice pattern type {ty:?}"), + }; + Box::new(Pat { ty, span, kind }) } fn lower_variant_or_leaf( @@ -509,7 +529,7 @@ impl<'tcx> PatCtxt<'tcx> { expr: Option<&'tcx hir::PatExpr<'tcx>>, res: Res, subpatterns: Vec>, - ) -> PatKind<'tcx> { + ) -> Box> { // Check whether the caller should have provided an `expr` for this pattern kind. assert_matches!( (pat.kind, expr), @@ -533,7 +553,7 @@ impl<'tcx> PatCtxt<'tcx> { res => res, }; - let mut kind = match res { + let kind = match res { Res::Def(DefKind::Variant, variant_id) => { let enum_id = self.tcx.parent(variant_id); let adt_def = self.tcx.adt_def(enum_id); @@ -542,7 +562,7 @@ impl<'tcx> PatCtxt<'tcx> { ty::Adt(_, args) | ty::FnDef(_, args) => args, ty::Error(e) => { // Avoid ICE (#50585) - return PatKind::Error(*e); + return Box::new(Pat { ty, span, kind: PatKind::Error(*e) }); } _ => bug!("inappropriate type for def: {:?}", ty), }; @@ -583,21 +603,26 @@ impl<'tcx> PatCtxt<'tcx> { PatKind::Error(e) } }; + let mut thir_pat = Box::new(Pat { ty, span, kind }); if let Some(user_ty) = self.user_args_applied_to_ty_of_hir_id(hir_id) { - debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span); + debug!(?thir_pat, ?user_ty, ?span, "lower_variant_or_leaf: applying ascription"); let annotation = CanonicalUserTypeAnnotation { user_ty: Box::new(user_ty), span, inferred_ty: self.typeck_results.node_type(hir_id), }; - kind = PatKind::AscribeUserType { - subpattern: Box::new(Pat { span, ty, kind }), - ascription: Ascription { annotation, variance: ty::Covariant }, - }; + thir_pat = Box::new(Pat { + ty, + span, + kind: PatKind::AscribeUserType { + subpattern: thir_pat, + ascription: Ascription { annotation, variance: ty::Covariant }, + }, + }); } - kind + thir_pat } fn user_args_applied_to_ty_of_hir_id( @@ -632,8 +657,7 @@ impl<'tcx> PatCtxt<'tcx> { _ => { // The path isn't the name of a constant, so it must actually // be a unit struct or unit variant (e.g. `Option::None`). - let kind = self.lower_variant_or_leaf(pat, Some(expr), res, vec![]); - return Box::new(Pat { span, ty, kind }); + return self.lower_variant_or_leaf(pat, Some(expr), res, vec![]); } }; @@ -674,10 +698,10 @@ impl<'tcx> PatCtxt<'tcx> { &mut self, pat: &'tcx hir::Pat<'tcx>, // Pattern that directly contains `expr` expr: &'tcx hir::PatExpr<'tcx>, - ) -> PatKind<'tcx> { + ) -> Box> { assert_matches!(pat.kind, hir::PatKind::Expr(..) | hir::PatKind::Range(..)); match &expr.kind { - hir::PatExprKind::Path(qpath) => self.lower_path(pat, expr, qpath).kind, + hir::PatExprKind::Path(qpath) => self.lower_path(pat, expr, qpath), hir::PatExprKind::Lit { lit, negated } => { // We handle byte string literal patterns by using the pattern's type instead of the // literal's type in `const_to_pat`: if the literal `b"..."` matches on a slice reference, @@ -691,7 +715,7 @@ impl<'tcx> PatCtxt<'tcx> { let pat_ty = self.typeck_results.node_type(pat.hir_id); let lit_input = LitToConstInput { lit: lit.node, ty: pat_ty, neg: *negated }; let constant = self.tcx.at(expr.span).lit_to_const(lit_input); - self.const_to_pat(constant, pat_ty, expr.hir_id, lit.span).kind + self.const_to_pat(constant, pat_ty, expr.hir_id, lit.span) } } } From bd7704830331f0feb1fd8b43e18fd535663acadb Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 6 Jan 2026 18:20:31 +1100 Subject: [PATCH 0458/1061] Initial plumbing for `thir::PatExtra` --- compiler/rustc_middle/src/thir.rs | 18 +++++++- compiler/rustc_middle/src/thir/visit.rs | 2 +- .../src/thir/pattern/const_to_pat.rs | 5 ++- .../rustc_mir_build/src/thir/pattern/mod.rs | 24 +++++++---- compiler/rustc_mir_build/src/thir/print.rs | 42 ++++++++++++++++++- 5 files changed, 78 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 3683c1cfb7dd..3ddb5a1523d0 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -643,10 +643,26 @@ pub struct FieldPat<'tcx> { pub pattern: Pat<'tcx>, } +/// Additional per-node data that is not present on most THIR pattern nodes. +#[derive(Clone, Debug, Default, HashStable, TypeVisitable)] +pub struct PatExtra<'tcx> { + /// If present, this node represents 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. + pub expanded_const: Option, + + /// User-written types that must be preserved into MIR so that they can be + /// checked. + pub ascriptions: Vec>, +} + #[derive(Clone, Debug, HashStable, TypeVisitable)] pub struct Pat<'tcx> { pub ty: Ty<'tcx>, pub span: Span, + pub extra: Option>>, pub kind: PatKind<'tcx>, } @@ -1119,7 +1135,7 @@ mod size_asserts { static_assert_size!(Block, 48); static_assert_size!(Expr<'_>, 64); static_assert_size!(ExprKind<'_>, 40); - static_assert_size!(Pat<'_>, 64); + static_assert_size!(Pat<'_>, 72); static_assert_size!(PatKind<'_>, 48); static_assert_size!(Stmt<'_>, 48); static_assert_size!(StmtKind<'_>, 48); diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index d792bbe60c88..e0c044220b81 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -259,7 +259,7 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>( pat: &'a Pat<'tcx>, mut callback: impl FnMut(&'a Pat<'tcx>), ) { - let Pat { kind, ty: _, span: _ } = pat; + let Pat { kind, ty: _, span: _, extra: _ } = pat; match kind { PatKind::Missing | PatKind::Wild diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 76b742aa6e45..98faf0ab613f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -90,7 +90,7 @@ impl<'tcx> ConstToPat<'tcx> { ); } } - Box::new(Pat { span: self.span, ty, kind: PatKind::Error(err.emit()) }) + Box::new(Pat { span: self.span, ty, kind: PatKind::Error(err.emit()), extra: None }) } fn unevaluated_to_pat( @@ -192,6 +192,7 @@ impl<'tcx> ConstToPat<'tcx> { ty: thir_pat.ty, span: thir_pat.span, kind: PatKind::ExpandedConstant { def_id: uv.def, subpattern: thir_pat }, + extra: None, }); thir_pat } @@ -355,7 +356,7 @@ impl<'tcx> ConstToPat<'tcx> { } }; - Box::new(Pat { span, ty, kind }) + Box::new(Pat { span, ty, kind, extra: None }) } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 01986d946d45..9c39a934c7ee 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -78,6 +78,7 @@ pub(super) fn pat_from_hir<'tcx>( ascription: Ascription { annotation, variance: ty::Covariant }, subpattern: thir_pat, }, + extra: None, }); } @@ -142,7 +143,7 @@ impl<'tcx> PatCtxt<'tcx> { } PatAdjust::PinDeref => PatKind::Deref { subpattern: thir_pat }, }; - Box::new(Pat { span, ty: adjust.source, kind }) + Box::new(Pat { span, ty: adjust.source, kind, extra: None }) }); if let Some(s) = &mut self.rust_2024_migration @@ -307,7 +308,7 @@ impl<'tcx> PatCtxt<'tcx> { return Err(e); } } - let mut thir_pat = Box::new(Pat { ty, span, kind }); + let mut thir_pat = Box::new(Pat { ty, span, kind, extra: None }); // If we are handling a range with associated constants (e.g. // `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated @@ -317,6 +318,7 @@ impl<'tcx> PatCtxt<'tcx> { ty, span, kind: PatKind::AscribeUserType { ascription, subpattern: thir_pat }, + extra: None, }); } // `PatKind::ExpandedConstant` wrappers from range endpoints used to @@ -428,7 +430,7 @@ impl<'tcx> PatCtxt<'tcx> { }; // We might have modified the type or span, so use the modified // values in the THIR pattern node. - return Box::new(Pat { ty: thir_pat_ty, span: thir_pat_span, kind }); + return Box::new(Pat { ty: thir_pat_ty, span: thir_pat_span, kind, extra: None }); } hir::PatKind::TupleStruct(ref qpath, pats, ddpos) => { @@ -468,7 +470,7 @@ impl<'tcx> PatCtxt<'tcx> { // For pattern kinds that haven't already returned, create a `thir::Pat` // with the HIR pattern node's type and span. - Box::new(Pat { span, ty, kind }) + Box::new(Pat { span, ty, kind, extra: None }) } fn lower_tuple_subpats( @@ -520,7 +522,7 @@ impl<'tcx> PatCtxt<'tcx> { } _ => span_bug!(span, "bad slice pattern type {ty:?}"), }; - Box::new(Pat { ty, span, kind }) + Box::new(Pat { ty, span, kind, extra: None }) } fn lower_variant_or_leaf( @@ -562,7 +564,12 @@ impl<'tcx> PatCtxt<'tcx> { ty::Adt(_, args) | ty::FnDef(_, args) => args, ty::Error(e) => { // Avoid ICE (#50585) - return Box::new(Pat { ty, span, kind: PatKind::Error(*e) }); + return Box::new(Pat { + ty, + span, + kind: PatKind::Error(*e), + extra: None, + }); } _ => bug!("inappropriate type for def: {:?}", ty), }; @@ -603,7 +610,7 @@ impl<'tcx> PatCtxt<'tcx> { PatKind::Error(e) } }; - let mut thir_pat = Box::new(Pat { ty, span, kind }); + let mut thir_pat = Box::new(Pat { ty, span, kind, extra: None }); if let Some(user_ty) = self.user_args_applied_to_ty_of_hir_id(hir_id) { debug!(?thir_pat, ?user_ty, ?span, "lower_variant_or_leaf: applying ascription"); @@ -619,6 +626,7 @@ impl<'tcx> PatCtxt<'tcx> { subpattern: thir_pat, ascription: Ascription { annotation, variance: ty::Covariant }, }, + extra: None, }); } @@ -685,7 +693,7 @@ impl<'tcx> PatCtxt<'tcx> { variance: ty::Contravariant, }, }; - pattern = Box::new(Pat { span, kind, ty }); + pattern = Box::new(Pat { span, kind, ty, extra: None }); } pattern diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 5a2d6cfef1cc..d735ef2134ab 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -73,6 +73,24 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.fmt } + fn print_list( + &mut self, + label: &str, + list: &[T], + depth_lvl: usize, + print_fn: impl Fn(&mut Self, &T, usize), + ) { + if list.is_empty() { + print_indented!(self, format_args!("{label}: []"), depth_lvl); + } else { + print_indented!(self, format_args!("{label}: ["), depth_lvl); + for item in list { + print_fn(self, item, depth_lvl + 1) + } + print_indented!(self, "]", depth_lvl); + } + } + fn print_param(&mut self, param: &Param<'tcx>, depth_lvl: usize) { let Param { pat, ty, ty_span, self_kind, hir_id } = param; @@ -663,15 +681,37 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { } fn print_pat(&mut self, pat: &Pat<'tcx>, depth_lvl: usize) { - let &Pat { ty, span, ref kind } = pat; + let &Pat { ty, span, ref kind, ref extra } = pat; print_indented!(self, "Pat: {", depth_lvl); print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1); print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + self.print_pat_extra(extra.as_deref(), depth_lvl + 1); self.print_pat_kind(kind, depth_lvl + 1); print_indented!(self, "}", depth_lvl); } + fn print_pat_extra(&mut self, extra: Option<&PatExtra<'tcx>>, depth_lvl: usize) { + let Some(extra) = extra else { + // Skip printing in the common case of a pattern node with no extra data. + return; + }; + + let PatExtra { expanded_const, ascriptions } = extra; + + print_indented!(self, "extra: PatExtra {", depth_lvl); + print_indented!(self, format_args!("expanded_const: {expanded_const:?}"), depth_lvl + 1); + self.print_list( + "ascriptions", + ascriptions, + depth_lvl + 1, + |this, ascription, depth_lvl| { + print_indented!(this, format_args!("{ascription:?}"), depth_lvl); + }, + ); + print_indented!(self, "}", depth_lvl); + } + fn print_pat_kind(&mut self, pat_kind: &PatKind<'tcx>, depth_lvl: usize) { print_indented!(self, "kind: PatKind {", depth_lvl); From 8516c64115ce3689e66a2ab95de77f978f7398b6 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 6 Jan 2026 18:30:20 +1100 Subject: [PATCH 0459/1061] Replace `AscribeUserType` and `ExpandedConstant` with per-node data --- compiler/rustc_middle/src/thir.rs | 20 ----- compiler/rustc_middle/src/thir/visit.rs | 6 +- .../src/builder/custom/parse.rs | 24 ++---- .../src/builder/custom/parse/instruction.rs | 5 -- .../src/builder/matches/match_pair.rs | 41 ++++------ .../src/builder/matches/mod.rs | 67 ++++------------ .../rustc_mir_build/src/check_unsafety.rs | 2 - .../src/thir/pattern/check_match.rs | 13 +--- .../src/thir/pattern/const_to_pat.rs | 9 +-- .../rustc_mir_build/src/thir/pattern/mod.rs | 76 ++++++------------- compiler/rustc_mir_build/src/thir/print.rs | 14 ---- compiler/rustc_pattern_analysis/src/rustc.rs | 2 - 12 files changed, 68 insertions(+), 211 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 3ddb5a1523d0..e538c2182924 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -778,11 +778,6 @@ pub enum PatKind<'tcx> { /// A wildcard pattern: `_`. Wild, - AscribeUserType { - ascription: Ascription<'tcx>, - subpattern: Box>, - }, - /// `x`, `ref x`, `x @ P`, etc. Binding { name: Symbol, @@ -847,21 +842,6 @@ pub enum PatKind<'tcx> { value: ty::Value<'tcx>, }, - /// 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` 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. - subpattern: Box>, - }, - Range(Arc>), /// Matches against a slice, checking the length and extracting elements. diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index e0c044220b81..b611b23e5261 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -269,11 +269,9 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>( | PatKind::Never | PatKind::Error(_) => {} - PatKind::AscribeUserType { subpattern, .. } - | PatKind::Binding { subpattern: Some(subpattern), .. } + PatKind::Binding { subpattern: Some(subpattern), .. } | PatKind::Deref { subpattern } - | PatKind::DerefPattern { subpattern, .. } - | PatKind::ExpandedConstant { subpattern, .. } => callback(subpattern), + | PatKind::DerefPattern { subpattern, .. } => callback(subpattern), PatKind::Variant { subpatterns, .. } | PatKind::Leaf { subpatterns } => { for field_pat in subpatterns { diff --git a/compiler/rustc_mir_build/src/builder/custom/parse.rs b/compiler/rustc_mir_build/src/builder/custom/parse.rs index c6ef362c6ea5..3ae4b1fadee9 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse.rs @@ -287,22 +287,14 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { self.parse_var(pattern) } - fn parse_var(&mut self, mut pat: &Pat<'tcx>) -> PResult<(LocalVarId, Ty<'tcx>, Span)> { - // Make sure we throw out any `AscribeUserType` we find - loop { - match &pat.kind { - PatKind::Binding { var, ty, .. } => break Ok((*var, *ty, pat.span)), - PatKind::AscribeUserType { subpattern, .. } => { - pat = subpattern; - } - _ => { - break Err(ParseError { - span: pat.span, - item_description: format!("{:?}", pat.kind), - expected: "local".to_string(), - }); - } - } + fn parse_var(&mut self, pat: &Pat<'tcx>) -> PResult<(LocalVarId, Ty<'tcx>, Span)> { + match &pat.kind { + PatKind::Binding { var, ty, .. } => Ok((*var, *ty, pat.span)), + _ => Err(ParseError { + span: pat.span, + item_description: format!("{:?}", pat.kind), + expected: "local".to_string(), + }), } } diff --git a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs index ddaa61c6cc91..13082d408ec0 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs @@ -144,11 +144,6 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { let arm = &self.thir[*arm]; let value = match arm.pattern.kind { PatKind::Constant { value } => value, - PatKind::ExpandedConstant { ref subpattern, def_id: _ } - if let PatKind::Constant { value } = subpattern.kind => - { - value - } _ => { return Err(ParseError { span: arm.pattern.span, diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index f0114c2193c3..8cee3ff27e8f 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -133,6 +133,20 @@ impl<'tcx> MatchPairTree<'tcx> { } let place = place_builder.try_to_place(cx); + + // Apply any type ascriptions to the value at `match_pair.place`. + if let Some(place) = place + && let Some(extra) = &pattern.extra + { + for &Ascription { ref annotation, variance } in &extra.ascriptions { + extra_data.ascriptions.push(super::Ascription { + source: place, + annotation: annotation.clone(), + variance, + }); + } + } + let mut subpairs = Vec::new(); let testable_case = match pattern.kind { PatKind::Missing | PatKind::Wild | PatKind::Error(_) => None, @@ -195,28 +209,6 @@ impl<'tcx> MatchPairTree<'tcx> { Some(TestableCase::Constant { value, kind: const_kind }) } - PatKind::AscribeUserType { - ascription: Ascription { ref annotation, variance }, - ref subpattern, - .. - } => { - MatchPairTree::for_pattern( - place_builder, - subpattern, - cx, - &mut subpairs, - extra_data, - ); - - // Apply the type ascription to the value at `match_pair.place` - if let Some(source) = place { - let annotation = annotation.clone(); - extra_data.ascriptions.push(super::Ascription { source, annotation, variance }); - } - - None - } - PatKind::Binding { mode, var, is_shorthand, ref subpattern, .. } => { // In order to please the borrow checker, when lowering a pattern // like `x @ subpat` we must establish any bindings in `subpat` @@ -263,11 +255,6 @@ impl<'tcx> MatchPairTree<'tcx> { None } - PatKind::ExpandedConstant { subpattern: ref pattern, .. } => { - MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data); - None - } - PatKind::Array { ref prefix, ref slice, ref suffix } => { cx.prefix_slice_suffix( &mut subpairs, diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index aaca6936dcd2..590316a47554 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -576,7 +576,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { initializer_id: ExprId, ) -> BlockAnd<()> { match irrefutable_pat.kind { - // Optimize the case of `let x = ...` to write directly into `x` + // Optimize `let x = ...` and `let x: T = ...` to write directly into `x`, + // and then require that `T == typeof(x)` if present. PatKind::Binding { mode: BindingMode(ByRef::No, _), var, subpattern: None, .. } => { let place = self.storage_live_binding( block, @@ -592,43 +593,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let source_info = self.source_info(irrefutable_pat.span); self.cfg.push_fake_read(block, source_info, FakeReadCause::ForLet(None), place); - self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard); - block.unit() - } + let ascriptions: &[_] = + try { irrefutable_pat.extra.as_deref()?.ascriptions.as_slice() } + .unwrap_or_default(); + for thir::Ascription { annotation, variance: _ } in ascriptions { + let ty_source_info = self.source_info(annotation.span); - // Optimize the case of `let x: T = ...` to write directly - // into `x` and then require that `T == typeof(x)`. - PatKind::AscribeUserType { - ref subpattern, - ascription: thir::Ascription { ref annotation, variance: _ }, - } if let PatKind::Binding { - mode: BindingMode(ByRef::No, _), - var, - subpattern: None, - .. - } = subpattern.kind => - { - let place = self.storage_live_binding( - block, - var, - irrefutable_pat.span, - false, - OutsideGuard, - ScheduleDrops::Yes, - ); - block = self.expr_into_dest(place, block, initializer_id).into_block(); - - // Inject a fake read, see comments on `FakeReadCause::ForLet`. - let pattern_source_info = self.source_info(irrefutable_pat.span); - let cause_let = FakeReadCause::ForLet(None); - self.cfg.push_fake_read(block, pattern_source_info, cause_let, place); - - let ty_source_info = self.source_info(annotation.span); - - let base = self.canonical_user_type_annotations.push(annotation.clone()); - self.cfg.push( - block, - Statement::new( + let base = self.canonical_user_type_annotations.push(annotation.clone()); + let stmt = Statement::new( ty_source_info, StatementKind::AscribeUserType( Box::new((place, UserTypeProjection { base, projs: Vec::new() })), @@ -648,8 +620,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // ``. ty::Invariant, ), - ), - ); + ); + self.cfg.push(block, stmt); + } self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard); block.unit() @@ -884,9 +857,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Caution: Pushing user types here is load-bearing even for // patterns containing no bindings, to ensure that the type ends // up represented in MIR _somewhere_. - let user_tys = match pattern.kind { - PatKind::AscribeUserType { ref ascription, .. } => { - let base_user_tys = std::iter::once(ascription) + let user_tys = match pattern.extra.as_deref() { + Some(PatExtra { ascriptions, .. }) if !ascriptions.is_empty() => { + let base_user_tys = ascriptions + .iter() .map(|thir::Ascription { annotation, variance: _ }| { // Note that the variance doesn't apply here, as we are tracking the effect // of user types on any bindings contained with subpattern. @@ -943,15 +917,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { visit_subpat(self, subpattern, &ProjectedUserTypesNode::None, f); } - PatKind::AscribeUserType { ref subpattern, ascription: _ } => { - // The ascription was already handled above, so just recurse to the subpattern. - visit_subpat(self, subpattern, user_tys, f) - } - - PatKind::ExpandedConstant { ref subpattern, .. } => { - visit_subpat(self, subpattern, user_tys, f) - } - PatKind::Leaf { ref subpatterns } => { for subpattern in subpatterns { let subpattern_user_tys = user_tys.leaf(subpattern.field); diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 4f03e3d965c6..68b8a842a2a6 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -342,8 +342,6 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { PatKind::Wild | // these just wrap other patterns, which we recurse on below. PatKind::Or { .. } | - PatKind::ExpandedConstant { .. } | - PatKind::AscribeUserType { .. } | PatKind::Error(_) => {} } }; diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index bf480cf601ee..d9a06de32bb0 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -680,20 +680,13 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { let mut interpreted_as_const = None; let mut interpreted_as_const_sugg = None; - // These next few matches want to peek through `AscribeUserType` to see - // the underlying pattern. - let mut unpeeled_pat = pat; - while let PatKind::AscribeUserType { ref subpattern, .. } = unpeeled_pat.kind { - unpeeled_pat = subpattern; - } - - if let Some(def_id) = is_const_pat_that_looks_like_binding(self.tcx, unpeeled_pat) { + if let Some(def_id) = is_const_pat_that_looks_like_binding(self.tcx, 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. interpreted_as_const = Some(InterpretedAsConst { span, variable: variable.clone() }); interpreted_as_const_sugg = Some(InterpretedAsConstSugg { span: pat.span, variable }); - } else if let PatKind::Constant { .. } = unpeeled_pat.kind + } else if let PatKind::Constant { .. } = pat.kind && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span) { // If the pattern to match is an integer literal: @@ -1213,7 +1206,7 @@ fn is_const_pat_that_looks_like_binding<'tcx>(tcx: TyCtxt<'tcx>, pat: &Pat<'tcx> // 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 + if let Some(def_id) = try { pat.extra.as_deref()?.expanded_const? } && 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 == '_') diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 98faf0ab613f..02409d2bae9f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -186,14 +186,9 @@ impl<'tcx> ConstToPat<'tcx> { } } - // Wrap the pattern in a marker node to indicate that it is the result of lowering a + // Mark the pattern to indicate that it is the result of lowering a named // constant. This is used for diagnostics. - thir_pat = Box::new(Pat { - ty: thir_pat.ty, - span: thir_pat.span, - kind: PatKind::ExpandedConstant { def_id: uv.def, subpattern: thir_pat }, - extra: None, - }); + thir_pat.extra.get_or_insert_default().expanded_const = Some(uv.def); thir_pat } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 9c39a934c7ee..650650cbaac9 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -71,15 +71,11 @@ pub(super) fn pat_from_hir<'tcx>( span: let_stmt_type.span, inferred_ty: typeck_results.node_type(let_stmt_type.hir_id), }; - thir_pat = Box::new(Pat { - ty: thir_pat.ty, - span: thir_pat.span, - kind: PatKind::AscribeUserType { - ascription: Ascription { annotation, variance: ty::Covariant }, - subpattern: thir_pat, - }, - extra: None, - }); + thir_pat + .extra + .get_or_insert_default() + .ascriptions + .push(Ascription { annotation, variance: ty::Covariant }); } if let Some(m) = pcx.rust_2024_migration { @@ -171,23 +167,11 @@ impl<'tcx> PatCtxt<'tcx> { // Lower the endpoint into a temporary `thir::Pat` that will then be // deconstructed to obtain the constant value and other data. let endpoint_pat: Box> = self.lower_pat_expr(pat, expr); - let box Pat { mut kind, .. } = endpoint_pat; + let box Pat { ref kind, extra, .. } = endpoint_pat; - // Unpeel any ascription or inline-const wrapper nodes. - loop { - match kind { - PatKind::AscribeUserType { ascription, subpattern } => { - ascriptions.push(ascription); - kind = subpattern.kind; - } - 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, - } + // Preserve any ascriptions from endpoint constants. + if let Some(extra) = extra { + ascriptions.extend(extra.ascriptions); } // The unpeeled kind should now be a constant, giving us the endpoint value. @@ -313,15 +297,8 @@ impl<'tcx> PatCtxt<'tcx> { // If we are handling a range with associated constants (e.g. // `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated // constants somewhere. Have them on the range pattern. - for ascription in ascriptions { - thir_pat = Box::new(Pat { - ty, - span, - kind: PatKind::AscribeUserType { ascription, subpattern: thir_pat }, - extra: None, - }); - } - // `PatKind::ExpandedConstant` wrappers from range endpoints used to + thir_pat.extra.get_or_insert_default().ascriptions.extend(ascriptions); + // IDs of expanded constants from range endpoints used to // also be preserved here, but that was only needed for unsafeck of // inline `const { .. }` patterns, which were removed by // . @@ -619,15 +596,11 @@ impl<'tcx> PatCtxt<'tcx> { span, inferred_ty: self.typeck_results.node_type(hir_id), }; - thir_pat = Box::new(Pat { - ty, - span, - kind: PatKind::AscribeUserType { - subpattern: thir_pat, - ascription: Ascription { annotation, variance: ty::Covariant }, - }, - extra: None, - }); + thir_pat + .extra + .get_or_insert_default() + .ascriptions + .push(Ascription { annotation, variance: ty::Covariant }); } thir_pat @@ -684,16 +657,13 @@ impl<'tcx> PatCtxt<'tcx> { span, inferred_ty: self.typeck_results.node_type(id), }; - let kind = PatKind::AscribeUserType { - subpattern: pattern, - ascription: Ascription { - annotation, - // Note that we use `Contravariant` here. See the - // `variance` field documentation for details. - variance: ty::Contravariant, - }, - }; - pattern = Box::new(Pat { span, kind, ty, extra: None }); + // Note that we use `Contravariant` here. See the + // `variance` field documentation for details. + pattern + .extra + .get_or_insert_default() + .ascriptions + .push(Ascription { annotation, variance: ty::Contravariant }); } pattern diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index d735ef2134ab..e12909305961 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -725,13 +725,6 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { PatKind::Never => { print_indented!(self, "Never", depth_lvl + 1); } - PatKind::AscribeUserType { ascription, subpattern } => { - print_indented!(self, "AscribeUserType: {", depth_lvl + 1); - print_indented!(self, format!("ascription: {:?}", ascription), depth_lvl + 2); - print_indented!(self, "subpattern: ", depth_lvl + 2); - self.print_pat(subpattern, depth_lvl + 3); - print_indented!(self, "}", depth_lvl + 1); - } PatKind::Binding { name, mode, var, ty, subpattern, is_primary, is_shorthand } => { print_indented!(self, "Binding {", depth_lvl + 1); print_indented!(self, format!("name: {:?}", name), depth_lvl + 2); @@ -796,13 +789,6 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, format!("value: {}", value), depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } - PatKind::ExpandedConstant { def_id, subpattern } => { - print_indented!(self, "ExpandedConstant {", depth_lvl + 1); - print_indented!(self, format!("def_id: {def_id:?}"), depth_lvl + 2); - print_indented!(self, "subpattern:", depth_lvl + 2); - self.print_pat(subpattern, depth_lvl + 2); - print_indented!(self, "}", depth_lvl + 1); - } PatKind::Range(pat_range) => { print_indented!(self, format!("Range ( {:?} )", pat_range), depth_lvl + 1); } diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index d66c303b1726..721635ed48ff 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -462,8 +462,6 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { let arity; let fields: Vec<_>; match &pat.kind { - PatKind::AscribeUserType { subpattern, .. } - | PatKind::ExpandedConstant { subpattern, .. } => return self.lower_pat(subpattern), PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat), PatKind::Missing | PatKind::Binding { subpattern: None, .. } | PatKind::Wild => { ctor = Wildcard; From 561b59255c7f9a9b6893a06b261ab08c4343b81e Mon Sep 17 00:00:00 2001 From: andjsrk Date: Fri, 9 Jan 2026 15:45:05 +0900 Subject: [PATCH 0460/1061] add test for binary ops --- ...can-have-side-effects-consider-operands.rs | 23 +++++++++++++++++++ ...have-side-effects-consider-operands.stderr | 13 +++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/ui/binop/can-have-side-effects-consider-operands.rs create mode 100644 tests/ui/binop/can-have-side-effects-consider-operands.stderr diff --git a/tests/ui/binop/can-have-side-effects-consider-operands.rs b/tests/ui/binop/can-have-side-effects-consider-operands.rs new file mode 100644 index 000000000000..34eeb11c6add --- /dev/null +++ b/tests/ui/binop/can-have-side-effects-consider-operands.rs @@ -0,0 +1,23 @@ +//@ check-pass + +#![allow(unused)] + +// Test if `Expr::can_have_side_effects` considers operands of binary operators. + +fn drop_repeat_in_arm_body() { + // Built-in lint `dropping_copy_types` relies on `Expr::can_have_side_effects` + // (See rust-clippy#9482 and rust#113231) + + match () { + () => drop(5 % 3), // No side effects + //~^ WARNING calls to `std::mem::drop` with a value that implements `Copy` does nothing + } + match () { + () => drop(5 % calls_are_considered_side_effects()), // Definitely has side effects + } +} +fn calls_are_considered_side_effects() -> i32 { + 3 +} + +fn main() {} diff --git a/tests/ui/binop/can-have-side-effects-consider-operands.stderr b/tests/ui/binop/can-have-side-effects-consider-operands.stderr new file mode 100644 index 000000000000..ef3fc6b4be7e --- /dev/null +++ b/tests/ui/binop/can-have-side-effects-consider-operands.stderr @@ -0,0 +1,13 @@ +warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing + --> $DIR/can-have-side-effects-consider-operands.rs:12:15 + | +LL | () => drop(5 % 3), // No side effects + | ^^^^^-----^ + | | + | argument has type `i32` + | + = note: use `let _ = ...` to ignore the expression or result + = note: `#[warn(dropping_copy_types)]` on by default + +warning: 1 warning emitted + From 7d0b1e144917b46d3e2b5c18ef6d434b098dab08 Mon Sep 17 00:00:00 2001 From: Coca Date: Fri, 2 Jan 2026 20:59:22 +0000 Subject: [PATCH 0461/1061] `transmuting_null`: Add checks for `without_provenance` and `without_provenance_mut` Currently `without_provenance`/`without_provenance_mut` do not have a `rustc_diagnostic_item` so this change is dependent on them being added before being ready to be used. changelog: [`transmuting_null`]: now checks for [`ptr::without_provenance`](https://doc.rust-lang.org/core/ptr/fn.without_provenance.html) and [`ptr::without_provenance_mut`](https://doc.rust-lang.org/core/ptr/fn.without_provenance_mut.html) which create null pointers --- clippy_lints/src/transmute/transmuting_null.rs | 12 ++++++++++++ tests/ui/transmuting_null.rs | 11 +++++++++++ tests/ui/transmuting_null.stderr | 14 +++++++++++++- 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/transmute/transmuting_null.rs b/clippy_lints/src/transmute/transmuting_null.rs index 3f435f255d91..4f06d98703f6 100644 --- a/clippy_lints/src/transmute/transmuting_null.rs +++ b/clippy_lints/src/transmute/transmuting_null.rs @@ -42,6 +42,18 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t return true; } + // Catching: + // `std::mem::transmute(std::ptr::without_provenance::(0))` + // `std::mem::transmute(std::ptr::without_provenance_mut::(0))` + if let ExprKind::Call(func1, [arg1]) = arg.kind + && (func1.basic_res().is_diag_item(cx, sym::ptr_without_provenance) + || func1.basic_res().is_diag_item(cx, sym::ptr_without_provenance_mut)) + && is_integer_const(cx, arg1, 0) + { + span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); + return true; + } + // Catching: // `std::mem::transmute({ 0 as *const u64 })` and similar const blocks if let ExprKind::Block(block, _) = arg.kind diff --git a/tests/ui/transmuting_null.rs b/tests/ui/transmuting_null.rs index 00aa35dff803..efa4c5cfdc2d 100644 --- a/tests/ui/transmuting_null.rs +++ b/tests/ui/transmuting_null.rs @@ -47,9 +47,20 @@ fn transumute_single_expr_blocks() { } } +fn transmute_pointer_creators() { + unsafe { + let _: &u64 = std::mem::transmute(std::ptr::without_provenance::(0)); + //~^ transmuting_null + + let _: &u64 = std::mem::transmute(std::ptr::without_provenance_mut::(0)); + //~^ transmuting_null + } +} + fn main() { one_liners(); transmute_const(); transmute_const_int(); transumute_single_expr_blocks(); + transmute_pointer_creators(); } diff --git a/tests/ui/transmuting_null.stderr b/tests/ui/transmuting_null.stderr index e1de391813bd..3c6c28f31d0d 100644 --- a/tests/ui/transmuting_null.stderr +++ b/tests/ui/transmuting_null.stderr @@ -37,5 +37,17 @@ error: transmuting a known null pointer into a reference LL | let _: &u64 = std::mem::transmute(const { u64::MIN as *const u64 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: transmuting a known null pointer into a reference + --> tests/ui/transmuting_null.rs:52:23 + | +LL | let _: &u64 = std::mem::transmute(std::ptr::without_provenance::(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: transmuting a known null pointer into a reference + --> tests/ui/transmuting_null.rs:55:23 + | +LL | let _: &u64 = std::mem::transmute(std::ptr::without_provenance_mut::(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 8 previous errors From 7e433ebe7e7b6d3749ec1aed039ab4408d4ad051 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Fri, 9 Jan 2026 04:08:45 +0100 Subject: [PATCH 0462/1061] [miri] make closing stdio file descriptions noops std supports redirecting stdio file descriptors. --- src/tools/miri/src/shims/files.rs | 36 +++++++++++++++++++ .../tests/fail-dep/libc/fs/close_stdout.rs | 10 ------ .../fail-dep/libc/fs/close_stdout.stderr | 12 ------- src/tools/miri/tests/pass-dep/libc/libc-fs.rs | 9 +++++ 4 files changed, 45 insertions(+), 22 deletions(-) delete mode 100644 src/tools/miri/tests/fail-dep/libc/fs/close_stdout.rs delete mode 100644 src/tools/miri/tests/fail-dep/libc/fs/close_stdout.stderr diff --git a/src/tools/miri/src/shims/files.rs b/src/tools/miri/src/shims/files.rs index f86933029341..694a5922b799 100644 --- a/src/tools/miri/src/shims/files.rs +++ b/src/tools/miri/src/shims/files.rs @@ -249,6 +249,15 @@ impl FileDescription for io::Stdin { finish.call(ecx, result) } + fn destroy<'tcx>( + self, + _self_id: FdId, + _communicate_allowed: bool, + _ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, io::Result<()>> { + interp_ok(Ok(())) + } + fn is_tty(&self, communicate_allowed: bool) -> bool { communicate_allowed && self.is_terminal() } @@ -279,6 +288,15 @@ impl FileDescription for io::Stdout { finish.call(ecx, result) } + fn destroy<'tcx>( + self, + _self_id: FdId, + _communicate_allowed: bool, + _ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, io::Result<()>> { + interp_ok(Ok(())) + } + fn is_tty(&self, communicate_allowed: bool) -> bool { communicate_allowed && self.is_terminal() } @@ -289,6 +307,15 @@ impl FileDescription for io::Stderr { "stderr" } + fn destroy<'tcx>( + self, + _self_id: FdId, + _communicate_allowed: bool, + _ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, io::Result<()>> { + interp_ok(Ok(())) + } + fn write<'tcx>( self: FileDescriptionRef, _communicate_allowed: bool, @@ -436,6 +463,15 @@ impl FileDescription for NullOutput { // We just don't write anything, but report to the user that we did. finish.call(ecx, Ok(len)) } + + fn destroy<'tcx>( + self, + _self_id: FdId, + _communicate_allowed: bool, + _ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, io::Result<()>> { + interp_ok(Ok(())) + } } /// Internal type of a file-descriptor - this is what [`FdTable`] expects diff --git a/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.rs b/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.rs deleted file mode 100644 index 7911133f548f..000000000000 --- a/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ignore-target: windows # No libc IO on Windows -//@compile-flags: -Zmiri-disable-isolation - -// FIXME: standard handles cannot be closed (https://github.com/rust-lang/rust/issues/40032) - -fn main() { - unsafe { - libc::close(1); //~ ERROR: cannot close stdout - } -} diff --git a/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.stderr b/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.stderr deleted file mode 100644 index 84973ac020de..000000000000 --- a/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error: unsupported operation: cannot close stdout - --> tests/fail-dep/libc/fs/close_stdout.rs:LL:CC - | -LL | libc::close(1); - | ^^^^^^^^^^^^^^ unsupported operation occurred here - | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs index 99685d6d976b..8c860b5db7ba 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs @@ -48,6 +48,7 @@ fn main() { test_nofollow_not_symlink(); #[cfg(target_os = "macos")] test_ioctl(); + test_close_stdout(); } fn test_file_open_unix_allow_two_args() { @@ -579,3 +580,11 @@ fn test_ioctl() { assert_eq!(libc::ioctl(fd, libc::FIOCLEX), 0); } } + +fn test_close_stdout() { + // This is std library UB, but that's not relevant since we're + // only interacting with libc here. + unsafe { + libc::close(1); + } +} From 3c8265a29f3354edfe03b7bd326c68e4decc2a77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 19 Dec 2025 14:59:22 +0100 Subject: [PATCH 0463/1061] add test for 149981 --- tests/ui/eii/duplicate/eii_conflict_with_macro.rs | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tests/ui/eii/duplicate/eii_conflict_with_macro.rs diff --git a/tests/ui/eii/duplicate/eii_conflict_with_macro.rs b/tests/ui/eii/duplicate/eii_conflict_with_macro.rs new file mode 100644 index 000000000000..4012ea268799 --- /dev/null +++ b/tests/ui/eii/duplicate/eii_conflict_with_macro.rs @@ -0,0 +1,6 @@ +//@ compile-flags: --crate-type rlib +#![feature(extern_item_impls)] + +macro_rules! foo_impl {} +#[eii] +fn foo_impl() {} From 5e5c724194594c9af85d6678aef90ebc4a3428b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 19 Dec 2025 18:24:15 +0100 Subject: [PATCH 0464/1061] turn panics into `span_delayed_bug` to make sure this pattern doesn't go unnoticed --- .../rustc_codegen_ssa/src/codegen_attrs.rs | 11 +++++++--- .../rustc_hir_analysis/src/check/wfcheck.rs | 4 +--- compiler/rustc_metadata/src/eii.rs | 20 +++++++++++++++---- .../eii/duplicate/eii_conflict_with_macro.rs | 2 +- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 74f4662118b6..2ad5792de3c0 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -285,11 +285,16 @@ fn process_builtin_attrs( } AttributeKind::EiiImpls(impls) => { for i in impls { - let extern_item = find_attr!( + let Some(extern_item) = find_attr!( tcx.get_all_attrs(i.eii_macro), AttributeKind::EiiExternTarget(target) => target.eii_extern_target - ) - .expect("eii should have declaration macro with extern target attribute"); + ) else { + tcx.dcx().span_delayed_bug( + i.span, + "resolved to something that's not an EII", + ); + continue; + }; // this is to prevent a bug where a single crate defines both the default and explicit implementation // for an EII. In that case, both of them may be part of the same final object file. I'm not 100% sure diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 725294dfd377..8cc3fab128e2 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1213,9 +1213,7 @@ fn check_eiis(tcx: TyCtxt<'_>, def_id: LocalDefId) { *span, ); } else { - panic!( - "EII impl macro {eii_macro:?} did not have an eii extern target attribute pointing to a foreign function" - ) + tcx.dcx().span_delayed_bug(*span, "resolved to something that's not an EII"); } } } diff --git a/compiler/rustc_metadata/src/eii.rs b/compiler/rustc_metadata/src/eii.rs index 5558ff930851..3f60f528776f 100644 --- a/compiler/rustc_metadata/src/eii.rs +++ b/compiler/rustc_metadata/src/eii.rs @@ -1,4 +1,5 @@ use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::indexmap::map::Entry; use rustc_hir::attrs::{AttributeKind, EiiDecl, EiiImpl}; use rustc_hir::def_id::DefId; use rustc_hir::find_attr; @@ -28,11 +29,22 @@ pub(crate) fn collect<'tcx>(tcx: TyCtxt<'tcx>, LocalCrate: LocalCrate) -> EiiMap for i in find_attr!(tcx.get_all_attrs(id), AttributeKind::EiiImpls(e) => e).into_iter().flatten() { - eiis.entry(i.eii_macro) - .or_insert_with(|| { + let registered_impls = match eiis.entry(i.eii_macro) { + Entry::Occupied(o) => &mut o.into_mut().1, + Entry::Vacant(v) => { // find the decl for this one if it wasn't in yet (maybe it's from the local crate? not very useful but not illegal) - (find_attr!(tcx.get_all_attrs(i.eii_macro), AttributeKind::EiiExternTarget(d) => *d).unwrap(), Default::default()) - }).1.insert(id.into(), *i); + let Some(decl) = find_attr!(tcx.get_all_attrs(i.eii_macro), AttributeKind::EiiExternTarget(d) => *d) + else { + // skip if it doesn't have eii_extern_target (if we resolved to another macro that's not an EII) + tcx.dcx() + .span_delayed_bug(i.span, "resolved to something that's not an EII"); + continue; + }; + &mut v.insert((decl, Default::default())).1 + } + }; + + registered_impls.insert(id.into(), *i); } // if we find a new declaration, add it to the list without a known implementation diff --git a/tests/ui/eii/duplicate/eii_conflict_with_macro.rs b/tests/ui/eii/duplicate/eii_conflict_with_macro.rs index 4012ea268799..deee2346552f 100644 --- a/tests/ui/eii/duplicate/eii_conflict_with_macro.rs +++ b/tests/ui/eii/duplicate/eii_conflict_with_macro.rs @@ -1,6 +1,6 @@ //@ compile-flags: --crate-type rlib #![feature(extern_item_impls)] -macro_rules! foo_impl {} +macro_rules! foo_impl { () => {} } #[eii] fn foo_impl() {} From e3cff18370d167b3e03eec8d31bf2f38709b7fc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 8 Jan 2026 16:15:41 +0100 Subject: [PATCH 0465/1061] dont resolve defaults anymore, store foreign item defid instead of macro --- compiler/rustc_ast/src/ast.rs | 13 +++ compiler/rustc_ast_lowering/src/item.rs | 96 +++++++++++-------- compiler/rustc_builtin_macros/src/eii.rs | 8 ++ .../rustc_codegen_ssa/src/codegen_attrs.rs | 31 +++--- .../rustc_hir/src/attrs/data_structures.rs | 17 +++- .../src/check/compare_eii.rs | 12 +-- .../rustc_hir_analysis/src/check/wfcheck.rs | 35 +++---- compiler/rustc_metadata/src/eii.rs | 24 +++-- compiler/rustc_metadata/src/rmeta/encoder.rs | 11 ++- compiler/rustc_passes/src/check_attr.rs | 16 +++- compiler/rustc_passes/src/eii.rs | 9 +- compiler/rustc_resolve/src/late.rs | 16 +++- 12 files changed, 188 insertions(+), 100 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index d4407dbf7be7..6d3cea95e77d 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3813,6 +3813,19 @@ pub struct Fn { pub struct EiiImpl { pub node_id: NodeId, pub eii_macro_path: Path, + /// This field is an implementation detail that prevents a lot of bugs. + /// See for an example. + /// + /// The problem is, that if we generate a declaration *together* with its default, + /// we generate both a declaration and an implementation. The generated implementation + /// uses the same mechanism to register itself as a user-defined implementation would, + /// despite being invisible to users. What does happen is a name resolution step. + /// The invisible default implementation has to find the declaration. + /// Both are generated at the same time, so we can skip that name resolution step. + /// + /// This field is that shortcut: we prefill the extern target to skip a name resolution step, + /// making sure it never fails. It'd be awful UX if we fail name resolution in code invisible to the user. + pub known_eii_macro_resolution: Option, pub impl_safety: Safety, pub span: Span, pub inner_span: Span, diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index f8b98a5ece40..4b7995aa079e 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -2,7 +2,7 @@ use rustc_abi::ExternAbi; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err}; -use rustc_hir::attrs::{AttributeKind, EiiDecl}; +use rustc_hir::attrs::{AttributeKind, EiiDecl, EiiImplResolution}; use rustc_hir::def::{DefKind, PerNS, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_hir::{ @@ -134,6 +134,55 @@ impl<'hir> LoweringContext<'_, 'hir> { } } + fn lower_eii_extern_target( + &mut self, + id: NodeId, + EiiExternTarget { extern_item_path, impl_unsafe, span }: &EiiExternTarget, + ) -> Option { + self.lower_path_simple_eii(id, extern_item_path).map(|did| EiiDecl { + eii_extern_target: did, + impl_unsafe: *impl_unsafe, + span: self.lower_span(*span), + }) + } + + fn lower_eii_impl( + &mut self, + EiiImpl { + node_id, + eii_macro_path, + impl_safety, + span, + inner_span, + is_default, + known_eii_macro_resolution, + }: &EiiImpl, + ) -> hir::attrs::EiiImpl { + let resolution = if let Some(target) = known_eii_macro_resolution + && let Some(decl) = self.lower_eii_extern_target(*node_id, target) + { + EiiImplResolution::Known( + decl, + // the expect is ok here since we always generate this path in the eii macro. + eii_macro_path.segments.last().expect("at least one segment").ident.name, + ) + } else if let Some(macro_did) = self.lower_path_simple_eii(*node_id, eii_macro_path) { + EiiImplResolution::Macro(macro_did) + } else { + EiiImplResolution::Error( + self.dcx().span_delayed_bug(*span, "eii never resolved without errors given"), + ) + }; + + hir::attrs::EiiImpl { + span: self.lower_span(*span), + inner_span: self.lower_span(*inner_span), + impl_marked_unsafe: self.lower_safety(*impl_safety, hir::Safety::Safe).is_unsafe(), + is_default: *is_default, + resolution, + } + } + fn generate_extra_attrs_for_item_kind( &mut self, id: NodeId, @@ -143,49 +192,14 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::Fn(box Fn { eii_impls, .. }) if eii_impls.is_empty() => Vec::new(), ItemKind::Fn(box Fn { eii_impls, .. }) => { vec![hir::Attribute::Parsed(AttributeKind::EiiImpls( - eii_impls - .iter() - .flat_map( - |EiiImpl { - node_id, - eii_macro_path, - impl_safety, - span, - inner_span, - is_default, - }| { - self.lower_path_simple_eii(*node_id, eii_macro_path).map(|did| { - hir::attrs::EiiImpl { - eii_macro: did, - span: self.lower_span(*span), - inner_span: self.lower_span(*inner_span), - impl_marked_unsafe: self - .lower_safety(*impl_safety, hir::Safety::Safe) - .is_unsafe(), - is_default: *is_default, - } - }) - }, - ) - .collect(), + eii_impls.iter().map(|i| self.lower_eii_impl(i)).collect(), ))] } - ItemKind::MacroDef( - _, - MacroDef { - eii_extern_target: Some(EiiExternTarget { extern_item_path, impl_unsafe, span }), - .. - }, - ) => self - .lower_path_simple_eii(id, extern_item_path) - .map(|did| { - vec![hir::Attribute::Parsed(AttributeKind::EiiExternTarget(EiiDecl { - eii_extern_target: did, - impl_unsafe: *impl_unsafe, - span: self.lower_span(*span), - }))] - }) + ItemKind::MacroDef(_, MacroDef { eii_extern_target: Some(target), .. }) => self + .lower_eii_extern_target(id, target) + .map(|decl| vec![hir::Attribute::Parsed(AttributeKind::EiiExternTarget(decl))]) .unwrap_or_default(), + ItemKind::ExternCrate(..) | ItemKind::Use(..) | ItemKind::Static(..) diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index 9049639925dd..5105cdacd186 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -116,6 +116,7 @@ fn eii_( macro_name, eii_attr_span, item_span, + foreign_item_name, ))) } @@ -192,6 +193,7 @@ fn generate_default_impl( macro_name: Ident, eii_attr_span: Span, item_span: Span, + foreign_item_name: Ident, ) -> ast::Item { // FIXME: re-add some original attrs let attrs = ThinVec::new(); @@ -208,6 +210,11 @@ fn generate_default_impl( }, span: eii_attr_span, is_default: true, + known_eii_macro_resolution: Some(ast::EiiExternTarget { + extern_item_path: ast::Path::from_ident(foreign_item_name), + impl_unsafe, + span: item_span, + }), }); ast::Item { @@ -508,6 +515,7 @@ pub(crate) fn eii_shared_macro( impl_safety: meta_item.unsafety, span, is_default, + known_eii_macro_resolution: None, }); vec![item] diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 2ad5792de3c0..8b8abfeb6a4f 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -3,7 +3,9 @@ use std::str::FromStr; use rustc_abi::{Align, ExternAbi}; use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode}; use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr}; -use rustc_hir::attrs::{AttributeKind, InlineAttr, Linkage, RtsanSetting, UsedBy}; +use rustc_hir::attrs::{ + AttributeKind, EiiImplResolution, InlineAttr, Linkage, RtsanSetting, UsedBy, +}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::{self as hir, Attribute, LangItem, find_attr, lang_items}; @@ -285,15 +287,22 @@ fn process_builtin_attrs( } AttributeKind::EiiImpls(impls) => { for i in impls { - let Some(extern_item) = find_attr!( - tcx.get_all_attrs(i.eii_macro), - AttributeKind::EiiExternTarget(target) => target.eii_extern_target - ) else { - tcx.dcx().span_delayed_bug( - i.span, - "resolved to something that's not an EII", - ); - continue; + let extern_item = match i.resolution { + EiiImplResolution::Macro(def_id) => { + let Some(extern_item) = find_attr!( + tcx.get_all_attrs(def_id), + AttributeKind::EiiExternTarget(target) => target.eii_extern_target + ) else { + tcx.dcx().span_delayed_bug( + i.span, + "resolved to something that's not an EII", + ); + continue; + }; + extern_item + } + EiiImplResolution::Known(decl, _) => decl.eii_extern_target, + EiiImplResolution::Error(_eg) => continue, }; // this is to prevent a bug where a single crate defines both the default and explicit implementation @@ -307,7 +316,7 @@ fn process_builtin_attrs( // iterate over all implementations *in the current crate* // (this is ok since we generate codegen fn attrs in the local crate) // if any of them is *not default* then don't emit the alias. - && tcx.externally_implementable_items(LOCAL_CRATE).get(&i.eii_macro).expect("at least one").1.iter().any(|(_, imp)| !imp.is_default) + && tcx.externally_implementable_items(LOCAL_CRATE).get(&extern_item).expect("at least one").1.iter().any(|(_, imp)| !imp.is_default) { continue; } diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index fa8998f0546d..5b2d73faef19 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -11,7 +11,7 @@ use rustc_error_messages::{DiagArgValue, IntoDiagArg}; use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute}; use rustc_span::def_id::DefId; use rustc_span::hygiene::Transparency; -use rustc_span::{Ident, Span, Symbol}; +use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol}; pub use rustc_target::spec::SanitizerSet; use thin_vec::ThinVec; @@ -19,9 +19,22 @@ use crate::attrs::pretty_printing::PrintAttribute; use crate::limit::Limit; use crate::{DefaultBodyStability, PartialConstStability, RustcVersion, Stability}; +#[derive(Copy, Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] +pub enum EiiImplResolution { + /// Usually, finding the extern item that an EII implementation implements means finding + /// the defid of the associated attribute macro, and looking at *its* attributes to find + /// what foreign item its associated with. + Macro(DefId), + /// Sometimes though, we already know statically and can skip some name resolution. + /// Stored together with the eii's name for diagnostics. + Known(EiiDecl, Symbol), + /// For when resolution failed, but we want to continue compilation + Error(ErrorGuaranteed), +} + #[derive(Copy, Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] pub struct EiiImpl { - pub eii_macro: DefId, + pub resolution: EiiImplResolution, pub impl_marked_unsafe: bool, pub span: Span, pub inner_span: Span, diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index 4e7f47a92108..d8afee9aafc9 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -32,21 +32,21 @@ use crate::errors::{EiiWithGenerics, LifetimesOrBoundsMismatchOnEii}; pub(crate) fn compare_eii_function_types<'tcx>( tcx: TyCtxt<'tcx>, external_impl: LocalDefId, - declaration: DefId, + foreign_item: DefId, eii_name: Symbol, eii_attr_span: Span, ) -> Result<(), ErrorGuaranteed> { - check_is_structurally_compatible(tcx, external_impl, declaration, eii_name, eii_attr_span)?; + check_is_structurally_compatible(tcx, external_impl, foreign_item, eii_name, eii_attr_span)?; let external_impl_span = tcx.def_span(external_impl); let cause = ObligationCause::new( external_impl_span, external_impl, - ObligationCauseCode::CompareEii { external_impl, declaration }, + ObligationCauseCode::CompareEii { external_impl, declaration: foreign_item }, ); // FIXME(eii): even if we don't support generic functions, we should support explicit outlive bounds here - let param_env = tcx.param_env(declaration); + let param_env = tcx.param_env(foreign_item); let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(infcx); @@ -62,7 +62,7 @@ pub(crate) fn compare_eii_function_types<'tcx>( let mut wf_tys = FxIndexSet::default(); let norm_cause = ObligationCause::misc(external_impl_span, external_impl); - let declaration_sig = tcx.fn_sig(declaration).instantiate_identity(); + let declaration_sig = tcx.fn_sig(foreign_item).instantiate_identity(); let declaration_sig = tcx.liberate_late_bound_regions(external_impl.into(), declaration_sig); debug!(?declaration_sig); @@ -103,7 +103,7 @@ pub(crate) fn compare_eii_function_types<'tcx>( cause, param_env, terr, - (declaration, declaration_sig), + (foreign_item, declaration_sig), (external_impl, external_impl_sig), eii_attr_span, eii_name, diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 8cc3fab128e2..cefd8c8f1443 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -6,7 +6,7 @@ use rustc_abi::{ExternAbi, ScalableElt}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err}; -use rustc_hir::attrs::{AttributeKind, EiiDecl, EiiImpl}; +use rustc_hir::attrs::{AttributeKind, EiiDecl, EiiImpl, EiiImplResolution}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; @@ -1196,25 +1196,28 @@ fn check_item_fn( fn check_eiis(tcx: TyCtxt<'_>, def_id: LocalDefId) { // does the function have an EiiImpl attribute? that contains the defid of a *macro* // that was used to mark the implementation. This is a two step process. - for EiiImpl { eii_macro, span, .. } in + for EiiImpl { resolution, span, .. } in find_attr!(tcx.get_all_attrs(def_id), AttributeKind::EiiImpls(impls) => impls) .into_iter() .flatten() { - // we expect this macro to have the `EiiMacroFor` attribute, that points to a function - // signature that we'd like to compare the function we're currently checking with - if let Some(eii_extern_target) = find_attr!(tcx.get_all_attrs(*eii_macro), AttributeKind::EiiExternTarget(EiiDecl {eii_extern_target, ..}) => *eii_extern_target) - { - let _ = compare_eii_function_types( - tcx, - def_id, - eii_extern_target, - tcx.item_name(*eii_macro), - *span, - ); - } else { - tcx.dcx().span_delayed_bug(*span, "resolved to something that's not an EII"); - } + let (foreign_item, name) = match resolution { + EiiImplResolution::Macro(def_id) => { + // we expect this macro to have the `EiiMacroFor` attribute, that points to a function + // signature that we'd like to compare the function we're currently checking with + if let Some(foreign_item) = find_attr!(tcx.get_all_attrs(*def_id), AttributeKind::EiiExternTarget(EiiDecl {eii_extern_target: t, ..}) => *t) + { + (foreign_item, tcx.item_name(*def_id)) + } else { + tcx.dcx().span_delayed_bug(*span, "resolved to something that's not an EII"); + continue; + } + } + EiiImplResolution::Known(decl, name) => (decl.eii_extern_target, *name), + EiiImplResolution::Error(_eg) => continue, + }; + + let _ = compare_eii_function_types(tcx, def_id, foreign_item, name, *span); } } diff --git a/compiler/rustc_metadata/src/eii.rs b/compiler/rustc_metadata/src/eii.rs index 3f60f528776f..425de9e62e50 100644 --- a/compiler/rustc_metadata/src/eii.rs +++ b/compiler/rustc_metadata/src/eii.rs @@ -1,6 +1,5 @@ use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::indexmap::map::Entry; -use rustc_hir::attrs::{AttributeKind, EiiDecl, EiiImpl}; +use rustc_hir::attrs::{AttributeKind, EiiDecl, EiiImpl, EiiImplResolution}; use rustc_hir::def_id::DefId; use rustc_hir::find_attr; use rustc_middle::query::LocalCrate; @@ -10,7 +9,7 @@ use rustc_middle::ty::TyCtxt; pub(crate) type EiiMapEncodedKeyValue = (DefId, (EiiDecl, Vec<(DefId, EiiImpl)>)); pub(crate) type EiiMap = FxIndexMap< - DefId, // the defid of the macro that declared the eii + DefId, // the defid of the foreign item associated with the eii ( // the corresponding declaration EiiDecl, @@ -29,29 +28,34 @@ pub(crate) fn collect<'tcx>(tcx: TyCtxt<'tcx>, LocalCrate: LocalCrate) -> EiiMap for i in find_attr!(tcx.get_all_attrs(id), AttributeKind::EiiImpls(e) => e).into_iter().flatten() { - let registered_impls = match eiis.entry(i.eii_macro) { - Entry::Occupied(o) => &mut o.into_mut().1, - Entry::Vacant(v) => { + let decl = match i.resolution { + EiiImplResolution::Macro(macro_defid) => { // find the decl for this one if it wasn't in yet (maybe it's from the local crate? not very useful but not illegal) - let Some(decl) = find_attr!(tcx.get_all_attrs(i.eii_macro), AttributeKind::EiiExternTarget(d) => *d) + let Some(decl) = find_attr!(tcx.get_all_attrs(macro_defid), AttributeKind::EiiExternTarget(d) => *d) else { // skip if it doesn't have eii_extern_target (if we resolved to another macro that's not an EII) tcx.dcx() .span_delayed_bug(i.span, "resolved to something that's not an EII"); continue; }; - &mut v.insert((decl, Default::default())).1 + decl } + EiiImplResolution::Known(decl, _) => decl, + EiiImplResolution::Error(_eg) => continue, }; - registered_impls.insert(id.into(), *i); + // FIXME(eii) remove extern target from encoded decl + eiis.entry(decl.eii_extern_target) + .or_insert_with(|| (decl, Default::default())) + .1 + .insert(id.into(), *i); } // if we find a new declaration, add it to the list without a known implementation if let Some(decl) = find_attr!(tcx.get_all_attrs(id), AttributeKind::EiiExternTarget(d) => *d) { - eiis.entry(id.into()).or_insert((decl, Default::default())); + eiis.entry(decl.eii_extern_target).or_insert((decl, Default::default())); } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index c85327dc3db1..eedb88783ec0 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1657,9 +1657,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { empty_proc_macro!(self); let externally_implementable_items = self.tcx.externally_implementable_items(LOCAL_CRATE); - self.lazy_array(externally_implementable_items.iter().map(|(decl_did, (decl, impls))| { - (*decl_did, (decl.clone(), impls.iter().map(|(impl_did, i)| (*impl_did, *i)).collect())) - })) + self.lazy_array(externally_implementable_items.iter().map( + |(foreign_item, (decl, impls))| { + ( + *foreign_item, + (decl.clone(), impls.iter().map(|(impl_did, i)| (*impl_did, *i)).collect()), + ) + }, + )) } #[instrument(level = "trace", skip(self))] diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index f1cbb72554d2..5b3bdc07ec94 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -21,8 +21,8 @@ use rustc_feature::{ BuiltinAttribute, }; use rustc_hir::attrs::{ - AttributeKind, DocAttribute, DocInline, EiiDecl, EiiImpl, InlineAttr, MirDialect, MirPhase, - ReprAttr, SanitizerSet, + AttributeKind, DocAttribute, DocInline, EiiDecl, EiiImpl, EiiImplResolution, InlineAttr, + MirDialect, MirPhase, ReprAttr, SanitizerSet, }; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalModDefId; @@ -506,7 +506,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } fn check_eii_impl(&self, impls: &[EiiImpl], target: Target) { - for EiiImpl { span, inner_span, eii_macro, impl_marked_unsafe, is_default: _ } in impls { + for EiiImpl { span, inner_span, resolution, impl_marked_unsafe, is_default: _ } in impls { match target { Target::Fn => {} _ => { @@ -514,7 +514,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - if find_attr!(self.tcx.get_all_attrs(*eii_macro), AttributeKind::EiiExternTarget(EiiDecl { impl_unsafe, .. }) if *impl_unsafe) + if let EiiImplResolution::Macro(eii_macro) = resolution + && find_attr!(self.tcx.get_all_attrs(*eii_macro), AttributeKind::EiiExternTarget(EiiDecl { impl_unsafe, .. }) if *impl_unsafe) && !impl_marked_unsafe { self.dcx().emit_err(errors::EiiImplRequiresUnsafe { @@ -758,9 +759,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if let Some(impls) = find_attr!(attrs, AttributeKind::EiiImpls(impls) => impls) { let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap(); for i in impls { + let name = match i.resolution { + EiiImplResolution::Macro(def_id) => self.tcx.item_name(def_id), + EiiImplResolution::Known(_, name) => name, + EiiImplResolution::Error(_eg) => continue, + }; self.dcx().emit_err(errors::EiiWithTrackCaller { attr_span, - name: self.tcx.item_name(i.eii_macro), + name, sig_span: sig.span, }); } diff --git a/compiler/rustc_passes/src/eii.rs b/compiler/rustc_passes/src/eii.rs index ab3f9f0d2182..7d6edb694d4b 100644 --- a/compiler/rustc_passes/src/eii.rs +++ b/compiler/rustc_passes/src/eii.rs @@ -81,7 +81,7 @@ pub(crate) fn check_externally_implementable_items<'tcx>(tcx: TyCtxt<'tcx>, (): } // now we have all eiis! For each of them, choose one we want to actually generate. - for (decl_did, FoundEii { decl, decl_crate, impls }) in eiis { + for (foreign_item, FoundEii { decl, decl_crate, impls }) in eiis { let mut default_impls = Vec::new(); let mut explicit_impls = Vec::new(); @@ -97,7 +97,7 @@ pub(crate) fn check_externally_implementable_items<'tcx>(tcx: TyCtxt<'tcx>, (): // is instantly an error. if explicit_impls.len() > 1 { tcx.dcx().emit_err(DuplicateEiiImpls { - name: tcx.item_name(decl_did), + name: tcx.item_name(foreign_item), first_span: tcx.def_span(explicit_impls[0].0), first_crate: tcx.crate_name(explicit_impls[0].1), second_span: tcx.def_span(explicit_impls[1].0), @@ -116,7 +116,7 @@ pub(crate) fn check_externally_implementable_items<'tcx>(tcx: TyCtxt<'tcx>, (): } if default_impls.len() > 1 { - let decl_span = tcx.def_ident_span(decl_did).unwrap(); + let decl_span = tcx.def_ident_span(foreign_item).unwrap(); tcx.dcx().span_delayed_bug(decl_span, "multiple not supported right now"); } @@ -139,7 +139,8 @@ pub(crate) fn check_externally_implementable_items<'tcx>(tcx: TyCtxt<'tcx>, (): tcx.dcx().emit_err(EiiWithoutImpl { current_crate_name: tcx.crate_name(LOCAL_CRATE), decl_crate_name: tcx.crate_name(decl_crate), - name: tcx.item_name(decl_did), + // FIXME: shouldn't call `item_name` + name: tcx.item_name(foreign_item), span: decl.span, help: (), }); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index b4941a6f5b99..f64bd4a1aa19 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1069,8 +1069,20 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc debug!("(resolving function) entering function"); if let FnKind::Fn(_, _, f) = fn_kind { - for EiiImpl { node_id, eii_macro_path, .. } in &f.eii_impls { - self.smart_resolve_path(*node_id, &None, &eii_macro_path, PathSource::Macro); + for EiiImpl { node_id, eii_macro_path, known_eii_macro_resolution, .. } in &f.eii_impls + { + // See docs on the `known_eii_macro_resolution` field: + // if we already know the resolution statically, don't bother resolving it. + if let Some(target) = known_eii_macro_resolution { + self.smart_resolve_path( + *node_id, + &None, + &target.extern_item_path, + PathSource::Expr(None), + ); + } else { + self.smart_resolve_path(*node_id, &None, &eii_macro_path, PathSource::Macro); + } } } From 5ddda0c37bae5d6867d04ed5be5dae5729df7bd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 8 Jan 2026 16:43:24 +0100 Subject: [PATCH 0466/1061] fix up diagnostics referring to the right items --- compiler/rustc_ast/src/ast.rs | 3 +-- compiler/rustc_ast_lowering/src/item.rs | 21 ++++++++++--------- compiler/rustc_builtin_macros/src/eii.rs | 8 +------ .../rustc_codegen_ssa/src/codegen_attrs.rs | 2 +- .../rustc_hir/src/attrs/data_structures.rs | 4 ++-- .../rustc_hir_analysis/src/check/wfcheck.rs | 2 +- compiler/rustc_metadata/src/eii.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 2 +- compiler/rustc_passes/src/eii.rs | 8 ++++--- compiler/rustc_resolve/src/late.rs | 2 +- tests/ui/eii/privacy2.stderr | 8 +++---- 11 files changed, 29 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 6d3cea95e77d..fb2ccefe12a1 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2117,10 +2117,9 @@ pub struct MacroDef { #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic, Walkable)] pub struct EiiExternTarget { - /// path to the extern item we're targetting + /// path to the extern item we're targeting pub extern_item_path: Path, pub impl_unsafe: bool, - pub span: Span, } #[derive(Clone, Encodable, Decodable, Debug, Copy, Hash, Eq, PartialEq)] diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 4b7995aa079e..3a7308ef7c97 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -137,12 +137,13 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_eii_extern_target( &mut self, id: NodeId, - EiiExternTarget { extern_item_path, impl_unsafe, span }: &EiiExternTarget, + eii_name: Ident, + EiiExternTarget { extern_item_path, impl_unsafe }: &EiiExternTarget, ) -> Option { self.lower_path_simple_eii(id, extern_item_path).map(|did| EiiDecl { eii_extern_target: did, impl_unsafe: *impl_unsafe, - span: self.lower_span(*span), + name: eii_name, }) } @@ -159,13 +160,13 @@ impl<'hir> LoweringContext<'_, 'hir> { }: &EiiImpl, ) -> hir::attrs::EiiImpl { let resolution = if let Some(target) = known_eii_macro_resolution - && let Some(decl) = self.lower_eii_extern_target(*node_id, target) - { - EiiImplResolution::Known( - decl, + && let Some(decl) = self.lower_eii_extern_target( + *node_id, // the expect is ok here since we always generate this path in the eii macro. - eii_macro_path.segments.last().expect("at least one segment").ident.name, - ) + eii_macro_path.segments.last().expect("at least one segment").ident, + target, + ) { + EiiImplResolution::Known(decl) } else if let Some(macro_did) = self.lower_path_simple_eii(*node_id, eii_macro_path) { EiiImplResolution::Macro(macro_did) } else { @@ -195,8 +196,8 @@ impl<'hir> LoweringContext<'_, 'hir> { eii_impls.iter().map(|i| self.lower_eii_impl(i)).collect(), ))] } - ItemKind::MacroDef(_, MacroDef { eii_extern_target: Some(target), .. }) => self - .lower_eii_extern_target(id, target) + ItemKind::MacroDef(name, MacroDef { eii_extern_target: Some(target), .. }) => self + .lower_eii_extern_target(id, *name, target) .map(|decl| vec![hir::Attribute::Parsed(AttributeKind::EiiExternTarget(decl))]) .unwrap_or_default(), diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index 5105cdacd186..ff24eba217df 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -103,8 +103,6 @@ fn eii_( // span of the declaring item without attributes let item_span = func.sig.span; - // span of the eii attribute and the item below it, i.e. the full declaration - let decl_span = eii_attr_span.to(item_span); let foreign_item_name = func.ident; let mut return_items = Vec::new(); @@ -134,7 +132,6 @@ fn eii_( macro_name, foreign_item_name, impl_unsafe, - decl_span, ))); return_items.into_iter().map(wrap_item).collect() @@ -213,7 +210,6 @@ fn generate_default_impl( known_eii_macro_resolution: Some(ast::EiiExternTarget { extern_item_path: ast::Path::from_ident(foreign_item_name), impl_unsafe, - span: item_span, }), }); @@ -359,7 +355,6 @@ fn generate_attribute_macro_to_implement( macro_name: Ident, foreign_item_name: Ident, impl_unsafe: bool, - decl_span: Span, ) -> ast::Item { let mut macro_attrs = ThinVec::new(); @@ -401,7 +396,6 @@ fn generate_attribute_macro_to_implement( eii_extern_target: Some(ast::EiiExternTarget { extern_item_path: ast::Path::from_ident(foreign_item_name), impl_unsafe, - span: decl_span, }), }, ), @@ -458,7 +452,7 @@ pub(crate) fn eii_extern_target( false }; - d.eii_extern_target = Some(EiiExternTarget { extern_item_path, impl_unsafe, span }); + d.eii_extern_target = Some(EiiExternTarget { extern_item_path, impl_unsafe }); // Return the original item and the new methods. vec![item] diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 8b8abfeb6a4f..7dda824e2b18 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -301,7 +301,7 @@ fn process_builtin_attrs( }; extern_item } - EiiImplResolution::Known(decl, _) => decl.eii_extern_target, + EiiImplResolution::Known(decl) => decl.eii_extern_target, EiiImplResolution::Error(_eg) => continue, }; diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 5b2d73faef19..23201eff455f 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -27,7 +27,7 @@ pub enum EiiImplResolution { Macro(DefId), /// Sometimes though, we already know statically and can skip some name resolution. /// Stored together with the eii's name for diagnostics. - Known(EiiDecl, Symbol), + Known(EiiDecl), /// For when resolution failed, but we want to continue compilation Error(ErrorGuaranteed), } @@ -46,7 +46,7 @@ pub struct EiiDecl { pub eii_extern_target: DefId, /// whether or not it is unsafe to implement this EII pub impl_unsafe: bool, - pub span: Span, + pub name: Ident, } #[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, PrintAttribute)] diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index cefd8c8f1443..7ec4110f80b9 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1213,7 +1213,7 @@ fn check_eiis(tcx: TyCtxt<'_>, def_id: LocalDefId) { continue; } } - EiiImplResolution::Known(decl, name) => (decl.eii_extern_target, *name), + EiiImplResolution::Known(decl) => (decl.eii_extern_target, decl.name.name), EiiImplResolution::Error(_eg) => continue, }; diff --git a/compiler/rustc_metadata/src/eii.rs b/compiler/rustc_metadata/src/eii.rs index 425de9e62e50..b06ac8481397 100644 --- a/compiler/rustc_metadata/src/eii.rs +++ b/compiler/rustc_metadata/src/eii.rs @@ -40,7 +40,7 @@ pub(crate) fn collect<'tcx>(tcx: TyCtxt<'tcx>, LocalCrate: LocalCrate) -> EiiMap }; decl } - EiiImplResolution::Known(decl, _) => decl, + EiiImplResolution::Known(decl) => decl, EiiImplResolution::Error(_eg) => continue, }; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 5b3bdc07ec94..2d3c5c7e48a0 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -761,7 +761,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { for i in impls { let name = match i.resolution { EiiImplResolution::Macro(def_id) => self.tcx.item_name(def_id), - EiiImplResolution::Known(_, name) => name, + EiiImplResolution::Known(decl) => decl.name.name, EiiImplResolution::Error(_eg) => continue, }; self.dcx().emit_err(errors::EiiWithTrackCaller { diff --git a/compiler/rustc_passes/src/eii.rs b/compiler/rustc_passes/src/eii.rs index 7d6edb694d4b..7c2c98920623 100644 --- a/compiler/rustc_passes/src/eii.rs +++ b/compiler/rustc_passes/src/eii.rs @@ -80,6 +80,8 @@ pub(crate) fn check_externally_implementable_items<'tcx>(tcx: TyCtxt<'tcx>, (): } } + println!("{eiis:#?}"); + // now we have all eiis! For each of them, choose one we want to actually generate. for (foreign_item, FoundEii { decl, decl_crate, impls }) in eiis { let mut default_impls = Vec::new(); @@ -97,7 +99,7 @@ pub(crate) fn check_externally_implementable_items<'tcx>(tcx: TyCtxt<'tcx>, (): // is instantly an error. if explicit_impls.len() > 1 { tcx.dcx().emit_err(DuplicateEiiImpls { - name: tcx.item_name(foreign_item), + name: decl.name.name, first_span: tcx.def_span(explicit_impls[0].0), first_crate: tcx.crate_name(explicit_impls[0].1), second_span: tcx.def_span(explicit_impls[1].0), @@ -140,8 +142,8 @@ pub(crate) fn check_externally_implementable_items<'tcx>(tcx: TyCtxt<'tcx>, (): current_crate_name: tcx.crate_name(LOCAL_CRATE), decl_crate_name: tcx.crate_name(decl_crate), // FIXME: shouldn't call `item_name` - name: tcx.item_name(foreign_item), - span: decl.span, + name: decl.name.name, + span: decl.name.span, help: (), }); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index f64bd4a1aa19..32cf57af2e7f 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2929,7 +2929,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.parent_scope.macro_rules = self.r.macro_rules_scopes[&def_id]; } - if let Some(EiiExternTarget { extern_item_path, impl_unsafe: _, span: _ }) = + if let Some(EiiExternTarget { extern_item_path, impl_unsafe: _ }) = ¯o_def.eii_extern_target { self.smart_resolve_path( diff --git a/tests/ui/eii/privacy2.stderr b/tests/ui/eii/privacy2.stderr index 0d44604567e4..903285d4d1e3 100644 --- a/tests/ui/eii/privacy2.stderr +++ b/tests/ui/eii/privacy2.stderr @@ -17,18 +17,18 @@ LL | fn decl1(x: u64); | ^^^^^^^^^^^^^^^^^ error: `#[eii2]` required, but not found - --> $DIR/auxiliary/codegen3.rs:9:1 + --> $DIR/auxiliary/codegen3.rs:9:7 | LL | #[eii(eii2)] - | ^^^^^^^^^^^^ expected because `#[eii2]` was declared here in crate `codegen3` + | ^^^^ expected because `#[eii2]` was declared here in crate `codegen3` | = help: expected at least one implementation in crate `privacy2` or any of its dependencies error: `#[eii3]` required, but not found - --> $DIR/auxiliary/codegen3.rs:13:5 + --> $DIR/auxiliary/codegen3.rs:13:11 | LL | #[eii(eii3)] - | ^^^^^^^^^^^^ expected because `#[eii3]` was declared here in crate `codegen3` + | ^^^^ expected because `#[eii3]` was declared here in crate `codegen3` | = help: expected at least one implementation in crate `privacy2` or any of its dependencies From 52b3ac476c78224a1d35d3857d24413fdfb89138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 8 Jan 2026 18:43:16 +0100 Subject: [PATCH 0467/1061] trick with super imports that fixes nameres in anonymous modules --- compiler/rustc_builtin_macros/src/eii.rs | 71 ++++++++++++++++++++++-- compiler/rustc_passes/src/eii.rs | 2 - 2 files changed, 66 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index ff24eba217df..2d67608609e3 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -109,6 +109,7 @@ fn eii_( if func.body.is_some() { return_items.push(Box::new(generate_default_impl( + ecx, &func, impl_unsafe, macro_name, @@ -185,6 +186,7 @@ fn filter_attrs_for_multiple_eii_attr( } fn generate_default_impl( + ecx: &mut ExtCtxt<'_>, func: &ast::Fn, impl_unsafe: bool, macro_name: Ident, @@ -208,7 +210,18 @@ fn generate_default_impl( span: eii_attr_span, is_default: true, known_eii_macro_resolution: Some(ast::EiiExternTarget { - extern_item_path: ast::Path::from_ident(foreign_item_name), + extern_item_path: ast::Path { + span: foreign_item_name.span, + segments: thin_vec![ + ast::PathSegment { + ident: Ident::from_str_and_span("super", foreign_item_name.span,), + id: DUMMY_NODE_ID, + args: None + }, + ast::PathSegment { ident: foreign_item_name, id: DUMMY_NODE_ID, args: None }, + ], + tokens: None, + }, impl_unsafe, }), }); @@ -239,18 +252,66 @@ fn generate_default_impl( stmts: thin_vec![ast::Stmt { id: DUMMY_NODE_ID, kind: ast::StmtKind::Item(Box::new(ast::Item { - attrs, + attrs: ThinVec::new(), id: DUMMY_NODE_ID, span: item_span, vis: ast::Visibility { - span: eii_attr_span, + span: item_span, kind: ast::VisibilityKind::Inherited, tokens: None }, - kind: ItemKind::Fn(Box::new(default_func)), + kind: ItemKind::Mod( + ast::Safety::Default, + Ident::from_str_and_span("dflt", item_span), + ast::ModKind::Loaded( + thin_vec![ + Box::new(ast::Item { + attrs: thin_vec![ecx.attr_nested_word( + sym::allow, + sym::unused_imports, + item_span + ),], + id: DUMMY_NODE_ID, + span: item_span, + vis: ast::Visibility { + span: eii_attr_span, + kind: ast::VisibilityKind::Inherited, + tokens: None + }, + kind: ItemKind::Use(ast::UseTree { + prefix: ast::Path::from_ident( + Ident::from_str_and_span( + "super", item_span, + ) + ), + kind: ast::UseTreeKind::Glob, + span: item_span, + }), + tokens: None, + }), + Box::new(ast::Item { + attrs, + id: DUMMY_NODE_ID, + span: item_span, + vis: ast::Visibility { + span: eii_attr_span, + kind: ast::VisibilityKind::Inherited, + tokens: None + }, + kind: ItemKind::Fn(Box::new(default_func)), + tokens: None, + }), + ], + ast::Inline::Yes, + ast::ModSpans { + inner_span: item_span, + inject_use_span: item_span, + } + ) + ), tokens: None, })), - span: eii_attr_span + span: eii_attr_span, }], id: DUMMY_NODE_ID, rules: ast::BlockCheckMode::Default, diff --git a/compiler/rustc_passes/src/eii.rs b/compiler/rustc_passes/src/eii.rs index 7c2c98920623..f3e84665f21d 100644 --- a/compiler/rustc_passes/src/eii.rs +++ b/compiler/rustc_passes/src/eii.rs @@ -80,8 +80,6 @@ pub(crate) fn check_externally_implementable_items<'tcx>(tcx: TyCtxt<'tcx>, (): } } - println!("{eiis:#?}"); - // now we have all eiis! For each of them, choose one we want to actually generate. for (foreign_item, FoundEii { decl, decl_crate, impls }) in eiis { let mut default_impls = Vec::new(); From 7791bc22133cce1693b364f76e99416b50f4d348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 8 Jan 2026 18:44:56 +0100 Subject: [PATCH 0468/1061] mark ICE regression test as fixed --- tests/ui/eii/duplicate/eii_conflict_with_macro.rs | 1 + tests/ui/eii/privacy2.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/ui/eii/duplicate/eii_conflict_with_macro.rs b/tests/ui/eii/duplicate/eii_conflict_with_macro.rs index deee2346552f..d8118f8417a0 100644 --- a/tests/ui/eii/duplicate/eii_conflict_with_macro.rs +++ b/tests/ui/eii/duplicate/eii_conflict_with_macro.rs @@ -1,4 +1,5 @@ //@ compile-flags: --crate-type rlib +//@ build-pass #![feature(extern_item_impls)] macro_rules! foo_impl { () => {} } diff --git a/tests/ui/eii/privacy2.rs b/tests/ui/eii/privacy2.rs index a4ae188bd0ec..a0bc26ef629b 100644 --- a/tests/ui/eii/privacy2.rs +++ b/tests/ui/eii/privacy2.rs @@ -1,5 +1,5 @@ //@ aux-build:codegen3.rs -// Tests whether name resulution respects privacy properly. +// Tests whether name resolution respects privacy properly. #![feature(extern_item_impls)] extern crate codegen3 as codegen; From 025ac8f512f8c90e4ba02d69e98851e7a4bdb999 Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Fri, 9 Jan 2026 08:37:01 +0000 Subject: [PATCH 0469/1061] The aarch64-unknown-none target requires NEON, so the docs were wrong. --- src/doc/rustc/src/platform-support/aarch64-unknown-none.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc/src/platform-support/aarch64-unknown-none.md b/src/doc/rustc/src/platform-support/aarch64-unknown-none.md index 3d776677d23e..5d1201bbf426 100644 --- a/src/doc/rustc/src/platform-support/aarch64-unknown-none.md +++ b/src/doc/rustc/src/platform-support/aarch64-unknown-none.md @@ -29,14 +29,15 @@ You may prefer the `-softfloat` target when writing a kernel or interfacing with pre-compiled binaries that use the soft-float ABI. When using the hardfloat targets, the minimum floating-point features assumed -are those of the `fp-armv8`, which excludes NEON SIMD support. If your +are [`FEAT_AdvSIMD`][feat-advsimd], which means NEON SIMD support. If your processor supports a different set of floating-point features than the default -expectations of `fp-armv8`, then these should also be enabled or disabled as -needed with `-C target-feature=(+/-)`. It is also possible to tell Rust (or +expectations of `FEAT_AdvSIMD`, then these should also be enabled or disabled +as needed with `-C target-feature=(+/-)`. It is also possible to tell Rust (or LLVM) that you have a specific model of Arm processor, using the [`-Ctarget-cpu`][target-cpu] option. Doing so may change the default set of target-features enabled. +[feat-advsimd]: https://developer.arm.com/documentation/109697/2025_12/Feature-descriptions/The-Armv8-0-architecture-extension?lang=en [target-cpu]: https://doc.rust-lang.org/rustc/codegen-options/index.html#target-cpu [target-feature]: https://doc.rust-lang.org/rustc/codegen-options/index.html#target-feature From 6a9dae4f3e679c298c6d6ad83f65d2d9c51a02f0 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Fri, 9 Jan 2026 10:37:00 +0100 Subject: [PATCH 0470/1061] Merge commit '500e0ff18726cd44b23004a02fc1b99f52c11ab1' into clippy-subtree-update --- COPYRIGHT | 2 +- Cargo.toml | 2 +- LICENSE-APACHE | 2 +- LICENSE-MIT | 2 +- README.md | 2 +- clippy_lints/src/attrs/allow_attributes.rs | 9 +- clippy_lints/src/attrs/mod.rs | 6 +- .../src/attrs/should_panic_without_expect.rs | 2 +- clippy_lints/src/bool_assert_comparison.rs | 33 +++-- clippy_lints/src/booleans.rs | 3 +- clippy_lints/src/cargo/mod.rs | 2 +- clippy_lints/src/cfg_not_test.rs | 13 +- clippy_lints/src/checked_conversions.rs | 5 +- .../src/derive/derive_ord_xor_partial_ord.rs | 9 +- clippy_lints/src/derive/mod.rs | 2 +- .../src/doc/include_in_doc_without_cfg.rs | 2 +- clippy_lints/src/doc/mod.rs | 10 +- clippy_lints/src/double_parens.rs | 2 + clippy_lints/src/implicit_saturating_sub.rs | 27 +++- clippy_lints/src/incompatible_msrv.rs | 10 +- clippy_lints/src/inherent_impl.rs | 23 ++- clippy_lints/src/large_include_file.rs | 2 +- clippy_lints/src/large_stack_arrays.rs | 9 ++ clippy_lints/src/loops/for_kv_map.rs | 24 +++- clippy_lints/src/loops/mod.rs | 2 +- clippy_lints/src/loops/never_loop.rs | 4 +- clippy_lints/src/manual_ignore_case_cmp.rs | 10 +- clippy_lints/src/manual_ilog2.rs | 4 +- clippy_lints/src/matches/manual_ok_err.rs | 2 +- clippy_lints/src/matches/match_as_ref.rs | 5 +- clippy_lints/src/matches/match_bool.rs | 96 ++++++------- .../src/matches/redundant_pattern_match.rs | 23 ++- clippy_lints/src/methods/is_empty.rs | 5 +- clippy_lints/src/methods/iter_kv_map.rs | 7 +- clippy_lints/src/methods/unnecessary_fold.rs | 111 +++++++++----- .../src/methods/unnecessary_to_owned.rs | 22 +-- .../src/missing_enforced_import_rename.rs | 3 +- clippy_lints/src/multiple_bound_locations.rs | 2 +- clippy_lints/src/mutex_atomic.rs | 2 +- clippy_lints/src/needless_bool.rs | 6 +- clippy_lints/src/needless_for_each.rs | 125 +++++++++------- clippy_lints/src/new_without_default.rs | 36 +++-- clippy_lints/src/operators/cmp_owned.rs | 58 +++----- clippy_lints/src/operators/manual_div_ceil.rs | 127 +++++++++------- .../src/operators/manual_is_multiple_of.rs | 4 +- clippy_lints/src/question_mark.rs | 7 +- clippy_lints/src/single_range_in_vec_init.rs | 2 +- clippy_lints/src/strings.rs | 8 +- clippy_lints/src/strlen_on_c_strings.rs | 4 +- .../src/transmute/transmuting_null.rs | 20 ++- clippy_lints/src/useless_conversion.rs | 14 +- clippy_lints/src/utils/author.rs | 1 - .../src/lint_without_lint_pass.rs | 4 +- clippy_utils/README.md | 4 +- clippy_utils/src/ast_utils/mod.rs | 4 +- clippy_utils/src/attrs.rs | 6 +- clippy_utils/src/consts.rs | 8 +- clippy_utils/src/hir_utils.rs | 4 +- clippy_utils/src/lib.rs | 29 +++- clippy_utils/src/res.rs | 4 +- clippy_utils/src/sugg.rs | 2 +- clippy_utils/src/sym.rs | 1 + rust-toolchain.toml | 2 +- rustc_tools_util/README.md | 2 +- .../clippy.toml | 3 +- .../conf_missing_enforced_import_rename.fixed | 1 + .../conf_missing_enforced_import_rename.rs | 1 + ...conf_missing_enforced_import_rename.stderr | 2 +- tests/ui/bool_assert_comparison.fixed | 13 ++ tests/ui/bool_assert_comparison.rs | 13 ++ tests/ui/bool_assert_comparison.stderr | 26 +++- tests/ui/checked_conversions.fixed | 16 +++ tests/ui/checked_conversions.rs | 16 +++ tests/ui/checked_conversions.stderr | 42 +++--- tests/ui/cmp_owned/with_suggestion.fixed | 29 ++++ tests/ui/cmp_owned/with_suggestion.rs | 29 ++++ tests/ui/cmp_owned/with_suggestion.stderr | 8 +- tests/ui/derive_ord_xor_partial_ord.rs | 14 ++ tests/ui/double_parens.fixed | 16 +++ tests/ui/double_parens.rs | 16 +++ tests/ui/for_kv_map.fixed | 17 +++ tests/ui/for_kv_map.rs | 17 +++ tests/ui/for_kv_map.stderr | 14 +- tests/ui/impl.rs | 42 +++++- tests/ui/impl.stderr | 90 ++++++++++-- tests/ui/implicit_saturating_sub.fixed | 8 ++ tests/ui/implicit_saturating_sub.rs | 8 ++ tests/ui/implicit_saturating_sub.stderr | 8 +- tests/ui/iter_kv_map.fixed | 6 + tests/ui/iter_kv_map.rs | 6 + tests/ui/iter_kv_map.stderr | 8 +- tests/ui/manual_div_ceil.fixed | 29 ++++ tests/ui/manual_div_ceil.rs | 29 ++++ tests/ui/manual_div_ceil.stderr | 20 ++- tests/ui/manual_div_ceil_with_feature.fixed | 29 ++++ tests/ui/manual_div_ceil_with_feature.rs | 29 ++++ tests/ui/manual_div_ceil_with_feature.stderr | 20 ++- tests/ui/manual_ignore_case_cmp.fixed | 20 +++ tests/ui/manual_ignore_case_cmp.rs | 20 +++ tests/ui/manual_ignore_case_cmp.stderr | 26 +++- tests/ui/manual_ilog2.fixed | 17 +++ tests/ui/manual_ilog2.rs | 17 +++ tests/ui/manual_ilog2.stderr | 14 +- tests/ui/manual_is_multiple_of.fixed | 16 +++ tests/ui/manual_is_multiple_of.rs | 16 +++ tests/ui/manual_is_multiple_of.stderr | 8 +- tests/ui/manual_ok_err.fixed | 10 ++ tests/ui/manual_ok_err.rs | 14 ++ tests/ui/manual_ok_err.stderr | 13 +- tests/ui/match_as_ref.fixed | 10 ++ tests/ui/match_as_ref.rs | 14 ++ tests/ui/match_as_ref.stderr | 23 ++- tests/ui/match_bool.fixed | 11 ++ tests/ui/match_bool.rs | 15 ++ tests/ui/match_bool.stderr | 12 +- tests/ui/mutex_atomic.fixed | 12 ++ tests/ui/mutex_atomic.rs | 12 ++ tests/ui/mutex_atomic.stderr | 10 +- tests/ui/needless_bool_assign.fixed | 19 +++ tests/ui/needless_bool_assign.rs | 23 +++ tests/ui/needless_bool_assign.stderr | 12 +- tests/ui/needless_for_each_fixable.fixed | 8 ++ tests/ui/needless_for_each_fixable.rs | 8 ++ tests/ui/needless_for_each_fixable.stderr | 19 ++- tests/ui/never_loop_iterator_reduction.rs | 9 +- tests/ui/never_loop_iterator_reduction.stderr | 2 +- tests/ui/new_without_default.fixed | 55 +++++++ tests/ui/new_without_default.rs | 36 +++++ tests/ui/new_without_default.stderr | 55 ++++++- tests/ui/question_mark.fixed | 17 ++- tests/ui/question_mark.rs | 22 ++- tests/ui/question_mark.stderr | 19 ++- .../redundant_pattern_matching_option.fixed | 13 ++ tests/ui/redundant_pattern_matching_option.rs | 13 ++ .../redundant_pattern_matching_option.stderr | 14 +- .../redundant_pattern_matching_result.fixed | 20 +++ tests/ui/redundant_pattern_matching_result.rs | 24 ++++ .../redundant_pattern_matching_result.stderr | 19 ++- .../ui/single_range_in_vec_init_unfixable.rs | 12 ++ .../single_range_in_vec_init_unfixable.stderr | 16 +++ tests/ui/str_to_string.fixed | 14 ++ tests/ui/str_to_string.rs | 14 ++ tests/ui/str_to_string.stderr | 8 +- tests/ui/string_from_utf8_as_bytes.fixed | 10 ++ tests/ui/string_from_utf8_as_bytes.rs | 10 ++ tests/ui/string_from_utf8_as_bytes.stderr | 10 +- tests/ui/transmuting_null.rs | 11 ++ tests/ui/transmuting_null.stderr | 14 +- tests/ui/unnecessary_fold.fixed | 11 ++ tests/ui/unnecessary_fold.rs | 11 ++ tests/ui/unnecessary_fold.stderr | 17 ++- tests/ui/unnecessary_to_owned.fixed | 9 ++ tests/ui/unnecessary_to_owned.rs | 9 ++ tests/ui/unnecessary_to_owned.stderr | 8 +- tests/ui/useless_conversion.fixed | 10 ++ tests/ui/useless_conversion.rs | 10 ++ tests/ui/useless_conversion.stderr | 135 ++++++++++-------- triagebot.toml | 1 - 158 files changed, 2147 insertions(+), 518 deletions(-) create mode 100644 tests/ui/single_range_in_vec_init_unfixable.rs create mode 100644 tests/ui/single_range_in_vec_init_unfixable.stderr diff --git a/COPYRIGHT b/COPYRIGHT index f402dcf465a3..d3b4c9e5fb2c 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,6 +1,6 @@ // REUSE-IgnoreStart -Copyright 2014-2025 The Rust Project Developers +Copyright (c) The Rust Project Contributors Licensed under the Apache License, Version 2.0 or the MIT license diff --git a/Cargo.toml b/Cargo.toml index 67078adea2b4..7379dcbb7b37 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ walkdir = "2.3" filetime = "0.2.9" itertools = "0.12" pulldown-cmark = { version = "0.11", default-features = false, features = ["html"] } -askama = { version = "0.14", default-features = false, features = ["alloc", "config", "derive"] } +askama = { version = "0.15", default-features = false, features = ["alloc", "config", "derive"] } [dev-dependencies.toml] version = "0.9.7" diff --git a/LICENSE-APACHE b/LICENSE-APACHE index 9990a0cec474..773ae298cc19 100644 --- a/LICENSE-APACHE +++ b/LICENSE-APACHE @@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work. same "printed page" as the copyright notice for easier identification within third-party archives. -Copyright 2014-2025 The Rust Project Developers +Copyright (c) The Rust Project Contributors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/LICENSE-MIT b/LICENSE-MIT index 5d6e36ef6bfc..9549420685cc 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2014-2025 The Rust Project Developers +Copyright (c) The Rust Project Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/README.md b/README.md index 78498c73ae78..8bccd040c1f9 100644 --- a/README.md +++ b/README.md @@ -277,7 +277,7 @@ If you want to contribute to Clippy, you can find more information in [CONTRIBUT -Copyright 2014-2025 The Rust Project Developers +Copyright (c) The Rust Project Contributors Licensed under the Apache License, Version 2.0 or the MIT license diff --git a/clippy_lints/src/attrs/allow_attributes.rs b/clippy_lints/src/attrs/allow_attributes.rs index 84b65d3185e3..0235b130b6c0 100644 --- a/clippy_lints/src/attrs/allow_attributes.rs +++ b/clippy_lints/src/attrs/allow_attributes.rs @@ -1,10 +1,10 @@ use super::ALLOW_ATTRIBUTES; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; +use rustc_ast::attr::AttributeExt; use rustc_ast::{AttrStyle, Attribute}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, LintContext}; -use rustc_ast::attr::AttributeExt; // Separate each crate's features. pub fn check<'cx>(cx: &EarlyContext<'cx>, attr: &'cx Attribute) { @@ -15,12 +15,7 @@ pub fn check<'cx>(cx: &EarlyContext<'cx>, attr: &'cx Attribute) { { #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] span_lint_and_then(cx, ALLOW_ATTRIBUTES, path_span, "#[allow] attribute found", |diag| { - diag.span_suggestion( - path_span, - "replace it with", - "expect", - Applicability::MachineApplicable, - ); + diag.span_suggestion(path_span, "replace it with", "expect", Applicability::MachineApplicable); }); } } diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index 366f5873a1aa..42c321df61c1 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -16,7 +16,7 @@ mod utils; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::msrvs::{self, Msrv, MsrvStack}; -use rustc_ast::{self as ast, AttrArgs, AttrKind, Attribute, MetaItemInner, MetaItemKind, AttrItemKind}; +use rustc_ast::{self as ast, AttrArgs, AttrItemKind, AttrKind, Attribute, MetaItemInner, MetaItemKind}; use rustc_hir::{ImplItem, Item, ItemKind, TraitItem}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -604,7 +604,9 @@ impl EarlyLintPass for PostExpansionEarlyAttributes { if attr.has_name(sym::ignore) && match &attr.kind { - AttrKind::Normal(normal_attr) => !matches!(normal_attr.item.args, AttrItemKind::Unparsed(AttrArgs::Eq { .. })), + AttrKind::Normal(normal_attr) => { + !matches!(normal_attr.item.args, AttrItemKind::Unparsed(AttrArgs::Eq { .. })) + }, AttrKind::DocComment(..) => true, } { diff --git a/clippy_lints/src/attrs/should_panic_without_expect.rs b/clippy_lints/src/attrs/should_panic_without_expect.rs index b854a3070bef..1a9abd88a46a 100644 --- a/clippy_lints/src/attrs/should_panic_without_expect.rs +++ b/clippy_lints/src/attrs/should_panic_without_expect.rs @@ -2,7 +2,7 @@ use super::{Attribute, SHOULD_PANIC_WITHOUT_EXPECT}; use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_ast::token::{Token, TokenKind}; use rustc_ast::tokenstream::TokenTree; -use rustc_ast::{AttrArgs, AttrKind, AttrItemKind}; +use rustc_ast::{AttrArgs, AttrItemKind, AttrKind}; use rustc_errors::Applicability; use rustc_lint::EarlyContext; use rustc_span::sym; diff --git a/clippy_lints/src/bool_assert_comparison.rs b/clippy_lints/src/bool_assert_comparison.rs index f31b67f470f9..165941a859f7 100644 --- a/clippy_lints/src/bool_assert_comparison.rs +++ b/clippy_lints/src/bool_assert_comparison.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node}; +use clippy_utils::source::walk_span_to_context; use clippy_utils::sugg::Sugg; use clippy_utils::sym; use clippy_utils::ty::{implements_trait, is_copy}; @@ -130,22 +131,24 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison { let mut suggestions = vec![(name_span, non_eq_mac.to_string()), (lit_span, String::new())]; - if let Some(sugg) = Sugg::hir_opt(cx, non_lit_expr) { - let sugg = if bool_value ^ eq_macro { - !sugg.maybe_paren() - } else if ty::Bool == *non_lit_ty.kind() { - sugg - } else { - !!sugg.maybe_paren() - }; - suggestions.push((non_lit_expr.span, sugg.to_string())); + let mut applicability = Applicability::MachineApplicable; + let sugg = Sugg::hir_with_context(cx, non_lit_expr, macro_call.span.ctxt(), "..", &mut applicability); + let sugg = if bool_value ^ eq_macro { + !sugg.maybe_paren() + } else if ty::Bool == *non_lit_ty.kind() { + sugg + } else { + !!sugg.maybe_paren() + }; + let non_lit_expr_span = + walk_span_to_context(non_lit_expr.span, macro_call.span.ctxt()).unwrap_or(non_lit_expr.span); + suggestions.push((non_lit_expr_span, sugg.to_string())); - diag.multipart_suggestion( - format!("replace it with `{non_eq_mac}!(..)`"), - suggestions, - Applicability::MachineApplicable, - ); - } + diag.multipart_suggestion( + format!("replace it with `{non_eq_mac}!(..)`"), + suggestions, + applicability, + ); }, ); } diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index a04a56d72bc0..0bd459d8b021 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -15,6 +15,7 @@ use rustc_lint::{LateContext, LateLintPass, Level}; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{Span, Symbol, SyntaxContext}; +use std::fmt::Write as _; declare_clippy_lint! { /// ### What it does @@ -356,7 +357,7 @@ impl SuggestContext<'_, '_, '_> { if app != Applicability::MachineApplicable { return None; } - self.output.push_str(&(!snip).to_string()); + let _cannot_fail = write!(&mut self.output, "{}", &(!snip)); } }, True | False | Not(_) => { diff --git a/clippy_lints/src/cargo/mod.rs b/clippy_lints/src/cargo/mod.rs index 60371dcd7715..08d92adbacef 100644 --- a/clippy_lints/src/cargo/mod.rs +++ b/clippy_lints/src/cargo/mod.rs @@ -132,7 +132,7 @@ declare_clippy_lint! { /// Because this can be caused purely by the dependencies /// themselves, it's not always possible to fix this issue. /// In those cases, you can allow that specific crate using - /// the `allowed_duplicate_crates` configuration option. + /// the `allowed-duplicate-crates` configuration option. /// /// ### Example /// ```toml diff --git a/clippy_lints/src/cfg_not_test.rs b/clippy_lints/src/cfg_not_test.rs index ec543d02c9dd..88d07be0d4d4 100644 --- a/clippy_lints/src/cfg_not_test.rs +++ b/clippy_lints/src/cfg_not_test.rs @@ -1,10 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_then; +use rustc_ast::attr::data_structures::CfgEntry; +use rustc_ast::{AttrItemKind, EarlyParsedAttribute}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; -use rustc_ast::AttrItemKind; -use rustc_ast::EarlyParsedAttribute; use rustc_span::sym; -use rustc_ast::attr::data_structures::CfgEntry; declare_clippy_lint! { /// ### What it does @@ -40,7 +39,7 @@ impl EarlyLintPass for CfgNotTest { unreachable!() }; - if contains_not_test(&cfg, false) { + if contains_not_test(cfg, false) { span_lint_and_then( cx, CFG_NOT_TEST, @@ -58,11 +57,9 @@ impl EarlyLintPass for CfgNotTest { fn contains_not_test(cfg: &CfgEntry, not: bool) -> bool { match cfg { - CfgEntry::All(subs, _) | CfgEntry::Any(subs, _) => subs.iter().any(|item| { - contains_not_test(item, not) - }), + CfgEntry::All(subs, _) | CfgEntry::Any(subs, _) => subs.iter().any(|item| contains_not_test(item, not)), CfgEntry::Not(sub, _) => contains_not_test(sub, !not), CfgEntry::NameValue { name: sym::test, .. } => not, - _ => false + _ => false, } } diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 9b3822f9d8f0..8303897d1294 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal, sym}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, TyKind}; @@ -80,7 +80,8 @@ impl LateLintPass<'_> for CheckedConversions { && self.msrv.meets(cx, msrvs::TRY_FROM) { let mut applicability = Applicability::MachineApplicable; - let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut applicability); + let (snippet, _) = + snippet_with_context(cx, cv.expr_to_cast.span, item.span.ctxt(), "_", &mut applicability); span_lint_and_sugg( cx, CHECKED_CONVERSIONS, diff --git a/clippy_lints/src/derive/derive_ord_xor_partial_ord.rs b/clippy_lints/src/derive/derive_ord_xor_partial_ord.rs index 2bd5e2cbfb1a..316d800a70c9 100644 --- a/clippy_lints/src/derive/derive_ord_xor_partial_ord.rs +++ b/clippy_lints/src/derive/derive_ord_xor_partial_ord.rs @@ -1,15 +1,16 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; +use clippy_utils::fulfill_or_allowed; use rustc_hir::{self as hir, HirId}; use rustc_lint::LateContext; use rustc_middle::ty::Ty; -use rustc_span::{Span, sym}; +use rustc_span::sym; use super::DERIVE_ORD_XOR_PARTIAL_ORD; /// Implementation of the `DERIVE_ORD_XOR_PARTIAL_ORD` lint. pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, - span: Span, + item: &hir::Item<'_>, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>, adt_hir_id: HirId, @@ -19,6 +20,8 @@ pub(super) fn check<'tcx>( && let Some(partial_ord_trait_def_id) = cx.tcx.lang_items().partial_ord_trait() && let Some(def_id) = &trait_ref.trait_def_id() && *def_id == ord_trait_def_id + && let item_hir_id = cx.tcx.local_def_id_to_hir_id(item.owner_id) + && !fulfill_or_allowed(cx, DERIVE_ORD_XOR_PARTIAL_ORD, [adt_hir_id]) { // Look for the PartialOrd implementations for `ty` cx.tcx.for_each_relevant_impl(partial_ord_trait_def_id, ty, |impl_id| { @@ -39,7 +42,7 @@ pub(super) fn check<'tcx>( "you are deriving `Ord` but have implemented `PartialOrd` explicitly" }; - span_lint_hir_and_then(cx, DERIVE_ORD_XOR_PARTIAL_ORD, adt_hir_id, span, mess, |diag| { + span_lint_hir_and_then(cx, DERIVE_ORD_XOR_PARTIAL_ORD, item_hir_id, item.span, mess, |diag| { if let Some(local_def_id) = impl_id.as_local() { let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id); diag.span_note(cx.tcx.hir_span(hir_id), "`PartialOrd` implemented here"); diff --git a/clippy_lints/src/derive/mod.rs b/clippy_lints/src/derive/mod.rs index eafe7c4bb9f2..86614201c406 100644 --- a/clippy_lints/src/derive/mod.rs +++ b/clippy_lints/src/derive/mod.rs @@ -208,7 +208,7 @@ impl<'tcx> LateLintPass<'tcx> for Derive { let is_automatically_derived = cx.tcx.is_automatically_derived(item.owner_id.to_def_id()); derived_hash_with_manual_eq::check(cx, item.span, trait_ref, ty, adt_hir_id, is_automatically_derived); - derive_ord_xor_partial_ord::check(cx, item.span, trait_ref, ty, adt_hir_id, is_automatically_derived); + derive_ord_xor_partial_ord::check(cx, item, trait_ref, ty, adt_hir_id, is_automatically_derived); if is_automatically_derived { unsafe_derive_deserialize::check(cx, item, trait_ref, ty, adt_hir_id); diff --git a/clippy_lints/src/doc/include_in_doc_without_cfg.rs b/clippy_lints/src/doc/include_in_doc_without_cfg.rs index f8e9e870f629..6c800f47b68a 100644 --- a/clippy_lints/src/doc/include_in_doc_without_cfg.rs +++ b/clippy_lints/src/doc/include_in_doc_without_cfg.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; -use rustc_ast::{AttrArgs, AttrKind, AttrStyle, Attribute, AttrItemKind}; +use rustc_ast::{AttrArgs, AttrItemKind, AttrKind, AttrStyle, Attribute}; use rustc_errors::Applicability; use rustc_lint::EarlyContext; diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index b11b2f8392c1..2b41275ee3a4 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -869,10 +869,12 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &[ }), true, ); - let mut doc = fragments.iter().fold(String::new(), |mut acc, fragment| { - add_doc_fragment(&mut acc, fragment); - acc - }); + + let mut doc = String::with_capacity(fragments.iter().map(|frag| frag.doc.as_str().len() + 1).sum()); + + for fragment in &fragments { + add_doc_fragment(&mut doc, fragment); + } doc.pop(); if doc.trim().is_empty() { diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index 8defbeeaa5f2..351d29d87432 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -114,6 +114,8 @@ fn check_source(cx: &EarlyContext<'_>, inner: &Expr) -> bool { && inner.starts_with('(') && inner.ends_with(')') && outer_after_inner.trim_start().starts_with(')') + // Don't lint macro repetition patterns like `($($result),*)` where parens are necessary + && !inner.trim_start_matches('(').trim_start().starts_with("$(") { true } else { diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 7b6f8729cb75..516f9e3aa60c 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -1,9 +1,13 @@ +use std::borrow::Cow; + use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::{Sugg, make_binop}; use clippy_utils::{ - SpanlessEq, eq_expr_value, higher, is_in_const_context, is_integer_literal, peel_blocks, peel_blocks_with_stmt, sym, + SpanlessEq, eq_expr_value, higher, is_in_const_context, is_integer_literal, is_integer_literal_untyped, + peel_blocks, peel_blocks_with_stmt, sym, }; use rustc_ast::ast::LitKind; use rustc_data_structures::packed::Pu128; @@ -238,10 +242,21 @@ fn check_subtraction( if eq_expr_value(cx, left, big_expr) && eq_expr_value(cx, right, little_expr) { // This part of the condition is voluntarily split from the one before to ensure that // if `snippet_opt` fails, it won't try the next conditions. - if (!is_in_const_context(cx) || msrv.meets(cx, msrvs::SATURATING_SUB_CONST)) - && let Some(big_expr_sugg) = Sugg::hir_opt(cx, big_expr).map(Sugg::maybe_paren) - && let Some(little_expr_sugg) = Sugg::hir_opt(cx, little_expr) - { + if !is_in_const_context(cx) || msrv.meets(cx, msrvs::SATURATING_SUB_CONST) { + let mut applicability = Applicability::MachineApplicable; + let big_expr_sugg = (if is_integer_literal_untyped(big_expr) { + let get_snippet = |span: Span| { + let snippet = snippet_with_applicability(cx, span, "..", &mut applicability); + let big_expr_ty = cx.typeck_results().expr_ty(big_expr); + Cow::Owned(format!("{snippet}_{big_expr_ty}")) + }; + Sugg::hir_from_snippet(cx, big_expr, get_snippet) + } else { + Sugg::hir_with_applicability(cx, big_expr, "..", &mut applicability) + }) + .maybe_paren(); + let little_expr_sugg = Sugg::hir_with_applicability(cx, little_expr, "..", &mut applicability); + let sugg = format!( "{}{big_expr_sugg}.saturating_sub({little_expr_sugg}){}", if is_composited { "{ " } else { "" }, @@ -254,7 +269,7 @@ fn check_subtraction( "manual arithmetic check found", "replace it with", sugg, - Applicability::MachineApplicable, + applicability, ); } } else if eq_expr_value(cx, left, little_expr) diff --git a/clippy_lints/src/incompatible_msrv.rs b/clippy_lints/src/incompatible_msrv.rs index e0149a23fccf..8d538ff1acba 100644 --- a/clippy_lints/src/incompatible_msrv.rs +++ b/clippy_lints/src/incompatible_msrv.rs @@ -3,14 +3,13 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::Msrv; use clippy_utils::{is_in_const_context, is_in_test, sym}; use rustc_data_structures::fx::FxHashMap; -use rustc_hir::{self as hir, AmbigArg, Expr, ExprKind, HirId, RustcVersion, StabilityLevel, StableSince}; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::{self as hir, AmbigArg, Expr, ExprKind, HirId, RustcVersion, StabilityLevel, StableSince, find_attr}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::impl_lint_pass; use rustc_span::def_id::{CrateNum, DefId}; use rustc_span::{ExpnKind, Span}; -use rustc_hir::attrs::AttributeKind; -use rustc_hir::find_attr; declare_clippy_lint! { /// ### What it does @@ -270,6 +269,9 @@ impl<'tcx> LateLintPass<'tcx> for IncompatibleMsrv { /// attribute. fn is_under_cfg_attribute(cx: &LateContext<'_>, hir_id: HirId) -> bool { cx.tcx.hir_parent_id_iter(hir_id).any(|id| { - find_attr!(cx.tcx.hir_attrs(id), AttributeKind::CfgTrace(..) | AttributeKind::CfgAttrTrace) + find_attr!( + cx.tcx.hir_attrs(id), + AttributeKind::CfgTrace(..) | AttributeKind::CfgAttrTrace + ) }) } diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index f59c7615d745..14928a1be13b 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -101,7 +101,21 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { InherentImplLintScope::Crate => Criterion::Crate, }; let is_test = is_cfg_test(cx.tcx, hir_id) || is_in_cfg_test(cx.tcx, hir_id); - match type_map.entry((impl_ty, criterion, is_test)) { + let predicates = { + // Gets the predicates (bounds) for the given impl block, + // sorted for consistent comparison to allow distinguishing between impl blocks + // with different generic bounds. + let mut predicates = cx + .tcx + .predicates_of(impl_id) + .predicates + .iter() + .map(|(clause, _)| *clause) + .collect::>(); + predicates.sort_by_key(|c| format!("{c:?}")); + predicates + }; + match type_map.entry((impl_ty, predicates, criterion, is_test)) { Entry::Vacant(e) => { // Store the id for the first impl block of this type. The span is retrieved lazily. e.insert(IdOrSpan::Id(impl_id)); @@ -152,15 +166,12 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { fn get_impl_span(cx: &LateContext<'_>, id: LocalDefId) -> Option { let id = cx.tcx.local_def_id_to_hir_id(id); if let Node::Item(&Item { - kind: ItemKind::Impl(impl_item), + kind: ItemKind::Impl(_), span, .. }) = cx.tcx.hir_node(id) { - (!span.from_expansion() - && impl_item.generics.params.is_empty() - && !fulfill_or_allowed(cx, MULTIPLE_INHERENT_IMPL, [id])) - .then_some(span) + (!span.from_expansion() && !fulfill_or_allowed(cx, MULTIPLE_INHERENT_IMPL, [id])).then_some(span) } else { None } diff --git a/clippy_lints/src/large_include_file.rs b/clippy_lints/src/large_include_file.rs index 5c37747b8c9b..d77e0beeaf4c 100644 --- a/clippy_lints/src/large_include_file.rs +++ b/clippy_lints/src/large_include_file.rs @@ -3,7 +3,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::source::snippet_opt; -use rustc_ast::{AttrArgs, AttrKind, Attribute, LitKind}; +use rustc_ast::{AttrArgs, AttrItemKind, AttrKind, Attribute, LitKind}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_session::impl_lint_pass; diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index 261b03abba17..32c23a2d0362 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -94,6 +94,15 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { }) && u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size) { + // libtest might generate a large array containing the test cases, and no span will be associated + // to it. In this case it is better not to complain. + // + // Note that this condition is not checked explicitly by a unit test. Do not remove it without + // ensuring that stays fixed. + if expr.span.is_dummy() { + return; + } + span_lint_and_then( cx, LARGE_STACK_ARRAYS, diff --git a/clippy_lints/src/loops/for_kv_map.rs b/clippy_lints/src/loops/for_kv_map.rs index 39b2391c98ec..7fb8e51377a2 100644 --- a/clippy_lints/src/loops/for_kv_map.rs +++ b/clippy_lints/src/loops/for_kv_map.rs @@ -1,16 +1,22 @@ use super::FOR_KV_MAP; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeDef; -use clippy_utils::source::snippet; +use clippy_utils::source::{snippet_with_applicability, walk_span_to_context}; use clippy_utils::{pat_is_wild, sugg}; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::sym; +use rustc_span::{Span, sym}; /// Checks for the `FOR_KV_MAP` lint. -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx Expr<'_>, body: &'tcx Expr<'_>) { +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + pat: &'tcx Pat<'_>, + arg: &'tcx Expr<'_>, + body: &'tcx Expr<'_>, + span: Span, +) { let pat_span = pat.span; if let PatKind::Tuple(pat, _) = pat.kind @@ -34,21 +40,25 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx _ => arg, }; - if matches!(ty.opt_diag_name(cx), Some(sym::HashMap | sym::BTreeMap)) { + if matches!(ty.opt_diag_name(cx), Some(sym::HashMap | sym::BTreeMap)) + && let Some(arg_span) = walk_span_to_context(arg_span, span.ctxt()) + { span_lint_and_then( cx, FOR_KV_MAP, arg_span, format!("you seem to want to iterate on a map's {kind}s"), |diag| { - let map = sugg::Sugg::hir(cx, arg, "map"); + let mut applicability = Applicability::MachineApplicable; + let map = sugg::Sugg::hir_with_context(cx, arg, span.ctxt(), "map", &mut applicability); + let pat = snippet_with_applicability(cx, new_pat_span, kind, &mut applicability); diag.multipart_suggestion( "use the corresponding method", vec![ - (pat_span, snippet(cx, new_pat_span, kind).into_owned()), + (pat_span, pat.to_string()), (arg_span, format!("{}.{kind}s{mutbl}()", map.maybe_paren())), ], - Applicability::MachineApplicable, + applicability, ); }, ); diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index ddc783069385..83574cab6b67 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -943,7 +943,7 @@ impl Loops { explicit_counter_loop::check(cx, pat, arg, body, expr, label); } self.check_for_loop_arg(cx, pat, arg); - for_kv_map::check(cx, pat, arg, body); + for_kv_map::check(cx, pat, arg, body, span); mut_range_bound::check(cx, arg, body); single_element_loop::check(cx, pat, arg, body, expr); same_item_push::check(cx, pat, arg, body, expr, self.msrv); diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index a037af3433c3..e7b9b1cd3881 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -4,8 +4,8 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::ForLoop; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::source::{snippet, snippet_with_context}; -use clippy_utils::sym; use clippy_utils::visitors::{Descend, for_each_expr_without_closures}; +use clippy_utils::{contains_return, sym}; use rustc_errors::Applicability; use rustc_hir::{ Block, Closure, Destination, Expr, ExprKind, HirId, InlineAsm, InlineAsmOperand, Node, Pat, Stmt, StmtKind, @@ -82,7 +82,7 @@ pub(super) fn check_iterator_reduction<'tcx>( ) { let closure_body = cx.tcx.hir_body(closure.body).value; let body_ty = cx.typeck_results().expr_ty(closure_body); - if body_ty.is_never() { + if body_ty.is_never() && !contains_return(closure_body) { span_lint_and_then( cx, NEVER_LOOP, diff --git a/clippy_lints/src/manual_ignore_case_cmp.rs b/clippy_lints/src/manual_ignore_case_cmp.rs index 25057b4aeaa2..1c20a8f81efb 100644 --- a/clippy_lints/src/manual_ignore_case_cmp.rs +++ b/clippy_lints/src/manual_ignore_case_cmp.rs @@ -1,7 +1,7 @@ use crate::manual_ignore_case_cmp::MatchType::{Literal, ToAscii}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeDef; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::sym; use rustc_ast::LitKind; use rustc_errors::Applicability; @@ -111,14 +111,12 @@ impl LateLintPass<'_> for ManualIgnoreCaseCmp { "manual case-insensitive ASCII comparison", |diag| { let mut app = Applicability::MachineApplicable; + let (left_snip, _) = snippet_with_context(cx, left_span, expr.span.ctxt(), "..", &mut app); + let (right_snip, _) = snippet_with_context(cx, right_span, expr.span.ctxt(), "..", &mut app); diag.span_suggestion_verbose( expr.span, "consider using `.eq_ignore_ascii_case()` instead", - format!( - "{neg}{}.eq_ignore_ascii_case({deref}{})", - snippet_with_applicability(cx, left_span, "_", &mut app), - snippet_with_applicability(cx, right_span, "_", &mut app) - ), + format!("{neg}{left_snip}.eq_ignore_ascii_case({deref}{right_snip})"), app, ); }, diff --git a/clippy_lints/src/manual_ilog2.rs b/clippy_lints/src/manual_ilog2.rs index 1c61db530606..4b411a60f3bf 100644 --- a/clippy_lints/src/manual_ilog2.rs +++ b/clippy_lints/src/manual_ilog2.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::{is_from_proc_macro, sym}; use rustc_ast::LitKind; use rustc_data_structures::packed::Pu128; @@ -102,7 +102,7 @@ impl LateLintPass<'_> for ManualIlog2 { fn emit(cx: &LateContext<'_>, recv: &Expr<'_>, full_expr: &Expr<'_>) { let mut app = Applicability::MachineApplicable; - let recv = snippet_with_applicability(cx, recv.span, "_", &mut app); + let (recv, _) = snippet_with_context(cx, recv.span, full_expr.span.ctxt(), "_", &mut app); span_lint_and_sugg( cx, MANUAL_ILOG2, diff --git a/clippy_lints/src/matches/manual_ok_err.rs b/clippy_lints/src/matches/manual_ok_err.rs index c35c3d1f62e6..1fc8bb9acce2 100644 --- a/clippy_lints/src/matches/manual_ok_err.rs +++ b/clippy_lints/src/matches/manual_ok_err.rs @@ -135,7 +135,7 @@ fn apply_lint(cx: &LateContext<'_>, expr: &Expr<'_>, scrutinee: &Expr<'_>, is_ok } else { Applicability::MachineApplicable }; - let scrut = Sugg::hir_with_applicability(cx, scrutinee, "..", &mut app).maybe_paren(); + let scrut = Sugg::hir_with_context(cx, scrutinee, expr.span.ctxt(), "..", &mut app).maybe_paren(); let scrutinee_ty = cx.typeck_results().expr_ty(scrutinee); let (_, _, mutability) = peel_and_count_ty_refs(scrutinee_ty); diff --git a/clippy_lints/src/matches/match_as_ref.rs b/clippy_lints/src/matches/match_as_ref.rs index 795355f25f9e..12fe44ef2f13 100644 --- a/clippy_lints/src/matches/match_as_ref.rs +++ b/clippy_lints/src/matches/match_as_ref.rs @@ -46,6 +46,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: let cast = if input_ty == output_ty { "" } else { ".map(|x| x as _)" }; let mut applicability = Applicability::MachineApplicable; + let ctxt = expr.span.ctxt(); span_lint_and_then( cx, MATCH_AS_REF, @@ -59,7 +60,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: "use `Option::as_ref()`", format!( "{}.as_ref(){cast}", - Sugg::hir_with_applicability(cx, ex, "_", &mut applicability).maybe_paren(), + Sugg::hir_with_context(cx, ex, ctxt, "_", &mut applicability).maybe_paren(), ), applicability, ); @@ -69,7 +70,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: format!("use `Option::{method}()` directly"), format!( "{}.{method}(){cast}", - Sugg::hir_with_applicability(cx, ex, "_", &mut applicability).maybe_paren(), + Sugg::hir_with_context(cx, ex, ctxt, "_", &mut applicability).maybe_paren(), ), applicability, ); diff --git a/clippy_lints/src/matches/match_bool.rs b/clippy_lints/src/matches/match_bool.rs index a2c8741f4f74..3e76231b6ef1 100644 --- a/clippy_lints/src/matches/match_bool.rs +++ b/clippy_lints/src/matches/match_bool.rs @@ -16,6 +16,7 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>] && arms .iter() .all(|arm| arm.pat.walk_short(|p| !matches!(p.kind, PatKind::Binding(..)))) + && arms.len() == 2 { span_lint_and_then( cx, @@ -23,59 +24,58 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>] expr.span, "`match` on a boolean expression", move |diag| { - if arms.len() == 2 { - let mut app = Applicability::MachineApplicable; - let test_sugg = if let PatKind::Expr(arm_bool) = arms[0].pat.kind { - let test = Sugg::hir_with_applicability(cx, scrutinee, "_", &mut app); - if let PatExprKind::Lit { lit, .. } = arm_bool.kind { - match &lit.node { - LitKind::Bool(true) => Some(test), - LitKind::Bool(false) => Some(!test), - _ => None, - } - .map(|test| { - if let Some(guard) = &arms[0] - .guard - .map(|g| Sugg::hir_with_applicability(cx, g, "_", &mut app)) - { - test.and(guard) - } else { - test - } - }) - } else { - None + let mut app = Applicability::MachineApplicable; + let ctxt = expr.span.ctxt(); + let test_sugg = if let PatKind::Expr(arm_bool) = arms[0].pat.kind { + let test = Sugg::hir_with_context(cx, scrutinee, ctxt, "_", &mut app); + if let PatExprKind::Lit { lit, .. } = arm_bool.kind { + match &lit.node { + LitKind::Bool(true) => Some(test), + LitKind::Bool(false) => Some(!test), + _ => None, } + .map(|test| { + if let Some(guard) = &arms[0] + .guard + .map(|g| Sugg::hir_with_context(cx, g, ctxt, "_", &mut app)) + { + test.and(guard) + } else { + test + } + }) } else { None + } + } else { + None + }; + + if let Some(test_sugg) = test_sugg { + let ctxt = expr.span.ctxt(); + let (true_expr, false_expr) = (arms[0].body, arms[1].body); + let sugg = match (is_unit_expr(true_expr), is_unit_expr(false_expr)) { + (false, false) => Some(format!( + "if {} {} else {}", + test_sugg, + expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app), + expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app) + )), + (false, true) => Some(format!( + "if {} {}", + test_sugg, + expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app) + )), + (true, false) => Some(format!( + "if {} {}", + !test_sugg, + expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app) + )), + (true, true) => None, }; - if let Some(test_sugg) = test_sugg { - let ctxt = expr.span.ctxt(); - let (true_expr, false_expr) = (arms[0].body, arms[1].body); - let sugg = match (is_unit_expr(true_expr), is_unit_expr(false_expr)) { - (false, false) => Some(format!( - "if {} {} else {}", - test_sugg, - expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app), - expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app) - )), - (false, true) => Some(format!( - "if {} {}", - test_sugg, - expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app) - )), - (true, false) => Some(format!( - "if {} {}", - !test_sugg, - expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app) - )), - (true, true) => None, - }; - - if let Some(sugg) = sugg { - diag.span_suggestion(expr.span, "consider using an `if`/`else` expression", sugg, app); - } + if let Some(sugg) = sugg { + diag.span_suggestion(expr.span, "consider using an `if`/`else` expression", sugg, app); } } }, diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index bc3783750e5c..bf0c0c4aec3c 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -1,7 +1,6 @@ use super::REDUNDANT_PATTERN_MATCHING; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; -use clippy_utils::source::walk_span_to_context; use clippy_utils::sugg::{Sugg, make_unop}; use clippy_utils::ty::needs_ordered_drop; use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr_without_closures}; @@ -25,7 +24,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { .. }) = higher::WhileLet::hir(expr) { - find_method_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false); + find_method_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false, let_span); find_if_let_true(cx, let_pat, let_expr, let_span); } } @@ -39,7 +38,7 @@ pub(super) fn check_if_let<'tcx>( let_span: Span, ) { find_if_let_true(cx, pat, scrutinee, let_span); - find_method_sugg_for_if_let(cx, expr, pat, scrutinee, "if", has_else); + find_method_sugg_for_if_let(cx, expr, pat, scrutinee, "if", has_else, let_span); } /// Looks for: @@ -182,6 +181,7 @@ fn find_method_sugg_for_if_let<'tcx>( let_expr: &'tcx Expr<'_>, keyword: &'static str, has_else: bool, + let_span: Span, ) { // also look inside refs // if we have &None for example, peel it so we can detect "if let None = x" @@ -239,15 +239,9 @@ fn find_method_sugg_for_if_let<'tcx>( let expr_span = expr.span; let ctxt = expr.span.ctxt(); - // if/while let ... = ... { ... } - // ^^^ - let Some(res_span) = walk_span_to_context(result_expr.span.source_callsite(), ctxt) else { - return; - }; - // if/while let ... = ... { ... } // ^^^^^^^^^^^^^^^^^^^^^^ - let span = expr_span.until(res_span.shrink_to_hi()); + let span = expr_span.until(let_span.shrink_to_hi()); let mut app = if needs_drop { Applicability::MaybeIncorrect @@ -273,13 +267,14 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op if let Ok(arms) = arms.try_into() // TODO: use `slice::as_array` once stabilized && let Some((good_method, maybe_guard)) = found_good_method(cx, arms) { - let span = is_expn_of(expr.span, sym::matches).unwrap_or(expr.span.to(op.span)); + let expr_span = is_expn_of(expr.span, sym::matches).unwrap_or(expr.span); + let result_expr = match &op.kind { ExprKind::AddrOf(_, _, borrowed) => borrowed, _ => op, }; let mut app = Applicability::MachineApplicable; - let receiver_sugg = Sugg::hir_with_applicability(cx, result_expr, "_", &mut app).maybe_paren(); + let receiver_sugg = Sugg::hir_with_context(cx, result_expr, expr_span.ctxt(), "_", &mut app).maybe_paren(); let mut sugg = format!("{receiver_sugg}.{good_method}"); if let Some(guard) = maybe_guard { @@ -302,14 +297,14 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op return; } - let guard = Sugg::hir(cx, guard, ".."); + let guard = Sugg::hir_with_context(cx, guard, expr_span.ctxt(), "..", &mut app); let _ = write!(sugg, " && {}", guard.maybe_paren()); } span_lint_and_sugg( cx, REDUNDANT_PATTERN_MATCHING, - span, + expr_span, format!("redundant pattern matching, consider using `{good_method}`"), "try", sugg, diff --git a/clippy_lints/src/methods/is_empty.rs b/clippy_lints/src/methods/is_empty.rs index 834456ff6668..8135c67d0d78 100644 --- a/clippy_lints/src/methods/is_empty.rs +++ b/clippy_lints/src/methods/is_empty.rs @@ -3,10 +3,9 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::macros::{is_assert_macro, root_macro_call}; use clippy_utils::res::MaybeResPath; use clippy_utils::{find_binding_init, get_parent_expr, is_inside_always_const_context}; -use rustc_hir::{Expr, HirId}; -use rustc_lint::{LateContext, LintContext}; use rustc_hir::attrs::AttributeKind; -use rustc_hir::find_attr; +use rustc_hir::{Expr, HirId, find_attr}; +use rustc_lint::{LateContext, LintContext}; use super::CONST_IS_EMPTY; diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index 16db8663941e..366bfaed73d4 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -2,7 +2,7 @@ use super::ITER_KV_MAP; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeDef; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::{pat_is_wild, sym}; use rustc_hir::{Body, Expr, ExprKind, PatKind}; use rustc_lint::LateContext; @@ -58,6 +58,8 @@ pub(super) fn check<'tcx>( applicability, ); } else { + let (body_snippet, _) = + snippet_with_context(cx, body_expr.span, expr.span.ctxt(), "..", &mut applicability); span_lint_and_sugg( cx, ITER_KV_MAP, @@ -65,9 +67,8 @@ pub(super) fn check<'tcx>( format!("iterating on a map's {replacement_kind}s"), "try", format!( - "{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{}{bound_ident}| {})", + "{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{}{bound_ident}| {body_snippet})", annotation.prefix_str(), - snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability) ), applicability, ); diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index 9dae6fbb48dd..c3f031edff2e 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -1,10 +1,10 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath, MaybeTypeckRes}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::{DefinedTy, ExprUseNode, expr_use_ctxt, peel_blocks, strip_pat_refs}; use rustc_ast::ast; use rustc_data_structures::packed::Pu128; -use rustc_errors::Applicability; +use rustc_errors::{Applicability, Diag}; use rustc_hir as hir; use rustc_hir::PatKind; use rustc_hir::def::{DefKind, Res}; @@ -59,6 +59,34 @@ struct Replacement { method_name: &'static str, has_args: bool, has_generic_return: bool, + is_short_circuiting: bool, +} + +impl Replacement { + fn default_applicability(&self) -> Applicability { + if self.is_short_circuiting { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + } + } + + fn maybe_add_note(&self, diag: &mut Diag<'_, ()>) { + if self.is_short_circuiting { + diag.note(format!( + "the `{}` method is short circuiting and may change the program semantics if the iterator has side effects", + self.method_name + )); + } + } + + fn maybe_turbofish(&self, ty: Ty<'_>) -> String { + if self.has_generic_return { + format!("::<{ty}>") + } else { + String::new() + } + } } fn check_fold_with_op( @@ -86,32 +114,30 @@ fn check_fold_with_op( && left_expr.res_local_id() == Some(first_arg_id) && (replacement.has_args || right_expr.res_local_id() == Some(second_arg_id)) { - let mut applicability = Applicability::MachineApplicable; - - let turbofish = if replacement.has_generic_return { - format!("::<{}>", cx.typeck_results().expr_ty_adjusted(right_expr).peel_refs()) - } else { - String::new() - }; - - let sugg = if replacement.has_args { - format!( - "{method}{turbofish}(|{second_arg_ident}| {r})", - method = replacement.method_name, - r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability), - ) - } else { - format!("{method}{turbofish}()", method = replacement.method_name) - }; - - span_lint_and_sugg( + let span = fold_span.with_hi(expr.span.hi()); + span_lint_and_then( cx, UNNECESSARY_FOLD, - fold_span.with_hi(expr.span.hi()), + span, "this `.fold` can be written more succinctly using another method", - "try", - sugg, - applicability, + |diag| { + let mut applicability = replacement.default_applicability(); + let turbofish = + replacement.maybe_turbofish(cx.typeck_results().expr_ty_adjusted(right_expr).peel_refs()); + let (r_snippet, _) = + snippet_with_context(cx, right_expr.span, expr.span.ctxt(), "EXPR", &mut applicability); + let sugg = if replacement.has_args { + format!( + "{method}{turbofish}(|{second_arg_ident}| {r_snippet})", + method = replacement.method_name, + ) + } else { + format!("{method}{turbofish}()", method = replacement.method_name) + }; + + diag.span_suggestion(span, "try", sugg, applicability); + replacement.maybe_add_note(diag); + }, ); return true; } @@ -131,22 +157,25 @@ fn check_fold_with_method( // Check if the function belongs to the operator && cx.tcx.is_diagnostic_item(method, fn_did) { - let applicability = Applicability::MachineApplicable; - - let turbofish = if replacement.has_generic_return { - format!("::<{}>", cx.typeck_results().expr_ty(expr)) - } else { - String::new() - }; - - span_lint_and_sugg( + let span = fold_span.with_hi(expr.span.hi()); + span_lint_and_then( cx, UNNECESSARY_FOLD, - fold_span.with_hi(expr.span.hi()), + span, "this `.fold` can be written more succinctly using another method", - "try", - format!("{method}{turbofish}()", method = replacement.method_name), - applicability, + |diag| { + diag.span_suggestion( + span, + "try", + format!( + "{method}{turbofish}()", + method = replacement.method_name, + turbofish = replacement.maybe_turbofish(cx.typeck_results().expr_ty(expr)) + ), + replacement.default_applicability(), + ); + replacement.maybe_add_note(diag); + }, ); } } @@ -171,6 +200,7 @@ pub(super) fn check<'tcx>( method_name: "any", has_args: true, has_generic_return: false, + is_short_circuiting: true, }; check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, replacement); }, @@ -179,6 +209,7 @@ pub(super) fn check<'tcx>( method_name: "all", has_args: true, has_generic_return: false, + is_short_circuiting: true, }; check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, replacement); }, @@ -187,6 +218,7 @@ pub(super) fn check<'tcx>( method_name: "sum", has_args: false, has_generic_return: needs_turbofish(cx, expr), + is_short_circuiting: false, }; if !check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, replacement) { check_fold_with_method(cx, expr, acc, fold_span, sym::add, replacement); @@ -197,6 +229,7 @@ pub(super) fn check<'tcx>( method_name: "product", has_args: false, has_generic_return: needs_turbofish(cx, expr), + is_short_circuiting: false, }; if !check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, replacement) { check_fold_with_method(cx, expr, acc, fold_span, sym::mul, replacement); diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index a6a39cb6ab30..74e8dbc15a6c 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -3,7 +3,7 @@ use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeDef; -use clippy_utils::source::{SpanRangeExt, snippet}; +use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_context}; use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, peel_and_count_ty_refs}; use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{fn_def_id, get_parent_expr, is_expr_temporary_value, return_ty, sym}; @@ -131,8 +131,10 @@ fn check_addr_of_expr( && (*referent_ty != receiver_ty || (matches!(referent_ty.kind(), ty::Array(..)) && is_copy(cx, *referent_ty)) || is_cow_into_owned(cx, method_name, method_parent_id)) - && let Some(receiver_snippet) = receiver.span.get_source_text(cx) { + let mut applicability = Applicability::MachineApplicable; + let (receiver_snippet, _) = snippet_with_context(cx, receiver.span, expr.span.ctxt(), "..", &mut applicability); + if receiver_ty == target_ty && n_target_refs >= n_receiver_refs { span_lint_and_sugg( cx, @@ -145,7 +147,7 @@ fn check_addr_of_expr( "", width = n_target_refs - n_receiver_refs ), - Applicability::MachineApplicable, + applicability, ); return true; } @@ -165,8 +167,8 @@ fn check_addr_of_expr( parent.span, format!("unnecessary use of `{method_name}`"), "use", - receiver_snippet.to_owned(), - Applicability::MachineApplicable, + receiver_snippet.to_string(), + applicability, ); } else { span_lint_and_sugg( @@ -176,7 +178,7 @@ fn check_addr_of_expr( format!("unnecessary use of `{method_name}`"), "remove this", String::new(), - Applicability::MachineApplicable, + applicability, ); } return true; @@ -191,7 +193,7 @@ fn check_addr_of_expr( format!("unnecessary use of `{method_name}`"), "use", format!("{receiver_snippet}.as_ref()"), - Applicability::MachineApplicable, + applicability, ); return true; } @@ -409,8 +411,10 @@ fn check_other_call_arg<'tcx>( None } && can_change_type(cx, maybe_arg, receiver_ty) - && let Some(receiver_snippet) = receiver.span.get_source_text(cx) { + let mut applicability = Applicability::MachineApplicable; + let (receiver_snippet, _) = snippet_with_context(cx, receiver.span, expr.span.ctxt(), "..", &mut applicability); + span_lint_and_sugg( cx, UNNECESSARY_TO_OWNED, @@ -418,7 +422,7 @@ fn check_other_call_arg<'tcx>( format!("unnecessary use of `{method_name}`"), "use", format!("{:&>n_refs$}{receiver_snippet}", ""), - Applicability::MachineApplicable, + applicability, ); return true; } diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs index eeea6dfd5f4b..5dd38cf059c2 100644 --- a/clippy_lints/src/missing_enforced_import_rename.rs +++ b/clippy_lints/src/missing_enforced_import_rename.rs @@ -82,7 +82,8 @@ impl LateLintPass<'_> for ImportRename { && let Some(import) = match snip.split_once(" as ") { None => Some(snip.as_str()), Some((import, rename)) => { - if rename.trim() == name.as_str() { + let trimmed_rename = rename.trim(); + if trimmed_rename == "_" || trimmed_rename == name.as_str() { None } else { Some(import.trim()) diff --git a/clippy_lints/src/multiple_bound_locations.rs b/clippy_lints/src/multiple_bound_locations.rs index 741f38f97560..5b6b4f112455 100644 --- a/clippy_lints/src/multiple_bound_locations.rs +++ b/clippy_lints/src/multiple_bound_locations.rs @@ -31,7 +31,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.78.0"] pub MULTIPLE_BOUND_LOCATIONS, - suspicious, + style, "defining generic bounds in multiple locations" } diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 2fef8404f824..ad44d65b4d66 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -143,7 +143,7 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, ty_ascription: &T && new.ident.name == sym::new { let mut applicability = Applicability::MaybeIncorrect; - let arg = Sugg::hir_with_applicability(cx, arg, "_", &mut applicability); + let arg = Sugg::hir_with_context(cx, arg, expr.span.ctxt(), "_", &mut applicability); let mut suggs = vec![(expr.span, format!("std::sync::atomic::{atomic_name}::new({arg})"))]; match ty_ascription { TypeAscriptionKind::Required(ty_ascription) => { diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 854e927aa2f7..6b5db9dcf3e2 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::Sugg; use clippy_utils::{ SpanlessEq, get_parent_expr, higher, is_block_like, is_else_clause, is_parent_stmt, is_receiver_of_method_call, @@ -171,8 +171,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool { && SpanlessEq::new(cx).eq_expr(lhs_a, lhs_b) { let mut applicability = Applicability::MachineApplicable; - let cond = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability); - let lhs = snippet_with_applicability(cx, lhs_a.span, "..", &mut applicability); + let cond = Sugg::hir_with_context(cx, cond, e.span.ctxt(), "..", &mut applicability); + let (lhs, _) = snippet_with_context(cx, lhs_a.span, e.span.ctxt(), "..", &mut applicability); let mut sugg = if a == b { format!("{cond}; {lhs} = {a:?};") } else { diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index d03188f1d39b..55a5a16c0099 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -56,8 +56,20 @@ declare_lint_pass!(NeedlessForEach => [NEEDLESS_FOR_EACH]); impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { - if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind - && let ExprKind::MethodCall(method_name, for_each_recv, [for_each_arg], _) = expr.kind + if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind { + check_expr(cx, expr, stmt.span); + } + } + + fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) { + if let Some(expr) = block.expr { + check_expr(cx, expr, expr.span); + } + } +} + +fn check_expr(cx: &LateContext<'_>, expr: &Expr<'_>, outer_span: Span) { + if let ExprKind::MethodCall(method_name, for_each_recv, [for_each_arg], _) = expr.kind && let ExprKind::MethodCall(_, iter_recv, [], _) = for_each_recv.kind // Skip the lint if the call chain is too long. e.g. `v.field.iter().for_each()` or // `v.foo().iter().for_each()` must be skipped. @@ -76,69 +88,74 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { // Skip the lint if the body is not safe, so as not to suggest `for … in … unsafe {}` // and suggesting `for … in … { unsafe { } }` is a little ugly. && !matches!(body.value.kind, ExprKind::Block(Block { rules: BlockCheckMode::UnsafeBlock(_), .. }, ..)) + { + let mut applicability = Applicability::MachineApplicable; + + // If any closure parameter has an explicit type specified, applying the lint would necessarily + // remove that specification, possibly breaking type inference + if fn_decl + .inputs + .iter() + .any(|input| matches!(input.kind, TyKind::Infer(..))) { - let mut applicability = Applicability::MachineApplicable; + applicability = Applicability::MaybeIncorrect; + } - // If any closure parameter has an explicit type specified, applying the lint would necessarily - // remove that specification, possibly breaking type inference - if fn_decl - .inputs - .iter() - .any(|input| matches!(input.kind, TyKind::Infer(..))) - { - applicability = Applicability::MaybeIncorrect; - } + let mut ret_collector = RetCollector::default(); + ret_collector.visit_expr(body.value); - let mut ret_collector = RetCollector::default(); - ret_collector.visit_expr(body.value); + // Skip the lint if `return` is used in `Loop` in order not to suggest using `'label`. + if ret_collector.ret_in_loop { + return; + } - // Skip the lint if `return` is used in `Loop` in order not to suggest using `'label`. - if ret_collector.ret_in_loop { - return; - } + let ret_suggs = if ret_collector.spans.is_empty() { + None + } else { + applicability = Applicability::MaybeIncorrect; + Some( + ret_collector + .spans + .into_iter() + .map(|span| (span, "continue".to_string())) + .collect(), + ) + }; - let ret_suggs = if ret_collector.spans.is_empty() { - None + let body_param_sugg = snippet_with_applicability(cx, body.params[0].pat.span, "..", &mut applicability); + let for_each_rev_sugg = snippet_with_applicability(cx, for_each_recv.span, "..", &mut applicability); + let (body_value_sugg, is_macro_call) = + snippet_with_context(cx, body.value.span, for_each_recv.span.ctxt(), "..", &mut applicability); + + let sugg = format!( + "for {} in {} {}", + body_param_sugg, + for_each_rev_sugg, + if is_macro_call { + format!("{{ {body_value_sugg}; }}") } else { - applicability = Applicability::MaybeIncorrect; - Some( - ret_collector - .spans - .into_iter() - .map(|span| (span, "continue".to_string())) - .collect(), - ) - }; - - let body_param_sugg = snippet_with_applicability(cx, body.params[0].pat.span, "..", &mut applicability); - let for_each_rev_sugg = snippet_with_applicability(cx, for_each_recv.span, "..", &mut applicability); - let (body_value_sugg, is_macro_call) = - snippet_with_context(cx, body.value.span, for_each_recv.span.ctxt(), "..", &mut applicability); - - let sugg = format!( - "for {} in {} {}", - body_param_sugg, - for_each_rev_sugg, - if is_macro_call { - format!("{{ {body_value_sugg}; }}") - } else { - match body.value.kind { - ExprKind::Block(block, _) if is_let_desugar(block) => { - format!("{{ {body_value_sugg} }}") - }, - ExprKind::Block(_, _) => body_value_sugg.to_string(), - _ => format!("{{ {body_value_sugg}; }}"), - } + match body.value.kind { + ExprKind::Block(block, _) if is_let_desugar(block) => { + format!("{{ {body_value_sugg} }}") + }, + ExprKind::Block(_, _) => body_value_sugg.to_string(), + _ => format!("{{ {body_value_sugg}; }}"), } - ); + } + ); - span_lint_and_then(cx, NEEDLESS_FOR_EACH, stmt.span, "needless use of `for_each`", |diag| { - diag.span_suggestion(stmt.span, "try", sugg, applicability); + span_lint_and_then( + cx, + NEEDLESS_FOR_EACH, + outer_span, + "needless use of `for_each`", + |diag| { + diag.span_suggestion(outer_span, "try", sugg, applicability); if let Some(ret_suggs) = ret_suggs { diag.multipart_suggestion("...and replace `return` with `continue`", ret_suggs, applicability); } - }); - } + }, + ); } } diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 67493d54b552..e151c06c6c20 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -1,16 +1,15 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::return_ty; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::{indent_of, reindent_multiline, snippet_with_applicability}; use clippy_utils::sugg::DiagExt; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::HirIdSet; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::{Attribute, HirIdSet}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::AssocKind; use rustc_session::impl_lint_pass; use rustc_span::sym; -use rustc_hir::Attribute; -use rustc_hir::attrs::AttributeKind; declare_clippy_lint! { /// ### What it does @@ -59,6 +58,7 @@ pub struct NewWithoutDefault { impl_lint_pass!(NewWithoutDefault => [NEW_WITHOUT_DEFAULT]); impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { + #[expect(clippy::too_many_lines)] fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { let hir::ItemKind::Impl(hir::Impl { of_trait: None, @@ -139,16 +139,34 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { sugg.push_str(&snippet_with_applicability(cx.sess(), *attr_span, "_", &mut app)); sugg.push('\n'); } - } sugg }; let generics_sugg = snippet_with_applicability(cx, generics.span, "", &mut app); let where_clause_sugg = if generics.has_where_clause_predicates { - format!( - "\n{}\n", - snippet_with_applicability(cx, generics.where_clause_span, "", &mut app) - ) + let where_clause_sugg = + snippet_with_applicability(cx, generics.where_clause_span, "", &mut app).to_string(); + let mut where_clause_sugg = reindent_multiline(&where_clause_sugg, true, Some(4)); + if impl_item.generics.has_where_clause_predicates { + if !where_clause_sugg.ends_with(',') { + where_clause_sugg.push(','); + } + + let additional_where_preds = + snippet_with_applicability(cx, impl_item.generics.where_clause_span, "", &mut app); + let ident = indent_of(cx, generics.where_clause_span).unwrap_or(0); + // Remove the leading `where ` keyword + let additional_where_preds = additional_where_preds.trim_start_matches("where").trim_start(); + where_clause_sugg.push('\n'); + where_clause_sugg.extend(std::iter::repeat_n(' ', ident)); + where_clause_sugg.push_str(additional_where_preds); + } + format!("\n{where_clause_sugg}\n") + } else if impl_item.generics.has_where_clause_predicates { + let where_clause_sugg = + snippet_with_applicability(cx, impl_item.generics.where_clause_span, "", &mut app); + let where_clause_sugg = reindent_multiline(&where_clause_sugg, true, Some(4)); + format!("\n{}\n", where_clause_sugg.trim_start()) } else { String::new() }; diff --git a/clippy_lints/src/operators/cmp_owned.rs b/clippy_lints/src/operators/cmp_owned.rs index 05358de5b348..39097833a6c5 100644 --- a/clippy_lints/src/operators/cmp_owned.rs +++ b/clippy_lints/src/operators/cmp_owned.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeQPath; -use clippy_utils::source::snippet; +use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{implements_trait, is_copy}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; @@ -94,51 +94,37 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) return; } - let arg_snip = snippet(cx, arg_span, ".."); - let expr_snip; - let eq_impl; - if with_deref.is_implemented() && !arg_ty.peel_refs().is_str() { - expr_snip = format!("*{arg_snip}"); - eq_impl = with_deref; + let mut applicability = Applicability::MachineApplicable; + let (arg_snip, _) = snippet_with_context(cx, arg_span, expr.span.ctxt(), "..", &mut applicability); + let (expr_snip, eq_impl) = if with_deref.is_implemented() && !arg_ty.peel_refs().is_str() { + (format!("*{arg_snip}"), with_deref) } else { - expr_snip = arg_snip.to_string(); - eq_impl = without_deref; - } + (arg_snip.to_string(), without_deref) + }; - let span; - let hint; - if (eq_impl.ty_eq_other && left) || (eq_impl.other_eq_ty && !left) { - span = expr.span; - hint = expr_snip; + let (span, hint) = if (eq_impl.ty_eq_other && left) || (eq_impl.other_eq_ty && !left) { + (expr.span, expr_snip) } else { - span = expr.span.to(other.span); + let span = expr.span.to(other.span); let cmp_span = if other.span < expr.span { other.span.between(expr.span) } else { expr.span.between(other.span) }; - if eq_impl.ty_eq_other { - hint = format!( - "{expr_snip}{}{}", - snippet(cx, cmp_span, ".."), - snippet(cx, other.span, "..") - ); - } else { - hint = format!( - "{}{}{expr_snip}", - snippet(cx, other.span, ".."), - snippet(cx, cmp_span, "..") - ); - } - } - diag.span_suggestion( - span, - "try", - hint, - Applicability::MachineApplicable, // snippet - ); + let (cmp_snippet, _) = snippet_with_context(cx, cmp_span, expr.span.ctxt(), "..", &mut applicability); + let (other_snippet, _) = + snippet_with_context(cx, other.span, expr.span.ctxt(), "..", &mut applicability); + + if eq_impl.ty_eq_other { + (span, format!("{expr_snip}{cmp_snippet}{other_snippet}")) + } else { + (span, format!("{other_snippet}{cmp_snippet}{expr_snip}")) + } + }; + + diag.span_suggestion(span, "try", hint, applicability); }, ); } diff --git a/clippy_lints/src/operators/manual_div_ceil.rs b/clippy_lints/src/operators/manual_div_ceil.rs index 98aa47421537..5ed923d719bc 100644 --- a/clippy_lints/src/operators/manual_div_ceil.rs +++ b/clippy_lints/src/operators/manual_div_ceil.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::res::{MaybeDef, MaybeQPath}; use clippy_utils::sugg::{Sugg, has_enclosing_paren}; use clippy_utils::{SpanlessEq, sym}; use rustc_ast::{BinOpKind, LitIntType, LitKind, UnOp}; @@ -7,7 +8,7 @@ use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_middle::ty::{self}; +use rustc_middle::ty::{self, Ty}; use rustc_span::source_map::Spanned; use super::MANUAL_DIV_CEIL; @@ -16,59 +17,84 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, op: BinOpKind, lhs: & let mut applicability = Applicability::MachineApplicable; if op == BinOpKind::Div - && check_int_ty_and_feature(cx, lhs) - && check_int_ty_and_feature(cx, rhs) - && let ExprKind::Binary(inner_op, inner_lhs, inner_rhs) = lhs.kind + && check_int_ty_and_feature(cx, cx.typeck_results().expr_ty(lhs)) + && check_int_ty_and_feature(cx, cx.typeck_results().expr_ty(rhs)) && msrv.meets(cx, msrvs::DIV_CEIL) { - // (x + (y - 1)) / y - if let ExprKind::Binary(sub_op, sub_lhs, sub_rhs) = inner_rhs.kind - && inner_op.node == BinOpKind::Add - && sub_op.node == BinOpKind::Sub - && check_literal(sub_rhs) - && check_eq_expr(cx, sub_lhs, rhs) - { - build_suggestion(cx, expr, inner_lhs, rhs, &mut applicability); - return; - } + match lhs.kind { + ExprKind::Binary(inner_op, inner_lhs, inner_rhs) => { + // (x + (y - 1)) / y + if let ExprKind::Binary(sub_op, sub_lhs, sub_rhs) = inner_rhs.kind + && inner_op.node == BinOpKind::Add + && sub_op.node == BinOpKind::Sub + && check_literal(sub_rhs) + && check_eq_expr(cx, sub_lhs, rhs) + { + build_suggestion(cx, expr, inner_lhs, rhs, &mut applicability); + return; + } - // ((y - 1) + x) / y - if let ExprKind::Binary(sub_op, sub_lhs, sub_rhs) = inner_lhs.kind - && inner_op.node == BinOpKind::Add - && sub_op.node == BinOpKind::Sub - && check_literal(sub_rhs) - && check_eq_expr(cx, sub_lhs, rhs) - { - build_suggestion(cx, expr, inner_rhs, rhs, &mut applicability); - return; - } + // ((y - 1) + x) / y + if let ExprKind::Binary(sub_op, sub_lhs, sub_rhs) = inner_lhs.kind + && inner_op.node == BinOpKind::Add + && sub_op.node == BinOpKind::Sub + && check_literal(sub_rhs) + && check_eq_expr(cx, sub_lhs, rhs) + { + build_suggestion(cx, expr, inner_rhs, rhs, &mut applicability); + return; + } - // (x + y - 1) / y - if let ExprKind::Binary(add_op, add_lhs, add_rhs) = inner_lhs.kind - && inner_op.node == BinOpKind::Sub - && add_op.node == BinOpKind::Add - && check_literal(inner_rhs) - && check_eq_expr(cx, add_rhs, rhs) - { - build_suggestion(cx, expr, add_lhs, rhs, &mut applicability); - } + // (x + y - 1) / y + if let ExprKind::Binary(add_op, add_lhs, add_rhs) = inner_lhs.kind + && inner_op.node == BinOpKind::Sub + && add_op.node == BinOpKind::Add + && check_literal(inner_rhs) + && check_eq_expr(cx, add_rhs, rhs) + { + build_suggestion(cx, expr, add_lhs, rhs, &mut applicability); + } - // (x + (Y - 1)) / Y - if inner_op.node == BinOpKind::Add && differ_by_one(inner_rhs, rhs) { - build_suggestion(cx, expr, inner_lhs, rhs, &mut applicability); - } + // (x + (Y - 1)) / Y + if inner_op.node == BinOpKind::Add && differ_by_one(inner_rhs, rhs) { + build_suggestion(cx, expr, inner_lhs, rhs, &mut applicability); + } - // ((Y - 1) + x) / Y - if inner_op.node == BinOpKind::Add && differ_by_one(inner_lhs, rhs) { - build_suggestion(cx, expr, inner_rhs, rhs, &mut applicability); - } + // ((Y - 1) + x) / Y + if inner_op.node == BinOpKind::Add && differ_by_one(inner_lhs, rhs) { + build_suggestion(cx, expr, inner_rhs, rhs, &mut applicability); + } - // (x - (-Y - 1)) / Y - if inner_op.node == BinOpKind::Sub - && let ExprKind::Unary(UnOp::Neg, abs_div_rhs) = rhs.kind - && differ_by_one(abs_div_rhs, inner_rhs) - { - build_suggestion(cx, expr, inner_lhs, rhs, &mut applicability); + // (x - (-Y - 1)) / Y + if inner_op.node == BinOpKind::Sub + && let ExprKind::Unary(UnOp::Neg, abs_div_rhs) = rhs.kind + && differ_by_one(abs_div_rhs, inner_rhs) + { + build_suggestion(cx, expr, inner_lhs, rhs, &mut applicability); + } + }, + ExprKind::MethodCall(method, receiver, [next_multiple_of_arg], _) => { + // x.next_multiple_of(Y) / Y + if method.ident.name == sym::next_multiple_of + && check_int_ty(cx.typeck_results().expr_ty(receiver)) + && check_eq_expr(cx, next_multiple_of_arg, rhs) + { + build_suggestion(cx, expr, receiver, rhs, &mut applicability); + } + }, + ExprKind::Call(callee, [receiver, next_multiple_of_arg]) => { + // int_type::next_multiple_of(x, Y) / Y + if let Some(impl_ty_binder) = callee + .ty_rel_def_if_named(cx, sym::next_multiple_of) + .assoc_fn_parent(cx) + .opt_impl_ty(cx) + && check_int_ty(impl_ty_binder.skip_binder()) + && check_eq_expr(cx, next_multiple_of_arg, rhs) + { + build_suggestion(cx, expr, receiver, rhs, &mut applicability); + } + }, + _ => (), } } } @@ -91,8 +117,11 @@ fn differ_by_one(small_expr: &Expr<'_>, large_expr: &Expr<'_>) -> bool { } } -fn check_int_ty_and_feature(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - let expr_ty = cx.typeck_results().expr_ty(expr); +fn check_int_ty(expr_ty: Ty<'_>) -> bool { + matches!(expr_ty.peel_refs().kind(), ty::Int(_) | ty::Uint(_)) +} + +fn check_int_ty_and_feature(cx: &LateContext<'_>, expr_ty: Ty<'_>) -> bool { match expr_ty.peel_refs().kind() { ty::Uint(_) => true, ty::Int(_) => cx.tcx.features().enabled(sym::int_roundings), diff --git a/clippy_lints/src/operators/manual_is_multiple_of.rs b/clippy_lints/src/operators/manual_is_multiple_of.rs index 0b9bd4fb6d32..291d81097b51 100644 --- a/clippy_lints/src/operators/manual_is_multiple_of.rs +++ b/clippy_lints/src/operators/manual_is_multiple_of.rs @@ -35,7 +35,7 @@ pub(super) fn check<'tcx>( { let mut app = Applicability::MachineApplicable; let divisor = deref_sugg( - Sugg::hir_with_applicability(cx, operand_right, "_", &mut app), + Sugg::hir_with_context(cx, operand_right, expr.span.ctxt(), "_", &mut app), cx.typeck_results().expr_ty_adjusted(operand_right), ); span_lint_and_sugg( @@ -47,7 +47,7 @@ pub(super) fn check<'tcx>( format!( "{}{}.is_multiple_of({divisor})", if op == BinOpKind::Eq { "" } else { "!" }, - Sugg::hir_with_applicability(cx, operand_left, "_", &mut app).maybe_paren() + Sugg::hir_with_context(cx, operand_left, expr.span.ctxt(), "_", &mut app).maybe_paren() ), app, ); diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 59d31f782bc3..e5fb3c0fa431 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -5,7 +5,7 @@ use clippy_config::types::MatchLintBehaviour; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{implements_trait, is_copy}; use clippy_utils::usage::local_used_after_expr; @@ -147,7 +147,8 @@ fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) { && !span_contains_cfg(cx, els.span) { let mut applicability = Applicability::MaybeIncorrect; - let init_expr_str = Sugg::hir_with_applicability(cx, init_expr, "..", &mut applicability).maybe_paren(); + let init_expr_str = + Sugg::hir_with_context(cx, init_expr, stmt.span.ctxt(), "..", &mut applicability).maybe_paren(); // Take care when binding is `ref` let sugg = if let PatKind::Binding( BindingMode(ByRef::Yes(_, ref_mutability), binding_mutability), @@ -295,7 +296,7 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex && (is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block)) { let mut applicability = Applicability::MachineApplicable; - let receiver_str = snippet_with_applicability(cx, caller.span, "..", &mut applicability); + let receiver_str = snippet_with_context(cx, caller.span, expr.span.ctxt(), "..", &mut applicability).0; let by_ref = !cx.type_is_copy_modulo_regions(caller_ty) && !matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)); let sugg = if let Some(else_inner) = r#else { diff --git a/clippy_lints/src/single_range_in_vec_init.rs b/clippy_lints/src/single_range_in_vec_init.rs index 92d1b112198f..e4906eb0c777 100644 --- a/clippy_lints/src/single_range_in_vec_init.rs +++ b/clippy_lints/src/single_range_in_vec_init.rs @@ -98,7 +98,7 @@ impl LateLintPass<'_> for SingleRangeInVecInit { && snippet.starts_with(suggested_type.starts_with()) && snippet.ends_with(suggested_type.ends_with()) { - let mut applicability = Applicability::MachineApplicable; + let mut applicability = Applicability::MaybeIncorrect; let (start_snippet, _) = snippet_with_context(cx, start.expr.span, span.ctxt(), "..", &mut applicability); let (end_snippet, _) = snippet_with_context(cx, end.expr.span, span.ctxt(), "..", &mut applicability); diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 1d0efa46a14c..c0be724bcdee 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::res::{MaybeDef, MaybeQPath}; -use clippy_utils::source::{snippet, snippet_with_applicability}; +use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context}; use clippy_utils::{ SpanlessEq, get_expr_use_or_unification_node, get_parent_expr, is_lint_allowed, method_calls, peel_blocks, sym, }; @@ -273,6 +273,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { let string_expression = &expressions[0].0; let snippet_app = snippet_with_applicability(cx, string_expression.span, "..", &mut applicability); + let (right_snip, _) = snippet_with_context(cx, right.span, e.span.ctxt(), "..", &mut applicability); span_lint_and_sugg( cx, @@ -280,7 +281,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { e.span, "calling a slice of `as_bytes()` with `from_utf8` should be not necessary", "try", - format!("Some(&{snippet_app}[{}])", snippet(cx, right.span, "..")), + format!("Some(&{snippet_app}[{right_snip}])"), applicability, ); } @@ -404,7 +405,8 @@ impl<'tcx> LateLintPass<'tcx> for StrToString { "`to_string()` called on a `&str`", |diag| { let mut applicability = Applicability::MachineApplicable; - let snippet = snippet_with_applicability(cx, self_arg.span, "..", &mut applicability); + let (snippet, _) = + snippet_with_context(cx, self_arg.span, expr.span.ctxt(), "..", &mut applicability); diag.span_suggestion(expr.span, "try", format!("{snippet}.to_owned()"), applicability); }, ); diff --git a/clippy_lints/src/strlen_on_c_strings.rs b/clippy_lints/src/strlen_on_c_strings.rs index 58d692db5029..0d50bd547652 100644 --- a/clippy_lints/src/strlen_on_c_strings.rs +++ b/clippy_lints/src/strlen_on_c_strings.rs @@ -14,8 +14,8 @@ declare_clippy_lint! { /// and suggest calling `as_bytes().len()` or `to_bytes().len()` respectively instead. /// /// ### Why is this bad? - /// This avoids calling an unsafe `libc` function. - /// Currently, it also avoids calculating the length. + /// libc::strlen is an unsafe function, which we don't need to call + /// if all we want to know is the length of the c-string. /// /// ### Example /// ```rust, ignore diff --git a/clippy_lints/src/transmute/transmuting_null.rs b/clippy_lints/src/transmute/transmuting_null.rs index 31e770f421e1..3f435f255d91 100644 --- a/clippy_lints/src/transmute/transmuting_null.rs +++ b/clippy_lints/src/transmute/transmuting_null.rs @@ -2,7 +2,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_integer_const; use clippy_utils::res::{MaybeDef, MaybeResPath}; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{ConstBlock, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::Ty; use rustc_span::symbol::sym; @@ -42,5 +42,23 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t return true; } + // Catching: + // `std::mem::transmute({ 0 as *const u64 })` and similar const blocks + if let ExprKind::Block(block, _) = arg.kind + && block.stmts.is_empty() + && let Some(inner) = block.expr + { + // Run again with the inner expression + return check(cx, expr, inner, to_ty); + } + + // Catching: + // `std::mem::transmute(const { u64::MIN as *const u64 });` + if let ExprKind::ConstBlock(ConstBlock { body, .. }) = arg.kind { + // Strip out the const and run again + let block = cx.tcx.hir_body(body).value; + return check(cx, expr, block, to_ty); + } + false } diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index c06313d1a4c4..423301edfe83 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -456,13 +456,25 @@ fn has_eligible_receiver(cx: &LateContext<'_>, recv: &Expr<'_>, expr: &Expr<'_>) fn adjustments(cx: &LateContext<'_>, expr: &Expr<'_>) -> String { let mut prefix = String::new(); - for adj in cx.typeck_results().expr_adjustments(expr) { + + let adjustments = cx.typeck_results().expr_adjustments(expr); + + let [.., last] = adjustments else { return prefix }; + let target = last.target; + + for adj in adjustments { match adj.kind { Adjust::Deref(_) => prefix = format!("*{prefix}"), Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Mut { .. })) => prefix = format!("&mut {prefix}"), Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Not)) => prefix = format!("&{prefix}"), _ => {}, } + + // Stop once we reach the final target type. + // This prevents over-adjusting (e.g. suggesting &**y instead of *y). + if adj.target == target { + break; + } } prefix } diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 7a54ba7a8fe1..58b153f06545 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -321,7 +321,6 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { }, ConstArgKind::Struct(..) => chain!(self, "let ConstArgKind::Struct(..) = {const_arg}.kind"), ConstArgKind::TupleCall(..) => chain!(self, "let ConstArgKind::TupleCall(..) = {const_arg}.kind"), - ConstArgKind::Tup(..) => chain!(self, "let ConstArgKind::Tup(..) = {const_arg}.kind"), ConstArgKind::Infer(..) => chain!(self, "let ConstArgKind::Infer(..) = {const_arg}.kind"), ConstArgKind::Error(..) => chain!(self, "let ConstArgKind::Error(..) = {const_arg}.kind"), ConstArgKind::Literal(..) => chain!(self, "let ConstArgKind::Literal(..) = {const_arg}.kind") diff --git a/clippy_lints_internal/src/lint_without_lint_pass.rs b/clippy_lints_internal/src/lint_without_lint_pass.rs index fda65bc84eda..f56b6f31550b 100644 --- a/clippy_lints_internal/src/lint_without_lint_pass.rs +++ b/clippy_lints_internal/src/lint_without_lint_pass.rs @@ -250,8 +250,8 @@ pub(super) fn extract_clippy_version_value(cx: &LateContext<'_>, item: &'_ Item< if let hir::Attribute::Unparsed(attr_kind) = &attr // Identify attribute && let [tool_name, attr_name] = &attr_kind.path.segments[..] - && tool_name.name == sym::clippy - && attr_name.name == sym::version + && tool_name == &sym::clippy + && attr_name == &sym::version && let Some(version) = attr.value_str() { Some(version) diff --git a/clippy_utils/README.md b/clippy_utils/README.md index 01257c1a3059..ecd36b157571 100644 --- a/clippy_utils/README.md +++ b/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: ``` -nightly-2025-12-25 +nightly-2026-01-08 ``` @@ -30,7 +30,7 @@ Function signatures can change or be removed without replacement without any pri -Copyright 2014-2025 The Rust Project Developers +Copyright (c) The Rust Project Contributors Licensed under the Apache License, Version 2.0 <[https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license diff --git a/clippy_utils/src/ast_utils/mod.rs b/clippy_utils/src/ast_utils/mod.rs index 618719286e8f..cf8716398efb 100644 --- a/clippy_utils/src/ast_utils/mod.rs +++ b/clippy_utils/src/ast_utils/mod.rs @@ -976,7 +976,9 @@ pub fn eq_attr(l: &Attribute, r: &Attribute) -> bool { l.style == r.style && match (&l.kind, &r.kind) { (DocComment(l1, l2), DocComment(r1, r2)) => l1 == r1 && l2 == r2, - (Normal(l), Normal(r)) => eq_path(&l.item.path, &r.item.path) && eq_attr_item_kind(&l.item.args, &r.item.args), + (Normal(l), Normal(r)) => { + eq_path(&l.item.path, &r.item.path) && eq_attr_item_kind(&l.item.args, &r.item.args) + }, _ => false, } } diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 87fdd755908b..32f6cb4fd5e9 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -23,7 +23,9 @@ pub fn get_builtin_attr<'a, A: AttributeExt + 'a>( if let [clippy, segment2] = &*attr.path() && *clippy == sym::clippy { - let path_span = attr.path_span().expect("Clippy attributes are unparsed and have a span"); + let path_span = attr + .path_span() + .expect("Clippy attributes are unparsed and have a span"); let new_name = match *segment2 { sym::cyclomatic_complexity => Some("cognitive_complexity"), sym::author @@ -48,7 +50,7 @@ pub fn get_builtin_attr<'a, A: AttributeExt + 'a>( .with_span_suggestion( path_span, "consider using", - format!("clippy::{}", new_name), + format!("clippy::{new_name}"), Applicability::MachineApplicable, ) .emit(); diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 5f4b87590dc1..334cc6bb5d55 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -1140,9 +1140,11 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx ConstItemRhs::Body(body_id) => Some(tcx.hir_body(body_id).value), ConstItemRhs::TypeConst(const_arg) => match const_arg.kind { ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value), - ConstArgKind::Struct(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Tup(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) | ConstArgKind::Literal(..) => { - None - }, + ConstArgKind::Struct(..) + | ConstArgKind::TupleCall(..) + | ConstArgKind::Path(_) + | ConstArgKind::Error(..) + | ConstArgKind::Infer(..) => None, }, } } diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index b4e483ea8072..73b1cbb21548 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -675,7 +675,7 @@ impl HirEqInterExpr<'_, '_, '_> { .iter() .zip(*inits_b) .all(|(init_a, init_b)| self.eq_const_arg(init_a.expr, init_b.expr)) - } + }, (ConstArgKind::TupleCall(path_a, args_a), ConstArgKind::TupleCall(path_b, args_b)) => { self.eq_qpath(path_a, path_b) && args_a @@ -688,7 +688,7 @@ impl HirEqInterExpr<'_, '_, '_> { .iter() .zip(*args_b) .all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b)) - } + }, (ConstArgKind::Literal(kind_l), ConstArgKind::Literal(kind_r)) => { kind_l == kind_r }, diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 38e1542cd758..2a620e917228 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -90,13 +90,13 @@ use std::sync::{Mutex, MutexGuard, OnceLock}; use itertools::Itertools; use rustc_abi::Integer; use rustc_ast::ast::{self, LitKind, RangeLimits}; -use rustc_ast::join_path_syms; +use rustc_ast::{LitIntType, join_path_syms}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexmap; use rustc_data_structures::packed::Pu128; use rustc_data_structures::unhash::UnindexMap; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; -use rustc_hir::attrs::AttributeKind; +use rustc_hir::attrs::{AttributeKind, CfgEntry}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::definitions::{DefPath, DefPathData}; @@ -121,7 +121,6 @@ use rustc_middle::ty::{ self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, GenericArgKind, GenericArgsRef, IntTy, Ty, TyCtxt, TypeFlags, TypeVisitableExt, UintTy, UpvarCapture, }; -use rustc_hir::attrs::CfgEntry; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{Ident, Symbol, kw}; @@ -1386,6 +1385,17 @@ pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool { false } +/// Checks whether the given expression is an untyped integer literal. +pub fn is_integer_literal_untyped(expr: &Expr<'_>) -> bool { + if let ExprKind::Lit(spanned) = expr.kind + && let LitKind::Int(_, suffix) = spanned.node + { + return suffix == LitIntType::Unsuffixed; + } + + false +} + /// Checks whether the given expression is a constant literal of the given value. pub fn is_float_literal(expr: &Expr<'_>, value: f64) -> bool { if let ExprKind::Lit(spanned) = expr.kind @@ -2403,7 +2413,10 @@ pub fn is_test_function(tcx: TyCtxt<'_>, fn_def_id: LocalDefId) -> bool { /// use [`is_in_cfg_test`] pub fn is_cfg_test(tcx: TyCtxt<'_>, id: HirId) -> bool { if let Some(cfgs) = find_attr!(tcx.hir_attrs(id), AttributeKind::CfgTrace(cfgs) => cfgs) - && cfgs.iter().any(|(cfg, _)| { matches!(cfg, CfgEntry::NameValue { name: sym::test, ..})}) { + && cfgs + .iter() + .any(|(cfg, _)| matches!(cfg, CfgEntry::NameValue { name: sym::test, .. })) + { true } else { false @@ -2423,9 +2436,11 @@ pub fn is_in_test(tcx: TyCtxt<'_>, hir_id: HirId) -> bool { /// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied. pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { find_attr!(tcx.get_all_attrs(def_id), AttributeKind::CfgTrace(..)) - || find_attr!(tcx - .hir_parent_iter(tcx.local_def_id_to_hir_id(def_id)) - .flat_map(|(parent_id, _)| tcx.hir_attrs(parent_id)), AttributeKind::CfgTrace(..)) + || find_attr!( + tcx.hir_parent_iter(tcx.local_def_id_to_hir_id(def_id)) + .flat_map(|(parent_id, _)| tcx.hir_attrs(parent_id)), + AttributeKind::CfgTrace(..) + ) } /// Walks up the HIR tree from the given expression in an attempt to find where the value is diff --git a/clippy_utils/src/res.rs b/clippy_utils/src/res.rs index a3efece7d224..e890a73620a5 100644 --- a/clippy_utils/src/res.rs +++ b/clippy_utils/src/res.rs @@ -301,7 +301,7 @@ impl<'tcx> MaybeQPath<'tcx> for &'tcx PatExpr<'_> { fn opt_qpath(self) -> Option> { match &self.kind { PatExprKind::Path(qpath) => Some((qpath, self.hir_id)), - _ => None, + PatExprKind::Lit { .. } => None, } } } @@ -419,7 +419,7 @@ impl<'a> MaybeResPath<'a> for &PatExpr<'a> { fn opt_res_path(self) -> OptResPath<'a> { match &self.kind { PatExprKind::Path(qpath) => qpath.opt_res_path(), - _ => (None, None), + PatExprKind::Lit { .. } => (None, None), } } } diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index 2ef2afb45071..3ade38bea8ed 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -127,7 +127,7 @@ impl<'a> Sugg<'a> { /// Generate a suggestion for an expression with the given snippet. This is used by the `hir_*` /// function variants of `Sugg`, since these use different snippet functions. - fn hir_from_snippet( + pub fn hir_from_snippet( cx: &LateContext<'_>, expr: &hir::Expr<'_>, mut get_snippet: impl FnMut(Span) -> Cow<'a, str>, diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index a0d2e8673fe6..5357a0941d32 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -248,6 +248,7 @@ generate! { next_back, next_if, next_if_eq, + next_multiple_of, next_tuple, nth, ok, diff --git a/rust-toolchain.toml b/rust-toolchain.toml index dbec79e111fb..0755e1d29c69 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2025-12-25" +channel = "nightly-2026-01-08" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" diff --git a/rustc_tools_util/README.md b/rustc_tools_util/README.md index f47a4c69c2c3..45d2844ad00b 100644 --- a/rustc_tools_util/README.md +++ b/rustc_tools_util/README.md @@ -51,7 +51,7 @@ The changelog for `rustc_tools_util` is available under: -Copyright 2014-2025 The Rust Project Developers +Copyright (c) The Rust Project Contributors Licensed under the Apache License, Version 2.0 or the MIT license diff --git a/tests/ui-toml/missing_enforced_import_rename/clippy.toml b/tests/ui-toml/missing_enforced_import_rename/clippy.toml index 05ba822874d5..11af5b0a3306 100644 --- a/tests/ui-toml/missing_enforced_import_rename/clippy.toml +++ b/tests/ui-toml/missing_enforced_import_rename/clippy.toml @@ -6,5 +6,6 @@ enforced-import-renames = [ { path = "std::clone", rename = "foo" }, { path = "std::thread::sleep", rename = "thread_sleep" }, { path = "std::any::type_name", rename = "ident" }, - { path = "std::sync::Mutex", rename = "StdMutie" } + { path = "std::sync::Mutex", rename = "StdMutie" }, + { path = "std::io::Write", rename = "to_test_rename_as_underscore" } ] diff --git a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed index 3e882f496985..c96df2884b8d 100644 --- a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed +++ b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed @@ -15,6 +15,7 @@ use std::{ sync :: Mutex as StdMutie, //~^ missing_enforced_import_renames }; +use std::io::Write as _; fn main() { use std::collections::BTreeMap as Map; diff --git a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs index 32255af5117f..662e89157675 100644 --- a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs +++ b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs @@ -15,6 +15,7 @@ use std::{ sync :: Mutex, //~^ missing_enforced_import_renames }; +use std::io::Write as _; fn main() { use std::collections::BTreeMap as OopsWrongRename; diff --git a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr index 982b144eb872..139331d17619 100644 --- a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr +++ b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr @@ -32,7 +32,7 @@ LL | sync :: Mutex, | ^^^^^^^^^^^^^ help: try: `sync :: Mutex as StdMutie` error: this import should be renamed - --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:20:5 + --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:21:5 | LL | use std::collections::BTreeMap as OopsWrongRename; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `use std::collections::BTreeMap as Map` diff --git a/tests/ui/bool_assert_comparison.fixed b/tests/ui/bool_assert_comparison.fixed index ec76abbef05a..cd390ce0db9d 100644 --- a/tests/ui/bool_assert_comparison.fixed +++ b/tests/ui/bool_assert_comparison.fixed @@ -216,3 +216,16 @@ fn main() { assert!(!(b + b)); //~^ bool_assert_comparison } + +fn issue16279() { + macro_rules! is_empty { + ($x:expr) => { + $x.is_empty() + }; + } + + assert!(!is_empty!("a")); + //~^ bool_assert_comparison + assert!(is_empty!("")); + //~^ bool_assert_comparison +} diff --git a/tests/ui/bool_assert_comparison.rs b/tests/ui/bool_assert_comparison.rs index 40824a23c82e..b2ea5b6ea540 100644 --- a/tests/ui/bool_assert_comparison.rs +++ b/tests/ui/bool_assert_comparison.rs @@ -216,3 +216,16 @@ fn main() { assert_eq!(b + b, false); //~^ bool_assert_comparison } + +fn issue16279() { + macro_rules! is_empty { + ($x:expr) => { + $x.is_empty() + }; + } + + assert_eq!(is_empty!("a"), false); + //~^ bool_assert_comparison + assert_eq!(is_empty!(""), true); + //~^ bool_assert_comparison +} diff --git a/tests/ui/bool_assert_comparison.stderr b/tests/ui/bool_assert_comparison.stderr index 72aa6303a202..b4e8fcf09bb6 100644 --- a/tests/ui/bool_assert_comparison.stderr +++ b/tests/ui/bool_assert_comparison.stderr @@ -444,5 +444,29 @@ LL - assert_eq!(b + b, false); LL + assert!(!(b + b)); | -error: aborting due to 37 previous errors +error: used `assert_eq!` with a literal bool + --> tests/ui/bool_assert_comparison.rs:227:5 + | +LL | assert_eq!(is_empty!("a"), false); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert!(..)` + | +LL - assert_eq!(is_empty!("a"), false); +LL + assert!(!is_empty!("a")); + | + +error: used `assert_eq!` with a literal bool + --> tests/ui/bool_assert_comparison.rs:229:5 + | +LL | assert_eq!(is_empty!(""), true); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert!(..)` + | +LL - assert_eq!(is_empty!(""), true); +LL + assert!(is_empty!("")); + | + +error: aborting due to 39 previous errors diff --git a/tests/ui/checked_conversions.fixed b/tests/ui/checked_conversions.fixed index 6175275ef047..2309a053146f 100644 --- a/tests/ui/checked_conversions.fixed +++ b/tests/ui/checked_conversions.fixed @@ -1,6 +1,7 @@ #![allow( clippy::cast_lossless, clippy::legacy_numeric_constants, + clippy::no_effect, unused, // Int::max_value will be deprecated in the future deprecated, @@ -105,4 +106,19 @@ fn msrv_1_34() { //~^ checked_conversions } +fn issue16293() { + struct Outer { + inner: u32, + } + let outer = Outer { inner: 42 }; + macro_rules! dot_inner { + ($obj:expr) => { + $obj.inner + }; + } + + i32::try_from(dot_inner!(outer)).is_ok(); + //~^ checked_conversions +} + fn main() {} diff --git a/tests/ui/checked_conversions.rs b/tests/ui/checked_conversions.rs index 9ed0e8f660d0..dabb552eba27 100644 --- a/tests/ui/checked_conversions.rs +++ b/tests/ui/checked_conversions.rs @@ -1,6 +1,7 @@ #![allow( clippy::cast_lossless, clippy::legacy_numeric_constants, + clippy::no_effect, unused, // Int::max_value will be deprecated in the future deprecated, @@ -105,4 +106,19 @@ fn msrv_1_34() { //~^ checked_conversions } +fn issue16293() { + struct Outer { + inner: u32, + } + let outer = Outer { inner: 42 }; + macro_rules! dot_inner { + ($obj:expr) => { + $obj.inner + }; + } + + dot_inner!(outer) <= i32::MAX as u32; + //~^ checked_conversions +} + fn main() {} diff --git a/tests/ui/checked_conversions.stderr b/tests/ui/checked_conversions.stderr index 624876dacb26..6018dacace39 100644 --- a/tests/ui/checked_conversions.stderr +++ b/tests/ui/checked_conversions.stderr @@ -1,5 +1,5 @@ error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:15:13 + --> tests/ui/checked_conversions.rs:16:13 | LL | let _ = value <= (u32::max_value() as i64) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()` @@ -8,100 +8,106 @@ LL | let _ = value <= (u32::max_value() as i64) && value >= 0; = help: to override `-D warnings` add `#[allow(clippy::checked_conversions)]` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:17:13 + --> tests/ui/checked_conversions.rs:18:13 | LL | let _ = value <= (u32::MAX as i64) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:22:13 + --> tests/ui/checked_conversions.rs:23:13 | LL | let _ = value <= i64::from(u16::max_value()) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:24:13 + --> tests/ui/checked_conversions.rs:25:13 | LL | let _ = value <= i64::from(u16::MAX) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:29:13 + --> tests/ui/checked_conversions.rs:30:13 | LL | let _ = value <= (u8::max_value() as isize) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:31:13 + --> tests/ui/checked_conversions.rs:32:13 | LL | let _ = value <= (u8::MAX as isize) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:38:13 + --> tests/ui/checked_conversions.rs:39:13 | LL | let _ = value <= (i32::max_value() as i64) && value >= (i32::min_value() as i64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:40:13 + --> tests/ui/checked_conversions.rs:41:13 | LL | let _ = value <= (i32::MAX as i64) && value >= (i32::MIN as i64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:45:13 + --> tests/ui/checked_conversions.rs:46:13 | LL | let _ = value <= i64::from(i16::max_value()) && value >= i64::from(i16::min_value()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:47:13 + --> tests/ui/checked_conversions.rs:48:13 | LL | let _ = value <= i64::from(i16::MAX) && value >= i64::from(i16::MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:54:13 + --> tests/ui/checked_conversions.rs:55:13 | LL | let _ = value <= i32::max_value() as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:56:13 + --> tests/ui/checked_conversions.rs:57:13 | LL | let _ = value <= i32::MAX as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:61:13 + --> tests/ui/checked_conversions.rs:62:13 | LL | let _ = value <= isize::max_value() as usize && value as i32 == 5; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:63:13 + --> tests/ui/checked_conversions.rs:64:13 | LL | let _ = value <= isize::MAX as usize && value as i32 == 5; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:68:13 + --> tests/ui/checked_conversions.rs:69:13 | LL | let _ = value <= u16::max_value() as u32 && value as i32 == 5; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:70:13 + --> tests/ui/checked_conversions.rs:71:13 | LL | let _ = value <= u16::MAX as u32 && value as i32 == 5; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:104:13 + --> tests/ui/checked_conversions.rs:105:13 | LL | let _ = value <= (u32::max_value() as i64) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()` -error: aborting due to 17 previous errors +error: checked cast can be simplified + --> tests/ui/checked_conversions.rs:120:5 + | +LL | dot_inner!(outer) <= i32::MAX as u32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(dot_inner!(outer)).is_ok()` + +error: aborting due to 18 previous errors diff --git a/tests/ui/cmp_owned/with_suggestion.fixed b/tests/ui/cmp_owned/with_suggestion.fixed index 85d0991bef05..4c3b13b30043 100644 --- a/tests/ui/cmp_owned/with_suggestion.fixed +++ b/tests/ui/cmp_owned/with_suggestion.fixed @@ -83,3 +83,32 @@ fn issue_8103() { let _ = foo1 == foo2; //~^ cmp_owned } + +macro_rules! issue16322_macro_generator { + ($locale:ident) => { + mod $locale { + macro_rules! _make { + ($token:tt) => { + stringify!($token) + }; + } + + pub(crate) use _make; + } + + macro_rules! t { + ($token:tt) => { + crate::$locale::_make!($token) + }; + } + }; +} + +issue16322_macro_generator!(de); + +fn issue16322(item: String) { + if item == t!(frohes_neu_Jahr) { + //~^ cmp_owned + println!("Ja!"); + } +} diff --git a/tests/ui/cmp_owned/with_suggestion.rs b/tests/ui/cmp_owned/with_suggestion.rs index 2393757d76f2..a9d7509feaaf 100644 --- a/tests/ui/cmp_owned/with_suggestion.rs +++ b/tests/ui/cmp_owned/with_suggestion.rs @@ -83,3 +83,32 @@ fn issue_8103() { let _ = foo1 == foo2.to_owned(); //~^ cmp_owned } + +macro_rules! issue16322_macro_generator { + ($locale:ident) => { + mod $locale { + macro_rules! _make { + ($token:tt) => { + stringify!($token) + }; + } + + pub(crate) use _make; + } + + macro_rules! t { + ($token:tt) => { + crate::$locale::_make!($token) + }; + } + }; +} + +issue16322_macro_generator!(de); + +fn issue16322(item: String) { + if item == t!(frohes_neu_Jahr).to_string() { + //~^ cmp_owned + println!("Ja!"); + } +} diff --git a/tests/ui/cmp_owned/with_suggestion.stderr b/tests/ui/cmp_owned/with_suggestion.stderr index dd9ffa70897a..66544ce0c217 100644 --- a/tests/ui/cmp_owned/with_suggestion.stderr +++ b/tests/ui/cmp_owned/with_suggestion.stderr @@ -49,5 +49,11 @@ error: this creates an owned instance just for comparison LL | let _ = foo1 == foo2.to_owned(); | ^^^^^^^^^^^^^^^ help: try: `foo2` -error: aborting due to 8 previous errors +error: this creates an owned instance just for comparison + --> tests/ui/cmp_owned/with_suggestion.rs:110:16 + | +LL | if item == t!(frohes_neu_Jahr).to_string() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t!(frohes_neu_Jahr)` + +error: aborting due to 9 previous errors diff --git a/tests/ui/derive_ord_xor_partial_ord.rs b/tests/ui/derive_ord_xor_partial_ord.rs index b4bb24b0d2fe..386ab39401c5 100644 --- a/tests/ui/derive_ord_xor_partial_ord.rs +++ b/tests/ui/derive_ord_xor_partial_ord.rs @@ -91,3 +91,17 @@ mod issue15708 { } } } + +mod issue16298 { + #[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)] + struct Normalized(S); + + impl Eq for Normalized {} + + #[expect(clippy::derive_ord_xor_partial_ord)] + impl Ord for Normalized { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.partial_cmp(other).unwrap() + } + } +} diff --git a/tests/ui/double_parens.fixed b/tests/ui/double_parens.fixed index 024af6840132..ef7838491f8f 100644 --- a/tests/ui/double_parens.fixed +++ b/tests/ui/double_parens.fixed @@ -161,4 +161,20 @@ fn issue15940() { pub struct Person; } +fn issue16224() { + fn test() -> i32 { 42 } + + macro_rules! call { + ($matcher:pat $(=> $result:expr)?) => { + match test() { + $matcher => Result::Ok(($($result),*)), + _ => Result::Err("No match".to_string()), + } + }; + } + + let _: Result<(), String> = call!(_); + let _: Result = call!(_ => 42); +} + fn main() {} diff --git a/tests/ui/double_parens.rs b/tests/ui/double_parens.rs index 8a76f2837f35..07eafdf69575 100644 --- a/tests/ui/double_parens.rs +++ b/tests/ui/double_parens.rs @@ -161,4 +161,20 @@ fn issue15940() { pub struct Person; } +fn issue16224() { + fn test() -> i32 { 42 } + + macro_rules! call { + ($matcher:pat $(=> $result:expr)?) => { + match test() { + $matcher => Result::Ok(($($result),*)), + _ => Result::Err("No match".to_string()), + } + }; + } + + let _: Result<(), String> = call!(_); + let _: Result = call!(_ => 42); +} + fn main() {} diff --git a/tests/ui/for_kv_map.fixed b/tests/ui/for_kv_map.fixed index 2a68b7443fbf..6ec4cb01ffd1 100644 --- a/tests/ui/for_kv_map.fixed +++ b/tests/ui/for_kv_map.fixed @@ -69,3 +69,20 @@ fn main() { let _v = v; } } + +fn wrongly_unmangled_macros() { + use std::collections::HashMap; + + macro_rules! test_map { + ($val:expr) => { + &*$val + }; + } + + let m: HashMap = HashMap::new(); + let wrapped = Rc::new(m); + for v in test_map!(wrapped).values() { + //~^ for_kv_map + let _v = v; + } +} diff --git a/tests/ui/for_kv_map.rs b/tests/ui/for_kv_map.rs index 485a97815e3c..19e907ff10a6 100644 --- a/tests/ui/for_kv_map.rs +++ b/tests/ui/for_kv_map.rs @@ -69,3 +69,20 @@ fn main() { let _v = v; } } + +fn wrongly_unmangled_macros() { + use std::collections::HashMap; + + macro_rules! test_map { + ($val:expr) => { + &*$val + }; + } + + let m: HashMap = HashMap::new(); + let wrapped = Rc::new(m); + for (_, v) in test_map!(wrapped) { + //~^ for_kv_map + let _v = v; + } +} diff --git a/tests/ui/for_kv_map.stderr b/tests/ui/for_kv_map.stderr index 0bd474a10682..5436592f2ab6 100644 --- a/tests/ui/for_kv_map.stderr +++ b/tests/ui/for_kv_map.stderr @@ -72,5 +72,17 @@ LL - 'label: for (k, _value) in rm { LL + 'label: for k in rm.keys() { | -error: aborting due to 6 previous errors +error: you seem to want to iterate on a map's values + --> tests/ui/for_kv_map.rs:84:19 + | +LL | for (_, v) in test_map!(wrapped) { + | ^^^^^^^^^^^^^^^^^^ + | +help: use the corresponding method + | +LL - for (_, v) in test_map!(wrapped) { +LL + for v in test_map!(wrapped).values() { + | + +error: aborting due to 7 previous errors diff --git a/tests/ui/impl.rs b/tests/ui/impl.rs index e6044cc50781..75761a34c86e 100644 --- a/tests/ui/impl.rs +++ b/tests/ui/impl.rs @@ -14,6 +14,7 @@ impl MyStruct { } impl<'a> MyStruct { + //~^ multiple_inherent_impl fn lifetimed() {} } @@ -90,10 +91,12 @@ struct Lifetime<'s> { } impl Lifetime<'_> {} -impl Lifetime<'_> {} // false negative +impl Lifetime<'_> {} +//~^ multiple_inherent_impl impl<'a> Lifetime<'a> {} -impl<'a> Lifetime<'a> {} // false negative +impl<'a> Lifetime<'a> {} +//~^ multiple_inherent_impl impl<'b> Lifetime<'b> {} // false negative? @@ -104,6 +107,39 @@ struct Generic { } impl Generic {} -impl Generic {} // false negative +impl Generic {} +//~^ multiple_inherent_impl + +use std::fmt::Debug; + +#[derive(Debug)] +struct GenericWithBounds(T); + +impl GenericWithBounds { + fn make_one(_one: T) -> Self { + todo!() + } +} + +impl GenericWithBounds { + //~^ multiple_inherent_impl + fn make_two(_two: T) -> Self { + todo!() + } +} + +struct MultipleTraitBounds(T); + +impl MultipleTraitBounds { + fn debug_fn() {} +} + +impl MultipleTraitBounds { + fn clone_fn() {} +} + +impl MultipleTraitBounds { + fn debug_clone_fn() {} +} fn main() {} diff --git a/tests/ui/impl.stderr b/tests/ui/impl.stderr index 93d4b3998f90..9c4aaf183d70 100644 --- a/tests/ui/impl.stderr +++ b/tests/ui/impl.stderr @@ -19,7 +19,24 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::multiple_inherent_impl)]` error: multiple implementations of this structure - --> tests/ui/impl.rs:26:5 + --> tests/ui/impl.rs:16:1 + | +LL | / impl<'a> MyStruct { +LL | | +LL | | fn lifetimed() {} +LL | | } + | |_^ + | +note: first implementation here + --> tests/ui/impl.rs:6:1 + | +LL | / impl MyStruct { +LL | | fn first() {} +LL | | } + | |_^ + +error: multiple implementations of this structure + --> tests/ui/impl.rs:27:5 | LL | / impl super::MyStruct { LL | | @@ -37,7 +54,7 @@ LL | | } | |_^ error: multiple implementations of this structure - --> tests/ui/impl.rs:48:1 + --> tests/ui/impl.rs:49:1 | LL | / impl WithArgs { LL | | @@ -47,7 +64,7 @@ LL | | } | |_^ | note: first implementation here - --> tests/ui/impl.rs:45:1 + --> tests/ui/impl.rs:46:1 | LL | / impl WithArgs { LL | | fn f2() {} @@ -55,28 +72,85 @@ LL | | } | |_^ error: multiple implementations of this structure - --> tests/ui/impl.rs:71:1 + --> tests/ui/impl.rs:72:1 | LL | impl OneAllowedImpl {} | ^^^^^^^^^^^^^^^^^^^^^^ | note: first implementation here - --> tests/ui/impl.rs:68:1 + --> tests/ui/impl.rs:69:1 | LL | impl OneAllowedImpl {} | ^^^^^^^^^^^^^^^^^^^^^^ error: multiple implementations of this structure - --> tests/ui/impl.rs:84:1 + --> tests/ui/impl.rs:85:1 | LL | impl OneExpected {} | ^^^^^^^^^^^^^^^^^^^ | note: first implementation here - --> tests/ui/impl.rs:81:1 + --> tests/ui/impl.rs:82:1 | LL | impl OneExpected {} | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 5 previous errors +error: multiple implementations of this structure + --> tests/ui/impl.rs:94:1 + | +LL | impl Lifetime<'_> {} + | ^^^^^^^^^^^^^^^^^^^^ + | +note: first implementation here + --> tests/ui/impl.rs:93:1 + | +LL | impl Lifetime<'_> {} + | ^^^^^^^^^^^^^^^^^^^^ + +error: multiple implementations of this structure + --> tests/ui/impl.rs:98:1 + | +LL | impl<'a> Lifetime<'a> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first implementation here + --> tests/ui/impl.rs:97:1 + | +LL | impl<'a> Lifetime<'a> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: multiple implementations of this structure + --> tests/ui/impl.rs:110:1 + | +LL | impl Generic {} + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: first implementation here + --> tests/ui/impl.rs:109:1 + | +LL | impl Generic {} + | ^^^^^^^^^^^^^^^^^^^^^ + +error: multiple implementations of this structure + --> tests/ui/impl.rs:124:1 + | +LL | / impl GenericWithBounds { +LL | | +LL | | fn make_two(_two: T) -> Self { +LL | | todo!() +LL | | } +LL | | } + | |_^ + | +note: first implementation here + --> tests/ui/impl.rs:118:1 + | +LL | / impl GenericWithBounds { +LL | | fn make_one(_one: T) -> Self { +LL | | todo!() +LL | | } +LL | | } + | |_^ + +error: aborting due to 10 previous errors diff --git a/tests/ui/implicit_saturating_sub.fixed b/tests/ui/implicit_saturating_sub.fixed index 1aab6c54407e..22e59bbd2705 100644 --- a/tests/ui/implicit_saturating_sub.fixed +++ b/tests/ui/implicit_saturating_sub.fixed @@ -252,3 +252,11 @@ fn arbitrary_expression() { 0 }; } + +fn issue16307() { + let x: u8 = 100; + let y = 100_u8.saturating_sub(x); + //~^ implicit_saturating_sub + + println!("{y}"); +} diff --git a/tests/ui/implicit_saturating_sub.rs b/tests/ui/implicit_saturating_sub.rs index 7ca57a2902db..7fa19f0c8ad2 100644 --- a/tests/ui/implicit_saturating_sub.rs +++ b/tests/ui/implicit_saturating_sub.rs @@ -326,3 +326,11 @@ fn arbitrary_expression() { 0 }; } + +fn issue16307() { + let x: u8 = 100; + let y = if x >= 100 { 0 } else { 100 - x }; + //~^ implicit_saturating_sub + + println!("{y}"); +} diff --git a/tests/ui/implicit_saturating_sub.stderr b/tests/ui/implicit_saturating_sub.stderr index 0c225856fd07..2f3d2ba787e8 100644 --- a/tests/ui/implicit_saturating_sub.stderr +++ b/tests/ui/implicit_saturating_sub.stderr @@ -238,5 +238,11 @@ error: manual arithmetic check found LL | let _ = if a < b * 2 { 0 } else { a - b * 2 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.saturating_sub(b * 2)` -error: aborting due to 27 previous errors +error: manual arithmetic check found + --> tests/ui/implicit_saturating_sub.rs:332:13 + | +LL | let y = if x >= 100 { 0 } else { 100 - x }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `100_u8.saturating_sub(x)` + +error: aborting due to 28 previous errors diff --git a/tests/ui/iter_kv_map.fixed b/tests/ui/iter_kv_map.fixed index b18dda358877..189d76bc9431 100644 --- a/tests/ui/iter_kv_map.fixed +++ b/tests/ui/iter_kv_map.fixed @@ -189,3 +189,9 @@ fn issue14595() { let _ = map.as_ref().values().copied().collect::>(); //~^ iter_kv_map } + +fn issue16340() { + let hm: HashMap<&str, &str> = HashMap::new(); + let _ = hm.keys().map(|key| vec![key]); + //~^ iter_kv_map +} diff --git a/tests/ui/iter_kv_map.rs b/tests/ui/iter_kv_map.rs index 729e4e8a266c..cfc303447004 100644 --- a/tests/ui/iter_kv_map.rs +++ b/tests/ui/iter_kv_map.rs @@ -193,3 +193,9 @@ fn issue14595() { let _ = map.as_ref().iter().map(|(_, v)| v).copied().collect::>(); //~^ iter_kv_map } + +fn issue16340() { + let hm: HashMap<&str, &str> = HashMap::new(); + let _ = hm.iter().map(|(key, _)| vec![key]); + //~^ iter_kv_map +} diff --git a/tests/ui/iter_kv_map.stderr b/tests/ui/iter_kv_map.stderr index 8f73541f5033..866e69ea1922 100644 --- a/tests/ui/iter_kv_map.stderr +++ b/tests/ui/iter_kv_map.stderr @@ -269,5 +269,11 @@ error: iterating on a map's values LL | let _ = map.as_ref().iter().map(|(_, v)| v).copied().collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.as_ref().values()` -error: aborting due to 39 previous errors +error: iterating on a map's keys + --> tests/ui/iter_kv_map.rs:199:13 + | +LL | let _ = hm.iter().map(|(key, _)| vec![key]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hm.keys().map(|key| vec![key])` + +error: aborting due to 40 previous errors diff --git a/tests/ui/manual_div_ceil.fixed b/tests/ui/manual_div_ceil.fixed index cd91be87ec17..8ffd107dd42e 100644 --- a/tests/ui/manual_div_ceil.fixed +++ b/tests/ui/manual_div_ceil.fixed @@ -105,3 +105,32 @@ fn issue_15705(size: u64, c: &u64) { let _ = size.div_ceil(*c); //~^ manual_div_ceil } + +struct MyStruct(u32); +impl MyStruct { + // Method matching name on different type should not trigger lint + fn next_multiple_of(self, y: u32) -> u32 { + self.0.next_multiple_of(y) + } +} + +fn issue_16219() { + let x = 33u32; + + // Lint. + let _ = x.div_ceil(8); + //~^ manual_div_ceil + let _ = x.div_ceil(8); + //~^ manual_div_ceil + + let y = &x; + let _ = y.div_ceil(8); + //~^ manual_div_ceil + + // No lint. + let _ = x.next_multiple_of(8) / 7; + let _ = x.next_multiple_of(7) / 8; + + let z = MyStruct(x); + let _ = z.next_multiple_of(8) / 8; +} diff --git a/tests/ui/manual_div_ceil.rs b/tests/ui/manual_div_ceil.rs index 9899c7d775c2..859fb5a13c44 100644 --- a/tests/ui/manual_div_ceil.rs +++ b/tests/ui/manual_div_ceil.rs @@ -105,3 +105,32 @@ fn issue_15705(size: u64, c: &u64) { let _ = (size + c - 1) / c; //~^ manual_div_ceil } + +struct MyStruct(u32); +impl MyStruct { + // Method matching name on different type should not trigger lint + fn next_multiple_of(self, y: u32) -> u32 { + self.0.next_multiple_of(y) + } +} + +fn issue_16219() { + let x = 33u32; + + // Lint. + let _ = x.next_multiple_of(8) / 8; + //~^ manual_div_ceil + let _ = u32::next_multiple_of(x, 8) / 8; + //~^ manual_div_ceil + + let y = &x; + let _ = y.next_multiple_of(8) / 8; + //~^ manual_div_ceil + + // No lint. + let _ = x.next_multiple_of(8) / 7; + let _ = x.next_multiple_of(7) / 8; + + let z = MyStruct(x); + let _ = z.next_multiple_of(8) / 8; +} diff --git a/tests/ui/manual_div_ceil.stderr b/tests/ui/manual_div_ceil.stderr index 44de3ba99be7..0efc114c7078 100644 --- a/tests/ui/manual_div_ceil.stderr +++ b/tests/ui/manual_div_ceil.stderr @@ -131,5 +131,23 @@ error: manually reimplementing `div_ceil` LL | let _ = (size + c - 1) / c; | ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `size.div_ceil(*c)` -error: aborting due to 20 previous errors +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:121:13 + | +LL | let _ = x.next_multiple_of(8) / 8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:123:13 + | +LL | let _ = u32::next_multiple_of(x, 8) / 8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:127:13 + | +LL | let _ = y.next_multiple_of(8) / 8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `y.div_ceil(8)` + +error: aborting due to 23 previous errors diff --git a/tests/ui/manual_div_ceil_with_feature.fixed b/tests/ui/manual_div_ceil_with_feature.fixed index f55999c5ad08..d77b8bc28986 100644 --- a/tests/ui/manual_div_ceil_with_feature.fixed +++ b/tests/ui/manual_div_ceil_with_feature.fixed @@ -84,3 +84,32 @@ fn issue_13950() { let _ = y.div_ceil(-7); //~^ manual_div_ceil } + +struct MyStruct(i32); +impl MyStruct { + // Method matching name on different type should not trigger lint + fn next_multiple_of(self, y: i32) -> i32 { + self.0.next_multiple_of(y) + } +} + +fn issue_16219() { + let x = 33i32; + + // Lint. + let _ = x.div_ceil(8); + //~^ manual_div_ceil + let _ = x.div_ceil(8); + //~^ manual_div_ceil + + let y = &x; + let _ = y.div_ceil(8); + //~^ manual_div_ceil + + // No lint. + let _ = x.next_multiple_of(8) / 7; + let _ = x.next_multiple_of(7) / 8; + + let z = MyStruct(x); + let _ = z.next_multiple_of(8) / 8; +} diff --git a/tests/ui/manual_div_ceil_with_feature.rs b/tests/ui/manual_div_ceil_with_feature.rs index 8a895f634cb4..5b9a4d9156a7 100644 --- a/tests/ui/manual_div_ceil_with_feature.rs +++ b/tests/ui/manual_div_ceil_with_feature.rs @@ -84,3 +84,32 @@ fn issue_13950() { let _ = (y - 8) / -7; //~^ manual_div_ceil } + +struct MyStruct(i32); +impl MyStruct { + // Method matching name on different type should not trigger lint + fn next_multiple_of(self, y: i32) -> i32 { + self.0.next_multiple_of(y) + } +} + +fn issue_16219() { + let x = 33i32; + + // Lint. + let _ = x.next_multiple_of(8) / 8; + //~^ manual_div_ceil + let _ = i32::next_multiple_of(x, 8) / 8; + //~^ manual_div_ceil + + let y = &x; + let _ = y.next_multiple_of(8) / 8; + //~^ manual_div_ceil + + // No lint. + let _ = x.next_multiple_of(8) / 7; + let _ = x.next_multiple_of(7) / 8; + + let z = MyStruct(x); + let _ = z.next_multiple_of(8) / 8; +} diff --git a/tests/ui/manual_div_ceil_with_feature.stderr b/tests/ui/manual_div_ceil_with_feature.stderr index e1160d962996..c5fa15112a87 100644 --- a/tests/ui/manual_div_ceil_with_feature.stderr +++ b/tests/ui/manual_div_ceil_with_feature.stderr @@ -139,5 +139,23 @@ error: manually reimplementing `div_ceil` LL | let _ = (y - 8) / -7; | ^^^^^^^^^^^^ help: consider using `.div_ceil()`: `y.div_ceil(-7)` -error: aborting due to 23 previous errors +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:100:13 + | +LL | let _ = x.next_multiple_of(8) / 8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:102:13 + | +LL | let _ = i32::next_multiple_of(x, 8) / 8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:106:13 + | +LL | let _ = y.next_multiple_of(8) / 8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `y.div_ceil(8)` + +error: aborting due to 26 previous errors diff --git a/tests/ui/manual_ignore_case_cmp.fixed b/tests/ui/manual_ignore_case_cmp.fixed index cd7adc20b127..f0e413aaec0d 100644 --- a/tests/ui/manual_ignore_case_cmp.fixed +++ b/tests/ui/manual_ignore_case_cmp.fixed @@ -160,3 +160,23 @@ fn ref_osstring(a: OsString, b: &OsString) { b.eq_ignore_ascii_case(a); //~^ manual_ignore_case_cmp } + +fn wrongly_unmangled_macros(a: &str, b: &str) -> bool { + struct S<'a> { + inner: &'a str, + } + + let a = S { inner: a }; + let b = S { inner: b }; + + macro_rules! dot_inner { + ($s:expr) => { + $s.inner + }; + } + + dot_inner!(a).eq_ignore_ascii_case(dot_inner!(b)) + //~^ manual_ignore_case_cmp + || dot_inner!(a).eq_ignore_ascii_case("abc") + //~^ manual_ignore_case_cmp +} diff --git a/tests/ui/manual_ignore_case_cmp.rs b/tests/ui/manual_ignore_case_cmp.rs index 85f6719827c9..9802e87cd233 100644 --- a/tests/ui/manual_ignore_case_cmp.rs +++ b/tests/ui/manual_ignore_case_cmp.rs @@ -160,3 +160,23 @@ fn ref_osstring(a: OsString, b: &OsString) { b.to_ascii_lowercase() == a.to_ascii_lowercase(); //~^ manual_ignore_case_cmp } + +fn wrongly_unmangled_macros(a: &str, b: &str) -> bool { + struct S<'a> { + inner: &'a str, + } + + let a = S { inner: a }; + let b = S { inner: b }; + + macro_rules! dot_inner { + ($s:expr) => { + $s.inner + }; + } + + dot_inner!(a).to_ascii_lowercase() == dot_inner!(b).to_ascii_lowercase() + //~^ manual_ignore_case_cmp + || dot_inner!(a).to_ascii_lowercase() == "abc" + //~^ manual_ignore_case_cmp +} diff --git a/tests/ui/manual_ignore_case_cmp.stderr b/tests/ui/manual_ignore_case_cmp.stderr index fa7fadd91076..2f698e076ed3 100644 --- a/tests/ui/manual_ignore_case_cmp.stderr +++ b/tests/ui/manual_ignore_case_cmp.stderr @@ -588,5 +588,29 @@ LL - b.to_ascii_lowercase() == a.to_ascii_lowercase(); LL + b.eq_ignore_ascii_case(a); | -error: aborting due to 49 previous errors +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:178:5 + | +LL | dot_inner!(a).to_ascii_lowercase() == dot_inner!(b).to_ascii_lowercase() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL - dot_inner!(a).to_ascii_lowercase() == dot_inner!(b).to_ascii_lowercase() +LL + dot_inner!(a).eq_ignore_ascii_case(dot_inner!(b)) + | + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:180:12 + | +LL | || dot_inner!(a).to_ascii_lowercase() == "abc" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL - || dot_inner!(a).to_ascii_lowercase() == "abc" +LL + || dot_inner!(a).eq_ignore_ascii_case("abc") + | + +error: aborting due to 51 previous errors diff --git a/tests/ui/manual_ilog2.fixed b/tests/ui/manual_ilog2.fixed index a0f6d9392c30..ea86fc927c7c 100644 --- a/tests/ui/manual_ilog2.fixed +++ b/tests/ui/manual_ilog2.fixed @@ -30,3 +30,20 @@ fn foo(a: u32, b: u64) { external!($a.ilog(2)); with_span!(span; a.ilog(2)); } + +fn wrongly_unmangled_macros() { + struct S { + inner: u32, + } + + let x = S { inner: 42 }; + macro_rules! access { + ($s:expr) => { + $s.inner + }; + } + let log = access!(x).ilog2(); + //~^ manual_ilog2 + let log = access!(x).ilog2(); + //~^ manual_ilog2 +} diff --git a/tests/ui/manual_ilog2.rs b/tests/ui/manual_ilog2.rs index bd4b5d9d3c0d..8cb0e12d7361 100644 --- a/tests/ui/manual_ilog2.rs +++ b/tests/ui/manual_ilog2.rs @@ -30,3 +30,20 @@ fn foo(a: u32, b: u64) { external!($a.ilog(2)); with_span!(span; a.ilog(2)); } + +fn wrongly_unmangled_macros() { + struct S { + inner: u32, + } + + let x = S { inner: 42 }; + macro_rules! access { + ($s:expr) => { + $s.inner + }; + } + let log = 31 - access!(x).leading_zeros(); + //~^ manual_ilog2 + let log = access!(x).ilog(2); + //~^ manual_ilog2 +} diff --git a/tests/ui/manual_ilog2.stderr b/tests/ui/manual_ilog2.stderr index 7c9694f35330..d0ef8378081a 100644 --- a/tests/ui/manual_ilog2.stderr +++ b/tests/ui/manual_ilog2.stderr @@ -19,5 +19,17 @@ error: manually reimplementing `ilog2` LL | 63 - b.leading_zeros(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `b.ilog2()` -error: aborting due to 3 previous errors +error: manually reimplementing `ilog2` + --> tests/ui/manual_ilog2.rs:45:15 + | +LL | let log = 31 - access!(x).leading_zeros(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `access!(x).ilog2()` + +error: manually reimplementing `ilog2` + --> tests/ui/manual_ilog2.rs:47:15 + | +LL | let log = access!(x).ilog(2); + | ^^^^^^^^^^^^^^^^^^ help: try: `access!(x).ilog2()` + +error: aborting due to 5 previous errors diff --git a/tests/ui/manual_is_multiple_of.fixed b/tests/ui/manual_is_multiple_of.fixed index 03f75e725ed5..82e0684e5e57 100644 --- a/tests/ui/manual_is_multiple_of.fixed +++ b/tests/ui/manual_is_multiple_of.fixed @@ -101,3 +101,19 @@ mod issue15103 { (1..1_000).filter(|&i| i == d(d(i)) && i != d(i)).sum() } } + +fn wrongly_unmangled_macros(a: u32, b: u32) { + struct Wrapper(u32); + let a = Wrapper(a); + let b = Wrapper(b); + macro_rules! dot_0 { + ($x:expr) => { + $x.0 + }; + } + + if dot_0!(a).is_multiple_of(dot_0!(b)) { + //~^ manual_is_multiple_of + todo!() + } +} diff --git a/tests/ui/manual_is_multiple_of.rs b/tests/ui/manual_is_multiple_of.rs index 7b6fa64c843d..82a492e24092 100644 --- a/tests/ui/manual_is_multiple_of.rs +++ b/tests/ui/manual_is_multiple_of.rs @@ -101,3 +101,19 @@ mod issue15103 { (1..1_000).filter(|&i| i == d(d(i)) && i != d(i)).sum() } } + +fn wrongly_unmangled_macros(a: u32, b: u32) { + struct Wrapper(u32); + let a = Wrapper(a); + let b = Wrapper(b); + macro_rules! dot_0 { + ($x:expr) => { + $x.0 + }; + } + + if dot_0!(a) % dot_0!(b) == 0 { + //~^ manual_is_multiple_of + todo!() + } +} diff --git a/tests/ui/manual_is_multiple_of.stderr b/tests/ui/manual_is_multiple_of.stderr index 8523599ec402..3aba869c9111 100644 --- a/tests/ui/manual_is_multiple_of.stderr +++ b/tests/ui/manual_is_multiple_of.stderr @@ -67,5 +67,11 @@ error: manual implementation of `.is_multiple_of()` LL | let d = |n: u32| -> u32 { (1..=n / 2).filter(|i| n % i == 0).sum() }; | ^^^^^^^^^^ help: replace with: `n.is_multiple_of(*i)` -error: aborting due to 11 previous errors +error: manual implementation of `.is_multiple_of()` + --> tests/ui/manual_is_multiple_of.rs:115:8 + | +LL | if dot_0!(a) % dot_0!(b) == 0 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `dot_0!(a).is_multiple_of(dot_0!(b))` + +error: aborting due to 12 previous errors diff --git a/tests/ui/manual_ok_err.fixed b/tests/ui/manual_ok_err.fixed index 9b70ce0df43a..e22f91a0155f 100644 --- a/tests/ui/manual_ok_err.fixed +++ b/tests/ui/manual_ok_err.fixed @@ -127,3 +127,13 @@ mod issue15051 { result_with_ref_mut(x).as_mut().ok() } } + +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + Ok::($val) + }; + } + + let _ = test_expr!(42).ok(); +} diff --git a/tests/ui/manual_ok_err.rs b/tests/ui/manual_ok_err.rs index dee904638245..c1355f0d4096 100644 --- a/tests/ui/manual_ok_err.rs +++ b/tests/ui/manual_ok_err.rs @@ -177,3 +177,17 @@ mod issue15051 { } } } + +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + Ok::($val) + }; + } + + let _ = match test_expr!(42) { + //~^ manual_ok_err + Ok(v) => Some(v), + Err(_) => None, + }; +} diff --git a/tests/ui/manual_ok_err.stderr b/tests/ui/manual_ok_err.stderr index 448fbffc0509..0c2ed368eb97 100644 --- a/tests/ui/manual_ok_err.stderr +++ b/tests/ui/manual_ok_err.stderr @@ -141,5 +141,16 @@ LL | | Err(_) => None, LL | | } | |_________^ help: replace with: `result_with_ref_mut(x).as_mut().ok()` -error: aborting due to 12 previous errors +error: manual implementation of `ok` + --> tests/ui/manual_ok_err.rs:188:13 + | +LL | let _ = match test_expr!(42) { + | _____________^ +LL | | +LL | | Ok(v) => Some(v), +LL | | Err(_) => None, +LL | | }; + | |_____^ help: replace with: `test_expr!(42).ok()` + +error: aborting due to 13 previous errors diff --git a/tests/ui/match_as_ref.fixed b/tests/ui/match_as_ref.fixed index 09a6ed169390..b1b8ffb885f5 100644 --- a/tests/ui/match_as_ref.fixed +++ b/tests/ui/match_as_ref.fixed @@ -90,3 +90,13 @@ fn issue15932() { let _: Option<&dyn std::fmt::Debug> = Some(0).as_ref().map(|x| x as _); } + +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + Some($val) + }; + } + + let _: Option<&u32> = test_expr!(42).as_ref(); +} diff --git a/tests/ui/match_as_ref.rs b/tests/ui/match_as_ref.rs index 347b6d186887..3113167957d4 100644 --- a/tests/ui/match_as_ref.rs +++ b/tests/ui/match_as_ref.rs @@ -114,3 +114,17 @@ fn issue15932() { Some(ref mut v) => Some(v), }; } + +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + Some($val) + }; + } + + let _: Option<&u32> = match test_expr!(42) { + //~^ match_as_ref + None => None, + Some(ref v) => Some(v), + }; +} diff --git a/tests/ui/match_as_ref.stderr b/tests/ui/match_as_ref.stderr index df06e358f296..3eab499fe409 100644 --- a/tests/ui/match_as_ref.stderr +++ b/tests/ui/match_as_ref.stderr @@ -127,5 +127,26 @@ LL - }; LL + let _: Option<&dyn std::fmt::Debug> = Some(0).as_ref().map(|x| x as _); | -error: aborting due to 6 previous errors +error: manual implementation of `Option::as_ref` + --> tests/ui/match_as_ref.rs:125:27 + | +LL | let _: Option<&u32> = match test_expr!(42) { + | ___________________________^ +LL | | +LL | | None => None, +LL | | Some(ref v) => Some(v), +LL | | }; + | |_____^ + | +help: use `Option::as_ref()` directly + | +LL - let _: Option<&u32> = match test_expr!(42) { +LL - +LL - None => None, +LL - Some(ref v) => Some(v), +LL - }; +LL + let _: Option<&u32> = test_expr!(42).as_ref(); + | + +error: aborting due to 7 previous errors diff --git a/tests/ui/match_bool.fixed b/tests/ui/match_bool.fixed index 876ae935afde..3d5d0a0d532c 100644 --- a/tests/ui/match_bool.fixed +++ b/tests/ui/match_bool.fixed @@ -74,4 +74,15 @@ fn issue15351() { } } +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + ($val + 1) > 0 + }; + } + + let x = 5; + if test_expr!(x) { 1 } else { 0 }; +} + fn main() {} diff --git a/tests/ui/match_bool.rs b/tests/ui/match_bool.rs index a134ad8346e2..4db0aedf3260 100644 --- a/tests/ui/match_bool.rs +++ b/tests/ui/match_bool.rs @@ -126,4 +126,19 @@ fn issue15351() { } } +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + ($val + 1) > 0 + }; + } + + let x = 5; + match test_expr!(x) { + //~^ match_bool + true => 1, + false => 0, + }; +} + fn main() {} diff --git a/tests/ui/match_bool.stderr b/tests/ui/match_bool.stderr index c05742e56339..223acd17aead 100644 --- a/tests/ui/match_bool.stderr +++ b/tests/ui/match_bool.stderr @@ -183,5 +183,15 @@ LL + break 'a; LL + } } | -error: aborting due to 13 previous errors +error: `match` on a boolean expression + --> tests/ui/match_bool.rs:137:5 + | +LL | / match test_expr!(x) { +LL | | +LL | | true => 1, +LL | | false => 0, +LL | | }; + | |_____^ help: consider using an `if`/`else` expression: `if test_expr!(x) { 1 } else { 0 }` + +error: aborting due to 14 previous errors diff --git a/tests/ui/mutex_atomic.fixed b/tests/ui/mutex_atomic.fixed index e4218726019f..dc05d8a2c61f 100644 --- a/tests/ui/mutex_atomic.fixed +++ b/tests/ui/mutex_atomic.fixed @@ -65,3 +65,15 @@ fn issue13378() { let (funky_mtx) = std::sync::atomic::AtomicU64::new(0); //~^ mutex_integer } + +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + ($val > 0 && true) + }; + } + + let _ = std::sync::atomic::AtomicBool::new(test_expr!(1)); + //~^ mutex_atomic + // The suggestion should preserve the macro call: `AtomicBool::new(test_expr!(true))` +} diff --git a/tests/ui/mutex_atomic.rs b/tests/ui/mutex_atomic.rs index 95f2b135903f..33745f8fc5e1 100644 --- a/tests/ui/mutex_atomic.rs +++ b/tests/ui/mutex_atomic.rs @@ -65,3 +65,15 @@ fn issue13378() { let (funky_mtx): Mutex = Mutex::new(0); //~^ mutex_integer } + +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + ($val > 0 && true) + }; + } + + let _ = Mutex::new(test_expr!(1)); + //~^ mutex_atomic + // The suggestion should preserve the macro call: `AtomicBool::new(test_expr!(true))` +} diff --git a/tests/ui/mutex_atomic.stderr b/tests/ui/mutex_atomic.stderr index 0afc6d541dea..56d94035583c 100644 --- a/tests/ui/mutex_atomic.stderr +++ b/tests/ui/mutex_atomic.stderr @@ -130,5 +130,13 @@ LL - let (funky_mtx): Mutex = Mutex::new(0); LL + let (funky_mtx) = std::sync::atomic::AtomicU64::new(0); | -error: aborting due to 14 previous errors +error: using a `Mutex` where an atomic would do + --> tests/ui/mutex_atomic.rs:76:13 + | +LL | let _ = Mutex::new(test_expr!(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicBool::new(test_expr!(1))` + | + = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>` + +error: aborting due to 15 previous errors diff --git a/tests/ui/needless_bool_assign.fixed b/tests/ui/needless_bool_assign.fixed index d6fab4c51b53..8fd572038140 100644 --- a/tests/ui/needless_bool_assign.fixed +++ b/tests/ui/needless_bool_assign.fixed @@ -42,3 +42,22 @@ fn issue15063(x: bool, y: bool) { } else { z = x || y; } //~^^^^^ needless_bool_assign } + +fn wrongly_unmangled_macros(must_keep: fn(usize, usize) -> bool, x: usize, y: usize) { + struct Wrapper(T); + let mut skip = Wrapper(false); + + macro_rules! invoke { + ($func:expr, $a:expr, $b:expr) => { + $func($a, $b) + }; + } + macro_rules! dot_0 { + ($w:expr) => { + $w.0 + }; + } + + dot_0!(skip) = !invoke!(must_keep, x, y); + //~^^^^^ needless_bool_assign +} diff --git a/tests/ui/needless_bool_assign.rs b/tests/ui/needless_bool_assign.rs index c504f61f4dd1..4721ab433b32 100644 --- a/tests/ui/needless_bool_assign.rs +++ b/tests/ui/needless_bool_assign.rs @@ -58,3 +58,26 @@ fn issue15063(x: bool, y: bool) { } //~^^^^^ needless_bool_assign } + +fn wrongly_unmangled_macros(must_keep: fn(usize, usize) -> bool, x: usize, y: usize) { + struct Wrapper(T); + let mut skip = Wrapper(false); + + macro_rules! invoke { + ($func:expr, $a:expr, $b:expr) => { + $func($a, $b) + }; + } + macro_rules! dot_0 { + ($w:expr) => { + $w.0 + }; + } + + if invoke!(must_keep, x, y) { + dot_0!(skip) = false; + } else { + dot_0!(skip) = true; + } + //~^^^^^ needless_bool_assign +} diff --git a/tests/ui/needless_bool_assign.stderr b/tests/ui/needless_bool_assign.stderr index 1d09b8b25a09..34ff782f34a3 100644 --- a/tests/ui/needless_bool_assign.stderr +++ b/tests/ui/needless_bool_assign.stderr @@ -62,5 +62,15 @@ LL | | z = false; LL | | } | |_____^ help: you can reduce it to: `{ z = x || y; }` -error: aborting due to 5 previous errors +error: this if-then-else expression assigns a bool literal + --> tests/ui/needless_bool_assign.rs:77:5 + | +LL | / if invoke!(must_keep, x, y) { +LL | | dot_0!(skip) = false; +LL | | } else { +LL | | dot_0!(skip) = true; +LL | | } + | |_____^ help: you can reduce it to: `dot_0!(skip) = !invoke!(must_keep, x, y);` + +error: aborting due to 6 previous errors diff --git a/tests/ui/needless_for_each_fixable.fixed b/tests/ui/needless_for_each_fixable.fixed index a6d64d9afc1a..19b34f42af24 100644 --- a/tests/ui/needless_for_each_fixable.fixed +++ b/tests/ui/needless_for_each_fixable.fixed @@ -149,3 +149,11 @@ fn issue15256() { for v in vec.iter() { println!("{v}"); } //~^ needless_for_each } + +fn issue16294() { + let vec: Vec = Vec::new(); + for elem in vec.iter() { + //~^ needless_for_each + println!("{elem}"); + } +} diff --git a/tests/ui/needless_for_each_fixable.rs b/tests/ui/needless_for_each_fixable.rs index 7e74d2b428fd..f04e2555a370 100644 --- a/tests/ui/needless_for_each_fixable.rs +++ b/tests/ui/needless_for_each_fixable.rs @@ -149,3 +149,11 @@ fn issue15256() { vec.iter().for_each(|v| println!("{v}")); //~^ needless_for_each } + +fn issue16294() { + let vec: Vec = Vec::new(); + vec.iter().for_each(|elem| { + //~^ needless_for_each + println!("{elem}"); + }) +} diff --git a/tests/ui/needless_for_each_fixable.stderr b/tests/ui/needless_for_each_fixable.stderr index 204cfa36b022..121669d15072 100644 --- a/tests/ui/needless_for_each_fixable.stderr +++ b/tests/ui/needless_for_each_fixable.stderr @@ -154,5 +154,22 @@ error: needless use of `for_each` LL | vec.iter().for_each(|v| println!("{v}")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for v in vec.iter() { println!("{v}"); }` -error: aborting due to 11 previous errors +error: needless use of `for_each` + --> tests/ui/needless_for_each_fixable.rs:155:5 + | +LL | / vec.iter().for_each(|elem| { +LL | | +LL | | println!("{elem}"); +LL | | }) + | |______^ + | +help: try + | +LL ~ for elem in vec.iter() { +LL + +LL + println!("{elem}"); +LL + } + | + +error: aborting due to 12 previous errors diff --git a/tests/ui/never_loop_iterator_reduction.rs b/tests/ui/never_loop_iterator_reduction.rs index 6b07b91db29a..27f1766b841d 100644 --- a/tests/ui/never_loop_iterator_reduction.rs +++ b/tests/ui/never_loop_iterator_reduction.rs @@ -1,8 +1,9 @@ //@no-rustfix #![warn(clippy::never_loop)] +#![expect(clippy::needless_return)] fn main() { - // diverging closure: should trigger + // diverging closure with no `return`: should trigger [0, 1].into_iter().for_each(|x| { //~^ never_loop @@ -14,4 +15,10 @@ fn main() { [0, 1].into_iter().for_each(|x| { let _ = x + 1; }); + + // `return` should NOT trigger even though it is diverging + [0, 1].into_iter().for_each(|x| { + println!("x = {x}"); + return; + }); } diff --git a/tests/ui/never_loop_iterator_reduction.stderr b/tests/ui/never_loop_iterator_reduction.stderr index b76ee283146c..92483c85432d 100644 --- a/tests/ui/never_loop_iterator_reduction.stderr +++ b/tests/ui/never_loop_iterator_reduction.stderr @@ -1,5 +1,5 @@ error: this iterator reduction never loops (closure always diverges) - --> tests/ui/never_loop_iterator_reduction.rs:6:5 + --> tests/ui/never_loop_iterator_reduction.rs:7:5 | LL | / [0, 1].into_iter().for_each(|x| { LL | | diff --git a/tests/ui/new_without_default.fixed b/tests/ui/new_without_default.fixed index 9a5e90b48065..f6591820feeb 100644 --- a/tests/ui/new_without_default.fixed +++ b/tests/ui/new_without_default.fixed @@ -409,3 +409,58 @@ mod issue15778 { } } } + +pub mod issue16255 { + use std::fmt::Display; + use std::marker::PhantomData; + + pub struct Foo { + marker: PhantomData, + } + + impl Default for Foo + where + T: Display, + T: Clone, + { + fn default() -> Self { + Self::new() + } + } + + impl Foo + where + T: Display, + { + pub fn new() -> Self + //~^ new_without_default + where + T: Clone, + { + Self { marker: PhantomData } + } + } + + pub struct Bar { + marker: PhantomData, + } + + impl Default for Bar + where + T: Clone, + { + fn default() -> Self { + Self::new() + } + } + + impl Bar { + pub fn new() -> Self + //~^ new_without_default + where + T: Clone, + { + Self { marker: PhantomData } + } + } +} diff --git a/tests/ui/new_without_default.rs b/tests/ui/new_without_default.rs index f7466aa32189..d3447f2e16b2 100644 --- a/tests/ui/new_without_default.rs +++ b/tests/ui/new_without_default.rs @@ -324,3 +324,39 @@ mod issue15778 { } } } + +pub mod issue16255 { + use std::fmt::Display; + use std::marker::PhantomData; + + pub struct Foo { + marker: PhantomData, + } + + impl Foo + where + T: Display, + { + pub fn new() -> Self + //~^ new_without_default + where + T: Clone, + { + Self { marker: PhantomData } + } + } + + pub struct Bar { + marker: PhantomData, + } + + impl Bar { + pub fn new() -> Self + //~^ new_without_default + where + T: Clone, + { + Self { marker: PhantomData } + } + } +} diff --git a/tests/ui/new_without_default.stderr b/tests/ui/new_without_default.stderr index 0593dbb00fb6..6c0f73d13185 100644 --- a/tests/ui/new_without_default.stderr +++ b/tests/ui/new_without_default.stderr @@ -250,5 +250,58 @@ LL + } LL + } | -error: aborting due to 13 previous errors +error: you should consider adding a `Default` implementation for `Foo` + --> tests/ui/new_without_default.rs:340:9 + | +LL | / pub fn new() -> Self +LL | | +LL | | where +LL | | T: Clone, +LL | | { +LL | | Self { marker: PhantomData } +LL | | } + | |_________^ + | +help: try adding this + | +LL ~ impl Default for Foo +LL + where +LL + T: Display, +LL + T: Clone, +LL + { +LL + fn default() -> Self { +LL + Self::new() +LL + } +LL + } +LL + +LL ~ impl Foo + | + +error: you should consider adding a `Default` implementation for `Bar` + --> tests/ui/new_without_default.rs:354:9 + | +LL | / pub fn new() -> Self +LL | | +LL | | where +LL | | T: Clone, +LL | | { +LL | | Self { marker: PhantomData } +LL | | } + | |_________^ + | +help: try adding this + | +LL ~ impl Default for Bar +LL + where +LL + T: Clone, +LL + { +LL + fn default() -> Self { +LL + Self::new() +LL + } +LL + } +LL + +LL ~ impl Bar { + | + +error: aborting due to 15 previous errors diff --git a/tests/ui/question_mark.fixed b/tests/ui/question_mark.fixed index 2c5ee0245038..b8072932c4ea 100644 --- a/tests/ui/question_mark.fixed +++ b/tests/ui/question_mark.fixed @@ -1,5 +1,5 @@ #![feature(try_blocks)] -#![allow(clippy::unnecessary_wraps)] +#![allow(clippy::unnecessary_wraps, clippy::no_effect)] use std::sync::MutexGuard; @@ -500,3 +500,18 @@ mod issue14894 { Ok(()) } } + +fn wrongly_unmangled_macros() -> Option { + macro_rules! test_expr { + ($val:expr) => { + Some($val) + }; + } + + let x = test_expr!(42)?; + //~^^^ question_mark + Some(x); + + test_expr!(42)?; + test_expr!(42) +} diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs index b9ff9d1565b2..b320dcd4b0bc 100644 --- a/tests/ui/question_mark.rs +++ b/tests/ui/question_mark.rs @@ -1,5 +1,5 @@ #![feature(try_blocks)] -#![allow(clippy::unnecessary_wraps)] +#![allow(clippy::unnecessary_wraps, clippy::no_effect)] use std::sync::MutexGuard; @@ -615,3 +615,23 @@ mod issue14894 { Ok(()) } } + +fn wrongly_unmangled_macros() -> Option { + macro_rules! test_expr { + ($val:expr) => { + Some($val) + }; + } + + let Some(x) = test_expr!(42) else { + return None; + }; + //~^^^ question_mark + Some(x); + + if test_expr!(42).is_none() { + //~^ question_mark + return None; + } + test_expr!(42) +} diff --git a/tests/ui/question_mark.stderr b/tests/ui/question_mark.stderr index 9b2896328e66..d645c8830adc 100644 --- a/tests/ui/question_mark.stderr +++ b/tests/ui/question_mark.stderr @@ -333,5 +333,22 @@ LL | | return Err(reason); LL | | } | |_________^ help: replace it with: `result?;` -error: aborting due to 35 previous errors +error: this `let...else` may be rewritten with the `?` operator + --> tests/ui/question_mark.rs:626:5 + | +LL | / let Some(x) = test_expr!(42) else { +LL | | return None; +LL | | }; + | |______^ help: replace it with: `let x = test_expr!(42)?;` + +error: this block may be rewritten with the `?` operator + --> tests/ui/question_mark.rs:632:5 + | +LL | / if test_expr!(42).is_none() { +LL | | +LL | | return None; +LL | | } + | |_____^ help: replace it with: `test_expr!(42)?;` + +error: aborting due to 37 previous errors diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed index 08903ef7fdda..b44009446640 100644 --- a/tests/ui/redundant_pattern_matching_option.fixed +++ b/tests/ui/redundant_pattern_matching_option.fixed @@ -195,3 +195,16 @@ fn issue16045() { } } } + +fn issue14989() { + macro_rules! x { + () => { + None:: + }; + } + + if x! {}.is_some() {}; + //~^ redundant_pattern_matching + while x! {}.is_some() {} + //~^ redundant_pattern_matching +} diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs index 95eff3f9ebf9..c13cf993e786 100644 --- a/tests/ui/redundant_pattern_matching_option.rs +++ b/tests/ui/redundant_pattern_matching_option.rs @@ -231,3 +231,16 @@ fn issue16045() { } } } + +fn issue14989() { + macro_rules! x { + () => { + None:: + }; + } + + if let Some(_) = (x! {}) {}; + //~^ redundant_pattern_matching + while let Some(_) = (x! {}) {} + //~^ redundant_pattern_matching +} diff --git a/tests/ui/redundant_pattern_matching_option.stderr b/tests/ui/redundant_pattern_matching_option.stderr index 6fd0c5a6f859..5c9edfd4c50a 100644 --- a/tests/ui/redundant_pattern_matching_option.stderr +++ b/tests/ui/redundant_pattern_matching_option.stderr @@ -236,5 +236,17 @@ error: redundant pattern matching, consider using `is_some()` LL | if let Some(_) = x.await { | -------^^^^^^^---------- help: try: `if x.await.is_some()` -error: aborting due to 33 previous errors +error: redundant pattern matching, consider using `is_some()` + --> tests/ui/redundant_pattern_matching_option.rs:242:12 + | +LL | if let Some(_) = (x! {}) {}; + | -------^^^^^^^---------- help: try: `if x! {}.is_some()` + +error: redundant pattern matching, consider using `is_some()` + --> tests/ui/redundant_pattern_matching_option.rs:244:15 + | +LL | while let Some(_) = (x! {}) {} + | ----------^^^^^^^---------- help: try: `while x! {}.is_some()` + +error: aborting due to 35 previous errors diff --git a/tests/ui/redundant_pattern_matching_result.fixed b/tests/ui/redundant_pattern_matching_result.fixed index 261d82fc35c8..8754d71aa629 100644 --- a/tests/ui/redundant_pattern_matching_result.fixed +++ b/tests/ui/redundant_pattern_matching_result.fixed @@ -165,3 +165,23 @@ fn issue10803() { // Don't lint let _ = matches!(x, Err(16)); } + +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + Ok::($val) + }; + } + + let _ = test_expr!(42).is_ok(); + + macro_rules! test_guard { + ($val:expr) => { + ($val + 1) > 0 + }; + } + + let x: Result = Ok(42); + let _ = x.is_ok() && test_guard!(42); + //~^ redundant_pattern_matching +} diff --git a/tests/ui/redundant_pattern_matching_result.rs b/tests/ui/redundant_pattern_matching_result.rs index 6cae4cc4b6b0..b83b02588fb6 100644 --- a/tests/ui/redundant_pattern_matching_result.rs +++ b/tests/ui/redundant_pattern_matching_result.rs @@ -205,3 +205,27 @@ fn issue10803() { // Don't lint let _ = matches!(x, Err(16)); } + +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + Ok::($val) + }; + } + + let _ = match test_expr!(42) { + //~^ redundant_pattern_matching + Ok(_) => true, + Err(_) => false, + }; + + macro_rules! test_guard { + ($val:expr) => { + ($val + 1) > 0 + }; + } + + let x: Result = Ok(42); + let _ = matches!(x, Ok(_) if test_guard!(42)); + //~^ redundant_pattern_matching +} diff --git a/tests/ui/redundant_pattern_matching_result.stderr b/tests/ui/redundant_pattern_matching_result.stderr index 7e7d27d07a7f..dda203b753c3 100644 --- a/tests/ui/redundant_pattern_matching_result.stderr +++ b/tests/ui/redundant_pattern_matching_result.stderr @@ -209,5 +209,22 @@ error: redundant pattern matching, consider using `is_err()` LL | let _ = matches!(x, Err(_)); | ^^^^^^^^^^^^^^^^^^^ help: try: `x.is_err()` -error: aborting due to 28 previous errors +error: redundant pattern matching, consider using `is_ok()` + --> tests/ui/redundant_pattern_matching_result.rs:216:13 + | +LL | let _ = match test_expr!(42) { + | _____________^ +LL | | +LL | | Ok(_) => true, +LL | | Err(_) => false, +LL | | }; + | |_____^ help: try: `test_expr!(42).is_ok()` + +error: redundant pattern matching, consider using `is_ok()` + --> tests/ui/redundant_pattern_matching_result.rs:229:13 + | +LL | let _ = matches!(x, Ok(_) if test_guard!(42)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_ok() && test_guard!(42)` + +error: aborting due to 30 previous errors diff --git a/tests/ui/single_range_in_vec_init_unfixable.rs b/tests/ui/single_range_in_vec_init_unfixable.rs new file mode 100644 index 000000000000..33378b386f34 --- /dev/null +++ b/tests/ui/single_range_in_vec_init_unfixable.rs @@ -0,0 +1,12 @@ +//@no-rustfix +#![warn(clippy::single_range_in_vec_init)] + +use std::ops::Range; + +fn issue16306(v: &[i32]) { + fn takes_range_slice(_: &[Range]) {} + + let len = v.len(); + takes_range_slice(&[0..len as i64]); + //~^ single_range_in_vec_init +} diff --git a/tests/ui/single_range_in_vec_init_unfixable.stderr b/tests/ui/single_range_in_vec_init_unfixable.stderr new file mode 100644 index 000000000000..b10af21ed21c --- /dev/null +++ b/tests/ui/single_range_in_vec_init_unfixable.stderr @@ -0,0 +1,16 @@ +error: an array of `Range` that is only one element + --> tests/ui/single_range_in_vec_init_unfixable.rs:10:24 + | +LL | takes_range_slice(&[0..len as i64]); + | ^^^^^^^^^^^^^^^ + | + = note: `-D clippy::single-range-in-vec-init` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::single_range_in_vec_init)]` +help: if you wanted a `Vec` that contains the entire range, try + | +LL - takes_range_slice(&[0..len as i64]); +LL + takes_range_slice(&(0..len as i64).collect::>()); + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/str_to_string.fixed b/tests/ui/str_to_string.fixed index 2941c4dbd33d..8713c4f9bc86 100644 --- a/tests/ui/str_to_string.fixed +++ b/tests/ui/str_to_string.fixed @@ -8,3 +8,17 @@ fn main() { msg.to_owned(); //~^ str_to_string } + +fn issue16271(key: &[u8]) { + macro_rules! t { + ($e:expr) => { + match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + } + }; + } + + let _value = t!(str::from_utf8(key)).to_owned(); + //~^ str_to_string +} diff --git a/tests/ui/str_to_string.rs b/tests/ui/str_to_string.rs index 4c4d2bb18062..b81759e1037b 100644 --- a/tests/ui/str_to_string.rs +++ b/tests/ui/str_to_string.rs @@ -8,3 +8,17 @@ fn main() { msg.to_string(); //~^ str_to_string } + +fn issue16271(key: &[u8]) { + macro_rules! t { + ($e:expr) => { + match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + } + }; + } + + let _value = t!(str::from_utf8(key)).to_string(); + //~^ str_to_string +} diff --git a/tests/ui/str_to_string.stderr b/tests/ui/str_to_string.stderr index cb7b6b48843a..c0a38c8ebe46 100644 --- a/tests/ui/str_to_string.stderr +++ b/tests/ui/str_to_string.stderr @@ -13,5 +13,11 @@ error: `to_string()` called on a `&str` LL | msg.to_string(); | ^^^^^^^^^^^^^^^ help: try: `msg.to_owned()` -error: aborting due to 2 previous errors +error: `to_string()` called on a `&str` + --> tests/ui/str_to_string.rs:22:18 + | +LL | let _value = t!(str::from_utf8(key)).to_string(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t!(str::from_utf8(key)).to_owned()` + +error: aborting due to 3 previous errors diff --git a/tests/ui/string_from_utf8_as_bytes.fixed b/tests/ui/string_from_utf8_as_bytes.fixed index 193217114d88..98fa3a4fcf70 100644 --- a/tests/ui/string_from_utf8_as_bytes.fixed +++ b/tests/ui/string_from_utf8_as_bytes.fixed @@ -1,6 +1,16 @@ #![warn(clippy::string_from_utf8_as_bytes)] +macro_rules! test_range { + ($start:expr, $end:expr) => { + $start..$end + }; +} + fn main() { let _ = Some(&"Hello World!"[6..11]); //~^ string_from_utf8_as_bytes + + let s = "Hello World!"; + let _ = Some(&s[test_range!(6, 11)]); + //~^ string_from_utf8_as_bytes } diff --git a/tests/ui/string_from_utf8_as_bytes.rs b/tests/ui/string_from_utf8_as_bytes.rs index 49beb19ee40f..6354d5376ad6 100644 --- a/tests/ui/string_from_utf8_as_bytes.rs +++ b/tests/ui/string_from_utf8_as_bytes.rs @@ -1,6 +1,16 @@ #![warn(clippy::string_from_utf8_as_bytes)] +macro_rules! test_range { + ($start:expr, $end:expr) => { + $start..$end + }; +} + fn main() { let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]); //~^ string_from_utf8_as_bytes + + let s = "Hello World!"; + let _ = std::str::from_utf8(&s.as_bytes()[test_range!(6, 11)]); + //~^ string_from_utf8_as_bytes } diff --git a/tests/ui/string_from_utf8_as_bytes.stderr b/tests/ui/string_from_utf8_as_bytes.stderr index 99c8d8ae4eab..bba9ec0caf19 100644 --- a/tests/ui/string_from_utf8_as_bytes.stderr +++ b/tests/ui/string_from_utf8_as_bytes.stderr @@ -1,5 +1,5 @@ error: calling a slice of `as_bytes()` with `from_utf8` should be not necessary - --> tests/ui/string_from_utf8_as_bytes.rs:4:13 + --> tests/ui/string_from_utf8_as_bytes.rs:10:13 | LL | let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(&"Hello World!"[6..11])` @@ -7,5 +7,11 @@ LL | let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]); = note: `-D clippy::string-from-utf8-as-bytes` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::string_from_utf8_as_bytes)]` -error: aborting due to 1 previous error +error: calling a slice of `as_bytes()` with `from_utf8` should be not necessary + --> tests/ui/string_from_utf8_as_bytes.rs:14:13 + | +LL | let _ = std::str::from_utf8(&s.as_bytes()[test_range!(6, 11)]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(&s[test_range!(6, 11)])` + +error: aborting due to 2 previous errors diff --git a/tests/ui/transmuting_null.rs b/tests/ui/transmuting_null.rs index 0d3b26673452..00aa35dff803 100644 --- a/tests/ui/transmuting_null.rs +++ b/tests/ui/transmuting_null.rs @@ -37,8 +37,19 @@ fn transmute_const_int() { } } +fn transumute_single_expr_blocks() { + unsafe { + let _: &u64 = std::mem::transmute({ 0 as *const u64 }); + //~^ transmuting_null + + let _: &u64 = std::mem::transmute(const { u64::MIN as *const u64 }); + //~^ transmuting_null + } +} + fn main() { one_liners(); transmute_const(); transmute_const_int(); + transumute_single_expr_blocks(); } diff --git a/tests/ui/transmuting_null.stderr b/tests/ui/transmuting_null.stderr index ed7c3396a243..e1de391813bd 100644 --- a/tests/ui/transmuting_null.stderr +++ b/tests/ui/transmuting_null.stderr @@ -25,5 +25,17 @@ error: transmuting a known null pointer into a reference LL | let _: &u64 = std::mem::transmute(u64::MIN as *const u64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: transmuting a known null pointer into a reference + --> tests/ui/transmuting_null.rs:42:23 + | +LL | let _: &u64 = std::mem::transmute({ 0 as *const u64 }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: transmuting a known null pointer into a reference + --> tests/ui/transmuting_null.rs:45:23 + | +LL | let _: &u64 = std::mem::transmute(const { u64::MIN as *const u64 }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors diff --git a/tests/ui/unnecessary_fold.fixed b/tests/ui/unnecessary_fold.fixed index c3eeafbc39cd..d51359349cb9 100644 --- a/tests/ui/unnecessary_fold.fixed +++ b/tests/ui/unnecessary_fold.fixed @@ -178,4 +178,15 @@ fn issue10000() { } } +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($e:expr) => { + ($e + 1) > 2 + }; + } + + let _ = (0..3).any(|x| test_expr!(x)); + //~^ unnecessary_fold +} + fn main() {} diff --git a/tests/ui/unnecessary_fold.rs b/tests/ui/unnecessary_fold.rs index 6ab41a942625..c6eb7157ab12 100644 --- a/tests/ui/unnecessary_fold.rs +++ b/tests/ui/unnecessary_fold.rs @@ -178,4 +178,15 @@ fn issue10000() { } } +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($e:expr) => { + ($e + 1) > 2 + }; + } + + let _ = (0..3).fold(false, |acc: bool, x| acc || test_expr!(x)); + //~^ unnecessary_fold +} + fn main() {} diff --git a/tests/ui/unnecessary_fold.stderr b/tests/ui/unnecessary_fold.stderr index bb8aa7e18d34..560427a681a9 100644 --- a/tests/ui/unnecessary_fold.stderr +++ b/tests/ui/unnecessary_fold.stderr @@ -4,6 +4,7 @@ error: this `.fold` can be written more succinctly using another method LL | let _ = (0..3).fold(false, |acc, x| acc || x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)` | + = note: the `any` method is short circuiting and may change the program semantics if the iterator has side effects = note: `-D clippy::unnecessary-fold` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_fold)]` @@ -21,6 +22,8 @@ error: this `.fold` can be written more succinctly using another method | LL | let _ = (0..3).fold(true, |acc, x| acc && x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `all(|x| x > 2)` + | + = note: the `all` method is short circuiting and may change the program semantics if the iterator has side effects error: this `.fold` can be written more succinctly using another method --> tests/ui/unnecessary_fold.rs:24:25 @@ -63,12 +66,16 @@ error: this `.fold` can be written more succinctly using another method | LL | let _: bool = (0..3).map(|x| 2 * x).fold(false, |acc, x| acc || x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)` + | + = note: the `any` method is short circuiting and may change the program semantics if the iterator has side effects error: this `.fold` can be written more succinctly using another method --> tests/ui/unnecessary_fold.rs:110:10 | LL | .fold(false, |acc, x| acc || x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)` + | + = note: the `any` method is short circuiting and may change the program semantics if the iterator has side effects error: this `.fold` can be written more succinctly using another method --> tests/ui/unnecessary_fold.rs:123:33 @@ -196,5 +203,13 @@ error: this `.fold` can be written more succinctly using another method LL | (0..3).fold(1, |acc, x| acc * x) | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `product::()` -error: aborting due to 32 previous errors +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:188:20 + | +LL | let _ = (0..3).fold(false, |acc: bool, x| acc || test_expr!(x)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| test_expr!(x))` + | + = note: the `any` method is short circuiting and may change the program semantics if the iterator has side effects + +error: aborting due to 33 previous errors diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index 316eac0b58b7..590359bc1ad2 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -681,3 +681,12 @@ fn issue14833() { let mut s = HashSet::<&String>::new(); s.remove(&"hello".to_owned()); } + +#[allow(clippy::redundant_clone)] +fn issue16351() { + fn take(_: impl AsRef) {} + + let dot = "."; + take(&format!("ouch{dot}")); + //~^ unnecessary_to_owned +} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index f2dbd1db3c9f..d1e3e6497c0a 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -681,3 +681,12 @@ fn issue14833() { let mut s = HashSet::<&String>::new(); s.remove(&"hello".to_owned()); } + +#[allow(clippy::redundant_clone)] +fn issue16351() { + fn take(_: impl AsRef) {} + + let dot = "."; + take(format!("ouch{dot}").to_string()); + //~^ unnecessary_to_owned +} diff --git a/tests/ui/unnecessary_to_owned.stderr b/tests/ui/unnecessary_to_owned.stderr index 6c52be839301..50e3d5eb2195 100644 --- a/tests/ui/unnecessary_to_owned.stderr +++ b/tests/ui/unnecessary_to_owned.stderr @@ -550,5 +550,11 @@ error: unnecessary use of `to_vec` LL | s.remove(&(&["b"]).to_vec()); | ^^^^^^^^^^^^^^^^^^ help: replace it with: `(&["b"]).as_slice()` -error: aborting due to 82 previous errors +error: unnecessary use of `to_string` + --> tests/ui/unnecessary_to_owned.rs:690:10 + | +LL | take(format!("ouch{dot}").to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `&format!("ouch{dot}")` + +error: aborting due to 83 previous errors diff --git a/tests/ui/useless_conversion.fixed b/tests/ui/useless_conversion.fixed index adf5e58d9a1a..4832e922fa8e 100644 --- a/tests/ui/useless_conversion.fixed +++ b/tests/ui/useless_conversion.fixed @@ -1,4 +1,5 @@ #![deny(clippy::useless_conversion)] +#![allow(clippy::into_iter_on_ref)] #![allow(clippy::needless_ifs, clippy::unnecessary_wraps, unused)] // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint #![allow(static_mut_refs)] @@ -131,6 +132,15 @@ fn main() { dont_lint_into_iter_on_copy_iter(); dont_lint_into_iter_on_static_copy_iter(); + { + // triggers the IntoIterator trait + fn consume(_: impl IntoIterator) {} + + // Should suggest `*items` instead of `&**items` + let items = &&[1, 2, 3]; + consume(*items); //~ useless_conversion + } + let _: String = "foo".into(); let _: String = From::from("foo"); let _ = String::from("foo"); diff --git a/tests/ui/useless_conversion.rs b/tests/ui/useless_conversion.rs index d95fe49e2e2b..6ef1f93a5606 100644 --- a/tests/ui/useless_conversion.rs +++ b/tests/ui/useless_conversion.rs @@ -1,4 +1,5 @@ #![deny(clippy::useless_conversion)] +#![allow(clippy::into_iter_on_ref)] #![allow(clippy::needless_ifs, clippy::unnecessary_wraps, unused)] // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint #![allow(static_mut_refs)] @@ -131,6 +132,15 @@ fn main() { dont_lint_into_iter_on_copy_iter(); dont_lint_into_iter_on_static_copy_iter(); + { + // triggers the IntoIterator trait + fn consume(_: impl IntoIterator) {} + + // Should suggest `*items` instead of `&**items` + let items = &&[1, 2, 3]; + consume(items.into_iter()); //~ useless_conversion + } + let _: String = "foo".into(); let _: String = From::from("foo"); let _ = String::from("foo"); diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr index 052c664f6f2e..d28b7a5cbfb6 100644 --- a/tests/ui/useless_conversion.stderr +++ b/tests/ui/useless_conversion.stderr @@ -1,5 +1,5 @@ error: useless conversion to the same type: `T` - --> tests/ui/useless_conversion.rs:9:13 + --> tests/ui/useless_conversion.rs:10:13 | LL | let _ = T::from(val); | ^^^^^^^^^^^^ help: consider removing `T::from()`: `val` @@ -11,115 +11,132 @@ LL | #![deny(clippy::useless_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: useless conversion to the same type: `T` - --> tests/ui/useless_conversion.rs:11:5 + --> tests/ui/useless_conversion.rs:12:5 | LL | val.into() | ^^^^^^^^^^ help: consider removing `.into()`: `val` error: useless conversion to the same type: `i32` - --> tests/ui/useless_conversion.rs:24:22 + --> tests/ui/useless_conversion.rs:25:22 | LL | let _: i32 = 0i32.into(); | ^^^^^^^^^^^ help: consider removing `.into()`: `0i32` error: useless conversion to the same type: `std::str::Lines<'_>` - --> tests/ui/useless_conversion.rs:55:22 + --> tests/ui/useless_conversion.rs:56:22 | LL | if Some("ok") == lines.into_iter().next() {} | ^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `lines` error: useless conversion to the same type: `std::str::Lines<'_>` - --> tests/ui/useless_conversion.rs:61:21 + --> tests/ui/useless_conversion.rs:62:21 | LL | let mut lines = text.lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()` error: useless conversion to the same type: `std::str::Lines<'_>` - --> tests/ui/useless_conversion.rs:68:22 + --> tests/ui/useless_conversion.rs:69:22 | LL | if Some("ok") == text.lines().into_iter().next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()` error: useless conversion to the same type: `std::ops::Range` - --> tests/ui/useless_conversion.rs:75:13 + --> tests/ui/useless_conversion.rs:76:13 | LL | let _ = NUMBERS.into_iter().next(); | ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS` error: useless conversion to the same type: `std::ops::Range` - --> tests/ui/useless_conversion.rs:81:17 + --> tests/ui/useless_conversion.rs:82:17 | LL | let mut n = NUMBERS.into_iter(); | ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS` +error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` + --> tests/ui/useless_conversion.rs:141:17 + | +LL | consume(items.into_iter()); + | ^^^^^^^^^^^^^^^^^ + | +note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` + --> tests/ui/useless_conversion.rs:137:28 + | +LL | fn consume(_: impl IntoIterator) {} + | ^^^^^^^^^^^^ +help: consider removing the `.into_iter()` + | +LL - consume(items.into_iter()); +LL + consume(*items); + | + error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:144:21 + --> tests/ui/useless_conversion.rs:154:21 | LL | let _: String = "foo".to_string().into(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:146:21 + --> tests/ui/useless_conversion.rs:156:21 | LL | let _: String = From::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:148:13 + --> tests/ui/useless_conversion.rs:158:13 | LL | let _ = String::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:150:13 + --> tests/ui/useless_conversion.rs:160:13 | LL | let _ = String::from(format!("A: {:04}", 123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)` error: useless conversion to the same type: `std::str::Lines<'_>` - --> tests/ui/useless_conversion.rs:152:13 + --> tests/ui/useless_conversion.rs:162:13 | LL | let _ = "".lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()` error: useless conversion to the same type: `std::vec::IntoIter` - --> tests/ui/useless_conversion.rs:154:13 + --> tests/ui/useless_conversion.rs:164:13 | LL | let _ = vec![1, 2, 3].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:156:21 + --> tests/ui/useless_conversion.rs:166:21 | LL | let _: String = format!("Hello {}", "world").into(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")` error: useless conversion to the same type: `i32` - --> tests/ui/useless_conversion.rs:162:13 + --> tests/ui/useless_conversion.rs:172:13 | LL | let _ = i32::from(a + b) * 3; | ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)` error: useless conversion to the same type: `Foo<'a'>` - --> tests/ui/useless_conversion.rs:169:23 + --> tests/ui/useless_conversion.rs:179:23 | LL | let _: Foo<'a'> = s2.into(); | ^^^^^^^^^ help: consider removing `.into()`: `s2` error: useless conversion to the same type: `Foo<'a'>` - --> tests/ui/useless_conversion.rs:172:13 + --> tests/ui/useless_conversion.rs:182:13 | LL | let _ = Foo::<'a'>::from(s3); | ^^^^^^^^^^^^^^^^^^^^ help: consider removing `Foo::<'a'>::from()`: `s3` error: useless conversion to the same type: `std::vec::IntoIter>` - --> tests/ui/useless_conversion.rs:175:13 + --> tests/ui/useless_conversion.rs:185:13 | LL | let _ = vec![s4, s4, s4].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![s4, s4, s4].into_iter()` error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:208:7 + --> tests/ui/useless_conversion.rs:218:7 | LL | b(vec![1, 2].into_iter()); | ^^^^^^^^^^------------ @@ -127,13 +144,13 @@ LL | b(vec![1, 2].into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:198:13 + --> tests/ui/useless_conversion.rs:208:13 | LL | fn b>(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:210:7 + --> tests/ui/useless_conversion.rs:220:7 | LL | c(vec![1, 2].into_iter()); | ^^^^^^^^^^------------ @@ -141,13 +158,13 @@ LL | c(vec![1, 2].into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:199:18 + --> tests/ui/useless_conversion.rs:209:18 | LL | fn c(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:212:7 + --> tests/ui/useless_conversion.rs:222:7 | LL | d(vec![1, 2].into_iter()); | ^^^^^^^^^^------------ @@ -155,13 +172,13 @@ LL | d(vec![1, 2].into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:202:12 + --> tests/ui/useless_conversion.rs:212:12 | LL | T: IntoIterator, | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:216:7 + --> tests/ui/useless_conversion.rs:226:7 | LL | b(vec![1, 2].into_iter().into_iter()); | ^^^^^^^^^^------------------------ @@ -169,13 +186,13 @@ LL | b(vec![1, 2].into_iter().into_iter()); | help: consider removing the `.into_iter()`s | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:198:13 + --> tests/ui/useless_conversion.rs:208:13 | LL | fn b>(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:218:7 + --> tests/ui/useless_conversion.rs:228:7 | LL | b(vec![1, 2].into_iter().into_iter().into_iter()); | ^^^^^^^^^^------------------------------------ @@ -183,13 +200,13 @@ LL | b(vec![1, 2].into_iter().into_iter().into_iter()); | help: consider removing the `.into_iter()`s | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:198:13 + --> tests/ui/useless_conversion.rs:208:13 | LL | fn b>(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:265:24 + --> tests/ui/useless_conversion.rs:275:24 | LL | foo2::([1, 2, 3].into_iter()); | ^^^^^^^^^------------ @@ -197,13 +214,13 @@ LL | foo2::([1, 2, 3].into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:244:12 + --> tests/ui/useless_conversion.rs:254:12 | LL | I: IntoIterator + Helper, | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:274:14 + --> tests/ui/useless_conversion.rs:284:14 | LL | foo3([1, 2, 3].into_iter()); | ^^^^^^^^^------------ @@ -211,13 +228,13 @@ LL | foo3([1, 2, 3].into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:253:12 + --> tests/ui/useless_conversion.rs:263:12 | LL | I: IntoIterator, | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:284:16 + --> tests/ui/useless_conversion.rs:294:16 | LL | S1.foo([1, 2].into_iter()); | ^^^^^^------------ @@ -225,13 +242,13 @@ LL | S1.foo([1, 2].into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:281:27 + --> tests/ui/useless_conversion.rs:291:27 | LL | pub fn foo(&self, _: I) {} | ^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:304:44 + --> tests/ui/useless_conversion.rs:314:44 | LL | v0.into_iter().interleave_shortest(v1.into_iter()); | ^^------------ @@ -239,67 +256,67 @@ LL | v0.into_iter().interleave_shortest(v1.into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:291:20 + --> tests/ui/useless_conversion.rs:301:20 | LL | J: IntoIterator, | ^^^^^^^^^^^^ error: useless conversion to the same type: `()` - --> tests/ui/useless_conversion.rs:332:58 + --> tests/ui/useless_conversion.rs:342:58 | LL | let _: Result<(), std::io::Error> = test_issue_3913().map(Into::into); | ^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `std::io::Error` - --> tests/ui/useless_conversion.rs:335:58 + --> tests/ui/useless_conversion.rs:345:58 | LL | let _: Result<(), std::io::Error> = test_issue_3913().map_err(Into::into); | ^^^^^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `()` - --> tests/ui/useless_conversion.rs:338:58 + --> tests/ui/useless_conversion.rs:348:58 | LL | let _: Result<(), std::io::Error> = test_issue_3913().map(From::from); | ^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `std::io::Error` - --> tests/ui/useless_conversion.rs:341:58 + --> tests/ui/useless_conversion.rs:351:58 | LL | let _: Result<(), std::io::Error> = test_issue_3913().map_err(From::from); | ^^^^^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `()` - --> tests/ui/useless_conversion.rs:345:31 + --> tests/ui/useless_conversion.rs:355:31 | LL | let _: ControlFlow<()> = c.map_break(Into::into); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `()` - --> tests/ui/useless_conversion.rs:349:31 + --> tests/ui/useless_conversion.rs:359:31 | LL | let _: ControlFlow<()> = c.map_continue(Into::into); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `u32` - --> tests/ui/useless_conversion.rs:363:41 + --> tests/ui/useless_conversion.rs:373:41 | LL | let _: Vec = [1u32].into_iter().map(Into::into).collect(); | ^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `T` - --> tests/ui/useless_conversion.rs:374:18 + --> tests/ui/useless_conversion.rs:384:18 | LL | x.into_iter().map(Into::into).collect() | ^^^^^^^^^^^^^^^^ help: consider removing error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:390:29 + --> tests/ui/useless_conversion.rs:400:29 | LL | takes_into_iter(self.my_field.into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:379:32 + --> tests/ui/useless_conversion.rs:389:32 | LL | fn takes_into_iter(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -310,13 +327,13 @@ LL + takes_into_iter(&self.my_field); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:398:29 + --> tests/ui/useless_conversion.rs:408:29 | LL | takes_into_iter(self.my_field.into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:379:32 + --> tests/ui/useless_conversion.rs:389:32 | LL | fn takes_into_iter(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -327,13 +344,13 @@ LL + takes_into_iter(&mut self.my_field); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:407:29 + --> tests/ui/useless_conversion.rs:417:29 | LL | takes_into_iter(self.my_field.into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:379:32 + --> tests/ui/useless_conversion.rs:389:32 | LL | fn takes_into_iter(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -344,13 +361,13 @@ LL + takes_into_iter(*self.my_field); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:416:29 + --> tests/ui/useless_conversion.rs:426:29 | LL | takes_into_iter(self.my_field.into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:379:32 + --> tests/ui/useless_conversion.rs:389:32 | LL | fn takes_into_iter(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -361,13 +378,13 @@ LL + takes_into_iter(&*self.my_field); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:425:29 + --> tests/ui/useless_conversion.rs:435:29 | LL | takes_into_iter(self.my_field.into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:379:32 + --> tests/ui/useless_conversion.rs:389:32 | LL | fn takes_into_iter(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -378,22 +395,22 @@ LL + takes_into_iter(&mut *self.my_field); | error: useless conversion to the same type: `std::ops::Range` - --> tests/ui/useless_conversion.rs:440:5 + --> tests/ui/useless_conversion.rs:450:5 | LL | R.into_iter().for_each(|_x| {}); | ^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `R` error: useless conversion to the same type: `std::ops::Range` - --> tests/ui/useless_conversion.rs:442:13 + --> tests/ui/useless_conversion.rs:452:13 | LL | let _ = R.into_iter().map(|_x| 0); | ^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `R` error: useless conversion to the same type: `std::slice::Iter<'_, i32>` - --> tests/ui/useless_conversion.rs:453:14 + --> tests/ui/useless_conversion.rs:463:14 | LL | for _ in mac!(iter [1, 2]).into_iter() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `mac!(iter [1, 2])` -error: aborting due to 44 previous errors +error: aborting due to 45 previous errors diff --git a/triagebot.toml b/triagebot.toml index 5f637205fa65..09dec7675e7e 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -63,7 +63,6 @@ users_on_vacation = [ "Alexendoo", "y21", "blyxyas", - "samueltardieu", ] [assign.owners] From a3690a2d25d564df5b86742a5be3bb0799a27926 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Thu, 8 Jan 2026 19:08:01 +0100 Subject: [PATCH 0471/1061] Make Clippy compile with `ConstArgKind::Tup()` --- src/tools/clippy/clippy_lints/src/large_include_file.rs | 1 - src/tools/clippy/clippy_lints/src/utils/author.rs | 1 + src/tools/clippy/clippy_utils/src/consts.rs | 1 + src/tools/clippy/clippy_utils/src/hir_utils.rs | 8 ++++++++ 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/tools/clippy/clippy_lints/src/large_include_file.rs b/src/tools/clippy/clippy_lints/src/large_include_file.rs index d77e0beeaf4c..54599499515e 100644 --- a/src/tools/clippy/clippy_lints/src/large_include_file.rs +++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs @@ -1,4 +1,3 @@ -use rustc_ast::AttrItemKind; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::root_macro_call_first_node; diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 58b153f06545..acea701b2e83 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -323,6 +323,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { ConstArgKind::TupleCall(..) => chain!(self, "let ConstArgKind::TupleCall(..) = {const_arg}.kind"), ConstArgKind::Infer(..) => chain!(self, "let ConstArgKind::Infer(..) = {const_arg}.kind"), ConstArgKind::Error(..) => chain!(self, "let ConstArgKind::Error(..) = {const_arg}.kind"), + ConstArgKind::Tup(..) => chain!(self, "let ConstArgKind::Tup(..) = {const_arg}.kind"), ConstArgKind::Literal(..) => chain!(self, "let ConstArgKind::Literal(..) = {const_arg}.kind") } } diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 334cc6bb5d55..e4f76cf4ed57 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -1141,6 +1141,7 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx ConstItemRhs::TypeConst(const_arg) => match const_arg.kind { ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value), ConstArgKind::Struct(..) + | ConstArgKind::Tup(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 73b1cbb21548..82a12fc51c9a 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -666,6 +666,8 @@ impl HirEqInterExpr<'_, '_, '_> { } match (&left.kind, &right.kind) { + (ConstArgKind::Tup(l_t), ConstArgKind::Tup(r_t)) => + l_t.len() == r_t.len() && l_t.iter().zip(*r_t).all(|(l_c, r_c)| self.eq_const_arg(*l_c, *r_c)), (ConstArgKind::Path(l_p), ConstArgKind::Path(r_p)) => self.eq_qpath(l_p, r_p), (ConstArgKind::Anon(l_an), ConstArgKind::Anon(r_an)) => self.eq_body(l_an.body, r_an.body), (ConstArgKind::Infer(..), ConstArgKind::Infer(..)) => true, @@ -695,6 +697,7 @@ impl HirEqInterExpr<'_, '_, '_> { // Use explicit match for now since ConstArg is undergoing flux. ( ConstArgKind::Path(..) + | ConstArgKind::Tup(..) | ConstArgKind::Anon(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Tup(..) @@ -1561,6 +1564,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { fn hash_const_arg(&mut self, const_arg: &ConstArg<'_>) { match &const_arg.kind { + ConstArgKind::Tup(tup) => { + for arg in *tup { + self.hash_const_arg(*arg); + } + }, ConstArgKind::Path(path) => self.hash_qpath(path), ConstArgKind::Anon(anon) => self.hash_body(anon.body), ConstArgKind::Struct(path, inits) => { From 7c3cc4f3ef6d936a11f19857984b06baa1a04d10 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Thu, 8 Jan 2026 19:08:01 +0100 Subject: [PATCH 0472/1061] Make Clippy compile with `ConstArgKind::Tup()` --- clippy_lints/src/large_include_file.rs | 1 - clippy_lints/src/utils/author.rs | 1 + clippy_utils/src/consts.rs | 1 + clippy_utils/src/hir_utils.rs | 8 ++++++++ 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/large_include_file.rs b/clippy_lints/src/large_include_file.rs index d77e0beeaf4c..54599499515e 100644 --- a/clippy_lints/src/large_include_file.rs +++ b/clippy_lints/src/large_include_file.rs @@ -1,4 +1,3 @@ -use rustc_ast::AttrItemKind; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::root_macro_call_first_node; diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 58b153f06545..acea701b2e83 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -323,6 +323,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { ConstArgKind::TupleCall(..) => chain!(self, "let ConstArgKind::TupleCall(..) = {const_arg}.kind"), ConstArgKind::Infer(..) => chain!(self, "let ConstArgKind::Infer(..) = {const_arg}.kind"), ConstArgKind::Error(..) => chain!(self, "let ConstArgKind::Error(..) = {const_arg}.kind"), + ConstArgKind::Tup(..) => chain!(self, "let ConstArgKind::Tup(..) = {const_arg}.kind"), ConstArgKind::Literal(..) => chain!(self, "let ConstArgKind::Literal(..) = {const_arg}.kind") } } diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 334cc6bb5d55..e4f76cf4ed57 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -1141,6 +1141,7 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx ConstItemRhs::TypeConst(const_arg) => match const_arg.kind { ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value), ConstArgKind::Struct(..) + | ConstArgKind::Tup(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 73b1cbb21548..82a12fc51c9a 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -666,6 +666,8 @@ impl HirEqInterExpr<'_, '_, '_> { } match (&left.kind, &right.kind) { + (ConstArgKind::Tup(l_t), ConstArgKind::Tup(r_t)) => + l_t.len() == r_t.len() && l_t.iter().zip(*r_t).all(|(l_c, r_c)| self.eq_const_arg(*l_c, *r_c)), (ConstArgKind::Path(l_p), ConstArgKind::Path(r_p)) => self.eq_qpath(l_p, r_p), (ConstArgKind::Anon(l_an), ConstArgKind::Anon(r_an)) => self.eq_body(l_an.body, r_an.body), (ConstArgKind::Infer(..), ConstArgKind::Infer(..)) => true, @@ -695,6 +697,7 @@ impl HirEqInterExpr<'_, '_, '_> { // Use explicit match for now since ConstArg is undergoing flux. ( ConstArgKind::Path(..) + | ConstArgKind::Tup(..) | ConstArgKind::Anon(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Tup(..) @@ -1561,6 +1564,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { fn hash_const_arg(&mut self, const_arg: &ConstArg<'_>) { match &const_arg.kind { + ConstArgKind::Tup(tup) => { + for arg in *tup { + self.hash_const_arg(*arg); + } + }, ConstArgKind::Path(path) => self.hash_qpath(path), ConstArgKind::Anon(anon) => self.hash_body(anon.body), ConstArgKind::Struct(path, inits) => { From d28379895b67641408adad95dc69d1e45f1a8a1b Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Fri, 9 Jan 2026 10:39:33 +0100 Subject: [PATCH 0473/1061] Update Cargo.lock --- Cargo.lock | 52 +++++----------------------------------------------- 1 file changed, 5 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c1bf48f704ab..9c791babc399 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -182,19 +182,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" -[[package]] -name = "askama" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4" -dependencies = [ - "askama_derive 0.14.0", - "itoa", - "percent-encoding", - "serde", - "serde_json", -] - [[package]] name = "askama" version = "0.15.1" @@ -208,30 +195,13 @@ dependencies = [ "serde_json", ] -[[package]] -name = "askama_derive" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f" -dependencies = [ - "askama_parser 0.14.0", - "basic-toml", - "memchr", - "proc-macro2", - "quote", - "rustc-hash 2.1.1", - "serde", - "serde_derive", - "syn 2.0.110", -] - [[package]] name = "askama_derive" version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ba5e7259a1580c61571e3116ebaaa01e3c001b2132b17c4cc5c70780ca3e994" dependencies = [ - "askama_parser 0.15.1", + "askama_parser", "basic-toml", "memchr", "proc-macro2", @@ -248,19 +218,7 @@ version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "236ce20b77cb13506eaf5024899f4af6e12e8825f390bd943c4c37fd8f322e46" dependencies = [ - "askama_derive 0.15.1", -] - -[[package]] -name = "askama_parser" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358" -dependencies = [ - "memchr", - "serde", - "serde_derive", - "winnow 0.7.13", + "askama_derive", ] [[package]] @@ -675,7 +633,7 @@ name = "clippy" version = "0.1.94" dependencies = [ "anstream", - "askama 0.14.0", + "askama", "cargo_metadata 0.18.1", "clippy_config", "clippy_lints", @@ -1566,7 +1524,7 @@ name = "generate-copyright" version = "0.1.0" dependencies = [ "anyhow", - "askama 0.15.1", + "askama", "cargo_metadata 0.21.0", "serde", "serde_json", @@ -4913,7 +4871,7 @@ name = "rustdoc" version = "0.0.0" dependencies = [ "arrayvec", - "askama 0.15.1", + "askama", "base64", "expect-test", "indexmap", From 91d4e40e0220cfe7a498f416499adf3ffd6e5c38 Mon Sep 17 00:00:00 2001 From: Flakebi Date: Fri, 9 Jan 2026 10:41:37 +0100 Subject: [PATCH 0474/1061] Add amdgpu_dispatch_ptr intrinsic Add a rustc intrinsic `amdgpu_dispatch_ptr` to access the kernel dispatch packet on amdgpu. The HSA kernel dispatch packet contains important information like the launch size and workgroup size. The Rust intrinsic lowers to the `llvm.amdgcn.dispatch.ptr` LLVM intrinsic, which returns a `ptr addrspace(4)`, plus an addrspacecast to `addrspace(0)`, so it can be returned as a Rust reference. The returned pointer/reference is valid for the whole program lifetime, and is therefore `'static`. The return type of the intrinsic (`*const ()`) does not mention the struct so that rustc does not need to know the exact struct type. An alternative would be to define the struct as lang item or add a generic argument to the function. Short version: ```rust #[cfg(target_arch = "amdgpu")] pub fn amdgpu_dispatch_ptr() -> *const (); ``` --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 6 +++++ .../rustc_codegen_ssa/src/mir/intrinsic.rs | 1 + .../rustc_hir_analysis/src/check/intrinsic.rs | 2 ++ compiler/rustc_span/src/symbol.rs | 1 + library/core/src/intrinsics/gpu.rs | 23 ++++++++++++++++ library/core/src/intrinsics/mod.rs | 1 + tests/codegen-llvm/amdgpu-dispatch-ptr.rs | 27 +++++++++++++++++++ 7 files changed, 61 insertions(+) create mode 100644 library/core/src/intrinsics/gpu.rs create mode 100644 tests/codegen-llvm/amdgpu-dispatch-ptr.rs diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index b4057eea735e..8803963f4bd3 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -560,6 +560,12 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { return Ok(()); } + sym::amdgpu_dispatch_ptr => { + let val = self.call_intrinsic("llvm.amdgcn.dispatch.ptr", &[], &[]); + // Relying on `LLVMBuildPointerCast` to produce an addrspacecast + self.pointercast(val, self.type_ptr()) + } + _ if name.as_str().starts_with("simd_") => { // Unpack non-power-of-2 #[repr(packed, simd)] arguments. // This gives them the expected layout of a regular #[repr(simd)] vector. diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index f4fae40d8828..f5ee9406f4bf 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -112,6 +112,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { | sym::unreachable | sym::cold_path | sym::breakpoint + | sym::amdgpu_dispatch_ptr | sym::assert_zero_valid | sym::assert_mem_uninitialized_valid | sym::assert_inhabited diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 4e8333f678b6..d4c4a73e64a2 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -70,6 +70,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::add_with_overflow | sym::aggregate_raw_ptr | sym::align_of + | sym::amdgpu_dispatch_ptr | sym::assert_inhabited | sym::assert_mem_uninitialized_valid | sym::assert_zero_valid @@ -285,6 +286,7 @@ pub(crate) fn check_intrinsic_type( let (n_tps, n_cts, inputs, output) = match intrinsic_name { sym::autodiff => (4, 0, vec![param(0), param(1), param(2)], param(3)), sym::abort => (0, 0, vec![], tcx.types.never), + sym::amdgpu_dispatch_ptr => (0, 0, vec![], Ty::new_imm_ptr(tcx, tcx.types.unit)), sym::unreachable => (0, 0, vec![], tcx.types.never), sym::breakpoint => (0, 0, vec![], tcx.types.unit), sym::size_of | sym::align_of | sym::variant_count => (1, 0, vec![], tcx.types.usize), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 72709753b1df..676e9a9ae042 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -454,6 +454,7 @@ symbols! { alu32, always, amdgpu, + amdgpu_dispatch_ptr, analysis, and, and_then, diff --git a/library/core/src/intrinsics/gpu.rs b/library/core/src/intrinsics/gpu.rs new file mode 100644 index 000000000000..9e7624841d0c --- /dev/null +++ b/library/core/src/intrinsics/gpu.rs @@ -0,0 +1,23 @@ +//! Intrinsics for GPU targets. +//! +//! Intrinsics in this module are intended for use on GPU targets. +//! They can be target specific but in general GPU targets are similar. + +#![unstable(feature = "gpu_intrinsics", issue = "none")] + +/// Returns a pointer to the HSA kernel dispatch packet. +/// +/// A `gpu-kernel` on amdgpu is always launched through a kernel dispatch packet. +/// The dispatch packet contains the workgroup size, launch size and other data. +/// The content is defined by the [HSA Platform System Architecture Specification], +/// which is implemented e.g. in AMD's [hsa.h]. +/// The intrinsic returns a unit pointer so that rustc does not need to know the packet struct. +/// The pointer is valid for the whole lifetime of the program. +/// +/// [HSA Platform System Architecture Specification]: https://hsafoundation.com/wp-content/uploads/2021/02/HSA-SysArch-1.2.pdf +/// [hsa.h]: https://github.com/ROCm/rocm-systems/blob/rocm-7.1.0/projects/rocr-runtime/runtime/hsa-runtime/inc/hsa.h#L2959 +#[rustc_nounwind] +#[rustc_intrinsic] +#[cfg(target_arch = "amdgpu")] +#[must_use = "returns a pointer that does nothing unless used"] +pub fn amdgpu_dispatch_ptr() -> *const (); diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index d46d3ed9d513..0c26aba8618e 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -60,6 +60,7 @@ use crate::{mem, ptr}; mod bounds; pub mod fallback; +pub mod gpu; pub mod mir; pub mod simd; diff --git a/tests/codegen-llvm/amdgpu-dispatch-ptr.rs b/tests/codegen-llvm/amdgpu-dispatch-ptr.rs new file mode 100644 index 000000000000..00bde96c3d59 --- /dev/null +++ b/tests/codegen-llvm/amdgpu-dispatch-ptr.rs @@ -0,0 +1,27 @@ +// Tests the amdgpu_dispatch_ptr intrinsic. + +//@ compile-flags: --crate-type=rlib --target amdgcn-amd-amdhsa -Ctarget-cpu=gfx900 +//@ needs-llvm-components: amdgpu +//@ add-minicore +#![feature(intrinsics, no_core, rustc_attrs)] +#![no_core] + +extern crate minicore; + +pub struct DispatchPacket { + pub header: u16, + pub setup: u16, + pub workgroup_size_x: u16, // and more +} + +#[rustc_intrinsic] +#[rustc_nounwind] +fn amdgpu_dispatch_ptr() -> *const (); + +// CHECK-LABEL: @get_dispatch_data +// CHECK: %[[ORIG_PTR:[^ ]+]] = {{(tail )?}}call ptr addrspace(4) @llvm.amdgcn.dispatch.ptr() +// CHECK-NEXT: %[[PTR:[^ ]+]] = addrspacecast ptr addrspace(4) %[[ORIG_PTR]] to ptr +#[unsafe(no_mangle)] +pub fn get_dispatch_data() -> &'static DispatchPacket { + unsafe { &*(amdgpu_dispatch_ptr() as *const _) } +} From b9ae4f7bf7dc4f4a7c8a8cc934522093d6868bf7 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Fri, 9 Jan 2026 08:55:02 +0100 Subject: [PATCH 0475/1061] rustdoc_json: Remove one call to `std::mem::take` in `after_krate`. This patch removes one call to `std::mem::take` to save two `memcpy`s: `JsonRenderer::index` can be quite large as noted https://github.com/rust-lang/rust/pull/142335. `self.index` can be passed directly to `types::Crate`. This removal makes `self` immutable. The private `serialize_and_write` method is moved as a function: the `self` argument is replaced by `sess: &Session`. This `&Session` was fetched earlier in `after_krate` in all cases. This change allows to call `serialize_and_write` after `output_crate` is created, without having a conflict around the move of `self`: the borrow checker is now happy. --- src/librustdoc/json/mod.rs | 48 +++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 37d456ae796b..a201f661d9f7 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -104,22 +104,6 @@ impl<'tcx> JsonRenderer<'tcx> { }) .unwrap_or_default() } - - fn serialize_and_write( - &self, - output_crate: types::Crate, - mut writer: BufWriter, - path: &str, - ) -> Result<(), Error> { - self.sess().time("rustdoc_json_serialize_and_write", || { - try_err!( - serde_json::ser::to_writer(&mut writer, &output_crate).map_err(|e| e.to_string()), - path - ); - try_err!(writer.flush(), path); - Ok(()) - }) - } } impl<'tcx> JsonRenderer<'tcx> { @@ -252,26 +236,23 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { unreachable!("RUN_ON_MODULE = false, should never call mod_item_in") } - fn after_krate(mut self) -> Result<(), Error> { + fn after_krate(self) -> Result<(), Error> { debug!("Done with crate"); let e = ExternalCrate { crate_num: LOCAL_CRATE }; - - // We've finished using the index, and don't want to clone it, because it is big. - let index = std::mem::take(&mut self.index); + let sess = self.sess(); // Note that tcx.rust_target_features is inappropriate here because rustdoc tries to run for // multiple targets: https://github.com/rust-lang/rust/pull/137632 // // We want to describe a single target, so pass tcx.sess rather than tcx. - let target = conversions::target(self.tcx.sess); + let target = conversions::target(sess); debug!("Constructing Output"); let output_crate = types::Crate { root: self.id_from_item_default(e.def_id().into()), crate_version: self.cache.crate_version.clone(), includes_private: self.cache.document_private, - index, paths: self .cache .paths @@ -313,6 +294,8 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { ) }) .collect(), + // Be careful to not clone the `index`, it is big. + index: self.index, target, format_version: types::FORMAT_VERSION, }; @@ -323,17 +306,34 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { p.push(output_crate.index.get(&output_crate.root).unwrap().name.clone().unwrap()); p.set_extension("json"); - self.serialize_and_write( + serialize_and_write( + sess, output_crate, try_err!(File::create_buffered(&p), p), &p.display().to_string(), ) } else { - self.serialize_and_write(output_crate, BufWriter::new(stdout().lock()), "") + serialize_and_write(sess, output_crate, BufWriter::new(stdout().lock()), "") } } } +fn serialize_and_write( + sess: &Session, + output_crate: types::Crate, + mut writer: BufWriter, + path: &str, +) -> Result<(), Error> { + sess.time("rustdoc_json_serialize_and_write", || { + try_err!( + serde_json::ser::to_writer(&mut writer, &output_crate).map_err(|e| e.to_string()), + path + ); + try_err!(writer.flush(), path); + Ok(()) + }) +} + // Some nodes are used a lot. Make sure they don't unintentionally get bigger. // // These assertions are here, not in `src/rustdoc-json-types/lib.rs` where the types are defined, From 330358a197e1a6df060a19ccb3b69f29006ba395 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Fri, 9 Jan 2026 11:59:23 +0100 Subject: [PATCH 0476/1061] Further Clippy fixes for Tup/Literal ConstArgKind --- src/tools/clippy/clippy_utils/src/consts.rs | 1 + .../clippy/clippy_utils/src/hir_utils.rs | 23 ++++--------------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index e4f76cf4ed57..538f1fd2628c 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -1142,6 +1142,7 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value), ConstArgKind::Struct(..) | ConstArgKind::Tup(..) + | ConstArgKind::Literal(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 82a12fc51c9a..0bb641568879 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -666,8 +666,9 @@ impl HirEqInterExpr<'_, '_, '_> { } match (&left.kind, &right.kind) { - (ConstArgKind::Tup(l_t), ConstArgKind::Tup(r_t)) => - l_t.len() == r_t.len() && l_t.iter().zip(*r_t).all(|(l_c, r_c)| self.eq_const_arg(*l_c, *r_c)), + (ConstArgKind::Tup(l_t), ConstArgKind::Tup(r_t)) => { + l_t.len() == r_t.len() && l_t.iter().zip(*r_t).all(|(l_c, r_c)| self.eq_const_arg(*l_c, *r_c)) + }, (ConstArgKind::Path(l_p), ConstArgKind::Path(r_p)) => self.eq_qpath(l_p, r_p), (ConstArgKind::Anon(l_an), ConstArgKind::Anon(r_an)) => self.eq_body(l_an.body, r_an.body), (ConstArgKind::Infer(..), ConstArgKind::Infer(..)) => true, @@ -684,23 +685,14 @@ impl HirEqInterExpr<'_, '_, '_> { .iter() .zip(*args_b) .all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b)) - } - (ConstArgKind::Tup(args_a), ConstArgKind::Tup(args_b)) => { - args_a - .iter() - .zip(*args_b) - .all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b)) - }, - (ConstArgKind::Literal(kind_l), ConstArgKind::Literal(kind_r)) => { - kind_l == kind_r }, + (ConstArgKind::Literal(kind_l), ConstArgKind::Literal(kind_r)) => kind_l == kind_r, // Use explicit match for now since ConstArg is undergoing flux. ( ConstArgKind::Path(..) | ConstArgKind::Tup(..) | ConstArgKind::Anon(..) | ConstArgKind::TupleCall(..) - | ConstArgKind::Tup(..) | ConstArgKind::Infer(..) | ConstArgKind::Struct(..) | ConstArgKind::Literal(..) @@ -1583,13 +1575,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_const_arg(arg); } }, - ConstArgKind::Tup(args) => { - for arg in *args { - self.hash_const_arg(arg); - } - }, ConstArgKind::Infer(..) | ConstArgKind::Error(..) => {}, - ConstArgKind::Literal(lit) => lit.hash(&mut self.s) + ConstArgKind::Literal(lit) => lit.hash(&mut self.s), } } From 697e9e2aacecaa6a610ab310b9af54a732903d21 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Fri, 9 Jan 2026 11:59:23 +0100 Subject: [PATCH 0477/1061] Further Clippy fixes for Tup/Literal ConstArgKind --- clippy_utils/src/consts.rs | 1 + clippy_utils/src/hir_utils.rs | 23 +++++------------------ 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index e4f76cf4ed57..538f1fd2628c 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -1142,6 +1142,7 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value), ConstArgKind::Struct(..) | ConstArgKind::Tup(..) + | ConstArgKind::Literal(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 82a12fc51c9a..0bb641568879 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -666,8 +666,9 @@ impl HirEqInterExpr<'_, '_, '_> { } match (&left.kind, &right.kind) { - (ConstArgKind::Tup(l_t), ConstArgKind::Tup(r_t)) => - l_t.len() == r_t.len() && l_t.iter().zip(*r_t).all(|(l_c, r_c)| self.eq_const_arg(*l_c, *r_c)), + (ConstArgKind::Tup(l_t), ConstArgKind::Tup(r_t)) => { + l_t.len() == r_t.len() && l_t.iter().zip(*r_t).all(|(l_c, r_c)| self.eq_const_arg(*l_c, *r_c)) + }, (ConstArgKind::Path(l_p), ConstArgKind::Path(r_p)) => self.eq_qpath(l_p, r_p), (ConstArgKind::Anon(l_an), ConstArgKind::Anon(r_an)) => self.eq_body(l_an.body, r_an.body), (ConstArgKind::Infer(..), ConstArgKind::Infer(..)) => true, @@ -684,23 +685,14 @@ impl HirEqInterExpr<'_, '_, '_> { .iter() .zip(*args_b) .all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b)) - } - (ConstArgKind::Tup(args_a), ConstArgKind::Tup(args_b)) => { - args_a - .iter() - .zip(*args_b) - .all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b)) - }, - (ConstArgKind::Literal(kind_l), ConstArgKind::Literal(kind_r)) => { - kind_l == kind_r }, + (ConstArgKind::Literal(kind_l), ConstArgKind::Literal(kind_r)) => kind_l == kind_r, // Use explicit match for now since ConstArg is undergoing flux. ( ConstArgKind::Path(..) | ConstArgKind::Tup(..) | ConstArgKind::Anon(..) | ConstArgKind::TupleCall(..) - | ConstArgKind::Tup(..) | ConstArgKind::Infer(..) | ConstArgKind::Struct(..) | ConstArgKind::Literal(..) @@ -1583,13 +1575,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_const_arg(arg); } }, - ConstArgKind::Tup(args) => { - for arg in *args { - self.hash_const_arg(arg); - } - }, ConstArgKind::Infer(..) | ConstArgKind::Error(..) => {}, - ConstArgKind::Literal(lit) => lit.hash(&mut self.s) + ConstArgKind::Literal(lit) => lit.hash(&mut self.s), } } From fb296d7a04ba42e723aa082d4ef9f96105dd1da0 Mon Sep 17 00:00:00 2001 From: Asger Hautop Drewsen Date: Fri, 9 Jan 2026 12:52:25 +0100 Subject: [PATCH 0478/1061] Use f64 NaN in documentation instead of sqrt(-1.0) --- library/core/src/cmp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index feb9c4319604..d61e1071db8b 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1186,7 +1186,7 @@ pub macro Ord($item:item) { /// every `a`. This isn't always the case for types that implement `PartialOrd`, for example: /// /// ``` -/// let a = f64::sqrt(-1.0); +/// let a = f64::NAN; /// assert_eq!(a <= a, false); /// ``` /// From 87d716701e83e39a0c9416ca1c54e14b66202260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 9 Jan 2026 14:35:15 +0100 Subject: [PATCH 0479/1061] Reenable GCC CI download --- src/ci/run.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ci/run.sh b/src/ci/run.sh index 425ad38a6655..b486f0525f40 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -187,9 +187,8 @@ else RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set llvm.static-libstdcpp" fi - # Download GCC from CI on test builders (temporarily disabled because the CI gcc component - # was renamed). - RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set gcc.download-ci-gcc=false" + # Download GCC from CI on test builders + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set gcc.download-ci-gcc=true" # download-rustc seems to be broken on CI after the stage0 redesign # Disable it until these issues are debugged and resolved From 58a9fdded8b4f38dfb88da3793bf5750bb136ee1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 9 Jan 2026 14:36:24 +0100 Subject: [PATCH 0480/1061] Bump `download-ci-gcc-stamp` --- src/bootstrap/download-ci-gcc-stamp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/download-ci-gcc-stamp b/src/bootstrap/download-ci-gcc-stamp index bbe26afc9526..ec8d0fa3135d 100644 --- a/src/bootstrap/download-ci-gcc-stamp +++ b/src/bootstrap/download-ci-gcc-stamp @@ -1,4 +1,4 @@ Change this file to make users of the `download-ci-gcc` configuration download a new version of GCC from CI, even if the GCC submodule hasn’t changed. -Last change is for: https://github.com/rust-lang/rust/pull/138051 +Last change is for: https://github.com/rust-lang/rust/pull/150873 From 5af08c0c28c97f03e2d89356cfd6d569dd18d24b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 9 Jan 2026 14:40:54 +0100 Subject: [PATCH 0481/1061] Ignore `rustc-src-gpl` in fast try builds --- src/tools/opt-dist/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs index b17cfb567e5b..b52dab001ef5 100644 --- a/src/tools/opt-dist/src/main.rs +++ b/src/tools/opt-dist/src/main.rs @@ -450,6 +450,7 @@ fn main() -> anyhow::Result<()> { "rust-docs-json", "rust-analyzer", "rustc-src", + "rustc-src-gpl", "extended", "clippy", "miri", From 01e8f14867ec14591aa73269c8744cbbe9f69645 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 9 Jan 2026 15:03:33 +0100 Subject: [PATCH 0482/1061] Mention that `rustc_codegen_gcc` is a subtree in `rustc-dev-guide` --- src/doc/rustc-dev-guide/src/external-repos.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/external-repos.md b/src/doc/rustc-dev-guide/src/external-repos.md index d2b4e791df0e..c43c1f680acf 100644 --- a/src/doc/rustc-dev-guide/src/external-repos.md +++ b/src/doc/rustc-dev-guide/src/external-repos.md @@ -22,6 +22,7 @@ The following external projects are managed using some form of a `subtree`: * [rustfmt](https://github.com/rust-lang/rustfmt) * [rust-analyzer](https://github.com/rust-lang/rust-analyzer) * [rustc_codegen_cranelift](https://github.com/rust-lang/rustc_codegen_cranelift) +* [rustc_codegen_gcc](https://github.com/rust-lang/rustc_codegen_gcc) * [rustc-dev-guide](https://github.com/rust-lang/rustc-dev-guide) * [compiler-builtins](https://github.com/rust-lang/compiler-builtins) * [stdarch](https://github.com/rust-lang/stdarch) @@ -40,6 +41,7 @@ implement a new tool feature or test, that should happen in one collective rustc * `portable-simd` ([sync script](https://github.com/rust-lang/portable-simd/blob/master/subtree-sync.sh)) * `rustfmt` * `rustc_codegen_cranelift` ([sync script](https://github.com/rust-lang/rustc_codegen_cranelift/blob/113af154d459e41b3dc2c5d7d878e3d3a8f33c69/scripts/rustup.sh#L7)) + * `rustc_codegen_gcc` ([sync guide](https://github.com/rust-lang/rustc_codegen_gcc/blob/master/doc/subtree.md)) * Using the [josh](#synchronizing-a-josh-subtree) tool * `miri` * `rust-analyzer` From 47f28fc71e03e968fc3bcdab8d3a2155698fa36e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 9 Jan 2026 14:54:59 +0100 Subject: [PATCH 0483/1061] Refactor artifact keep mode in bootstrap --- src/bootstrap/src/core/build_steps/check.rs | 51 ++++++++++-- src/bootstrap/src/core/build_steps/clippy.rs | 15 ++-- src/bootstrap/src/core/build_steps/compile.rs | 77 +++++++++++-------- src/bootstrap/src/core/build_steps/test.rs | 5 +- 4 files changed, 97 insertions(+), 51 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 7da2551c76fe..f983c59f9bf8 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -4,7 +4,8 @@ use std::fs; use std::path::{Path, PathBuf}; use crate::core::build_steps::compile::{ - add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make, + ArtifactKeepMode, add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, + std_crates_for_run_make, }; use crate::core::build_steps::tool; use crate::core::build_steps::tool::{ @@ -111,8 +112,7 @@ impl Step for Std { builder.config.free_args.clone(), &check_stamp, vec![], - true, - false, + ArtifactKeepMode::OnlyRmeta, ); drop(_guard); @@ -148,7 +148,14 @@ impl Step for Std { build_compiler, target, ); - run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); + run_cargo( + builder, + cargo, + builder.config.free_args.clone(), + &stamp, + vec![], + ArtifactKeepMode::OnlyRmeta, + ); check_stamp } @@ -368,7 +375,14 @@ impl Step for Rustc { let stamp = build_stamp::librustc_stamp(builder, build_compiler, target).with_prefix("check"); - run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); + run_cargo( + builder, + cargo, + builder.config.free_args.clone(), + &stamp, + vec![], + ArtifactKeepMode::OnlyRmeta, + ); stamp } @@ -568,7 +582,14 @@ impl Step for CraneliftCodegenBackend { ) .with_prefix("check"); - run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); + run_cargo( + builder, + cargo, + builder.config.free_args.clone(), + &stamp, + vec![], + ArtifactKeepMode::OnlyRmeta, + ); } fn metadata(&self) -> Option { @@ -639,7 +660,14 @@ impl Step for GccCodegenBackend { ) .with_prefix("check"); - run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); + run_cargo( + builder, + cargo, + builder.config.free_args.clone(), + &stamp, + vec![], + ArtifactKeepMode::OnlyRmeta, + ); } fn metadata(&self) -> Option { @@ -777,7 +805,14 @@ fn run_tool_check_step( .with_prefix(&format!("{display_name}-check")); let _guard = builder.msg(builder.kind, display_name, mode, build_compiler, target); - run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); + run_cargo( + builder, + cargo, + builder.config.free_args.clone(), + &stamp, + vec![], + ArtifactKeepMode::OnlyRmeta, + ); } tool_check_step!(Rustdoc { diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 085c2d952e30..9e5bfd2e60e9 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -15,7 +15,7 @@ use build_helper::exit; -use super::compile::{run_cargo, rustc_cargo, std_cargo}; +use super::compile::{ArtifactKeepMode, run_cargo, rustc_cargo, std_cargo}; use super::tool::{SourceType, prepare_tool_cargo}; use crate::builder::{Builder, ShouldRun}; use crate::core::build_steps::check::{CompilerForCheck, prepare_compiler_for_check}; @@ -214,8 +214,7 @@ impl Step for Std { lint_args(builder, &self.config, IGNORED_RULES_FOR_STD_AND_RUSTC), &build_stamp::libstd_stamp(builder, build_compiler, target), vec![], - true, - false, + ArtifactKeepMode::OnlyRmeta, ); } @@ -309,8 +308,7 @@ impl Step for Rustc { lint_args(builder, &self.config, IGNORED_RULES_FOR_STD_AND_RUSTC), &build_stamp::librustc_stamp(builder, build_compiler, target), vec![], - true, - false, + ArtifactKeepMode::OnlyRmeta, ); } @@ -380,7 +378,7 @@ impl Step for CodegenGcc { .with_prefix("rustc_codegen_gcc-check"); let args = lint_args(builder, &self.config, &[]); - run_cargo(builder, cargo, args.clone(), &stamp, vec![], true, false); + run_cargo(builder, cargo, args.clone(), &stamp, vec![], ArtifactKeepMode::OnlyRmeta); // Same but we disable the features enabled by default. let mut cargo = prepare_tool_cargo( @@ -396,7 +394,7 @@ impl Step for CodegenGcc { self.build_compiler.configure_cargo(&mut cargo); println!("Now running clippy on `rustc_codegen_gcc` with `--no-default-features`"); cargo.arg("--no-default-features"); - run_cargo(builder, cargo, args, &stamp, vec![], true, false); + run_cargo(builder, cargo, args, &stamp, vec![], ArtifactKeepMode::OnlyRmeta); } fn metadata(&self) -> Option { @@ -478,8 +476,7 @@ macro_rules! lint_any { lint_args(builder, &self.config, &[]), &stamp, vec![], - true, - false, + ArtifactKeepMode::OnlyRmeta ); } diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 02be3f2cc735..2808c29cc6c0 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -296,8 +296,11 @@ impl Step for Std { vec![], &stamp, target_deps, - self.is_for_mir_opt_tests, // is_check - false, + if self.is_for_mir_opt_tests { + ArtifactKeepMode::OnlyRmeta + } else { + ArtifactKeepMode::OnlyRlib + }, ); builder.ensure(StdLink::from_std( @@ -1167,14 +1170,28 @@ impl Step for Rustc { target, ); let stamp = build_stamp::librustc_stamp(builder, build_compiler, target); + run_cargo( builder, cargo, vec![], &stamp, vec![], - false, - true, // Only ship rustc_driver.so and .rmeta files, not all intermediate .rlib files. + ArtifactKeepMode::Custom(Box::new(|filename| { + if filename.contains("jemalloc_sys") + || filename.contains("rustc_public_bridge") + || filename.contains("rustc_public") + { + // jemalloc_sys and rustc_public_bridge are not linked into librustc_driver.so, + // so we need to distribute them as rlib to be able to use them. + filename.ends_with(".rlib") + } else { + // Distribute the rest of the rustc crates as rmeta files only to reduce + // the tarball sizes by about 50%. The object files are linked into + // librustc_driver.so, so it is still possible to link against them. + filename.ends_with(".rmeta") + } + })), ); let target_root_dir = stamp.path().parent().unwrap(); @@ -1714,7 +1731,7 @@ impl Step for GccCodegenBackend { let _guard = builder.msg(Kind::Build, "codegen backend gcc", Mode::Codegen, build_compiler, host); - let files = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false); + let files = run_cargo(builder, cargo, vec![], &stamp, vec![], ArtifactKeepMode::OnlyRlib); GccCodegenBackendOutput { stamp: write_codegen_backend_stamp(stamp, files, builder.config.dry_run()), @@ -1790,7 +1807,7 @@ impl Step for CraneliftCodegenBackend { build_compiler, target, ); - let files = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false); + let files = run_cargo(builder, cargo, vec![], &stamp, vec![], ArtifactKeepMode::OnlyRlib); write_codegen_backend_stamp(stamp, files, builder.config.dry_run()) } @@ -2620,14 +2637,26 @@ pub fn add_to_sysroot( } } +/// Specifies which rlib/rmeta artifacts outputted by Cargo should be put into the resulting +/// build stamp, and thus be included in dist archives and copied into sysroots by default. +/// Note that some kinds of artifacts are copied automatically (e.g. native libraries). +pub enum ArtifactKeepMode { + /// Only keep .rlib files, ignore .rmeta files + OnlyRlib, + /// Only keep .rmeta files, ignore .rlib files + OnlyRmeta, + /// Custom logic for keeping an artifact + /// It receives the filename of an artifact, and returns true if it should be kept. + Custom(Box bool>), +} + pub fn run_cargo( builder: &Builder<'_>, cargo: Cargo, tail_args: Vec, stamp: &BuildStamp, additional_target_deps: Vec<(PathBuf, DependencyType)>, - is_check: bool, - rlib_only_metadata: bool, + artifact_keep_mode: ArtifactKeepMode, ) -> Vec { // `target_root_dir` looks like $dir/$target/release let target_root_dir = stamp.path().parent().unwrap(); @@ -2661,36 +2690,20 @@ pub fn run_cargo( }; for filename in filenames_vec { // Skip files like executables - let mut keep = false; - if filename.ends_with(".lib") + let keep = if filename.ends_with(".lib") || filename.ends_with(".a") || is_debug_info(&filename) || is_dylib(Path::new(&*filename)) { // Always keep native libraries, rust dylibs and debuginfo - keep = true; - } - if is_check && filename.ends_with(".rmeta") { - // During check builds we need to keep crate metadata - keep = true; - } else if rlib_only_metadata { - if filename.contains("jemalloc_sys") - || filename.contains("rustc_public_bridge") - || filename.contains("rustc_public") - { - // jemalloc_sys and rustc_public_bridge are not linked into librustc_driver.so, - // so we need to distribute them as rlib to be able to use them. - keep |= filename.ends_with(".rlib"); - } else { - // Distribute the rest of the rustc crates as rmeta files only to reduce - // the tarball sizes by about 50%. The object files are linked into - // librustc_driver.so, so it is still possible to link against them. - keep |= filename.ends_with(".rmeta"); - } + true } else { - // In all other cases keep all rlibs - keep |= filename.ends_with(".rlib"); - } + match &artifact_keep_mode { + ArtifactKeepMode::OnlyRlib => filename.ends_with(".rlib"), + ArtifactKeepMode::OnlyRmeta => filename.ends_with(".rmeta"), + ArtifactKeepMode::Custom(func) => func(&filename), + } + }; if !keep { continue; diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 7d7cfccf54e6..f3a1c6b0e3dd 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -14,7 +14,7 @@ use std::{env, fs, iter}; use build_helper::exit; -use crate::core::build_steps::compile::{Std, run_cargo}; +use crate::core::build_steps::compile::{ArtifactKeepMode, Std, run_cargo}; use crate::core::build_steps::doc::{DocumentationFormat, prepare_doc_compiler}; use crate::core::build_steps::gcc::{Gcc, GccTargetPair, add_cg_gcc_cargo_flags}; use crate::core::build_steps::llvm::get_llvm_version; @@ -2587,7 +2587,8 @@ impl BookTest { let stamp = BuildStamp::new(&builder.cargo_out(test_compiler, mode, target)) .with_prefix(PathBuf::from(dep).file_name().and_then(|v| v.to_str()).unwrap()); - let output_paths = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false); + let output_paths = + run_cargo(builder, cargo, vec![], &stamp, vec![], ArtifactKeepMode::OnlyRlib); let directories = output_paths .into_iter() .filter_map(|p| p.parent().map(ToOwned::to_owned)) From b022edce934b2fb939f876ccb78c1fb8b5bd6349 Mon Sep 17 00:00:00 2001 From: Wonko Date: Fri, 9 Jan 2026 15:17:06 +0100 Subject: [PATCH 0484/1061] add test for unstacking cognitive_complexity= attribute --- tests/ui/cognitive_complexity.rs | 25 +++++++++++++++++++++++++ tests/ui/cognitive_complexity.stderr | 18 +++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/tests/ui/cognitive_complexity.rs b/tests/ui/cognitive_complexity.rs index 8080c6775e0b..3945028f8271 100644 --- a/tests/ui/cognitive_complexity.rs +++ b/tests/ui/cognitive_complexity.rs @@ -472,3 +472,28 @@ mod issue14422 { return; } } + +#[clippy::cognitive_complexity = "1"] +mod attribute_stacking { + fn bad() { + //~^ cognitive_complexity + if true { + println!("a"); + } + } + + #[clippy::cognitive_complexity = "2"] + fn ok() { + if true { + println!("a"); + } + } + + // should revert to cognitive_complexity = "1" + fn bad_again() { + //~^ cognitive_complexity + if true { + println!("a"); + } + } +} diff --git a/tests/ui/cognitive_complexity.stderr b/tests/ui/cognitive_complexity.stderr index 67ef4e5655bd..e5f54a37229d 100644 --- a/tests/ui/cognitive_complexity.stderr +++ b/tests/ui/cognitive_complexity.stderr @@ -176,5 +176,21 @@ LL | fn bar() { | = help: you could split it up into multiple smaller functions -error: aborting due to 22 previous errors +error: the function has a cognitive complexity of (2/1) + --> tests/ui/cognitive_complexity.rs:478:8 + | +LL | fn bad() { + | ^^^ + | + = help: you could split it up into multiple smaller functions + +error: the function has a cognitive complexity of (2/1) + --> tests/ui/cognitive_complexity.rs:493:8 + | +LL | fn bad_again() { + | ^^^^^^^^^ + | + = help: you could split it up into multiple smaller functions + +error: aborting due to 24 previous errors From 13b82eb615c68c71baf85ea8dcfbcab51a1dce1a Mon Sep 17 00:00:00 2001 From: Wonko Date: Fri, 9 Jan 2026 13:43:55 +0100 Subject: [PATCH 0485/1061] Fix LimitStack::pop_attrs in release mode The `LimitStack::pop_attrs` function used to pop from the stack in `debug_assert_eq!` and check the value. The `pop` operation was therefore only executed in debug builds, leading to an unbalanced stack in release builds when attributes were present. This change ensures the `pop` operation is always executed, by moving it out of the debug-only assertion. The assertion is kept for debug builds. changelog: fix unbalanced stack in attributes --- clippy_utils/src/attrs.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 32f6cb4fd5e9..56490cfc8b65 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -159,7 +159,10 @@ impl LimitStack { } pub fn pop_attrs(&mut self, sess: &Session, attrs: &[impl AttributeExt], name: Symbol) { let stack = &mut self.stack; - parse_attrs(sess, attrs, name, |val| debug_assert_eq!(stack.pop(), Some(val))); + parse_attrs(sess, attrs, name, |val| { + let popped = stack.pop(); + debug_assert_eq!(popped, Some(val)); + }); } } From e0324b527e2ca5976adb9d813df9e271f3402867 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 9 Jan 2026 14:44:51 +0000 Subject: [PATCH 0486/1061] Emit an error for linking staticlibs on BPF Rather than panicking. --- compiler/rustc_codegen_ssa/messages.ftl | 2 ++ compiler/rustc_codegen_ssa/src/back/linker.rs | 2 +- compiler/rustc_codegen_ssa/src/errors.rs | 4 ++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 1d87dc5da8d2..4875f309cca5 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -10,6 +10,8 @@ codegen_ssa_archive_build_failure = failed to build archive at `{$path}`: {$erro codegen_ssa_binary_output_to_tty = option `-o` or `--emit` is used to write binary output type `{$shorthand}` to stdout, but stdout is a tty +codegen_ssa_bpf_staticlib_not_supported = linking static libraries is not supported for BPF + codegen_ssa_cgu_not_recorded = CGU-reuse for `{$cgu_user_name}` is (mangled: `{$cgu_name}`) was not recorded diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index b47652092ed5..637d54dd06c6 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -2075,7 +2075,7 @@ impl<'a> Linker for BpfLinker<'a> { } fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) { - panic!("staticlibs not supported") + self.sess.dcx().emit_fatal(errors::BpfStaticlibNotSupported) } fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 95306c140895..f57c37ca7929 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -713,6 +713,10 @@ pub struct UnknownArchiveKind<'a> { pub kind: &'a str, } +#[derive(Diagnostic)] +#[diag(codegen_ssa_bpf_staticlib_not_supported)] +pub(crate) struct BpfStaticlibNotSupported; + #[derive(Diagnostic)] #[diag(codegen_ssa_multiple_main_functions)] #[help] From 90c84d0aaea127743b248552c8ab793f5c0f9429 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 9 Jan 2026 14:45:25 +0000 Subject: [PATCH 0487/1061] Reduce visibility of some errors --- compiler/rustc_codegen_ssa/src/back/archive.rs | 7 ++++--- compiler/rustc_codegen_ssa/src/errors.rs | 8 +++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 93f6cb3b87e6..3f12e857391b 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -22,10 +22,11 @@ use tracing::trace; use super::metadata::{create_compressed_metadata_file, search_for_section}; use crate::common; -// Re-exporting for rustc_codegen_llvm::back::archive -pub use crate::errors::{ArchiveBuildFailure, ExtractBundledLibsError, UnknownArchiveKind}; +// Public for ArchiveBuilderBuilder::extract_bundled_libs +pub use crate::errors::ExtractBundledLibsError; use crate::errors::{ - DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, ErrorWritingDEFFile, + ArchiveBuildFailure, DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, + ErrorWritingDEFFile, UnknownArchiveKind, }; /// An item to be included in an import library. diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index f57c37ca7929..39727685aec1 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -661,7 +661,7 @@ pub(crate) struct RlibArchiveBuildFailure { } #[derive(Diagnostic)] -// Public for rustc_codegen_llvm::back::archive +// Public for ArchiveBuilderBuilder::extract_bundled_libs pub enum ExtractBundledLibsError<'a> { #[diag(codegen_ssa_extract_bundled_libs_open_file)] OpenFile { rlib: &'a Path, error: Box }, @@ -700,16 +700,14 @@ pub(crate) struct UnsupportedLinkSelfContained; #[derive(Diagnostic)] #[diag(codegen_ssa_archive_build_failure)] -// Public for rustc_codegen_llvm::back::archive -pub struct ArchiveBuildFailure { +pub(crate) struct ArchiveBuildFailure { pub path: PathBuf, pub error: std::io::Error, } #[derive(Diagnostic)] #[diag(codegen_ssa_unknown_archive_kind)] -// Public for rustc_codegen_llvm::back::archive -pub struct UnknownArchiveKind<'a> { +pub(crate) struct UnknownArchiveKind<'a> { pub kind: &'a str, } From 2cde8d967a7b5b6dbec30cd18d8f7417e4e22d33 Mon Sep 17 00:00:00 2001 From: Colin Murphy Date: Fri, 9 Jan 2026 09:44:39 -0500 Subject: [PATCH 0488/1061] Fix std::fs::copy on WASI by setting proper OpenOptions flags When PR #147572 switched WASI to use Unix-style filesystem APIs, the open_to_and_set_permissions function for WASI was implemented to call OpenOptions::new().open() without setting any access mode flags. This causes std::fs::copy to fail with the error: "must specify at least one of read, write, or append access" The fix is to explicitly set .write(true), .create(true), and .truncate(true) on the OpenOptions, matching the behavior of the non-WASI Unix implementation but without the permission handling that WASI doesn't support. Minimal reproduction: fn main() { std::fs::write("/src.txt", b"test").unwrap(); match std::fs::copy("/src.txt", "/dst.txt") { Ok(_) => println!("PASS: fs::copy works!"), Err(e) => println!("FAIL: {}", e), } } # Compile and run: rustc +nightly --target wasm32-wasip2 test.rs -o test.wasm wasmtime -S cli --dir . test.wasm # Before fix: FAIL: must specify at least one of read, write, or append access # After fix: PASS: fs::copy works! Note: The existing test library/std/src/fs/tests.rs::copy_file_ok would have caught this regression if the std test suite ran on WASI targets. Currently std tests don't compile for wasm32-wasip2 due to Unix-specific test code in library/std/src/sys/fd/unix/tests.rs. Fixes the regression introduced in nightly-2025-12-10. --- library/std/src/sys/fs/unix.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 327b0eb7468a..02f733c6e4c1 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -2296,7 +2296,11 @@ fn open_to_and_set_permissions( _reader_metadata: &crate::fs::Metadata, ) -> io::Result<(crate::fs::File, crate::fs::Metadata)> { use crate::fs::OpenOptions; - let writer = OpenOptions::new().open(to)?; + let writer = OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(to)?; let writer_metadata = writer.metadata()?; Ok((writer, writer_metadata)) } From 0946c867a86cf3c830dbbd7073d8df7f71b3149b Mon Sep 17 00:00:00 2001 From: Sebastian Bernauer Date: Wed, 17 Dec 2025 16:12:22 +0100 Subject: [PATCH 0489/1061] Add new `duration_suboptimal_units` lint --- CHANGELOG.md | 1 + clippy_dev/src/serve.rs | 2 +- clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/duration_suboptimal_units.rs | 204 ++++++++++++++++++ clippy_lints/src/lib.rs | 6 +- clippy_utils/src/msrvs.rs | 6 +- clippy_utils/src/sym.rs | 9 + tests/ui/duration_suboptimal_units.fixed | 91 ++++++++ tests/ui/duration_suboptimal_units.rs | 91 ++++++++ tests/ui/duration_suboptimal_units.stderr | 152 +++++++++++++ ...duration_suboptimal_units_days_weeks.fixed | 17 ++ .../duration_suboptimal_units_days_weeks.rs | 17 ++ ...uration_suboptimal_units_days_weeks.stderr | 40 ++++ 13 files changed, 633 insertions(+), 4 deletions(-) create mode 100644 clippy_lints/src/duration_suboptimal_units.rs create mode 100644 tests/ui/duration_suboptimal_units.fixed create mode 100644 tests/ui/duration_suboptimal_units.rs create mode 100644 tests/ui/duration_suboptimal_units.stderr create mode 100644 tests/ui/duration_suboptimal_units_days_weeks.fixed create mode 100644 tests/ui/duration_suboptimal_units_days_weeks.rs create mode 100644 tests/ui/duration_suboptimal_units_days_weeks.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 91d793489be2..4cda8003b05c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6406,6 +6406,7 @@ Released 2018-09-13 [`duplicate_mod`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_mod [`duplicate_underscore_argument`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_underscore_argument [`duplicated_attributes`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicated_attributes +[`duration_suboptimal_units`]: https://rust-lang.github.io/rust-clippy/master/index.html#duration_suboptimal_units [`duration_subsec`]: https://rust-lang.github.io/rust-clippy/master/index.html#duration_subsec [`eager_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#eager_transmute [`elidable_lifetime_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names diff --git a/clippy_dev/src/serve.rs b/clippy_dev/src/serve.rs index d9e018133813..b99289672420 100644 --- a/clippy_dev/src/serve.rs +++ b/clippy_dev/src/serve.rs @@ -54,7 +54,7 @@ pub fn run(port: u16, lint: Option) -> ! { } // Delay to avoid updating the metadata too aggressively. - thread::sleep(Duration::from_millis(1000)); + thread::sleep(Duration::from_secs(1)); } } diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 6b68940c6423..ef9da84c4407 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -135,6 +135,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::drop_forget_ref::FORGET_NON_DROP_INFO, crate::drop_forget_ref::MEM_FORGET_INFO, crate::duplicate_mod::DUPLICATE_MOD_INFO, + crate::duration_suboptimal_units::DURATION_SUBOPTIMAL_UNITS_INFO, crate::else_if_without_else::ELSE_IF_WITHOUT_ELSE_INFO, crate::empty_drop::EMPTY_DROP_INFO, crate::empty_enums::EMPTY_ENUMS_INFO, diff --git a/clippy_lints/src/duration_suboptimal_units.rs b/clippy_lints/src/duration_suboptimal_units.rs new file mode 100644 index 000000000000..8140585b70d3 --- /dev/null +++ b/clippy_lints/src/duration_suboptimal_units.rs @@ -0,0 +1,204 @@ +use std::ops::ControlFlow; + +use clippy_config::Conf; +use clippy_utils::consts::{ConstEvalCtxt, Constant}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::res::MaybeDef; +use clippy_utils::sym; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, QPath, RustcVersion}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::ty::TyCtxt; +use rustc_session::impl_lint_pass; +use rustc_span::Symbol; + +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for instances where a `std::time::Duration` is constructed using a smaller time unit + /// when the value could be expressed more clearly using a larger unit. + /// + /// ### Why is this bad? + /// + /// Using a smaller unit for a duration that is evenly divisible by a larger unit reduces + /// readability. Readers have to mentally convert values, which can be error-prone and makes + /// the code less clear. + /// + /// ### Example + /// ``` + /// use std::time::Duration; + /// + /// let dur = Duration::from_millis(5_000); + /// let dur = Duration::from_secs(180); + /// let dur = Duration::from_mins(10 * 60); + /// ``` + /// + /// Use instead: + /// ``` + /// use std::time::Duration; + /// + /// let dur = Duration::from_secs(5); + /// let dur = Duration::from_mins(3); + /// let dur = Duration::from_hours(10); + /// ``` + #[clippy::version = "1.95.0"] + pub DURATION_SUBOPTIMAL_UNITS, + pedantic, + "constructing a `Duration` using a smaller unit when a larger unit would be more readable" +} + +impl_lint_pass!(DurationSuboptimalUnits => [DURATION_SUBOPTIMAL_UNITS]); + +pub struct DurationSuboptimalUnits { + msrv: Msrv, + units: Vec, +} + +impl DurationSuboptimalUnits { + pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { + // The order of the units matters, as they are walked top to bottom + let mut units = UNITS.to_vec(); + if tcx.features().enabled(sym::duration_constructors) { + units.extend(EXTENDED_UNITS); + } + Self { msrv: conf.msrv, units } + } +} + +impl LateLintPass<'_> for DurationSuboptimalUnits { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { + if !expr.span.in_external_macro(cx.sess().source_map()) + // Check if a function on std::time::Duration is called + && let ExprKind::Call(func, [arg]) = expr.kind + && let ExprKind::Path(QPath::TypeRelative(func_ty, func_name)) = func.kind + && cx + .typeck_results() + .node_type(func_ty.hir_id) + .is_diag_item(cx, sym::Duration) + // We intentionally don't want to evaluate referenced constants, as we don't want to + // recommend a literal value over using constants: + // + // let dur = Duration::from_secs(SIXTY); + // ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Duration::from_mins(1)` + && let Some(Constant::Int(value)) = ConstEvalCtxt::new(cx).eval_local(arg, expr.span.ctxt()) + && let value = u64::try_from(value).expect("All Duration::from_ constructors take a u64") + // There is no need to promote e.g. 0 seconds to 0 hours + && value != 0 + && let Some((promoted_constructor, promoted_value)) = self.promote(cx, func_name.ident.name, value) + { + span_lint_and_then( + cx, + DURATION_SUBOPTIMAL_UNITS, + expr.span, + "constructing a `Duration` using a smaller unit when a larger unit would be more readable", + |diag| { + let suggestions = vec![ + (func_name.ident.span, promoted_constructor.to_string()), + (arg.span, promoted_value.to_string()), + ]; + diag.multipart_suggestion_verbose( + format!("try using {promoted_constructor}"), + suggestions, + Applicability::MachineApplicable, + ); + }, + ); + } + } +} + +impl DurationSuboptimalUnits { + /// Tries to promote the given constructor and value to a bigger time unit and returns the + /// promoted constructor name and value. + /// + /// Returns [`None`] in case no promotion could be done. + fn promote(&self, cx: &LateContext<'_>, constructor_name: Symbol, value: u64) -> Option<(Symbol, u64)> { + let (best_unit, best_value) = self + .units + .iter() + .skip_while(|unit| unit.constructor_name != constructor_name) + .skip(1) + .try_fold( + (constructor_name, value), + |(current_unit, current_value), bigger_unit| { + if let Some(bigger_value) = current_value.div_exact(u64::from(bigger_unit.factor)) + && bigger_unit.stable_since.is_none_or(|v| self.msrv.meets(cx, v)) + { + ControlFlow::Continue((bigger_unit.constructor_name, bigger_value)) + } else { + // We have to break early, as we can't skip versions, as they are needed to + // correctly calculate the promoted value. + ControlFlow::Break((current_unit, current_value)) + } + }, + ) + .into_value(); + (best_unit != constructor_name).then_some((best_unit, best_value)) + } +} + +#[derive(Clone, Copy)] +struct Unit { + /// Name of the constructor on [`Duration`](std::time::Duration) to construct it from the given + /// unit, e.g. [`Duration::from_secs`](std::time::Duration::from_secs) + constructor_name: Symbol, + + /// The increase factor over the previous (smaller) unit + factor: u16, + + /// In what rustc version stable support for this constructor was added. + /// We do not need to track the version stable support in const contexts was added, as the const + /// stabilization was done in an ascending order of the time unites, so it's always valid to + /// promote a const constructor. + stable_since: Option, +} + +/// Time unit constructors available on stable. The order matters! +const UNITS: [Unit; 6] = [ + Unit { + constructor_name: sym::from_nanos, + // The value doesn't matter, as there is no previous unit + factor: 0, + stable_since: Some(msrvs::DURATION_FROM_NANOS_MICROS), + }, + Unit { + constructor_name: sym::from_micros, + factor: 1_000, + stable_since: Some(msrvs::DURATION_FROM_NANOS_MICROS), + }, + Unit { + constructor_name: sym::from_millis, + factor: 1_000, + stable_since: Some(msrvs::DURATION_FROM_MILLIS_SECS), + }, + Unit { + constructor_name: sym::from_secs, + factor: 1_000, + stable_since: Some(msrvs::DURATION_FROM_MILLIS_SECS), + }, + Unit { + constructor_name: sym::from_mins, + factor: 60, + stable_since: Some(msrvs::DURATION_FROM_MINUTES_HOURS), + }, + Unit { + constructor_name: sym::from_hours, + factor: 60, + stable_since: Some(msrvs::DURATION_FROM_MINUTES_HOURS), + }, +]; + +/// Time unit constructors behind the `duration_constructors` feature. The order matters! +const EXTENDED_UNITS: [Unit; 2] = [ + Unit { + constructor_name: sym::from_days, + factor: 24, + stable_since: None, + }, + Unit { + constructor_name: sym::from_weeks, + factor: 7, + stable_since: None, + }, +]; diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index a957afdb1910..ef2461f8b097 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1,11 +1,13 @@ #![cfg_attr(bootstrap, feature(array_windows))] #![feature(box_patterns)] -#![feature(macro_metavar_expr_concat)] +#![feature(control_flow_into_value)] +#![feature(exact_div)] #![feature(f128)] #![feature(f16)] #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(iter_partition_in_place)] +#![feature(macro_metavar_expr_concat)] #![feature(never_type)] #![feature(rustc_private)] #![feature(stmt_expr_attributes)] @@ -113,6 +115,7 @@ mod doc; mod double_parens; mod drop_forget_ref; mod duplicate_mod; +mod duration_suboptimal_units; mod else_if_without_else; mod empty_drop; mod empty_enums; @@ -857,6 +860,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co Box::new(|_| Box::::default()), Box::new(move |_| Box::new(manual_ilog2::ManualIlog2::new(conf))), Box::new(|_| Box::new(same_length_and_capacity::SameLengthAndCapacity)), + Box::new(move |tcx| Box::new(duration_suboptimal_units::DurationSuboptimalUnits::new(tcx, conf))), // add late passes here, used by `cargo dev new_lint` ]; store.late_passes.extend(late_lints); diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 4a7fa3472cae..14cfb5a88283 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -23,6 +23,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { + 1,91,0 { DURATION_FROM_MINUTES_HOURS } 1,88,0 { LET_CHAINS } 1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT, UNSIGNED_IS_MULTIPLE_OF, INTEGER_SIGN_CAST } 1,85,0 { UINT_FLOAT_MIDPOINT, CONST_SIZE_OF_VAL } @@ -69,12 +70,12 @@ msrv_aliases! { 1,35,0 { OPTION_COPIED, RANGE_CONTAINS } 1,34,0 { TRY_FROM } 1,33,0 { UNDERSCORE_IMPORTS } - 1,32,0 { CONST_IS_POWER_OF_TWO } + 1,32,0 { CONST_IS_POWER_OF_TWO, CONST_DURATION_FROM_NANOS_MICROS_MILLIS_SECS } 1,31,0 { OPTION_REPLACE } 1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES } 1,29,0 { ITER_FLATTEN } 1,28,0 { FROM_BOOL, REPEAT_WITH, SLICE_FROM_REF } - 1,27,0 { ITERATOR_TRY_FOLD, DOUBLE_ENDED_ITERATOR_RFIND } + 1,27,0 { ITERATOR_TRY_FOLD, DOUBLE_ENDED_ITERATOR_RFIND, DURATION_FROM_NANOS_MICROS } 1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN, POINTER_ADD_SUB_METHODS } 1,24,0 { IS_ASCII_DIGIT, PTR_NULL } 1,18,0 { HASH_MAP_RETAIN, HASH_SET_RETAIN } @@ -82,6 +83,7 @@ msrv_aliases! { 1,16,0 { STR_REPEAT, RESULT_UNWRAP_OR_DEFAULT } 1,15,0 { MAYBE_BOUND_IN_WHERE } 1,13,0 { QUESTION_MARK_OPERATOR } + 1,3,0 { DURATION_FROM_MILLIS_SECS } } /// `#[clippy::msrv]` attributes are rarely used outside of Clippy's test suite, as a basic diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index a0d2e8673fe6..f11af159bc2e 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -140,6 +140,7 @@ generate! { disallowed_types, drain, dump, + duration_constructors, ends_with, enum_glob_use, enumerate, @@ -164,12 +165,20 @@ generate! { from_be_bytes, from_bytes_with_nul, from_bytes_with_nul_unchecked, + from_days, + from_hours, from_le_bytes, + from_micros, + from_millis, + from_mins, + from_nanos, from_ne_bytes, from_ptr, from_raw, from_raw_parts, + from_secs, from_str_radix, + from_weeks, fs, fuse, futures_util, diff --git a/tests/ui/duration_suboptimal_units.fixed b/tests/ui/duration_suboptimal_units.fixed new file mode 100644 index 000000000000..98c4b6e965ba --- /dev/null +++ b/tests/ui/duration_suboptimal_units.fixed @@ -0,0 +1,91 @@ +//@aux-build:proc_macros.rs +#![warn(clippy::duration_suboptimal_units)] + +use std::time::Duration; + +const SIXTY: u64 = 60; + +macro_rules! mac { + (slow_rythm) => { + 3600 + }; + (duration) => { + Duration::from_mins(5) + //~^ duration_suboptimal_units + }; + (arg => $e:expr) => { + Duration::from_secs($e) + }; +} + +fn main() { + let dur = Duration::from_secs(0); + let dur = Duration::from_secs(42); + let dur = Duration::from_hours(3); + + let dur = Duration::from_mins(1); + //~^ duration_suboptimal_units + let dur = Duration::from_mins(3); + //~^ duration_suboptimal_units + let dur = Duration::from_mins(10); + //~^ duration_suboptimal_units + let dur = Duration::from_hours(24); + //~^ duration_suboptimal_units + let dur = Duration::from_secs(5); + //~^ duration_suboptimal_units + let dur = Duration::from_hours(13); + //~^ duration_suboptimal_units + + // Constants are intentionally not resolved, as we don't want to recommend a literal value over + // using constants. + let dur = Duration::from_secs(SIXTY); + // Technically it would be nice to use Duration::from_mins(SIXTY) here, but that is a follow-up + let dur = Duration::from_secs(SIXTY * 60); + + const { + let dur = Duration::from_secs(0); + let dur = Duration::from_secs(5); + //~^ duration_suboptimal_units + let dur = Duration::from_mins(3); + //~^ duration_suboptimal_units + let dur = Duration::from_hours(24); + //~^ duration_suboptimal_units + + let dur = Duration::from_secs(SIXTY); + } + + // Qualified Durations must be kept + std::time::Duration::from_mins(1); + //~^ duration_suboptimal_units + + // We lint in normal macros + assert_eq!(Duration::from_hours(1), Duration::from_mins(6)); + //~^ duration_suboptimal_units + + // We lint in normal macros (marker is in macro itself) + let dur = mac!(duration); + + // We don't lint in macros if duration comes from outside + let dur = mac!(arg => 3600); + + // We don't lint in external macros + let dur = proc_macros::external! { Duration::from_secs(3_600) }; + + // We don't lint values coming from macros + let dur = Duration::from_secs(mac!(slow_rythm)); +} + +mod my_duration { + struct Duration {} + + impl Duration { + pub const fn from_secs(_secs: u64) -> Self { + Self {} + } + } + + fn test() { + // Only suggest the change for std::time::Duration, not for other Duration structs + let dur = Duration::from_secs(60); + } +} diff --git a/tests/ui/duration_suboptimal_units.rs b/tests/ui/duration_suboptimal_units.rs new file mode 100644 index 000000000000..c4f33a9f92e0 --- /dev/null +++ b/tests/ui/duration_suboptimal_units.rs @@ -0,0 +1,91 @@ +//@aux-build:proc_macros.rs +#![warn(clippy::duration_suboptimal_units)] + +use std::time::Duration; + +const SIXTY: u64 = 60; + +macro_rules! mac { + (slow_rythm) => { + 3600 + }; + (duration) => { + Duration::from_secs(300) + //~^ duration_suboptimal_units + }; + (arg => $e:expr) => { + Duration::from_secs($e) + }; +} + +fn main() { + let dur = Duration::from_secs(0); + let dur = Duration::from_secs(42); + let dur = Duration::from_hours(3); + + let dur = Duration::from_secs(60); + //~^ duration_suboptimal_units + let dur = Duration::from_secs(180); + //~^ duration_suboptimal_units + let dur = Duration::from_secs(10 * 60); + //~^ duration_suboptimal_units + let dur = Duration::from_mins(24 * 60); + //~^ duration_suboptimal_units + let dur = Duration::from_millis(5_000); + //~^ duration_suboptimal_units + let dur = Duration::from_nanos(13 * 60 * 60 * 1_000 * 1_000 * 1_000); + //~^ duration_suboptimal_units + + // Constants are intentionally not resolved, as we don't want to recommend a literal value over + // using constants. + let dur = Duration::from_secs(SIXTY); + // Technically it would be nice to use Duration::from_mins(SIXTY) here, but that is a follow-up + let dur = Duration::from_secs(SIXTY * 60); + + const { + let dur = Duration::from_secs(0); + let dur = Duration::from_millis(5_000); + //~^ duration_suboptimal_units + let dur = Duration::from_secs(180); + //~^ duration_suboptimal_units + let dur = Duration::from_mins(24 * 60); + //~^ duration_suboptimal_units + + let dur = Duration::from_secs(SIXTY); + } + + // Qualified Durations must be kept + std::time::Duration::from_secs(60); + //~^ duration_suboptimal_units + + // We lint in normal macros + assert_eq!(Duration::from_secs(3_600), Duration::from_mins(6)); + //~^ duration_suboptimal_units + + // We lint in normal macros (marker is in macro itself) + let dur = mac!(duration); + + // We don't lint in macros if duration comes from outside + let dur = mac!(arg => 3600); + + // We don't lint in external macros + let dur = proc_macros::external! { Duration::from_secs(3_600) }; + + // We don't lint values coming from macros + let dur = Duration::from_secs(mac!(slow_rythm)); +} + +mod my_duration { + struct Duration {} + + impl Duration { + pub const fn from_secs(_secs: u64) -> Self { + Self {} + } + } + + fn test() { + // Only suggest the change for std::time::Duration, not for other Duration structs + let dur = Duration::from_secs(60); + } +} diff --git a/tests/ui/duration_suboptimal_units.stderr b/tests/ui/duration_suboptimal_units.stderr new file mode 100644 index 000000000000..f129dbade8dc --- /dev/null +++ b/tests/ui/duration_suboptimal_units.stderr @@ -0,0 +1,152 @@ +error: constructing a `Duration` using a smaller unit when a larger unit would be more readable + --> tests/ui/duration_suboptimal_units.rs:26:15 + | +LL | let dur = Duration::from_secs(60); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::duration-suboptimal-units` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::duration_suboptimal_units)]` +help: try using from_mins + | +LL - let dur = Duration::from_secs(60); +LL + let dur = Duration::from_mins(1); + | + +error: constructing a `Duration` using a smaller unit when a larger unit would be more readable + --> tests/ui/duration_suboptimal_units.rs:28:15 + | +LL | let dur = Duration::from_secs(180); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try using from_mins + | +LL - let dur = Duration::from_secs(180); +LL + let dur = Duration::from_mins(3); + | + +error: constructing a `Duration` using a smaller unit when a larger unit would be more readable + --> tests/ui/duration_suboptimal_units.rs:30:15 + | +LL | let dur = Duration::from_secs(10 * 60); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try using from_mins + | +LL - let dur = Duration::from_secs(10 * 60); +LL + let dur = Duration::from_mins(10); + | + +error: constructing a `Duration` using a smaller unit when a larger unit would be more readable + --> tests/ui/duration_suboptimal_units.rs:32:15 + | +LL | let dur = Duration::from_mins(24 * 60); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try using from_hours + | +LL - let dur = Duration::from_mins(24 * 60); +LL + let dur = Duration::from_hours(24); + | + +error: constructing a `Duration` using a smaller unit when a larger unit would be more readable + --> tests/ui/duration_suboptimal_units.rs:34:15 + | +LL | let dur = Duration::from_millis(5_000); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try using from_secs + | +LL - let dur = Duration::from_millis(5_000); +LL + let dur = Duration::from_secs(5); + | + +error: constructing a `Duration` using a smaller unit when a larger unit would be more readable + --> tests/ui/duration_suboptimal_units.rs:36:15 + | +LL | let dur = Duration::from_nanos(13 * 60 * 60 * 1_000 * 1_000 * 1_000); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try using from_hours + | +LL - let dur = Duration::from_nanos(13 * 60 * 60 * 1_000 * 1_000 * 1_000); +LL + let dur = Duration::from_hours(13); + | + +error: constructing a `Duration` using a smaller unit when a larger unit would be more readable + --> tests/ui/duration_suboptimal_units.rs:47:19 + | +LL | let dur = Duration::from_millis(5_000); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try using from_secs + | +LL - let dur = Duration::from_millis(5_000); +LL + let dur = Duration::from_secs(5); + | + +error: constructing a `Duration` using a smaller unit when a larger unit would be more readable + --> tests/ui/duration_suboptimal_units.rs:49:19 + | +LL | let dur = Duration::from_secs(180); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try using from_mins + | +LL - let dur = Duration::from_secs(180); +LL + let dur = Duration::from_mins(3); + | + +error: constructing a `Duration` using a smaller unit when a larger unit would be more readable + --> tests/ui/duration_suboptimal_units.rs:51:19 + | +LL | let dur = Duration::from_mins(24 * 60); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try using from_hours + | +LL - let dur = Duration::from_mins(24 * 60); +LL + let dur = Duration::from_hours(24); + | + +error: constructing a `Duration` using a smaller unit when a larger unit would be more readable + --> tests/ui/duration_suboptimal_units.rs:58:5 + | +LL | std::time::Duration::from_secs(60); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try using from_mins + | +LL - std::time::Duration::from_secs(60); +LL + std::time::Duration::from_mins(1); + | + +error: constructing a `Duration` using a smaller unit when a larger unit would be more readable + --> tests/ui/duration_suboptimal_units.rs:62:16 + | +LL | assert_eq!(Duration::from_secs(3_600), Duration::from_mins(6)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try using from_hours + | +LL - assert_eq!(Duration::from_secs(3_600), Duration::from_mins(6)); +LL + assert_eq!(Duration::from_hours(1), Duration::from_mins(6)); + | + +error: constructing a `Duration` using a smaller unit when a larger unit would be more readable + --> tests/ui/duration_suboptimal_units.rs:13:9 + | +LL | Duration::from_secs(300) + | ^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | let dur = mac!(duration); + | -------------- in this macro invocation + | + = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) +help: try using from_mins + | +LL - Duration::from_secs(300) +LL + Duration::from_mins(5) + | + +error: aborting due to 12 previous errors + diff --git a/tests/ui/duration_suboptimal_units_days_weeks.fixed b/tests/ui/duration_suboptimal_units_days_weeks.fixed new file mode 100644 index 000000000000..b0abcbb7bf03 --- /dev/null +++ b/tests/ui/duration_suboptimal_units_days_weeks.fixed @@ -0,0 +1,17 @@ +#![warn(clippy::duration_suboptimal_units)] +// The duration_constructors feature enables `Duration::from_days` and `Duration::from_weeks`, so we +// should suggest them +#![feature(duration_constructors)] + +use std::time::Duration; + +fn main() { + let dur = Duration::from_mins(1); + //~^ duration_suboptimal_units + + let dur = Duration::from_days(1); + //~^ duration_suboptimal_units + + let dur = Duration::from_weeks(13); + //~^ duration_suboptimal_units +} diff --git a/tests/ui/duration_suboptimal_units_days_weeks.rs b/tests/ui/duration_suboptimal_units_days_weeks.rs new file mode 100644 index 000000000000..663476905c0f --- /dev/null +++ b/tests/ui/duration_suboptimal_units_days_weeks.rs @@ -0,0 +1,17 @@ +#![warn(clippy::duration_suboptimal_units)] +// The duration_constructors feature enables `Duration::from_days` and `Duration::from_weeks`, so we +// should suggest them +#![feature(duration_constructors)] + +use std::time::Duration; + +fn main() { + let dur = Duration::from_secs(60); + //~^ duration_suboptimal_units + + let dur = Duration::from_hours(24); + //~^ duration_suboptimal_units + + let dur = Duration::from_nanos(13 * 7 * 24 * 60 * 60 * 1_000 * 1_000 * 1_000); + //~^ duration_suboptimal_units +} diff --git a/tests/ui/duration_suboptimal_units_days_weeks.stderr b/tests/ui/duration_suboptimal_units_days_weeks.stderr new file mode 100644 index 000000000000..98325358bfa6 --- /dev/null +++ b/tests/ui/duration_suboptimal_units_days_weeks.stderr @@ -0,0 +1,40 @@ +error: constructing a `Duration` using a smaller unit when a larger unit would be more readable + --> tests/ui/duration_suboptimal_units_days_weeks.rs:9:15 + | +LL | let dur = Duration::from_secs(60); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::duration-suboptimal-units` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::duration_suboptimal_units)]` +help: try using from_mins + | +LL - let dur = Duration::from_secs(60); +LL + let dur = Duration::from_mins(1); + | + +error: constructing a `Duration` using a smaller unit when a larger unit would be more readable + --> tests/ui/duration_suboptimal_units_days_weeks.rs:12:15 + | +LL | let dur = Duration::from_hours(24); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try using from_days + | +LL - let dur = Duration::from_hours(24); +LL + let dur = Duration::from_days(1); + | + +error: constructing a `Duration` using a smaller unit when a larger unit would be more readable + --> tests/ui/duration_suboptimal_units_days_weeks.rs:15:15 + | +LL | let dur = Duration::from_nanos(13 * 7 * 24 * 60 * 60 * 1_000 * 1_000 * 1_000); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try using from_weeks + | +LL - let dur = Duration::from_nanos(13 * 7 * 24 * 60 * 60 * 1_000 * 1_000 * 1_000); +LL + let dur = Duration::from_weeks(13); + | + +error: aborting due to 3 previous errors + From 642663596d87863521b708b9eabb5f7e63446600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 9 Jan 2026 17:00:49 +0100 Subject: [PATCH 0490/1061] Fix unpacking of gcc-dev component --- src/bootstrap/src/core/download.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 43efdcd7db17..074404b4cdf3 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -396,7 +396,7 @@ impl Config { "; self.download_file(&format!("{base}/{gcc_sha}/{filename}"), &tarball, help_on_error); } - self.unpack(&tarball, root_dir, "gcc"); + self.unpack(&tarball, root_dir, "gcc-dev"); } } From 2a3932295e9ac167f8cd09dc08e86c46e94dbb50 Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Fri, 9 Jan 2026 16:15:39 +0000 Subject: [PATCH 0491/1061] Supress unused_parens lint for guard patterns --- compiler/rustc_lint/src/unused.rs | 2 ++ .../parens-around-guard-patterns-not-unused.rs | 13 +++++++++++++ tests/ui/reachable/guard_read_for_never.rs | 2 +- 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tests/ui/lint/unused/unused_parens/parens-around-guard-patterns-not-unused.rs diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 0ba54e3829f5..506a16355e22 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1190,6 +1190,8 @@ impl UnusedParens { // `&(a..=b)`, there is a recursive `check_pat` on `a` and `b`, but we will assume // that if there are unnecessary parens they serve a purpose of readability. PatKind::Range(..) => return, + // Parentheses may be necessary to disambiguate precedence in guard patterns. + PatKind::Guard(..) => return, // Avoid `p0 | .. | pn` if we should. PatKind::Or(..) if avoid_or => return, // Avoid `mut x` and `mut x @ p` if we should: diff --git a/tests/ui/lint/unused/unused_parens/parens-around-guard-patterns-not-unused.rs b/tests/ui/lint/unused/unused_parens/parens-around-guard-patterns-not-unused.rs new file mode 100644 index 000000000000..d5b8365ee612 --- /dev/null +++ b/tests/ui/lint/unused/unused_parens/parens-around-guard-patterns-not-unused.rs @@ -0,0 +1,13 @@ +//! Guard patterns require parentheses to disambiguate precedence +//! +//! Regression test for https://github.com/rust-lang/rust/issues/149594 + +//@ check-pass + +#![feature(guard_patterns)] +#![expect(incomplete_features)] +#![warn(unused_parens)] + +fn main() { + let (_ if false) = (); +} diff --git a/tests/ui/reachable/guard_read_for_never.rs b/tests/ui/reachable/guard_read_for_never.rs index 7061da635301..763dfd354b58 100644 --- a/tests/ui/reachable/guard_read_for_never.rs +++ b/tests/ui/reachable/guard_read_for_never.rs @@ -2,7 +2,7 @@ // //@ check-pass #![feature(guard_patterns, never_type)] -#![expect(incomplete_features, unused_parens)] +#![expect(incomplete_features)] #![deny(unreachable_code)] fn main() { From e275c2371649d145e4cfafc16b1b02ef37593e0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 9 Jan 2026 17:46:49 +0100 Subject: [PATCH 0492/1061] Update bors email in CI postprocessing step --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bb6bc325a3bb..8963039dd50b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -289,7 +289,7 @@ jobs: fi # Get closest bors merge commit - PARENT_COMMIT=`git rev-list --author='bors ' -n1 --first-parent HEAD^1` + PARENT_COMMIT=`git rev-list --author='122020455+rust-bors\[bot\]@users.noreply.github.com' -n1 --first-parent HEAD^1` ./build/citool/debug/citool postprocess-metrics \ --job-name ${CI_JOB_NAME} \ From 43c1db7d5676ce023f873871cbf6b2c61f1e362d Mon Sep 17 00:00:00 2001 From: Colin Murphy Date: Fri, 9 Jan 2026 11:51:59 -0500 Subject: [PATCH 0493/1061] Run clippy --- library/std/src/sys/fs/unix.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 02f733c6e4c1..bb2ee6ae10ed 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -2296,11 +2296,7 @@ fn open_to_and_set_permissions( _reader_metadata: &crate::fs::Metadata, ) -> io::Result<(crate::fs::File, crate::fs::Metadata)> { use crate::fs::OpenOptions; - let writer = OpenOptions::new() - .write(true) - .create(true) - .truncate(true) - .open(to)?; + let writer = OpenOptions::new().write(true).create(true).truncate(true).open(to)?; let writer_metadata = writer.metadata()?; Ok((writer, writer_metadata)) } From fd59b32f8bf0a14451b390b4a7904c63252a56ad Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Fri, 9 Jan 2026 10:40:25 +0530 Subject: [PATCH 0494/1061] std: sys: fs: uefi: Implement File::read Tested using OVMF on QEMU. Signed-off-by: Ayush Singh --- library/std/src/sys/fs/uefi.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index b1e5f33b1b22..e12c7fb397d8 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -320,8 +320,8 @@ impl File { self.0.set_file_info(file_info) } - pub fn read(&self, _buf: &mut [u8]) -> io::Result { - unsupported() + pub fn read(&self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) } pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { @@ -666,6 +666,19 @@ mod uefi_fs { Ok(p) } + pub(crate) fn read(&self, buf: &mut [u8]) -> io::Result { + let file_ptr = self.protocol.as_ptr(); + let mut buf_size = buf.len(); + + let r = unsafe { ((*file_ptr).read)(file_ptr, &mut buf_size, buf.as_mut_ptr().cast()) }; + + if buf_size == 0 && r.is_error() { + Err(io::Error::from_raw_os_error(r.as_usize())) + } else { + Ok(buf_size) + } + } + pub(crate) fn read_dir_entry(&self) -> io::Result>> { let file_ptr = self.protocol.as_ptr(); let mut buf_size = 0; From f6f901fa6d2f27a6a309505c9d56a7cb81dd2453 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Fri, 9 Jan 2026 12:24:02 +0530 Subject: [PATCH 0495/1061] std: sys: fs: uefi: Implement File::{flush, *sync} - Make flush a noop since it is only for buffered writers. - Also forward fsync to datasync. UEFI does not have anything separate for metadata sync. Signed-off-by: Ayush Singh --- library/std/src/sys/fs/uefi.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index b1e5f33b1b22..3fec1ee9ae13 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -285,11 +285,11 @@ impl File { } pub fn fsync(&self) -> io::Result<()> { - unsupported() + self.datasync() } pub fn datasync(&self) -> io::Result<()> { - unsupported() + self.0.flush() } pub fn lock(&self) -> io::Result<()> { @@ -348,8 +348,9 @@ impl File { false } + // Write::flush is only meant for buffered writers. So should be noop for unbuffered files. pub fn flush(&self) -> io::Result<()> { - unsupported() + Ok(()) } pub fn seek(&self, _pos: SeekFrom) -> io::Result { @@ -744,6 +745,12 @@ mod uefi_fs { if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } } + pub(crate) fn flush(&self) -> io::Result<()> { + let file_ptr = self.protocol.as_ptr(); + let r = unsafe { ((*file_ptr).flush)(file_ptr) }; + if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } + } + pub(crate) fn path(&self) -> &Path { &self.path } From 6f12b86e9c0703114d3496abf3d7e93f080c6d5e Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 8 Jan 2026 19:41:35 +0100 Subject: [PATCH 0496/1061] s390x: support `f16` and `f16x8` in inline assembly --- compiler/rustc_target/src/asm/s390x.rs | 6 +-- tests/assembly-llvm/asm/s390x-types.rs | 46 ++++++++++++++++++- .../ui/asm/s390x/bad-reg.s390x_vector.stderr | 6 +-- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_target/src/asm/s390x.rs b/compiler/rustc_target/src/asm/s390x.rs index 410590b722b1..37176c0d73ea 100644 --- a/compiler/rustc_target/src/asm/s390x.rs +++ b/compiler/rustc_target/src/asm/s390x.rs @@ -42,13 +42,13 @@ impl S390xInlineAsmRegClass { ) -> &'static [(InlineAsmType, Option)] { match self { Self::reg | Self::reg_addr => types! { _: I8, I16, I32, I64; }, - Self::freg => types! { _: F32, F64; }, + Self::freg => types! { _: F16, F32, F64; }, Self::vreg => { if allow_experimental_reg { // non-clobber-only vector register support is unstable. types! { - vector: I32, F32, I64, F64, I128, F128, - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2); + vector: I32, F16, F32, I64, F64, I128, F128, + VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2); } } else { &[] diff --git a/tests/assembly-llvm/asm/s390x-types.rs b/tests/assembly-llvm/asm/s390x-types.rs index 24db91bf7772..10e2966ace0a 100644 --- a/tests/assembly-llvm/asm/s390x-types.rs +++ b/tests/assembly-llvm/asm/s390x-types.rs @@ -6,8 +6,9 @@ //@[s390x_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-feature=+vector //@[s390x_vector] needs-llvm-components: systemz //@ compile-flags: -Zmerge-functions=disabled +//@ min-llvm-version: 21 -#![feature(no_core, repr_simd, f128)] +#![feature(no_core, repr_simd, f16, f128)] #![cfg_attr(s390x_vector, feature(asm_experimental_reg))] #![crate_type = "rlib"] #![no_core] @@ -27,6 +28,8 @@ pub struct i32x4([i32; 4]); #[repr(simd)] pub struct i64x2([i64; 2]); #[repr(simd)] +pub struct f16x8([f16; 8]); +#[repr(simd)] pub struct f32x4([f32; 4]); #[repr(simd)] pub struct f64x2([f64; 2]); @@ -35,6 +38,7 @@ impl Copy for i8x16 {} impl Copy for i16x8 {} impl Copy for i32x4 {} impl Copy for i64x2 {} +impl Copy for f16x8 {} impl Copy for f32x4 {} impl Copy for f64x2 {} @@ -127,6 +131,12 @@ check!(reg_i32_addr, i32, reg_addr, "lgr"); // CHECK: #NO_APP check!(reg_i64_addr, i64, reg_addr, "lgr"); +// CHECK-LABEL: reg_f16: +// CHECK: #APP +// CHECK: ler %f{{[0-9]+}}, %f{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_f16, f16, freg, "ler"); + // CHECK-LABEL: reg_f32: // CHECK: #APP // CHECK: ler %f{{[0-9]+}}, %f{{[0-9]+}} @@ -173,6 +183,13 @@ check!(vreg_i32x4, i32x4, vreg, "vlr"); #[cfg(s390x_vector)] check!(vreg_i64x2, i64x2, vreg, "vlr"); +// s390x_vector-LABEL: vreg_f16x8: +// s390x_vector: #APP +// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check!(vreg_f16x8, f16x8, vreg, "vlr"); + // s390x_vector-LABEL: vreg_f32x4: // s390x_vector: #APP // s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} @@ -208,6 +225,13 @@ check!(vreg_i64, i64, vreg, "vlr"); #[cfg(s390x_vector)] check!(vreg_i128, i128, vreg, "vlr"); +// s390x_vector-LABEL: vreg_f16: +// s390x_vector: #APP +// s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check!(vreg_f16, f16, vreg, "vlr"); + // s390x_vector-LABEL: vreg_f32: // s390x_vector: #APP // s390x_vector: vlr %v{{[0-9]+}}, %v{{[0-9]+}} @@ -253,6 +277,12 @@ check_reg!(r0_i32, i32, "r0", "lr"); // CHECK: #NO_APP check_reg!(r0_i64, i64, "r0", "lr"); +// CHECK-LABEL: f0_f16: +// CHECK: #APP +// CHECK: ler %f0, %f0 +// CHECK: #NO_APP +check_reg!(f0_f16, f16, "f0", "ler"); + // CHECK-LABEL: f0_f32: // CHECK: #APP // CHECK: ler %f0, %f0 @@ -293,6 +323,13 @@ check_reg!(v0_i32x4, i32x4, "v0", "vlr"); #[cfg(s390x_vector)] check_reg!(v0_i64x2, i64x2, "v0", "vlr"); +// s390x_vector-LABEL: v0_f16x8: +// s390x_vector: #APP +// s390x_vector: vlr %v0, %v0 +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check_reg!(v0_f16x8, f16x8, "v0", "vlr"); + // s390x_vector-LABEL: v0_f32x4: // s390x_vector: #APP // s390x_vector: vlr %v0, %v0 @@ -328,6 +365,13 @@ check_reg!(v0_i64, i64, "v0", "vlr"); #[cfg(s390x_vector)] check_reg!(v0_i128, i128, "v0", "vlr"); +// s390x_vector-LABEL: v0_f16: +// s390x_vector: #APP +// s390x_vector: vlr %v0, %v0 +// s390x_vector: #NO_APP +#[cfg(s390x_vector)] +check_reg!(v0_f16, f16, "v0", "vlr"); + // s390x_vector-LABEL: v0_f32: // s390x_vector: #APP // s390x_vector: vlr %v0, %v0 diff --git a/tests/ui/asm/s390x/bad-reg.s390x_vector.stderr b/tests/ui/asm/s390x/bad-reg.s390x_vector.stderr index 897f872ae72a..8e2da4dcc2a4 100644 --- a/tests/ui/asm/s390x/bad-reg.s390x_vector.stderr +++ b/tests/ui/asm/s390x/bad-reg.s390x_vector.stderr @@ -282,7 +282,7 @@ error: type `u8` cannot be used with this register class LL | asm!("", in("v0") b); | ^ | - = note: register class `vreg` supports these types: i32, f32, i64, f64, i128, f128, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2 + = note: register class `vreg` supports these types: i32, f16, f32, i64, f64, i128, f128, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2 error: type `u8` cannot be used with this register class --> $DIR/bad-reg.rs:95:28 @@ -290,7 +290,7 @@ error: type `u8` cannot be used with this register class LL | asm!("", out("v0") b); | ^ | - = note: register class `vreg` supports these types: i32, f32, i64, f64, i128, f128, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2 + = note: register class `vreg` supports these types: i32, f16, f32, i64, f64, i128, f128, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2 error: type `u8` cannot be used with this register class --> $DIR/bad-reg.rs:108:35 @@ -298,7 +298,7 @@ error: type `u8` cannot be used with this register class LL | asm!("/* {} */", in(vreg) b); | ^ | - = note: register class `vreg` supports these types: i32, f32, i64, f64, i128, f128, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2 + = note: register class `vreg` supports these types: i32, f16, f32, i64, f64, i128, f128, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2 error: type `i32` cannot be used with this register class --> $DIR/bad-reg.rs:120:27 From 0401e792f470e1cb776c522da1fb4da47541b508 Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Fri, 9 Jan 2026 13:49:17 -0500 Subject: [PATCH 0497/1061] Fix a trivial typo --- compiler/rustc_span/src/def_id.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index 484e626d4638..a0ccf8d7e798 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -81,7 +81,7 @@ impl fmt::Display for CrateNum { /// because it depends on the set of crates in the entire crate graph of a /// compilation session. Again, using the same crate with a different version /// number would fix the issue with a high probability -- but that might be -/// easier said then done if the crates in questions are dependencies of +/// easier said than done if the crates in questions are dependencies of /// third-party crates. /// /// That being said, given a high quality hash function, the collision From f73e504eea0a2cdd90fa1e27b8faa1ffd93ed370 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Fri, 9 Jan 2026 20:20:35 +0100 Subject: [PATCH 0498/1061] fix(useless_conversion): respect reduced applicability --- clippy_lints/src/useless_conversion.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 423301edfe83..4ce132e9e3ab 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -365,7 +365,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { format!("useless conversion to the same type: `{b}`"), "consider removing `.into_iter()`", sugg, - Applicability::MachineApplicable, // snippet + applicability, ); } } From f9c71df88ab864536d07a3a98341d3200aae7603 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 9 Jan 2026 17:40:28 +0100 Subject: [PATCH 0499/1061] Improve span for "unresolved intra doc link" on `deprecated` attribute --- compiler/rustc_ast/src/attr/mod.rs | 8 +++---- .../src/attributes/deprecation.rs | 22 ++++++++++++------- compiler/rustc_attr_parsing/src/parser.rs | 7 ++++++ .../rustc_hir/src/attrs/data_structures.rs | 2 +- compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_middle/src/middle/stability.rs | 4 ++-- src/librustdoc/clean/types.rs | 6 ++--- tests/rustdoc-ui/intra-doc/deprecated.stderr | 12 +++++----- tests/ui/unpretty/deprecated-attr.stdout | 8 +++---- 9 files changed, 42 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 0a2a34d932f6..b9411a3269a5 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -235,14 +235,14 @@ impl AttributeExt for Attribute { } } - fn deprecation_note(&self) -> Option { + fn deprecation_note(&self) -> Option { match &self.kind { AttrKind::Normal(normal) if normal.item.path == sym::deprecated => { let meta = &normal.item; // #[deprecated = "..."] if let Some(s) = meta.value_str() { - return Some(s); + return Some(Ident { name: s, span: meta.span() }); } // #[deprecated(note = "...")] @@ -252,7 +252,7 @@ impl AttributeExt for Attribute { && mi.path == sym::note && let Some(s) = mi.value_str() { - return Some(s); + return Some(Ident { name: s, span: mi.span }); } } } @@ -905,7 +905,7 @@ pub trait AttributeExt: Debug { /// Returns the deprecation note if this is deprecation attribute. /// * `#[deprecated = "note"]` returns `Some("note")`. /// * `#[deprecated(note = "note", ...)]` returns `Some("note")`. - fn deprecation_note(&self) -> Option; + fn deprecation_note(&self) -> Option; fn is_proc_macro_attr(&self) -> bool { [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive] diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index 2d79e3a103d6..e01377d247bb 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -13,14 +13,14 @@ fn get( name: Symbol, param_span: Span, arg: &ArgParser, - item: &Option, -) -> Option { + item: Option, +) -> Option { if item.is_some() { cx.duplicate_key(param_span, name); return None; } if let Some(v) = arg.name_value() { - if let Some(value_str) = v.value_as_str() { + if let Some(value_str) = v.value_as_ident() { Some(value_str) } else { cx.expected_string_literal(v.value_span, Some(&v.value_as_lit())); @@ -72,7 +72,7 @@ impl SingleAttributeParser for DeprecationParser { let features = cx.features(); let mut since = None; - let mut note = None; + let mut note: Option = None; let mut suggestion = None; let is_rustc = features.staged_api(); @@ -92,10 +92,16 @@ impl SingleAttributeParser for DeprecationParser { match ident_name { Some(name @ sym::since) => { - since = Some(get(cx, name, param.span(), param.args(), &since)?); + since = Some(get(cx, name, param.span(), param.args(), since)?.name); } Some(name @ sym::note) => { - note = Some(get(cx, name, param.span(), param.args(), ¬e)?); + note = Some(get( + cx, + name, + param.span(), + param.args(), + note.map(|ident| ident.name), + )?); } Some(name @ sym::suggestion) => { if !features.deprecated_suggestion() { @@ -107,7 +113,7 @@ impl SingleAttributeParser for DeprecationParser { } suggestion = - Some(get(cx, name, param.span(), param.args(), &suggestion)?); + Some(get(cx, name, param.span(), param.args(), suggestion)?.name); } _ => { cx.expected_specific_argument( @@ -124,7 +130,7 @@ impl SingleAttributeParser for DeprecationParser { } } ArgParser::NameValue(v) => { - let Some(value) = v.value_as_str() else { + let Some(value) = v.value_as_ident() else { cx.expected_string_literal(v.value_span, Some(v.value_as_lit())); return None; }; diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index d79579fdf0b7..68265649d182 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -322,6 +322,13 @@ impl NameValueParser { self.value_as_lit().kind.str() } + /// If the value is a string literal, it will return its value associated with its span (an + /// `Ident` in short). + pub fn value_as_ident(&self) -> Option { + let meta_item = self.value_as_lit(); + meta_item.kind.str().map(|name| Ident { name, span: meta_item.span }) + } + pub fn args_span(&self) -> Span { self.eq_span.to(self.value_span) } diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index fa8998f0546d..7c2700cea058 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -123,7 +123,7 @@ pub enum IntType { pub struct Deprecation { pub since: DeprecatedSince, /// The note to issue a reason. - pub note: Option, + pub note: Option, /// A text snippet used to completely replace any use of the deprecated item in an expression. /// /// This is currently unstable. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2fb6daf6469b..1b59d76be68c 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1402,7 +1402,7 @@ impl AttributeExt for Attribute { } #[inline] - fn deprecation_note(&self) -> Option { + fn deprecation_note(&self) -> Option { match &self { Attribute::Parsed(AttributeKind::Deprecation { deprecation, .. }) => deprecation.note, _ => None, diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 18520089e3ea..63bbd1a0b854 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -185,7 +185,7 @@ pub fn early_report_macro_deprecation( let diag = BuiltinLintDiag::DeprecatedMacro { suggestion: depr.suggestion, suggestion_span: span, - note: depr.note, + note: depr.note.map(|ident| ident.name), path, since_kind: deprecated_since_kind(is_in_effect, depr.since), }; @@ -228,7 +228,7 @@ fn late_report_deprecation( }), kind: def_kind.to_owned(), path: def_path, - note: depr.note, + note: depr.note.map(|ident| ident.name), since_kind: deprecated_since_kind(is_in_effect, depr.since), }; tcx.emit_node_span_lint(lint, hir_id, method_span, diag); diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index c3bafd3db13a..c2e63f475bec 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -26,7 +26,7 @@ use rustc_resolve::rustdoc::{ use rustc_session::Session; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{Symbol, kw, sym}; -use rustc_span::{DUMMY_SP, FileName, Loc, RemapPathScopeComponents}; +use rustc_span::{DUMMY_SP, FileName, Ident, Loc, RemapPathScopeComponents}; use tracing::{debug, trace}; use {rustc_ast as ast, rustc_hir as hir}; @@ -418,7 +418,7 @@ impl Item { { Some(Deprecation { since: DeprecatedSince::Unspecified, - note: Some(note), + note: Some(Ident { name: note, span: DUMMY_SP }), suggestion: None, }) } else { @@ -455,7 +455,7 @@ impl Item { .attrs .other_attrs .iter() - .filter_map(|attr| attr.deprecation_note().map(|_| attr.span())); + .filter_map(|attr| attr.deprecation_note().map(|note| note.span)); span_of_fragments(&self.attrs.doc_strings) .into_iter() diff --git a/tests/rustdoc-ui/intra-doc/deprecated.stderr b/tests/rustdoc-ui/intra-doc/deprecated.stderr index 9bd64544eef8..85290c334626 100644 --- a/tests/rustdoc-ui/intra-doc/deprecated.stderr +++ b/tests/rustdoc-ui/intra-doc/deprecated.stderr @@ -1,8 +1,8 @@ error: unresolved link to `TypeAlias::hoge` - --> $DIR/deprecated.rs:3:1 + --> $DIR/deprecated.rs:3:16 | LL | #[deprecated = "[broken cross-reference](TypeAlias::hoge)"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the link appears in this line: @@ -16,10 +16,10 @@ LL | #![deny(rustdoc::broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unresolved link to `TypeAlias::hoge` - --> $DIR/deprecated.rs:6:1 + --> $DIR/deprecated.rs:6:38 | LL | #[deprecated(since = "0.0.0", note = "[broken cross-reference](TypeAlias::hoge)")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the link appears in this line: @@ -28,10 +28,10 @@ LL | #[deprecated(since = "0.0.0", note = "[broken cross-reference](TypeAlias::h = note: no item named `TypeAlias` in scope error: unresolved link to `TypeAlias::hoge` - --> $DIR/deprecated.rs:9:1 + --> $DIR/deprecated.rs:9:21 | LL | #[deprecated(note = "[broken cross-reference](TypeAlias::hoge)", since = "0.0.0")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the link appears in this line: diff --git a/tests/ui/unpretty/deprecated-attr.stdout b/tests/ui/unpretty/deprecated-attr.stdout index 26cc74c11604..976598b0bfa3 100644 --- a/tests/ui/unpretty/deprecated-attr.stdout +++ b/tests/ui/unpretty/deprecated-attr.stdout @@ -10,19 +10,19 @@ use ::std::prelude::rust_2015::*; struct PlainDeprecated; #[attr = Deprecation {deprecation: Deprecation {since: Unspecified, -note: "here's why this is deprecated"}}] +note: here's why this is deprecated#0}}] struct DirectNote; #[attr = Deprecation {deprecation: Deprecation {since: Unspecified, -note: "here's why this is deprecated"}}] +note: here's why this is deprecated#0}}] struct ExplicitNote; #[attr = Deprecation {deprecation: Deprecation {since: NonStandard("1.2.3"), -note: "here's why this is deprecated"}}] +note: here's why this is deprecated#0}}] struct SinceAndNote; #[attr = Deprecation {deprecation: Deprecation {since: NonStandard("1.2.3"), -note: "here's why this is deprecated"}}] +note: here's why this is deprecated#0}}] struct FlippedOrder; fn f() { From 9d2ce878106ab85b2b098358ccd094a0cf7415c3 Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 9 Jan 2026 20:42:01 +0100 Subject: [PATCH 0500/1061] Don't check `[mentions]` paths in submodules from tidy --- src/tools/tidy/src/triagebot.rs | 38 +++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/tools/tidy/src/triagebot.rs b/src/tools/tidy/src/triagebot.rs index 59cd9d80b07a..a74d980cfcb7 100644 --- a/src/tools/tidy/src/triagebot.rs +++ b/src/tools/tidy/src/triagebot.rs @@ -2,11 +2,22 @@ use std::collections::HashSet; use std::path::Path; +use std::sync::LazyLock; use toml::Value; use crate::diagnostics::TidyCtx; +static SUBMODULES: LazyLock> = LazyLock::new(|| { + // WORKSPACES doesn't list all submodules but it's contains the main at least + crate::deps::WORKSPACES + .iter() + .map(|ws| ws.submodules.iter()) + .flatten() + .map(|p| Path::new(p)) + .collect() +}); + pub fn check(path: &Path, tidy_ctx: TidyCtx) { let mut check = tidy_ctx.start_check("triagebot"); let triagebot_path = path.join("triagebot.toml"); @@ -39,8 +50,13 @@ pub fn check(path: &Path, tidy_ctx: TidyCtx) { if !full_path.exists() { // The full-path doesn't exists, maybe it's a glob, let's add it to the glob set builder // to be checked against all the file and directories in the repository. - builder.add(globset::Glob::new(&format!("{clean_path}*")).unwrap()); + let trimmed_path = clean_path.trim_end_matches('/'); + builder.add(globset::Glob::new(&format!("{trimmed_path}{{,/*}}")).unwrap()); glob_entries.push(clean_path.to_string()); + } else if is_in_submodule(Path::new(clean_path)) { + check.error(format!( + "triagebot.toml [mentions.*] '{clean_path}' cannot match inside a submodule" + )); } } @@ -49,8 +65,18 @@ pub fn check(path: &Path, tidy_ctx: TidyCtx) { let mut found = HashSet::new(); let mut matches = Vec::new(); + let cloned_path = path.to_path_buf(); + // Walk the entire repository and match any entry against the remaining paths - for entry in ignore::WalkBuilder::new(path).build().flatten() { + for entry in ignore::WalkBuilder::new(&path) + .filter_entry(move |entry| { + // Ignore entries inside submodules as triagebot cannot detect them + let entry_path = entry.path().strip_prefix(&cloned_path).unwrap(); + is_not_in_submodule(entry_path) + }) + .build() + .flatten() + { // Strip the prefix as mentions entries are always relative to the repo let entry_path = entry.path().strip_prefix(path).unwrap(); @@ -126,3 +152,11 @@ pub fn check(path: &Path, tidy_ctx: TidyCtx) { } } } + +fn is_not_in_submodule(path: &Path) -> bool { + SUBMODULES.contains(&path) || !SUBMODULES.iter().any(|p| path.starts_with(*p)) +} + +fn is_in_submodule(path: &Path) -> bool { + !SUBMODULES.contains(&path) && SUBMODULES.iter().any(|p| path.starts_with(*p)) +} From 8e61f0de27b038e6bdb245e192aa2ae48c677523 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Fri, 9 Jan 2026 22:47:59 +0200 Subject: [PATCH 0501/1061] cg_llvm: add a pause to make comment less confusing --- compiler/rustc_codegen_llvm/src/mono_item.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 3ce28612ddfc..54ba671b09bc 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -153,7 +153,7 @@ impl CodegenCx<'_, '_> { return false; } - // With pie relocation model calls of functions defined in the translation + // With pie relocation model, calls of functions defined in the translation // unit can use copy relocations. if self.tcx.sess.relocation_model() == RelocModel::Pie && !is_declaration { return true; From 229673ac85ef40dca4f2bbcb984cfd4d50a9b02d Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Fri, 9 Jan 2026 22:49:32 +0200 Subject: [PATCH 0502/1061] make sentence more simple --- compiler/rustc_codegen_llvm/src/mono_item.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 54ba671b09bc..1878f4043ee8 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -111,7 +111,7 @@ impl CodegenCx<'_, '_> { } } - /// Whether a definition or declaration can be assumed to be local to a group of + /// A definition or declaration can be assumed to be local to a group of /// libraries that form a single DSO or executable. /// Marks the local as DSO if so. pub(crate) fn assume_dso_local(&self, llval: &llvm::Value, is_declaration: bool) -> bool { From 3ec7666a2ac99ccfa9de268a89d855ceb380024c Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Fri, 9 Jan 2026 20:43:26 +0100 Subject: [PATCH 0503/1061] clean-up --- clippy_lints/src/int_plus_one.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 67ce57de254d..540f9bb1e260 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -100,7 +100,7 @@ impl IntPlusOne { _ => None, } }, - // case where `... >= y - 1` or `... >= -1 + y` + // case where `... <= y - 1` or `... <= -1 + y` (BinOpKind::Le, _, ExprKind::Binary(rhskind, rhslhs, rhsrhs)) => { match (rhskind.node, &rhslhs.kind, &rhsrhs.kind) { // `-1 + y` @@ -156,11 +156,11 @@ impl IntPlusOne { } impl EarlyLintPass for IntPlusOne { - fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) { - if let ExprKind::Binary(ref kind, ref lhs, ref rhs) = item.kind + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + if let ExprKind::Binary(kind, lhs, rhs) = &expr.kind && let Some(rec) = Self::check_binop(cx, kind.node, lhs, rhs) { - Self::emit_warning(cx, item, rec); + Self::emit_warning(cx, expr, rec); } } } From 0180ec4d5d9e47b1b36bf33d783ac72600c4abd4 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Fri, 9 Jan 2026 22:38:08 +0100 Subject: [PATCH 0504/1061] fix: negative literals are not literals --- clippy_lints/src/int_plus_one.rs | 67 ++++++++++++++++++-------------- tests/ui/int_plus_one.fixed | 16 ++++---- tests/ui/int_plus_one.rs | 16 ++++---- tests/ui/int_plus_one.stderr | 26 ++++++++++++- 4 files changed, 78 insertions(+), 47 deletions(-) diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 540f9bb1e260..c25821751b3f 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::SpanRangeExt; -use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind}; -use rustc_ast::token; +use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind, UnOp}; +use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; @@ -50,25 +50,36 @@ enum Side { } impl IntPlusOne { - #[expect(clippy::cast_sign_loss)] - fn check_lit(token_lit: token::Lit, target_value: i128) -> bool { - if let Ok(LitKind::Int(value, ..)) = LitKind::from_token_lit(token_lit) { - return value == (target_value as u128); + fn is_one(expr: &Expr) -> bool { + if let ExprKind::Lit(token_lit) = expr.kind + && let Ok(LitKind::Int(Pu128(1), ..)) = LitKind::from_token_lit(token_lit) + { + return true; } false } + fn is_neg_one(expr: &Expr) -> bool { + if let ExprKind::Unary(UnOp::Neg, expr) = &expr.kind + && Self::is_one(expr) + { + true + } else { + false + } + } + fn check_binop(cx: &EarlyContext<'_>, binop: BinOpKind, lhs: &Expr, rhs: &Expr) -> Option { match (binop, &lhs.kind, &rhs.kind) { // case where `x - 1 >= ...` or `-1 + x >= ...` (BinOpKind::Ge, ExprKind::Binary(lhskind, lhslhs, lhsrhs), _) => { - match (lhskind.node, &lhslhs.kind, &lhsrhs.kind) { + match lhskind.node { // `-1 + x` - (BinOpKind::Add, ExprKind::Lit(lit), _) if Self::check_lit(*lit, -1) => { + BinOpKind::Add if Self::is_neg_one(lhslhs) => { Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::Lhs) }, // `x - 1` - (BinOpKind::Sub, _, ExprKind::Lit(lit)) if Self::check_lit(*lit, 1) => { + BinOpKind::Sub if Self::is_one(lhsrhs) => { Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::Lhs) }, _ => None, @@ -76,39 +87,35 @@ impl IntPlusOne { }, // case where `... >= y + 1` or `... >= 1 + y` (BinOpKind::Ge, _, ExprKind::Binary(rhskind, rhslhs, rhsrhs)) if rhskind.node == BinOpKind::Add => { - match (&rhslhs.kind, &rhsrhs.kind) { - // `y + 1` and `1 + y` - (ExprKind::Lit(lit), _) if Self::check_lit(*lit, 1) => { - Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::Rhs) - }, - (_, ExprKind::Lit(lit)) if Self::check_lit(*lit, 1) => { - Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::Rhs) - }, - _ => None, + // `y + 1` and `1 + y` + if Self::is_one(rhslhs) { + Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::Rhs) + } else if Self::is_one(rhsrhs) { + Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::Rhs) + } else { + None } }, // case where `x + 1 <= ...` or `1 + x <= ...` (BinOpKind::Le, ExprKind::Binary(lhskind, lhslhs, lhsrhs), _) if lhskind.node == BinOpKind::Add => { - match (&lhslhs.kind, &lhsrhs.kind) { - // `1 + x` and `x + 1` - (ExprKind::Lit(lit), _) if Self::check_lit(*lit, 1) => { - Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::Lhs) - }, - (_, ExprKind::Lit(lit)) if Self::check_lit(*lit, 1) => { - Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::Lhs) - }, - _ => None, + // `1 + x` and `x + 1` + if Self::is_one(lhslhs) { + Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::Lhs) + } else if Self::is_one(lhsrhs) { + Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::Lhs) + } else { + None } }, // case where `... <= y - 1` or `... <= -1 + y` (BinOpKind::Le, _, ExprKind::Binary(rhskind, rhslhs, rhsrhs)) => { - match (rhskind.node, &rhslhs.kind, &rhsrhs.kind) { + match rhskind.node { // `-1 + y` - (BinOpKind::Add, ExprKind::Lit(lit), _) if Self::check_lit(*lit, -1) => { + BinOpKind::Add if Self::is_neg_one(rhslhs) => { Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::Rhs) }, // `y - 1` - (BinOpKind::Sub, _, ExprKind::Lit(lit)) if Self::check_lit(*lit, 1) => { + BinOpKind::Sub if Self::is_one(rhsrhs) => { Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::Rhs) }, _ => None, diff --git a/tests/ui/int_plus_one.fixed b/tests/ui/int_plus_one.fixed index a1aba6bf7f64..cdd19515e9a7 100644 --- a/tests/ui/int_plus_one.fixed +++ b/tests/ui/int_plus_one.fixed @@ -4,15 +4,15 @@ fn main() { let x = 1i32; let y = 0i32; - let _ = x > y; - //~^ int_plus_one - let _ = y < x; - //~^ int_plus_one + let _ = x > y; //~ int_plus_one + let _ = x > y; //~ int_plus_one + let _ = y < x; //~ int_plus_one + let _ = y < x; //~ int_plus_one - let _ = x > y; - //~^ int_plus_one - let _ = y < x; - //~^ int_plus_one + let _ = x > y; //~ int_plus_one + let _ = x > y; //~ int_plus_one + let _ = y < x; //~ int_plus_one + let _ = y < x; //~ int_plus_one let _ = x > y; // should be ok let _ = y < x; // should be ok diff --git a/tests/ui/int_plus_one.rs b/tests/ui/int_plus_one.rs index f804fc9047de..8d7d2e8982d8 100644 --- a/tests/ui/int_plus_one.rs +++ b/tests/ui/int_plus_one.rs @@ -4,15 +4,15 @@ fn main() { let x = 1i32; let y = 0i32; - let _ = x >= y + 1; - //~^ int_plus_one - let _ = y + 1 <= x; - //~^ int_plus_one + let _ = x >= y + 1; //~ int_plus_one + let _ = x >= 1 + y; //~ int_plus_one + let _ = y + 1 <= x; //~ int_plus_one + let _ = 1 + y <= x; //~ int_plus_one - let _ = x - 1 >= y; - //~^ int_plus_one - let _ = y <= x - 1; - //~^ int_plus_one + let _ = x - 1 >= y; //~ int_plus_one + let _ = -1 + x >= y; //~ int_plus_one + let _ = y <= x - 1; //~ int_plus_one + let _ = y <= -1 + x; //~ int_plus_one let _ = x > y; // should be ok let _ = y < x; // should be ok diff --git a/tests/ui/int_plus_one.stderr b/tests/ui/int_plus_one.stderr index 052706028141..8bdff5680bdc 100644 --- a/tests/ui/int_plus_one.stderr +++ b/tests/ui/int_plus_one.stderr @@ -7,23 +7,47 @@ LL | let _ = x >= y + 1; = note: `-D clippy::int-plus-one` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::int_plus_one)]` +error: unnecessary `>= y + 1` or `x - 1 >=` + --> tests/ui/int_plus_one.rs:8:13 + | +LL | let _ = x >= 1 + y; + | ^^^^^^^^^^ help: change it to: `x > y` + error: unnecessary `>= y + 1` or `x - 1 >=` --> tests/ui/int_plus_one.rs:9:13 | LL | let _ = y + 1 <= x; | ^^^^^^^^^^ help: change it to: `y < x` +error: unnecessary `>= y + 1` or `x - 1 >=` + --> tests/ui/int_plus_one.rs:10:13 + | +LL | let _ = 1 + y <= x; + | ^^^^^^^^^^ help: change it to: `y < x` + error: unnecessary `>= y + 1` or `x - 1 >=` --> tests/ui/int_plus_one.rs:12:13 | LL | let _ = x - 1 >= y; | ^^^^^^^^^^ help: change it to: `x > y` +error: unnecessary `>= y + 1` or `x - 1 >=` + --> tests/ui/int_plus_one.rs:13:13 + | +LL | let _ = -1 + x >= y; + | ^^^^^^^^^^^ help: change it to: `x > y` + error: unnecessary `>= y + 1` or `x - 1 >=` --> tests/ui/int_plus_one.rs:14:13 | LL | let _ = y <= x - 1; | ^^^^^^^^^^ help: change it to: `y < x` -error: aborting due to 4 previous errors +error: unnecessary `>= y + 1` or `x - 1 >=` + --> tests/ui/int_plus_one.rs:15:13 + | +LL | let _ = y <= -1 + x; + | ^^^^^^^^^^^ help: change it to: `y < x` + +error: aborting due to 8 previous errors From df65d1a6a8509f9167078aab372f59ac7762af6c Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Fri, 9 Jan 2026 20:39:42 +0100 Subject: [PATCH 0505/1061] introduce `LeOrGe` removes the need for a wildcard match --- clippy_lints/src/int_plus_one.rs | 63 ++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index c25821751b3f..8143dbad79e8 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -35,11 +35,11 @@ declare_clippy_lint! { declare_lint_pass!(IntPlusOne => [INT_PLUS_ONE]); // cases: -// BinOpKind::Ge +// LeOrGe::Ge // x >= y + 1 // x - 1 >= y // -// BinOpKind::Le +// LeOrGe::Le // x + 1 <= y // x <= y - 1 @@ -49,6 +49,23 @@ enum Side { Rhs, } +#[derive(Copy, Clone)] +enum LeOrGe { + Le, + Ge, +} + +impl TryFrom for LeOrGe { + type Error = (); + fn try_from(value: BinOpKind) -> Result { + match value { + BinOpKind::Le => Ok(Self::Le), + BinOpKind::Ge => Ok(Self::Ge), + _ => Err(()), + } + } +} + impl IntPlusOne { fn is_one(expr: &Expr) -> bool { if let ExprKind::Lit(token_lit) = expr.kind @@ -69,54 +86,54 @@ impl IntPlusOne { } } - fn check_binop(cx: &EarlyContext<'_>, binop: BinOpKind, lhs: &Expr, rhs: &Expr) -> Option { - match (binop, &lhs.kind, &rhs.kind) { + fn check_binop(cx: &EarlyContext<'_>, le_or_ge: LeOrGe, lhs: &Expr, rhs: &Expr) -> Option { + match (le_or_ge, &lhs.kind, &rhs.kind) { // case where `x - 1 >= ...` or `-1 + x >= ...` - (BinOpKind::Ge, ExprKind::Binary(lhskind, lhslhs, lhsrhs), _) => { + (LeOrGe::Ge, ExprKind::Binary(lhskind, lhslhs, lhsrhs), _) => { match lhskind.node { // `-1 + x` BinOpKind::Add if Self::is_neg_one(lhslhs) => { - Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::Lhs) + Self::generate_recommendation(cx, le_or_ge, lhsrhs, rhs, Side::Lhs) }, // `x - 1` BinOpKind::Sub if Self::is_one(lhsrhs) => { - Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::Lhs) + Self::generate_recommendation(cx, le_or_ge, lhslhs, rhs, Side::Lhs) }, _ => None, } }, // case where `... >= y + 1` or `... >= 1 + y` - (BinOpKind::Ge, _, ExprKind::Binary(rhskind, rhslhs, rhsrhs)) if rhskind.node == BinOpKind::Add => { + (LeOrGe::Ge, _, ExprKind::Binary(rhskind, rhslhs, rhsrhs)) if rhskind.node == BinOpKind::Add => { // `y + 1` and `1 + y` if Self::is_one(rhslhs) { - Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::Rhs) + Self::generate_recommendation(cx, le_or_ge, rhsrhs, lhs, Side::Rhs) } else if Self::is_one(rhsrhs) { - Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::Rhs) + Self::generate_recommendation(cx, le_or_ge, rhslhs, lhs, Side::Rhs) } else { None } }, // case where `x + 1 <= ...` or `1 + x <= ...` - (BinOpKind::Le, ExprKind::Binary(lhskind, lhslhs, lhsrhs), _) if lhskind.node == BinOpKind::Add => { + (LeOrGe::Le, ExprKind::Binary(lhskind, lhslhs, lhsrhs), _) if lhskind.node == BinOpKind::Add => { // `1 + x` and `x + 1` if Self::is_one(lhslhs) { - Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::Lhs) + Self::generate_recommendation(cx, le_or_ge, lhsrhs, rhs, Side::Lhs) } else if Self::is_one(lhsrhs) { - Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::Lhs) + Self::generate_recommendation(cx, le_or_ge, lhslhs, rhs, Side::Lhs) } else { None } }, // case where `... <= y - 1` or `... <= -1 + y` - (BinOpKind::Le, _, ExprKind::Binary(rhskind, rhslhs, rhsrhs)) => { + (LeOrGe::Le, _, ExprKind::Binary(rhskind, rhslhs, rhsrhs)) => { match rhskind.node { // `-1 + y` BinOpKind::Add if Self::is_neg_one(rhslhs) => { - Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::Rhs) + Self::generate_recommendation(cx, le_or_ge, rhsrhs, lhs, Side::Rhs) }, // `y - 1` BinOpKind::Sub if Self::is_one(rhsrhs) => { - Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::Rhs) + Self::generate_recommendation(cx, le_or_ge, rhslhs, lhs, Side::Rhs) }, _ => None, } @@ -127,15 +144,14 @@ impl IntPlusOne { fn generate_recommendation( cx: &EarlyContext<'_>, - binop: BinOpKind, + le_or_ge: LeOrGe, node: &Expr, other_side: &Expr, side: Side, ) -> Option { - let binop_string = match binop { - BinOpKind::Ge => ">", - BinOpKind::Le => "<", - _ => return None, + let binop_string = match le_or_ge { + LeOrGe::Ge => ">", + LeOrGe::Le => "<", }; if let Some(snippet) = node.span.get_source_text(cx) && let Some(other_side_snippet) = other_side.span.get_source_text(cx) @@ -164,8 +180,9 @@ impl IntPlusOne { impl EarlyLintPass for IntPlusOne { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if let ExprKind::Binary(kind, lhs, rhs) = &expr.kind - && let Some(rec) = Self::check_binop(cx, kind.node, lhs, rhs) + if let ExprKind::Binary(binop, lhs, rhs) = &expr.kind + && let Ok(le_or_ge) = LeOrGe::try_from(binop.node) + && let Some(rec) = Self::check_binop(cx, le_or_ge, lhs, rhs) { Self::emit_warning(cx, expr, rec); } From d554092c27f0ad5cf8dc013b4fbcbd7853c40c0c Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Fri, 9 Jan 2026 21:01:55 +0100 Subject: [PATCH 0506/1061] get rid of `Side` --- clippy_lints/src/int_plus_one.rs | 33 +++++++++----------------------- 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 8143dbad79e8..97b7afb61d86 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -43,12 +43,6 @@ declare_lint_pass!(IntPlusOne => [INT_PLUS_ONE]); // x + 1 <= y // x <= y - 1 -#[derive(Copy, Clone)] -enum Side { - Lhs, - Rhs, -} - #[derive(Copy, Clone)] enum LeOrGe { Le, @@ -93,12 +87,10 @@ impl IntPlusOne { match lhskind.node { // `-1 + x` BinOpKind::Add if Self::is_neg_one(lhslhs) => { - Self::generate_recommendation(cx, le_or_ge, lhsrhs, rhs, Side::Lhs) + Self::generate_recommendation(cx, le_or_ge, lhsrhs, rhs) }, // `x - 1` - BinOpKind::Sub if Self::is_one(lhsrhs) => { - Self::generate_recommendation(cx, le_or_ge, lhslhs, rhs, Side::Lhs) - }, + BinOpKind::Sub if Self::is_one(lhsrhs) => Self::generate_recommendation(cx, le_or_ge, lhslhs, rhs), _ => None, } }, @@ -106,9 +98,9 @@ impl IntPlusOne { (LeOrGe::Ge, _, ExprKind::Binary(rhskind, rhslhs, rhsrhs)) if rhskind.node == BinOpKind::Add => { // `y + 1` and `1 + y` if Self::is_one(rhslhs) { - Self::generate_recommendation(cx, le_or_ge, rhsrhs, lhs, Side::Rhs) + Self::generate_recommendation(cx, le_or_ge, lhs, rhsrhs) } else if Self::is_one(rhsrhs) { - Self::generate_recommendation(cx, le_or_ge, rhslhs, lhs, Side::Rhs) + Self::generate_recommendation(cx, le_or_ge, lhs, rhslhs) } else { None } @@ -117,9 +109,9 @@ impl IntPlusOne { (LeOrGe::Le, ExprKind::Binary(lhskind, lhslhs, lhsrhs), _) if lhskind.node == BinOpKind::Add => { // `1 + x` and `x + 1` if Self::is_one(lhslhs) { - Self::generate_recommendation(cx, le_or_ge, lhsrhs, rhs, Side::Lhs) + Self::generate_recommendation(cx, le_or_ge, lhsrhs, rhs) } else if Self::is_one(lhsrhs) { - Self::generate_recommendation(cx, le_or_ge, lhslhs, rhs, Side::Lhs) + Self::generate_recommendation(cx, le_or_ge, lhslhs, rhs) } else { None } @@ -129,12 +121,10 @@ impl IntPlusOne { match rhskind.node { // `-1 + y` BinOpKind::Add if Self::is_neg_one(rhslhs) => { - Self::generate_recommendation(cx, le_or_ge, rhsrhs, lhs, Side::Rhs) + Self::generate_recommendation(cx, le_or_ge, lhs, rhsrhs) }, // `y - 1` - BinOpKind::Sub if Self::is_one(rhsrhs) => { - Self::generate_recommendation(cx, le_or_ge, rhslhs, lhs, Side::Rhs) - }, + BinOpKind::Sub if Self::is_one(rhsrhs) => Self::generate_recommendation(cx, le_or_ge, lhs, rhslhs), _ => None, } }, @@ -147,7 +137,6 @@ impl IntPlusOne { le_or_ge: LeOrGe, node: &Expr, other_side: &Expr, - side: Side, ) -> Option { let binop_string = match le_or_ge { LeOrGe::Ge => ">", @@ -156,11 +145,7 @@ impl IntPlusOne { if let Some(snippet) = node.span.get_source_text(cx) && let Some(other_side_snippet) = other_side.span.get_source_text(cx) { - let rec = match side { - Side::Lhs => Some(format!("{snippet} {binop_string} {other_side_snippet}")), - Side::Rhs => Some(format!("{other_side_snippet} {binop_string} {snippet}")), - }; - return rec; + return Some(format!("{snippet} {binop_string} {other_side_snippet}")); } None } From ccaa2fa9841447092bfe96111629747a27fa419a Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Fri, 9 Jan 2026 20:30:20 +0100 Subject: [PATCH 0507/1061] fix: respect reduced applicability By building the whole suggestion in `emit_suggestion`, we avoid the need to thread `Applicability` through `check_binop` into `generate_suggestion` --- clippy_lints/src/int_plus_one.rs | 69 +++++++++++++------------------- 1 file changed, 28 insertions(+), 41 deletions(-) diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 97b7afb61d86..b82ca0205a9f 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -1,5 +1,5 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg; use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind, UnOp}; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; @@ -80,17 +80,15 @@ impl IntPlusOne { } } - fn check_binop(cx: &EarlyContext<'_>, le_or_ge: LeOrGe, lhs: &Expr, rhs: &Expr) -> Option { + fn check_binop<'tcx>(le_or_ge: LeOrGe, lhs: &'tcx Expr, rhs: &'tcx Expr) -> Option<(&'tcx Expr, &'tcx Expr)> { match (le_or_ge, &lhs.kind, &rhs.kind) { // case where `x - 1 >= ...` or `-1 + x >= ...` (LeOrGe::Ge, ExprKind::Binary(lhskind, lhslhs, lhsrhs), _) => { match lhskind.node { // `-1 + x` - BinOpKind::Add if Self::is_neg_one(lhslhs) => { - Self::generate_recommendation(cx, le_or_ge, lhsrhs, rhs) - }, + BinOpKind::Add if Self::is_neg_one(lhslhs) => Some((lhsrhs, rhs)), // `x - 1` - BinOpKind::Sub if Self::is_one(lhsrhs) => Self::generate_recommendation(cx, le_or_ge, lhslhs, rhs), + BinOpKind::Sub if Self::is_one(lhsrhs) => Some((lhslhs, rhs)), _ => None, } }, @@ -98,9 +96,9 @@ impl IntPlusOne { (LeOrGe::Ge, _, ExprKind::Binary(rhskind, rhslhs, rhsrhs)) if rhskind.node == BinOpKind::Add => { // `y + 1` and `1 + y` if Self::is_one(rhslhs) { - Self::generate_recommendation(cx, le_or_ge, lhs, rhsrhs) + Some((lhs, rhsrhs)) } else if Self::is_one(rhsrhs) { - Self::generate_recommendation(cx, le_or_ge, lhs, rhslhs) + Some((lhs, rhslhs)) } else { None } @@ -109,9 +107,9 @@ impl IntPlusOne { (LeOrGe::Le, ExprKind::Binary(lhskind, lhslhs, lhsrhs), _) if lhskind.node == BinOpKind::Add => { // `1 + x` and `x + 1` if Self::is_one(lhslhs) { - Self::generate_recommendation(cx, le_or_ge, lhsrhs, rhs) + Some((lhsrhs, rhs)) } else if Self::is_one(lhsrhs) { - Self::generate_recommendation(cx, le_or_ge, lhslhs, rhs) + Some((lhslhs, rhs)) } else { None } @@ -120,11 +118,9 @@ impl IntPlusOne { (LeOrGe::Le, _, ExprKind::Binary(rhskind, rhslhs, rhsrhs)) => { match rhskind.node { // `-1 + y` - BinOpKind::Add if Self::is_neg_one(rhslhs) => { - Self::generate_recommendation(cx, le_or_ge, lhs, rhsrhs) - }, + BinOpKind::Add if Self::is_neg_one(rhslhs) => Some((lhs, rhsrhs)), // `y - 1` - BinOpKind::Sub if Self::is_one(rhsrhs) => Self::generate_recommendation(cx, le_or_ge, lhs, rhslhs), + BinOpKind::Sub if Self::is_one(rhsrhs) => Some((lhs, rhslhs)), _ => None, } }, @@ -132,33 +128,24 @@ impl IntPlusOne { } } - fn generate_recommendation( - cx: &EarlyContext<'_>, - le_or_ge: LeOrGe, - node: &Expr, - other_side: &Expr, - ) -> Option { - let binop_string = match le_or_ge { - LeOrGe::Ge => ">", - LeOrGe::Le => "<", - }; - if let Some(snippet) = node.span.get_source_text(cx) - && let Some(other_side_snippet) = other_side.span.get_source_text(cx) - { - return Some(format!("{snippet} {binop_string} {other_side_snippet}")); - } - None - } - - fn emit_warning(cx: &EarlyContext<'_>, block: &Expr, recommendation: String) { - span_lint_and_sugg( + fn emit_warning(cx: &EarlyContext<'_>, expr: &Expr, new_lhs: &Expr, le_or_ge: LeOrGe, new_rhs: &Expr) { + span_lint_and_then( cx, INT_PLUS_ONE, - block.span, + expr.span, "unnecessary `>= y + 1` or `x - 1 >=`", - "change it to", - recommendation, - Applicability::MachineApplicable, // snippet + |diag| { + let mut app = Applicability::MachineApplicable; + let ctxt = expr.span.ctxt(); + let new_lhs = sugg::Sugg::ast(cx, new_lhs, "_", ctxt, &mut app); + let new_rhs = sugg::Sugg::ast(cx, new_rhs, "_", ctxt, &mut app); + let new_binop = match le_or_ge { + LeOrGe::Ge => BinOpKind::Gt, + LeOrGe::Le => BinOpKind::Lt, + }; + let rec = sugg::make_binop(new_binop, &new_lhs, &new_rhs); + diag.span_suggestion(expr.span, "change it to", rec, app); + }, ); } } @@ -167,9 +154,9 @@ impl EarlyLintPass for IntPlusOne { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if let ExprKind::Binary(binop, lhs, rhs) = &expr.kind && let Ok(le_or_ge) = LeOrGe::try_from(binop.node) - && let Some(rec) = Self::check_binop(cx, le_or_ge, lhs, rhs) + && let Some((new_lhs, new_rhs)) = Self::check_binop(le_or_ge, lhs, rhs) { - Self::emit_warning(cx, expr, rec); + Self::emit_warning(cx, expr, new_lhs, le_or_ge, new_rhs); } } } From ea591b55f43483bacb2e8b2b1cb9f6c7aa999d7e Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Fri, 9 Jan 2026 23:15:06 +0100 Subject: [PATCH 0508/1061] fix `clippy_utils::std_or_core(_)` --- clippy_utils/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 2a620e917228..33f5f5c8873d 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2031,12 +2031,12 @@ pub fn is_expr_temporary_value(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } pub fn std_or_core(cx: &LateContext<'_>) -> Option<&'static str> { - if !is_no_std_crate(cx) { - Some("std") - } else if !is_no_core_crate(cx) { + if is_no_core_crate(cx) { + None + } else if is_no_std_crate(cx) { Some("core") } else { - None + Some("std") } } From f982bc6a2dd661dd5713a39e96d469c6309f3b2e Mon Sep 17 00:00:00 2001 From: Keith-Cancel Date: Thu, 8 Jan 2026 01:24:13 -0800 Subject: [PATCH 0509/1061] Fix ICE: can't type-check body of DefId, since type_consts don't have a body. Handling for inherent associated consts is missing elsewhere, remove so it can be handled later in that handling. Diagnostic not always be emitted on associated constant Add a test case and Fix for a different ICE I encountered. I noticed when trying various permuations of the test case code to see if I could find anymore ICEs. I did, but not one that I expected. So in the instances of the a named const not having any args, insantiate it directly. Since it is likely an inherent assocaiated const. Added tests. Centralize the is_type_const() logic. I also noticed basically the exact same check in other part the code. Const blocks can't be a type_const, therefore this check is uneeded. Fix comment spelling error. get_all_attrs is not valid to call for all DefIds it seems. Make sure that if the type is omitted for a type_const that we don't ICE. Co-Authored-By: Boxy --- .../src/check_consts/qualifs.rs | 12 +++------ .../rustc_hir_analysis/src/collect/type_of.rs | 17 +++++++++++- compiler/rustc_middle/src/ty/context.rs | 6 +++++ .../src/builder/expr/as_constant.rs | 10 ++++++- .../mgca/type_const-array-return.rs | 26 +++++++++++++++++++ .../type_const-inherent-const-omitted-type.rs | 12 +++++++++ ...e_const-inherent-const-omitted-type.stderr | 13 ++++++++++ .../type_const-only-in-impl-omitted-type.rs | 22 ++++++++++++++++ ...ype_const-only-in-impl-omitted-type.stderr | 16 ++++++++++++ .../mgca/type_const-recursive.rs | 8 ++++++ .../mgca/type_const-recursive.stderr | 11 ++++++++ .../ui/const-generics/mgca/type_const-use.rs | 13 ++++++++++ 12 files changed, 155 insertions(+), 11 deletions(-) create mode 100644 tests/ui/const-generics/mgca/type_const-array-return.rs create mode 100644 tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.rs create mode 100644 tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.stderr create mode 100644 tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.rs create mode 100644 tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.stderr create mode 100644 tests/ui/const-generics/mgca/type_const-recursive.rs create mode 100644 tests/ui/const-generics/mgca/type_const-recursive.stderr create mode 100644 tests/ui/const-generics/mgca/type_const-use.rs diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index 113e0d66c48a..02615e3bbc18 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -6,9 +6,7 @@ // having basically only two use-cases that act in different ways. use rustc_errors::ErrorGuaranteed; -use rustc_hir::attrs::AttributeKind; -use rustc_hir::def::DefKind; -use rustc_hir::{LangItem, find_attr}; +use rustc_hir::LangItem; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::*; use rustc_middle::ty::{self, AdtDef, Ty}; @@ -366,14 +364,10 @@ where // check performed after the promotion. Verify that with an assertion. assert!(promoted.is_none() || Q::ALLOW_PROMOTED); - // Avoid looking at attrs of anon consts as that will ICE - let is_type_const_item = - matches!(cx.tcx.def_kind(def), DefKind::Const | DefKind::AssocConst) - && find_attr!(cx.tcx.get_all_attrs(def), AttributeKind::TypeConst(_)); - // Don't peak inside trait associated constants, also `#[type_const] const` items // don't have bodies so there's nothing to look at - if promoted.is_none() && cx.tcx.trait_of_assoc(def).is_none() && !is_type_const_item { + if promoted.is_none() && cx.tcx.trait_of_assoc(def).is_none() && !cx.tcx.is_type_const(def) + { let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def); if !Q::in_qualifs(&qualifs) { diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index aa0e5c7fd710..910176a0689c 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -420,7 +420,22 @@ fn infer_placeholder_type<'tcx>( kind: &'static str, ) -> Ty<'tcx> { let tcx = cx.tcx(); - let ty = tcx.typeck(def_id).node_type(hir_id); + // If the type is omitted on a #[type_const] we can't run + // type check on since that requires the const have a body + // which type_consts don't. + let ty = if tcx.is_type_const(def_id.to_def_id()) { + if let Some(trait_item_def_id) = tcx.trait_item_of(def_id.to_def_id()) { + tcx.type_of(trait_item_def_id).instantiate_identity() + } else { + Ty::new_error_with_message( + tcx, + ty_span, + "constant with #[type_const] requires an explicit type", + ) + } + } else { + tcx.typeck(def_id).node_type(hir_id) + }; // If this came from a free `const` or `static mut?` item, // then the user may have written e.g. `const A = 42;`. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index a2f4714d1b2c..a3eec72214c0 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1891,6 +1891,12 @@ impl<'tcx> TyCtxt<'tcx> { self.is_lang_item(self.parent(def_id), LangItem::AsyncDropInPlace) } + /// Check if the given `def_id` is a const with the `#[type_const]` attribute. + pub fn is_type_const(self, def_id: DefId) -> bool { + matches!(self.def_kind(def_id), DefKind::Const | DefKind::AssocConst) + && find_attr!(self.get_all_attrs(def_id), AttributeKind::TypeConst(_)) + } + /// Returns the movability of the coroutine of `def_id`, or panics /// if given a `def_id` that is not a coroutine. pub fn coroutine_movability(self, def_id: DefId) -> hir::Movability { diff --git a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs index 186fde4883df..1772d66f5285 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs @@ -1,7 +1,7 @@ //! See docs in build/expr/mod.rs use rustc_abi::Size; -use rustc_ast as ast; +use rustc_ast::{self as ast}; use rustc_hir::LangItem; use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, LitToConstInput, Scalar}; use rustc_middle::mir::*; @@ -47,6 +47,7 @@ pub(crate) fn as_constant_inner<'tcx>( tcx: TyCtxt<'tcx>, ) -> ConstOperand<'tcx> { let Expr { ty, temp_scope_id: _, span, ref kind } = *expr; + match *kind { ExprKind::Literal { lit, neg } => { let const_ = lit_to_mir_constant(tcx, LitToConstInput { lit: lit.node, ty, neg }); @@ -69,6 +70,13 @@ pub(crate) fn as_constant_inner<'tcx>( } ExprKind::NamedConst { def_id, args, ref user_ty } => { let user_ty = user_ty.as_ref().and_then(push_cuta); + if tcx.is_type_const(def_id) { + let uneval = ty::UnevaluatedConst::new(def_id, args); + let ct = ty::Const::new_unevaluated(tcx, uneval); + + let const_ = Const::Ty(ty, ct); + return ConstOperand { span, user_ty, const_ }; + } let uneval = mir::UnevaluatedConst::new(def_id, args); let const_ = Const::Unevaluated(uneval, ty); diff --git a/tests/ui/const-generics/mgca/type_const-array-return.rs b/tests/ui/const-generics/mgca/type_const-array-return.rs new file mode 100644 index 000000000000..5375e4fded6d --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-array-return.rs @@ -0,0 +1,26 @@ +//@ check-pass +// This test should compile without an ICE. +#![expect(incomplete_features)] +#![feature(min_generic_const_args)] + +pub struct A; + +pub trait Array { + #[type_const] + const LEN: usize; + fn arr() -> [u8; Self::LEN]; +} + +impl Array for A { + #[type_const] + const LEN: usize = 4; + + #[allow(unused_braces)] + fn arr() -> [u8; const { Self::LEN }] { + return [0u8; const { Self::LEN }]; + } +} + +fn main() { + let _ = A::arr(); +} diff --git a/tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.rs b/tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.rs new file mode 100644 index 000000000000..b2c734098009 --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.rs @@ -0,0 +1,12 @@ +#![expect(incomplete_features)] +#![feature(min_generic_const_args)] + +struct A; + +impl A { + #[type_const] + const B = 4; + //~^ ERROR: missing type for `const` item +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.stderr b/tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.stderr new file mode 100644 index 000000000000..b44e47cd7e61 --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.stderr @@ -0,0 +1,13 @@ +error: missing type for `const` item + --> $DIR/type_const-inherent-const-omitted-type.rs:8:12 + | +LL | const B = 4; + | ^ + | +help: provide a type for the item + | +LL | const B: = 4; + | ++++++++ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.rs b/tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.rs new file mode 100644 index 000000000000..ab613859aa5c --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.rs @@ -0,0 +1,22 @@ +#![expect(incomplete_features)] +#![feature(min_generic_const_args)] + +trait BadTr { + const NUM: usize; +} + +struct GoodS; + +impl BadTr for GoodS { + #[type_const] + const NUM: = 84; + //~^ ERROR: missing type for `const` item + +} + +fn accept_bad_tr>(_x: &T) {} +//~^ ERROR use of trait associated const without `#[type_const]` + +fn main() { + accept_bad_tr::<84, _>(&GoodS); +} diff --git a/tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.stderr b/tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.stderr new file mode 100644 index 000000000000..16f312454ed2 --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.stderr @@ -0,0 +1,16 @@ +error: missing type for `const` item + --> $DIR/type_const-only-in-impl-omitted-type.rs:12:15 + | +LL | const NUM: = 84; + | ^ help: provide a type for the associated constant: `usize` + +error: use of trait associated const without `#[type_const]` + --> $DIR/type_const-only-in-impl-omitted-type.rs:17:43 + | +LL | fn accept_bad_tr>(_x: &T) {} + | ^^^^^^^^^^^ + | + = note: the declaration in the trait must be marked with `#[type_const]` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/const-generics/mgca/type_const-recursive.rs b/tests/ui/const-generics/mgca/type_const-recursive.rs new file mode 100644 index 000000000000..15e49f747ed6 --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-recursive.rs @@ -0,0 +1,8 @@ +#![expect(incomplete_features)] +#![feature(min_generic_const_args)] + +#[type_const] +const A: u8 = A; +//~^ ERROR: overflow normalizing the unevaluated constant `A` [E0275] + +fn main() {} diff --git a/tests/ui/const-generics/mgca/type_const-recursive.stderr b/tests/ui/const-generics/mgca/type_const-recursive.stderr new file mode 100644 index 000000000000..947319ec7eda --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-recursive.stderr @@ -0,0 +1,11 @@ +error[E0275]: overflow normalizing the unevaluated constant `A` + --> $DIR/type_const-recursive.rs:5:1 + | +LL | const A: u8 = A; + | ^^^^^^^^^^^ + | + = note: in case this is a recursive type alias, consider using a struct, enum, or union instead + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/const-generics/mgca/type_const-use.rs b/tests/ui/const-generics/mgca/type_const-use.rs new file mode 100644 index 000000000000..04362cd28538 --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-use.rs @@ -0,0 +1,13 @@ +//@ check-pass +// This test should compile without an ICE. +#![expect(incomplete_features)] +#![feature(min_generic_const_args)] + +#[type_const] +const CONST: usize = 1; + +fn uses_const() { + CONST; +} + +fn main() {} From 9156b540aa35820a87c377b780e6058fe5dface9 Mon Sep 17 00:00:00 2001 From: Guilherme Luiz Date: Fri, 9 Jan 2026 19:33:18 -0300 Subject: [PATCH 0510/1061] =?UTF-8?q?Update=20to=5Fuppercase=20docs=20to?= =?UTF-8?q?=20avoid=20=C3=9F->SS=20example?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- library/core/src/char/methods.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 89cb06972392..c30edeed580a 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -1147,7 +1147,7 @@ impl char { /// As an iterator: /// /// ``` - /// for c in 'ß'.to_uppercase() { + /// for c in 'ffi'.to_uppercase() { /// print!("{c}"); /// } /// println!(); @@ -1156,13 +1156,13 @@ impl char { /// Using `println!` directly: /// /// ``` - /// println!("{}", 'ß'.to_uppercase()); + /// println!("{}", 'ffi'.to_uppercase()); /// ``` /// /// Both are equivalent to: /// /// ``` - /// println!("SS"); + /// println!("FFI"); /// ``` /// /// Using [`to_string`](../std/string/trait.ToString.html#tymethod.to_string): @@ -1171,7 +1171,7 @@ impl char { /// assert_eq!('c'.to_uppercase().to_string(), "C"); /// /// // Sometimes the result is more than one character: - /// assert_eq!('ß'.to_uppercase().to_string(), "SS"); + /// assert_eq!('ffi'.to_uppercase().to_string(), "FFI"); /// /// // Characters that do not have both uppercase and lowercase /// // convert into themselves. From 3f51a315e0668ff1c72459a08dfc42780032918c Mon Sep 17 00:00:00 2001 From: Paul Mabileau Date: Fri, 9 Jan 2026 21:20:39 +0100 Subject: [PATCH 0511/1061] Fix(lib/win/net): Remove hostname support under Win7 `GetHostNameW` is not available under Windows 7, leading to dynamic linking failures upon program executions. For now, as it is still unstable, this therefore appropriately cfg-gates the feature in order to mark the Win7 as unsupported with regards to this particular feature. Porting the functionality for Windows 7 would require changing the underlying system call and so more work for the immediate need. Signed-off-by: Paul Mabileau --- library/std/src/net/hostname.rs | 8 ++++---- library/std/src/sys/net/hostname/mod.rs | 3 ++- library/std/src/sys/pal/windows/c.rs | 4 ++++ library/std/src/sys/pal/windows/c/bindings.txt | 1 - library/std/src/sys/pal/windows/c/windows_sys.rs | 1 - 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/library/std/src/net/hostname.rs b/library/std/src/net/hostname.rs index b1010cec6005..4042496d534f 100644 --- a/library/std/src/net/hostname.rs +++ b/library/std/src/net/hostname.rs @@ -8,10 +8,10 @@ use crate::ffi::OsString; /// /// # Underlying system calls /// -/// | Platform | System call | -/// |----------|---------------------------------------------------------------------------------------------------------| -/// | UNIX | [`gethostname`](https://www.man7.org/linux/man-pages/man2/gethostname.2.html) | -/// | Windows | [`GetHostNameW`](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-gethostnamew) | +/// | Platform | System call | +/// |--------------|---------------------------------------------------------------------------------------------------------| +/// | UNIX | [`gethostname`](https://www.man7.org/linux/man-pages/man2/gethostname.2.html) | +/// | Windows (8+) | [`GetHostNameW`](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-gethostnamew) | /// /// Note that platform-specific behavior [may change in the future][changes]. /// diff --git a/library/std/src/sys/net/hostname/mod.rs b/library/std/src/sys/net/hostname/mod.rs index 8ffe4894d718..65fcd6bfb00d 100644 --- a/library/std/src/sys/net/hostname/mod.rs +++ b/library/std/src/sys/net/hostname/mod.rs @@ -3,7 +3,8 @@ cfg_select! { mod unix; pub use unix::hostname; } - target_os = "windows" => { + // `GetHostNameW` is only available starting with Windows 8. + all(target_os = "windows", not(target_vendor = "win7")) => { mod windows; pub use windows::hostname; } diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 25c1a82cc426..0f54f80d72ee 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -237,3 +237,7 @@ cfg_select! { } _ => {} } + +// Only available starting with Windows 8. +#[cfg(not(target_vendor = "win7"))] +windows_targets::link!("ws2_32.dll" "system" fn GetHostNameW(name : PWSTR, namelen : i32) -> i32); diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index 9009aa09f48e..12babcb84ccf 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2170,7 +2170,6 @@ GetFileType GETFINALPATHNAMEBYHANDLE_FLAGS GetFinalPathNameByHandleW GetFullPathNameW -GetHostNameW GetLastError GetModuleFileNameW GetModuleHandleA diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index 98f277b33780..edc9d2d11f7c 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -49,7 +49,6 @@ windows_targets::link!("kernel32.dll" "system" fn GetFileSizeEx(hfile : HANDLE, windows_targets::link!("kernel32.dll" "system" fn GetFileType(hfile : HANDLE) -> FILE_TYPE); windows_targets::link!("kernel32.dll" "system" fn GetFinalPathNameByHandleW(hfile : HANDLE, lpszfilepath : PWSTR, cchfilepath : u32, dwflags : GETFINALPATHNAMEBYHANDLE_FLAGS) -> u32); windows_targets::link!("kernel32.dll" "system" fn GetFullPathNameW(lpfilename : PCWSTR, nbufferlength : u32, lpbuffer : PWSTR, lpfilepart : *mut PWSTR) -> u32); -windows_targets::link!("ws2_32.dll" "system" fn GetHostNameW(name : PWSTR, namelen : i32) -> i32); windows_targets::link!("kernel32.dll" "system" fn GetLastError() -> WIN32_ERROR); windows_targets::link!("kernel32.dll" "system" fn GetModuleFileNameW(hmodule : HMODULE, lpfilename : PWSTR, nsize : u32) -> u32); windows_targets::link!("kernel32.dll" "system" fn GetModuleHandleA(lpmodulename : PCSTR) -> HMODULE); From 07fa70e104647b4b9b4ad9ba93bfaaba4ed5bcdf Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 9 Jan 2026 19:15:49 -0600 Subject: [PATCH 0512/1061] llvm: Update `reliable_f16` configuration for LLVM22 Since yesterday, the LLVM `main` branch should have working `f16` on all platforms that Rust supports; this will be LLVM version 22, so update how `cfg(target_has_reliable_f16)` is set to reflect this. Within the rust-lang organization, this currently has no effect. The goal is to start catching problems as early as possible in external CI that runs top-of-tree rust against top-of-tree LLVM, and once testing for the rust-lang bump to LLVM 22 starts. Hopefully this will mean that we can fix any problems that show up before the bump actually happens, meaning `f16` will be about ready for stabilization at that point (with some considerations for the GCC patch at [1] propagating). References: * https://github.com/llvm/llvm-project/commit/919021b0df8c91417784bfd84a6ad4869a0d2206 * https://github.com/llvm/llvm-project/commit/054ee2f8706b582859fcf96d1771aa68c37d9e6a * https://github.com/llvm/llvm-project/commit/db26ce5c5572a1a54ce307c762689ab63e5c5485 * https://github.com/llvm/llvm-project/commit/549d7c4f35a99598a269004ee13b237d2565b5ec * https://github.com/llvm/llvm-project/commit/4903c6260cbd781881906007f9c82aceb71fd7c7 [1]: https://github.com/gcc-mirror/gcc/commit/8b6a18ecaf44553230b90bf28adfb9fe9c9d5ab9 --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 9b08f4e9869c..63f820dc2918 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -379,19 +379,19 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) { { false } - // Unsupported - (Arch::Arm64EC, _) => false, + // Unsupported (fixed in llvm22) + (Arch::Arm64EC, _) if major < 22 => false, // Selection failure (fixed in llvm21) (Arch::S390x, _) if major < 21 => false, // MinGW ABI bugs (Arch::X86_64, Os::Windows) if *target_env == Env::Gnu && *target_abi != Abi::Llvm => false, // Infinite recursion - (Arch::CSky, _) => false, + (Arch::CSky, _) if major < 22 => false, // (fixed in llvm22) (Arch::Hexagon, _) if major < 21 => false, // (fixed in llvm21) (Arch::LoongArch32 | Arch::LoongArch64, _) if major < 21 => false, // (fixed in llvm21) - (Arch::PowerPC | Arch::PowerPC64, _) => false, - (Arch::Sparc | Arch::Sparc64, _) => false, - (Arch::Wasm32 | Arch::Wasm64, _) => false, + (Arch::PowerPC | Arch::PowerPC64, _) if major < 22 => false, // (fixed in llvm22) + (Arch::Sparc | Arch::Sparc64, _) if major < 22 => false, // (fixed in llvm22) + (Arch::Wasm32 | Arch::Wasm64, _) if major < 22 => false, // (fixed in llvm22) // `f16` support only requires that symbols converting to and from `f32` are available. We // provide these in `compiler-builtins`, so `f16` should be available on all platforms that // do not have other ABI issues or LLVM crashes. From fc06a57a786de3efc723c9c00085f481157b72df Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Wed, 7 Jan 2026 19:47:02 +0900 Subject: [PATCH 0513/1061] Introduce hir::ConstArgKind::Array --- compiler/rustc_ast_lowering/src/lib.rs | 19 +++++++++++++++++++ compiler/rustc_hir/src/hir.rs | 8 ++++++++ compiler/rustc_hir/src/intravisit.rs | 6 ++++++ .../src/hir_ty_lowering/mod.rs | 3 +++ compiler/rustc_hir_pretty/src/lib.rs | 1 + compiler/rustc_metadata/src/rmeta/encoder.rs | 1 + compiler/rustc_resolve/src/def_collector.rs | 2 +- src/librustdoc/clean/mod.rs | 3 +++ 8 files changed, 42 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 42eb8673f30c..de403a262879 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2517,6 +2517,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span, } } + ExprKind::Array(elements) => { + let lowered_elems = self.arena.alloc_from_iter(elements.iter().map(|element| { + let const_arg = if let ExprKind::ConstBlock(anon_const) = &element.kind { + let def_id = self.local_def_id(anon_const.id); + assert_eq!(DefKind::AnonConst, self.tcx.def_kind(def_id)); + self.lower_anon_const_to_const_arg(anon_const) + } else { + self.lower_expr_to_const_arg_direct(element) + }; + &*self.arena.alloc(const_arg) + })); + let array_expr = self.arena.alloc(hir::ConstArgArrayExpr { + span: self.lower_span(expr.span), + elems: lowered_elems, + }); + + ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Array(array_expr) } + } ExprKind::Underscore => ConstArg { hir_id: self.lower_node_id(expr.id), kind: hir::ConstArgKind::Infer(()), @@ -2532,6 +2550,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { | ExprKind::Struct(..) | ExprKind::Call(..) | ExprKind::Tup(..) + | ExprKind::Array(..) ) { return self.lower_expr_to_const_arg_direct(expr); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2fb6daf6469b..055df9c2a085 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -513,6 +513,8 @@ pub enum ConstArgKind<'hir, Unambig = ()> { Struct(QPath<'hir>, &'hir [&'hir ConstArgExprField<'hir>]), /// Tuple constructor variant TupleCall(QPath<'hir>, &'hir [&'hir ConstArg<'hir>]), + /// Array literal argument + Array(&'hir ConstArgArrayExpr<'hir>), /// Error const Error(ErrorGuaranteed), /// This variant is not always used to represent inference consts, sometimes @@ -529,6 +531,12 @@ pub struct ConstArgExprField<'hir> { pub expr: &'hir ConstArg<'hir>, } +#[derive(Clone, Copy, Debug, HashStable_Generic)] +pub struct ConstArgArrayExpr<'hir> { + pub span: Span, + pub elems: &'hir [&'hir ConstArg<'hir>], +} + #[derive(Clone, Copy, Debug, HashStable_Generic)] pub struct InferArg { #[stable_hasher(ignore)] diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index e5e6fc7b1d8d..d1b75325af26 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1101,6 +1101,12 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>( } V::Result::output() } + ConstArgKind::Array(array_expr) => { + for arg in array_expr.elems { + try_visit!(visitor.visit_const_arg_unambig(*arg)); + } + V::Result::output() + } ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, qpath.span()), ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon), ConstArgKind::Error(_) => V::Result::output(), // errors and spans are not important diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 1dd9bff42575..42893906a386 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2389,6 +2389,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::ConstArgKind::TupleCall(qpath, args) => { self.lower_const_arg_tuple_call(hir_id, qpath, args, const_arg.span) } + hir::ConstArgKind::Array(_array_expr) => { + span_bug!(const_arg.span(), "lowering `{:?}` is not yet implemented", const_arg) + } hir::ConstArgKind::Anon(anon) => self.lower_const_arg_anon(anon), hir::ConstArgKind::Infer(()) => self.ct_infer(None, const_arg.span), hir::ConstArgKind::Error(e) => ty::Const::new_error(tcx, e), diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 37fa18c00887..e0e9fe775853 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1153,6 +1153,7 @@ impl<'a> State<'a> { } ConstArgKind::Struct(qpath, fields) => self.print_const_struct(qpath, fields), ConstArgKind::TupleCall(qpath, args) => self.print_const_ctor(qpath, args), + ConstArgKind::Array(..) => self.word("/* ARRAY EXPR */"), ConstArgKind::Path(qpath) => self.print_qpath(qpath, true), ConstArgKind::Anon(anon) => self.print_anon_const(anon), ConstArgKind::Error(_) => self.word("/*ERROR*/"), diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index c85327dc3db1..fd0fcb18bfe1 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1441,6 +1441,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // Skip encoding defs for these as they should not have had a `DefId` created hir::ConstArgKind::Error(..) | hir::ConstArgKind::Struct(..) + | hir::ConstArgKind::Array(..) | hir::ConstArgKind::TupleCall(..) | hir::ConstArgKind::Tup(..) | hir::ConstArgKind::Path(..) diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index b392b7747b55..ea5640ecc1fa 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -419,7 +419,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { // Avoid overwriting `const_arg_context` as we may want to treat const blocks // as being anon consts if we are inside a const argument. - ExprKind::Struct(_) | ExprKind::Call(..) | ExprKind::Tup(..) => { + ExprKind::Struct(_) | ExprKind::Call(..) | ExprKind::Tup(..) | ExprKind::Array(..) => { return visit::walk_expr(self, expr); } // FIXME(mgca): we may want to handle block labels in some manner diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 817eda4c52ec..c8e38330b82c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -329,6 +329,8 @@ pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg<'tcx>) -> ConstantKind hir::ConstArgKind::Tup(..) => { // FIXME(mgca): proper printing :3 ConstantKind::Path { path: "/* TUPLE EXPR */".to_string().into() } + hir::ConstArgKind::Array(..) => { + ConstantKind::Path { path: "/* ARRAY EXPR */".to_string().into() } } hir::ConstArgKind::Anon(anon) => ConstantKind::Anonymous { body: anon.body }, hir::ConstArgKind::Infer(..) | hir::ConstArgKind::Error(..) => ConstantKind::Infer, @@ -1818,6 +1820,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T | hir::ConstArgKind::Path(..) | hir::ConstArgKind::TupleCall(..) | hir::ConstArgKind::Tup(..) + | hir::ConstArgKind::Array(..) | hir::ConstArgKind::Literal(..) => { let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, FeedConstTy::No); print_const(cx, ct) From 618b0b5464b8c078fbfaea3f3181d7248072a183 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 8 Jan 2026 10:35:52 +0900 Subject: [PATCH 0514/1061] Lower hir::ConstArgKind::Array to a ValTree --- compiler/rustc_ast_lowering/src/lib.rs | 6 +++- .../src/hir_ty_lowering/mod.rs | 34 +++++++++++++++++-- src/librustdoc/clean/mod.rs | 1 + tests/ui/const-generics/mgca/array-expr.rs | 24 +++++++++++++ .../ui/const-generics/mgca/array-expr.stderr | 14 ++++++++ 5 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 tests/ui/const-generics/mgca/array-expr.rs create mode 100644 tests/ui/const-generics/mgca/array-expr.stderr diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index de403a262879..350fa04ab3bd 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2533,7 +2533,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { elems: lowered_elems, }); - ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Array(array_expr) } + ConstArg { + hir_id: self.next_id(), + kind: hir::ConstArgKind::Array(array_expr), + span, + } } ExprKind::Underscore => ConstArg { hir_id: self.lower_node_id(expr.id), diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 42893906a386..6f44a728242d 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2389,9 +2389,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::ConstArgKind::TupleCall(qpath, args) => { self.lower_const_arg_tuple_call(hir_id, qpath, args, const_arg.span) } - hir::ConstArgKind::Array(_array_expr) => { - span_bug!(const_arg.span(), "lowering `{:?}` is not yet implemented", const_arg) - } + hir::ConstArgKind::Array(array_expr) => self.lower_const_arg_array(array_expr, feed), hir::ConstArgKind::Anon(anon) => self.lower_const_arg_anon(anon), hir::ConstArgKind::Infer(()) => self.ct_infer(None, const_arg.span), hir::ConstArgKind::Error(e) => ty::Const::new_error(tcx, e), @@ -2405,6 +2403,36 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } + fn lower_const_arg_array( + &self, + array_expr: &'tcx hir::ConstArgArrayExpr<'tcx>, + feed: FeedConstTy<'tcx>, + ) -> Const<'tcx> { + let tcx = self.tcx(); + + let FeedConstTy::WithTy(ty) = feed else { + return Const::new_error_with_message(tcx, array_expr.span, "unsupported const array"); + }; + + let ty::Array(elem_ty, _) = ty.kind() else { + return Const::new_error_with_message( + tcx, + array_expr.span, + "const array must have an array type", + ); + }; + + let elems = array_expr + .elems + .iter() + .map(|elem| self.lower_const_arg(elem, FeedConstTy::WithTy(*elem_ty))) + .collect::>(); + + let valtree = ty::ValTree::from_branches(tcx, elems); + + ty::Const::new_value(tcx, valtree, ty) + } + fn lower_const_arg_tuple_call( &self, hir_id: HirId, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c8e38330b82c..597a85f39769 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -329,6 +329,7 @@ pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg<'tcx>) -> ConstantKind hir::ConstArgKind::Tup(..) => { // FIXME(mgca): proper printing :3 ConstantKind::Path { path: "/* TUPLE EXPR */".to_string().into() } + } hir::ConstArgKind::Array(..) => { ConstantKind::Path { path: "/* ARRAY EXPR */".to_string().into() } } diff --git a/tests/ui/const-generics/mgca/array-expr.rs b/tests/ui/const-generics/mgca/array-expr.rs new file mode 100644 index 000000000000..099fee7ecd03 --- /dev/null +++ b/tests/ui/const-generics/mgca/array-expr.rs @@ -0,0 +1,24 @@ +#![expect(incomplete_features)] +#![feature(min_generic_const_args, adt_const_params)] + +fn takes_array() {} + +fn generic_caller() { + takes_array::<{ [N, N2, N] }>(); // ok + + takes_array::<{ [N, N2, const { 1 }] }>(); // ok + + takes_array::<{ [N, N2, const { 1 + 1 }] }>(); // ok + + takes_array::<{ [N, N2, 1] }>(); // ok + + takes_array::<{ [1, 1u32, 1_u32] }>(); // ok + + takes_array::<{ [N, N2, 1 + 1] }>(); // not implemented + //~^ ERROR complex const arguments must be placed inside of a `const` block + + takes_array::<{ [N; 3] }>(); // not implemented + //~^ ERROR complex const arguments must be placed inside of a `const` block +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/array-expr.stderr b/tests/ui/const-generics/mgca/array-expr.stderr new file mode 100644 index 000000000000..0dda791c2e10 --- /dev/null +++ b/tests/ui/const-generics/mgca/array-expr.stderr @@ -0,0 +1,14 @@ +error: complex const arguments must be placed inside of a `const` block + --> $DIR/array-expr.rs:17:29 + | +LL | takes_array::<{ [N, N2, 1 + 1] }>(); // not implemented + | ^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/array-expr.rs:20:19 + | +LL | takes_array::<{ [N; 3] }>(); // not implemented + | ^^^^^^^^^^ + +error: aborting due to 2 previous errors + From 522be7f1c0430cd7201b1f75ec72cb473099835c Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 8 Jan 2026 12:19:43 +0900 Subject: [PATCH 0515/1061] Fix clippy --- src/tools/clippy/clippy_lints/src/utils/author.rs | 1 + src/tools/clippy/clippy_utils/src/consts.rs | 1 + src/tools/clippy/clippy_utils/src/hir_utils.rs | 11 +++++++++++ 3 files changed, 13 insertions(+) diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index acea701b2e83..8243077cab89 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -321,6 +321,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { }, ConstArgKind::Struct(..) => chain!(self, "let ConstArgKind::Struct(..) = {const_arg}.kind"), ConstArgKind::TupleCall(..) => chain!(self, "let ConstArgKind::TupleCall(..) = {const_arg}.kind"), + ConstArgKind::Array(..) => chain!(self, "let ConstArgKind::Array(..) = {const_arg}.kind"), ConstArgKind::Infer(..) => chain!(self, "let ConstArgKind::Infer(..) = {const_arg}.kind"), ConstArgKind::Error(..) => chain!(self, "let ConstArgKind::Error(..) = {const_arg}.kind"), ConstArgKind::Tup(..) => chain!(self, "let ConstArgKind::Tup(..) = {const_arg}.kind"), diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 538f1fd2628c..e2ada37d53b3 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -1144,6 +1144,7 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx | ConstArgKind::Tup(..) | ConstArgKind::Literal(..) | ConstArgKind::TupleCall(..) + | ConstArgKind::Array(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => None, diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 0bb641568879..c7bb3a064a09 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -687,6 +687,11 @@ impl HirEqInterExpr<'_, '_, '_> { .all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b)) }, (ConstArgKind::Literal(kind_l), ConstArgKind::Literal(kind_r)) => kind_l == kind_r, + (ConstArgKind::Array(l_arr), ConstArgKind::Array(r_arr)) => { + l_arr.elems.len() == r_arr.elems.len() + && l_arr.elems.iter().zip(r_arr.elems.iter()) + .all(|(l_elem, r_elem)| self.eq_const_arg(l_elem, r_elem)) + } // Use explicit match for now since ConstArg is undergoing flux. ( ConstArgKind::Path(..) @@ -696,6 +701,7 @@ impl HirEqInterExpr<'_, '_, '_> { | ConstArgKind::Infer(..) | ConstArgKind::Struct(..) | ConstArgKind::Literal(..) + | ConstArgKind::Array(..) | ConstArgKind::Error(..), _, ) => false, @@ -1575,6 +1581,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_const_arg(arg); } }, + ConstArgKind::Array(array_expr) => { + for elem in array_expr.elems { + self.hash_const_arg(elem); + } + }, ConstArgKind::Infer(..) | ConstArgKind::Error(..) => {}, ConstArgKind::Literal(lit) => lit.hash(&mut self.s), } From f4a6e4f0d94670e162370c2a495b0f1a8bb43262 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 8 Jan 2026 12:19:43 +0900 Subject: [PATCH 0516/1061] Fix clippy --- clippy_lints/src/utils/author.rs | 1 + clippy_utils/src/consts.rs | 1 + clippy_utils/src/hir_utils.rs | 11 +++++++++++ 3 files changed, 13 insertions(+) diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index acea701b2e83..8243077cab89 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -321,6 +321,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { }, ConstArgKind::Struct(..) => chain!(self, "let ConstArgKind::Struct(..) = {const_arg}.kind"), ConstArgKind::TupleCall(..) => chain!(self, "let ConstArgKind::TupleCall(..) = {const_arg}.kind"), + ConstArgKind::Array(..) => chain!(self, "let ConstArgKind::Array(..) = {const_arg}.kind"), ConstArgKind::Infer(..) => chain!(self, "let ConstArgKind::Infer(..) = {const_arg}.kind"), ConstArgKind::Error(..) => chain!(self, "let ConstArgKind::Error(..) = {const_arg}.kind"), ConstArgKind::Tup(..) => chain!(self, "let ConstArgKind::Tup(..) = {const_arg}.kind"), diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 538f1fd2628c..e2ada37d53b3 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -1144,6 +1144,7 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx | ConstArgKind::Tup(..) | ConstArgKind::Literal(..) | ConstArgKind::TupleCall(..) + | ConstArgKind::Array(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => None, diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 0bb641568879..c7bb3a064a09 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -687,6 +687,11 @@ impl HirEqInterExpr<'_, '_, '_> { .all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b)) }, (ConstArgKind::Literal(kind_l), ConstArgKind::Literal(kind_r)) => kind_l == kind_r, + (ConstArgKind::Array(l_arr), ConstArgKind::Array(r_arr)) => { + l_arr.elems.len() == r_arr.elems.len() + && l_arr.elems.iter().zip(r_arr.elems.iter()) + .all(|(l_elem, r_elem)| self.eq_const_arg(l_elem, r_elem)) + } // Use explicit match for now since ConstArg is undergoing flux. ( ConstArgKind::Path(..) @@ -696,6 +701,7 @@ impl HirEqInterExpr<'_, '_, '_> { | ConstArgKind::Infer(..) | ConstArgKind::Struct(..) | ConstArgKind::Literal(..) + | ConstArgKind::Array(..) | ConstArgKind::Error(..), _, ) => false, @@ -1575,6 +1581,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_const_arg(arg); } }, + ConstArgKind::Array(array_expr) => { + for elem in array_expr.elems { + self.hash_const_arg(elem); + } + }, ConstArgKind::Infer(..) | ConstArgKind::Error(..) => {}, ConstArgKind::Literal(lit) => lit.hash(&mut self.s), } From f2f45ffddd584377b36e1da628b79d05d538a2a4 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 9 Jan 2026 14:13:41 +0900 Subject: [PATCH 0517/1061] Add mGCA array expression tests --- .../const-generics/mgca/array-expr-complex.rs | 16 ++++++++++++ .../mgca/array-expr-complex.stderr | 20 +++++++++++++++ .../const-generics/mgca/array-expr-empty.rs | 9 +++++++ .../mgca/array-expr-empty.stderr | 8 ++++++ .../const-generics/mgca/array-expr-simple.rs | 25 +++++++++++++++++++ .../mgca/array-expr-with-assoc-const.rs | 18 +++++++++++++ .../mgca/array-expr-with-macro.rs | 18 +++++++++++++ .../mgca/array-expr-with-struct.rs | 20 +++++++++++++++ .../mgca/array-expr-with-tuple.rs | 13 ++++++++++ tests/ui/const-generics/mgca/array-expr.rs | 24 ------------------ .../ui/const-generics/mgca/array-expr.stderr | 14 ----------- 11 files changed, 147 insertions(+), 38 deletions(-) create mode 100644 tests/ui/const-generics/mgca/array-expr-complex.rs create mode 100644 tests/ui/const-generics/mgca/array-expr-complex.stderr create mode 100644 tests/ui/const-generics/mgca/array-expr-empty.rs create mode 100644 tests/ui/const-generics/mgca/array-expr-empty.stderr create mode 100644 tests/ui/const-generics/mgca/array-expr-simple.rs create mode 100644 tests/ui/const-generics/mgca/array-expr-with-assoc-const.rs create mode 100644 tests/ui/const-generics/mgca/array-expr-with-macro.rs create mode 100644 tests/ui/const-generics/mgca/array-expr-with-struct.rs create mode 100644 tests/ui/const-generics/mgca/array-expr-with-tuple.rs delete mode 100644 tests/ui/const-generics/mgca/array-expr.rs delete mode 100644 tests/ui/const-generics/mgca/array-expr.stderr diff --git a/tests/ui/const-generics/mgca/array-expr-complex.rs b/tests/ui/const-generics/mgca/array-expr-complex.rs new file mode 100644 index 000000000000..3e8320bc94de --- /dev/null +++ b/tests/ui/const-generics/mgca/array-expr-complex.rs @@ -0,0 +1,16 @@ +#![expect(incomplete_features)] +#![feature(min_generic_const_args, adt_const_params)] + +fn takes_array() {} + +fn generic_caller() { + // not supported yet + takes_array::<{ [1, 2, 1 + 2] }>(); + //~^ ERROR: complex const arguments must be placed inside of a `const` block + takes_array::<{ [X; 3] }>(); + //~^ ERROR: complex const arguments must be placed inside of a `const` block + takes_array::<{ [0; Y] }>(); + //~^ ERROR: complex const arguments must be placed inside of a `const` block +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/array-expr-complex.stderr b/tests/ui/const-generics/mgca/array-expr-complex.stderr new file mode 100644 index 000000000000..beac1aa232f2 --- /dev/null +++ b/tests/ui/const-generics/mgca/array-expr-complex.stderr @@ -0,0 +1,20 @@ +error: complex const arguments must be placed inside of a `const` block + --> $DIR/array-expr-complex.rs:8:28 + | +LL | takes_array::<{ [1, 2, 1 + 2] }>(); + | ^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/array-expr-complex.rs:10:19 + | +LL | takes_array::<{ [X; 3] }>(); + | ^^^^^^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/array-expr-complex.rs:12:19 + | +LL | takes_array::<{ [0; Y] }>(); + | ^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/const-generics/mgca/array-expr-empty.rs b/tests/ui/const-generics/mgca/array-expr-empty.rs new file mode 100644 index 000000000000..d37c6f2fcfe3 --- /dev/null +++ b/tests/ui/const-generics/mgca/array-expr-empty.rs @@ -0,0 +1,9 @@ +#![expect(incomplete_features)] +#![feature(min_generic_const_args)] + +fn takes_empty_array() {} +//~^ ERROR: expected type, found `]` + +fn main() { + takes_empty_array::<{ [] }>(); +} diff --git a/tests/ui/const-generics/mgca/array-expr-empty.stderr b/tests/ui/const-generics/mgca/array-expr-empty.stderr new file mode 100644 index 000000000000..91340e621acb --- /dev/null +++ b/tests/ui/const-generics/mgca/array-expr-empty.stderr @@ -0,0 +1,8 @@ +error: expected type, found `]` + --> $DIR/array-expr-empty.rs:4:32 + | +LL | fn takes_empty_array() {} + | ^ expected type + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/array-expr-simple.rs b/tests/ui/const-generics/mgca/array-expr-simple.rs new file mode 100644 index 000000000000..44feeccb4f9f --- /dev/null +++ b/tests/ui/const-generics/mgca/array-expr-simple.rs @@ -0,0 +1,25 @@ +//@ run-pass +#![expect(incomplete_features)] +#![feature(min_generic_const_args, adt_const_params)] +#![allow(dead_code)] + +fn takes_array_u32() {} +fn takes_array_bool() {} +fn takes_nested_array() {} +fn takes_empty_array() {} + +fn generic_caller() { + takes_array_u32::<{ [X, Y, X] }>(); + takes_array_u32::<{ [X, Y, const { 1 }] }>(); + takes_array_u32::<{ [X, Y, const { 1 + 1 }] }>(); + takes_array_u32::<{ [2_002, 2u32, 1_u32] }>(); + + takes_array_bool::<{ [true, false] }>(); + + takes_nested_array::<{ [[X, Y], [3, 4]] }>(); + takes_nested_array::<{ [[1u32, 2_u32], [const { 3 }, 4]] }>(); + + takes_empty_array::<{ [] }>(); +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/array-expr-with-assoc-const.rs b/tests/ui/const-generics/mgca/array-expr-with-assoc-const.rs new file mode 100644 index 000000000000..47ecbfa6b7e1 --- /dev/null +++ b/tests/ui/const-generics/mgca/array-expr-with-assoc-const.rs @@ -0,0 +1,18 @@ +//@ run-pass +#![expect(incomplete_features)] +#![feature(min_generic_const_args, adt_const_params)] +#![allow(dead_code)] + +fn takes_array() {} + +trait Trait { + #[type_const] + const ASSOC: u32; +} + +fn generic_caller() { + takes_array::<{ [T::ASSOC, N, T::ASSOC] }>(); + takes_array::<{ [1_u32, T::ASSOC, 2] }>(); +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/array-expr-with-macro.rs b/tests/ui/const-generics/mgca/array-expr-with-macro.rs new file mode 100644 index 000000000000..aef5acc1c803 --- /dev/null +++ b/tests/ui/const-generics/mgca/array-expr-with-macro.rs @@ -0,0 +1,18 @@ +//@ run-pass +#![expect(incomplete_features)] +#![feature(min_generic_const_args, adt_const_params)] +#![allow(dead_code)] + +macro_rules! make_array { + ($n:expr, $m:expr, $p:expr) => { + [N, $m, $p] + }; +} + +fn takes_array() {} + +fn generic_caller() { + takes_array::<{ make_array!(N, 2, 3) }>(); +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/array-expr-with-struct.rs b/tests/ui/const-generics/mgca/array-expr-with-struct.rs new file mode 100644 index 000000000000..883af57e918e --- /dev/null +++ b/tests/ui/const-generics/mgca/array-expr-with-struct.rs @@ -0,0 +1,20 @@ +//@ run-pass +#![feature(min_generic_const_args, adt_const_params)] +#![expect(incomplete_features)] +#![allow(dead_code)] + +use std::marker::ConstParamTy; + +#[derive(PartialEq, Eq, ConstParamTy)] +struct Container { + values: [u32; 3], +} + +fn takes_container() {} + +fn generic_caller() { + takes_container::<{ Container { values: [N, M, 1] } }>(); + takes_container::<{ Container { values: [1, 2, 3] } }>(); +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/array-expr-with-tuple.rs b/tests/ui/const-generics/mgca/array-expr-with-tuple.rs new file mode 100644 index 000000000000..004663dcefab --- /dev/null +++ b/tests/ui/const-generics/mgca/array-expr-with-tuple.rs @@ -0,0 +1,13 @@ +//@ run-pass +#![feature(min_generic_const_args, adt_const_params, unsized_const_params)] +#![expect(incomplete_features)] +#![allow(dead_code)] + +fn takes_tuple() {} + +fn generic_caller() { + takes_tuple::<{ ([N, M], 5, [M, N]) }>(); + takes_tuple::<{ ([1, 2], 3, [4, 5]) }>(); +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/array-expr.rs b/tests/ui/const-generics/mgca/array-expr.rs deleted file mode 100644 index 099fee7ecd03..000000000000 --- a/tests/ui/const-generics/mgca/array-expr.rs +++ /dev/null @@ -1,24 +0,0 @@ -#![expect(incomplete_features)] -#![feature(min_generic_const_args, adt_const_params)] - -fn takes_array() {} - -fn generic_caller() { - takes_array::<{ [N, N2, N] }>(); // ok - - takes_array::<{ [N, N2, const { 1 }] }>(); // ok - - takes_array::<{ [N, N2, const { 1 + 1 }] }>(); // ok - - takes_array::<{ [N, N2, 1] }>(); // ok - - takes_array::<{ [1, 1u32, 1_u32] }>(); // ok - - takes_array::<{ [N, N2, 1 + 1] }>(); // not implemented - //~^ ERROR complex const arguments must be placed inside of a `const` block - - takes_array::<{ [N; 3] }>(); // not implemented - //~^ ERROR complex const arguments must be placed inside of a `const` block -} - -fn main() {} diff --git a/tests/ui/const-generics/mgca/array-expr.stderr b/tests/ui/const-generics/mgca/array-expr.stderr deleted file mode 100644 index 0dda791c2e10..000000000000 --- a/tests/ui/const-generics/mgca/array-expr.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: complex const arguments must be placed inside of a `const` block - --> $DIR/array-expr.rs:17:29 - | -LL | takes_array::<{ [N, N2, 1 + 1] }>(); // not implemented - | ^^^^^ - -error: complex const arguments must be placed inside of a `const` block - --> $DIR/array-expr.rs:20:19 - | -LL | takes_array::<{ [N; 3] }>(); // not implemented - | ^^^^^^^^^^ - -error: aborting due to 2 previous errors - From ccc86f222830386e90b898deb13cbf2314a5fec8 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Fri, 9 Jan 2026 09:32:20 +0530 Subject: [PATCH 0518/1061] std: sys: fs: uefi: Implement File::write Tested using OVMF on QEMU. Signed-off-by: Ayush Singh --- library/std/src/sys/fs/uefi.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index b1e5f33b1b22..95c1b437c057 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -336,8 +336,8 @@ impl File { crate::io::default_read_buf(|buf| self.read(buf), cursor) } - pub fn write(&self, _buf: &[u8]) -> io::Result { - unsupported() + pub fn write(&self, buf: &[u8]) -> io::Result { + self.0.write(buf) } pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { @@ -692,6 +692,25 @@ mod uefi_fs { } } + pub(crate) fn write(&self, buf: &[u8]) -> io::Result { + let file_ptr = self.protocol.as_ptr(); + let mut buf_size = buf.len(); + + let r = unsafe { + ((*file_ptr).write)( + file_ptr, + &mut buf_size, + buf.as_ptr().cast::().cast_mut(), + ) + }; + + if buf_size == 0 && r.is_error() { + Err(io::Error::from_raw_os_error(r.as_usize())) + } else { + Ok(buf_size) + } + } + pub(crate) fn file_info(&self) -> io::Result> { let file_ptr = self.protocol.as_ptr(); let mut info_id = file::INFO_ID; From 7c7cf45dcf6f84937faddf18f55b625f76012a3c Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Fri, 9 Jan 2026 12:48:19 +0000 Subject: [PATCH 0519/1061] Don't special-case `while` block type mismatch 67ea84d erroneously added this special-case when introducing `DesugaringKind::WhileLoop`. It had the unintended effect of emitting erroneous diagnostics in certain `while` blocks. --- compiler/rustc_hir_typeck/src/coercion.rs | 9 ++++----- .../block-result/block-must-not-have-result-while.stderr | 8 ++------ 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 5e1e567d103e..52ea6cdeaa0e 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -54,7 +54,7 @@ use rustc_middle::ty::adjustment::{ }; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; -use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Span}; +use rustc_span::{BytePos, DUMMY_SP, Span}; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::solve::inspect::{self, InferCtxtProofTreeExt, ProofTreeVisitor}; use rustc_trait_selection::solve::{Certainty, Goal, NoSolution}; @@ -1828,10 +1828,9 @@ impl<'tcx> CoerceMany<'tcx> { // If the block is from an external macro or try (`?`) desugaring, then // do not suggest adding a semicolon, because there's nowhere to put it. // See issues #81943 and #87051. - && matches!( - cond_expr.span.desugaring_kind(), - None | Some(DesugaringKind::WhileLoop) - ) + // Similarly, if the block is from a loop desugaring, then also do not + // suggest adding a semicolon. See issue #150850. + && cond_expr.span.desugaring_kind().is_none() && !cond_expr.span.in_external_macro(fcx.tcx.sess.source_map()) && !matches!( cond_expr.kind, diff --git a/tests/ui/block-result/block-must-not-have-result-while.stderr b/tests/ui/block-result/block-must-not-have-result-while.stderr index 0b9941ea96ef..d8e854c9b9ba 100644 --- a/tests/ui/block-result/block-must-not-have-result-while.stderr +++ b/tests/ui/block-result/block-must-not-have-result-while.stderr @@ -9,12 +9,8 @@ LL | while true { error[E0308]: mismatched types --> $DIR/block-must-not-have-result-while.rs:5:9 | -LL | / while true { -LL | | true - | | ^^^^ expected `()`, found `bool` -LL | | -LL | | } - | |_____- expected this to be `()` +LL | true + | ^^^^ expected `()`, found `bool` error: aborting due to 1 previous error; 1 warning emitted From 5674be29fa5819cf5d1578f5a53f7a9603a38d90 Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Fri, 9 Jan 2026 12:04:23 +0000 Subject: [PATCH 0520/1061] Don't suggest breaking with value from `for` or `while` loops --- .../src/fn_ctxt/suggestions.rs | 22 ++++++---- ...nt-suggest-break-from-unbreakable-loops.rs | 39 +++++++++++++++++ ...uggest-break-from-unbreakable-loops.stderr | 42 +++++++++++++++++++ 3 files changed, 96 insertions(+), 7 deletions(-) create mode 100644 tests/ui/for-loop-while/dont-suggest-break-from-unbreakable-loops.rs create mode 100644 tests/ui/for-loop-while/dont-suggest-break-from-unbreakable-loops.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index d51b052e0d1b..3e4c194147f9 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -10,8 +10,8 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::lang_items::LangItem; use rustc_hir::{ self as hir, Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, - GenericBound, HirId, Node, PatExpr, PatExprKind, Path, QPath, Stmt, StmtKind, TyKind, - WherePredicateKind, expr_needs_parens, is_range_literal, + GenericBound, HirId, LoopSource, Node, PatExpr, PatExprKind, Path, QPath, Stmt, StmtKind, + TyKind, WherePredicateKind, expr_needs_parens, is_range_literal, }; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_hir_analysis::suggest_impl_trait; @@ -1170,15 +1170,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let found = self.resolve_vars_if_possible(found); - let in_loop = self.is_loop(id) - || self - .tcx + let innermost_loop = if self.is_loop(id) { + Some(self.tcx.hir_node(id)) + } else { + self.tcx .hir_parent_iter(id) .take_while(|(_, node)| { // look at parents until we find the first body owner node.body_id().is_none() }) - .any(|(parent_id, _)| self.is_loop(parent_id)); + .find_map(|(parent_id, node)| self.is_loop(parent_id).then_some(node)) + }; + let can_break_with_value = innermost_loop.is_some_and(|node| { + matches!( + node, + Node::Expr(Expr { kind: ExprKind::Loop(_, _, LoopSource::Loop, ..), .. }) + ) + }); let in_local_statement = self.is_local_statement(id) || self @@ -1186,7 +1194,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .hir_parent_iter(id) .any(|(parent_id, _)| self.is_local_statement(parent_id)); - if in_loop && in_local_statement { + if can_break_with_value && in_local_statement { err.multipart_suggestion( "you might have meant to break the loop with this value", vec![ diff --git a/tests/ui/for-loop-while/dont-suggest-break-from-unbreakable-loops.rs b/tests/ui/for-loop-while/dont-suggest-break-from-unbreakable-loops.rs new file mode 100644 index 000000000000..69b57486138d --- /dev/null +++ b/tests/ui/for-loop-while/dont-suggest-break-from-unbreakable-loops.rs @@ -0,0 +1,39 @@ +//! Don't suggest breaking with value from `for` or `while` loops +//! +//! Regression test for https://github.com/rust-lang/rust/issues/150850 + +fn returns_i32() -> i32 { 0 } + +fn suggest_breaking_from_loop() { + let _ = loop { + returns_i32() //~ ERROR mismatched types + //~^ SUGGESTION ; + //~| SUGGESTION break + }; +} + +fn dont_suggest_breaking_from_for() { + let _ = for _ in 0.. { + returns_i32() //~ ERROR mismatched types + //~^ SUGGESTION ; + }; +} + +fn dont_suggest_breaking_from_while() { + let cond = true; + let _ = while cond { + returns_i32() //~ ERROR mismatched types + //~^ SUGGESTION ; + }; +} + +fn dont_suggest_breaking_from_for_nested_in_loop() { + let _ = loop { + for _ in 0.. { + returns_i32() //~ ERROR mismatched types + //~^ SUGGESTION ; + } + }; +} + +fn main() {} diff --git a/tests/ui/for-loop-while/dont-suggest-break-from-unbreakable-loops.stderr b/tests/ui/for-loop-while/dont-suggest-break-from-unbreakable-loops.stderr new file mode 100644 index 000000000000..880cc53f9a7c --- /dev/null +++ b/tests/ui/for-loop-while/dont-suggest-break-from-unbreakable-loops.stderr @@ -0,0 +1,42 @@ +error[E0308]: mismatched types + --> $DIR/dont-suggest-break-from-unbreakable-loops.rs:9:9 + | +LL | returns_i32() + | ^^^^^^^^^^^^^ expected `()`, found `i32` + | +help: consider using a semicolon here + | +LL | returns_i32(); + | + +help: you might have meant to break the loop with this value + | +LL | break returns_i32(); + | +++++ + + +error[E0308]: mismatched types + --> $DIR/dont-suggest-break-from-unbreakable-loops.rs:17:9 + | +LL | returns_i32() + | ^^^^^^^^^^^^^- help: consider using a semicolon here: `;` + | | + | expected `()`, found `i32` + +error[E0308]: mismatched types + --> $DIR/dont-suggest-break-from-unbreakable-loops.rs:25:9 + | +LL | returns_i32() + | ^^^^^^^^^^^^^- help: consider using a semicolon here: `;` + | | + | expected `()`, found `i32` + +error[E0308]: mismatched types + --> $DIR/dont-suggest-break-from-unbreakable-loops.rs:33:13 + | +LL | returns_i32() + | ^^^^^^^^^^^^^- help: consider using a semicolon here: `;` + | | + | expected `()`, found `i32` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. From 14c6e602f423e01082367954fb0ea19f2b177ba0 Mon Sep 17 00:00:00 2001 From: oncecelll Date: Sat, 10 Jan 2026 13:25:31 +0800 Subject: [PATCH 0521/1061] Add missing documentation for globs feature Signed-off-by: oncecelll --- compiler/rustc_feature/src/accepted.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 13c1f2219bed..43032bf938c0 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -235,7 +235,7 @@ declare_features! ( (accepted, generic_param_attrs, "1.27.0", Some(48848)), /// Allows the `#[global_allocator]` attribute. (accepted, global_allocator, "1.28.0", Some(27389)), - // FIXME: explain `globs`. + /// Allows globs imports (`use module::*;`) to import all public items from a module. (accepted, globs, "1.0.0", None), /// Allows using `..=X` as a pattern. (accepted, half_open_range_patterns, "1.66.0", Some(67264)), From a0df7b2ad5c94f97a30d04008059e9dcfd1492a2 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sat, 10 Jan 2026 09:34:44 +0100 Subject: [PATCH 0522/1061] compiler: Forward attributes to eii-expanded macros Otherwise you get errors like these if you have an Externally Implementable Item defined in std: error: attribute macro has missing stability attribute --> library/std/src/io/mod.rs:2269:1 | 2269 | #[eii(on_broken_pipe)] | ^^^^^^^^^^^^^^^^^^^^-- | | | in this attribute macro expansion | ::: library/core/src/macros/mod.rs:1899:5 | 1899 | pub macro eii($item:item) { | ------------- in this expansion of `#[eii]` Or (fatal) warnings like these: warning: missing documentation for an attribute macro --> library/std/src/io/mod.rs:2269:1 --- compiler/rustc_builtin_macros/src/eii.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index 2d67608609e3..0ebd3dc826d4 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -133,6 +133,7 @@ fn eii_( macro_name, foreign_item_name, impl_unsafe, + &attrs_from_decl, ))); return_items.into_iter().map(wrap_item).collect() @@ -416,9 +417,14 @@ fn generate_attribute_macro_to_implement( macro_name: Ident, foreign_item_name: Ident, impl_unsafe: bool, + attrs_from_decl: &[Attribute], ) -> ast::Item { let mut macro_attrs = ThinVec::new(); + // To avoid e.g. `error: attribute macro has missing stability attribute` + // errors for eii's in std. + macro_attrs.extend_from_slice(attrs_from_decl); + // #[builtin_macro(eii_shared_macro)] macro_attrs.push(ecx.attr_nested_word(sym::rustc_builtin_macro, sym::eii_shared_macro, span)); From 9b811544f211639c4e828e5bbe3497167ff40723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sat, 10 Jan 2026 11:10:31 +0100 Subject: [PATCH 0523/1061] once again reorganize the EII tests a bit --- .../auxiliary/{codegen1.rs => other_crate_privacy1.rs} | 0 .../auxiliary/{codegen3.rs => other_crate_privacy2.rs} | 0 tests/ui/eii/{ => duplicate}/multiple_decls.rs | 0 tests/ui/eii/{ => duplicate}/multiple_decls.stderr | 0 tests/ui/eii/{ => duplicate}/multiple_impls.rs | 0 tests/ui/eii/{ => duplicate}/multiple_impls.run.stdout | 0 .../auxiliary/codegen_cross_crate_other_crate.rs} | 0 tests/ui/eii/{ => linking}/codegen_cross_crate.rs | 4 ++-- .../eii/{ => linking}/codegen_cross_crate.run.stdout | 0 tests/ui/eii/{ => linking}/codegen_single_crate.rs | 0 .../eii/{ => linking}/codegen_single_crate.run.stdout | 0 tests/ui/eii/{ => linking}/same-symbol.rs | 0 tests/ui/eii/{ => linking}/same-symbol.run.stdout | 0 tests/ui/eii/privacy1.rs | 6 +++--- tests/ui/eii/privacy2.rs | 4 ++-- tests/ui/eii/privacy2.stderr | 10 +++++----- .../auxiliary/cross_crate_eii_declaration.rs | 0 .../cross_crate_type_ok.rs} | 0 .../ui/eii/{ => type_checking}/cross_crate_wrong_ty.rs | 0 .../{ => type_checking}/cross_crate_wrong_ty.stderr | 0 20 files changed, 12 insertions(+), 12 deletions(-) rename tests/ui/eii/auxiliary/{codegen1.rs => other_crate_privacy1.rs} (100%) rename tests/ui/eii/auxiliary/{codegen3.rs => other_crate_privacy2.rs} (100%) rename tests/ui/eii/{ => duplicate}/multiple_decls.rs (100%) rename tests/ui/eii/{ => duplicate}/multiple_decls.stderr (100%) rename tests/ui/eii/{ => duplicate}/multiple_impls.rs (100%) rename tests/ui/eii/{ => duplicate}/multiple_impls.run.stdout (100%) rename tests/ui/eii/{auxiliary/codegen2.rs => linking/auxiliary/codegen_cross_crate_other_crate.rs} (100%) rename tests/ui/eii/{ => linking}/codegen_cross_crate.rs (82%) rename tests/ui/eii/{ => linking}/codegen_cross_crate.run.stdout (100%) rename tests/ui/eii/{ => linking}/codegen_single_crate.rs (100%) rename tests/ui/eii/{ => linking}/codegen_single_crate.run.stdout (100%) rename tests/ui/eii/{ => linking}/same-symbol.rs (100%) rename tests/ui/eii/{ => linking}/same-symbol.run.stdout (100%) rename tests/ui/eii/{ => type_checking}/auxiliary/cross_crate_eii_declaration.rs (100%) rename tests/ui/eii/{cross_crate.rs => type_checking/cross_crate_type_ok.rs} (100%) rename tests/ui/eii/{ => type_checking}/cross_crate_wrong_ty.rs (100%) rename tests/ui/eii/{ => type_checking}/cross_crate_wrong_ty.stderr (100%) diff --git a/tests/ui/eii/auxiliary/codegen1.rs b/tests/ui/eii/auxiliary/other_crate_privacy1.rs similarity index 100% rename from tests/ui/eii/auxiliary/codegen1.rs rename to tests/ui/eii/auxiliary/other_crate_privacy1.rs diff --git a/tests/ui/eii/auxiliary/codegen3.rs b/tests/ui/eii/auxiliary/other_crate_privacy2.rs similarity index 100% rename from tests/ui/eii/auxiliary/codegen3.rs rename to tests/ui/eii/auxiliary/other_crate_privacy2.rs diff --git a/tests/ui/eii/multiple_decls.rs b/tests/ui/eii/duplicate/multiple_decls.rs similarity index 100% rename from tests/ui/eii/multiple_decls.rs rename to tests/ui/eii/duplicate/multiple_decls.rs diff --git a/tests/ui/eii/multiple_decls.stderr b/tests/ui/eii/duplicate/multiple_decls.stderr similarity index 100% rename from tests/ui/eii/multiple_decls.stderr rename to tests/ui/eii/duplicate/multiple_decls.stderr diff --git a/tests/ui/eii/multiple_impls.rs b/tests/ui/eii/duplicate/multiple_impls.rs similarity index 100% rename from tests/ui/eii/multiple_impls.rs rename to tests/ui/eii/duplicate/multiple_impls.rs diff --git a/tests/ui/eii/multiple_impls.run.stdout b/tests/ui/eii/duplicate/multiple_impls.run.stdout similarity index 100% rename from tests/ui/eii/multiple_impls.run.stdout rename to tests/ui/eii/duplicate/multiple_impls.run.stdout diff --git a/tests/ui/eii/auxiliary/codegen2.rs b/tests/ui/eii/linking/auxiliary/codegen_cross_crate_other_crate.rs similarity index 100% rename from tests/ui/eii/auxiliary/codegen2.rs rename to tests/ui/eii/linking/auxiliary/codegen_cross_crate_other_crate.rs diff --git a/tests/ui/eii/codegen_cross_crate.rs b/tests/ui/eii/linking/codegen_cross_crate.rs similarity index 82% rename from tests/ui/eii/codegen_cross_crate.rs rename to tests/ui/eii/linking/codegen_cross_crate.rs index a1fa617491bd..4016712e7504 100644 --- a/tests/ui/eii/codegen_cross_crate.rs +++ b/tests/ui/eii/linking/codegen_cross_crate.rs @@ -1,6 +1,6 @@ //@ run-pass //@ check-run-results -//@ aux-build: codegen2.rs +//@ aux-build: codegen_cross_crate_other_crate.rs //@ compile-flags: -O //@ ignore-backends: gcc // FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418 @@ -8,7 +8,7 @@ // Tests whether calling EIIs works with the declaration in another crate. #![feature(extern_item_impls)] -extern crate codegen2 as codegen; +extern crate codegen_cross_crate_other_crate as codegen; #[codegen::eii1] fn eii1_impl(x: u64) { diff --git a/tests/ui/eii/codegen_cross_crate.run.stdout b/tests/ui/eii/linking/codegen_cross_crate.run.stdout similarity index 100% rename from tests/ui/eii/codegen_cross_crate.run.stdout rename to tests/ui/eii/linking/codegen_cross_crate.run.stdout diff --git a/tests/ui/eii/codegen_single_crate.rs b/tests/ui/eii/linking/codegen_single_crate.rs similarity index 100% rename from tests/ui/eii/codegen_single_crate.rs rename to tests/ui/eii/linking/codegen_single_crate.rs diff --git a/tests/ui/eii/codegen_single_crate.run.stdout b/tests/ui/eii/linking/codegen_single_crate.run.stdout similarity index 100% rename from tests/ui/eii/codegen_single_crate.run.stdout rename to tests/ui/eii/linking/codegen_single_crate.run.stdout diff --git a/tests/ui/eii/same-symbol.rs b/tests/ui/eii/linking/same-symbol.rs similarity index 100% rename from tests/ui/eii/same-symbol.rs rename to tests/ui/eii/linking/same-symbol.rs diff --git a/tests/ui/eii/same-symbol.run.stdout b/tests/ui/eii/linking/same-symbol.run.stdout similarity index 100% rename from tests/ui/eii/same-symbol.run.stdout rename to tests/ui/eii/linking/same-symbol.run.stdout diff --git a/tests/ui/eii/privacy1.rs b/tests/ui/eii/privacy1.rs index b5bbf68bfdaf..72aec83d2cee 100644 --- a/tests/ui/eii/privacy1.rs +++ b/tests/ui/eii/privacy1.rs @@ -1,13 +1,13 @@ //@ run-pass //@ check-run-results -//@ aux-build: codegen1.rs +//@ aux-build: other_crate_privacy1.rs //@ ignore-backends: gcc -// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418 +// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418 //@ ignore-windows // Tests whether re-exports work. #![feature(extern_item_impls)] -extern crate codegen1 as codegen; +extern crate other_crate_privacy1 as codegen; #[codegen::eii1] fn eii1_impl(x: u64) { diff --git a/tests/ui/eii/privacy2.rs b/tests/ui/eii/privacy2.rs index a0bc26ef629b..e3f1f8c863da 100644 --- a/tests/ui/eii/privacy2.rs +++ b/tests/ui/eii/privacy2.rs @@ -1,8 +1,8 @@ -//@ aux-build:codegen3.rs +//@ aux-build:other_crate_privacy2.rs // Tests whether name resolution respects privacy properly. #![feature(extern_item_impls)] -extern crate codegen3 as codegen; +extern crate other_crate_privacy2 as codegen; // has a span but in the other crate //~? ERROR `#[eii2]` required, but not found diff --git a/tests/ui/eii/privacy2.stderr b/tests/ui/eii/privacy2.stderr index 903285d4d1e3..9f4fd6a071c9 100644 --- a/tests/ui/eii/privacy2.stderr +++ b/tests/ui/eii/privacy2.stderr @@ -11,24 +11,24 @@ LL | codegen::decl1(42); | ^^^^^ private function | note: the function `decl1` is defined here - --> $DIR/auxiliary/codegen3.rs:7:1 + --> $DIR/auxiliary/other_crate_privacy2.rs:7:1 | LL | fn decl1(x: u64); | ^^^^^^^^^^^^^^^^^ error: `#[eii2]` required, but not found - --> $DIR/auxiliary/codegen3.rs:9:7 + --> $DIR/auxiliary/other_crate_privacy2.rs:9:7 | LL | #[eii(eii2)] - | ^^^^ expected because `#[eii2]` was declared here in crate `codegen3` + | ^^^^ expected because `#[eii2]` was declared here in crate `other_crate_privacy2` | = help: expected at least one implementation in crate `privacy2` or any of its dependencies error: `#[eii3]` required, but not found - --> $DIR/auxiliary/codegen3.rs:13:11 + --> $DIR/auxiliary/other_crate_privacy2.rs:13:11 | LL | #[eii(eii3)] - | ^^^^ expected because `#[eii3]` was declared here in crate `codegen3` + | ^^^^ expected because `#[eii3]` was declared here in crate `other_crate_privacy2` | = help: expected at least one implementation in crate `privacy2` or any of its dependencies diff --git a/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs b/tests/ui/eii/type_checking/auxiliary/cross_crate_eii_declaration.rs similarity index 100% rename from tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs rename to tests/ui/eii/type_checking/auxiliary/cross_crate_eii_declaration.rs diff --git a/tests/ui/eii/cross_crate.rs b/tests/ui/eii/type_checking/cross_crate_type_ok.rs similarity index 100% rename from tests/ui/eii/cross_crate.rs rename to tests/ui/eii/type_checking/cross_crate_type_ok.rs diff --git a/tests/ui/eii/cross_crate_wrong_ty.rs b/tests/ui/eii/type_checking/cross_crate_wrong_ty.rs similarity index 100% rename from tests/ui/eii/cross_crate_wrong_ty.rs rename to tests/ui/eii/type_checking/cross_crate_wrong_ty.rs diff --git a/tests/ui/eii/cross_crate_wrong_ty.stderr b/tests/ui/eii/type_checking/cross_crate_wrong_ty.stderr similarity index 100% rename from tests/ui/eii/cross_crate_wrong_ty.stderr rename to tests/ui/eii/type_checking/cross_crate_wrong_ty.stderr From c87bb01b9e8bc2419f95bba7f06f1ccee0cabca5 Mon Sep 17 00:00:00 2001 From: Aliaksei Semianiuk Date: Sat, 10 Jan 2026 15:34:41 +0500 Subject: [PATCH 0524/1061] Changelog for Clippy 1.93 --- CHANGELOG.md | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cda8003b05c..afefd436aada 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,66 @@ document. ## Unreleased / Beta / In Rust Nightly -[d9fb15c...master](https://github.com/rust-lang/rust-clippy/compare/d9fb15c...master) +[92b4b68...master](https://github.com/rust-lang/rust-clippy/compare/92b4b68...master) + +## Rust 1.93 + +Current stable, released 2026-01-22 + +[View all 96 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2025-10-17T15%3A48%3A11Z..2025-11-28T19%3A22%3A54Z+base%3Amaster) + +### New Lints + +* Added [`doc_paragraphs_missing_punctuation`] to `restriction` + [#15758](https://github.com/rust-lang/rust-clippy/pull/15758) + +### Moves and Deprecations + +* Renamed [`needless_if`] to [`needless_ifs`] + [#15961](https://github.com/rust-lang/rust-clippy/pull/15961) +* Renamed [`empty_enum`] to [`empty_enums`] + [#15912](https://github.com/rust-lang/rust-clippy/pull/15912) + +### Enhancements + +* [`result_large_err`] added `large_error_ignored` configuration + [#15697](https://github.com/rust-lang/rust-clippy/pull/15697) +* [`explicit_deref_methods`] don't lint in `impl Deref(Mut)` + [#16113](https://github.com/rust-lang/rust-clippy/pull/16113) +* [`missing_docs_in_private_items`] don't lint items in bodies and automatically derived impls; + better detect when things are accessible from the crate root; lint unnameable items which are + accessible outside the crate + [#14741](https://github.com/rust-lang/rust-clippy/pull/14741) +* [`unnecessary_unwrap`] and [`panicking_unwrap`] lint field accesses + [#15949](https://github.com/rust-lang/rust-clippy/pull/15949) +* [`ok_expect`] add autofix + [#15867](https://github.com/rust-lang/rust-clippy/pull/15867) +* [`let_and_return`] disallow _any_ text between let and return + [#16006](https://github.com/rust-lang/rust-clippy/pull/16006) +* [`needless_collect`] extend to lint more cases + [#14361](https://github.com/rust-lang/rust-clippy/pull/14361) +* [`needless_doctest_main`] and [`test_attr_in_doctest`] now handle whitespace in language tags + [#15967](https://github.com/rust-lang/rust-clippy/pull/15967) +* [`search_is_some`] now fixes code spanning multiple lines + [#15902](https://github.com/rust-lang/rust-clippy/pull/15902) +* [`unnecessary_find_map`] and [`unnecessary_filter_map`] make diagnostic spans more precise + [#15929](https://github.com/rust-lang/rust-clippy/pull/15929) +* [`precedence`] warn about ambiguity when a closure is used as a method call receiver + [#14421](https://github.com/rust-lang/rust-clippy/pull/14421) +* [`match_as_ref`] suggest `as_ref` when the reference needs to be cast; improve diagnostics + [#15934](https://github.com/rust-lang/rust-clippy/pull/15934) + [#15928](https://github.com/rust-lang/rust-clippy/pull/15928) + +### False Positive Fixes + +* [`single_range_in_vec_init`] fix FP for explicit `Range` + [#16043](https://github.com/rust-lang/rust-clippy/pull/16043) +* [`mod_module_files`] fix false positive for integration tests in workspace crates + [#16048](https://github.com/rust-lang/rust-clippy/pull/16048) +* [`replace_box`] fix FP when the box is moved + [#15984](https://github.com/rust-lang/rust-clippy/pull/15984) +* [`len_zero`] fix FP on unstable methods + [#15894](https://github.com/rust-lang/rust-clippy/pull/15894) ## Rust 1.92 From 539e85500854f987f4b1b9003042b20b54e81a89 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 10 Jan 2026 21:18:01 +1100 Subject: [PATCH 0525/1061] Use a hook to decouple `rustc_mir_transform` from `rustc_mir_build` --- Cargo.lock | 1 - compiler/rustc_middle/src/hooks/mod.rs | 5 +++++ compiler/rustc_mir_build/src/builder/mod.rs | 8 +++++--- compiler/rustc_mir_build/src/lib.rs | 3 ++- compiler/rustc_mir_transform/Cargo.toml | 1 - compiler/rustc_mir_transform/src/lib.rs | 6 ++++-- 6 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c791babc399..bf28939ac87b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4360,7 +4360,6 @@ dependencies = [ "rustc_infer", "rustc_macros", "rustc_middle", - "rustc_mir_build", "rustc_mir_dataflow", "rustc_session", "rustc_span", diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs index dc6a3334a4c8..c926604a4195 100644 --- a/compiler/rustc_middle/src/hooks/mod.rs +++ b/compiler/rustc_middle/src/hooks/mod.rs @@ -102,6 +102,11 @@ declare_hooks! { /// Ensure the given scalar is valid for the given type. /// This checks non-recursive runtime validity. hook validate_scalar_in_layout(scalar: crate::ty::ScalarInt, ty: Ty<'tcx>) -> bool; + + /// **Do not call this directly; call the `mir_built` query instead.** + /// + /// Creates the MIR for a given `DefId`, including unreachable code. + hook build_mir_inner_impl(def: LocalDefId) -> mir::Body<'tcx>; } #[cold] diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 40f1fe0d5d11..75c6df842b50 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -64,9 +64,11 @@ pub(crate) fn closure_saved_names_of_captured_variables<'tcx>( .collect() } -/// Create the MIR for a given `DefId`, including unreachable code. Do not call -/// this directly; instead use the cached version via `mir_built`. -pub fn build_mir<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> { +/// Create the MIR for a given `DefId`, including unreachable code. +/// +/// This is the implementation of hook `build_mir_inner_impl`, which should only +/// be called by the query `mir_built`. +pub(crate) fn build_mir_inner_impl<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> { tcx.ensure_done().thir_abstract_const(def); if let Err(e) = tcx.ensure_ok().check_match(def) { return construct_error(tcx, def, e); diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 8c7003b77876..410ea791ac5c 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -12,7 +12,7 @@ // The `builder` module used to be named `build`, but that was causing GitHub's // "Go to file" feature to silently ignore all files in the module, probably // because it assumes that "build" is a build-output directory. See #134365. -pub mod builder; +mod builder; mod check_tail_calls; mod check_unsafety; mod errors; @@ -30,4 +30,5 @@ pub fn provide(providers: &mut Providers) { providers.check_unsafety = check_unsafety::check_unsafety; providers.check_tail_calls = check_tail_calls::check_tail_calls; providers.thir_body = thir::cx::thir_body; + providers.hooks.build_mir_inner_impl = builder::build_mir_inner_impl; } diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml index 511c1960e40b..6df7a869ca28 100644 --- a/compiler/rustc_mir_transform/Cargo.toml +++ b/compiler/rustc_mir_transform/Cargo.toml @@ -20,7 +20,6 @@ rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } -rustc_mir_build = { path = "../rustc_mir_build" } rustc_mir_dataflow = { path = "../rustc_mir_dataflow" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 701d7ff854a7..c78b0adaf6f1 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -30,7 +30,6 @@ use rustc_middle::mir::{ use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_middle::util::Providers; use rustc_middle::{bug, query, span_bug}; -use rustc_mir_build::builder::build_mir; use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, sym}; use tracing::debug; @@ -378,8 +377,11 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs { validator.qualifs_in_return_place() } +/// Implementation of the `mir_built` query. fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal> { - let mut body = build_mir(tcx, def); + // Delegate to the main MIR building code in the `rustc_mir_build` crate. + // This is the one place that is allowed to call `build_mir_inner_impl`. + let mut body = tcx.build_mir_inner_impl(def); // Identifying trivial consts based on their mir_built is easy, but a little wasteful. // Trying to push this logic earlier in the compiler and never even produce the Body would From 00ad6714064e0003d04731933be62636a19c9400 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 10 Jan 2026 13:00:07 +0100 Subject: [PATCH 0526/1061] Subscribe myself to attr parsing --- triagebot.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index 59c5e5f24330..3007ec765e00 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1358,11 +1358,11 @@ message = "The rustc-dev-guide subtree was changed. If this PR *only* touches th cc = ["@BoxyUwU", "@jieyouxu", "@kobzol", "@tshepang"] [mentions."compiler/rustc_passes/src/check_attr.rs"] -cc = ["@jdonszelmann"] +cc = ["@jdonszelmann", "@JonathanBrouwer"] [mentions."compiler/rustc_attr_parsing"] -cc = ["@jdonszelmann"] +cc = ["@jdonszelmann", "@JonathanBrouwer"] [mentions."compiler/rustc_hir/src/attrs"] -cc = ["@jdonszelmann"] +cc = ["@jdonszelmann", "@JonathanBrouwer"] [mentions."src/tools/enzyme"] cc = ["@ZuseZ4"] From 1caf7b222859c6de1b6fce064e32d3fdc50048c5 Mon Sep 17 00:00:00 2001 From: Lofty Inclination Date: Sat, 10 Jan 2026 12:54:50 +0000 Subject: [PATCH 0527/1061] Add miri specific shims for managing threads in no_std projects --- src/tools/miri/src/shims/foreign_items.rs | 36 ++++++++++++++++++- src/tools/miri/src/shims/sig.rs | 1 + .../concurrency/miri_thread_join_spawned.rs | 28 +++++++++++++++ src/tools/miri/tests/pass/miri-alloc.rs | 10 +++--- src/tools/miri/tests/utils/miri_extern.rs | 13 +++++++ 5 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 src/tools/miri/tests/pass/concurrency/miri_thread_join_spawned.rs diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 571f5efc9739..4c25caf56446 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -2,7 +2,7 @@ use std::collections::hash_map::Entry; use std::io::Write; use std::path::Path; -use rustc_abi::{Align, CanonAbi, Size}; +use rustc_abi::{Align, CanonAbi, ExternAbi, Size}; use rustc_ast::expand::allocator::NO_ALLOC_SHIM_IS_UNSTABLE; use rustc_data_structures::either::Either; use rustc_hir::attrs::Linkage; @@ -435,6 +435,40 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Return value: 0 on success, otherwise the size it would have needed. this.write_int(if success { 0 } else { needed_size }, dest)?; } + "miri_thread_spawn" => { + // FIXME: `check_shim_sig` does not work with function pointers. + let [start_routine, func_arg] = + this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; + let start_routine = this.read_pointer(start_routine)?; + let func_arg = this.read_immediate(func_arg)?; + + this.start_regular_thread( + Some(dest.clone()), + start_routine, + ExternAbi::Rust, + func_arg, + this.machine.layouts.unit, + )?; + } + "miri_thread_join" => { + let [thread_id] = this.check_shim_sig( + shim_sig!(extern "Rust" fn(usize) -> bool), + link_name, + abi, + args, + )?; + + let thread = this.read_target_usize(thread_id)?; + if let Ok(thread) = this.thread_id_try_from(thread) { + this.join_thread_exclusive( + thread, + /* success_retval */ Scalar::from_bool(true), + dest, + )?; + } else { + this.write_scalar(Scalar::from_bool(false), dest)?; + } + } // Hint that a loop is spinning indefinitely. "miri_spin_loop" => { let [] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; diff --git a/src/tools/miri/src/shims/sig.rs b/src/tools/miri/src/shims/sig.rs index e88cc66b6ea5..4e4b1bc2b9fe 100644 --- a/src/tools/miri/src/shims/sig.rs +++ b/src/tools/miri/src/shims/sig.rs @@ -57,6 +57,7 @@ macro_rules! shim_sig_arg { "u128" => $this.tcx.types.u128, "usize" => $this.tcx.types.usize, "()" => $this.tcx.types.unit, + "bool" => $this.tcx.types.bool, "*const _" => $this.machine.layouts.const_raw_ptr.ty, "*mut _" => $this.machine.layouts.mut_raw_ptr.ty, ty if let Some(win_ty) = ty.strip_prefix("winapi::") => diff --git a/src/tools/miri/tests/pass/concurrency/miri_thread_join_spawned.rs b/src/tools/miri/tests/pass/concurrency/miri_thread_join_spawned.rs new file mode 100644 index 000000000000..5b78068b6853 --- /dev/null +++ b/src/tools/miri/tests/pass/concurrency/miri_thread_join_spawned.rs @@ -0,0 +1,28 @@ +#![no_std] +#![no_main] +//@compile-flags: -Cpanic=abort +//@ignore-target: windows # no-std not supported on Windows + +#[path = "../../utils/mod.no_std.rs"] +mod utils; + +extern "Rust" fn thread_start(_null: *mut ()) { + unsafe { + utils::miri_spin_loop(); + utils::miri_spin_loop(); + } +} + +#[no_mangle] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + unsafe { + let thread_id = utils::miri_thread_spawn(thread_start, core::ptr::null_mut()); + assert_eq!(utils::miri_thread_join(thread_id), true); + } + 0 +} + +#[panic_handler] +fn panic_handler(_: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/src/tools/miri/tests/pass/miri-alloc.rs b/src/tools/miri/tests/pass/miri-alloc.rs index 20269d8ced03..7469e29a8c96 100644 --- a/src/tools/miri/tests/pass/miri-alloc.rs +++ b/src/tools/miri/tests/pass/miri-alloc.rs @@ -6,17 +6,15 @@ // windows linker section, we can run this test on windows again. //@ignore-target: windows # no-std not supported on Windows -extern "Rust" { - fn miri_alloc(size: usize, align: usize) -> *mut u8; - fn miri_dealloc(ptr: *mut u8, size: usize, align: usize); -} +#[path = "../utils/mod.no_std.rs"] +mod utils; #[no_mangle] fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { unsafe { - let ptr = miri_alloc(123, 1); + let ptr = utils::miri_alloc(123, 1); core::ptr::write_bytes(ptr, 0u8, 123); - miri_dealloc(ptr, 123, 1); + utils::miri_dealloc(ptr, 123, 1); } 0 } diff --git a/src/tools/miri/tests/utils/miri_extern.rs b/src/tools/miri/tests/utils/miri_extern.rs index bd01866dc34c..e9cde20412f4 100644 --- a/src/tools/miri/tests/utils/miri_extern.rs +++ b/src/tools/miri/tests/utils/miri_extern.rs @@ -156,6 +156,19 @@ extern "Rust" { /// Blocks the current execution if the argument is false pub fn miri_genmc_assume(condition: bool); + /// Miri-provided extern function to spawn a new thread in the interpreter. + /// + /// Returns the thread id. + /// + /// This is useful when no fundamental way of spawning threads is available, e.g. when using + /// `no_std`. + pub fn miri_thread_spawn(t: extern "Rust" fn(*mut ()), data: *mut ()) -> usize; + + /// Miri-provided extern function to join a thread that was spawned by Miri. + pub fn miri_thread_join(thread_id: usize) -> bool; + /// Indicate to Miri that this thread is busy-waiting in a spin loop. + /// + /// As far as Miri is concerned, this is equivalent to `yield_now`. pub fn miri_spin_loop(); } From 9eb4d7c56ebf768576183e5c5fd3e8159520dd22 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Sat, 10 Jan 2026 13:58:47 +0100 Subject: [PATCH 0528/1061] remove `no-rustfix` the suggestions are no longer overlapping?.. --- tests/ui/suspicious_to_owned.1.fixed | 73 ++++++++++++++++++++++++++++ tests/ui/suspicious_to_owned.2.fixed | 73 ++++++++++++++++++++++++++++ tests/ui/suspicious_to_owned.rs | 1 - tests/ui/suspicious_to_owned.stderr | 12 ++--- 4 files changed, 152 insertions(+), 7 deletions(-) create mode 100644 tests/ui/suspicious_to_owned.1.fixed create mode 100644 tests/ui/suspicious_to_owned.2.fixed diff --git a/tests/ui/suspicious_to_owned.1.fixed b/tests/ui/suspicious_to_owned.1.fixed new file mode 100644 index 000000000000..6fd536a38ed1 --- /dev/null +++ b/tests/ui/suspicious_to_owned.1.fixed @@ -0,0 +1,73 @@ +#![warn(clippy::suspicious_to_owned)] +#![warn(clippy::implicit_clone)] +#![allow(clippy::redundant_clone)] +use std::borrow::Cow; +use std::ffi::{CStr, c_char}; + +fn main() { + let moo = "Moooo"; + let c_moo = b"Moooo\0"; + let c_moo_ptr = c_moo.as_ptr() as *const c_char; + let moos = ['M', 'o', 'o']; + let moos_vec = moos.to_vec(); + + // we expect this to be linted + let cow = Cow::Borrowed(moo); + let _ = cow.into_owned(); + //~^ suspicious_to_owned + + // we expect no lints for this + let cow = Cow::Borrowed(moo); + let _ = cow.into_owned(); + // we expect no lints for this + let cow = Cow::Borrowed(moo); + let _ = cow.clone(); + + // we expect this to be linted + let cow = Cow::Borrowed(&moos); + let _ = cow.into_owned(); + //~^ suspicious_to_owned + + // we expect no lints for this + let cow = Cow::Borrowed(&moos); + let _ = cow.into_owned(); + // we expect no lints for this + let cow = Cow::Borrowed(&moos); + let _ = cow.clone(); + + // we expect this to be linted + let cow = Cow::Borrowed(&moos_vec); + let _ = cow.into_owned(); + //~^ suspicious_to_owned + + // we expect no lints for this + let cow = Cow::Borrowed(&moos_vec); + let _ = cow.into_owned(); + // we expect no lints for this + let cow = Cow::Borrowed(&moos_vec); + let _ = cow.clone(); + + // we expect this to be linted + let cow = unsafe { CStr::from_ptr(c_moo_ptr) }.to_string_lossy(); + let _ = cow.into_owned(); + //~^ suspicious_to_owned + + // we expect no lints for this + let cow = unsafe { CStr::from_ptr(c_moo_ptr) }.to_string_lossy(); + let _ = cow.into_owned(); + // we expect no lints for this + let cow = unsafe { CStr::from_ptr(c_moo_ptr) }.to_string_lossy(); + let _ = cow.clone(); + + // we expect no lints for these + let _ = moo.to_owned(); + let _ = c_moo.to_owned(); + let _ = moos.to_owned(); + + // we expect implicit_clone lints for these + let _ = String::from(moo).clone(); + //~^ implicit_clone + + let _ = moos_vec.clone(); + //~^ implicit_clone +} diff --git a/tests/ui/suspicious_to_owned.2.fixed b/tests/ui/suspicious_to_owned.2.fixed new file mode 100644 index 000000000000..841adf8ea274 --- /dev/null +++ b/tests/ui/suspicious_to_owned.2.fixed @@ -0,0 +1,73 @@ +#![warn(clippy::suspicious_to_owned)] +#![warn(clippy::implicit_clone)] +#![allow(clippy::redundant_clone)] +use std::borrow::Cow; +use std::ffi::{CStr, c_char}; + +fn main() { + let moo = "Moooo"; + let c_moo = b"Moooo\0"; + let c_moo_ptr = c_moo.as_ptr() as *const c_char; + let moos = ['M', 'o', 'o']; + let moos_vec = moos.to_vec(); + + // we expect this to be linted + let cow = Cow::Borrowed(moo); + let _ = cow.clone(); + //~^ suspicious_to_owned + + // we expect no lints for this + let cow = Cow::Borrowed(moo); + let _ = cow.into_owned(); + // we expect no lints for this + let cow = Cow::Borrowed(moo); + let _ = cow.clone(); + + // we expect this to be linted + let cow = Cow::Borrowed(&moos); + let _ = cow.clone(); + //~^ suspicious_to_owned + + // we expect no lints for this + let cow = Cow::Borrowed(&moos); + let _ = cow.into_owned(); + // we expect no lints for this + let cow = Cow::Borrowed(&moos); + let _ = cow.clone(); + + // we expect this to be linted + let cow = Cow::Borrowed(&moos_vec); + let _ = cow.clone(); + //~^ suspicious_to_owned + + // we expect no lints for this + let cow = Cow::Borrowed(&moos_vec); + let _ = cow.into_owned(); + // we expect no lints for this + let cow = Cow::Borrowed(&moos_vec); + let _ = cow.clone(); + + // we expect this to be linted + let cow = unsafe { CStr::from_ptr(c_moo_ptr) }.to_string_lossy(); + let _ = cow.clone(); + //~^ suspicious_to_owned + + // we expect no lints for this + let cow = unsafe { CStr::from_ptr(c_moo_ptr) }.to_string_lossy(); + let _ = cow.into_owned(); + // we expect no lints for this + let cow = unsafe { CStr::from_ptr(c_moo_ptr) }.to_string_lossy(); + let _ = cow.clone(); + + // we expect no lints for these + let _ = moo.to_owned(); + let _ = c_moo.to_owned(); + let _ = moos.to_owned(); + + // we expect implicit_clone lints for these + let _ = String::from(moo).clone(); + //~^ implicit_clone + + let _ = moos_vec.clone(); + //~^ implicit_clone +} diff --git a/tests/ui/suspicious_to_owned.rs b/tests/ui/suspicious_to_owned.rs index 2eec05ccaf4c..f59b3fd6ed0c 100644 --- a/tests/ui/suspicious_to_owned.rs +++ b/tests/ui/suspicious_to_owned.rs @@ -1,4 +1,3 @@ -//@no-rustfix: overlapping suggestions #![warn(clippy::suspicious_to_owned)] #![warn(clippy::implicit_clone)] #![allow(clippy::redundant_clone)] diff --git a/tests/ui/suspicious_to_owned.stderr b/tests/ui/suspicious_to_owned.stderr index f90bea5fb8ff..1e631d4d4a14 100644 --- a/tests/ui/suspicious_to_owned.stderr +++ b/tests/ui/suspicious_to_owned.stderr @@ -1,5 +1,5 @@ error: this `to_owned` call clones the Cow<'_, str> itself and does not cause the Cow<'_, str> contents to become owned - --> tests/ui/suspicious_to_owned.rs:17:13 + --> tests/ui/suspicious_to_owned.rs:16:13 | LL | let _ = cow.to_owned(); | ^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL + let _ = cow.clone(); | error: this `to_owned` call clones the Cow<'_, [char; 3]> itself and does not cause the Cow<'_, [char; 3]> contents to become owned - --> tests/ui/suspicious_to_owned.rs:29:13 + --> tests/ui/suspicious_to_owned.rs:28:13 | LL | let _ = cow.to_owned(); | ^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL + let _ = cow.clone(); | error: this `to_owned` call clones the Cow<'_, Vec> itself and does not cause the Cow<'_, Vec> contents to become owned - --> tests/ui/suspicious_to_owned.rs:41:13 + --> tests/ui/suspicious_to_owned.rs:40:13 | LL | let _ = cow.to_owned(); | ^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + let _ = cow.clone(); | error: this `to_owned` call clones the Cow<'_, str> itself and does not cause the Cow<'_, str> contents to become owned - --> tests/ui/suspicious_to_owned.rs:53:13 + --> tests/ui/suspicious_to_owned.rs:52:13 | LL | let _ = cow.to_owned(); | ^^^^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL + let _ = cow.clone(); | error: implicitly cloning a `String` by calling `to_owned` on its dereferenced type - --> tests/ui/suspicious_to_owned.rs:69:13 + --> tests/ui/suspicious_to_owned.rs:68:13 | LL | let _ = String::from(moo).to_owned(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::from(moo).clone()` @@ -74,7 +74,7 @@ LL | let _ = String::from(moo).to_owned(); = help: to override `-D warnings` add `#[allow(clippy::implicit_clone)]` error: implicitly cloning a `Vec` by calling `to_owned` on its dereferenced type - --> tests/ui/suspicious_to_owned.rs:72:13 + --> tests/ui/suspicious_to_owned.rs:71:13 | LL | let _ = moos_vec.to_owned(); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `moos_vec.clone()` From f228056c644969488958f01cb88a89f0a93f642d Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Sat, 10 Jan 2026 13:51:44 +0100 Subject: [PATCH 0529/1061] improve lint messages - only mention the type once - put types in backticks - only highlight the method name in the suggestion - removes the need for a snippet - makes for finer diffs (seen through `cargo dev lint`) --- clippy_lints/src/methods/mod.rs | 2 +- .../src/methods/suspicious_to_owned.rs | 23 +++++++----------- tests/ui/suspicious_to_owned.stderr | 24 +++++++++---------- 3 files changed, 21 insertions(+), 28 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 248a147cfd77..d483496549fd 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -5576,7 +5576,7 @@ impl Methods { unnecessary_fallible_conversions::check_method(cx, expr); }, (sym::to_owned, []) => { - if !suspicious_to_owned::check(cx, expr, recv) { + if !suspicious_to_owned::check(cx, expr, span) { implicit_clone::check(cx, name, expr, recv); } }, diff --git a/clippy_lints/src/methods/suspicious_to_owned.rs b/clippy_lints/src/methods/suspicious_to_owned.rs index bcd1f11931fc..e9a5104eb3b4 100644 --- a/clippy_lints/src/methods/suspicious_to_owned.rs +++ b/clippy_lints/src/methods/suspicious_to_owned.rs @@ -1,15 +1,14 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeDef; -use clippy_utils::source::snippet_with_context; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty::print::with_forced_trimmed_paths; -use rustc_span::sym; +use rustc_span::{Span, sym}; use super::SUSPICIOUS_TO_OWNED; -pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) -> bool { +pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_span: Span) -> bool { if cx .typeck_results() .type_dependent_def_id(expr.hir_id) @@ -18,28 +17,22 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) - && let input_type = cx.typeck_results().expr_ty(expr) && input_type.is_diag_item(cx, sym::Cow) { - let mut app = Applicability::MaybeIncorrect; - let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0; + let app = Applicability::MaybeIncorrect; span_lint_and_then( cx, SUSPICIOUS_TO_OWNED, expr.span, with_forced_trimmed_paths!(format!( - "this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned" + "this `to_owned` call clones the `{input_type}` itself and does not cause its contents to become owned" )), |diag| { diag.span_suggestion( - expr.span, - "depending on intent, either make the Cow an Owned variant", - format!("{recv_snip}.into_owned()"), - app, - ); - diag.span_suggestion( - expr.span, - "or clone the Cow itself", - format!("{recv_snip}.clone()"), + method_span, + "depending on intent, either make the `Cow` an `Owned` variant", + "into_owned".to_string(), app, ); + diag.span_suggestion(method_span, "or clone the `Cow` itself", "clone".to_string(), app); }, ); return true; diff --git a/tests/ui/suspicious_to_owned.stderr b/tests/ui/suspicious_to_owned.stderr index 1e631d4d4a14..5fda1ed1cc9c 100644 --- a/tests/ui/suspicious_to_owned.stderr +++ b/tests/ui/suspicious_to_owned.stderr @@ -1,4 +1,4 @@ -error: this `to_owned` call clones the Cow<'_, str> itself and does not cause the Cow<'_, str> contents to become owned +error: this `to_owned` call clones the `Cow<'_, str>` itself and does not cause its contents to become owned --> tests/ui/suspicious_to_owned.rs:16:13 | LL | let _ = cow.to_owned(); @@ -6,59 +6,59 @@ LL | let _ = cow.to_owned(); | = note: `-D clippy::suspicious-to-owned` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::suspicious_to_owned)]` -help: depending on intent, either make the Cow an Owned variant +help: depending on intent, either make the `Cow` an `Owned` variant | LL | let _ = cow.into_owned(); | ++ -help: or clone the Cow itself +help: or clone the `Cow` itself | LL - let _ = cow.to_owned(); LL + let _ = cow.clone(); | -error: this `to_owned` call clones the Cow<'_, [char; 3]> itself and does not cause the Cow<'_, [char; 3]> contents to become owned +error: this `to_owned` call clones the `Cow<'_, [char; 3]>` itself and does not cause its contents to become owned --> tests/ui/suspicious_to_owned.rs:28:13 | LL | let _ = cow.to_owned(); | ^^^^^^^^^^^^^^ | -help: depending on intent, either make the Cow an Owned variant +help: depending on intent, either make the `Cow` an `Owned` variant | LL | let _ = cow.into_owned(); | ++ -help: or clone the Cow itself +help: or clone the `Cow` itself | LL - let _ = cow.to_owned(); LL + let _ = cow.clone(); | -error: this `to_owned` call clones the Cow<'_, Vec> itself and does not cause the Cow<'_, Vec> contents to become owned +error: this `to_owned` call clones the `Cow<'_, Vec>` itself and does not cause its contents to become owned --> tests/ui/suspicious_to_owned.rs:40:13 | LL | let _ = cow.to_owned(); | ^^^^^^^^^^^^^^ | -help: depending on intent, either make the Cow an Owned variant +help: depending on intent, either make the `Cow` an `Owned` variant | LL | let _ = cow.into_owned(); | ++ -help: or clone the Cow itself +help: or clone the `Cow` itself | LL - let _ = cow.to_owned(); LL + let _ = cow.clone(); | -error: this `to_owned` call clones the Cow<'_, str> itself and does not cause the Cow<'_, str> contents to become owned +error: this `to_owned` call clones the `Cow<'_, str>` itself and does not cause its contents to become owned --> tests/ui/suspicious_to_owned.rs:52:13 | LL | let _ = cow.to_owned(); | ^^^^^^^^^^^^^^ | -help: depending on intent, either make the Cow an Owned variant +help: depending on intent, either make the `Cow` an `Owned` variant | LL | let _ = cow.into_owned(); | ++ -help: or clone the Cow itself +help: or clone the `Cow` itself | LL - let _ = cow.to_owned(); LL + let _ = cow.clone(); From bd31b9d3bcd430a4236162d6b8e87661b8904964 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Jan 2026 14:22:48 +0100 Subject: [PATCH 0530/1061] use io::Result for read/write helpers, and add read_until_eof_into_slice --- .../tests/pass-dep/libc/libc-socketpair.rs | 11 ++--- src/tools/miri/tests/utils/libc.rs | 46 +++++++++---------- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs b/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs index 2031149aaf4f..20424fc86dc2 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs @@ -62,14 +62,11 @@ fn test_socketpair() { errno_check(unsafe { libc::close(fds[0]) }); // Reading the other end should return that data, then EOF. let mut buf: [u8; 5] = [0; 5]; - read_all_into_slice(fds[1], &mut buf[0..3]).unwrap(); - assert_eq!(&buf[0..3], data); - let res = read_into_slice(fds[1], &mut buf[3..5]).unwrap().0.len(); - assert_eq!(res, 0); // 0-sized read: EOF. + let (res, _) = read_until_eof_into_slice(fds[1], &mut buf).unwrap(); + assert_eq!(res, data); // Writing the other end should emit EPIPE. - let res = write_all_from_slice(fds[1], &mut buf); - assert_eq!(res, Err(-1)); - assert_eq!(std::io::Error::last_os_error().raw_os_error(), Some(libc::EPIPE)); + let err = write_all_from_slice(fds[1], &mut buf).unwrap_err(); + assert_eq!(err.raw_os_error(), Some(libc::EPIPE)); } fn test_socketpair_threaded() { diff --git a/src/tools/miri/tests/utils/libc.rs b/src/tools/miri/tests/utils/libc.rs index 0765bacb6bd8..4e9a94718c38 100644 --- a/src/tools/miri/tests/utils/libc.rs +++ b/src/tools/miri/tests/utils/libc.rs @@ -40,21 +40,17 @@ pub unsafe fn read_all( return read_so_far as libc::ssize_t; } -/// Try to fill the given slice by reading from `fd`. Error if that many bytes could not be read. +/// Try to fill the given slice by reading from `fd`. Panic if that many bytes could not be read. #[track_caller] -pub fn read_all_into_slice(fd: libc::c_int, buf: &mut [u8]) -> Result<(), libc::ssize_t> { - let res = unsafe { read_all(fd, buf.as_mut_ptr().cast(), buf.len()) }; - if res >= 0 { - assert_eq!(res as usize, buf.len()); - Ok(()) - } else { - Err(res) - } +pub fn read_all_into_slice(fd: libc::c_int, buf: &mut [u8]) -> io::Result<()> { + let res = errno_result(unsafe { read_all(fd, buf.as_mut_ptr().cast(), buf.len()) })?; + assert_eq!(res as usize, buf.len()); + Ok(()) } /// Read exactly `N` bytes from `fd`. Error if that many bytes could not be read. #[track_caller] -pub fn read_all_into_array(fd: libc::c_int) -> Result<[u8; N], libc::ssize_t> { +pub fn read_all_into_array(fd: libc::c_int) -> io::Result<[u8; N]> { let mut buf = [0; N]; read_all_into_slice(fd, &mut buf)?; Ok(buf) @@ -63,12 +59,20 @@ pub fn read_all_into_array(fd: libc::c_int) -> Result<[u8; N], l /// Do a single read from `fd` and return the part of the buffer that was written into, /// and the rest. #[track_caller] -pub fn read_into_slice( +pub fn read_into_slice(fd: libc::c_int, buf: &mut [u8]) -> io::Result<(&mut [u8], &mut [u8])> { + let res = errno_result(unsafe { libc::read(fd, buf.as_mut_ptr().cast(), buf.len()) })?; + Ok(buf.split_at_mut(res as usize)) +} + +/// Read from `fd` until we get EOF and return the part of the buffer that was written into, +/// and the rest. +#[track_caller] +pub fn read_until_eof_into_slice( fd: libc::c_int, buf: &mut [u8], -) -> Result<(&mut [u8], &mut [u8]), libc::ssize_t> { - let res = unsafe { libc::read(fd, buf.as_mut_ptr().cast(), buf.len()) }; - if res >= 0 { Ok(buf.split_at_mut(res as usize)) } else { Err(res) } +) -> io::Result<(&mut [u8], &mut [u8])> { + let res = errno_result(unsafe { read_all(fd, buf.as_mut_ptr().cast(), buf.len()) })?; + Ok(buf.split_at_mut(res as usize)) } pub unsafe fn write_all( @@ -89,16 +93,12 @@ pub unsafe fn write_all( return written_so_far as libc::ssize_t; } -/// Write the entire `buf` to `fd`. Error if not all bytes could be written. +/// Write the entire `buf` to `fd`. Panic if not all bytes could be written. #[track_caller] -pub fn write_all_from_slice(fd: libc::c_int, buf: &[u8]) -> Result<(), libc::ssize_t> { - let res = unsafe { write_all(fd, buf.as_ptr().cast(), buf.len()) }; - if res >= 0 { - assert_eq!(res as usize, buf.len()); - Ok(()) - } else { - Err(res) - } +pub fn write_all_from_slice(fd: libc::c_int, buf: &[u8]) -> io::Result<()> { + let res = errno_result(unsafe { write_all(fd, buf.as_ptr().cast(), buf.len()) })?; + assert_eq!(res as usize, buf.len()); + Ok(()) } #[cfg(any(target_os = "linux", target_os = "android", target_os = "illumos"))] From da0dda15036e486778afee422ab8603cc6d1334e Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 10 Jan 2026 14:21:46 +0100 Subject: [PATCH 0531/1061] Remove special case for `AllowedTargets::CrateLevel` --- .../src/attributes/crate_level.rs | 18 ++++++------ compiler/rustc_attr_parsing/src/context.rs | 14 ++-------- .../rustc_attr_parsing/src/target_checking.rs | 28 ++++++------------- 3 files changed, 19 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index 01c503357fc7..5604fbd25edc 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -9,7 +9,7 @@ impl SingleAttributeParser for CrateNameParser { const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(n) = args else { @@ -33,7 +33,7 @@ impl SingleAttributeParser for RecursionLimitParser { const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute"); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { @@ -56,7 +56,7 @@ impl SingleAttributeParser for MoveSizeLimitParser { const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { @@ -79,7 +79,7 @@ impl SingleAttributeParser for TypeLengthLimitParser { const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { @@ -102,7 +102,7 @@ impl SingleAttributeParser for PatternComplexityLimitParser { const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { @@ -123,7 +123,7 @@ pub(crate) struct NoCoreParser; impl NoArgsAttributeParser for NoCoreParser { const PATH: &[Symbol] = &[sym::no_core]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoCore; } @@ -132,7 +132,7 @@ pub(crate) struct NoStdParser; impl NoArgsAttributeParser for NoStdParser { const PATH: &[Symbol] = &[sym::no_std]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoStd; } @@ -141,7 +141,7 @@ pub(crate) struct RustcCoherenceIsCoreParser; impl NoArgsAttributeParser for RustcCoherenceIsCoreParser { const PATH: &[Symbol] = &[sym::rustc_coherence_is_core]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcCoherenceIsCore; } @@ -151,7 +151,7 @@ impl SingleAttributeParser for WindowsSubsystemParser { const PATH: &[Symbol] = &[sym::windows_subsystem]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: ["windows", "console"], "https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute"); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index b85bb6c6c89d..527e3f567cf3 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -4,12 +4,12 @@ use std::ops::{Deref, DerefMut}; use std::sync::LazyLock; use private::Sealed; -use rustc_ast::{AttrStyle, CRATE_NODE_ID, MetaItemLit, NodeId}; +use rustc_ast::{AttrStyle, MetaItemLit, NodeId}; use rustc_errors::{Diag, Diagnostic, Level}; use rustc_feature::{AttrSuggestionStyle, AttributeTemplate}; use rustc_hir::attrs::AttributeKind; use rustc_hir::lints::{AttributeLint, AttributeLintKind}; -use rustc_hir::{AttrPath, CRATE_HIR_ID, HirId}; +use rustc_hir::{AttrPath, HirId}; use rustc_session::Session; use rustc_session::lint::{Lint, LintId}; use rustc_span::{ErrorGuaranteed, Span, Symbol}; @@ -303,8 +303,6 @@ pub trait Stage: Sized + 'static + Sealed { ) -> ErrorGuaranteed; fn should_emit(&self) -> ShouldEmit; - - fn id_is_crate_root(id: Self::Id) -> bool; } // allow because it's a sealed trait @@ -326,10 +324,6 @@ impl Stage for Early { fn should_emit(&self) -> ShouldEmit { self.emit_errors } - - fn id_is_crate_root(id: Self::Id) -> bool { - id == CRATE_NODE_ID - } } // allow because it's a sealed trait @@ -351,10 +345,6 @@ impl Stage for Late { fn should_emit(&self) -> ShouldEmit { ShouldEmit::ErrorsAndLints } - - fn id_is_crate_root(id: Self::Id) -> bool { - id == CRATE_HIR_ID - } } /// used when parsing attributes for miscellaneous things *before* ast lowering diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index 88fa3e436292..52c2d10f4797 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -15,11 +15,6 @@ use crate::session_diagnostics::InvalidTarget; pub(crate) enum AllowedTargets { AllowList(&'static [Policy]), AllowListWarnRest(&'static [Policy]), - /// Special, and not the same as `AllowList(&[Allow(Target::Crate)])`. - /// For crate-level attributes we emit a specific set of lints to warn - /// people about accidentally not using them on the crate. - /// Only use this for attributes that are *exclusively* valid at the crate level. - CrateLevel, } pub(crate) enum AllowedResult { @@ -53,7 +48,6 @@ impl AllowedTargets { AllowedResult::Warn } } - AllowedTargets::CrateLevel => AllowedResult::Allowed, } } @@ -61,7 +55,6 @@ impl AllowedTargets { match self { AllowedTargets::AllowList(list) => list, AllowedTargets::AllowListWarnRest(list) => list, - AllowedTargets::CrateLevel => ALL_TARGETS, } .iter() .filter_map(|target| match target { @@ -95,7 +88,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { target: Target, cx: &mut AcceptContext<'_, 'sess, S>, ) { - Self::check_type(matches!(allowed_targets, AllowedTargets::CrateLevel), target, cx); + if allowed_targets.allowed_targets() == &[Target::Crate] { + Self::check_crate_level(target, cx); + return; + } match allowed_targets.is_allowed(target) { AllowedResult::Allowed => {} @@ -149,18 +145,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { } } - pub(crate) fn check_type( - crate_level: bool, - target: Target, - cx: &mut AcceptContext<'_, 'sess, S>, - ) { - let is_crate_root = S::id_is_crate_root(cx.target_id); - - if is_crate_root { - return; - } - - if !crate_level { + pub(crate) fn check_crate_level(target: Target, cx: &mut AcceptContext<'_, 'sess, S>) { + // For crate-level attributes we emit a specific set of lints to warn + // people about accidentally not using them on the crate. + if target == Target::Crate { return; } From 2b597f599e857a5718f16ca70c676447a5b4e68e Mon Sep 17 00:00:00 2001 From: Fabio Almeida Date: Sat, 10 Jan 2026 14:31:37 +0000 Subject: [PATCH 0532/1061] feat: invisible character help string --- compiler/rustc_parse/messages.ftl | 1 + compiler/rustc_parse/src/errors.rs | 6 ++++++ compiler/rustc_parse/src/lexer/mod.rs | 5 +++++ tests/ui/lexer/lex-invisible-characters.rs | 6 ++++++ tests/ui/lexer/lex-invisible-characters.stderr | 10 ++++++++++ 5 files changed, 28 insertions(+) create mode 100644 tests/ui/lexer/lex-invisible-characters.rs create mode 100644 tests/ui/lexer/lex-invisible-characters.stderr diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 747895c80469..1331d99c01ea 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -967,6 +967,7 @@ parse_unknown_start_of_token = unknown start of token: {$escaped} .sugg_quotes = Unicode characters '“' (Left Double Quotation Mark) and '”' (Right Double Quotation Mark) look like '{$ascii_str}' ({$ascii_name}), but are not .sugg_other = Unicode character '{$ch}' ({$u_name}) looks like '{$ascii_str}' ({$ascii_name}), but it is not .help_null = source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used + .help_invisible_char = invisible characters like '{$escaped}' are not usually visible in text editors .note_repeats = character appears {$repeats -> [one] once more *[other] {$repeats} more times diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 3b72c9802afd..60e4a240c85e 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2369,6 +2369,8 @@ pub(crate) struct UnknownTokenStart { pub null: Option, #[subdiagnostic] pub repeat: Option, + #[subdiagnostic] + pub invisible: Option, } #[derive(Subdiagnostic)] @@ -2409,6 +2411,10 @@ pub(crate) struct UnknownTokenRepeat { pub repeats: usize, } +#[derive(Subdiagnostic)] +#[help(parse_help_invisible_char)] +pub(crate) struct InvisibleCharacter; + #[derive(Subdiagnostic)] #[help(parse_help_null)] pub(crate) struct UnknownTokenNull; diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 94ae35c19582..7c969dd7f9f4 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -36,6 +36,10 @@ use unescape_error_reporting::{emit_unescape_error, escaped_char}; #[cfg(target_pointer_width = "64")] rustc_data_structures::static_assert_size!(rustc_lexer::Token, 12); +const INVISIBLE_CHARACTERS: [char; 8] = [ + '\u{200b}', '\u{200c}', '\u{2060}', '\u{2061}', '\u{2062}', '\u{00ad}', '\u{034f}', '\u{061c}', +]; + #[derive(Clone, Debug)] pub(crate) struct UnmatchedDelim { pub found_delim: Option, @@ -456,6 +460,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { escaped: escaped_char(c), sugg, null: if c == '\x00' { Some(errors::UnknownTokenNull) } else { None }, + invisible: if INVISIBLE_CHARACTERS.contains(&c) { Some(errors::InvisibleCharacter) } else { None }, repeat: if repeats > 0 { swallow_next_invalid = repeats; Some(errors::UnknownTokenRepeat { repeats }) diff --git a/tests/ui/lexer/lex-invisible-characters.rs b/tests/ui/lexer/lex-invisible-characters.rs new file mode 100644 index 000000000000..2db72b8475dc --- /dev/null +++ b/tests/ui/lexer/lex-invisible-characters.rs @@ -0,0 +1,6 @@ +// Provide extra help when a user has an invisible character in their code + +fn main​() { + //~^ ERROR unknown start of token: \u{200b} + //~| HELP invisible characters like '\u{200b}' are not usually visible in text editors +} diff --git a/tests/ui/lexer/lex-invisible-characters.stderr b/tests/ui/lexer/lex-invisible-characters.stderr new file mode 100644 index 000000000000..ddac0f4e9325 --- /dev/null +++ b/tests/ui/lexer/lex-invisible-characters.stderr @@ -0,0 +1,10 @@ +error: unknown start of token: \u{200b} + --> $DIR/lex-invisible-characters.rs:3:8 + | +LL | fn main​() { + | ^ + | + = help: invisible characters like '\u{200b}' are not usually visible in text editors + +error: aborting due to 1 previous error + From 03ad5b07ee3aae10cfb9d70c9ff75ef3b9570e01 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Jan 2026 15:40:04 +0100 Subject: [PATCH 0533/1061] readme: clarify 'single-threaded interpreter' --- src/tools/miri/README.md | 3 ++- src/tools/miri/src/bin/miri.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index d5ef9c767414..925b85f58766 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -228,7 +228,8 @@ and macOS targets are usually on par. Windows is supported less well. ### Running tests in parallel -Though it implements Rust threading, Miri itself is a single-threaded interpreter. +Though it implements Rust threading, Miri itself is a single-threaded interpreter +(it works like a multi-threaded OS on a single-core CPU). This means that when running `cargo miri test`, you will probably see a dramatic increase in the amount of time it takes to run your whole test suite due to the inherent interpreter slowdown and a loss of parallelism. diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 19fbf90246c9..55c1fa203eb9 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -710,7 +710,7 @@ fn main() { if !miri_config.native_lib.is_empty() && miri_config.provenance_mode == ProvenanceMode::Strict { fatal_error!("strict provenance is not compatible with calling native functions"); } - // Native calls and many-seeds are an "intersting" combination. + // Native calls and many-seeds are an "interesting" combination. if !miri_config.native_lib.is_empty() && many_seeds.is_some() { eprintln!( "warning: `-Zmiri-many-seeds` runs multiple instances of the program in the same address space, \ From 8332887f36091d9c6c8b2faefdb33dcaa1743e32 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Sat, 10 Jan 2026 11:04:54 -0500 Subject: [PATCH 0534/1061] Update cargo submodule --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 8c133afcd5e0..6d1bd93c47f0 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 8c133afcd5e0d69932fe11f5907683723f8d361d +Subproject commit 6d1bd93c47f059ec1344cb31e68a2fb284cbc6b1 From 6878e73d26af87e01c1c289c77f1448fa3c3e76f Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Sat, 10 Jan 2026 11:59:33 +0530 Subject: [PATCH 0535/1061] std: sys: fs: uefi: Implement File::seek - Tested using OVMF on QEMU. Signed-off-by: Ayush Singh --- library/std/src/sys/fs/uefi.rs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index fcf21d9e9731..23de7adfabc6 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -352,8 +352,24 @@ impl File { unsupported() } - pub fn seek(&self, _pos: SeekFrom) -> io::Result { - unsupported() + pub fn seek(&self, pos: SeekFrom) -> io::Result { + const NEG_OFF_ERR: io::Error = + io::const_error!(io::ErrorKind::InvalidInput, "cannot seek to negative offset."); + + let off = match pos { + SeekFrom::Start(p) => p, + SeekFrom::End(p) => { + // Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to be set to the end of the file. + if p == 0 { + 0xFFFFFFFFFFFFFFFF + } else { + self.file_attr()?.size().checked_add_signed(p).ok_or(NEG_OFF_ERR)? + } + } + SeekFrom::Current(p) => self.tell()?.checked_add_signed(p).ok_or(NEG_OFF_ERR)?, + }; + + self.0.set_position(off).map(|_| off) } pub fn size(&self) -> Option> { @@ -755,6 +771,12 @@ mod uefi_fs { if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(pos) } } + pub(crate) fn set_position(&self, pos: u64) -> io::Result<()> { + let file_ptr = self.protocol.as_ptr(); + let r = unsafe { ((*file_ptr).set_position)(file_ptr, pos) }; + if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } + } + pub(crate) fn delete(self) -> io::Result<()> { let file_ptr = self.protocol.as_ptr(); let r = unsafe { ((*file_ptr).delete)(file_ptr) }; From 767291606e7071e6e13e56f2eb4e620e688fbc9e Mon Sep 17 00:00:00 2001 From: kirk Date: Sat, 27 Dec 2025 16:43:10 +0000 Subject: [PATCH 0536/1061] Remove mentions of debootstrap and chroots from the m68k-unknown-none-elf platform support doc --- .../platform-support/m68k-unknown-none-elf.md | 36 +------------------ 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/src/doc/rustc/src/platform-support/m68k-unknown-none-elf.md b/src/doc/rustc/src/platform-support/m68k-unknown-none-elf.md index e390ba0aee96..ed13886fe935 100644 --- a/src/doc/rustc/src/platform-support/m68k-unknown-none-elf.md +++ b/src/doc/rustc/src/platform-support/m68k-unknown-none-elf.md @@ -29,40 +29,6 @@ binaries: # apt install qemu-user-static ``` -To run more complex programs, it will be necessary to set up a Debian/m68k chroot with -the help of the command `debootstrap`: - -```text -# apt install debootstrap debian-ports-archive-keyring -# debootstrap --keyring=/usr/share/keyrings/debian-ports-archive-keyring.gpg --arch=m68k unstable debian-68k http://ftp.ports.debian.org/debian-ports -``` - -This chroot can then seamlessly entered using the normal `chroot` command thanks to -QEMU user emulation: - -```text -# chroot /path/to/debian-68k -``` - -To get started with native builds, which are currently untested, a native Debian/m68k -system can be installed either on real hardware such as 68k-based Commodore Amiga or -Atari systems or emulated environments such as QEMU version 4.2 or newer or ARAnyM. - -ISO images for installation are provided by the Debian Ports team and can be obtained -from the Debian CD image server available at: - -[https://cdimage.debian.org/cdimage/ports/current](https://cdimage.debian.org/cdimage/ports/current/) - -Documentation for Debian/m68k is available on the Debian Wiki at: - -[https://wiki.debian.org/M68k](https://wiki.debian.org/M68k) - -Support is available either through the `debian-68k` mailing list: - -[https://lists.debian.org/debian-68k/](https://lists.debian.org/debian-68k/) - -or the `#debian-68k` IRC channel on OFTC network. - ## Building At least llvm version `19.1.5` is required to build `core` and `alloc` for this target, and currently the gnu linker is required, as `lld` has no support for the `m68k` architecture @@ -105,4 +71,4 @@ Very simple programs can be run using the `qemu-m68k-static` program: qemu-m68k-static your-code ``` -For more complex applications, a chroot or native m68k system is required for testing. +For more complex applications, a native (or emulated) m68k system is required for testing. From ab1caae91203e9aa976fe2eb9faba3d013d812ad Mon Sep 17 00:00:00 2001 From: kirk Date: Sun, 28 Dec 2025 17:58:52 +0000 Subject: [PATCH 0537/1061] move sentence about gnu ld from 'Building' to 'Requirements' section --- src/doc/rustc/src/platform-support/m68k-unknown-none-elf.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/m68k-unknown-none-elf.md b/src/doc/rustc/src/platform-support/m68k-unknown-none-elf.md index ed13886fe935..0a9bdc7e1c98 100644 --- a/src/doc/rustc/src/platform-support/m68k-unknown-none-elf.md +++ b/src/doc/rustc/src/platform-support/m68k-unknown-none-elf.md @@ -12,6 +12,7 @@ Bare metal Motorola 680x0 This target requires an m68k build environment for cross-compilation which is available on Debian, Debian-based systems, openSUSE, and other distributions. +The gnu linker is currently required, as `lld` has no support for the `m68k` architecture On Debian-based systems, it should be sufficient to install a g++ cross-compiler for the m68k architecture which will automatically pull in additional dependencies such as @@ -31,7 +32,7 @@ binaries: ## Building -At least llvm version `19.1.5` is required to build `core` and `alloc` for this target, and currently the gnu linker is required, as `lld` has no support for the `m68k` architecture +At least llvm version `19.1.5` is required to build `core` and `alloc` for this target. ## Cross-compilation From c10f0dd1947645259a7e1e9f436956aea73d1cdf Mon Sep 17 00:00:00 2001 From: Guilherme Luiz Date: Sat, 10 Jan 2026 14:09:21 -0300 Subject: [PATCH 0538/1061] =?UTF-8?q?Add=20comment=20to=20clarify=20that?= =?UTF-8?q?=20'=EF=AC=83'=20is=20a=20single=20Unicode=20code=20point=20map?= =?UTF-8?q?ping=20to=20FFI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- library/core/src/char/methods.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index c30edeed580a..0acb3e964f54 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -1143,6 +1143,7 @@ impl char { /// [Unicode Standard]: https://www.unicode.org/versions/latest/ /// /// # Examples + /// `'ffi'` (U+FB03) is a single Unicode code point (a ligature) that maps to "FFI" in uppercase. /// /// As an iterator: /// From e4dd9475234017adeda572d02320876f98e26775 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Sat, 10 Jan 2026 19:57:28 +0100 Subject: [PATCH 0539/1061] introduce `Self::as_x_{plus,minus}_one` reduces duplication --- clippy_lints/src/int_plus_one.rs | 91 +++++++++++++++----------------- 1 file changed, 44 insertions(+), 47 deletions(-) diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index b82ca0205a9f..f8184b30f400 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -63,7 +63,7 @@ impl TryFrom for LeOrGe { impl IntPlusOne { fn is_one(expr: &Expr) -> bool { if let ExprKind::Lit(token_lit) = expr.kind - && let Ok(LitKind::Int(Pu128(1), ..)) = LitKind::from_token_lit(token_lit) + && matches!(LitKind::from_token_lit(token_lit), Ok(LitKind::Int(Pu128(1), ..))) { return true; } @@ -71,60 +71,57 @@ impl IntPlusOne { } fn is_neg_one(expr: &Expr) -> bool { - if let ExprKind::Unary(UnOp::Neg, expr) = &expr.kind - && Self::is_one(expr) - { - true + if let ExprKind::Unary(UnOp::Neg, expr) = &expr.kind { + Self::is_one(expr) } else { false } } + /// Checks whether `expr` is `x + 1` or `1 + x`, and if so, returns `x` + fn as_x_plus_one(expr: &Expr) -> Option<&Expr> { + if let ExprKind::Binary(op, lhs, rhs) = &expr.kind + && op.node == BinOpKind::Add + { + if Self::is_one(rhs) { + // x + 1 + return Some(lhs); + } else if Self::is_one(lhs) { + // 1 + x + return Some(rhs); + } + } + None + } + + /// Checks whether `expr` is `x - 1` or `-1 + x`, and if so, returns `x` + fn as_x_minus_one(expr: &Expr) -> Option<&Expr> { + if let ExprKind::Binary(op, lhs, rhs) = &expr.kind { + if op.node == BinOpKind::Sub && Self::is_one(rhs) { + // x - 1 + return Some(lhs); + } else if op.node == BinOpKind::Add && Self::is_neg_one(lhs) { + // -1 + x + return Some(rhs); + } + } + None + } + fn check_binop<'tcx>(le_or_ge: LeOrGe, lhs: &'tcx Expr, rhs: &'tcx Expr) -> Option<(&'tcx Expr, &'tcx Expr)> { - match (le_or_ge, &lhs.kind, &rhs.kind) { - // case where `x - 1 >= ...` or `-1 + x >= ...` - (LeOrGe::Ge, ExprKind::Binary(lhskind, lhslhs, lhsrhs), _) => { - match lhskind.node { - // `-1 + x` - BinOpKind::Add if Self::is_neg_one(lhslhs) => Some((lhsrhs, rhs)), - // `x - 1` - BinOpKind::Sub if Self::is_one(lhsrhs) => Some((lhslhs, rhs)), - _ => None, - } + match le_or_ge { + LeOrGe::Ge => { + // case where `x - 1 >= ...` or `-1 + x >= ...` + (Self::as_x_minus_one(lhs).map(|new_lhs| (new_lhs, rhs))) + // case where `... >= y + 1` or `... >= 1 + y` + .or_else(|| Self::as_x_plus_one(rhs).map(|new_rhs| (lhs, new_rhs))) }, - // case where `... >= y + 1` or `... >= 1 + y` - (LeOrGe::Ge, _, ExprKind::Binary(rhskind, rhslhs, rhsrhs)) if rhskind.node == BinOpKind::Add => { - // `y + 1` and `1 + y` - if Self::is_one(rhslhs) { - Some((lhs, rhsrhs)) - } else if Self::is_one(rhsrhs) { - Some((lhs, rhslhs)) - } else { - None - } + LeOrGe::Le => { + // case where `x + 1 <= ...` or `1 + x <= ...` + (Self::as_x_plus_one(lhs).map(|new_lhs| (new_lhs, rhs))) + // case where `... <= y - 1` or `... <= -1 + y` + .or_else(|| Self::as_x_minus_one(rhs).map(|new_rhs| (lhs, new_rhs))) }, - // case where `x + 1 <= ...` or `1 + x <= ...` - (LeOrGe::Le, ExprKind::Binary(lhskind, lhslhs, lhsrhs), _) if lhskind.node == BinOpKind::Add => { - // `1 + x` and `x + 1` - if Self::is_one(lhslhs) { - Some((lhsrhs, rhs)) - } else if Self::is_one(lhsrhs) { - Some((lhslhs, rhs)) - } else { - None - } - }, - // case where `... <= y - 1` or `... <= -1 + y` - (LeOrGe::Le, _, ExprKind::Binary(rhskind, rhslhs, rhsrhs)) => { - match rhskind.node { - // `-1 + y` - BinOpKind::Add if Self::is_neg_one(rhslhs) => Some((lhs, rhsrhs)), - // `y - 1` - BinOpKind::Sub if Self::is_one(rhsrhs) => Some((lhs, rhslhs)), - _ => None, - } - }, - _ => None, } } From 306254b40e83189ae65fdda6501b1523d8c19c03 Mon Sep 17 00:00:00 2001 From: relaxcn Date: Sun, 11 Jan 2026 03:51:36 +0800 Subject: [PATCH 0540/1061] improve the doc of `doc_paragraphs_missing_punctuation` --- clippy_lints/src/doc/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index 2b41275ee3a4..ecf7acbd7ce6 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -692,6 +692,12 @@ declare_clippy_lint! { /// /// /// /// It was chosen by a fair dice roll. /// ``` + /// + /// ### Terminal punctuation marks + /// This lint treats these characters as end markers: '.', '?', '!', '…' and ':'. + /// + /// The colon is not exactly a terminal punctuation mark, but this is required for paragraphs that + /// introduce a table or a list for example. #[clippy::version = "1.93.0"] pub DOC_PARAGRAPHS_MISSING_PUNCTUATION, restriction, From 5ee964049a9f0808bc0729fad79be446a2a987cb Mon Sep 17 00:00:00 2001 From: dianqk Date: Sat, 10 Jan 2026 18:34:02 +0800 Subject: [PATCH 0541/1061] Add FileCheck to if_condition_int.rs --- ...t_opt_bool.SimplifyComparisonIntegral.diff | 2 +- ...opt_floats.SimplifyComparisonIntegral.diff | 2 +- ...comparison.SimplifyComparisonIntegral.diff | 18 ++--- ...t.opt_char.SimplifyComparisonIntegral.diff | 4 +- ...int.opt_i8.SimplifyComparisonIntegral.diff | 4 +- ...ltiple_ifs.SimplifyComparisonIntegral.diff | 8 +- ...t_negative.SimplifyComparisonIntegral.diff | 4 +- ...nt.opt_u32.SimplifyComparisonIntegral.diff | 4 +- tests/mir-opt/if_condition_int.rs | 76 ++++++++++++++++--- 9 files changed, 88 insertions(+), 34 deletions(-) diff --git a/tests/mir-opt/if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff index 2350faa05d3f..f2d527326592 100644 --- a/tests/mir-opt/if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff @@ -9,7 +9,7 @@ bb0: { StorageLive(_2); _2 = copy _1; - switchInt(move _2) -> [0: bb2, otherwise: bb1]; + switchInt(copy _1) -> [0: bb2, otherwise: bb1]; } bb1: { diff --git a/tests/mir-opt/if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff index 94570017730d..c72a58a145f4 100644 --- a/tests/mir-opt/if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff @@ -11,7 +11,7 @@ StorageLive(_2); StorageLive(_3); _3 = copy _1; - _2 = Eq(move _3, const -42f32); + _2 = Eq(copy _1, const -42f32); switchInt(move _2) -> [0: bb2, otherwise: bb1]; } diff --git a/tests/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff index d19b4148405e..29d57722355b 100644 --- a/tests/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff @@ -15,23 +15,20 @@ } bb0: { - StorageLive(_2); + nop; StorageLive(_3); _3 = copy _1; -- _2 = Eq(move _3, const 17_i8); -- StorageDead(_3); + _2 = Eq(copy _1, const 17_i8); + StorageDead(_3); - switchInt(copy _2) -> [0: bb2, otherwise: bb1]; -+ _2 = Eq(copy _3, const 17_i8); -+ nop; -+ switchInt(move _3) -> [17: bb1, otherwise: bb2]; ++ switchInt(move _1) -> [17: bb1, otherwise: bb2]; } bb1: { -+ StorageDead(_3); StorageLive(_6); StorageLive(_7); _7 = copy _2; - _6 = move _7 as i32 (IntToInt); + _6 = copy _2 as i32 (IntToInt); StorageDead(_7); _0 = Add(const 100_i32, move _6); StorageDead(_6); @@ -39,11 +36,10 @@ } bb2: { -+ StorageDead(_3); StorageLive(_4); StorageLive(_5); _5 = copy _2; - _4 = move _5 as i32 (IntToInt); + _4 = copy _2 as i32 (IntToInt); StorageDead(_5); _0 = Add(const 10_i32, move _4); StorageDead(_4); @@ -51,7 +47,7 @@ } bb3: { - StorageDead(_2); + nop; return; } } diff --git a/tests/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff index e47b7e522598..37b41c2aa5ab 100644 --- a/tests/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff @@ -11,10 +11,10 @@ StorageLive(_2); StorageLive(_3); _3 = copy _1; -- _2 = Eq(move _3, const 'x'); +- _2 = Eq(copy _1, const 'x'); - switchInt(move _2) -> [0: bb2, otherwise: bb1]; + nop; -+ switchInt(move _3) -> [120: bb1, otherwise: bb2]; ++ switchInt(move _1) -> [120: bb1, otherwise: bb2]; } bb1: { diff --git a/tests/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff index b6cdc6af8bf4..c92a606090e4 100644 --- a/tests/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff @@ -11,10 +11,10 @@ StorageLive(_2); StorageLive(_3); _3 = copy _1; -- _2 = Eq(move _3, const 42_i8); +- _2 = Eq(copy _1, const 42_i8); - switchInt(move _2) -> [0: bb2, otherwise: bb1]; + nop; -+ switchInt(move _3) -> [42: bb1, otherwise: bb2]; ++ switchInt(move _1) -> [42: bb1, otherwise: bb2]; } bb1: { diff --git a/tests/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff index 31745ac732a2..a73670323b1f 100644 --- a/tests/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff @@ -13,10 +13,10 @@ StorageLive(_2); StorageLive(_3); _3 = copy _1; -- _2 = Eq(move _3, const 42_u32); +- _2 = Eq(copy _1, const 42_u32); - switchInt(move _2) -> [0: bb2, otherwise: bb1]; + nop; -+ switchInt(move _3) -> [42: bb1, otherwise: bb2]; ++ switchInt(move _1) -> [42: bb1, otherwise: bb2]; } bb1: { @@ -30,10 +30,10 @@ StorageLive(_4); StorageLive(_5); _5 = copy _1; -- _4 = Ne(move _5, const 21_u32); +- _4 = Ne(copy _1, const 21_u32); - switchInt(move _4) -> [0: bb4, otherwise: bb3]; + nop; -+ switchInt(move _5) -> [21: bb4, otherwise: bb3]; ++ switchInt(move _1) -> [21: bb4, otherwise: bb3]; } bb3: { diff --git a/tests/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff index d747985f6e13..36145ab02bea 100644 --- a/tests/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff @@ -11,10 +11,10 @@ StorageLive(_2); StorageLive(_3); _3 = copy _1; -- _2 = Eq(move _3, const -42_i32); +- _2 = Eq(copy _1, const -42_i32); - switchInt(move _2) -> [0: bb2, otherwise: bb1]; + nop; -+ switchInt(move _3) -> [4294967254: bb1, otherwise: bb2]; ++ switchInt(move _1) -> [4294967254: bb1, otherwise: bb2]; } bb1: { diff --git a/tests/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff index 1d6809a9438a..2cc4a8b76973 100644 --- a/tests/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff @@ -11,10 +11,10 @@ StorageLive(_2); StorageLive(_3); _3 = copy _1; -- _2 = Eq(move _3, const 42_u32); +- _2 = Eq(copy _1, const 42_u32); - switchInt(move _2) -> [0: bb2, otherwise: bb1]; + nop; -+ switchInt(move _3) -> [42: bb1, otherwise: bb2]; ++ switchInt(move _1) -> [42: bb1, otherwise: bb2]; } bb1: { diff --git a/tests/mir-opt/if_condition_int.rs b/tests/mir-opt/if_condition_int.rs index 4cc2c2b90210..24ef6b85529e 100644 --- a/tests/mir-opt/if_condition_int.rs +++ b/tests/mir-opt/if_condition_int.rs @@ -1,36 +1,76 @@ -// skip-filecheck //@ test-mir-pass: SimplifyComparisonIntegral -// EMIT_MIR if_condition_int.opt_u32.SimplifyComparisonIntegral.diff -// EMIT_MIR if_condition_int.opt_negative.SimplifyComparisonIntegral.diff -// EMIT_MIR if_condition_int.opt_char.SimplifyComparisonIntegral.diff -// EMIT_MIR if_condition_int.opt_i8.SimplifyComparisonIntegral.diff -// EMIT_MIR if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff -// EMIT_MIR if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff -// EMIT_MIR if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff -// EMIT_MIR if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff +// GVN simplifies FileCheck. +//@ compile-flags: -Zmir-enable-passes=+GVN +// EMIT_MIR if_condition_int.opt_u32.SimplifyComparisonIntegral.diff fn opt_u32(x: u32) -> u32 { + // CHECK-LABEL: fn opt_u32( + // FIXME: This should be copy. + // CHECK: switchInt(move _1) -> [42: [[BB1:bb.*]], otherwise: [[BB2:bb.*]]]; + // CHECK: [[BB1]]: + // CHECK: _0 = const 0_u32; + // CHECK: [[BB2]]: + // CHECK: _0 = const 1_u32; if x == 42 { 0 } else { 1 } } +// EMIT_MIR if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff // don't opt: it is already optimal to switch on the bool fn dont_opt_bool(x: bool) -> u32 { + // CHECK-LABEL: fn dont_opt_bool( + // CHECK: switchInt(copy _1) -> [0: [[BB2:bb.*]], otherwise: [[BB1:bb.*]]]; + // CHECK: [[BB1]]: + // CHECK: _0 = const 0_u32; + // CHECK: [[BB2]]: + // CHECK: _0 = const 1_u32; if x { 0 } else { 1 } } +// EMIT_MIR if_condition_int.opt_char.SimplifyComparisonIntegral.diff fn opt_char(x: char) -> u32 { + // CHECK-LABEL: fn opt_char( + // CHECK: switchInt(move _1) -> [120: [[BB1:bb.*]], otherwise: [[BB2:bb.*]]]; + // CHECK: [[BB1]]: + // CHECK: _0 = const 0_u32; + // CHECK: [[BB2]]: + // CHECK: _0 = const 1_u32; if x == 'x' { 0 } else { 1 } } +// EMIT_MIR if_condition_int.opt_i8.SimplifyComparisonIntegral.diff fn opt_i8(x: i8) -> u32 { + // CHECK-LABEL: fn opt_i8( + // CHECK: switchInt(move _1) -> [42: [[BB1:bb.*]], otherwise: [[BB2:bb.*]]]; + // CHECK: [[BB1]]: + // CHECK: _0 = const 0_u32; + // CHECK: [[BB2]]: + // CHECK: _0 = const 1_u32; if x == 42 { 0 } else { 1 } } +// EMIT_MIR if_condition_int.opt_negative.SimplifyComparisonIntegral.diff fn opt_negative(x: i32) -> u32 { + // CHECK-LABEL: fn opt_negative( + // CHECK: switchInt(move _1) -> [4294967254: [[BB1:bb.*]], otherwise: [[BB2:bb.*]]]; + // CHECK: [[BB1]]: + // CHECK: _0 = const 0_u32; + // CHECK: [[BB2]]: + // CHECK: _0 = const 1_u32; if x == -42 { 0 } else { 1 } } +// EMIT_MIR if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff fn opt_multiple_ifs(x: u32) -> u32 { + // CHECK-LABEL: fn opt_multiple_ifs( + // CHECK: switchInt(move _1) -> [42: [[BB1:bb.*]], otherwise: [[BB2:bb.*]]]; + // CHECK: [[BB1]]: + // CHECK: _0 = const 0_u32; + // CHECK: [[BB2]]: + // CHECK: switchInt(move _1) -> [21: [[BB4:bb.*]], otherwise: [[BB3:bb.*]]]; + // CHECK: [[BB3]]: + // CHECK: _0 = const 1_u32; + // CHECK: [[BB4]]: + // CHECK: _0 = const 2_u32; if x == 42 { 0 } else if x != 21 { @@ -40,8 +80,18 @@ fn opt_multiple_ifs(x: u32) -> u32 { } } +// EMIT_MIR if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff // test that we optimize, but do not remove the b statement, as that is used later on fn dont_remove_comparison(a: i8) -> i32 { + // CHECK-LABEL: fn dont_remove_comparison( + // CHECK: [[b:_.*]] = Eq(copy _1, const 17_i8); + // CHECK: switchInt(move _1) -> [17: [[BB1:bb.*]], otherwise: [[BB2:bb.*]]]; + // CHECK: [[BB1]]: + // CHECK: [[cast_1:_.*]] = copy [[b]] as i32 (IntToInt); + // CHECK: _0 = Add(const 100_i32, move [[cast_1]]); + // CHECK: [[BB2]]: + // CHECK: [[cast_2:_.*]] = copy [[b]] as i32 (IntToInt); + // CHECK: _0 = Add(const 10_i32, move [[cast_2]]); let b = a == 17; match b { false => 10 + b as i32, @@ -49,8 +99,16 @@ fn dont_remove_comparison(a: i8) -> i32 { } } +// EMIT_MIR if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff // test that we do not optimize on floats fn dont_opt_floats(a: f32) -> i32 { + // CHECK-LABEL: fn dont_opt_floats( + // CHECK: [[cmp:_.*]] = Eq(copy _1, const -42f32); + // CHECK: switchInt(move [[cmp]]) -> [0: [[BB2:bb.*]], otherwise: [[BB1:bb.*]]]; + // CHECK: [[BB1]]: + // CHECK: _0 = const 0_i32; + // CHECK: [[BB2]]: + // CHECK: _0 = const 1_i32; if a == -42.0 { 0 } else { 1 } } From 528fd2a33057644dd3aca50d04a626e4b1527948 Mon Sep 17 00:00:00 2001 From: dianqk Date: Sat, 10 Jan 2026 18:45:33 +0800 Subject: [PATCH 0542/1061] Add miscompiled test cases --- ...on_ssa_cmp.SimplifyComparisonIntegral.diff | 25 ++++++ ..._ssa_place.SimplifyComparisonIntegral.diff | 25 ++++++ ...ssa_switch.SimplifyComparisonIntegral.diff | 25 ++++++ tests/mir-opt/if_condition_int.rs | 81 +++++++++++++++++++ 4 files changed, 156 insertions(+) create mode 100644 tests/mir-opt/if_condition_int.on_non_ssa_cmp.SimplifyComparisonIntegral.diff create mode 100644 tests/mir-opt/if_condition_int.on_non_ssa_place.SimplifyComparisonIntegral.diff create mode 100644 tests/mir-opt/if_condition_int.on_non_ssa_switch.SimplifyComparisonIntegral.diff diff --git a/tests/mir-opt/if_condition_int.on_non_ssa_cmp.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.on_non_ssa_cmp.SimplifyComparisonIntegral.diff new file mode 100644 index 000000000000..d0983c660623 --- /dev/null +++ b/tests/mir-opt/if_condition_int.on_non_ssa_cmp.SimplifyComparisonIntegral.diff @@ -0,0 +1,25 @@ +- // MIR for `on_non_ssa_cmp` before SimplifyComparisonIntegral ++ // MIR for `on_non_ssa_cmp` after SimplifyComparisonIntegral + + fn on_non_ssa_cmp(_1: u64) -> i32 { + let mut _0: i32; + let mut _2: bool; + + bb0: { + _2 = Eq(copy _1, const 42_u64); + _1 = const 43_u64; +- switchInt(copy _2) -> [1: bb1, otherwise: bb2]; ++ switchInt(move _1) -> [42: bb1, otherwise: bb2]; + } + + bb1: { + _0 = const 0_i32; + return; + } + + bb2: { + _0 = const 1_i32; + return; + } + } + diff --git a/tests/mir-opt/if_condition_int.on_non_ssa_place.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.on_non_ssa_place.SimplifyComparisonIntegral.diff new file mode 100644 index 000000000000..0c6c8dca4753 --- /dev/null +++ b/tests/mir-opt/if_condition_int.on_non_ssa_place.SimplifyComparisonIntegral.diff @@ -0,0 +1,25 @@ +- // MIR for `on_non_ssa_place` before SimplifyComparisonIntegral ++ // MIR for `on_non_ssa_place` after SimplifyComparisonIntegral + + fn on_non_ssa_place(_1: [u64; 10], _2: usize) -> i32 { + let mut _0: i32; + let mut _3: bool; + + bb0: { + _3 = Eq(copy _1[_2], const 42_u64); + _2 = const 10_usize; +- switchInt(copy _3) -> [1: bb1, otherwise: bb2]; ++ switchInt(move _1[_2]) -> [42: bb1, otherwise: bb2]; + } + + bb1: { + _0 = const 0_i32; + return; + } + + bb2: { + _0 = const 1_i32; + return; + } + } + diff --git a/tests/mir-opt/if_condition_int.on_non_ssa_switch.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.on_non_ssa_switch.SimplifyComparisonIntegral.diff new file mode 100644 index 000000000000..b1b1ab2c2205 --- /dev/null +++ b/tests/mir-opt/if_condition_int.on_non_ssa_switch.SimplifyComparisonIntegral.diff @@ -0,0 +1,25 @@ +- // MIR for `on_non_ssa_switch` before SimplifyComparisonIntegral ++ // MIR for `on_non_ssa_switch` after SimplifyComparisonIntegral + + fn on_non_ssa_switch(_1: u64) -> i32 { + let mut _0: i32; + let mut _2: bool; + + bb0: { + _2 = Eq(copy _1, const 42_u64); + _2 = const false; +- switchInt(copy _2) -> [1: bb1, otherwise: bb2]; ++ switchInt(move _1) -> [42: bb1, otherwise: bb2]; + } + + bb1: { + _0 = const 0_i32; + return; + } + + bb2: { + _0 = const 1_i32; + return; + } + } + diff --git a/tests/mir-opt/if_condition_int.rs b/tests/mir-opt/if_condition_int.rs index 24ef6b85529e..ba901f6b9b15 100644 --- a/tests/mir-opt/if_condition_int.rs +++ b/tests/mir-opt/if_condition_int.rs @@ -2,6 +2,11 @@ // GVN simplifies FileCheck. //@ compile-flags: -Zmir-enable-passes=+GVN +#![feature(custom_mir, core_intrinsics)] + +extern crate core; +use core::intrinsics::mir::*; + // EMIT_MIR if_condition_int.opt_u32.SimplifyComparisonIntegral.diff fn opt_u32(x: u32) -> u32 { // CHECK-LABEL: fn opt_u32( @@ -112,6 +117,81 @@ fn dont_opt_floats(a: f32) -> i32 { if a == -42.0 { 0 } else { 1 } } +// EMIT_MIR if_condition_int.on_non_ssa_switch.SimplifyComparisonIntegral.diff +#[custom_mir(dialect = "runtime")] +pub fn on_non_ssa_switch(mut v: u64) -> i32 { + mir! { + let a: bool; + { + a = v == 42; + a = false; + match a { + true => bb1, + _ => bb2, + } + + } + bb1 = { + RET = 0; + Return() + } + bb2 = { + RET = 1; + Return() + } + } +} + +// EMIT_MIR if_condition_int.on_non_ssa_cmp.SimplifyComparisonIntegral.diff +#[custom_mir(dialect = "runtime")] +pub fn on_non_ssa_cmp(mut v: u64) -> i32 { + mir! { + let a: bool; + { + a = v == 42; + v = 43; + match a { + true => bb1, + _ => bb2, + } + + } + bb1 = { + RET = 0; + Return() + } + bb2 = { + RET = 1; + Return() + } + } +} + +// EMIT_MIR if_condition_int.on_non_ssa_place.SimplifyComparisonIntegral.diff +#[custom_mir(dialect = "runtime")] +pub fn on_non_ssa_place(mut v: [u64; 10], mut i: usize) -> i32 { + mir! { + let a: bool; + { + a = v[i] == 42; + i = 10; + match a { + true => bb1, + _ => bb2, + } + + } + bb1 = { + RET = 0; + Return() + } + bb2 = { + RET = 1; + Return() + } + } +} + fn main() { opt_u32(0); opt_char('0'); @@ -121,4 +201,5 @@ fn main() { opt_multiple_ifs(0); dont_remove_comparison(11); dont_opt_floats(1.0); + on_non_ssa_switch(42); } From 76fcac23713815f214aba8d4751986d771f7f131 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Sat, 10 Jan 2026 23:40:22 +0100 Subject: [PATCH 0543/1061] Port `#[rustc_has_incoherent_inherent_impls]` to attribute parser --- .../src/attributes/rustc_internal.rs | 15 +++++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 13 +++++++------ compiler/rustc_hir/src/attrs/data_structures.rs | 3 +++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + .../src/coherence/inherent_impls.rs | 7 +++++-- compiler/rustc_middle/src/ty/trait_def.rs | 6 +++--- compiler/rustc_passes/messages.ftl | 4 ---- compiler/rustc_passes/src/check_attr.rs | 15 +-------------- compiler/rustc_passes/src/errors.rs | 9 --------- 9 files changed, 35 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 922a5bd297ac..834b1d988cb4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -305,3 +305,18 @@ impl SingleAttributeParser for RustcScalableVectorParser { Some(AttributeKind::RustcScalableVector { element_count: Some(n), span: cx.attr_span }) } } + +pub(crate) struct RustcHasIncoherentInherentImplsParser; + +impl NoArgsAttributeParser for RustcHasIncoherentInherentImplsParser { + const PATH: &[Symbol] = &[sym::rustc_has_incoherent_inherent_impls]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Trait), + Allow(Target::Struct), + Allow(Target::Enum), + Allow(Target::Union), + Allow(Target::ForeignTy), + ]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcHasIncoherentInherentImpls; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index b85bb6c6c89d..513e6ad72b56 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -62,12 +62,12 @@ use crate::attributes::proc_macro_attrs::{ use crate::attributes::prototype::CustomMirParser; use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; use crate::attributes::rustc_internal::{ - RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser, - RustcLegacyConstGenericsParser, RustcLintDiagnosticsParser, RustcLintOptDenyFieldAccessParser, - RustcLintOptTyParser, RustcLintQueryInstabilityParser, - RustcLintUntrackedQueryInformationParser, RustcMainParser, RustcMustImplementOneOfParser, - RustcNeverReturnsNullPointerParser, RustcNoImplicitAutorefsParser, - RustcObjectLifetimeDefaultParser, RustcScalableVectorParser, + RustcHasIncoherentInherentImplsParser, RustcLayoutScalarValidRangeEndParser, + RustcLayoutScalarValidRangeStartParser, RustcLegacyConstGenericsParser, + RustcLintDiagnosticsParser, RustcLintOptDenyFieldAccessParser, RustcLintOptTyParser, + RustcLintQueryInstabilityParser, RustcLintUntrackedQueryInformationParser, RustcMainParser, + RustcMustImplementOneOfParser, RustcNeverReturnsNullPointerParser, + RustcNoImplicitAutorefsParser, RustcObjectLifetimeDefaultParser, RustcScalableVectorParser, RustcSimdMonomorphizeLaneLimitParser, }; use crate::attributes::semantics::MayDangleParser; @@ -264,6 +264,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 23201eff455f..c791f54902d1 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -880,6 +880,9 @@ pub enum AttributeKind { /// Represents `#[rustc_coherence_is_core]` RustcCoherenceIsCore(Span), + /// Represents `#[rustc_has_incoherent_inherent_impls]` + RustcHasIncoherentInherentImpls, + /// Represents `#[rustc_layout_scalar_valid_range_end]`. RustcLayoutScalarValidRangeEnd(Box, Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 3efa876ed6a9..4e1e9a074e66 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -95,6 +95,7 @@ impl AttributeKind { Repr { .. } => No, RustcBuiltinMacro { .. } => Yes, RustcCoherenceIsCore(..) => No, + RustcHasIncoherentInherentImpls => Yes, RustcLayoutScalarValidRangeEnd(..) => Yes, RustcLayoutScalarValidRangeStart(..) => Yes, RustcLegacyConstGenerics { .. } => Yes, diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index 984a812246eb..fe47f3258846 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -15,7 +15,7 @@ use rustc_hir::find_attr; use rustc_middle::bug; use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams, simplify_type}; use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt}; -use rustc_span::{ErrorGuaranteed, sym}; +use rustc_span::ErrorGuaranteed; use crate::errors; @@ -79,7 +79,10 @@ impl<'tcx> InherentCollect<'tcx> { } if self.tcx.features().rustc_attrs() { - if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) { + if !find_attr!( + self.tcx.get_all_attrs(ty_def_id), + AttributeKind::RustcHasIncoherentInherentImpls + ) { let impl_span = self.tcx.def_span(impl_def_id); return Err(self.tcx.dcx().emit_err(errors::InherentTyOutside { span: impl_span })); } diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 691cb43b724a..2f6b38a619d2 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -2,11 +2,11 @@ use std::iter; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorGuaranteed; -use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_hir::{self as hir, find_attr}; use rustc_macros::{Decodable, Encodable, HashStable}; -use rustc_span::symbol::sym; use tracing::debug; use crate::query::LocalCrate; @@ -241,7 +241,7 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait /// Query provider for `incoherent_impls`. pub(super) fn incoherent_impls_provider(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] { if let Some(def_id) = simp.def() - && !tcx.has_attr(def_id, sym::rustc_has_incoherent_inherent_impls) + && !find_attr!(tcx.get_all_attrs(def_id), AttributeKind::RustcHasIncoherentInherentImpls) { return &[]; } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 94996c0adb47..ba44aa3a35ab 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -244,10 +244,6 @@ passes_function_not_have_default_implementation = function doesn't have a defaul passes_functions_names_duplicated = functions names are duplicated .note = all `#[rustc_must_implement_one_of]` arguments must be unique -passes_has_incoherent_inherent_impl = - `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits - .label = only adts, extern types and traits are supported - passes_ignored_derived_impls = `{$name}` has {$trait_list_len -> [one] a derived impl diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 2d3c5c7e48a0..360feacac0e9 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -306,6 +306,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::CfgAttrTrace | AttributeKind::ThreadLocal | AttributeKind::CfiEncoding { .. } + | AttributeKind::RustcHasIncoherentInherentImpls ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); @@ -325,9 +326,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | [sym::rustc_then_this_would_need, ..] => self.check_rustc_dirty_clean(attr), [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target), [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target), - [sym::rustc_has_incoherent_inherent_impls, ..] => { - self.check_has_incoherent_inherent_impls(attr, span, target) - } [sym::autodiff_forward, ..] | [sym::autodiff_reverse, ..] => { self.check_autodiff(hir_id, attr, span, target) } @@ -1164,17 +1162,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_has_incoherent_inherent_impls(&self, attr: &Attribute, span: Span, target: Target) { - match target { - Target::Trait | Target::Struct | Target::Enum | Target::Union | Target::ForeignTy => {} - _ => { - self.tcx - .dcx() - .emit_err(errors::HasIncoherentInherentImpl { attr_span: attr.span(), span }); - } - } - } - fn check_ffi_pure(&self, attr_span: Span, attrs: &[Attribute]) { if find_attr!(attrs, AttributeKind::FfiConst(_)) { // `#[ffi_const]` functions cannot be `#[ffi_pure]` diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index af5cb29b83d0..14555765e423 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -187,15 +187,6 @@ pub(crate) struct DocAttrNotCrateLevel<'a> { pub attr_name: &'a str, } -#[derive(Diagnostic)] -#[diag(passes_has_incoherent_inherent_impl)] -pub(crate) struct HasIncoherentInherentImpl { - #[primary_span] - pub attr_span: Span, - #[label] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(passes_both_ffi_const_and_pure, code = E0757)] pub(crate) struct BothFfiConstAndPure { From 50813939e4d21a90cef22f42d4fb2d32600f2910 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 11 Jan 2026 12:04:46 +1100 Subject: [PATCH 0544/1061] Don't run the longer partial-sort tests under Miri --- library/alloctests/tests/sort/partial.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/alloctests/tests/sort/partial.rs b/library/alloctests/tests/sort/partial.rs index c7248990c70c..679841b91e8d 100644 --- a/library/alloctests/tests/sort/partial.rs +++ b/library/alloctests/tests/sort/partial.rs @@ -79,6 +79,10 @@ fn basic_impl() { fn random_patterns() { check_is_partial_sorted_ranges(&patterns::random(10)); check_is_partial_sorted_ranges(&patterns::random(50)); - check_is_partial_sorted_ranges(&patterns::random(100)); - check_is_partial_sorted_ranges(&patterns::random(1000)); + + // Longer tests would take hours to run under Miri. + if !cfg!(miri) { + check_is_partial_sorted_ranges(&patterns::random(100)); + check_is_partial_sorted_ranges(&patterns::random(1000)); + } } From 9e0a27cfa9a35e35a9065a2802a9b1620639845d Mon Sep 17 00:00:00 2001 From: mu001999 Date: Fri, 9 Jan 2026 19:31:53 +0800 Subject: [PATCH 0545/1061] Emit error instead of delayed bug when meeting mismatch type for const tuple --- compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs | 5 +++-- .../const-generics/mgca/tuple_expr_arg_mismatch_type.rs | 8 ++++++++ .../mgca/tuple_expr_arg_mismatch_type.stderr | 8 ++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 tests/ui/const-generics/mgca/tuple_expr_arg_mismatch_type.rs create mode 100644 tests/ui/const-generics/mgca/tuple_expr_arg_mismatch_type.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 1dd9bff42575..f3b4e7a9072c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2502,11 +2502,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let tcx = self.tcx(); let FeedConstTy::WithTy(ty) = feed else { - return Const::new_error_with_message(tcx, span, "unsupported const tuple"); + return Const::new_error_with_message(tcx, span, "const tuple lack type information"); }; let ty::Tuple(tys) = ty.kind() else { - return Const::new_error_with_message(tcx, span, "const tuple must have a tuple type"); + let e = tcx.dcx().span_err(span, format!("expected {}, found const tuple", ty)); + return Const::new_error(tcx, e); }; let exprs = exprs diff --git a/tests/ui/const-generics/mgca/tuple_expr_arg_mismatch_type.rs b/tests/ui/const-generics/mgca/tuple_expr_arg_mismatch_type.rs new file mode 100644 index 000000000000..02807dfc302e --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_expr_arg_mismatch_type.rs @@ -0,0 +1,8 @@ +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +pub fn takes_nested_tuple() { + takes_nested_tuple::<{ () }> //~ ERROR expected u32, found const tuple +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/tuple_expr_arg_mismatch_type.stderr b/tests/ui/const-generics/mgca/tuple_expr_arg_mismatch_type.stderr new file mode 100644 index 000000000000..ad6db9e12373 --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_expr_arg_mismatch_type.stderr @@ -0,0 +1,8 @@ +error: expected u32, found const tuple + --> $DIR/tuple_expr_arg_mismatch_type.rs:5:28 + | +LL | takes_nested_tuple::<{ () }> + | ^^ + +error: aborting due to 1 previous error + From 8ca1c9eb8fb16c97892a9628a6f94466d54ba24a Mon Sep 17 00:00:00 2001 From: mu001999 Date: Fri, 9 Jan 2026 19:32:23 +0800 Subject: [PATCH 0546/1061] Rename tests for const tuple properly --- compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs | 2 +- ...rg_tuple_expr_complex.rs => tuple_expr_arg_complex.rs} | 0 ..._expr_complex.stderr => tuple_expr_arg_complex.stderr} | 8 ++++---- .../const-generics/mgca/tuple_expr_arg_mismatch_type.rs | 2 +- .../mgca/tuple_expr_arg_mismatch_type.stderr | 2 +- ..._arg_tuple_expr_simple.rs => tuple_expr_arg_simple.rs} | 0 6 files changed, 7 insertions(+), 7 deletions(-) rename tests/ui/const-generics/mgca/{adt_expr_arg_tuple_expr_complex.rs => tuple_expr_arg_complex.rs} (100%) rename tests/ui/const-generics/mgca/{adt_expr_arg_tuple_expr_complex.stderr => tuple_expr_arg_complex.stderr} (77%) rename tests/ui/const-generics/mgca/{adt_expr_arg_tuple_expr_simple.rs => tuple_expr_arg_simple.rs} (100%) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index f3b4e7a9072c..4f610d2512a4 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2506,7 +2506,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; let ty::Tuple(tys) = ty.kind() else { - let e = tcx.dcx().span_err(span, format!("expected {}, found const tuple", ty)); + let e = tcx.dcx().span_err(span, format!("expected `{}`, found const tuple", ty)); return Const::new_error(tcx, e); }; diff --git a/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_complex.rs b/tests/ui/const-generics/mgca/tuple_expr_arg_complex.rs similarity index 100% rename from tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_complex.rs rename to tests/ui/const-generics/mgca/tuple_expr_arg_complex.rs diff --git a/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_complex.stderr b/tests/ui/const-generics/mgca/tuple_expr_arg_complex.stderr similarity index 77% rename from tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_complex.stderr rename to tests/ui/const-generics/mgca/tuple_expr_arg_complex.stderr index dbc64a1bf59d..b294e1032ce8 100644 --- a/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_complex.stderr +++ b/tests/ui/const-generics/mgca/tuple_expr_arg_complex.stderr @@ -1,23 +1,23 @@ error: complex const arguments must be placed inside of a `const` block - --> $DIR/adt_expr_arg_tuple_expr_complex.rs:13:25 + --> $DIR/tuple_expr_arg_complex.rs:13:25 | LL | takes_tuple::<{ (N, N + 1) }>(); | ^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/adt_expr_arg_tuple_expr_complex.rs:14:25 + --> $DIR/tuple_expr_arg_complex.rs:14:25 | LL | takes_tuple::<{ (N, T::ASSOC + 1) }>(); | ^^^^^^^^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/adt_expr_arg_tuple_expr_complex.rs:16:36 + --> $DIR/tuple_expr_arg_complex.rs:16:36 | LL | takes_nested_tuple::<{ (N, (N, N + 1)) }>(); | ^^^^^ error: generic parameters may not be used in const operations - --> $DIR/adt_expr_arg_tuple_expr_complex.rs:17:44 + --> $DIR/tuple_expr_arg_complex.rs:17:44 | LL | takes_nested_tuple::<{ (N, (N, const { N + 1 })) }>(); | ^ diff --git a/tests/ui/const-generics/mgca/tuple_expr_arg_mismatch_type.rs b/tests/ui/const-generics/mgca/tuple_expr_arg_mismatch_type.rs index 02807dfc302e..95acd66074f6 100644 --- a/tests/ui/const-generics/mgca/tuple_expr_arg_mismatch_type.rs +++ b/tests/ui/const-generics/mgca/tuple_expr_arg_mismatch_type.rs @@ -2,7 +2,7 @@ #![expect(incomplete_features)] pub fn takes_nested_tuple() { - takes_nested_tuple::<{ () }> //~ ERROR expected u32, found const tuple + takes_nested_tuple::<{ () }> //~ ERROR expected `u32`, found const tuple } fn main() {} diff --git a/tests/ui/const-generics/mgca/tuple_expr_arg_mismatch_type.stderr b/tests/ui/const-generics/mgca/tuple_expr_arg_mismatch_type.stderr index ad6db9e12373..dfbd294951fd 100644 --- a/tests/ui/const-generics/mgca/tuple_expr_arg_mismatch_type.stderr +++ b/tests/ui/const-generics/mgca/tuple_expr_arg_mismatch_type.stderr @@ -1,4 +1,4 @@ -error: expected u32, found const tuple +error: expected `u32`, found const tuple --> $DIR/tuple_expr_arg_mismatch_type.rs:5:28 | LL | takes_nested_tuple::<{ () }> diff --git a/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_simple.rs b/tests/ui/const-generics/mgca/tuple_expr_arg_simple.rs similarity index 100% rename from tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_simple.rs rename to tests/ui/const-generics/mgca/tuple_expr_arg_simple.rs From bd8c67c75ac1890c2cb9c31f658e0907cd50dab4 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Sun, 11 Jan 2026 12:38:20 +0530 Subject: [PATCH 0547/1061] std: sys: fs: uefi: Implement copy - Using the implementation from sys::fs::common since ther is no built-in copy implementation in UEFI. - Tested with OVMF on QEMU. Signed-off-by: Ayush Singh --- library/std/src/sys/fs/uefi.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index c416419bd008..b6bc14efdfb4 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -6,7 +6,7 @@ use crate::fs::TryLockError; use crate::hash::Hash; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::path::{Path, PathBuf}; -pub use crate::sys::fs::common::{Dir, remove_dir_all}; +pub use crate::sys::fs::common::{Dir, copy, remove_dir_all}; use crate::sys::pal::{helpers, unsupported}; use crate::sys::time::SystemTime; @@ -524,10 +524,6 @@ pub fn canonicalize(p: &Path) -> io::Result { crate::path::absolute(p) } -pub fn copy(_from: &Path, _to: &Path) -> io::Result { - unsupported() -} - fn set_perm_inner(f: &uefi_fs::File, perm: FilePermissions) -> io::Result<()> { let mut file_info = f.file_info()?; From ea93fb548c7c6e838b35893f3f9cc2ed3011aaea Mon Sep 17 00:00:00 2001 From: yukang Date: Sun, 11 Jan 2026 16:30:38 +0800 Subject: [PATCH 0548/1061] Underscore-prefixed bindings are explicitly allowed to be unused --- compiler/rustc_mir_transform/src/liveness.rs | 5 ++++ .../unused/underscore-capture-issue-149889.rs | 29 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 tests/ui/lint/unused/underscore-capture-issue-149889.rs diff --git a/compiler/rustc_mir_transform/src/liveness.rs b/compiler/rustc_mir_transform/src/liveness.rs index 1d1ba455a81e..a5a2fcd71a9a 100644 --- a/compiler/rustc_mir_transform/src/liveness.rs +++ b/compiler/rustc_mir_transform/src/liveness.rs @@ -1086,6 +1086,11 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> { let Some((name, decl_span)) = self.checked_places.names[index] else { continue }; + // By convention, underscore-prefixed bindings are explicitly allowed to be unused. + if name.as_str().starts_with('_') { + continue; + } + let is_maybe_drop_guard = maybe_drop_guard( tcx, self.typing_env, diff --git a/tests/ui/lint/unused/underscore-capture-issue-149889.rs b/tests/ui/lint/unused/underscore-capture-issue-149889.rs new file mode 100644 index 000000000000..3fbaf2588516 --- /dev/null +++ b/tests/ui/lint/unused/underscore-capture-issue-149889.rs @@ -0,0 +1,29 @@ +//@ check-pass +#![deny(unused_assignments)] + +fn lock() -> impl Drop { + struct Handle; + + impl Drop for Handle { + fn drop(&mut self) {} + } + + Handle +} + +fn bar(_f: impl FnMut(bool)) {} + +pub fn foo() { + let mut _handle = None; + bar(move |l| { + if l { + _handle = Some(lock()); + } else { + _handle = None; + } + }) +} + +fn main() { + foo(); +} From faea581d45ce89968064788c43fa45524c10c89c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sun, 11 Jan 2026 10:35:13 +0100 Subject: [PATCH 0549/1061] Remove references to bors2 --- src/ci/github-actions/jobs.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 9acad5c06b21..7411b394b94a 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -152,8 +152,8 @@ try: - <<: *job-dist-x86_64-linux # Jobs that only run when explicitly invoked in one of the following ways: -# - comment `@bors2 try jobs=` -# - `try-job: ` in the PR description and comment `@bors try` or `@bors2 try`. +# - comment `@bors try jobs=` +# - `try-job: ` in the PR description and comment `@bors try`. optional: # This job is used just to test optional jobs. # It will be replaced by tier 2 and tier 3 jobs in the future. From 47b987eccb7c2defece8f053c197836784baf421 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sun, 11 Jan 2026 10:15:05 +0100 Subject: [PATCH 0550/1061] Do not show spans from external crates in `missing_trait_methods` Pointing to the missing method definition in external crates will use paths which depend on the system, and even on the Rust compiler version used when the iterator is defined in the standard library. When the trait being implemented and whose method is missing is external, point only to the trait implementation. The user will be able to figure out, or even navigate using their IDE, to the proper definition. As a side-effect, this will remove a large lintcheck churn at every Rustup for this lint. --- clippy_lints/src/missing_trait_methods.rs | 10 +++++++++- tests/ui/missing_trait_methods.rs | 7 +++++++ tests/ui/missing_trait_methods.stderr | 10 +++++++++- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/missing_trait_methods.rs b/clippy_lints/src/missing_trait_methods.rs index 8e9400e9d583..7a791f949943 100644 --- a/clippy_lints/src/missing_trait_methods.rs +++ b/clippy_lints/src/missing_trait_methods.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_lint_allowed; use clippy_utils::macros::span_is_local; +use clippy_utils::source::snippet_opt; use rustc_hir::def_id::DefIdSet; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -84,7 +85,14 @@ impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods { cx.tcx.def_span(item.owner_id), format!("missing trait method provided by default: `{}`", assoc.name()), |diag| { - diag.span_help(cx.tcx.def_span(assoc.def_id), "implement the method"); + if assoc.def_id.is_local() { + diag.span_help(cx.tcx.def_span(assoc.def_id), "implement the method"); + } else if let Some(snippet) = snippet_opt(cx, of_trait.trait_ref.path.span) { + diag.help(format!( + "implement the missing `{}` method of the `{snippet}` trait", + assoc.name(), + )); + } }, ); } diff --git a/tests/ui/missing_trait_methods.rs b/tests/ui/missing_trait_methods.rs index 7af186ba3322..67070a299951 100644 --- a/tests/ui/missing_trait_methods.rs +++ b/tests/ui/missing_trait_methods.rs @@ -62,3 +62,10 @@ impl MissingMultiple for Partial {} //~| missing_trait_methods fn main() {} + +//~v missing_trait_methods +impl PartialEq for Partial { + fn eq(&self, other: &Partial) -> bool { + todo!() + } +} diff --git a/tests/ui/missing_trait_methods.stderr b/tests/ui/missing_trait_methods.stderr index d9fb8951ab3d..e5155ad587cb 100644 --- a/tests/ui/missing_trait_methods.stderr +++ b/tests/ui/missing_trait_methods.stderr @@ -60,5 +60,13 @@ help: implement the method LL | fn three() {} | ^^^^^^^^^^ -error: aborting due to 5 previous errors +error: missing trait method provided by default: `ne` + --> tests/ui/missing_trait_methods.rs:67:1 + | +LL | impl PartialEq for Partial { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: implement the missing `ne` method of the `PartialEq` trait + +error: aborting due to 6 previous errors From b5dd72d2921500c9d9e15f074e1d831adcaa3dee Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 10 Jan 2026 23:06:07 +0100 Subject: [PATCH 0551/1061] Port `#[collapse_debuginfo]` to the new attribute parsing system --- .../src/attributes/macro_attrs.rs | 45 ++++++++++++++++- compiler/rustc_attr_parsing/src/context.rs | 4 +- compiler/rustc_expand/messages.ftl | 3 -- compiler/rustc_expand/src/base.rs | 49 +++++-------------- compiler/rustc_expand/src/errors.rs | 7 --- .../rustc_hir/src/attrs/data_structures.rs | 23 +++++++++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_interface/src/tests.rs | 14 +++--- compiler/rustc_passes/messages.ftl | 4 -- compiler/rustc_passes/src/check_attr.rs | 14 +----- compiler/rustc_passes/src/errors.rs | 9 ---- compiler/rustc_session/src/config.rs | 33 +++---------- compiler/rustc_session/src/options.rs | 1 + 13 files changed, 98 insertions(+), 109 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index 0f1ab02fca25..d37915b1b80b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -1,4 +1,4 @@ -use rustc_hir::attrs::MacroUseArgs; +use rustc_hir::attrs::{CollapseMacroDebuginfo, MacroUseArgs}; use rustc_session::lint::builtin::INVALID_MACRO_EXPORT_ARGUMENTS; use super::prelude::*; @@ -163,3 +163,46 @@ impl SingleAttributeParser for MacroExportParser { Some(AttributeKind::MacroExport { span: cx.attr_span, local_inner_macros }) } } + +pub(crate) struct CollapseDebugInfoParser; + +impl SingleAttributeParser for CollapseDebugInfoParser { + const PATH: &[Symbol] = &[sym::collapse_debuginfo]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const TEMPLATE: AttributeTemplate = template!( + List: &["no", "external", "yes"], + "https://doc.rust-lang.org/reference/attributes/debugger.html#the-collapse_debuginfo-attribute" + ); + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { + let Some(list) = args.list() else { + cx.expected_list(cx.attr_span, args); + return None; + }; + let Some(single) = list.single() else { + cx.expected_single_argument(list.span); + return None; + }; + let Some(mi) = single.meta_item() else { + cx.unexpected_literal(single.span()); + return None; + }; + if let Err(err) = mi.args().no_args() { + cx.expected_no_args(err); + } + let path = mi.path().word_sym(); + let info = match path { + Some(sym::yes) => CollapseMacroDebuginfo::Yes, + Some(sym::no) => CollapseMacroDebuginfo::No, + Some(sym::external) => CollapseMacroDebuginfo::External, + _ => { + cx.expected_specific_argument(mi.span(), &[sym::yes, sym::no, sym::external]); + return None; + } + }; + + Some(AttributeKind::CollapseDebugInfo(info)) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index b85bb6c6c89d..114dacd8c795 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -48,7 +48,8 @@ use crate::attributes::lint_helpers::{ }; use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser}; use crate::attributes::macro_attrs::{ - AllowInternalUnsafeParser, MacroEscapeParser, MacroExportParser, MacroUseParser, + AllowInternalUnsafeParser, CollapseDebugInfoParser, MacroEscapeParser, MacroExportParser, + MacroUseParser, }; use crate::attributes::must_use::MustUseParser; use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser; @@ -191,6 +192,7 @@ attribute_parsers!( // tidy-alphabetical-start Single, + Single, Single, Single, Single, diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index 6c23320a1b11..851d78e0b105 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -5,9 +5,6 @@ expand_attributes_on_expressions_experimental = expand_cfg_attr_no_attributes = `#[cfg_attr]` does not expand to any attributes -expand_collapse_debuginfo_illegal = - illegal value for attribute #[collapse_debuginfo(no|external|yes)] - expand_count_repetition_misplaced = `count` can not be placed inside the innermost repetition diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 946f17943fe3..bf653fac5253 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -6,7 +6,7 @@ use std::path::{Path, PathBuf}; use std::rc::Rc; use std::sync::Arc; -use rustc_ast::attr::{AttributeExt, MarkedAttrs}; +use rustc_ast::attr::MarkedAttrs; use rustc_ast::token::MetaVarKind; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{AssocCtxt, Visitor}; @@ -16,7 +16,7 @@ use rustc_data_structures::sync; use rustc_errors::{BufferedEarlyLint, DiagCtxtHandle, ErrorGuaranteed, PResult}; use rustc_feature::Features; use rustc_hir as hir; -use rustc_hir::attrs::{AttributeKind, CfgEntry, Deprecation}; +use rustc_hir::attrs::{AttributeKind, CfgEntry, CollapseMacroDebuginfo, Deprecation}; use rustc_hir::def::MacroKinds; use rustc_hir::limit::Limit; use rustc_hir::{Stability, find_attr}; @@ -24,7 +24,6 @@ use rustc_lint_defs::RegisteredTools; use rustc_parse::MACRO_ARGUMENTS; use rustc_parse::parser::{ForceCollect, Parser}; use rustc_session::Session; -use rustc_session::config::CollapseMacroDebuginfo; use rustc_session::parse::ParseSess; use rustc_span::def_id::{CrateNum, DefId, LocalDefId}; use rustc_span::edition::Edition; @@ -34,7 +33,6 @@ use rustc_span::{DUMMY_SP, FileName, Ident, Span, Symbol, kw, sym}; use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; -use crate::base::ast::MetaItemInner; use crate::errors; use crate::expand::{self, AstFragment, Invocation}; use crate::mbe::macro_rules::ParserAnyMacro; @@ -887,25 +885,6 @@ impl SyntaxExtension { } } - fn collapse_debuginfo_by_name( - attr: &impl AttributeExt, - ) -> Result { - let list = attr.meta_item_list(); - let Some([MetaItemInner::MetaItem(item)]) = list.as_deref() else { - return Err(attr.span()); - }; - if !item.is_word() { - return Err(item.span); - } - - match item.name() { - Some(sym::no) => Ok(CollapseMacroDebuginfo::No), - Some(sym::external) => Ok(CollapseMacroDebuginfo::External), - Some(sym::yes) => Ok(CollapseMacroDebuginfo::Yes), - _ => Err(item.path.span), - } - } - /// if-ext - if macro from different crate (related to callsite code) /// | cmd \ attr | no | (unspecified) | external | yes | /// | no | no | no | no | no | @@ -914,21 +893,15 @@ impl SyntaxExtension { /// | yes | yes | yes | yes | yes | fn get_collapse_debuginfo(sess: &Session, attrs: &[hir::Attribute], ext: bool) -> bool { let flag = sess.opts.cg.collapse_macro_debuginfo; - let attr = ast::attr::find_by_name(attrs, sym::collapse_debuginfo) - .and_then(|attr| { - Self::collapse_debuginfo_by_name(attr) - .map_err(|span| { - sess.dcx().emit_err(errors::CollapseMacroDebuginfoIllegal { span }) - }) - .ok() - }) - .unwrap_or_else(|| { - if find_attr!(attrs, AttributeKind::RustcBuiltinMacro { .. }) { - CollapseMacroDebuginfo::Yes - } else { - CollapseMacroDebuginfo::Unspecified - } - }); + let attr = + if let Some(info) = find_attr!(attrs, AttributeKind::CollapseDebugInfo(info) => info) { + info.clone() + } else if find_attr!(attrs, AttributeKind::RustcBuiltinMacro { .. }) { + CollapseMacroDebuginfo::Yes + } else { + CollapseMacroDebuginfo::Unspecified + }; + #[rustfmt::skip] let collapse_table = [ [false, false, false, false], diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index 6bae16b3bba1..9f9764e060d1 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -78,13 +78,6 @@ pub(crate) struct ResolveRelativePath { pub path: String, } -#[derive(Diagnostic)] -#[diag(expand_collapse_debuginfo_illegal)] -pub(crate) struct CollapseMacroDebuginfoIllegal { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(expand_macro_const_stability)] pub(crate) struct MacroConstStability { diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 23201eff455f..25d6950c823d 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -568,6 +568,26 @@ impl rustc_serialize::Encodable for DocAttribute } } +/// How to perform collapse macros debug info +/// if-ext - if macro from different crate (related to callsite code) +/// | cmd \ attr | no | (unspecified) | external | yes | +/// | no | no | no | no | no | +/// | (unspecified) | no | no | if-ext | yes | +/// | external | no | if-ext | if-ext | yes | +/// | yes | yes | yes | yes | yes | +#[derive(Copy, Clone, Debug, Hash, PartialEq)] +#[derive(HashStable_Generic, Encodable, Decodable, PrintAttribute)] +pub enum CollapseMacroDebuginfo { + /// Don't collapse debuginfo for the macro + No = 0, + /// Unspecified value + Unspecified = 1, + /// Collapse debuginfo if the macro comes from a different crate + External = 2, + /// Collapse debuginfo for the macro + Yes = 3, +} + /// Represents parsed *built-in* inert attributes. /// /// ## Overview @@ -664,6 +684,9 @@ pub enum AttributeKind { /// Represents `#[cold]`. Cold(Span), + /// Represents `#[collapse_debuginfo]`. + CollapseDebugInfo(CollapseMacroDebuginfo), + /// Represents `#[rustc_confusables]`. Confusables { symbols: ThinVec, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 3efa876ed6a9..aa042ac10be4 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -31,6 +31,7 @@ impl AttributeKind { CfiEncoding { .. } => Yes, Coinductive(..) => No, Cold(..) => No, + CollapseDebugInfo(..) => Yes, Confusables { .. } => Yes, ConstContinue(..) => No, ConstStability { .. } => Yes, diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index d075f94ef850..a78b0e8e1ed8 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -8,14 +8,14 @@ use rustc_abi::Align; use rustc_data_structures::profiling::TimePassesFormat; use rustc_errors::emitter::HumanReadableErrorType; use rustc_errors::{ColorConfig, registry}; -use rustc_hir::attrs::NativeLibKind; +use rustc_hir::attrs::{CollapseMacroDebuginfo, NativeLibKind}; use rustc_session::config::{ - AnnotateMoves, AutoDiff, BranchProtection, CFGuard, Cfg, CollapseMacroDebuginfo, CoverageLevel, - CoverageOptions, DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, - Externs, FmtDebug, FunctionReturn, InliningThreshold, Input, InstrumentCoverage, - InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, MirIncludeSpans, - NextSolverConfig, Offload, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, - Passes, PatchableFunctionEntry, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, + AnnotateMoves, AutoDiff, BranchProtection, CFGuard, Cfg, CoverageLevel, CoverageOptions, + DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs, + FmtDebug, FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentXRay, + LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, MirIncludeSpans, NextSolverConfig, + Offload, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, + PatchableFunctionEntry, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel, build_configuration, build_session_options, rustc_optgroups, }; diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 94996c0adb47..9257802d6194 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -55,10 +55,6 @@ passes_change_fields_to_be_of_unit_type = *[other] fields } -passes_collapse_debuginfo = - `collapse_debuginfo` attribute should be applied to macro definitions - .label = not a macro definition - passes_const_continue_attr = `#[const_continue]` should be applied to a break expression .label = not a break expression diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 2d3c5c7e48a0..96bd976e5f6a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -229,6 +229,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect | AttributeKind::MacroTransparency(_) + | AttributeKind::CollapseDebugInfo(..) | AttributeKind::CfgTrace(..) | AttributeKind::Pointee(..) | AttributeKind::Dummy @@ -323,7 +324,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | [sym::rustc_dirty, ..] | [sym::rustc_if_this_changed, ..] | [sym::rustc_then_this_would_need, ..] => self.check_rustc_dirty_clean(attr), - [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target), [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target), [sym::rustc_has_incoherent_inherent_impls, ..] => { self.check_has_incoherent_inherent_impls(attr, span, target) @@ -718,18 +718,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } } - /// Checks if `#[collapse_debuginfo]` is applied to a macro. - fn check_collapse_debuginfo(&self, attr: &Attribute, span: Span, target: Target) { - match target { - Target::MacroDef => {} - _ => { - self.tcx.dcx().emit_err(errors::CollapseDebuginfo { - attr_span: attr.span(), - defn_span: span, - }); - } - } - } /// Checks if a `#[track_caller]` is applied to a function. fn check_track_caller( diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index af5cb29b83d0..382eab805354 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -384,15 +384,6 @@ pub(crate) struct UnusedMultiple { pub name: Symbol, } -#[derive(Diagnostic)] -#[diag(passes_collapse_debuginfo)] -pub(crate) struct CollapseDebuginfo { - #[primary_span] - pub attr_span: Span, - #[label] - pub defn_span: Span, -} - #[derive(LintDiagnostic)] #[diag(passes_deprecated_annotation_has_no_effect)] pub(crate) struct DeprecatedAnnotationHasNoEffect { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 8c492fcf8f15..f0dc5b9ac48c 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -3065,6 +3065,7 @@ pub(crate) mod dep_tracking { use rustc_errors::LanguageIdentifier; use rustc_feature::UnstableFeatures; use rustc_hashes::Hash64; + use rustc_hir::attrs::CollapseMacroDebuginfo; use rustc_span::edition::Edition; use rustc_span::{RealFileName, RemapPathScopeComponents}; use rustc_target::spec::{ @@ -3074,13 +3075,12 @@ pub(crate) mod dep_tracking { }; use super::{ - AnnotateMoves, AutoDiff, BranchProtection, CFGuard, CFProtection, CollapseMacroDebuginfo, - CoverageOptions, CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, FmtDebug, - FunctionReturn, InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, - LocationDetail, LtoCli, MirStripDebugInfo, NextSolverConfig, Offload, OptLevel, - OutFileName, OutputType, OutputTypes, PatchableFunctionEntry, Polonius, ResolveDocLinks, - SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, - WasiExecModel, + AnnotateMoves, AutoDiff, BranchProtection, CFGuard, CFProtection, CoverageOptions, + CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, FmtDebug, FunctionReturn, + InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail, + LtoCli, MirStripDebugInfo, NextSolverConfig, Offload, OptLevel, OutFileName, OutputType, + OutputTypes, PatchableFunctionEntry, Polonius, ResolveDocLinks, SourceFileHashAlgorithm, + SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel, }; use crate::lint; use crate::utils::NativeLib; @@ -3299,25 +3299,6 @@ pub enum ProcMacroExecutionStrategy { CrossThread, } -/// How to perform collapse macros debug info -/// if-ext - if macro from different crate (related to callsite code) -/// | cmd \ attr | no | (unspecified) | external | yes | -/// | no | no | no | no | no | -/// | (unspecified) | no | no | if-ext | yes | -/// | external | no | if-ext | if-ext | yes | -/// | yes | yes | yes | yes | yes | -#[derive(Clone, Copy, PartialEq, Hash, Debug)] -pub enum CollapseMacroDebuginfo { - /// Don't collapse debuginfo for the macro - No = 0, - /// Unspecified value - Unspecified = 1, - /// Collapse debuginfo if the macro comes from a different crate - External = 2, - /// Collapse debuginfo for the macro - Yes = 3, -} - /// Which format to use for `-Z dump-mono-stats` #[derive(Clone, Copy, PartialEq, Hash, Debug)] pub enum DumpMonoStatsFormat { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 21fa3321a30a..99ab13403812 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -10,6 +10,7 @@ use rustc_data_structures::stable_hasher::StableHasher; use rustc_errors::{ColorConfig, LanguageIdentifier, TerminalUrl}; use rustc_feature::UnstableFeatures; use rustc_hashes::Hash64; +use rustc_hir::attrs::CollapseMacroDebuginfo; use rustc_macros::{BlobDecodable, Encodable}; use rustc_span::edition::Edition; use rustc_span::{RealFileName, RemapPathScopeComponents, SourceFileHashAlgorithm}; From f0da7832b7956c29596c64a3a09e3e556a870d4a Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 10 Jan 2026 23:07:20 +0100 Subject: [PATCH 0552/1061] Update uitests --- .../attributes/collapse-debuginfo-invalid.rs | 44 ++-- .../collapse-debuginfo-invalid.stderr | 223 +++++++----------- 2 files changed, 112 insertions(+), 155 deletions(-) diff --git a/tests/ui/attributes/collapse-debuginfo-invalid.rs b/tests/ui/attributes/collapse-debuginfo-invalid.rs index ccf11df2eb0d..e467c72f52c0 100644 --- a/tests/ui/attributes/collapse-debuginfo-invalid.rs +++ b/tests/ui/attributes/collapse-debuginfo-invalid.rs @@ -5,80 +5,80 @@ // Test that the `#[collapse_debuginfo]` attribute can only be used on macro definitions. #[collapse_debuginfo(yes)] -//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions +//~^ ERROR `#[collapse_debuginfo]` attribute cannot be used on extern crate std; #[collapse_debuginfo(yes)] -//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions +//~^ ERROR `#[collapse_debuginfo]` attribute cannot be used on use std::collections::HashMap; #[collapse_debuginfo(yes)] -//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions +//~^ ERROR `#[collapse_debuginfo]` attribute cannot be used on static FOO: u32 = 3; #[collapse_debuginfo(yes)] -//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions +//~^ ERROR `#[collapse_debuginfo]` attribute cannot be used on const BAR: u32 = 3; #[collapse_debuginfo(yes)] -//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions +//~^ ERROR `#[collapse_debuginfo]` attribute cannot be used on fn foo() { let _ = #[collapse_debuginfo(yes)] || { }; - //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions + //~^ ERROR `#[collapse_debuginfo]` attribute cannot be used on #[collapse_debuginfo(yes)] - //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions + //~^ ERROR `#[collapse_debuginfo]` attribute cannot be used on let _ = 3; let _ = #[collapse_debuginfo(yes)] 3; - //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions + //~^ ERROR `#[collapse_debuginfo]` attribute cannot be used on match (3, 4) { #[collapse_debuginfo(yes)] - //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions + //~^ ERROR `#[collapse_debuginfo]` attribute cannot be used on _ => (), } } #[collapse_debuginfo(yes)] -//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions +//~^ ERROR `#[collapse_debuginfo]` attribute cannot be used on mod bar { } #[collapse_debuginfo(yes)] -//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions +//~^ ERROR `#[collapse_debuginfo]` attribute cannot be used on type Map = HashMap; #[collapse_debuginfo(yes)] -//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions +//~^ ERROR `#[collapse_debuginfo]` attribute cannot be used on enum Foo { #[collapse_debuginfo(yes)] - //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions + //~^ ERROR `#[collapse_debuginfo]` attribute cannot be used on Variant, } #[collapse_debuginfo(yes)] -//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions +//~^ ERROR `#[collapse_debuginfo]` attribute cannot be used on struct Bar { #[collapse_debuginfo(yes)] - //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions + //~^ ERROR `#[collapse_debuginfo]` attribute cannot be used on field: u32, } #[collapse_debuginfo(yes)] -//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions +//~^ ERROR `#[collapse_debuginfo]` attribute cannot be used on union Qux { a: u32, b: u16 } #[collapse_debuginfo(yes)] -//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions +//~^ ERROR `#[collapse_debuginfo]` attribute cannot be used on trait Foobar { #[collapse_debuginfo(yes)] - //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions + //~^ ERROR `#[collapse_debuginfo]` attribute cannot be used on type Bar; } #[collapse_debuginfo(yes)] -//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions +//~^ ERROR `#[collapse_debuginfo]` attribute cannot be used on type AFoobar = impl Foobar; impl Foobar for Bar { @@ -91,14 +91,14 @@ fn constraining() -> AFoobar { } #[collapse_debuginfo(yes)] -//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions +//~^ ERROR `#[collapse_debuginfo]` attribute cannot be used on impl Bar { #[collapse_debuginfo(yes)] - //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions + //~^ ERROR `#[collapse_debuginfo]` attribute cannot be used on const FOO: u32 = 3; #[collapse_debuginfo(yes)] - //~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions + //~^ ERROR `#[collapse_debuginfo]` attribute cannot be used on fn bar(&self) {} } diff --git a/tests/ui/attributes/collapse-debuginfo-invalid.stderr b/tests/ui/attributes/collapse-debuginfo-invalid.stderr index 081e4445a869..d66e334c993c 100644 --- a/tests/ui/attributes/collapse-debuginfo-invalid.stderr +++ b/tests/ui/attributes/collapse-debuginfo-invalid.stderr @@ -1,221 +1,178 @@ -error: `collapse_debuginfo` attribute should be applied to macro definitions +error: `#[collapse_debuginfo]` attribute cannot be used on extern crates --> $DIR/collapse-debuginfo-invalid.rs:7:1 | LL | #[collapse_debuginfo(yes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | extern crate std; - | ----------------- not a macro definition + | + = help: `#[collapse_debuginfo]` can only be applied to macro defs -error: `collapse_debuginfo` attribute should be applied to macro definitions +error: `#[collapse_debuginfo]` attribute cannot be used on use statements --> $DIR/collapse-debuginfo-invalid.rs:11:1 | LL | #[collapse_debuginfo(yes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | use std::collections::HashMap; - | ------------------------------ not a macro definition + | + = help: `#[collapse_debuginfo]` can only be applied to macro defs -error: `collapse_debuginfo` attribute should be applied to macro definitions +error: `#[collapse_debuginfo]` attribute cannot be used on statics --> $DIR/collapse-debuginfo-invalid.rs:15:1 | LL | #[collapse_debuginfo(yes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | static FOO: u32 = 3; - | -------------------- not a macro definition + | + = help: `#[collapse_debuginfo]` can only be applied to macro defs -error: `collapse_debuginfo` attribute should be applied to macro definitions +error: `#[collapse_debuginfo]` attribute cannot be used on constants --> $DIR/collapse-debuginfo-invalid.rs:19:1 | LL | #[collapse_debuginfo(yes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | const BAR: u32 = 3; - | ------------------- not a macro definition + | + = help: `#[collapse_debuginfo]` can only be applied to macro defs -error: `collapse_debuginfo` attribute should be applied to macro definitions +error: `#[collapse_debuginfo]` attribute cannot be used on functions --> $DIR/collapse-debuginfo-invalid.rs:23:1 | -LL | #[collapse_debuginfo(yes)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | / fn foo() { -LL | | let _ = #[collapse_debuginfo(yes)] || { }; -LL | | -LL | | #[collapse_debuginfo(yes)] -... | -LL | | } - | |_- not a macro definition +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[collapse_debuginfo]` can only be applied to macro defs -error: `collapse_debuginfo` attribute should be applied to macro definitions +error: `#[collapse_debuginfo]` attribute cannot be used on closures --> $DIR/collapse-debuginfo-invalid.rs:26:13 | LL | let _ = #[collapse_debuginfo(yes)] || { }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ------ not a macro definition + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[collapse_debuginfo]` can only be applied to macro defs -error: `collapse_debuginfo` attribute should be applied to macro definitions +error: `#[collapse_debuginfo]` attribute cannot be used on statements --> $DIR/collapse-debuginfo-invalid.rs:28:5 | LL | #[collapse_debuginfo(yes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | let _ = 3; - | ---------- not a macro definition + | + = help: `#[collapse_debuginfo]` can only be applied to macro defs -error: `collapse_debuginfo` attribute should be applied to macro definitions +error: `#[collapse_debuginfo]` attribute cannot be used on expressions --> $DIR/collapse-debuginfo-invalid.rs:31:13 | LL | let _ = #[collapse_debuginfo(yes)] 3; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - not a macro definition + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[collapse_debuginfo]` can only be applied to macro defs -error: `collapse_debuginfo` attribute should be applied to macro definitions +error: `#[collapse_debuginfo]` attribute cannot be used on match arms --> $DIR/collapse-debuginfo-invalid.rs:34:9 | LL | #[collapse_debuginfo(yes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | _ => (), - | ------- not a macro definition + | + = help: `#[collapse_debuginfo]` can only be applied to macro defs -error: `collapse_debuginfo` attribute should be applied to macro definitions +error: `#[collapse_debuginfo]` attribute cannot be used on modules --> $DIR/collapse-debuginfo-invalid.rs:40:1 | -LL | #[collapse_debuginfo(yes)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | / mod bar { -LL | | } - | |_- not a macro definition +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[collapse_debuginfo]` can only be applied to macro defs -error: `collapse_debuginfo` attribute should be applied to macro definitions +error: `#[collapse_debuginfo]` attribute cannot be used on type aliases --> $DIR/collapse-debuginfo-invalid.rs:45:1 | LL | #[collapse_debuginfo(yes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | type Map = HashMap; - | ----------------------------- not a macro definition + | + = help: `#[collapse_debuginfo]` can only be applied to macro defs -error: `collapse_debuginfo` attribute should be applied to macro definitions +error: `#[collapse_debuginfo]` attribute cannot be used on enums --> $DIR/collapse-debuginfo-invalid.rs:49:1 | -LL | #[collapse_debuginfo(yes)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | / enum Foo { -LL | | #[collapse_debuginfo(yes)] -LL | | -LL | | Variant, -LL | | } - | |_- not a macro definition +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[collapse_debuginfo]` can only be applied to macro defs -error: `collapse_debuginfo` attribute should be applied to macro definitions +error: `#[collapse_debuginfo]` attribute cannot be used on enum variants --> $DIR/collapse-debuginfo-invalid.rs:52:5 | LL | #[collapse_debuginfo(yes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | Variant, - | ------- not a macro definition + | + = help: `#[collapse_debuginfo]` can only be applied to macro defs -error: `collapse_debuginfo` attribute should be applied to macro definitions +error: `#[collapse_debuginfo]` attribute cannot be used on structs --> $DIR/collapse-debuginfo-invalid.rs:57:1 | -LL | #[collapse_debuginfo(yes)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | / struct Bar { -LL | | #[collapse_debuginfo(yes)] -LL | | -LL | | field: u32, -LL | | } - | |_- not a macro definition +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[collapse_debuginfo]` can only be applied to macro defs -error: `collapse_debuginfo` attribute should be applied to macro definitions +error: `#[collapse_debuginfo]` attribute cannot be used on struct fields --> $DIR/collapse-debuginfo-invalid.rs:60:5 | LL | #[collapse_debuginfo(yes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | field: u32, - | ---------- not a macro definition + | + = help: `#[collapse_debuginfo]` can only be applied to macro defs -error: `collapse_debuginfo` attribute should be applied to macro definitions +error: `#[collapse_debuginfo]` attribute cannot be used on unions --> $DIR/collapse-debuginfo-invalid.rs:65:1 | -LL | #[collapse_debuginfo(yes)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | / union Qux { -LL | | a: u32, -LL | | b: u16 -LL | | } - | |_- not a macro definition - -error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:72:1 - | -LL | #[collapse_debuginfo(yes)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | / trait Foobar { -LL | | #[collapse_debuginfo(yes)] -LL | | -LL | | type Bar; -LL | | } - | |_- not a macro definition - -error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:80:1 - | LL | #[collapse_debuginfo(yes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | type AFoobar = impl Foobar; - | --------------------------- not a macro definition - -error: `collapse_debuginfo` attribute should be applied to macro definitions - --> $DIR/collapse-debuginfo-invalid.rs:93:1 | -LL | #[collapse_debuginfo(yes)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | / impl Bar { -LL | | #[collapse_debuginfo(yes)] -LL | | -LL | | const FOO: u32 = 3; -... | -LL | | fn bar(&self) {} -LL | | } - | |_- not a macro definition + = help: `#[collapse_debuginfo]` can only be applied to macro defs -error: `collapse_debuginfo` attribute should be applied to macro definitions +error: `#[collapse_debuginfo]` attribute cannot be used on traits + --> $DIR/collapse-debuginfo-invalid.rs:72:1 + | +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[collapse_debuginfo]` can only be applied to macro defs + +error: `#[collapse_debuginfo]` attribute cannot be used on associated types --> $DIR/collapse-debuginfo-invalid.rs:75:5 | LL | #[collapse_debuginfo(yes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | type Bar; - | --------- not a macro definition + | + = help: `#[collapse_debuginfo]` can only be applied to macro defs -error: `collapse_debuginfo` attribute should be applied to macro definitions +error: `#[collapse_debuginfo]` attribute cannot be used on type aliases + --> $DIR/collapse-debuginfo-invalid.rs:80:1 + | +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[collapse_debuginfo]` can only be applied to macro defs + +error: `#[collapse_debuginfo]` attribute cannot be used on inherent impl blocks + --> $DIR/collapse-debuginfo-invalid.rs:93:1 + | +LL | #[collapse_debuginfo(yes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[collapse_debuginfo]` can only be applied to macro defs + +error: `#[collapse_debuginfo]` attribute cannot be used on associated consts --> $DIR/collapse-debuginfo-invalid.rs:96:5 | LL | #[collapse_debuginfo(yes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | const FOO: u32 = 3; - | ------------------- not a macro definition + | + = help: `#[collapse_debuginfo]` can only be applied to macro defs -error: `collapse_debuginfo` attribute should be applied to macro definitions +error: `#[collapse_debuginfo]` attribute cannot be used on inherent methods --> $DIR/collapse-debuginfo-invalid.rs:100:5 | LL | #[collapse_debuginfo(yes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | fn bar(&self) {} - | ---------------- not a macro definition + | + = help: `#[collapse_debuginfo]` can only be applied to macro defs error: aborting due to 22 previous errors From cf580b8e2b23fd0c51935664678227d2ba10127f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sun, 11 Jan 2026 10:38:58 +0100 Subject: [PATCH 0553/1061] Revert bors email to the original homu one --- src/build_helper/src/git.rs | 19 ++++++++++--------- src/stage0 | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/build_helper/src/git.rs b/src/build_helper/src/git.rs index 1fdc2ddb4cfc..330fb465de42 100644 --- a/src/build_helper/src/git.rs +++ b/src/build_helper/src/git.rs @@ -152,7 +152,10 @@ pub fn has_changed_since(git_dir: &Path, base: &str, paths: &[&str]) -> bool { }) } -const LEGACY_BORS_EMAIL: &str = "bors@rust-lang.org"; +// Temporary e-mail used by new bors for merge commits for a few days, until it learned how to reuse +// the original homu e-mail +// FIXME: remove in Q2 2026 +const TEMPORARY_BORS_EMAIL: &str = "122020455+rust-bors[bot]@users.noreply.github.com"; /// Escape characters from the git user e-mail, so that git commands do not interpret it as regex /// special characters. @@ -193,10 +196,9 @@ fn get_latest_upstream_commit_that_modified_files( &escape_email_git_regex(git_config.git_merge_commit_email), ]); - // Also search for legacy bors account, before we accrue enough commits to - // have changes to all relevant file paths done by new bors. - if git_config.git_merge_commit_email != LEGACY_BORS_EMAIL { - git.args(["--author", LEGACY_BORS_EMAIL]); + // Also search for temporary bors account + if git_config.git_merge_commit_email != TEMPORARY_BORS_EMAIL { + git.args(["--author", &escape_email_git_regex(TEMPORARY_BORS_EMAIL)]); } if !target_paths.is_empty() { @@ -248,10 +250,9 @@ pub fn get_closest_upstream_commit( base, ]); - // Also search for legacy bors account, before we accrue enough commits to - // have changes to all relevant file paths done by new bors. - if config.git_merge_commit_email != LEGACY_BORS_EMAIL { - git.args(["--author", LEGACY_BORS_EMAIL]); + // Also search for temporary bors account + if config.git_merge_commit_email != TEMPORARY_BORS_EMAIL { + git.args(["--author", &escape_email_git_regex(TEMPORARY_BORS_EMAIL)]); } let output = output_result(&mut git)?.trim().to_owned(); diff --git a/src/stage0 b/src/stage0 index 226f1d6f645e..66b652a844f3 100644 --- a/src/stage0 +++ b/src/stage0 @@ -1,7 +1,7 @@ dist_server=https://static.rust-lang.org artifacts_server=https://ci-artifacts.rust-lang.org/rustc-builds artifacts_with_llvm_assertions_server=https://ci-artifacts.rust-lang.org/rustc-builds-alt -git_merge_commit_email=122020455+rust-bors[bot]@users.noreply.github.com +git_merge_commit_email=bors@rust-lang.org nightly_branch=main # The configuration above this comment is editable, and can be changed From ad713ab666f97dcc4585aaad0344493926f9c4ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sun, 11 Jan 2026 10:40:40 +0100 Subject: [PATCH 0554/1061] Use both bors e-mails for CI postprocessing git lookup --- .github/workflows/ci.yml | 2 +- .github/workflows/post-merge.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8963039dd50b..2458eb5fafb1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -289,7 +289,7 @@ jobs: fi # Get closest bors merge commit - PARENT_COMMIT=`git rev-list --author='122020455+rust-bors\[bot\]@users.noreply.github.com' -n1 --first-parent HEAD^1` + PARENT_COMMIT=`git rev-list --author='bors@rust-lang.org' --author='122020455+rust-bors\[bot\]@users.noreply.github.com' -n1 --first-parent HEAD^1` ./build/citool/debug/citool postprocess-metrics \ --job-name ${CI_JOB_NAME} \ diff --git a/.github/workflows/post-merge.yml b/.github/workflows/post-merge.yml index 51e0a40d46f2..c3d9217a645b 100644 --- a/.github/workflows/post-merge.yml +++ b/.github/workflows/post-merge.yml @@ -29,7 +29,7 @@ jobs: sleep 60 # Get closest bors merge commit - PARENT_COMMIT=`git rev-list --author='122020455+rust-bors\[bot\]@users.noreply.github.com' -n1 --first-parent HEAD^1` + PARENT_COMMIT=`git rev-list --author='bors@rust-lang.org' --author='122020455+rust-bors\[bot\]@users.noreply.github.com' -n1 --first-parent HEAD^1` echo "Parent: ${PARENT_COMMIT}" # Find PR for the current commit From d772c3d99d41d1f44a23ab5256e2fbf62b589b03 Mon Sep 17 00:00:00 2001 From: Tristan Guichaoua Date: Sun, 11 Jan 2026 12:05:49 +0100 Subject: [PATCH 0555/1061] add freeze file times on Windows --- library/std/src/os/windows/fs.rs | 22 ++++++++++++++++++++++ library/std/src/sys/fs/windows.rs | 22 ++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs index b445f368aeb1..95a4ea53ce1e 100644 --- a/library/std/src/os/windows/fs.rs +++ b/library/std/src/os/windows/fs.rs @@ -305,6 +305,18 @@ pub trait OpenOptionsExt { /// https://docs.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-security_impersonation_level #[stable(feature = "open_options_ext", since = "1.10.0")] fn security_qos_flags(&mut self, flags: u32) -> &mut Self; + + /// If set to `true`, prevent the "last access time" of the file from being changed. + /// + /// Default to `false`. + #[unstable(feature = "windows_freeze_file_times", issue = "149715")] + fn freeze_last_access_time(&mut self, freeze: bool) -> &mut Self; + + /// If set to `true`, prevent the "last write time" of the file from being changed. + /// + /// Default to `false`. + #[unstable(feature = "windows_freeze_file_times", issue = "149715")] + fn freeze_last_write_time(&mut self, freeze: bool) -> &mut Self; } #[stable(feature = "open_options_ext", since = "1.10.0")] @@ -333,6 +345,16 @@ impl OpenOptionsExt for OpenOptions { self.as_inner_mut().security_qos_flags(flags); self } + + fn freeze_last_access_time(&mut self, freeze: bool) -> &mut Self { + self.as_inner_mut().freeze_last_access_time(freeze); + self + } + + fn freeze_last_write_time(&mut self, freeze: bool) -> &mut Self { + self.as_inner_mut().freeze_last_write_time(freeze); + self + } } /// Windows-specific extensions to [`fs::Metadata`]. diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index f2d325da35c7..e214284a03a7 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -81,6 +81,8 @@ pub struct OpenOptions { share_mode: u32, security_qos_flags: u32, inherit_handle: bool, + freeze_last_access_time: bool, + freeze_last_write_time: bool, } #[derive(Clone, PartialEq, Eq, Debug)] @@ -204,6 +206,8 @@ impl OpenOptions { attributes: 0, security_qos_flags: 0, inherit_handle: false, + freeze_last_access_time: false, + freeze_last_write_time: false, } } @@ -246,6 +250,12 @@ impl OpenOptions { pub fn inherit_handle(&mut self, inherit: bool) { self.inherit_handle = inherit; } + pub fn freeze_last_access_time(&mut self, freeze: bool) { + self.freeze_last_access_time = freeze; + } + pub fn freeze_last_write_time(&mut self, freeze: bool) { + self.freeze_last_write_time = freeze; + } fn get_access_mode(&self) -> io::Result { match (self.read, self.write, self.append, self.access_mode) { @@ -343,6 +353,18 @@ impl File { }; let handle = unsafe { HandleOrInvalid::from_raw_handle(handle) }; if let Ok(handle) = OwnedHandle::try_from(handle) { + if opts.freeze_last_access_time || opts.freeze_last_write_time { + let file_time = + c::FILETIME { dwLowDateTime: 0xFFFFFFFF, dwHighDateTime: 0xFFFFFFFF }; + cvt(unsafe { + c::SetFileTime( + handle.as_raw_handle(), + core::ptr::null(), + if opts.freeze_last_access_time { &file_time } else { core::ptr::null() }, + if opts.freeze_last_write_time { &file_time } else { core::ptr::null() }, + ) + })?; + } // Manual truncation. See #115745. if opts.truncate && creation == c::OPEN_ALWAYS From 6153fa0f88befd0f1c925a582b630b7412964aba Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 11 Jan 2026 12:12:41 +0100 Subject: [PATCH 0556/1061] Fix that `cfg` attribute was incorrectly not a parsed attribute --- compiler/rustc_attr_parsing/src/interface.rs | 12 +++++++++++- compiler/rustc_passes/src/check_attr.rs | 2 -- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index e38fffa6587c..7602e3c4598a 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -442,7 +442,17 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { /// Returns whether there is a parser for an attribute with this name pub fn is_parsed_attribute(path: &[Symbol]) -> bool { - Late::parsers().accepters.contains_key(path) || EARLY_PARSED_ATTRIBUTES.contains(&path) + /// The list of attributes that are parsed attributes, + /// even though they don't have a parser in `Late::parsers()` + const SPECIAL_ATTRIBUTES: &[&[Symbol]] = &[ + // Cfg attrs are removed after being early-parsed, so don't need to be in the parser list + &[sym::cfg], + &[sym::cfg_attr], + ]; + + Late::parsers().accepters.contains_key(path) + || EARLY_PARSED_ATTRIBUTES.contains(&path) + || SPECIAL_ATTRIBUTES.contains(&path) } fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs { diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 2d3c5c7e48a0..75a30497b228 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -338,8 +338,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::warn | sym::deny | sym::forbid - | sym::cfg - | sym::cfg_attr // need to be fixed | sym::patchable_function_entry // FIXME(patchable_function_entry) | sym::deprecated_safe // FIXME(deprecated_safe) From eac7bda659dd0e9a6e4c3bacdeb2df026050fbea Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 11 Jan 2026 12:56:00 +0100 Subject: [PATCH 0557/1061] Completely list all unparsed attributes --- compiler/rustc_passes/src/check_attr.rs | 62 +++++++++++++++++++++---- 1 file changed, 52 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 75a30497b228..2ef6fdf1568b 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -346,7 +346,54 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::panic_handler | sym::lang | sym::needs_allocator - | sym::default_lib_allocator, + | sym::default_lib_allocator + | sym::rustc_diagnostic_item + | sym::rustc_no_mir_inline + | sym::rustc_insignificant_dtor + | sym::rustc_nonnull_optimization_guaranteed + | sym::rustc_intrinsic + | sym::rustc_inherit_overflow_checks + | sym::rustc_intrinsic_const_stable_indirect + | sym::rustc_trivial_field_reads + | sym::rustc_on_unimplemented + | sym::rustc_do_not_const_check + | sym::rustc_reservation_impl + | sym::rustc_doc_primitive + | sym::rustc_allocator + | sym::rustc_deallocator + | sym::rustc_reallocator + | sym::rustc_conversion_suggestion + | sym::rustc_allocator_zeroed + | sym::rustc_allocator_zeroed_variant + | sym::rustc_deprecated_safe_2024 + | sym::rustc_test_marker + | sym::rustc_abi + | sym::rustc_layout + | sym::rustc_proc_macro_decls + | sym::rustc_dump_def_parents + | sym::rustc_never_type_options + | sym::rustc_autodiff + | sym::rustc_capture_analysis + | sym::rustc_regions + | sym::rustc_strict_coherence + | sym::rustc_dump_predicates + | sym::rustc_variance + | sym::rustc_variance_of_opaques + | sym::rustc_hidden_type_of_opaques + | sym::rustc_mir + | sym::rustc_dump_user_args + | sym::rustc_effective_visibility + | sym::rustc_outlives + | sym::rustc_symbol_name + | sym::rustc_evaluate_where_clauses + | sym::rustc_dump_vtable + | sym::rustc_delayed_bug_from_inside_query + | sym::rustc_dump_item_bounds + | sym::rustc_def_path + | sym::rustc_partition_reused + | sym::rustc_partition_codegened + | sym::rustc_expected_cgu_reuse + | sym::rustc_nounwind, .. ] => {} [name, rest@..] => { @@ -361,15 +408,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> { continue } - // FIXME: differentiate between unstable and internal attributes just - // like we do with features instead of just accepting `rustc_` - // attributes by name. That should allow trimming the above list, too. - if !name.as_str().starts_with("rustc_") { - span_bug!( - attr.span(), - "builtin attribute {name:?} not handled by `CheckAttrVisitor`" - ) - } + span_bug!( + attr.span(), + "builtin attribute {name:?} not handled by `CheckAttrVisitor`" + ) } None => (), } From d993bd1bb133f3d129aba5ae027acefd92f26acb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 8 Jan 2026 19:16:57 +0100 Subject: [PATCH 0558/1061] improve eii macro by using ecx methods --- compiler/rustc_builtin_macros/src/eii.rs | 214 +++++++++-------------- 1 file changed, 78 insertions(+), 136 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index 0ebd3dc826d4..a5009b3bfa52 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -108,7 +108,7 @@ fn eii_( let mut return_items = Vec::new(); if func.body.is_some() { - return_items.push(Box::new(generate_default_impl( + return_items.push(generate_default_impl( ecx, &func, impl_unsafe, @@ -116,25 +116,25 @@ fn eii_( eii_attr_span, item_span, foreign_item_name, - ))) + )) } - return_items.push(Box::new(generate_foreign_item( + return_items.push(generate_foreign_item( ecx, eii_attr_span, item_span, func, vis, &attrs_from_decl, - ))); - return_items.push(Box::new(generate_attribute_macro_to_implement( + )); + return_items.push(generate_attribute_macro_to_implement( ecx, eii_attr_span, macro_name, foreign_item_name, impl_unsafe, &attrs_from_decl, - ))); + )); return_items.into_iter().map(wrap_item).collect() } @@ -194,7 +194,7 @@ fn generate_default_impl( eii_attr_span: Span, item_span: Span, foreign_item_name: Ident, -) -> ast::Item { +) -> Box { // FIXME: re-add some original attrs let attrs = ThinVec::new(); @@ -211,124 +211,72 @@ fn generate_default_impl( span: eii_attr_span, is_default: true, known_eii_macro_resolution: Some(ast::EiiExternTarget { - extern_item_path: ast::Path { - span: foreign_item_name.span, - segments: thin_vec![ - ast::PathSegment { - ident: Ident::from_str_and_span("super", foreign_item_name.span,), - id: DUMMY_NODE_ID, - args: None - }, - ast::PathSegment { ident: foreign_item_name, id: DUMMY_NODE_ID, args: None }, - ], - tokens: None, - }, + extern_item_path: ecx.path( + foreign_item_name.span, + // prefix super to escape the `dflt` module generated below + vec![Ident::from_str_and_span("super", foreign_item_name.span), foreign_item_name], + ), impl_unsafe, }), }); - ast::Item { - attrs: ThinVec::new(), - id: ast::DUMMY_NODE_ID, - span: eii_attr_span, - vis: ast::Visibility { - span: eii_attr_span, - kind: ast::VisibilityKind::Inherited, - tokens: None, - }, - kind: ast::ItemKind::Const(Box::new(ast::ConstItem { - ident: Ident { name: kw::Underscore, span: eii_attr_span }, - defaultness: ast::Defaultness::Final, - generics: ast::Generics::default(), - ty: Box::new(ast::Ty { - id: DUMMY_NODE_ID, - kind: ast::TyKind::Tup(ThinVec::new()), - span: eii_attr_span, - tokens: None, - }), - rhs: Some(ast::ConstItemRhs::Body(Box::new(ast::Expr { - id: DUMMY_NODE_ID, - kind: ast::ExprKind::Block( - Box::new(ast::Block { - stmts: thin_vec![ast::Stmt { - id: DUMMY_NODE_ID, - kind: ast::StmtKind::Item(Box::new(ast::Item { - attrs: ThinVec::new(), - id: DUMMY_NODE_ID, - span: item_span, - vis: ast::Visibility { - span: item_span, - kind: ast::VisibilityKind::Inherited, - tokens: None - }, - kind: ItemKind::Mod( - ast::Safety::Default, - Ident::from_str_and_span("dflt", item_span), - ast::ModKind::Loaded( - thin_vec![ - Box::new(ast::Item { - attrs: thin_vec![ecx.attr_nested_word( - sym::allow, - sym::unused_imports, - item_span - ),], - id: DUMMY_NODE_ID, - span: item_span, - vis: ast::Visibility { - span: eii_attr_span, - kind: ast::VisibilityKind::Inherited, - tokens: None - }, - kind: ItemKind::Use(ast::UseTree { - prefix: ast::Path::from_ident( - Ident::from_str_and_span( - "super", item_span, - ) - ), - kind: ast::UseTreeKind::Glob, - span: item_span, - }), - tokens: None, - }), - Box::new(ast::Item { - attrs, - id: DUMMY_NODE_ID, - span: item_span, - vis: ast::Visibility { - span: eii_attr_span, - kind: ast::VisibilityKind::Inherited, - tokens: None - }, - kind: ItemKind::Fn(Box::new(default_func)), - tokens: None, - }), - ], - ast::Inline::Yes, - ast::ModSpans { - inner_span: item_span, - inject_use_span: item_span, - } - ) - ), - tokens: None, - })), - span: eii_attr_span, - }], - id: DUMMY_NODE_ID, - rules: ast::BlockCheckMode::Default, - span: eii_attr_span, - tokens: None, - }), - None, + let item_mod = |span: Span, name: Ident, items: ThinVec>| { + ecx.item( + item_span, + ThinVec::new(), + ItemKind::Mod( + ast::Safety::Default, + name, + ast::ModKind::Loaded( + items, + ast::Inline::Yes, + ast::ModSpans { inner_span: span, inject_use_span: span }, ), - span: eii_attr_span, - attrs: ThinVec::new(), - tokens: None, - }))), - define_opaque: None, - })), - tokens: None, - } + ), + ) + }; + + let anon_mod = |span: Span, stmts: ThinVec| { + let unit = ecx.ty(item_span, ast::TyKind::Tup(ThinVec::new())); + let underscore = Ident::new(kw::Underscore, item_span); + ecx.item_const( + span, + underscore, + unit, + ast::ConstItemRhs::Body(ecx.expr_block(ecx.block(span, stmts))), + ) + }; + + // const _: () = { + // mod dflt { + // use super::*; + // + // } + // } + anon_mod( + item_span, + thin_vec![ecx.stmt_item( + item_span, + item_mod( + item_span, + Ident::from_str_and_span("dflt", item_span), + thin_vec![ + ecx.item( + item_span, + thin_vec![ecx.attr_nested_word(sym::allow, sym::unused_imports, item_span)], + ItemKind::Use(ast::UseTree { + prefix: ast::Path::from_ident(Ident::from_str_and_span( + "super", item_span, + )), + kind: ast::UseTreeKind::Glob, + span: item_span, + }) + ), + ecx.item(item_span, attrs, ItemKind::Fn(Box::new(default_func))) + ] + ) + ),], + ) } /// Generates a foreign item, like @@ -343,7 +291,7 @@ fn generate_foreign_item( mut func: ast::Fn, vis: Visibility, attrs_from_decl: &[Attribute], -) -> ast::Item { +) -> Box { let mut foreign_item_attrs = ThinVec::new(); foreign_item_attrs.extend_from_slice(attrs_from_decl); @@ -375,16 +323,10 @@ fn generate_foreign_item( func.sig.header.safety = ast::Safety::Safe(func.sig.span); } - ast::Item { - attrs: ast::AttrVec::default(), - id: ast::DUMMY_NODE_ID, - span: eii_attr_span, - vis: ast::Visibility { - span: eii_attr_span, - kind: ast::VisibilityKind::Inherited, - tokens: None, - }, - kind: ast::ItemKind::ForeignMod(ast::ForeignMod { + ecx.item( + eii_attr_span, + ThinVec::new(), + ast::ItemKind::ForeignMod(ast::ForeignMod { extern_span: eii_attr_span, safety: ast::Safety::Unsafe(eii_attr_span), abi, @@ -397,8 +339,7 @@ fn generate_foreign_item( tokens: None, })]), }), - tokens: None, - } + ) } /// Generate a stub macro (a bit like in core) that will roughly look like: @@ -418,7 +359,7 @@ fn generate_attribute_macro_to_implement( foreign_item_name: Ident, impl_unsafe: bool, attrs_from_decl: &[Attribute], -) -> ast::Item { +) -> Box { let mut macro_attrs = ThinVec::new(); // To avoid e.g. `error: attribute macro has missing stability attribute` @@ -428,7 +369,8 @@ fn generate_attribute_macro_to_implement( // #[builtin_macro(eii_shared_macro)] macro_attrs.push(ecx.attr_nested_word(sym::rustc_builtin_macro, sym::eii_shared_macro, span)); - ast::Item { + // cant use ecx methods here to construct item since we need it to be public + Box::new(ast::Item { attrs: macro_attrs, id: ast::DUMMY_NODE_ID, span, @@ -467,7 +409,7 @@ fn generate_attribute_macro_to_implement( }, ), tokens: None, - } + }) } pub(crate) fn eii_extern_target( From e21256031782bdb355f3ff2e4ed126360b9cc7ab Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Sun, 9 Nov 2025 23:17:09 +0300 Subject: [PATCH 0559/1061] Stabilize `alloc_layout_extra` --- ...sroot_tests-128bit-atomic-operations.patch | 3 +- library/alloc/src/alloc.rs | 6 +- library/alloc/src/boxed.rs | 2 +- library/alloc/src/boxed/thin.rs | 4 +- library/alloc/src/lib.rs | 1 - library/alloc/src/rc.rs | 8 +-- library/alloc/src/sync.rs | 8 +-- library/alloctests/lib.rs | 1 - library/alloctests/tests/boxed.rs | 2 +- library/alloctests/tests/lib.rs | 1 - library/core/src/alloc/layout.rs | 65 +++++++++++-------- library/coretests/tests/alloc.rs | 2 +- library/coretests/tests/lib.rs | 1 - library/std/src/alloc.rs | 4 +- library/std/src/lib.rs | 1 - 15 files changed, 58 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/patches/0027-sysroot_tests-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-sysroot_tests-128bit-atomic-operations.patch index f3d1d5c43ea1..6ed0b17f679c 100644 --- a/compiler/rustc_codegen_cranelift/patches/0027-sysroot_tests-128bit-atomic-operations.patch +++ b/compiler/rustc_codegen_cranelift/patches/0027-sysroot_tests-128bit-atomic-operations.patch @@ -14,11 +14,10 @@ diff --git a/coretests/tests/lib.rs b/coretests/tests/lib.rs index 1e336bf..35e6f54 100644 --- a/coretests/tests/lib.rs +++ b/coretests/tests/lib.rs -@@ -2,5 +2,4 @@ +@@ -2,4 +2,3 @@ // tidy-alphabetical-start -#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] #![cfg_attr(test, feature(cfg_select))] - #![feature(alloc_layout_extra)] #![feature(array_ptr_get)] diff --git a/coretests/tests/atomic.rs b/coretests/tests/atomic.rs index b735957..ea728b6 100644 diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 5dd828bd54e1..cd1c2ea8fcd1 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -184,7 +184,7 @@ impl Global { #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces fn alloc_impl_runtime(layout: Layout, zeroed: bool) -> Result, AllocError> { match layout.size() { - 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)), + 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling_ptr(), 0)), // SAFETY: `layout` is non-zero in size, size => unsafe { let raw_ptr = if zeroed { alloc_zeroed(layout) } else { alloc(layout) }; @@ -277,7 +277,7 @@ impl Global { // SAFETY: conditions must be upheld by the caller 0 => unsafe { self.deallocate(ptr, old_layout); - Ok(NonNull::slice_from_raw_parts(new_layout.dangling(), 0)) + Ok(NonNull::slice_from_raw_parts(new_layout.dangling_ptr(), 0)) }, // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller @@ -368,7 +368,7 @@ impl Global { #[rustc_const_unstable(feature = "const_heap", issue = "79597")] const fn alloc_impl_const(layout: Layout, zeroed: bool) -> Result, AllocError> { match layout.size() { - 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)), + 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling_ptr(), 0)), // SAFETY: `layout` is non-zero in size, size => unsafe { let raw_ptr = core::intrinsics::const_allocate(layout.size(), layout.align()); diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 60758551cc04..eb741c9211f2 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -834,7 +834,7 @@ impl Box { } let layout = Layout::for_value::(src); let (ptr, guard) = if layout.size() == 0 { - (layout.dangling(), None) + (layout.dangling_ptr(), None) } else { // Safety: layout is non-zero-sized let ptr = alloc.allocate(layout)?.cast(); diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs index 1cce36606d2c..b50810b8d923 100644 --- a/library/alloc/src/boxed/thin.rs +++ b/library/alloc/src/boxed/thin.rs @@ -245,7 +245,7 @@ impl WithHeader { // Some paranoia checking, mostly so that the ThinBox tests are // more able to catch issues. debug_assert!(value_offset == 0 && T::IS_ZST && H::IS_ZST); - layout.dangling() + layout.dangling_ptr() } else { let ptr = alloc::alloc(layout); if ptr.is_null() { @@ -282,7 +282,7 @@ impl WithHeader { // Some paranoia checking, mostly so that the ThinBox tests are // more able to catch issues. debug_assert!(value_offset == 0 && size_of::() == 0 && size_of::() == 0); - layout.dangling() + layout.dangling_ptr() } else { let ptr = alloc::alloc(layout); if ptr.is_null() { diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 3ca9f3ae0bc9..f7167650635d 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -86,7 +86,6 @@ // Library features: // tidy-alphabetical-start #![cfg_attr(not(no_global_oom_handling), feature(string_replace_in_place))] -#![feature(alloc_layout_extra)] #![feature(allocator_api)] #![feature(array_into_iter_constructors)] #![feature(ascii_char)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 8a72748668cc..f58ebd488d7c 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -261,7 +261,7 @@ use core::panic::{RefUnwindSafe, UnwindSafe}; #[cfg(not(no_global_oom_handling))] use core::pin::Pin; use core::pin::PinCoerceUnsized; -use core::ptr::{self, NonNull, drop_in_place}; +use core::ptr::{self, Alignment, NonNull, drop_in_place}; #[cfg(not(no_global_oom_handling))] use core::slice::from_raw_parts_mut; use core::{borrow, fmt, hint}; @@ -3847,11 +3847,11 @@ unsafe fn data_offset(ptr: *const T) -> usize { // and extern types, the input safety requirement is currently enough to // satisfy the requirements of align_of_val_raw; this is an implementation // detail of the language that must not be relied upon outside of std. - unsafe { data_offset_align(align_of_val_raw(ptr)) } + unsafe { data_offset_align(Alignment::new_unchecked(align_of_val_raw(ptr))) } } #[inline] -fn data_offset_align(align: usize) -> usize { +fn data_offset_align(align: Alignment) -> usize { let layout = Layout::new::>(); layout.size() + layout.padding_needed_for(align) } @@ -4478,7 +4478,7 @@ impl UniqueRcUninit { /// Returns the pointer to be written into to initialize the [`Rc`]. fn data_ptr(&mut self) -> *mut T { - let offset = data_offset_align(self.layout_for_value.align()); + let offset = data_offset_align(self.layout_for_value.alignment()); unsafe { self.ptr.as_ptr().byte_add(offset) as *mut T } } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 4180fe91cb55..fc44a468c8a4 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -26,7 +26,7 @@ use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, Lega use core::ops::{Residual, Try}; use core::panic::{RefUnwindSafe, UnwindSafe}; use core::pin::{Pin, PinCoerceUnsized}; -use core::ptr::{self, NonNull}; +use core::ptr::{self, Alignment, NonNull}; #[cfg(not(no_global_oom_handling))] use core::slice::from_raw_parts_mut; use core::sync::atomic::Ordering::{Acquire, Relaxed, Release}; @@ -4208,11 +4208,11 @@ unsafe fn data_offset(ptr: *const T) -> usize { // and extern types, the input safety requirement is currently enough to // satisfy the requirements of align_of_val_raw; this is an implementation // detail of the language that must not be relied upon outside of std. - unsafe { data_offset_align(align_of_val_raw(ptr)) } + unsafe { data_offset_align(Alignment::new_unchecked(align_of_val_raw(ptr))) } } #[inline] -fn data_offset_align(align: usize) -> usize { +fn data_offset_align(align: Alignment) -> usize { let layout = Layout::new::>(); layout.size() + layout.padding_needed_for(align) } @@ -4258,7 +4258,7 @@ impl UniqueArcUninit { /// Returns the pointer to be written into to initialize the [`Arc`]. fn data_ptr(&mut self) -> *mut T { - let offset = data_offset_align(self.layout_for_value.align()); + let offset = data_offset_align(self.layout_for_value.alignment()); unsafe { self.ptr.as_ptr().byte_add(offset) as *mut T } } diff --git a/library/alloctests/lib.rs b/library/alloctests/lib.rs index b85fc8eb9970..32a876cdc5f7 100644 --- a/library/alloctests/lib.rs +++ b/library/alloctests/lib.rs @@ -14,7 +14,6 @@ // // Library features: // tidy-alphabetical-start -#![feature(alloc_layout_extra)] #![feature(allocator_api)] #![feature(array_into_iter_constructors)] #![feature(assert_matches)] diff --git a/library/alloctests/tests/boxed.rs b/library/alloctests/tests/boxed.rs index 94389cf2de93..83fd1ef7449a 100644 --- a/library/alloctests/tests/boxed.rs +++ b/library/alloctests/tests/boxed.rs @@ -104,7 +104,7 @@ pub struct ConstAllocator; unsafe impl Allocator for ConstAllocator { fn allocate(&self, layout: Layout) -> Result, AllocError> { match layout.size() { - 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)), + 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling_ptr(), 0)), _ => unsafe { let ptr = core::intrinsics::const_allocate(layout.size(), layout.align()); Ok(NonNull::new_unchecked(ptr as *mut [u8; 0] as *mut [u8])) diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index c7fdc2054f71..2926248edbf5 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -1,5 +1,4 @@ #![feature(allocator_api)] -#![feature(alloc_layout_extra)] #![feature(const_heap)] #![feature(deque_extend_front)] #![feature(iter_array_chunks)] diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index a4e25b8734a9..3a2111350a4e 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -217,10 +217,11 @@ impl Layout { /// be that of a valid pointer, which means this must not be used /// as a "not yet initialized" sentinel value. /// Types that lazily allocate must track initialization by some other means. - #[unstable(feature = "alloc_layout_extra", issue = "55724")] + #[stable(feature = "alloc_layout_extra", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "alloc_layout_extra", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] - pub const fn dangling(&self) -> NonNull { + pub const fn dangling_ptr(&self) -> NonNull { NonNull::without_provenance(self.align.as_nonzero()) } @@ -250,29 +251,23 @@ impl Layout { } /// Returns the amount of padding we must insert after `self` - /// to ensure that the following address will satisfy `align` - /// (measured in bytes). + /// to ensure that the following address will satisfy `alignment`. /// - /// e.g., if `self.size()` is 9, then `self.padding_needed_for(4)` + /// e.g., if `self.size()` is 9, then `self.padding_needed_for(alignment4)` + /// (where `alignment4.as_usize() == 4`) /// returns 3, because that is the minimum number of bytes of /// padding required to get a 4-aligned address (assuming that the /// corresponding memory block starts at a 4-aligned address). /// - /// The return value of this function has no meaning if `align` is - /// not a power-of-two. - /// - /// Note that the utility of the returned value requires `align` + /// Note that the utility of the returned value requires `alignment` /// to be less than or equal to the alignment of the starting /// address for the whole allocated block of memory. One way to - /// satisfy this constraint is to ensure `align <= self.align()`. - #[unstable(feature = "alloc_layout_extra", issue = "55724")] - #[must_use = "this returns the padding needed, \ - without modifying the `Layout`"] + /// satisfy this constraint is to ensure `alignment.as_usize() <= self.align()`. + #[unstable(feature = "ptr_alignment_type", issue = "102070")] + #[must_use = "this returns the padding needed, without modifying the `Layout`"] #[inline] - pub const fn padding_needed_for(&self, align: usize) -> usize { - // FIXME: Can we just change the type on this to `Alignment`? - let Some(align) = Alignment::new(align) else { return usize::MAX }; - let len_rounded_up = self.size_rounded_up_to_custom_align(align); + pub const fn padding_needed_for(&self, alignment: Alignment) -> usize { + let len_rounded_up = self.size_rounded_up_to_custom_align(alignment); // SAFETY: Cannot overflow because the rounded-up value is never less unsafe { unchecked_sub(len_rounded_up, self.size) } } @@ -335,6 +330,8 @@ impl Layout { /// layout of the array and `offs` is the distance between the start /// of each element in the array. /// + /// Does not include padding after the trailing element. + /// /// (That distance between elements is sometimes known as "stride".) /// /// On arithmetic overflow, returns `LayoutError`. @@ -342,7 +339,6 @@ impl Layout { /// # Examples /// /// ``` - /// #![feature(alloc_layout_extra)] /// use std::alloc::Layout; /// /// // All rust types have a size that's a multiple of their alignment. @@ -353,17 +349,32 @@ impl Layout { /// // But you can manually make layouts which don't meet that rule. /// let padding_needed = Layout::from_size_align(6, 4).unwrap(); /// let repeated = padding_needed.repeat(3).unwrap(); - /// assert_eq!(repeated, (Layout::from_size_align(24, 4).unwrap(), 8)); + /// assert_eq!(repeated, (Layout::from_size_align(22, 4).unwrap(), 8)); + /// + /// // Repeating an element zero times has zero size, but keeps the alignment (like `[T; 0]`) + /// let repeated = normal.repeat(0).unwrap(); + /// assert_eq!(repeated, (Layout::from_size_align(0, 4).unwrap(), 12)); + /// let repeated = padding_needed.repeat(0).unwrap(); + /// assert_eq!(repeated, (Layout::from_size_align(0, 4).unwrap(), 8)); /// ``` - #[unstable(feature = "alloc_layout_extra", issue = "55724")] + #[stable(feature = "alloc_layout_extra", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "alloc_layout_extra", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutError> { + // FIXME(const-hack): the following could be way shorter with `?` let padded = self.pad_to_align(); - if let Ok(repeated) = padded.repeat_packed(n) { - Ok((repeated, padded.size())) + let Ok(result) = (if let Some(k) = n.checked_sub(1) { + let Ok(repeated) = padded.repeat_packed(k) else { + return Err(LayoutError); + }; + repeated.extend_packed(*self) } else { - Err(LayoutError) - } + debug_assert!(n == 0); + self.repeat_packed(0) + }) else { + return Err(LayoutError); + }; + Ok((result, padded.size())) } /// Creates a layout describing the record for `self` followed by @@ -443,7 +454,8 @@ impl Layout { /// aligned. /// /// On arithmetic overflow, returns `LayoutError`. - #[unstable(feature = "alloc_layout_extra", issue = "55724")] + #[stable(feature = "alloc_layout_extra", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "alloc_layout_extra", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn repeat_packed(&self, n: usize) -> Result { if let Some(size) = self.size.checked_mul(n) { @@ -460,7 +472,8 @@ impl Layout { /// and is not incorporated *at all* into the resulting layout. /// /// On arithmetic overflow, returns `LayoutError`. - #[unstable(feature = "alloc_layout_extra", issue = "55724")] + #[stable(feature = "alloc_layout_extra", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "alloc_layout_extra", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn extend_packed(&self, next: Self) -> Result { // SAFETY: each `size` is at most `isize::MAX == usize::MAX/2`, so the diff --git a/library/coretests/tests/alloc.rs b/library/coretests/tests/alloc.rs index a4af6fd32a11..aac1d60ce32c 100644 --- a/library/coretests/tests/alloc.rs +++ b/library/coretests/tests/alloc.rs @@ -6,7 +6,7 @@ fn const_unchecked_layout() { const SIZE: usize = 0x2000; const ALIGN: usize = 0x1000; const LAYOUT: Layout = unsafe { Layout::from_size_align_unchecked(SIZE, ALIGN) }; - const DANGLING: NonNull = LAYOUT.dangling(); + const DANGLING: NonNull = LAYOUT.dangling_ptr(); assert_eq!(LAYOUT.size(), SIZE); assert_eq!(LAYOUT.align(), ALIGN); assert_eq!(Some(DANGLING), NonNull::new(ptr::without_provenance_mut(ALIGN))); diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index b28e7338859c..4974f52cd9df 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -1,7 +1,6 @@ // tidy-alphabetical-start #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] #![cfg_attr(test, feature(cfg_select))] -#![feature(alloc_layout_extra)] #![feature(array_ptr_get)] #![feature(array_try_from_fn)] #![feature(array_try_map)] diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index f0d2b913bbbb..ed0322e2cf5d 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -142,7 +142,7 @@ impl System { #[inline] fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result, AllocError> { match layout.size() { - 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)), + 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling_ptr(), 0)), // SAFETY: `layout` is non-zero in size, size => unsafe { let raw_ptr = if zeroed { @@ -266,7 +266,7 @@ unsafe impl Allocator for System { // SAFETY: conditions must be upheld by the caller 0 => unsafe { Allocator::deallocate(self, ptr, old_layout); - Ok(NonNull::slice_from_raw_parts(new_layout.dangling(), 0)) + Ok(NonNull::slice_from_raw_parts(new_layout.dangling_ptr(), 0)) }, // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index f5b9f69a5f9f..4f48f23f44b8 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -367,7 +367,6 @@ // // Library features (alloc): // tidy-alphabetical-start -#![feature(alloc_layout_extra)] #![feature(allocator_api)] #![feature(clone_from_ref)] #![feature(get_mut_unchecked)] From ef1e4e65b7c76bd03fa82bbbc42393712af05f81 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 10 Jan 2026 15:54:09 +0100 Subject: [PATCH 0560/1061] Move checks from `check_doc_attrs` directly into `rustc_attr_parsing` --- compiler/rustc_attr_parsing/messages.ftl | 3 + .../rustc_attr_parsing/src/attributes/doc.rs | 119 ++++++++++++++---- compiler/rustc_attr_parsing/src/context.rs | 1 + compiler/rustc_attr_parsing/src/interface.rs | 3 + .../src/session_diagnostics.rs | 8 ++ compiler/rustc_lint/messages.ftl | 5 + compiler/rustc_lint/src/early/diagnostics.rs | 2 + compiler/rustc_lint/src/lints.rs | 5 + compiler/rustc_lint_defs/src/lib.rs | 1 + compiler/rustc_passes/messages.ftl | 8 -- compiler/rustc_passes/src/check_attr.rs | 87 ++++--------- compiler/rustc_passes/src/errors.rs | 13 -- .../lints/invalid-crate-level-lint.rs | 13 ++ .../lints/invalid-crate-level-lint.stderr | 27 ++++ tests/rustdoc-ui/lints/invalid-doc-attr.rs | 7 -- .../rustdoc-ui/lints/invalid-doc-attr.stderr | 38 ++---- tests/ui/rustdoc/doc-alias-crate-level.stderr | 12 +- tests/ui/rustdoc/doc_keyword.stderr | 12 +- 18 files changed, 204 insertions(+), 160 deletions(-) create mode 100644 tests/rustdoc-ui/lints/invalid-crate-level-lint.rs create mode 100644 tests/rustdoc-ui/lints/invalid-crate-level-lint.stderr diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 36213e68a52b..4b4358ab0a9c 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -23,6 +23,9 @@ attr_parsing_doc_alias_malformed = attr_parsing_doc_alias_start_end = {$attr_str} cannot start or end with ' ' +attr_parsing_doc_attr_not_crate_level = + `#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute + attr_parsing_doc_attribute_not_attribute = nonexistent builtin attribute `{$attribute}` used in `#[doc(attribute = "...")]` .help = only existing builtin attributes are allowed in core/std diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 16dbb04b48eb..6cc4ac35eadb 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -1,5 +1,6 @@ use rustc_ast::ast::{AttrStyle, LitKind, MetaItemLit}; use rustc_feature::template; +use rustc_hir::Target; use rustc_hir::attrs::{ AttributeKind, CfgEntry, CfgHideShow, CfgInfo, DocAttribute, DocInline, HideOrShow, }; @@ -12,8 +13,8 @@ use super::{AcceptMapping, AttributeParser}; use crate::context::{AcceptContext, FinalizeContext, Stage}; use crate::parser::{ArgParser, MetaItemOrLitParser, MetaItemParser, OwnedPathParser}; use crate::session_diagnostics::{ - DocAliasBadChar, DocAliasEmpty, DocAliasMalformed, DocAliasStartEnd, DocAttributeNotAttribute, - DocKeywordNotKeyword, + DocAliasBadChar, DocAliasEmpty, DocAliasMalformed, DocAliasStartEnd, DocAttrNotCrateLevel, + DocAttributeNotAttribute, DocKeywordNotKeyword, }; fn check_keyword(cx: &mut AcceptContext<'_, '_, S>, keyword: Symbol, span: Span) -> bool { @@ -43,16 +44,39 @@ fn check_attribute( false } -fn parse_keyword_and_attribute( +/// Checks that an attribute is *not* used at the crate level. Returns `true` if valid. +fn check_attr_not_crate_level( + cx: &mut AcceptContext<'_, '_, S>, + span: Span, + attr_name: Symbol, +) -> bool { + if cx.shared.target.is_some_and(|target| target == Target::Crate) { + cx.emit_err(DocAttrNotCrateLevel { span, attr_name }); + return false; + } + true +} + +/// Checks that an attribute is used at the crate level. Returns `true` if valid. +fn check_attr_crate_level(cx: &mut AcceptContext<'_, '_, S>, span: Span) -> bool { + if cx.shared.target.is_some_and(|target| target != Target::Crate) { + cx.emit_lint( + rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, + AttributeLintKind::AttrCrateLevelOnly, + span, + ); + return false; + } + true +} + +fn parse_keyword_and_attribute( cx: &mut AcceptContext<'_, '_, S>, path: &OwnedPathParser, args: &ArgParser, attr_value: &mut Option<(Symbol, Span)>, - callback: F, -) where - S: Stage, - F: FnOnce(&mut AcceptContext<'_, '_, S>, Symbol, Span) -> bool, -{ + attr_name: Symbol, +) { let Some(nv) = args.name_value() else { cx.expected_name_value(args.span().unwrap_or(path.span()), path.word_sym()); return; @@ -63,16 +87,26 @@ fn parse_keyword_and_attribute( return; }; - if !callback(cx, value, nv.value_span) { + let ret = if attr_name == sym::keyword { + check_keyword(cx, value, nv.value_span) + } else { + check_attribute(cx, value, nv.value_span) + }; + if !ret { return; } + let span = path.span(); if attr_value.is_some() { - cx.duplicate_key(path.span(), path.word_sym().unwrap()); + cx.duplicate_key(span, path.word_sym().unwrap()); return; } - *attr_value = Some((value, path.span())); + if !check_attr_not_crate_level(cx, span, attr_name) { + return; + } + + *attr_value = Some((value, span)); } #[derive(Default, Debug)] @@ -102,6 +136,10 @@ impl DocParser { return; } + if !check_attr_crate_level(cx, path.span()) { + return; + } + self.attribute.no_crate_inject = Some(path.span()) } Some(sym::attr) => { @@ -155,6 +193,9 @@ impl DocParser { cx.emit_err(DocAliasStartEnd { span, attr_str }); return; } + if !check_attr_not_crate_level(cx, span, sym::alias) { + return; + } if let Some(first_definition) = self.attribute.aliases.get(&alias).copied() { cx.emit_lint( @@ -366,7 +407,33 @@ impl DocParser { self.attribute.$ident = Some(path.span()); }}; } - macro_rules! string_arg { + macro_rules! no_args_and_not_crate_level { + ($ident: ident) => {{ + if let Err(span) = args.no_args() { + cx.expected_no_args(span); + return; + } + let span = path.span(); + if !check_attr_not_crate_level(cx, span, sym::$ident) { + return; + } + self.attribute.$ident = Some(span); + }}; + } + macro_rules! no_args_and_crate_level { + ($ident: ident) => {{ + if let Err(span) = args.no_args() { + cx.expected_no_args(span); + return; + } + let span = path.span(); + if !check_attr_crate_level(cx, span) { + return; + } + self.attribute.$ident = Some(span); + }}; + } + macro_rules! string_arg_and_crate_level { ($ident: ident) => {{ let Some(nv) = args.name_value() else { cx.expected_name_value(args.span().unwrap_or(path.span()), path.word_sym()); @@ -378,6 +445,10 @@ impl DocParser { return; }; + if !check_attr_crate_level(cx, path.span()) { + return; + } + // FIXME: It's errorring when the attribute is passed multiple times on the command // line. // The right fix for this would be to only check this rule if the attribute is @@ -394,12 +465,14 @@ impl DocParser { match path.word_sym() { Some(sym::alias) => self.parse_alias(cx, path, args), Some(sym::hidden) => no_args!(hidden), - Some(sym::html_favicon_url) => string_arg!(html_favicon_url), - Some(sym::html_logo_url) => string_arg!(html_logo_url), - Some(sym::html_no_source) => no_args!(html_no_source), - Some(sym::html_playground_url) => string_arg!(html_playground_url), - Some(sym::html_root_url) => string_arg!(html_root_url), - Some(sym::issue_tracker_base_url) => string_arg!(issue_tracker_base_url), + Some(sym::html_favicon_url) => string_arg_and_crate_level!(html_favicon_url), + Some(sym::html_logo_url) => string_arg_and_crate_level!(html_logo_url), + Some(sym::html_no_source) => no_args_and_crate_level!(html_no_source), + Some(sym::html_playground_url) => string_arg_and_crate_level!(html_playground_url), + Some(sym::html_root_url) => string_arg_and_crate_level!(html_root_url), + Some(sym::issue_tracker_base_url) => { + string_arg_and_crate_level!(issue_tracker_base_url) + } Some(sym::inline) => self.parse_inline(cx, path, args, DocInline::Inline), Some(sym::no_inline) => self.parse_inline(cx, path, args, DocInline::NoInline), Some(sym::masked) => no_args!(masked), @@ -410,18 +483,18 @@ impl DocParser { path, args, &mut self.attribute.keyword, - check_keyword, + sym::keyword, ), Some(sym::attribute) => parse_keyword_and_attribute( cx, path, args, &mut self.attribute.attribute, - check_attribute, + sym::attribute, ), - Some(sym::fake_variadic) => no_args!(fake_variadic), - Some(sym::search_unbox) => no_args!(search_unbox), - Some(sym::rust_logo) => no_args!(rust_logo), + Some(sym::fake_variadic) => no_args_and_not_crate_level!(fake_variadic), + Some(sym::search_unbox) => no_args_and_not_crate_level!(search_unbox), + Some(sym::rust_logo) => no_args_and_crate_level!(rust_logo), Some(sym::auto_cfg) => self.parse_auto_cfg(cx, path, args), Some(sym::test) => { let Some(list) = args.list() else { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 732bf111b256..2e7804e51d81 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -653,6 +653,7 @@ pub struct SharedContext<'p, 'sess, S: Stage> { pub(crate) target_span: Span, /// The id ([`NodeId`] if `S` is `Early`, [`HirId`] if `S` is `Late`) of the syntactical component this attribute was applied to pub(crate) target_id: S::Id, + pub(crate) target: Option, pub(crate) emit_lint: &'p mut dyn FnMut(AttributeLint), } diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index e38fffa6587c..d87fc3855954 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -218,6 +218,7 @@ impl<'sess> AttributeParser<'sess, Early> { cx: &mut parser, target_span, target_id: target_node_id, + target: None, emit_lint: &mut emit_lint, }, attr_span, @@ -378,6 +379,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { cx: self, target_span, target_id, + target: Some(target), emit_lint: &mut emit_lint, }, attr_span, @@ -429,6 +431,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { cx: self, target_span, target_id, + target: Some(target), emit_lint: &mut emit_lint, }, all_attrs: &attr_paths, diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 20d00a82cadb..85e7891b1e64 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -47,6 +47,14 @@ pub(crate) struct DocAliasStartEnd<'a> { pub attr_str: &'a str, } +#[derive(Diagnostic)] +#[diag(attr_parsing_doc_attr_not_crate_level)] +pub(crate) struct DocAttrNotCrateLevel { + #[primary_span] + pub span: Span, + pub attr_name: Symbol, +} + #[derive(Diagnostic)] #[diag(attr_parsing_doc_keyword_not_keyword)] #[help] diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index b49b090272d4..9b0b1abc91df 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -40,6 +40,11 @@ lint_atomic_ordering_load = atomic loads cannot have `Release` or `AcqRel` order lint_atomic_ordering_store = atomic stores cannot have `Acquire` or `AcqRel` ordering .help = consider using ordering modes `Release`, `SeqCst` or `Relaxed` +lint_attr_crate_level = + this attribute can only be applied at the crate level + .suggestion = to apply to the crate, use an inner attribute + .note = read for more information + lint_bad_attribute_argument = bad attribute argument lint_bad_opt_access = {$msg} diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index f622de7f84d9..5745f0d4edde 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -417,5 +417,7 @@ pub fn decorate_attribute_lint( } &AttributeLintKind::DocTestLiteral => lints::DocTestLiteral.decorate_lint(diag), + + &AttributeLintKind::AttrCrateLevelOnly => lints::AttrCrateLevelOnly.decorate_lint(diag), } } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 841b11c99687..33e9375ec71b 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3312,3 +3312,8 @@ pub(crate) struct DocTestUnknown { #[derive(LintDiagnostic)] #[diag(lint_doc_test_literal)] pub(crate) struct DocTestLiteral; + +#[derive(LintDiagnostic)] +#[diag(lint_attr_crate_level)] +#[note] +pub(crate) struct AttrCrateLevelOnly; diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 7b41cfbb43ef..c8713b23633f 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -820,6 +820,7 @@ pub enum AttributeLintKind { name: Symbol, }, DocTestLiteral, + AttrCrateLevelOnly, } pub type RegisteredTools = FxIndexSet; diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index ba44aa3a35ab..d8e5574efc91 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -29,11 +29,6 @@ passes_attr_application_struct_union = attribute should be applied to a struct or union .label = not a struct or union -passes_attr_crate_level = - this attribute can only be applied at the crate level - .suggestion = to apply to the crate, use an inner attribute - .note = read for more information - passes_autodiff_attr = `#[autodiff]` should be applied to a function .label = not a function @@ -112,9 +107,6 @@ passes_doc_alias_bad_location = passes_doc_alias_not_an_alias = `#[doc(alias = "{$attr_str}"]` is the same as the item's name -passes_doc_attr_not_crate_level = - `#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute - passes_doc_fake_variadic_not_valid = `#[doc(fake_variadic)]` must be used on the first of a set of tuple or fn pointer trait impls with varying arity diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 360feacac0e9..512322f9e933 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1034,29 +1034,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks that an attribute is *not* used at the crate level. Returns `true` if valid. - fn check_attr_not_crate_level(&self, span: Span, hir_id: HirId, attr_name: &str) -> bool { - if CRATE_HIR_ID == hir_id { - self.dcx().emit_err(errors::DocAttrNotCrateLevel { span, attr_name }); - return false; - } - true - } - - /// Checks that an attribute is used at the crate level. Returns `true` if valid. - fn check_attr_crate_level(&self, span: Span, hir_id: HirId) -> bool { - if hir_id != CRATE_HIR_ID { - self.tcx.emit_node_span_lint( - INVALID_DOC_ATTRIBUTES, - hir_id, - span, - errors::AttrCrateLevelOnly {}, - ); - return false; - } - true - } - /// Runs various checks on `#[doc]` attributes. /// /// `specified_inline` should be initialized to `None` and kept for the scope @@ -1072,9 +1049,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { inline, // FIXME: currently unchecked cfg: _, - // already check in attr_parsing + // already checked in attr_parsing auto_cfg: _, - // already check in attr_parsing + // already checked in attr_parsing auto_cfg_change: _, fake_variadic, keyword, @@ -1082,70 +1059,48 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // FIXME: currently unchecked notable_trait: _, search_unbox, - html_favicon_url, - html_logo_url, - html_playground_url, - html_root_url, - html_no_source, - issue_tracker_base_url, + // already checked in attr_parsing + html_favicon_url: _, + // already checked in attr_parsing + html_logo_url: _, + // already checked in attr_parsing + html_playground_url: _, + // already checked in attr_parsing + html_root_url: _, + // already checked in attr_parsing + html_no_source: _, + // already checked in attr_parsing + issue_tracker_base_url: _, rust_logo, // allowed anywhere test_attrs: _, - no_crate_inject, + // already checked in attr_parsing + no_crate_inject: _, attribute, } = attr; for (alias, span) in aliases { - if self.check_attr_not_crate_level(*span, hir_id, "alias") { - self.check_doc_alias_value(*span, hir_id, target, *alias); - } + self.check_doc_alias_value(*span, hir_id, target, *alias); } - if let Some((_, span)) = keyword - && self.check_attr_not_crate_level(*span, hir_id, "keyword") - { + if let Some((_, span)) = keyword { self.check_doc_keyword_and_attribute(*span, hir_id, "keyword"); } - if let Some((_, span)) = attribute - && self.check_attr_not_crate_level(*span, hir_id, "attribute") - { + if let Some((_, span)) = attribute { self.check_doc_keyword_and_attribute(*span, hir_id, "attribute"); } - if let Some(span) = fake_variadic - && self.check_attr_not_crate_level(*span, hir_id, "fake_variadic") - { + if let Some(span) = fake_variadic { self.check_doc_fake_variadic(*span, hir_id); } - if let Some(span) = search_unbox - && self.check_attr_not_crate_level(*span, hir_id, "search_unbox") - { + if let Some(span) = search_unbox { self.check_doc_search_unbox(*span, hir_id); } - for i in [ - html_favicon_url, - html_logo_url, - html_playground_url, - issue_tracker_base_url, - html_root_url, - ] { - if let Some((_, span)) = i { - self.check_attr_crate_level(*span, hir_id); - } - } - - for i in [html_no_source, no_crate_inject] { - if let Some(span) = i { - self.check_attr_crate_level(*span, hir_id); - } - } - self.check_doc_inline(hir_id, target, inline); if let Some(span) = rust_logo - && self.check_attr_crate_level(*span, hir_id) && !self.tcx.features().rustdoc_internals() { feature_err( diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 14555765e423..c1b5988cc7f6 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -179,14 +179,6 @@ pub(crate) struct DocMaskedNotExternCrateSelf { pub item_span: Span, } -#[derive(Diagnostic)] -#[diag(passes_doc_attr_not_crate_level)] -pub(crate) struct DocAttrNotCrateLevel<'a> { - #[primary_span] - pub span: Span, - pub attr_name: &'a str, -} - #[derive(Diagnostic)] #[diag(passes_both_ffi_const_and_pure, code = E0757)] pub(crate) struct BothFfiConstAndPure { @@ -1104,11 +1096,6 @@ pub(crate) struct UnnecessaryPartialStableFeature { #[note] pub(crate) struct IneffectiveUnstableImpl; -#[derive(LintDiagnostic)] -#[diag(passes_attr_crate_level)] -#[note] -pub(crate) struct AttrCrateLevelOnly {} - /// "sanitize attribute not allowed here" #[derive(Diagnostic)] #[diag(passes_sanitize_attribute_not_allowed)] diff --git a/tests/rustdoc-ui/lints/invalid-crate-level-lint.rs b/tests/rustdoc-ui/lints/invalid-crate-level-lint.rs new file mode 100644 index 000000000000..275e20e80a17 --- /dev/null +++ b/tests/rustdoc-ui/lints/invalid-crate-level-lint.rs @@ -0,0 +1,13 @@ +#![crate_type = "lib"] + +#[doc(test(no_crate_inject))] +//~^ ERROR can only be applied at the crate level + +pub mod bar { + #![doc(test(no_crate_inject))] + //~^ ERROR can only be applied at the crate level + + #[doc(test(no_crate_inject))] + //~^ ERROR can only be applied at the crate level + fn foo() {} +} diff --git a/tests/rustdoc-ui/lints/invalid-crate-level-lint.stderr b/tests/rustdoc-ui/lints/invalid-crate-level-lint.stderr new file mode 100644 index 000000000000..fdb95e7de41c --- /dev/null +++ b/tests/rustdoc-ui/lints/invalid-crate-level-lint.stderr @@ -0,0 +1,27 @@ +error: this attribute can only be applied at the crate level + --> $DIR/invalid-crate-level-lint.rs:3:12 + | +LL | #[doc(test(no_crate_inject))] + | ^^^^^^^^^^^^^^^ + | + = note: read for more information + = note: `#[deny(invalid_doc_attributes)]` on by default + +error: this attribute can only be applied at the crate level + --> $DIR/invalid-crate-level-lint.rs:7:17 + | +LL | #![doc(test(no_crate_inject))] + | ^^^^^^^^^^^^^^^ + | + = note: read for more information + +error: this attribute can only be applied at the crate level + --> $DIR/invalid-crate-level-lint.rs:10:16 + | +LL | #[doc(test(no_crate_inject))] + | ^^^^^^^^^^^^^^^ + | + = note: read for more information + +error: aborting due to 3 previous errors + diff --git a/tests/rustdoc-ui/lints/invalid-doc-attr.rs b/tests/rustdoc-ui/lints/invalid-doc-attr.rs index a8c42b8fd79c..169d092d7e17 100644 --- a/tests/rustdoc-ui/lints/invalid-doc-attr.rs +++ b/tests/rustdoc-ui/lints/invalid-doc-attr.rs @@ -4,18 +4,11 @@ #![doc(masked)] //~^ ERROR this attribute can only be applied to an `extern crate` item -#[doc(test(no_crate_inject))] -//~^ ERROR can only be applied at the crate level #[doc(inline)] //~^ ERROR can only be applied to a `use` item pub fn foo() {} pub mod bar { - #![doc(test(no_crate_inject))] - //~^ ERROR can only be applied at the crate level - - #[doc(test(no_crate_inject))] - //~^ ERROR can only be applied at the crate level #[doc(inline)] //~^ ERROR can only be applied to a `use` item pub fn baz() {} diff --git a/tests/rustdoc-ui/lints/invalid-doc-attr.stderr b/tests/rustdoc-ui/lints/invalid-doc-attr.stderr index 82e1b62b57a6..e431b8df2263 100644 --- a/tests/rustdoc-ui/lints/invalid-doc-attr.stderr +++ b/tests/rustdoc-ui/lints/invalid-doc-attr.stderr @@ -1,14 +1,5 @@ -error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:7:12 - | -LL | #[doc(test(no_crate_inject))] - | ^^^^^^^^^^^^^^^ - | - = note: read for more information - = note: `#[deny(invalid_doc_attributes)]` on by default - error: this attribute can only be applied to a `use` item - --> $DIR/invalid-doc-attr.rs:9:7 + --> $DIR/invalid-doc-attr.rs:7:7 | LL | #[doc(inline)] | ^^^^^^ only applicable on `use` items @@ -17,17 +8,10 @@ LL | pub fn foo() {} | ------------ not a `use` item | = note: read for more information - -error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:14:17 - | -LL | #![doc(test(no_crate_inject))] - | ^^^^^^^^^^^^^^^ - | - = note: read for more information + = note: `#[deny(invalid_doc_attributes)]` on by default error: conflicting doc inlining attributes - --> $DIR/invalid-doc-attr.rs:24:7 + --> $DIR/invalid-doc-attr.rs:17:7 | LL | #[doc(inline)] | ^^^^^^ this attribute... @@ -37,7 +21,7 @@ LL | #[doc(no_inline)] = help: remove one of the conflicting attributes error: this attribute can only be applied to an `extern crate` item - --> $DIR/invalid-doc-attr.rs:30:7 + --> $DIR/invalid-doc-attr.rs:23:7 | LL | #[doc(masked)] | ^^^^^^ only applicable on `extern crate` items @@ -48,7 +32,7 @@ LL | pub struct Masked; = note: read for more information error: this attribute cannot be applied to an `extern crate self` item - --> $DIR/invalid-doc-attr.rs:34:7 + --> $DIR/invalid-doc-attr.rs:27:7 | LL | #[doc(masked)] | ^^^^^^ not applicable on `extern crate self` items @@ -70,16 +54,8 @@ LL | | pub extern crate self as reexport; | = note: read for more information -error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:17:16 - | -LL | #[doc(test(no_crate_inject))] - | ^^^^^^^^^^^^^^^ - | - = note: read for more information - error: this attribute can only be applied to a `use` item - --> $DIR/invalid-doc-attr.rs:19:11 + --> $DIR/invalid-doc-attr.rs:12:11 | LL | #[doc(inline)] | ^^^^^^ only applicable on `use` items @@ -89,5 +65,5 @@ LL | pub fn baz() {} | = note: read for more information -error: aborting due to 9 previous errors +error: aborting due to 6 previous errors diff --git a/tests/ui/rustdoc/doc-alias-crate-level.stderr b/tests/ui/rustdoc/doc-alias-crate-level.stderr index a40e31714f14..1d10446a4e7c 100644 --- a/tests/ui/rustdoc/doc-alias-crate-level.stderr +++ b/tests/ui/rustdoc/doc-alias-crate-level.stderr @@ -1,14 +1,14 @@ -error: '\'' character isn't allowed in `#[doc(alias = "...")]` - --> $DIR/doc-alias-crate-level.rs:7:15 - | -LL | #[doc(alias = "shouldn't work!")] - | ^^^^^^^^^^^^^^^^^ - error: `#![doc(alias = "...")]` isn't allowed as a crate-level attribute --> $DIR/doc-alias-crate-level.rs:5:16 | LL | #![doc(alias = "not working!")] | ^^^^^^^^^^^^^^ +error: '\'' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/doc-alias-crate-level.rs:7:15 + | +LL | #[doc(alias = "shouldn't work!")] + | ^^^^^^^^^^^^^^^^^ + error: aborting due to 2 previous errors diff --git a/tests/ui/rustdoc/doc_keyword.stderr b/tests/ui/rustdoc/doc_keyword.stderr index 56da4b00724a..c8038cbf0196 100644 --- a/tests/ui/rustdoc/doc_keyword.stderr +++ b/tests/ui/rustdoc/doc_keyword.stderr @@ -1,3 +1,9 @@ +error: `#![doc(keyword = "...")]` isn't allowed as a crate-level attribute + --> $DIR/doc_keyword.rs:4:8 + | +LL | #![doc(keyword = "match")] + | ^^^^^^^ + error: nonexistent keyword `tadam` used in `#[doc(keyword = "...")]` --> $DIR/doc_keyword.rs:22:17 | @@ -24,11 +30,5 @@ error: `#[doc(keyword = "...")]` should be used on modules LL | #[doc(keyword = "match")] | ^^^^^^^ -error: `#![doc(keyword = "...")]` isn't allowed as a crate-level attribute - --> $DIR/doc_keyword.rs:4:8 - | -LL | #![doc(keyword = "match")] - | ^^^^^^^ - error: aborting due to 5 previous errors From 76ad528d32db21abca9d9f55c5abc8666d4a2afe Mon Sep 17 00:00:00 2001 From: Usman Akinyemi Date: Sun, 11 Jan 2026 04:49:50 +0530 Subject: [PATCH 0561/1061] rustc_parse_format: improve diagnostics for unsupported python numeric grouping Detect Python-style numeric grouping syntax in format strings (e.g. `{x:,}`) and emit a clear diagnostic explaining that it is not supported in Rust. This helps users coming from Python understand the error without exposing the full set of valid Rust format specifiers. Signed-off-by: Usman Akinyemi --- compiler/rustc_parse_format/src/lib.rs | 22 ++++++++++++++++++++++ tests/ui/fmt/format-string-error-2.rs | 2 ++ tests/ui/fmt/format-string-error-2.stderr | 12 +++++++++++- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 143fd0c4436c..490af1257760 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -461,6 +461,7 @@ impl<'input> Parser<'input> { ('?', '}') => self.missing_colon_before_debug_formatter(), ('?', _) => self.suggest_format_debug(), ('<' | '^' | '>', _) => self.suggest_format_align(c), + (',', _) => self.suggest_unsupported_python_numeric_grouping(), _ => self.suggest_positional_arg_instead_of_captured_arg(arg), } } @@ -934,6 +935,27 @@ impl<'input> Parser<'input> { } } } + + fn suggest_unsupported_python_numeric_grouping(&mut self) { + if let Some((range, _)) = self.consume_pos(',') { + self.errors.insert( + 0, + ParseError { + description: + "python's numeric grouping `,` is not supported in rust format strings" + .to_owned(), + note: Some(format!("to print `{{`, you can escape it using `{{{{`",)), + label: "expected `}`".to_owned(), + span: range, + secondary_label: self + .last_open_brace + .clone() + .map(|sp| ("because of this opening brace".to_owned(), sp)), + suggestion: Suggestion::None, + }, + ); + } + } } // Assert a reasonable size for `Piece` diff --git a/tests/ui/fmt/format-string-error-2.rs b/tests/ui/fmt/format-string-error-2.rs index e14a4064aa83..63d65023eb78 100644 --- a/tests/ui/fmt/format-string-error-2.rs +++ b/tests/ui/fmt/format-string-error-2.rs @@ -86,4 +86,6 @@ raw { \n println!("{x?}, world!",); //~^ ERROR invalid format string: expected `}`, found `?` + println!("{x,}, world!",); + //~^ ERROR invalid format string: python's numeric grouping `,` is not supported in rust format strings } diff --git a/tests/ui/fmt/format-string-error-2.stderr b/tests/ui/fmt/format-string-error-2.stderr index b117fb57cf07..e7fbc2e81fc6 100644 --- a/tests/ui/fmt/format-string-error-2.stderr +++ b/tests/ui/fmt/format-string-error-2.stderr @@ -188,5 +188,15 @@ LL | println!("{x?}, world!",); | = note: to print `{`, you can escape it using `{{` -error: aborting due to 19 previous errors +error: invalid format string: python's numeric grouping `,` is not supported in rust format strings + --> $DIR/format-string-error-2.rs:89:17 + | +LL | println!("{x,}, world!",); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: to print `{`, you can escape it using `{{` + +error: aborting due to 20 previous errors From 8d1d88bfc4768a43c845d3de04e1ace4e9d0c1a3 Mon Sep 17 00:00:00 2001 From: vsriram Date: Mon, 12 Jan 2026 00:07:07 +0530 Subject: [PATCH 0562/1061] ui: add test for normalizing const projections with assoc const equality --- .../normalization-via-param-env.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tests/ui/const-generics/associated-const-bindings/normalization-via-param-env.rs diff --git a/tests/ui/const-generics/associated-const-bindings/normalization-via-param-env.rs b/tests/ui/const-generics/associated-const-bindings/normalization-via-param-env.rs new file mode 100644 index 000000000000..c7bb5bccedb3 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/normalization-via-param-env.rs @@ -0,0 +1,18 @@ +//@ check-pass +#![feature(min_generic_const_args)] +#![allow(incomplete_features)] + +// Regression test for normalizing const projections +// with associated const equality bounds. + +trait Trait { + #[type_const] + const C: usize; +} + +fn f>() { + // This must normalize ::C to 1 + let _: [(); T::C] = [()]; +} + +fn main() {} From 8a71deb28275b847492208a325db589f2c222a49 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Thu, 8 Jan 2026 23:26:12 +0100 Subject: [PATCH 0563/1061] add `manual_take` lint --- CHANGELOG.md | 1 + book/src/lint_configuration.md | 1 + clippy_config/src/conf.rs | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/manual_take.rs | 114 +++++++++++++++++++++++++++++ tests/ui/manual_take.fixed | 57 +++++++++++++++ tests/ui/manual_take.rs | 69 +++++++++++++++++ tests/ui/manual_take.stderr | 53 ++++++++++++++ tests/ui/manual_take_nocore.rs | 37 ++++++++++ tests/ui/manual_take_nocore.stderr | 0 tests/ui/manual_take_nostd.fixed | 10 +++ tests/ui/manual_take_nostd.rs | 22 ++++++ tests/ui/manual_take_nostd.stderr | 54 ++++++++++++++ 14 files changed, 422 insertions(+) create mode 100644 clippy_lints/src/manual_take.rs create mode 100644 tests/ui/manual_take.fixed create mode 100644 tests/ui/manual_take.rs create mode 100644 tests/ui/manual_take.stderr create mode 100644 tests/ui/manual_take_nocore.rs create mode 100644 tests/ui/manual_take_nocore.stderr create mode 100644 tests/ui/manual_take_nostd.fixed create mode 100644 tests/ui/manual_take_nostd.rs create mode 100644 tests/ui/manual_take_nostd.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cda8003b05c..b5172267fcaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6653,6 +6653,7 @@ Released 2018-09-13 [`manual_string_new`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_string_new [`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap +[`manual_take`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_take [`manual_try_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_try_fold [`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or [`manual_unwrap_or_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or_default diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index a1c079898594..f81dd421f59b 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -905,6 +905,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`manual_split_once`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once) * [`manual_str_repeat`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat) * [`manual_strip`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip) +* [`manual_take`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_take) * [`manual_try_fold`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_try_fold) * [`map_clone`](https://rust-lang.github.io/rust-clippy/master/index.html#map_clone) * [`map_unwrap_or`](https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or) diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index e1d7c1d88eb9..849d9a613d80 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -780,6 +780,7 @@ define_Conf! { manual_split_once, manual_str_repeat, manual_strip, + manual_take, manual_try_fold, map_clone, map_unwrap_or, diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index ef9da84c4407..549fc64d50e2 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -316,6 +316,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::manual_slice_size_calculation::MANUAL_SLICE_SIZE_CALCULATION_INFO, crate::manual_string_new::MANUAL_STRING_NEW_INFO, crate::manual_strip::MANUAL_STRIP_INFO, + crate::manual_take::MANUAL_TAKE_INFO, crate::map_unit_fn::OPTION_MAP_UNIT_FN_INFO, crate::map_unit_fn::RESULT_MAP_UNIT_FN_INFO, crate::match_result_ok::MATCH_RESULT_OK_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ef2461f8b097..eccff4789a20 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -219,6 +219,7 @@ mod manual_rotate; mod manual_slice_size_calculation; mod manual_string_new; mod manual_strip; +mod manual_take; mod map_unit_fn; mod match_result_ok; mod matches; @@ -861,6 +862,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co Box::new(move |_| Box::new(manual_ilog2::ManualIlog2::new(conf))), Box::new(|_| Box::new(same_length_and_capacity::SameLengthAndCapacity)), Box::new(move |tcx| Box::new(duration_suboptimal_units::DurationSuboptimalUnits::new(tcx, conf))), + Box::new(move |_| Box::new(manual_take::ManualTake::new(conf))), // add late passes here, used by `cargo dev new_lint` ]; store.late_passes.extend(late_lints); diff --git a/clippy_lints/src/manual_take.rs b/clippy_lints/src/manual_take.rs new file mode 100644 index 000000000000..8e74d04c4556 --- /dev/null +++ b/clippy_lints/src/manual_take.rs @@ -0,0 +1,114 @@ +use clippy_config::Conf; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{MEM_TAKE, Msrv}; +use clippy_utils::source::snippet_with_context; +use rustc_ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{Block, Expr, ExprKind, StmtKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_session::impl_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// Detects manual re-implementations of `std::mem::take`. + /// + /// ### Why is this bad? + /// Because the function call is shorter and easier to read. + /// + /// ### Known issues + /// Currently the lint only detects cases involving `bool`s. + /// + /// ### Example + /// ```no_run + /// let mut x = true; + /// let _ = if x { + /// x = false; + /// true + /// } else { + /// false + /// }; + /// ``` + /// Use instead: + /// ```no_run + /// let mut x = true; + /// let _ = std::mem::take(&mut x); + /// ``` + #[clippy::version = "1.94.0"] + pub MANUAL_TAKE, + complexity, + "manual `mem::take` implementation" +} +pub struct ManualTake { + msrv: Msrv, +} + +impl ManualTake { + pub fn new(conf: &'static Conf) -> Self { + Self { msrv: conf.msrv } + } +} + +impl_lint_pass!(ManualTake => [MANUAL_TAKE]); + +impl LateLintPass<'_> for ManualTake { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + if let ExprKind::If(cond, then, Some(otherwise)) = expr.kind + && let ExprKind::Path(_) = cond.kind + && let ExprKind::Block( + Block { + stmts: [stmt], + expr: Some(then_expr), + .. + }, + .., + ) = then.kind + && let ExprKind::Block( + Block { + stmts: [], + expr: Some(else_expr), + .. + }, + .., + ) = otherwise.kind + && let StmtKind::Semi(assignment) = stmt.kind + && let ExprKind::Assign(mut_c, possible_false, _) = assignment.kind + && let ExprKind::Path(_) = mut_c.kind + && !expr.span.in_external_macro(cx.sess().source_map()) + && let Some(std_or_core) = clippy_utils::std_or_core(cx) + && self.msrv.meets(cx, MEM_TAKE) + && clippy_utils::SpanlessEq::new(cx).eq_expr(cond, mut_c) + && Some(false) == as_const_bool(possible_false) + && let Some(then_bool) = as_const_bool(then_expr) + && let Some(else_bool) = as_const_bool(else_expr) + && then_bool != else_bool + { + span_lint_and_then( + cx, + MANUAL_TAKE, + expr.span, + "manual implementation of `mem::take`", + |diag| { + let mut app = Applicability::MachineApplicable; + let negate = if then_bool { "" } else { "!" }; + let taken = snippet_with_context(cx, cond.span, expr.span.ctxt(), "_", &mut app).0; + diag.span_suggestion_verbose( + expr.span, + "use", + format!("{negate}{std_or_core}::mem::take(&mut {taken})"), + app, + ); + }, + ); + } + } +} + +fn as_const_bool(e: &Expr<'_>) -> Option { + if let ExprKind::Lit(lit) = e.kind + && let LitKind::Bool(b) = lit.node + { + Some(b) + } else { + None + } +} diff --git a/tests/ui/manual_take.fixed b/tests/ui/manual_take.fixed new file mode 100644 index 000000000000..5891bd49c81c --- /dev/null +++ b/tests/ui/manual_take.fixed @@ -0,0 +1,57 @@ +#![warn(clippy::manual_take)] + +fn main() { + msrv_1_39(); + msrv_1_40(); + let mut x = true; + let mut y = false; + + let _lint_negated = !std::mem::take(&mut x); + + let _ = if x { + y = false; + true + } else { + false + }; + + let _ = if x { + x = true; + true + } else { + false + }; + + let _ = if x { + x = false; + y = true; + false + } else { + true + }; + + let _ = if x { + x = false; + false + } else { + y = true; + true + }; +} + +#[clippy::msrv = "1.39.0"] +fn msrv_1_39() -> bool { + let mut x = true; + if x { + x = false; + true + } else { + false + } +} + +#[clippy::msrv = "1.40.0"] +fn msrv_1_40() -> bool { + let mut x = true; + std::mem::take(&mut x) +} diff --git a/tests/ui/manual_take.rs b/tests/ui/manual_take.rs new file mode 100644 index 000000000000..89903fcb2416 --- /dev/null +++ b/tests/ui/manual_take.rs @@ -0,0 +1,69 @@ +#![warn(clippy::manual_take)] + +fn main() { + msrv_1_39(); + msrv_1_40(); + let mut x = true; + let mut y = false; + + let _lint_negated = if x { + //~^ manual_take + x = false; + false + } else { + true + }; + + let _ = if x { + y = false; + true + } else { + false + }; + + let _ = if x { + x = true; + true + } else { + false + }; + + let _ = if x { + x = false; + y = true; + false + } else { + true + }; + + let _ = if x { + x = false; + false + } else { + y = true; + true + }; +} + +#[clippy::msrv = "1.39.0"] +fn msrv_1_39() -> bool { + let mut x = true; + if x { + x = false; + true + } else { + false + } +} + +#[clippy::msrv = "1.40.0"] +fn msrv_1_40() -> bool { + let mut x = true; + if x { + //~^ manual_take + x = false; + true + } else { + false + } +} diff --git a/tests/ui/manual_take.stderr b/tests/ui/manual_take.stderr new file mode 100644 index 000000000000..69ba7778a275 --- /dev/null +++ b/tests/ui/manual_take.stderr @@ -0,0 +1,53 @@ +error: manual implementation of `mem::take` + --> tests/ui/manual_take.rs:9:25 + | +LL | let _lint_negated = if x { + | _________________________^ +LL | | +LL | | x = false; +LL | | false +LL | | } else { +LL | | true +LL | | }; + | |_____^ + | + = note: `-D clippy::manual-take` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_take)]` +help: use + | +LL - let _lint_negated = if x { +LL - +LL - x = false; +LL - false +LL - } else { +LL - true +LL - }; +LL + let _lint_negated = !std::mem::take(&mut x); + | + +error: manual implementation of `mem::take` + --> tests/ui/manual_take.rs:62:5 + | +LL | / if x { +LL | | +LL | | x = false; +LL | | true +LL | | } else { +LL | | false +LL | | } + | |_____^ + | +help: use + | +LL - if x { +LL - +LL - x = false; +LL - true +LL - } else { +LL - false +LL - } +LL + std::mem::take(&mut x) + | + +error: aborting due to 2 previous errors + diff --git a/tests/ui/manual_take_nocore.rs b/tests/ui/manual_take_nocore.rs new file mode 100644 index 000000000000..ef4f23395028 --- /dev/null +++ b/tests/ui/manual_take_nocore.rs @@ -0,0 +1,37 @@ +//@ check-pass +#![feature(no_core, lang_items)] +#![no_core] +#![allow(clippy::missing_safety_doc)] +#![warn(clippy::manual_take)] + +#[link(name = "c")] +unsafe extern "C" {} + +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + +#[lang = "sized"] +pub trait Sized: MetaSized {} +#[lang = "copy"] +pub trait Copy {} +#[lang = "freeze"] +pub unsafe trait Freeze {} + +#[lang = "start"] +fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { + 0 +} + +fn main() { + let mut x = true; + // this should not lint because we don't have std nor core + let _manual_take = if x { + x = false; + true + } else { + false + }; +} diff --git a/tests/ui/manual_take_nocore.stderr b/tests/ui/manual_take_nocore.stderr new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/ui/manual_take_nostd.fixed b/tests/ui/manual_take_nostd.fixed new file mode 100644 index 000000000000..123c5a91998c --- /dev/null +++ b/tests/ui/manual_take_nostd.fixed @@ -0,0 +1,10 @@ +#![no_std] +#![warn(clippy::manual_take)] + +pub fn manual_mem_take_should_reference_core() { + let mut x = true; + + let _lint_negated = !core::mem::take(&mut x); + + let _lint = core::mem::take(&mut x); +} diff --git a/tests/ui/manual_take_nostd.rs b/tests/ui/manual_take_nostd.rs new file mode 100644 index 000000000000..0df352477b74 --- /dev/null +++ b/tests/ui/manual_take_nostd.rs @@ -0,0 +1,22 @@ +#![no_std] +#![warn(clippy::manual_take)] + +pub fn manual_mem_take_should_reference_core() { + let mut x = true; + + let _lint_negated = if x { + //~^ manual_take + x = false; + false + } else { + true + }; + + let _lint = if x { + //~^ manual_take + x = false; + true + } else { + false + }; +} diff --git a/tests/ui/manual_take_nostd.stderr b/tests/ui/manual_take_nostd.stderr new file mode 100644 index 000000000000..71a5066e4db3 --- /dev/null +++ b/tests/ui/manual_take_nostd.stderr @@ -0,0 +1,54 @@ +error: manual implementation of `mem::take` + --> tests/ui/manual_take_nostd.rs:7:25 + | +LL | let _lint_negated = if x { + | _________________________^ +LL | | +LL | | x = false; +LL | | false +LL | | } else { +LL | | true +LL | | }; + | |_____^ + | + = note: `-D clippy::manual-take` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_take)]` +help: use + | +LL - let _lint_negated = if x { +LL - +LL - x = false; +LL - false +LL - } else { +LL - true +LL - }; +LL + let _lint_negated = !core::mem::take(&mut x); + | + +error: manual implementation of `mem::take` + --> tests/ui/manual_take_nostd.rs:15:17 + | +LL | let _lint = if x { + | _________________^ +LL | | +LL | | x = false; +LL | | true +LL | | } else { +LL | | false +LL | | }; + | |_____^ + | +help: use + | +LL - let _lint = if x { +LL - +LL - x = false; +LL - true +LL - } else { +LL - false +LL - }; +LL + let _lint = core::mem::take(&mut x); + | + +error: aborting due to 2 previous errors + From 2ae298711f92a79ea5bc59479846bfeea49481ef Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 9 Jan 2026 10:42:48 +1100 Subject: [PATCH 0564/1061] Replace two `BottomUpFolder`s with `fold_regions`. Because these folders only change regions. Note: `BottomUpFolder` folds all regions, while `fold_regions` skips some bound regions. But that's ok because these two folders only modify `ReVar`s. --- .../src/interpret/intrinsics.rs | 11 +++-------- compiler/rustc_hir_analysis/src/check/check.rs | 17 ++++++----------- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 94832c0c2577..fe1dd1b6eb35 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -13,7 +13,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, read_target_uint, write_target_uint}; use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic}; use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::{FloatTy, PolyExistentialPredicate, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{FloatTy, PolyExistentialPredicate, Ty, TyCtxt}; use rustc_middle::{bug, span_bug, ty}; use rustc_span::{Symbol, sym}; use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt}; @@ -243,13 +243,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ocx.register_obligations(preds.iter().map(|pred: PolyExistentialPredicate<'_>| { let pred = pred.with_self_ty(tcx, tp_ty); // Lifetimes can only be 'static because of the bound on T - let pred = pred.fold_with(&mut ty::BottomUpFolder { - tcx, - ty_op: |ty| ty, - lt_op: |lt| { - if lt == tcx.lifetimes.re_erased { tcx.lifetimes.re_static } else { lt } - }, - ct_op: |ct| ct, + let pred = ty::fold_regions(tcx, pred, |r, _| { + if r == tcx.lifetimes.re_erased { tcx.lifetimes.re_static } else { r } }); Obligation::new(tcx, ObligationCause::dummy(), param_env, pred) })); diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index ad66003a6bf9..4664bfcce853 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -508,23 +508,18 @@ fn sanity_check_found_hidden_type<'tcx>( return Ok(()); } } - let strip_vars = |ty: Ty<'tcx>| { - ty.fold_with(&mut BottomUpFolder { - tcx, - ty_op: |t| t, - ct_op: |c| c, - lt_op: |l| match l.kind() { - RegionKind::ReVar(_) => tcx.lifetimes.re_erased, - _ => l, - }, + let erase_re_vars = |ty: Ty<'tcx>| { + fold_regions(tcx, ty, |r, _| match r.kind() { + RegionKind::ReVar(_) => tcx.lifetimes.re_erased, + _ => r, }) }; // Closures frequently end up containing erased lifetimes in their final representation. // These correspond to lifetime variables that never got resolved, so we patch this up here. - ty.ty = strip_vars(ty.ty); + ty.ty = erase_re_vars(ty.ty); // Get the hidden type. let hidden_ty = tcx.type_of(key.def_id).instantiate(tcx, key.args); - let hidden_ty = strip_vars(hidden_ty); + let hidden_ty = erase_re_vars(hidden_ty); // If the hidden types differ, emit a type mismatch diagnostic. if hidden_ty == ty.ty { From 71d1b2ca7fe64242d1f5a2a96da7a32b78bbcc9b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 9 Jan 2026 13:09:14 +1100 Subject: [PATCH 0565/1061] Whitespace fixes. --- compiler/rustc_type_ir/src/flags.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 2c1fc7decc3e..8b057e5866cd 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -74,7 +74,7 @@ bitflags::bitflags! { /// Does this have `Projection`? const HAS_TY_PROJECTION = 1 << 10; /// Does this have `Free` aliases? - const HAS_TY_FREE_ALIAS = 1 << 11; + const HAS_TY_FREE_ALIAS = 1 << 11; /// Does this have `Opaque`? const HAS_TY_OPAQUE = 1 << 12; /// Does this have `Inherent`? @@ -135,7 +135,7 @@ bitflags::bitflags! { const HAS_TY_CORO = 1 << 24; /// Does this have have a `Bound(BoundVarIndexKind::Canonical, _)`? - const HAS_CANONICAL_BOUND = 1 << 25; + const HAS_CANONICAL_BOUND = 1 << 25; } } From 02e0879c5d7eb637bcb4df78f247fe23abd10e6a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 9 Jan 2026 13:01:45 +1100 Subject: [PATCH 0566/1061] Remove redundant call to `erase_and_anonymize_regions`. The exact same call appears earlier in this function. --- compiler/rustc_ty_utils/src/instance.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 23bbd9ca6d63..cbe15eb54787 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -222,8 +222,6 @@ fn resolve_associated_item<'tcx>( return Err(guar); } - let args = tcx.erase_and_anonymize_regions(args); - // We check that the impl item is compatible with the trait item // because otherwise we may ICE in const eval due to type mismatches, // signature incompatibilities, etc. From 5e510929c65c1340f024311ba5aed9ff57443c54 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 9 Jan 2026 13:34:08 +1100 Subject: [PATCH 0567/1061] Remove useless call to `erase_and_anonymize_regions`. The only thing we do with the result is consult the `.def_id` field, which is unaffected by `erase_and_anonymize_regions`. --- compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index dc941cb41c56..e11ed796887a 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1520,7 +1520,6 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>( // Unwrap potential addrspacecast let vtable = find_vtable_behind_cast(vtable); let trait_ref_self = trait_ref.with_self_ty(cx.tcx, ty); - let trait_ref_self = cx.tcx.erase_and_anonymize_regions(trait_ref_self); let trait_def_id = trait_ref_self.def_id; let trait_vis = cx.tcx.visibility(trait_def_id); From 46d8c2beebf0d3c527eaecc836bff61478fc300b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 9 Jan 2026 15:42:37 +1100 Subject: [PATCH 0568/1061] Clean up `src`/`dst` transmute mess. - Remove the vacuous `Types`, which provides extremely little value. - Make sure `src` comes before `dst` in all transmute-related functions. (Currently it's a mix: sometimes `src` is first, sometimes it is second`.) --- .../rustc_next_trait_solver/src/delegate.rs | 2 +- .../src/solve/eval_ctxt/mod.rs | 2 +- .../traits/fulfillment_errors.rs | 7 +------ .../src/solve/delegate.rs | 6 ++---- .../src/traits/select/confirmation.rs | 3 +-- compiler/rustc_transmute/src/lib.rs | 18 ++++-------------- .../crates/hir-ty/src/next_solver/solver.rs | 2 +- 7 files changed, 11 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index 41c2e5f60ec3..9d5aa8bc124b 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -86,8 +86,8 @@ pub trait SolverDelegate: Deref + Sized { fn is_transmutable( &self, - dst: ::Ty, src: ::Ty, + dst: ::Ty, assume: ::Const, ) -> Result; } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 8d0a3ac94d5a..3ab42d64f2ff 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -1170,8 +1170,8 @@ where pub(super) fn is_transmutable( &mut self, - dst: I::Ty, src: I::Ty, + dst: I::Ty, assume: I::Const, ) -> Result { self.delegate.is_transmutable(dst, src, assume) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 0f021946e06a..8762607edf5d 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -2781,11 +2781,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.tcx.instantiate_bound_regions_with_erased(trait_pred), ); - let src_and_dst = rustc_transmute::Types { - dst: trait_pred.trait_ref.args.type_at(0), - src: trait_pred.trait_ref.args.type_at(1), - }; - let ocx = ObligationCtxt::new(self); let Ok(assume) = ocx.structurally_normalize_const( &obligation.cause, @@ -2812,7 +2807,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`"); match rustc_transmute::TransmuteTypeEnv::new(self.infcx.tcx) - .is_transmutable(src_and_dst, assume) + .is_transmutable(src, dst, assume) { Answer::No(reason) => { let safe_transmute_explanation = match reason { diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index b6bdf1067a35..62572694de32 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -294,8 +294,8 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< // register candidates. We probably need to register >1 since we may have an OR of ANDs. fn is_transmutable( &self, - dst: Ty<'tcx>, src: Ty<'tcx>, + dst: Ty<'tcx>, assume: ty::Const<'tcx>, ) -> Result { // Erase regions because we compute layouts in `rustc_transmute`, @@ -307,9 +307,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< }; // FIXME(transmutability): This really should be returning nested goals for `Answer::If*` - match rustc_transmute::TransmuteTypeEnv::new(self.0.tcx) - .is_transmutable(rustc_transmute::Types { src, dst }, assume) - { + match rustc_transmute::TransmuteTypeEnv::new(self.0.tcx).is_transmutable(src, dst, assume) { rustc_transmute::Answer::Yes => Ok(Certainty::Yes), rustc_transmute::Answer::No(_) | rustc_transmute::Answer::If(_) => Err(NoSolution), } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 20a8842f2e8e..4f65b30775ed 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -365,8 +365,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?src, ?dst); let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx.tcx); - let maybe_transmutable = - transmute_env.is_transmutable(rustc_transmute::Types { dst, src }, assume); + let maybe_transmutable = transmute_env.is_transmutable(src, dst, assume); let fully_flattened = match maybe_transmutable { Answer::No(_) => Err(SelectionError::Unimplemented)?, diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 08ae561c972c..732881f12d2c 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -93,15 +93,6 @@ mod rustc { use super::*; - /// The source and destination types of a transmutation. - #[derive(Debug, Clone, Copy)] - pub struct Types<'tcx> { - /// The source type. - pub src: Ty<'tcx>, - /// The destination type. - pub dst: Ty<'tcx>, - } - pub struct TransmuteTypeEnv<'tcx> { tcx: TyCtxt<'tcx>, } @@ -113,13 +104,12 @@ mod rustc { pub fn is_transmutable( &mut self, - types: Types<'tcx>, + src: Ty<'tcx>, + dst: Ty<'tcx>, assume: crate::Assume, ) -> crate::Answer, Ty<'tcx>> { - crate::maybe_transmutable::MaybeTransmutableQuery::new( - types.src, types.dst, assume, self.tcx, - ) - .answer() + crate::maybe_transmutable::MaybeTransmutableQuery::new(src, dst, assume, self.tcx) + .answer() } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs index 21fbd64dd066..15d6e2e4516e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs @@ -232,8 +232,8 @@ impl<'db> SolverDelegate for SolverContext<'db> { fn is_transmutable( &self, - _dst: Ty<'db>, _src: Ty<'db>, + _dst: Ty<'db>, _assume: ::Const, ) -> Result { // It's better to return some value while not fully implement From e7036b136f44f9e385d794a783f6f66816f32ec0 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 9 Jan 2026 10:45:26 +1100 Subject: [PATCH 0569/1061] clippy: remove `ty_has_erased_regions`. It duplicates `has_erased_regions` from the compiler. --- .../matches/significant_drop_in_scrutinee.rs | 24 +++---------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index bac35e7f8c70..14d265bfdad8 100644 --- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -12,7 +12,7 @@ use rustc_errors::{Applicability, Diag}; use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Arm, Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LintContext}; -use rustc_middle::ty::{GenericArgKind, Region, RegionKind, Ty, TyCtxt, TypeVisitable, TypeVisitor}; +use rustc_middle::ty::{GenericArgKind, RegionKind, Ty, TypeVisitableExt}; use rustc_span::Span; use super::SIGNIFICANT_DROP_IN_SCRUTINEE; @@ -303,13 +303,13 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> { if self.sig_drop_holder != SigDropHolder::None { let parent_ty = self.cx.typeck_results().expr_ty(parent_expr); - if !ty_has_erased_regions(parent_ty) && !parent_expr.is_syntactic_place_expr() { + if !parent_ty.has_erased_regions() && !parent_expr.is_syntactic_place_expr() { self.replace_current_sig_drop(parent_expr.span, parent_ty.is_unit(), 0); self.sig_drop_holder = SigDropHolder::Moved; } let (peel_ref_ty, peel_ref_times) = ty_peel_refs(parent_ty); - if !ty_has_erased_regions(peel_ref_ty) && is_copy(self.cx, peel_ref_ty) { + if !peel_ref_ty.has_erased_regions() && is_copy(self.cx, peel_ref_ty) { self.replace_current_sig_drop(parent_expr.span, peel_ref_ty.is_unit(), peel_ref_times); self.sig_drop_holder = SigDropHolder::Moved; } @@ -399,24 +399,6 @@ fn ty_peel_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) { (ty, n) } -fn ty_has_erased_regions(ty: Ty<'_>) -> bool { - struct V; - - impl<'tcx> TypeVisitor> for V { - type Result = ControlFlow<()>; - - fn visit_region(&mut self, region: Region<'tcx>) -> Self::Result { - if region.is_erased() { - ControlFlow::Break(()) - } else { - ControlFlow::Continue(()) - } - } - } - - ty.visit_with(&mut V).is_break() -} - impl<'tcx> Visitor<'tcx> for SigDropHelper<'_, 'tcx> { fn visit_expr(&mut self, ex: &'tcx Expr<'_>) { // We've emitted a lint on some neighborhood expression. That lint will suggest to move out the From d419bddb96f8177a3d8a7cb3c4df15902a24028a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 9 Jan 2026 10:45:26 +1100 Subject: [PATCH 0570/1061] clippy: remove `ty_has_erased_regions`. It duplicates `has_erased_regions` from the compiler. --- .../matches/significant_drop_in_scrutinee.rs | 24 +++---------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index bac35e7f8c70..14d265bfdad8 100644 --- a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -12,7 +12,7 @@ use rustc_errors::{Applicability, Diag}; use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Arm, Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LintContext}; -use rustc_middle::ty::{GenericArgKind, Region, RegionKind, Ty, TyCtxt, TypeVisitable, TypeVisitor}; +use rustc_middle::ty::{GenericArgKind, RegionKind, Ty, TypeVisitableExt}; use rustc_span::Span; use super::SIGNIFICANT_DROP_IN_SCRUTINEE; @@ -303,13 +303,13 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> { if self.sig_drop_holder != SigDropHolder::None { let parent_ty = self.cx.typeck_results().expr_ty(parent_expr); - if !ty_has_erased_regions(parent_ty) && !parent_expr.is_syntactic_place_expr() { + if !parent_ty.has_erased_regions() && !parent_expr.is_syntactic_place_expr() { self.replace_current_sig_drop(parent_expr.span, parent_ty.is_unit(), 0); self.sig_drop_holder = SigDropHolder::Moved; } let (peel_ref_ty, peel_ref_times) = ty_peel_refs(parent_ty); - if !ty_has_erased_regions(peel_ref_ty) && is_copy(self.cx, peel_ref_ty) { + if !peel_ref_ty.has_erased_regions() && is_copy(self.cx, peel_ref_ty) { self.replace_current_sig_drop(parent_expr.span, peel_ref_ty.is_unit(), peel_ref_times); self.sig_drop_holder = SigDropHolder::Moved; } @@ -399,24 +399,6 @@ fn ty_peel_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) { (ty, n) } -fn ty_has_erased_regions(ty: Ty<'_>) -> bool { - struct V; - - impl<'tcx> TypeVisitor> for V { - type Result = ControlFlow<()>; - - fn visit_region(&mut self, region: Region<'tcx>) -> Self::Result { - if region.is_erased() { - ControlFlow::Break(()) - } else { - ControlFlow::Continue(()) - } - } - } - - ty.visit_with(&mut V).is_break() -} - impl<'tcx> Visitor<'tcx> for SigDropHelper<'_, 'tcx> { fn visit_expr(&mut self, ex: &'tcx Expr<'_>) { // We've emitted a lint on some neighborhood expression. That lint will suggest to move out the From e555d2c44b6b4a4ec8ac220aa972d18cac87e662 Mon Sep 17 00:00:00 2001 From: Asuna Date: Sun, 11 Jan 2026 23:34:36 +0100 Subject: [PATCH 0571/1061] Use updated indexes to build reverse map for delegation generics --- compiler/rustc_hir_analysis/src/delegation.rs | 6 +++--- tests/ui/delegation/ice-issue-150673.rs | 21 +++++++++++++++++++ tests/ui/delegation/ice-issue-150673.stderr | 19 +++++++++++++++++ 3 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 tests/ui/delegation/ice-issue-150673.rs create mode 100644 tests/ui/delegation/ice-issue-150673.stderr diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs index 4ab13140bf9c..cf0533c39e73 100644 --- a/compiler/rustc_hir_analysis/src/delegation.rs +++ b/compiler/rustc_hir_analysis/src/delegation.rs @@ -135,9 +135,6 @@ fn build_generics<'tcx>( // } own_params.sort_by_key(|key| key.kind.is_ty_or_const()); - let param_def_id_to_index = - own_params.iter().map(|param| (param.def_id, param.index)).collect(); - let (parent_count, has_self) = if let Some(def_id) = parent { let parent_generics = tcx.generics_of(def_id); let parent_kind = tcx.def_kind(def_id); @@ -162,6 +159,9 @@ fn build_generics<'tcx>( } } + let param_def_id_to_index = + own_params.iter().map(|param| (param.def_id, param.index)).collect(); + ty::Generics { parent, parent_count, diff --git a/tests/ui/delegation/ice-issue-150673.rs b/tests/ui/delegation/ice-issue-150673.rs new file mode 100644 index 000000000000..7f041d3ce257 --- /dev/null +++ b/tests/ui/delegation/ice-issue-150673.rs @@ -0,0 +1,21 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod to_reuse { + pub fn foo() -> T { + unimplemented!() + } +} + +struct S(T); + +trait Trait { + reuse to_reuse::foo; +} + +impl Trait for S { +//~^ ERROR: missing generics for struct `S` + reuse Trait::foo; +} + +fn main() {} diff --git a/tests/ui/delegation/ice-issue-150673.stderr b/tests/ui/delegation/ice-issue-150673.stderr new file mode 100644 index 000000000000..fc817b07770e --- /dev/null +++ b/tests/ui/delegation/ice-issue-150673.stderr @@ -0,0 +1,19 @@ +error[E0107]: missing generics for struct `S` + --> $DIR/ice-issue-150673.rs:16:16 + | +LL | impl Trait for S { + | ^ expected 1 generic argument + | +note: struct defined here, with 1 generic parameter: `T` + --> $DIR/ice-issue-150673.rs:10:8 + | +LL | struct S(T); + | ^ - +help: add missing generic argument + | +LL | impl Trait for S { + | +++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0107`. From 63481058f77a3324ac629fabc3208837f4353188 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sun, 11 Jan 2026 19:57:21 -0500 Subject: [PATCH 0572/1061] std: Fix size returned by UEFI tcp4 read operations The read and read_vectored methods were returning the length of the input buffer, rather than the number of bytes actually read. Fix by changing read_inner to return the correct value, and have both read and read_vectored return that. --- library/std/src/sys/net/connection/uefi/tcp4.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/net/connection/uefi/tcp4.rs b/library/std/src/sys/net/connection/uefi/tcp4.rs index 00c93384e5f6..ac38dd901e4d 100644 --- a/library/std/src/sys/net/connection/uefi/tcp4.rs +++ b/library/std/src/sys/net/connection/uefi/tcp4.rs @@ -248,7 +248,7 @@ impl Tcp4 { fragment_table: [fragment], }; - self.read_inner((&raw mut rx_data).cast(), timeout).map(|_| data_len as usize) + self.read_inner((&raw mut rx_data).cast(), timeout) } pub(crate) fn read_vectored( @@ -288,14 +288,14 @@ impl Tcp4 { ); }; - self.read_inner(rx_data.as_mut_ptr(), timeout).map(|_| data_length as usize) + self.read_inner(rx_data.as_mut_ptr(), timeout) } pub(crate) fn read_inner( &self, rx_data: *mut tcp4::ReceiveData, timeout: Option, - ) -> io::Result<()> { + ) -> io::Result { let evt = unsafe { self.create_evt() }?; let completion_token = tcp4::CompletionToken { event: evt.as_ptr(), status: Status::SUCCESS }; @@ -313,7 +313,8 @@ impl Tcp4 { if completion_token.status.is_error() { Err(io::Error::from_raw_os_error(completion_token.status.as_usize())) } else { - Ok(()) + let data_length = unsafe { (*rx_data).data_length }; + Ok(data_length as usize) } } From e6071522dba3032c5e51c6975694956ba000100a Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sat, 10 Jan 2026 14:21:33 +0100 Subject: [PATCH 0573/1061] mark rust_dealloc as captures(address) Co-authored-by: Ralf Jung --- compiler/rustc_codegen_llvm/src/attributes.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index a25ce9e5a90a..bf6bb81b53b0 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -517,7 +517,16 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( to_add.push(llvm::CreateAllocKindAttr(cx.llcx, AllocKindFlags::Free)); // applies to argument place instead of function place let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx); - attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]); + let attrs: &[_] = if llvm_util::get_version() >= (21, 0, 0) { + // "Does not capture provenance" means "if the function call stashes the pointer somewhere, + // accessing that pointer after the function returns is UB". That is definitely the case here since + // freeing will destroy the provenance. + let captures_addr = AttributeKind::CapturesAddress.create_attr(cx.llcx); + &[allocated_pointer, captures_addr] + } else { + &[allocated_pointer] + }; + attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), attrs); } if let Some(align) = codegen_fn_attrs.alignment { llvm::set_alignment(llfn, align); From 468eb45b3f3e106735327748308f7e04e942fe40 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sun, 29 Sep 2024 00:27:50 +0200 Subject: [PATCH 0574/1061] avoid phi node for pointers flowing into Vec appends --- library/alloc/src/slice.rs | 8 +++-- library/alloc/src/vec/mod.rs | 6 +++- .../lib-optimizations/append-elements.rs | 30 +++++++++++++++++++ 3 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 tests/codegen-llvm/lib-optimizations/append-elements.rs diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index e7d0fc3454ee..58abf4bd6571 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -448,9 +448,11 @@ impl [T] { // SAFETY: // allocated above with the capacity of `s`, and initialize to `s.len()` in // ptr::copy_to_non_overlapping below. - unsafe { - s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len()); - v.set_len(s.len()); + if s.len() > 0 { + unsafe { + s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len()); + v.set_len(s.len()); + } } v } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 379e964f0a0c..ac86399df7ab 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2818,7 +2818,11 @@ impl Vec { let count = other.len(); self.reserve(count); let len = self.len(); - unsafe { ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count) }; + if count > 0 { + unsafe { + ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count) + }; + } self.len += count; } diff --git a/tests/codegen-llvm/lib-optimizations/append-elements.rs b/tests/codegen-llvm/lib-optimizations/append-elements.rs new file mode 100644 index 000000000000..8ee520a131f0 --- /dev/null +++ b/tests/codegen-llvm/lib-optimizations/append-elements.rs @@ -0,0 +1,30 @@ +//@ compile-flags: -O -Zmerge-functions=disabled +//@ min-llvm-version: 21 +#![crate_type = "lib"] + +//! Check that a temporary intermediate allocations can eliminated and replaced +//! with memcpy forwarding. +//! This requires Vec code to be structured in a way that avoids phi nodes from the +//! zero-capacity length flowing into the memcpy arguments. + +// CHECK-LABEL: @vec_append_with_temp_alloc +#[no_mangle] +pub fn vec_append_with_temp_alloc(dst: &mut Vec, src: &[u8]) { + // CHECK-NOT: call void @llvm.memcpy + // CHECK: call void @llvm.memcpy.{{.*}}%dst.i{{.*}}%src.0 + // CHECK-NOT: call void @llvm.memcpy + let temp = src.to_vec(); + dst.extend(&temp); + // CHECK: ret +} + +// CHECK-LABEL: @string_append_with_temp_alloc +#[no_mangle] +pub fn string_append_with_temp_alloc(dst: &mut String, src: &str) { + // CHECK-NOT: call void @llvm.memcpy + // CHECK: call void @llvm.memcpy.{{.*}}%dst.i{{.*}}%src.0 + // CHECK-NOT: call void @llvm.memcpy + let temp = src.to_string(); + dst.push_str(&temp); + // CHECK: ret +} From 2d2d3b0a6bb9bc88f795002e1da70e4181254d34 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sun, 11 Jan 2026 23:21:38 -0500 Subject: [PATCH 0575/1061] remote-test-server: Fix header in batch mode In https://github.com/rust-lang/rust/pull/119999, the length field of the header was changed from 4 bytes to 8. One of the headers in `batch_copy` was missed though, so it sends the wrong size. Fix by switching to `create_header` in that spot too. --- src/tools/remote-test-server/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/remote-test-server/src/main.rs b/src/tools/remote-test-server/src/main.rs index bfe8f54937f6..48b0d83e8d82 100644 --- a/src/tools/remote-test-server/src/main.rs +++ b/src/tools/remote-test-server/src/main.rs @@ -387,7 +387,7 @@ fn batch_copy(buf: &[u8], which: u8, dst: &Mutex) { if n > 0 { t!(dst.write_all(buf)); // Marking buf finished - t!(dst.write_all(&[which, 0, 0, 0, 0,])); + t!(dst.write_all(&create_header(which, 0))); } } From e20d903c1c43a4fb288dc75fc332a6fe39073b9a Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Mon, 12 Jan 2026 04:29:24 +0000 Subject: [PATCH 0576/1061] Prepare for merging from rust-lang/rust This updates the rust-version file to 44a5b55557c26353f388400d7da95527256fe260. --- src/doc/rustc-dev-guide/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index 7b444a9ef5f1..b53a66c66751 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -85c8ff69cb3efd950395cc444a54bbbdad668865 +44a5b55557c26353f388400d7da95527256fe260 From 199aa6813eb08b32abca02745f1fb331813bb044 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Mon, 12 Jan 2026 05:04:54 +0000 Subject: [PATCH 0577/1061] Prepare for merging from rust-lang/rust This updates the rust-version file to 44a5b55557c26353f388400d7da95527256fe260. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index c44422d758c5..b53a66c66751 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -f57b9e6f565a1847e83a63f3e90faa3870536c1f +44a5b55557c26353f388400d7da95527256fe260 From 322bbdfaaf469c2571930b051ad0630d83d35ccd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sat, 10 Jan 2026 11:26:20 +0100 Subject: [PATCH 0578/1061] rename eii-extern-target --- compiler/rustc_ast/src/ast.rs | 16 +++--- compiler/rustc_ast/src/visit.rs | 2 +- compiler/rustc_ast_lowering/src/item.rs | 35 ++++++------ compiler/rustc_ast_pretty/src/pprust/state.rs | 8 +-- compiler/rustc_builtin_macros/messages.ftl | 6 +-- compiler/rustc_builtin_macros/src/eii.rs | 20 +++---- compiler/rustc_builtin_macros/src/errors.rs | 6 +-- compiler/rustc_builtin_macros/src/lib.rs | 2 +- .../rustc_codegen_ssa/src/codegen_attrs.rs | 10 ++-- .../rustc_hir/src/attrs/data_structures.rs | 6 +-- .../rustc_hir/src/attrs/encode_cross_crate.rs | 2 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 4 +- compiler/rustc_metadata/src/eii.rs | 10 ++-- compiler/rustc_metadata/src/rmeta/decoder.rs | 2 +- compiler/rustc_parse/src/parser/item.rs | 4 +- compiler/rustc_passes/src/check_attr.rs | 4 +- compiler/rustc_resolve/src/late.rs | 6 +-- compiler/rustc_span/src/symbol.rs | 2 +- library/core/src/macros/mod.rs | 2 +- library/core/src/prelude/v1.rs | 2 +- library/std/src/prelude/v1.rs | 2 +- tests/ui/eii/errors.rs | 18 +++---- tests/ui/eii/errors.stderr | 54 +++++++++---------- .../auxiliary/cross_crate_eii_declaration.rs | 2 +- tests/ui/eii/type_checking/subtype_1.rs | 2 +- tests/ui/eii/type_checking/subtype_2.rs | 2 +- tests/ui/eii/type_checking/subtype_3.rs | 2 +- tests/ui/eii/type_checking/subtype_4.rs | 2 +- tests/ui/eii/type_checking/wrong_ret_ty.rs | 2 +- tests/ui/eii/type_checking/wrong_ty.rs | 2 +- tests/ui/eii/type_checking/wrong_ty_2.rs | 2 +- tests/ui/eii/unsafe_impl_err.rs | 2 +- tests/ui/eii/unsafe_impl_ok.rs | 2 +- .../feature-gate-eii-internals.rs | 2 +- .../feature-gate-eii-internals.stderr | 4 +- 35 files changed, 124 insertions(+), 125 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index fb2ccefe12a1..a4a80475ba73 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2109,16 +2109,18 @@ pub struct MacroDef { /// `true` if macro was defined with `macro_rules`. pub macro_rules: bool, - /// If this is a macro used for externally implementable items, - /// it refers to an extern item which is its "target". This requires - /// name resolution so can't just be an attribute, so we store it in this field. - pub eii_extern_target: Option, + /// Corresponds to `#[eii_declaration(...)]`. + /// `#[eii_declaration(...)]` is a built-in attribute macro, not a built-in attribute, + /// because we require some name resolution to occur in the parameters of this attribute. + /// Name resolution isn't possible in attributes otherwise, so we encode it in the AST. + /// During ast lowering, we turn it back into an attribute again + pub eii_declaration: Option, } #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic, Walkable)] -pub struct EiiExternTarget { +pub struct EiiDecl { /// path to the extern item we're targeting - pub extern_item_path: Path, + pub foreign_item: Path, pub impl_unsafe: bool, } @@ -3824,7 +3826,7 @@ pub struct EiiImpl { /// /// This field is that shortcut: we prefill the extern target to skip a name resolution step, /// making sure it never fails. It'd be awful UX if we fail name resolution in code invisible to the user. - pub known_eii_macro_resolution: Option, + pub known_eii_macro_resolution: Option, pub impl_safety: Safety, pub span: Span, pub inner_span: Span, diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 83b751fbde90..f7b8b9da3241 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -489,7 +489,7 @@ macro_rules! common_visitor_and_walkers { WhereEqPredicate, WhereRegionPredicate, YieldKind, - EiiExternTarget, + EiiDecl, EiiImpl, ); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 3a7308ef7c97..c8ebfb96b558 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -2,7 +2,7 @@ use rustc_abi::ExternAbi; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err}; -use rustc_hir::attrs::{AttributeKind, EiiDecl, EiiImplResolution}; +use rustc_hir::attrs::{AttributeKind, EiiImplResolution}; use rustc_hir::def::{DefKind, PerNS, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_hir::{ @@ -134,16 +134,16 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn lower_eii_extern_target( + fn lower_eii_decl( &mut self, id: NodeId, - eii_name: Ident, - EiiExternTarget { extern_item_path, impl_unsafe }: &EiiExternTarget, - ) -> Option { - self.lower_path_simple_eii(id, extern_item_path).map(|did| EiiDecl { - eii_extern_target: did, + name: Ident, + EiiDecl { foreign_item, impl_unsafe }: &EiiDecl, + ) -> Option { + self.lower_path_simple_eii(id, foreign_item).map(|did| hir::attrs::EiiDecl { + foreign_item: did, impl_unsafe: *impl_unsafe, - name: eii_name, + name, }) } @@ -160,7 +160,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }: &EiiImpl, ) -> hir::attrs::EiiImpl { let resolution = if let Some(target) = known_eii_macro_resolution - && let Some(decl) = self.lower_eii_extern_target( + && let Some(decl) = self.lower_eii_decl( *node_id, // the expect is ok here since we always generate this path in the eii macro. eii_macro_path.segments.last().expect("at least one segment").ident, @@ -196,9 +196,9 @@ impl<'hir> LoweringContext<'_, 'hir> { eii_impls.iter().map(|i| self.lower_eii_impl(i)).collect(), ))] } - ItemKind::MacroDef(name, MacroDef { eii_extern_target: Some(target), .. }) => self - .lower_eii_extern_target(id, *name, target) - .map(|decl| vec![hir::Attribute::Parsed(AttributeKind::EiiExternTarget(decl))]) + ItemKind::MacroDef(name, MacroDef { eii_declaration: Some(target), .. }) => self + .lower_eii_decl(id, *name, target) + .map(|decl| vec![hir::Attribute::Parsed(AttributeKind::EiiDeclaration(decl))]) .unwrap_or_default(), ItemKind::ExternCrate(..) @@ -242,10 +242,7 @@ impl<'hir> LoweringContext<'_, 'hir> { vis_span, span: self.lower_span(i.span), has_delayed_lints: !self.delayed_lints.is_empty(), - eii: find_attr!( - attrs, - AttributeKind::EiiImpls(..) | AttributeKind::EiiExternTarget(..) - ), + eii: find_attr!(attrs, AttributeKind::EiiImpls(..) | AttributeKind::EiiDeclaration(..)), }; self.arena.alloc(item) } @@ -539,7 +536,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); hir::ItemKind::TraitAlias(constness, ident, generics, bounds) } - ItemKind::MacroDef(ident, MacroDef { body, macro_rules, eii_extern_target: _ }) => { + ItemKind::MacroDef(ident, MacroDef { body, macro_rules, eii_declaration: _ }) => { let ident = self.lower_ident(*ident); let body = Box::new(self.lower_delim_args(body)); let def_id = self.local_def_id(id); @@ -553,7 +550,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let macro_def = self.arena.alloc(ast::MacroDef { body, macro_rules: *macro_rules, - eii_extern_target: None, + eii_declaration: None, }); hir::ItemKind::Macro(ident, macro_def, macro_kinds) } @@ -693,7 +690,7 @@ impl<'hir> LoweringContext<'_, 'hir> { has_delayed_lints: !this.delayed_lints.is_empty(), eii: find_attr!( attrs, - AttributeKind::EiiImpls(..) | AttributeKind::EiiExternTarget(..) + AttributeKind::EiiImpls(..) | AttributeKind::EiiDeclaration(..) ), }; hir::OwnerNode::Item(this.arena.alloc(item)) diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 0cf0eae821e9..e50e31c226fd 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -865,10 +865,10 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere sp: Span, print_visibility: impl FnOnce(&mut Self), ) { - if let Some(eii_extern_target) = ¯o_def.eii_extern_target { - self.word("#[eii_extern_target("); - self.print_path(&eii_extern_target.extern_item_path, false, 0); - if eii_extern_target.impl_unsafe { + if let Some(eii_decl) = ¯o_def.eii_declaration { + self.word("#[eii_declaration("); + self.print_path(&eii_decl.foreign_item, false, 0); + if eii_decl.impl_unsafe { self.word(","); self.space(); self.word("unsafe"); diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index e4fded0cb01e..1501bd6c73e2 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -151,9 +151,9 @@ builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept builtin_macros_duplicate_macro_attribute = duplicated attribute -builtin_macros_eii_extern_target_expected_list = `#[eii_extern_target(...)]` expects a list of one or two elements -builtin_macros_eii_extern_target_expected_macro = `#[eii_extern_target(...)]` is only valid on macros -builtin_macros_eii_extern_target_expected_unsafe = expected this argument to be "unsafe" +builtin_macros_eii_declaration_expected_list = `#[eii_declaration(...)]` expects a list of one or two elements +builtin_macros_eii_declaration_expected_macro = `#[eii_declaration(...)]` is only valid on macros +builtin_macros_eii_declaration_expected_unsafe = expected this argument to be "unsafe" .note = the second argument is optional builtin_macros_eii_only_once = `#[{$name}]` can only be specified once diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index a5009b3bfa52..e8aeb8090bf4 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -1,7 +1,7 @@ use rustc_ast::token::{Delimiter, TokenKind}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_ast::{ - Attribute, DUMMY_NODE_ID, EiiExternTarget, EiiImpl, ItemKind, MetaItem, Path, Stmt, StmtKind, + Attribute, DUMMY_NODE_ID, EiiDecl, EiiImpl, ItemKind, MetaItem, Path, Stmt, StmtKind, Visibility, ast, }; use rustc_ast_pretty::pprust::path_to_string; @@ -30,7 +30,7 @@ use crate::errors::{ /// } /// /// #[rustc_builtin_macro(eii_shared_macro)] -/// #[eii_extern_target(panic_handler)] +/// #[eii_declaration(panic_handler)] /// macro panic_handler() {} /// ``` pub(crate) fn eii( @@ -210,8 +210,8 @@ fn generate_default_impl( }, span: eii_attr_span, is_default: true, - known_eii_macro_resolution: Some(ast::EiiExternTarget { - extern_item_path: ecx.path( + known_eii_macro_resolution: Some(ast::EiiDecl { + foreign_item: ecx.path( foreign_item_name.span, // prefix super to escape the `dflt` module generated below vec![Ident::from_str_and_span("super", foreign_item_name.span), foreign_item_name], @@ -349,7 +349,7 @@ fn generate_foreign_item( /// // This attribute tells the compiler that /// #[builtin_macro(eii_shared_macro)] /// // the metadata to link this macro to the generated foreign item. -/// #[eii_extern_target()] +/// #[eii_declaration()] /// macro macro_name { () => {} } /// ``` fn generate_attribute_macro_to_implement( @@ -401,9 +401,9 @@ fn generate_attribute_macro_to_implement( ]), }), macro_rules: false, - // #[eii_extern_target(foreign_item_ident)] - eii_extern_target: Some(ast::EiiExternTarget { - extern_item_path: ast::Path::from_ident(foreign_item_name), + // #[eii_declaration(foreign_item_ident)] + eii_declaration: Some(ast::EiiDecl { + foreign_item: ast::Path::from_ident(foreign_item_name), impl_unsafe, }), }, @@ -412,7 +412,7 @@ fn generate_attribute_macro_to_implement( }) } -pub(crate) fn eii_extern_target( +pub(crate) fn eii_declaration( ecx: &mut ExtCtxt<'_>, span: Span, meta_item: &ast::MetaItem, @@ -461,7 +461,7 @@ pub(crate) fn eii_extern_target( false }; - d.eii_extern_target = Some(EiiExternTarget { extern_item_path, impl_unsafe }); + d.eii_declaration = Some(EiiDecl { foreign_item: extern_item_path, impl_unsafe }); // Return the original item and the new methods. vec![item] diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index e673ad3f8a64..5d4c4e340fa1 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1010,21 +1010,21 @@ pub(crate) struct CfgSelectUnreachable { } #[derive(Diagnostic)] -#[diag(builtin_macros_eii_extern_target_expected_macro)] +#[diag(builtin_macros_eii_declaration_expected_macro)] pub(crate) struct EiiExternTargetExpectedMacro { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(builtin_macros_eii_extern_target_expected_list)] +#[diag(builtin_macros_eii_declaration_expected_list)] pub(crate) struct EiiExternTargetExpectedList { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(builtin_macros_eii_extern_target_expected_unsafe)] +#[diag(builtin_macros_eii_declaration_expected_unsafe)] pub(crate) struct EiiExternTargetExpectedUnsafe { #[primary_span] #[note] diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 89ac8db76063..e1c5a4f85c1b 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -119,7 +119,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { derive: derive::Expander { is_const: false }, derive_const: derive::Expander { is_const: true }, eii: eii::eii, - eii_extern_target: eii::eii_extern_target, + eii_declaration: eii::eii_declaration, eii_shared_macro: eii::eii_shared_macro, global_allocator: global_allocator::expand, test: test::expand_test, diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 7dda824e2b18..db150faea86d 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -287,11 +287,11 @@ fn process_builtin_attrs( } AttributeKind::EiiImpls(impls) => { for i in impls { - let extern_item = match i.resolution { + let foreign_item = match i.resolution { EiiImplResolution::Macro(def_id) => { let Some(extern_item) = find_attr!( tcx.get_all_attrs(def_id), - AttributeKind::EiiExternTarget(target) => target.eii_extern_target + AttributeKind::EiiDeclaration(target) => target.foreign_item ) else { tcx.dcx().span_delayed_bug( i.span, @@ -301,7 +301,7 @@ fn process_builtin_attrs( }; extern_item } - EiiImplResolution::Known(decl) => decl.eii_extern_target, + EiiImplResolution::Known(decl) => decl.foreign_item, EiiImplResolution::Error(_eg) => continue, }; @@ -316,13 +316,13 @@ fn process_builtin_attrs( // iterate over all implementations *in the current crate* // (this is ok since we generate codegen fn attrs in the local crate) // if any of them is *not default* then don't emit the alias. - && tcx.externally_implementable_items(LOCAL_CRATE).get(&extern_item).expect("at least one").1.iter().any(|(_, imp)| !imp.is_default) + && tcx.externally_implementable_items(LOCAL_CRATE).get(&foreign_item).expect("at least one").1.iter().any(|(_, imp)| !imp.is_default) { continue; } codegen_fn_attrs.foreign_item_symbol_aliases.push(( - extern_item, + foreign_item, if i.is_default { Linkage::LinkOnceAny } else { Linkage::External }, Visibility::Default, )); diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index a5ecfa45fb40..c6c50bb793f8 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -43,7 +43,7 @@ pub struct EiiImpl { #[derive(Copy, Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] pub struct EiiDecl { - pub eii_extern_target: DefId, + pub foreign_item: DefId, /// whether or not it is unsafe to implement this EII pub impl_unsafe: bool, pub name: Ident, @@ -744,10 +744,10 @@ pub enum AttributeKind { Dummy, /// Implementation detail of `#[eii]` - EiiExternItem, + EiiDeclaration(EiiDecl), /// Implementation detail of `#[eii]` - EiiExternTarget(EiiDecl), + EiiExternItem, /// Implementation detail of `#[eii]` EiiImpls(ThinVec), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index efdb4f2f22b2..d854cc34c0f3 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -47,8 +47,8 @@ impl AttributeKind { Doc(_) => Yes, DocComment { .. } => Yes, Dummy => No, + EiiDeclaration(_) => Yes, EiiExternItem => No, - EiiExternTarget(_) => Yes, EiiImpls(..) => No, ExportName { .. } => Yes, ExportStable => No, diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 7ec4110f80b9..cfc7e57cc14e 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1205,7 +1205,7 @@ fn check_eiis(tcx: TyCtxt<'_>, def_id: LocalDefId) { EiiImplResolution::Macro(def_id) => { // we expect this macro to have the `EiiMacroFor` attribute, that points to a function // signature that we'd like to compare the function we're currently checking with - if let Some(foreign_item) = find_attr!(tcx.get_all_attrs(*def_id), AttributeKind::EiiExternTarget(EiiDecl {eii_extern_target: t, ..}) => *t) + if let Some(foreign_item) = find_attr!(tcx.get_all_attrs(*def_id), AttributeKind::EiiDeclaration(EiiDecl {foreign_item: t, ..}) => *t) { (foreign_item, tcx.item_name(*def_id)) } else { @@ -1213,7 +1213,7 @@ fn check_eiis(tcx: TyCtxt<'_>, def_id: LocalDefId) { continue; } } - EiiImplResolution::Known(decl) => (decl.eii_extern_target, decl.name.name), + EiiImplResolution::Known(decl) => (decl.foreign_item, decl.name.name), EiiImplResolution::Error(_eg) => continue, }; diff --git a/compiler/rustc_metadata/src/eii.rs b/compiler/rustc_metadata/src/eii.rs index b06ac8481397..42497a82ef8c 100644 --- a/compiler/rustc_metadata/src/eii.rs +++ b/compiler/rustc_metadata/src/eii.rs @@ -31,9 +31,9 @@ pub(crate) fn collect<'tcx>(tcx: TyCtxt<'tcx>, LocalCrate: LocalCrate) -> EiiMap let decl = match i.resolution { EiiImplResolution::Macro(macro_defid) => { // find the decl for this one if it wasn't in yet (maybe it's from the local crate? not very useful but not illegal) - let Some(decl) = find_attr!(tcx.get_all_attrs(macro_defid), AttributeKind::EiiExternTarget(d) => *d) + let Some(decl) = find_attr!(tcx.get_all_attrs(macro_defid), AttributeKind::EiiDeclaration(d) => *d) else { - // skip if it doesn't have eii_extern_target (if we resolved to another macro that's not an EII) + // skip if it doesn't have eii_declaration (if we resolved to another macro that's not an EII) tcx.dcx() .span_delayed_bug(i.span, "resolved to something that's not an EII"); continue; @@ -45,7 +45,7 @@ pub(crate) fn collect<'tcx>(tcx: TyCtxt<'tcx>, LocalCrate: LocalCrate) -> EiiMap }; // FIXME(eii) remove extern target from encoded decl - eiis.entry(decl.eii_extern_target) + eiis.entry(decl.foreign_item) .or_insert_with(|| (decl, Default::default())) .1 .insert(id.into(), *i); @@ -53,9 +53,9 @@ pub(crate) fn collect<'tcx>(tcx: TyCtxt<'tcx>, LocalCrate: LocalCrate) -> EiiMap // if we find a new declaration, add it to the list without a known implementation if let Some(decl) = - find_attr!(tcx.get_all_attrs(id), AttributeKind::EiiExternTarget(d) => *d) + find_attr!(tcx.get_all_attrs(id), AttributeKind::EiiDeclaration(d) => *d) { - eiis.entry(decl.eii_extern_target).or_insert((decl, Default::default())); + eiis.entry(decl.foreign_item).or_insert((decl, Default::default())); } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index f8610f0c5b03..c7423386a771 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1536,7 +1536,7 @@ impl<'a> CrateMetadataRef<'a> { .get((self, tcx), id) .unwrap() .decode((self, tcx)); - ast::MacroDef { macro_rules, body: Box::new(body), eii_extern_target: None } + ast::MacroDef { macro_rules, body: Box::new(body), eii_declaration: None } } _ => bug!(), } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 26f60c96aed6..cdcdaa342a5d 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2283,7 +2283,7 @@ impl<'a> Parser<'a> { self.psess.gated_spans.gate(sym::decl_macro, lo.to(self.prev_token.span)); Ok(ItemKind::MacroDef( ident, - ast::MacroDef { body, macro_rules: false, eii_extern_target: None }, + ast::MacroDef { body, macro_rules: false, eii_declaration: None }, )) } @@ -2333,7 +2333,7 @@ impl<'a> Parser<'a> { Ok(ItemKind::MacroDef( ident, - ast::MacroDef { body, macro_rules: true, eii_extern_target: None }, + ast::MacroDef { body, macro_rules: true, eii_declaration: None }, )) } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 717a0e54d0c6..beae0efa927f 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -224,7 +224,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_rustc_must_implement_one_of(*attr_span, fn_names, hir_id,target) }, Attribute::Parsed( - AttributeKind::EiiExternTarget { .. } + AttributeKind::EiiDeclaration { .. } | AttributeKind::EiiExternItem | AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect @@ -553,7 +553,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } if let EiiImplResolution::Macro(eii_macro) = resolution - && find_attr!(self.tcx.get_all_attrs(*eii_macro), AttributeKind::EiiExternTarget(EiiDecl { impl_unsafe, .. }) if *impl_unsafe) + && find_attr!(self.tcx.get_all_attrs(*eii_macro), AttributeKind::EiiDeclaration(EiiDecl { impl_unsafe, .. }) if *impl_unsafe) && !impl_marked_unsafe { self.dcx().emit_err(errors::EiiImplRequiresUnsafe { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 4d2ba73c9cab..6d0097631772 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1079,7 +1079,7 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc self.smart_resolve_path( *node_id, &None, - &target.extern_item_path, + &target.foreign_item, PathSource::Expr(None), ); } else { @@ -2931,8 +2931,8 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.parent_scope.macro_rules = self.r.macro_rules_scopes[&def_id]; } - if let Some(EiiExternTarget { extern_item_path, impl_unsafe: _ }) = - ¯o_def.eii_extern_target + if let Some(EiiDecl { foreign_item: extern_item_path, impl_unsafe: _ }) = + ¯o_def.eii_declaration { self.smart_resolve_path( item.id, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index b473d36a45fc..d5a46bc02f1a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -935,7 +935,7 @@ symbols! { eh_catch_typeinfo, eh_personality, eii, - eii_extern_target, + eii_declaration, eii_impl, eii_internals, eii_shared_macro, diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 338c5688bf10..a437a4795481 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1912,7 +1912,7 @@ pub(crate) mod builtin { /// Impl detail of EII #[unstable(feature = "eii_internals", issue = "none")] #[rustc_builtin_macro] - pub macro eii_extern_target($item:item) { + pub macro eii_declaration($item:item) { /* compiler built-in */ } } diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index a5d9a5352dfc..7e0a84df5118 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -122,4 +122,4 @@ pub use crate::macros::builtin::define_opaque; pub use crate::macros::builtin::{eii, unsafe_eii}; #[unstable(feature = "eii_internals", issue = "none")] -pub use crate::macros::builtin::eii_extern_target; +pub use crate::macros::builtin::eii_declaration; diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 63f75ea8a881..0f0841379b29 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -114,7 +114,7 @@ pub use core::prelude::v1::define_opaque; pub use core::prelude::v1::{eii, unsafe_eii}; #[unstable(feature = "eii_internals", issue = "none")] -pub use core::prelude::v1::eii_extern_target; +pub use core::prelude::v1::eii_declaration; // The file so far is equivalent to core/src/prelude/v1.rs. It is duplicated // rather than glob imported because we want docs to show these re-exports as diff --git a/tests/ui/eii/errors.rs b/tests/ui/eii/errors.rs index d59850a7d5f5..5fcf33336b40 100644 --- a/tests/ui/eii/errors.rs +++ b/tests/ui/eii/errors.rs @@ -5,19 +5,19 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[eii_extern_target(bar)] //~ ERROR `#[eii_extern_target(...)]` is only valid on macros +#[eii_declaration(bar)] //~ ERROR `#[eii_declaration(...)]` is only valid on macros fn hello() { - #[eii_extern_target(bar)] //~ ERROR `#[eii_extern_target(...)]` is only valid on macros + #[eii_declaration(bar)] //~ ERROR `#[eii_declaration(...)]` is only valid on macros let x = 3 + 3; } -#[eii_extern_target] //~ ERROR `#[eii_extern_target(...)]` expects a list of one or two elements -#[eii_extern_target()] //~ ERROR `#[eii_extern_target(...)]` expects a list of one or two elements -#[eii_extern_target(bar, hello)] //~ ERROR expected this argument to be "unsafe" -#[eii_extern_target(bar, "unsafe", hello)] //~ ERROR `#[eii_extern_target(...)]` expects a list of one or two elements -#[eii_extern_target(bar, hello, "unsafe")] //~ ERROR `#[eii_extern_target(...)]` expects a list of one or two elements -#[eii_extern_target = "unsafe"] //~ ERROR `#[eii_extern_target(...)]` expects a list of one or two elements -#[eii_extern_target(bar)] +#[eii_declaration] //~ ERROR `#[eii_declaration(...)]` expects a list of one or two elements +#[eii_declaration()] //~ ERROR `#[eii_declaration(...)]` expects a list of one or two elements +#[eii_declaration(bar, hello)] //~ ERROR expected this argument to be "unsafe" +#[eii_declaration(bar, "unsafe", hello)] //~ ERROR `#[eii_declaration(...)]` expects a list of one or two elements +#[eii_declaration(bar, hello, "unsafe")] //~ ERROR `#[eii_declaration(...)]` expects a list of one or two elements +#[eii_declaration = "unsafe"] //~ ERROR `#[eii_declaration(...)]` expects a list of one or two elements +#[eii_declaration(bar)] #[rustc_builtin_macro(eii_shared_macro)] macro foo() {} diff --git a/tests/ui/eii/errors.stderr b/tests/ui/eii/errors.stderr index c3b51421f295..c7eb96a9c219 100644 --- a/tests/ui/eii/errors.stderr +++ b/tests/ui/eii/errors.stderr @@ -1,56 +1,56 @@ -error: `#[eii_extern_target(...)]` is only valid on macros +error: `#[eii_declaration(...)]` is only valid on macros --> $DIR/errors.rs:8:1 | -LL | #[eii_extern_target(bar)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[eii_declaration(bar)] + | ^^^^^^^^^^^^^^^^^^^^^^^ -error: `#[eii_extern_target(...)]` is only valid on macros +error: `#[eii_declaration(...)]` is only valid on macros --> $DIR/errors.rs:10:5 | -LL | #[eii_extern_target(bar)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[eii_declaration(bar)] + | ^^^^^^^^^^^^^^^^^^^^^^^ -error: `#[eii_extern_target(...)]` expects a list of one or two elements +error: `#[eii_declaration(...)]` expects a list of one or two elements --> $DIR/errors.rs:14:1 | -LL | #[eii_extern_target] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #[eii_declaration] + | ^^^^^^^^^^^^^^^^^^ -error: `#[eii_extern_target(...)]` expects a list of one or two elements +error: `#[eii_declaration(...)]` expects a list of one or two elements --> $DIR/errors.rs:15:1 | -LL | #[eii_extern_target()] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #[eii_declaration()] + | ^^^^^^^^^^^^^^^^^^^^ error: expected this argument to be "unsafe" - --> $DIR/errors.rs:16:26 + --> $DIR/errors.rs:16:24 | -LL | #[eii_extern_target(bar, hello)] - | ^^^^^ +LL | #[eii_declaration(bar, hello)] + | ^^^^^ | note: the second argument is optional - --> $DIR/errors.rs:16:26 + --> $DIR/errors.rs:16:24 | -LL | #[eii_extern_target(bar, hello)] - | ^^^^^ +LL | #[eii_declaration(bar, hello)] + | ^^^^^ -error: `#[eii_extern_target(...)]` expects a list of one or two elements +error: `#[eii_declaration(...)]` expects a list of one or two elements --> $DIR/errors.rs:17:1 | -LL | #[eii_extern_target(bar, "unsafe", hello)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[eii_declaration(bar, "unsafe", hello)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `#[eii_extern_target(...)]` expects a list of one or two elements +error: `#[eii_declaration(...)]` expects a list of one or two elements --> $DIR/errors.rs:18:1 | -LL | #[eii_extern_target(bar, hello, "unsafe")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[eii_declaration(bar, hello, "unsafe")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `#[eii_extern_target(...)]` expects a list of one or two elements +error: `#[eii_declaration(...)]` expects a list of one or two elements --> $DIR/errors.rs:19:1 | -LL | #[eii_extern_target = "unsafe"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[eii_declaration = "unsafe"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[foo]` is only valid on functions --> $DIR/errors.rs:28:1 diff --git a/tests/ui/eii/type_checking/auxiliary/cross_crate_eii_declaration.rs b/tests/ui/eii/type_checking/auxiliary/cross_crate_eii_declaration.rs index 40d0222082d5..95ae5d923b60 100644 --- a/tests/ui/eii/type_checking/auxiliary/cross_crate_eii_declaration.rs +++ b/tests/ui/eii/type_checking/auxiliary/cross_crate_eii_declaration.rs @@ -5,7 +5,7 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[eii_extern_target(bar)] +#[eii_declaration(bar)] #[rustc_builtin_macro(eii_shared_macro)] pub macro foo() {} diff --git a/tests/ui/eii/type_checking/subtype_1.rs b/tests/ui/eii/type_checking/subtype_1.rs index dfb998aa6f66..d853bc4e7e3d 100644 --- a/tests/ui/eii/type_checking/subtype_1.rs +++ b/tests/ui/eii/type_checking/subtype_1.rs @@ -6,7 +6,7 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[eii_extern_target(bar)] +#[eii_declaration(bar)] #[rustc_builtin_macro(eii_shared_macro)] macro foo() {} diff --git a/tests/ui/eii/type_checking/subtype_2.rs b/tests/ui/eii/type_checking/subtype_2.rs index 5f0c5553fccc..d2b2eb073de2 100644 --- a/tests/ui/eii/type_checking/subtype_2.rs +++ b/tests/ui/eii/type_checking/subtype_2.rs @@ -6,7 +6,7 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[eii_extern_target(bar)] +#[eii_declaration(bar)] #[rustc_builtin_macro(eii_shared_macro)] macro foo() {} diff --git a/tests/ui/eii/type_checking/subtype_3.rs b/tests/ui/eii/type_checking/subtype_3.rs index 269bc84df744..458bacf4a772 100644 --- a/tests/ui/eii/type_checking/subtype_3.rs +++ b/tests/ui/eii/type_checking/subtype_3.rs @@ -7,7 +7,7 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[eii_extern_target(bar)] +#[eii_declaration(bar)] #[rustc_builtin_macro(eii_shared_macro)] macro foo() {} diff --git a/tests/ui/eii/type_checking/subtype_4.rs b/tests/ui/eii/type_checking/subtype_4.rs index e9194df7584c..6f1e4253dd73 100644 --- a/tests/ui/eii/type_checking/subtype_4.rs +++ b/tests/ui/eii/type_checking/subtype_4.rs @@ -7,7 +7,7 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[eii_extern_target(bar)] +#[eii_declaration(bar)] #[rustc_builtin_macro(eii_shared_macro)] macro foo() {} diff --git a/tests/ui/eii/type_checking/wrong_ret_ty.rs b/tests/ui/eii/type_checking/wrong_ret_ty.rs index 5fe7d2f8bb62..8ee81a4f2465 100644 --- a/tests/ui/eii/type_checking/wrong_ret_ty.rs +++ b/tests/ui/eii/type_checking/wrong_ret_ty.rs @@ -5,7 +5,7 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[eii_extern_target(bar)] +#[eii_declaration(bar)] #[rustc_builtin_macro(eii_shared_macro)] macro foo() {} diff --git a/tests/ui/eii/type_checking/wrong_ty.rs b/tests/ui/eii/type_checking/wrong_ty.rs index ebb756f6a314..625af6e11dbf 100644 --- a/tests/ui/eii/type_checking/wrong_ty.rs +++ b/tests/ui/eii/type_checking/wrong_ty.rs @@ -5,7 +5,7 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[eii_extern_target(bar)] +#[eii_declaration(bar)] #[rustc_builtin_macro(eii_shared_macro)] macro foo() {} diff --git a/tests/ui/eii/type_checking/wrong_ty_2.rs b/tests/ui/eii/type_checking/wrong_ty_2.rs index d55f405bf157..2e477b5b6fcc 100644 --- a/tests/ui/eii/type_checking/wrong_ty_2.rs +++ b/tests/ui/eii/type_checking/wrong_ty_2.rs @@ -5,7 +5,7 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[eii_extern_target(bar)] +#[eii_declaration(bar)] #[rustc_builtin_macro(eii_shared_macro)] macro foo() {} diff --git a/tests/ui/eii/unsafe_impl_err.rs b/tests/ui/eii/unsafe_impl_err.rs index 6af7e9724e15..a6d24c47ae21 100644 --- a/tests/ui/eii/unsafe_impl_err.rs +++ b/tests/ui/eii/unsafe_impl_err.rs @@ -5,7 +5,7 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[eii_extern_target(bar, "unsafe")] +#[eii_declaration(bar, "unsafe")] #[rustc_builtin_macro(eii_shared_macro)] macro foo() {} diff --git a/tests/ui/eii/unsafe_impl_ok.rs b/tests/ui/eii/unsafe_impl_ok.rs index 268c5bc16fd8..1af6d63eb7cf 100644 --- a/tests/ui/eii/unsafe_impl_ok.rs +++ b/tests/ui/eii/unsafe_impl_ok.rs @@ -7,7 +7,7 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] -#[eii_extern_target(bar, "unsafe")] +#[eii_declaration(bar, "unsafe")] #[rustc_builtin_macro(eii_shared_macro)] macro foo() {} diff --git a/tests/ui/feature-gates/feature-gate-eii-internals.rs b/tests/ui/feature-gates/feature-gate-eii-internals.rs index b70e007ed798..96699f2905b6 100644 --- a/tests/ui/feature-gates/feature-gate-eii-internals.rs +++ b/tests/ui/feature-gates/feature-gate-eii-internals.rs @@ -2,7 +2,7 @@ #![feature(decl_macro)] #![feature(rustc_attrs)] -#[eii_extern_target(bar)] //~ ERROR use of unstable library feature `eii_internals` +#[eii_declaration(bar)] //~ ERROR use of unstable library feature `eii_internals` #[rustc_builtin_macro(eii_macro)] macro foo() {} //~ ERROR: cannot find a built-in macro with name `foo` diff --git a/tests/ui/feature-gates/feature-gate-eii-internals.stderr b/tests/ui/feature-gates/feature-gate-eii-internals.stderr index f08f0a5e65b3..78aa49ebab1c 100644 --- a/tests/ui/feature-gates/feature-gate-eii-internals.stderr +++ b/tests/ui/feature-gates/feature-gate-eii-internals.stderr @@ -1,8 +1,8 @@ error[E0658]: use of unstable library feature `eii_internals` --> $DIR/feature-gate-eii-internals.rs:5:3 | -LL | #[eii_extern_target(bar)] - | ^^^^^^^^^^^^^^^^^ +LL | #[eii_declaration(bar)] + | ^^^^^^^^^^^^^^^ | = help: add `#![feature(eii_internals)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date From 6d0f23adad84c37863de550a878f84dd9e3bb1fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sat, 10 Jan 2026 11:26:20 +0100 Subject: [PATCH 0579/1061] rename extern item to foreign item --- .../rustc_attr_parsing/src/attributes/codegen_attrs.rs | 8 ++++---- compiler/rustc_attr_parsing/src/context.rs | 4 ++-- compiler/rustc_builtin_macros/src/eii.rs | 4 ++-- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 2 +- compiler/rustc_feature/src/builtin_attrs.rs | 2 +- compiler/rustc_hir/src/attrs/data_structures.rs | 2 +- compiler/rustc_hir/src/attrs/encode_cross_crate.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 2 +- compiler/rustc_span/src/symbol.rs | 2 +- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index c68c66b27185..5bbaeda18df3 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -709,11 +709,11 @@ impl NoArgsAttributeParser for RustcPassIndirectlyInNonRusticAbisPa const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassIndirectlyInNonRusticAbis; } -pub(crate) struct EiiExternItemParser; +pub(crate) struct EiiForeignItemParser; -impl NoArgsAttributeParser for EiiExternItemParser { - const PATH: &[Symbol] = &[sym::rustc_eii_extern_item]; +impl NoArgsAttributeParser for EiiForeignItemParser { + const PATH: &[Symbol] = &[sym::rustc_eii_foreign_item]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]); - const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::EiiExternItem; + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::EiiForeignItem; } diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 835bf8ae5c9c..00921cf54cd8 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -21,7 +21,7 @@ use crate::attributes::allow_unstable::{ use crate::attributes::body::CoroutineParser; use crate::attributes::cfi_encoding::CfiEncodingParser; use crate::attributes::codegen_attrs::{ - ColdParser, CoverageParser, EiiExternItemParser, ExportNameParser, ForceTargetFeatureParser, + ColdParser, CoverageParser, EiiForeignItemParser, ExportNameParser, ForceTargetFeatureParser, NakedParser, NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser, RustcPassIndirectlyInNonRusticAbisParser, SanitizeParser, TargetFeatureParser, ThreadLocalParser, TrackCallerParser, UsedParser, @@ -243,7 +243,7 @@ attribute_parsers!( Single>, Single>, Single>, - Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index e8aeb8090bf4..cec7599d68e9 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -295,9 +295,9 @@ fn generate_foreign_item( let mut foreign_item_attrs = ThinVec::new(); foreign_item_attrs.extend_from_slice(attrs_from_decl); - // Add the rustc_eii_extern_item on the foreign item. Usually, foreign items are mangled. + // Add the rustc_eii_foreign_item on the foreign item. Usually, foreign items are mangled. // This attribute makes sure that we later know that this foreign item's symbol should not be. - foreign_item_attrs.push(ecx.attr_word(sym::rustc_eii_extern_item, eii_attr_span)); + foreign_item_attrs.push(ecx.attr_word(sym::rustc_eii_foreign_item, eii_attr_span)); let abi = match func.sig.header.ext { // extern "X" fn => extern "X" {} diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index db150faea86d..fa02c5c51f7c 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -282,7 +282,7 @@ fn process_builtin_attrs( AttributeKind::ObjcSelector { methname, .. } => { codegen_fn_attrs.objc_selector = Some(*methname); } - AttributeKind::EiiExternItem => { + AttributeKind::EiiForeignItem => { codegen_fn_attrs.flags |= CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM; } AttributeKind::EiiImpls(impls) => { diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index a7e8515e415f..22753adb4c99 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -962,7 +962,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ EncodeCrossCrate::No, "allow_internal_unsafe side-steps the unsafe_code lint", ), gated!( - rustc_eii_extern_item, Normal, template!(Word), + rustc_eii_foreign_item, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, eii_internals, "used internally to mark types with a `transparent` representation when it is guaranteed by the documentation", ), diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index c6c50bb793f8..15a668bd9199 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -747,7 +747,7 @@ pub enum AttributeKind { EiiDeclaration(EiiDecl), /// Implementation detail of `#[eii]` - EiiExternItem, + EiiForeignItem, /// Implementation detail of `#[eii]` EiiImpls(ThinVec), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index d854cc34c0f3..233aee54adbb 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -48,7 +48,7 @@ impl AttributeKind { DocComment { .. } => Yes, Dummy => No, EiiDeclaration(_) => Yes, - EiiExternItem => No, + EiiForeignItem => No, EiiImpls(..) => No, ExportName { .. } => Yes, ExportStable => No, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index beae0efa927f..1d48785169d7 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -225,7 +225,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { }, Attribute::Parsed( AttributeKind::EiiDeclaration { .. } - | AttributeKind::EiiExternItem + | AttributeKind::EiiForeignItem | AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect | AttributeKind::MacroTransparency(_) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d5a46bc02f1a..f56c3421ce0f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1951,7 +1951,7 @@ symbols! { rustc_dump_user_args, rustc_dump_vtable, rustc_effective_visibility, - rustc_eii_extern_item, + rustc_eii_foreign_item, rustc_evaluate_where_clauses, rustc_expected_cgu_reuse, rustc_force_inline, From b327e309b9dba5f3fadc3fc9d2b3bc0ca9e1b747 Mon Sep 17 00:00:00 2001 From: Leon Schuermann Date: Mon, 12 Jan 2026 03:16:27 -0500 Subject: [PATCH 0580/1061] core: ptr: split_at_mut: fix typo in safety doc Removes the double subject "it" in the safety documentation of `core::ptr::split_at_mut` for raw slice pointers, as it does not refer to anything. Reported-by: Johnathan Van Why --- library/core/src/ptr/mut_ptr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 8976154c61db..11e0a83bd7ec 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1742,7 +1742,7 @@ impl *mut [T] { /// that is at least `mid * size_of::()` bytes long. Not upholding these /// requirements is *[undefined behavior]* even if the resulting pointers are not used. /// - /// Since `len` being in-bounds it is not a safety invariant of `*mut [T]` the + /// Since `len` being in-bounds is not a safety invariant of `*mut [T]` the /// safety requirements of this method are the same as for [`split_at_mut_unchecked`]. /// The explicit bounds check is only as useful as `len` is correct. /// From 3ca709c7450317aa465e5193965e31204b39cb04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 12 Jan 2026 09:57:05 +0100 Subject: [PATCH 0581/1061] Remove `S-waiting-on-bors` after a PR is merged --- rust-bors.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rust-bors.toml b/rust-bors.toml index 0d59918e3f77..ad1100fd2421 100644 --- a/rust-bors.toml +++ b/rust-bors.toml @@ -55,7 +55,8 @@ try_failed = [ "-S-waiting-on-crater" ] auto_build_succeeded = [ - "+merged-by-bors" + "+merged-by-bors", + "-S-waiting-on-bors" ] auto_build_failed = [ "+S-waiting-on-review", From 284d1361e4cffeaafad6c5d9c31acf823cc4a43f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 25 Aug 2025 16:21:17 +0200 Subject: [PATCH 0582/1061] Dogfood `-Zno-embed-metadata` for the standard library --- src/bootstrap/src/core/build_steps/compile.rs | 10 +++++++++- src/bootstrap/src/core/builder/cargo.rs | 4 ++++ tests/ui/error-codes/E0152-duplicate-lang-items.rs | 2 +- tests/ui/error-codes/E0152-duplicate-lang-items.stderr | 2 +- tests/ui/error-codes/E0152.rs | 2 +- tests/ui/error-codes/E0152.stderr | 2 +- tests/ui/lang-items/duplicate.rs | 2 +- tests/ui/lang-items/duplicate.stderr | 2 +- tests/ui/panic-handler/panic-handler-std.rs | 2 +- tests/ui/panic-handler/panic-handler-std.stderr | 2 +- 10 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 2808c29cc6c0..4b13776bcf39 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -299,7 +299,8 @@ impl Step for Std { if self.is_for_mir_opt_tests { ArtifactKeepMode::OnlyRmeta } else { - ArtifactKeepMode::OnlyRlib + // We use -Zno-embed-metadata for the standard library + ArtifactKeepMode::BothRlibAndRmeta }, ); @@ -2645,6 +2646,10 @@ pub enum ArtifactKeepMode { OnlyRlib, /// Only keep .rmeta files, ignore .rlib files OnlyRmeta, + /// Keep both .rlib and .rmeta files. + /// This is essentially only useful when using `-Zno-embed-metadata`, in which case both the + /// .rlib and .rmeta files are needed for compilation/linking. + BothRlibAndRmeta, /// Custom logic for keeping an artifact /// It receives the filename of an artifact, and returns true if it should be kept. Custom(Box bool>), @@ -2701,6 +2706,9 @@ pub fn run_cargo( match &artifact_keep_mode { ArtifactKeepMode::OnlyRlib => filename.ends_with(".rlib"), ArtifactKeepMode::OnlyRmeta => filename.ends_with(".rmeta"), + ArtifactKeepMode::BothRlibAndRmeta => { + filename.ends_with(".rmeta") || filename.ends_with(".rlib") + } ArtifactKeepMode::Custom(func) => func(&filename), } }; diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index b95533e11202..dda0b40cb69e 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -1095,6 +1095,10 @@ impl Builder<'_> { // Enable usage of unstable features cargo.env("RUSTC_BOOTSTRAP", "1"); + if matches!(mode, Mode::Std) { + cargo.arg("-Zno-embed-metadata"); + } + if self.config.dump_bootstrap_shims { prepare_behaviour_dump_dir(self.build); diff --git a/tests/ui/error-codes/E0152-duplicate-lang-items.rs b/tests/ui/error-codes/E0152-duplicate-lang-items.rs index f707b72f9b2b..4b243205dc48 100644 --- a/tests/ui/error-codes/E0152-duplicate-lang-items.rs +++ b/tests/ui/error-codes/E0152-duplicate-lang-items.rs @@ -3,7 +3,7 @@ //! //! Issue: -//@ normalize-stderr: "loaded from .*libstd-.*.rlib" -> "loaded from SYSROOT/libstd-*.rlib" +//@ normalize-stderr: "loaded from .*libstd-.*.rmeta" -> "loaded from SYSROOT/libstd-*.rmeta" //@ dont-require-annotations: NOTE #![feature(lang_items)] diff --git a/tests/ui/error-codes/E0152-duplicate-lang-items.stderr b/tests/ui/error-codes/E0152-duplicate-lang-items.stderr index 2fe0d18fc2f4..55d5206b42ce 100644 --- a/tests/ui/error-codes/E0152-duplicate-lang-items.stderr +++ b/tests/ui/error-codes/E0152-duplicate-lang-items.stderr @@ -9,7 +9,7 @@ LL | | } | |_^ | = note: the lang item is first defined in crate `std` (which `E0152_duplicate_lang_items` depends on) - = note: first definition in `std` loaded from SYSROOT/libstd-*.rlib + = note: first definition in `std` loaded from SYSROOT/libstd-*.rmeta = note: second definition in the local crate (`E0152_duplicate_lang_items`) error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0152.rs b/tests/ui/error-codes/E0152.rs index 565e92baf02e..53c7c027eff3 100644 --- a/tests/ui/error-codes/E0152.rs +++ b/tests/ui/error-codes/E0152.rs @@ -1,4 +1,4 @@ -//@ normalize-stderr: "loaded from .*liballoc-.*.rlib" -> "loaded from SYSROOT/liballoc-*.rlib" +//@ normalize-stderr: "loaded from .*liballoc-.*.rmeta" -> "loaded from SYSROOT/liballoc-*.rmeta" #![feature(lang_items)] #[lang = "owned_box"] diff --git a/tests/ui/error-codes/E0152.stderr b/tests/ui/error-codes/E0152.stderr index dbea7e6d27fb..73df5803e839 100644 --- a/tests/ui/error-codes/E0152.stderr +++ b/tests/ui/error-codes/E0152.stderr @@ -5,7 +5,7 @@ LL | struct Foo(T); | ^^^^^^^^^^^^^^^^^ | = note: the lang item is first defined in crate `alloc` (which `std` depends on) - = note: first definition in `alloc` loaded from SYSROOT/liballoc-*.rlib + = note: first definition in `alloc` loaded from SYSROOT/liballoc-*.rmeta = note: second definition in the local crate (`E0152`) error: aborting due to 1 previous error diff --git a/tests/ui/lang-items/duplicate.rs b/tests/ui/lang-items/duplicate.rs index 4594e9456a4c..bab952fc9ad1 100644 --- a/tests/ui/lang-items/duplicate.rs +++ b/tests/ui/lang-items/duplicate.rs @@ -1,4 +1,4 @@ -//@ normalize-stderr: "loaded from .*libcore-.*.rlib" -> "loaded from SYSROOT/libcore-*.rlib" +//@ normalize-stderr: "loaded from .*libcore-.*.rmeta" -> "loaded from SYSROOT/libcore-*.rmeta" #![feature(lang_items)] #[lang = "sized"] diff --git a/tests/ui/lang-items/duplicate.stderr b/tests/ui/lang-items/duplicate.stderr index aaa8f5e605af..5639bcc838d8 100644 --- a/tests/ui/lang-items/duplicate.stderr +++ b/tests/ui/lang-items/duplicate.stderr @@ -5,7 +5,7 @@ LL | trait Sized {} | ^^^^^^^^^^^^^^ | = note: the lang item is first defined in crate `core` (which `std` depends on) - = note: first definition in `core` loaded from SYSROOT/libcore-*.rlib + = note: first definition in `core` loaded from SYSROOT/libcore-*.rmeta = note: second definition in the local crate (`duplicate`) error: aborting due to 1 previous error diff --git a/tests/ui/panic-handler/panic-handler-std.rs b/tests/ui/panic-handler/panic-handler-std.rs index f6a4b60461ce..4d4e20037aaa 100644 --- a/tests/ui/panic-handler/panic-handler-std.rs +++ b/tests/ui/panic-handler/panic-handler-std.rs @@ -1,4 +1,4 @@ -//@ normalize-stderr: "loaded from .*libstd-.*.rlib" -> "loaded from SYSROOT/libstd-*.rlib" +//@ normalize-stderr: "loaded from .*libstd-.*.rmeta" -> "loaded from SYSROOT/libstd-*.rmeta" extern crate core; diff --git a/tests/ui/panic-handler/panic-handler-std.stderr b/tests/ui/panic-handler/panic-handler-std.stderr index 48c216ce27ec..3c4426782233 100644 --- a/tests/ui/panic-handler/panic-handler-std.stderr +++ b/tests/ui/panic-handler/panic-handler-std.stderr @@ -7,7 +7,7 @@ LL | | } | |_^ | = note: the lang item is first defined in crate `std` (which `panic_handler_std` depends on) - = note: first definition in `std` loaded from SYSROOT/libstd-*.rlib + = note: first definition in `std` loaded from SYSROOT/libstd-*.rmeta = note: second definition in the local crate (`panic_handler_std`) error: aborting due to 1 previous error From e03cb1f0a6d99d0874a4f88066d6217dfcd22d8b Mon Sep 17 00:00:00 2001 From: Akshit Gaur <119689115+akshitgaur2005@users.noreply.github.com> Date: Fri, 2 Jan 2026 14:52:50 +0530 Subject: [PATCH 0583/1061] run-make-support: resolve .rmeta companion for .rlib stubs Add .rmeta resolution for run-make/sysroot-crates-are-unstable test --- .../sysroot-crates-are-unstable/rmake.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/tests/run-make/sysroot-crates-are-unstable/rmake.rs b/tests/run-make/sysroot-crates-are-unstable/rmake.rs index 623b9650771c..3b75e4d90d96 100644 --- a/tests/run-make/sysroot-crates-are-unstable/rmake.rs +++ b/tests/run-make/sysroot-crates-are-unstable/rmake.rs @@ -28,13 +28,17 @@ fn check_crate_is_unstable(cr: &Crate) { print!("- Verifying that sysroot crate '{name}' is an unstable crate ..."); - // Trying to use this crate from a user program should fail. - let output = rustc() - .crate_type("rlib") - .extern_(name, path) - .input("-") - .stdin_buf(format!("extern crate {name};")) - .run_fail(); + // Checking if rmeta path exists + let rmeta_path = path.with_extension("rmeta"); + + let mut cmd = rustc(); + cmd.crate_type("rlib").extern_(name, path); // Pass the rlib + + if rmeta_path.exists() { + cmd.extern_(name, &rmeta_path); + } + + let output = cmd.input("-").stdin_buf(format!("extern crate {name};")).run_fail(); // Make sure it failed for the intended reason, not some other reason. // (The actual feature required varies between crates.) From 6ca950136de7abd91cc1820b5a7f7109fe568016 Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Mon, 12 Jan 2026 11:03:04 +0100 Subject: [PATCH 0584/1061] Relax test expectation for @__llvm_profile_runtime_user After https://github.com/llvm/llvm-project/pull/174174 it has profile info marking it cold. --- tests/codegen-llvm/instrument-coverage/testprog.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/codegen-llvm/instrument-coverage/testprog.rs b/tests/codegen-llvm/instrument-coverage/testprog.rs index 9e918499d577..ef61ede6de8e 100644 --- a/tests/codegen-llvm/instrument-coverage/testprog.rs +++ b/tests/codegen-llvm/instrument-coverage/testprog.rs @@ -109,7 +109,7 @@ fn main() { // CHECK: declare void @llvm.instrprof.increment(ptr, i64, i32, i32) #[[LLVM_INSTRPROF_INCREMENT_ATTR:[0-9]+]] -// WIN: define linkonce_odr hidden i32 @__llvm_profile_runtime_user() #[[LLVM_PROFILE_RUNTIME_USER_ATTR:[0-9]+]] comdat { +// WIN: define linkonce_odr hidden i32 @__llvm_profile_runtime_user() #[[LLVM_PROFILE_RUNTIME_USER_ATTR:[0-9]+]] comdat {{.*}}{ // WIN-NEXT: %1 = load i32, ptr @__llvm_profile_runtime // WIN-NEXT: ret i32 %1 // WIN-NEXT: } From ac80ccec5f5999e7251474380661be5a84e56683 Mon Sep 17 00:00:00 2001 From: dianqk Date: Sat, 10 Jan 2026 20:10:18 +0800 Subject: [PATCH 0585/1061] Only use SSA locals in SimplifyComparisonIntegral --- compiler/rustc_middle/src/mir/statement.rs | 6 ++++ .../src/simplify_comparison_integral.rs | 31 ++++++++++++------- ...on_ssa_cmp.SimplifyComparisonIntegral.diff | 3 +- ..._ssa_place.SimplifyComparisonIntegral.diff | 3 +- ...ssa_switch.SimplifyComparisonIntegral.diff | 3 +- tests/mir-opt/if_condition_int.rs | 24 ++++++++++++++ 6 files changed, 52 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index c1f8c46baddb..adaac3d7ffc2 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -374,6 +374,12 @@ impl<'tcx> Place<'tcx> { self.projection.iter().any(|elem| elem.is_indirect()) } + /// Returns `true` if the `Place` always refers to the same memory region + /// whatever the state of the program. + pub fn is_stable_offset(&self) -> bool { + self.projection.iter().all(|elem| elem.is_stable_offset()) + } + /// Returns `true` if this `Place`'s first projection is `Deref`. /// /// This is useful because for MIR phases `AnalysisPhase::PostCleanup` and later, diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs index 2643d78990e5..53a796b1179a 100644 --- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs +++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs @@ -9,6 +9,8 @@ use rustc_middle::mir::{ use rustc_middle::ty::{Ty, TyCtxt}; use tracing::trace; +use crate::ssa::SsaLocals; + /// Pass to convert `if` conditions on integrals into switches on the integral. /// For an example, it turns something like /// @@ -33,11 +35,12 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { trace!("Running SimplifyComparisonIntegral on {:?}", body.source); + let typing_env = body.typing_env(tcx); + let ssa = SsaLocals::new(tcx, body, typing_env); let helper = OptimizationFinder { body }; - let opts = helper.find_optimizations(); + let opts = helper.find_optimizations(&ssa); let mut storage_deads_to_insert = vec![]; let mut storage_deads_to_remove: Vec<(usize, BasicBlock)> = vec![]; - let typing_env = body.typing_env(tcx); for opt in opts { trace!("SUCCESS: Applying {:?}", opt); // replace terminator with a switchInt that switches on the integer directly @@ -154,19 +157,18 @@ struct OptimizationFinder<'a, 'tcx> { } impl<'tcx> OptimizationFinder<'_, 'tcx> { - fn find_optimizations(&self) -> Vec> { + fn find_optimizations(&self, ssa: &SsaLocals) -> Vec> { self.body .basic_blocks .iter_enumerated() .filter_map(|(bb_idx, bb)| { // find switch - let (place_switched_on, targets, place_switched_on_moved) = - match &bb.terminator().kind { - rustc_middle::mir::TerminatorKind::SwitchInt { discr, targets, .. } => { - Some((discr.place()?, targets, discr.is_move())) - } - _ => None, - }?; + let (discr, targets) = bb.terminator().kind.as_switch()?; + let place_switched_on = discr.place()?; + // Make sure that the place is not modified. + if !ssa.is_ssa(place_switched_on.local) || !place_switched_on.is_stable_offset() { + return None; + } // find the statement that assigns the place being switched on bb.statements.iter().enumerate().rev().find_map(|(stmt_idx, stmt)| { @@ -180,12 +182,12 @@ impl<'tcx> OptimizationFinder<'_, 'tcx> { box (left, right), ) => { let (branch_value_scalar, branch_value_ty, to_switch_on) = - find_branch_value_info(left, right)?; + find_branch_value_info(left, right, ssa)?; Some(OptimizationInfo { bin_op_stmt_idx: stmt_idx, bb_idx, - can_remove_bin_op_stmt: place_switched_on_moved, + can_remove_bin_op_stmt: discr.is_move(), to_switch_on, branch_value_scalar, branch_value_ty, @@ -207,6 +209,7 @@ impl<'tcx> OptimizationFinder<'_, 'tcx> { fn find_branch_value_info<'tcx>( left: &Operand<'tcx>, right: &Operand<'tcx>, + ssa: &SsaLocals, ) -> Option<(Scalar, Ty<'tcx>, Place<'tcx>)> { // check that either left or right is a constant. // if any are, we can use the other to switch on, and the constant as a value in a switch @@ -214,6 +217,10 @@ fn find_branch_value_info<'tcx>( match (left, right) { (Constant(branch_value), Copy(to_switch_on) | Move(to_switch_on)) | (Copy(to_switch_on) | Move(to_switch_on), Constant(branch_value)) => { + // Make sure that the place is not modified. + if !ssa.is_ssa(to_switch_on.local) || !to_switch_on.is_stable_offset() { + return None; + } let branch_value_ty = branch_value.const_.ty(); // we only want to apply this optimization if we are matching on integrals (and chars), // as it is not possible to switch on floats diff --git a/tests/mir-opt/if_condition_int.on_non_ssa_cmp.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.on_non_ssa_cmp.SimplifyComparisonIntegral.diff index d0983c660623..ce5a2bf172a9 100644 --- a/tests/mir-opt/if_condition_int.on_non_ssa_cmp.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/if_condition_int.on_non_ssa_cmp.SimplifyComparisonIntegral.diff @@ -8,8 +8,7 @@ bb0: { _2 = Eq(copy _1, const 42_u64); _1 = const 43_u64; -- switchInt(copy _2) -> [1: bb1, otherwise: bb2]; -+ switchInt(move _1) -> [42: bb1, otherwise: bb2]; + switchInt(copy _2) -> [1: bb1, otherwise: bb2]; } bb1: { diff --git a/tests/mir-opt/if_condition_int.on_non_ssa_place.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.on_non_ssa_place.SimplifyComparisonIntegral.diff index 0c6c8dca4753..7ad0a87f1cdd 100644 --- a/tests/mir-opt/if_condition_int.on_non_ssa_place.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/if_condition_int.on_non_ssa_place.SimplifyComparisonIntegral.diff @@ -8,8 +8,7 @@ bb0: { _3 = Eq(copy _1[_2], const 42_u64); _2 = const 10_usize; -- switchInt(copy _3) -> [1: bb1, otherwise: bb2]; -+ switchInt(move _1[_2]) -> [42: bb1, otherwise: bb2]; + switchInt(copy _3) -> [1: bb1, otherwise: bb2]; } bb1: { diff --git a/tests/mir-opt/if_condition_int.on_non_ssa_switch.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.on_non_ssa_switch.SimplifyComparisonIntegral.diff index b1b1ab2c2205..e2dc97f76b5c 100644 --- a/tests/mir-opt/if_condition_int.on_non_ssa_switch.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/if_condition_int.on_non_ssa_switch.SimplifyComparisonIntegral.diff @@ -8,8 +8,7 @@ bb0: { _2 = Eq(copy _1, const 42_u64); _2 = const false; -- switchInt(copy _2) -> [1: bb1, otherwise: bb2]; -+ switchInt(move _1) -> [42: bb1, otherwise: bb2]; + switchInt(copy _2) -> [1: bb1, otherwise: bb2]; } bb1: { diff --git a/tests/mir-opt/if_condition_int.rs b/tests/mir-opt/if_condition_int.rs index ba901f6b9b15..b49f8768253a 100644 --- a/tests/mir-opt/if_condition_int.rs +++ b/tests/mir-opt/if_condition_int.rs @@ -120,6 +120,14 @@ fn dont_opt_floats(a: f32) -> i32 { // EMIT_MIR if_condition_int.on_non_ssa_switch.SimplifyComparisonIntegral.diff #[custom_mir(dialect = "runtime")] pub fn on_non_ssa_switch(mut v: u64) -> i32 { + // CHECK-LABEL: fn on_non_ssa_switch( + // CHECK: [[cmp:_.*]] = Eq(copy _1, const 42_u64); + // CHECK: [[cmp]] = const false; + // CHECK: switchInt(copy [[cmp]]) -> [1: [[BB1:bb.*]], otherwise: [[BB2:bb.*]]]; + // CHECK: [[BB1]]: + // CHECK: _0 = const 0_i32; + // CHECK: [[BB2]]: + // CHECK: _0 = const 1_i32; mir! { let a: bool; { @@ -145,6 +153,14 @@ pub fn on_non_ssa_switch(mut v: u64) -> i32 { // EMIT_MIR if_condition_int.on_non_ssa_cmp.SimplifyComparisonIntegral.diff #[custom_mir(dialect = "runtime")] pub fn on_non_ssa_cmp(mut v: u64) -> i32 { + // CHECK-LABEL: fn on_non_ssa_cmp( + // CHECK: [[cmp:_.*]] = Eq(copy _1, const 42_u64); + // CHECK: _1 = const 43_u64; + // CHECK: switchInt(copy [[cmp]]) -> [1: [[BB1:bb.*]], otherwise: [[BB2:bb.*]]]; + // CHECK: [[BB1]]: + // CHECK: _0 = const 0_i32; + // CHECK: [[BB2]]: + // CHECK: _0 = const 1_i32; mir! { let a: bool; { @@ -170,6 +186,14 @@ pub fn on_non_ssa_cmp(mut v: u64) -> i32 { // EMIT_MIR if_condition_int.on_non_ssa_place.SimplifyComparisonIntegral.diff #[custom_mir(dialect = "runtime")] pub fn on_non_ssa_place(mut v: [u64; 10], mut i: usize) -> i32 { + // CHECK-LABEL: fn on_non_ssa_place( + // CHECK: [[cmp:_.*]] = Eq(copy _1[_2], const 42_u64); + // CHECK: _2 = const 10_usize; + // CHECK: switchInt(copy [[cmp]]) -> [1: [[BB1:bb.*]], otherwise: [[BB2:bb.*]]]; + // CHECK: [[BB1]]: + // CHECK: _0 = const 0_i32; + // CHECK: [[BB2]]: + // CHECK: _0 = const 1_i32; mir! { let a: bool; { From 37f83fb11d187aea102340b1be20f3f65c4c2cac Mon Sep 17 00:00:00 2001 From: dianqk Date: Sat, 10 Jan 2026 20:27:08 +0800 Subject: [PATCH 0586/1061] Use Copy in the SwitchInt terminator Move can be used only when both the compared operand and the operand on switch are move operands. This commit directly changes to Copy, because I don't know if Move has beneficial. --- .../src/simplify_comparison_integral.rs | 2 +- ..._exponential_common.GVN.32bit.panic-abort.diff | 2 +- ...exponential_common.GVN.32bit.panic-unwind.diff | 2 +- ..._exponential_common.GVN.64bit.panic-abort.diff | 2 +- ...exponential_common.GVN.64bit.panic-unwind.diff | 2 +- ...ove_comparison.SimplifyComparisonIntegral.diff | 2 +- ...n_int.opt_char.SimplifyComparisonIntegral.diff | 2 +- ...ion_int.opt_i8.SimplifyComparisonIntegral.diff | 2 +- ...t_multiple_ifs.SimplifyComparisonIntegral.diff | 4 ++-- ...t.opt_negative.SimplifyComparisonIntegral.diff | 2 +- ...on_int.opt_u32.SimplifyComparisonIntegral.diff | 2 +- tests/mir-opt/if_condition_int.rs | 15 +++++++-------- ...o_digit.PreCodegen.after.32bit.panic-abort.mir | 2 +- ..._digit.PreCodegen.after.32bit.panic-unwind.mir | 2 +- ...o_digit.PreCodegen.after.64bit.panic-abort.mir | 2 +- ..._digit.PreCodegen.after.64bit.panic-unwind.mir | 2 +- 16 files changed, 23 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs index 53a796b1179a..b7445a0f7c2e 100644 --- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs +++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs @@ -135,7 +135,7 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral { let terminator = bb.terminator_mut(); terminator.kind = - TerminatorKind::SwitchInt { discr: Operand::Move(opt.to_switch_on), targets }; + TerminatorKind::SwitchInt { discr: Operand::Copy(opt.to_switch_on), targets }; } for (idx, bb_idx) in storage_deads_to_remove { diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff index 6baa902b6f4b..2b77aa380a0f 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff @@ -74,7 +74,7 @@ _23 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); _22 = BitAnd(move _23, const core::fmt::flags::PRECISION_FLAG); StorageDead(_23); - switchInt(move _22) -> [0: bb10, otherwise: bb11]; + switchInt(copy _22) -> [0: bb10, otherwise: bb11]; } bb4: { diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff index 36540e038654..ba6d2f3e155c 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff @@ -74,7 +74,7 @@ _23 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); _22 = BitAnd(move _23, const core::fmt::flags::PRECISION_FLAG); StorageDead(_23); - switchInt(move _22) -> [0: bb10, otherwise: bb11]; + switchInt(copy _22) -> [0: bb10, otherwise: bb11]; } bb4: { diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff index 41c350f3eaeb..bf6d9d864d57 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff @@ -74,7 +74,7 @@ _23 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); _22 = BitAnd(move _23, const core::fmt::flags::PRECISION_FLAG); StorageDead(_23); - switchInt(move _22) -> [0: bb10, otherwise: bb11]; + switchInt(copy _22) -> [0: bb10, otherwise: bb11]; } bb4: { diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff index b839bf81eaf4..01c87fd5317a 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff @@ -74,7 +74,7 @@ _23 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); _22 = BitAnd(move _23, const core::fmt::flags::PRECISION_FLAG); StorageDead(_23); - switchInt(move _22) -> [0: bb10, otherwise: bb11]; + switchInt(copy _22) -> [0: bb10, otherwise: bb11]; } bb4: { diff --git a/tests/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff index 29d57722355b..f5f2e0317ead 100644 --- a/tests/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff @@ -21,7 +21,7 @@ _2 = Eq(copy _1, const 17_i8); StorageDead(_3); - switchInt(copy _2) -> [0: bb2, otherwise: bb1]; -+ switchInt(move _1) -> [17: bb1, otherwise: bb2]; ++ switchInt(copy _1) -> [17: bb1, otherwise: bb2]; } bb1: { diff --git a/tests/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff index 37b41c2aa5ab..22f6443a6c0f 100644 --- a/tests/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff @@ -14,7 +14,7 @@ - _2 = Eq(copy _1, const 'x'); - switchInt(move _2) -> [0: bb2, otherwise: bb1]; + nop; -+ switchInt(move _1) -> [120: bb1, otherwise: bb2]; ++ switchInt(copy _1) -> [120: bb1, otherwise: bb2]; } bb1: { diff --git a/tests/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff index c92a606090e4..d5c48fd04ca6 100644 --- a/tests/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff @@ -14,7 +14,7 @@ - _2 = Eq(copy _1, const 42_i8); - switchInt(move _2) -> [0: bb2, otherwise: bb1]; + nop; -+ switchInt(move _1) -> [42: bb1, otherwise: bb2]; ++ switchInt(copy _1) -> [42: bb1, otherwise: bb2]; } bb1: { diff --git a/tests/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff index a73670323b1f..84d62b813607 100644 --- a/tests/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff @@ -16,7 +16,7 @@ - _2 = Eq(copy _1, const 42_u32); - switchInt(move _2) -> [0: bb2, otherwise: bb1]; + nop; -+ switchInt(move _1) -> [42: bb1, otherwise: bb2]; ++ switchInt(copy _1) -> [42: bb1, otherwise: bb2]; } bb1: { @@ -33,7 +33,7 @@ - _4 = Ne(copy _1, const 21_u32); - switchInt(move _4) -> [0: bb4, otherwise: bb3]; + nop; -+ switchInt(move _1) -> [21: bb4, otherwise: bb3]; ++ switchInt(copy _1) -> [21: bb4, otherwise: bb3]; } bb3: { diff --git a/tests/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff index 36145ab02bea..a1cbaff796b3 100644 --- a/tests/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff @@ -14,7 +14,7 @@ - _2 = Eq(copy _1, const -42_i32); - switchInt(move _2) -> [0: bb2, otherwise: bb1]; + nop; -+ switchInt(move _1) -> [4294967254: bb1, otherwise: bb2]; ++ switchInt(copy _1) -> [4294967254: bb1, otherwise: bb2]; } bb1: { diff --git a/tests/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff b/tests/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff index 2cc4a8b76973..8101de8cbf38 100644 --- a/tests/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff @@ -14,7 +14,7 @@ - _2 = Eq(copy _1, const 42_u32); - switchInt(move _2) -> [0: bb2, otherwise: bb1]; + nop; -+ switchInt(move _1) -> [42: bb1, otherwise: bb2]; ++ switchInt(copy _1) -> [42: bb1, otherwise: bb2]; } bb1: { diff --git a/tests/mir-opt/if_condition_int.rs b/tests/mir-opt/if_condition_int.rs index b49f8768253a..5e0961da3cce 100644 --- a/tests/mir-opt/if_condition_int.rs +++ b/tests/mir-opt/if_condition_int.rs @@ -10,8 +10,7 @@ use core::intrinsics::mir::*; // EMIT_MIR if_condition_int.opt_u32.SimplifyComparisonIntegral.diff fn opt_u32(x: u32) -> u32 { // CHECK-LABEL: fn opt_u32( - // FIXME: This should be copy. - // CHECK: switchInt(move _1) -> [42: [[BB1:bb.*]], otherwise: [[BB2:bb.*]]]; + // CHECK: switchInt(copy _1) -> [42: [[BB1:bb.*]], otherwise: [[BB2:bb.*]]]; // CHECK: [[BB1]]: // CHECK: _0 = const 0_u32; // CHECK: [[BB2]]: @@ -34,7 +33,7 @@ fn dont_opt_bool(x: bool) -> u32 { // EMIT_MIR if_condition_int.opt_char.SimplifyComparisonIntegral.diff fn opt_char(x: char) -> u32 { // CHECK-LABEL: fn opt_char( - // CHECK: switchInt(move _1) -> [120: [[BB1:bb.*]], otherwise: [[BB2:bb.*]]]; + // CHECK: switchInt(copy _1) -> [120: [[BB1:bb.*]], otherwise: [[BB2:bb.*]]]; // CHECK: [[BB1]]: // CHECK: _0 = const 0_u32; // CHECK: [[BB2]]: @@ -45,7 +44,7 @@ fn opt_char(x: char) -> u32 { // EMIT_MIR if_condition_int.opt_i8.SimplifyComparisonIntegral.diff fn opt_i8(x: i8) -> u32 { // CHECK-LABEL: fn opt_i8( - // CHECK: switchInt(move _1) -> [42: [[BB1:bb.*]], otherwise: [[BB2:bb.*]]]; + // CHECK: switchInt(copy _1) -> [42: [[BB1:bb.*]], otherwise: [[BB2:bb.*]]]; // CHECK: [[BB1]]: // CHECK: _0 = const 0_u32; // CHECK: [[BB2]]: @@ -56,7 +55,7 @@ fn opt_i8(x: i8) -> u32 { // EMIT_MIR if_condition_int.opt_negative.SimplifyComparisonIntegral.diff fn opt_negative(x: i32) -> u32 { // CHECK-LABEL: fn opt_negative( - // CHECK: switchInt(move _1) -> [4294967254: [[BB1:bb.*]], otherwise: [[BB2:bb.*]]]; + // CHECK: switchInt(copy _1) -> [4294967254: [[BB1:bb.*]], otherwise: [[BB2:bb.*]]]; // CHECK: [[BB1]]: // CHECK: _0 = const 0_u32; // CHECK: [[BB2]]: @@ -67,11 +66,11 @@ fn opt_negative(x: i32) -> u32 { // EMIT_MIR if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff fn opt_multiple_ifs(x: u32) -> u32 { // CHECK-LABEL: fn opt_multiple_ifs( - // CHECK: switchInt(move _1) -> [42: [[BB1:bb.*]], otherwise: [[BB2:bb.*]]]; + // CHECK: switchInt(copy _1) -> [42: [[BB1:bb.*]], otherwise: [[BB2:bb.*]]]; // CHECK: [[BB1]]: // CHECK: _0 = const 0_u32; // CHECK: [[BB2]]: - // CHECK: switchInt(move _1) -> [21: [[BB4:bb.*]], otherwise: [[BB3:bb.*]]]; + // CHECK: switchInt(copy _1) -> [21: [[BB4:bb.*]], otherwise: [[BB3:bb.*]]]; // CHECK: [[BB3]]: // CHECK: _0 = const 1_u32; // CHECK: [[BB4]]: @@ -90,7 +89,7 @@ fn opt_multiple_ifs(x: u32) -> u32 { fn dont_remove_comparison(a: i8) -> i32 { // CHECK-LABEL: fn dont_remove_comparison( // CHECK: [[b:_.*]] = Eq(copy _1, const 17_i8); - // CHECK: switchInt(move _1) -> [17: [[BB1:bb.*]], otherwise: [[BB2:bb.*]]]; + // CHECK: switchInt(copy _1) -> [17: [[BB1:bb.*]], otherwise: [[BB2:bb.*]]]; // CHECK: [[BB1]]: // CHECK: [[cast_1:_.*]] = copy [[b]] as i32 (IntToInt); // CHECK: _0 = Add(const 100_i32, move [[cast_1]]); diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir index b5c23822162c..f3c83f62edf6 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir @@ -28,7 +28,7 @@ fn num_to_digit(_1: char) -> u32 { StorageLive(_3); _3 = discriminant(_2); StorageDead(_2); - switchInt(move _3) -> [1: bb2, otherwise: bb7]; + switchInt(copy _3) -> [1: bb2, otherwise: bb7]; } bb2: { diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir index f22b8835735d..0e55df24cc57 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir @@ -28,7 +28,7 @@ fn num_to_digit(_1: char) -> u32 { StorageLive(_3); _3 = discriminant(_2); StorageDead(_2); - switchInt(move _3) -> [1: bb2, otherwise: bb7]; + switchInt(copy _3) -> [1: bb2, otherwise: bb7]; } bb2: { diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir index b5c23822162c..f3c83f62edf6 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir @@ -28,7 +28,7 @@ fn num_to_digit(_1: char) -> u32 { StorageLive(_3); _3 = discriminant(_2); StorageDead(_2); - switchInt(move _3) -> [1: bb2, otherwise: bb7]; + switchInt(copy _3) -> [1: bb2, otherwise: bb7]; } bb2: { diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir index f22b8835735d..0e55df24cc57 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir @@ -28,7 +28,7 @@ fn num_to_digit(_1: char) -> u32 { StorageLive(_3); _3 = discriminant(_2); StorageDead(_2); - switchInt(move _3) -> [1: bb2, otherwise: bb7]; + switchInt(copy _3) -> [1: bb2, otherwise: bb7]; } bb2: { From 3b1756fbf56fcfede8ac2c1d877ddd1e8a88be8c Mon Sep 17 00:00:00 2001 From: dianqk Date: Sun, 11 Jan 2026 18:10:05 +0800 Subject: [PATCH 0587/1061] Run SimplifyComparisonIntegral with opt-level 2 --- .../rustc_mir_transform/src/simplify_comparison_integral.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs index b7445a0f7c2e..58b5e45672a2 100644 --- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs +++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs @@ -29,7 +29,7 @@ pub(super) struct SimplifyComparisonIntegral; impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - sess.mir_opt_level() > 0 + sess.mir_opt_level() > 1 } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { From 756e1bac6e1939dcd80125934fc6409846f02dac Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 11 Oct 2025 23:48:20 -0400 Subject: [PATCH 0588/1061] `clippy_dev`: Move lint uplifting into its own command. --- clippy_dev/src/deprecate_lint.rs | 54 ++++++++++++++++++++++++++++- clippy_dev/src/main.rs | 36 +++++++++----------- clippy_dev/src/rename_lint.rs | 58 +++++--------------------------- 3 files changed, 78 insertions(+), 70 deletions(-) diff --git a/clippy_dev/src/deprecate_lint.rs b/clippy_dev/src/deprecate_lint.rs index 0401cfda7080..bee7508dabb9 100644 --- a/clippy_dev/src/deprecate_lint.rs +++ b/clippy_dev/src/deprecate_lint.rs @@ -1,4 +1,4 @@ -use crate::parse::{DeprecatedLint, Lint, ParseCx}; +use crate::parse::{DeprecatedLint, Lint, ParseCx, RenamedLint}; use crate::update_lints::generate_lint_files; use crate::utils::{UpdateMode, Version}; use std::ffi::OsStr; @@ -61,6 +61,58 @@ pub fn deprecate<'cx>(cx: ParseCx<'cx>, clippy_version: Version, name: &'cx str, } } +pub fn uplift<'cx, 'env: 'cx>(cx: ParseCx<'cx>, clippy_version: Version, old_name: &'env str, new_name: &'env str) { + let mut lints = cx.find_lint_decls(); + let (deprecated_lints, mut renamed_lints) = cx.read_deprecated_lints(); + + let Some(lint) = lints.iter().find(|l| l.name == old_name) else { + eprintln!("error: failed to find lint `{old_name}`"); + return; + }; + + let old_name_prefixed = cx.str_buf.with(|buf| { + buf.extend(["clippy::", old_name]); + cx.arena.alloc_str(buf) + }); + for lint in &mut renamed_lints { + if lint.new_name == old_name_prefixed { + lint.new_name = new_name; + } + } + match renamed_lints.binary_search_by(|x| x.old_name.cmp(old_name_prefixed)) { + Ok(_) => { + println!("`{old_name}` is already deprecated"); + return; + }, + Err(idx) => renamed_lints.insert( + idx, + RenamedLint { + old_name: old_name_prefixed, + new_name, + version: cx.str_buf.alloc_display(cx.arena, clippy_version.rust_display()), + }, + ), + } + + let mod_path = { + let mut mod_path = PathBuf::from(format!("clippy_lints/src/{}", lint.module)); + if mod_path.is_dir() { + mod_path = mod_path.join("mod"); + } + + mod_path.set_extension("rs"); + mod_path + }; + + if remove_lint_declaration(old_name, &mod_path, &mut lints).unwrap_or(false) { + generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); + println!("info: `{old_name}` has successfully been uplifted"); + println!("note: you must run `cargo uitest` to update the test results"); + } else { + eprintln!("error: lint not found"); + } +} + fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec>) -> io::Result { fn remove_lint(name: &str, lints: &mut Vec>) { lints.iter().position(|l| l.name == name).map(|pos| lints.remove(pos)); diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 392c3aabf193..9571dfde1877 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -74,18 +74,11 @@ fn main() { }, DevCommand::Serve { port, lint } => serve::run(port, lint), DevCommand::Lint { path, edition, args } => lint::run(&path, &edition, args.iter()), - DevCommand::RenameLint { - old_name, - new_name, - uplift, - } => new_parse_cx(|cx| { - rename_lint::rename( - cx, - clippy.version, - &old_name, - new_name.as_ref().unwrap_or(&old_name), - uplift, - ); + DevCommand::RenameLint { old_name, new_name } => new_parse_cx(|cx| { + rename_lint::rename(cx, clippy.version, &old_name, &new_name); + }), + DevCommand::Uplift { old_name, new_name } => new_parse_cx(|cx| { + deprecate_lint::uplift(cx, clippy.version, &old_name, new_name.as_deref().unwrap_or(&old_name)); }), DevCommand::Deprecate { name, reason } => { new_parse_cx(|cx| deprecate_lint::deprecate(cx, clippy.version, &name, &reason)); @@ -243,15 +236,9 @@ enum DevCommand { /// The name of the lint to rename #[arg(value_parser = lint_name)] old_name: String, - #[arg( - required_unless_present = "uplift", - value_parser = lint_name, - )] + #[arg(value_parser = lint_name)] /// The new name of the lint - new_name: Option, - #[arg(long)] - /// This lint will be uplifted into rustc - uplift: bool, + new_name: String, }, /// Deprecate the given lint Deprecate { @@ -266,6 +253,15 @@ enum DevCommand { Sync(SyncCommand), /// Manage Clippy releases Release(ReleaseCommand), + /// Marks a lint as uplifted into rustc and removes its code + Uplift { + /// The name of the lint to uplift + #[arg(value_parser = lint_name)] + old_name: String, + /// The name of the lint in rustc + #[arg(value_parser = lint_name)] + new_name: Option, + }, } #[derive(Args)] diff --git a/clippy_dev/src/rename_lint.rs b/clippy_dev/src/rename_lint.rs index 8e30eb7ce95b..9be4f2bdc970 100644 --- a/clippy_dev/src/rename_lint.rs +++ b/clippy_dev/src/rename_lint.rs @@ -25,8 +25,7 @@ use std::path::Path; /// * If either lint name has a prefix /// * If `old_name` doesn't name an existing lint. /// * If `old_name` names a deprecated or renamed lint. -#[expect(clippy::too_many_lines)] -pub fn rename<'cx>(cx: ParseCx<'cx>, clippy_version: Version, old_name: &'cx str, new_name: &'cx str, uplift: bool) { +pub fn rename<'cx>(cx: ParseCx<'cx>, clippy_version: Version, old_name: &'cx str, new_name: &'cx str) { let mut updater = FileUpdater::default(); let mut lints = cx.find_lint_decls(); let (deprecated_lints, mut renamed_lints) = cx.read_deprecated_lints(); @@ -34,20 +33,15 @@ pub fn rename<'cx>(cx: ParseCx<'cx>, clippy_version: Version, old_name: &'cx str let Ok(lint_idx) = lints.binary_search_by(|x| x.name.cmp(old_name)) else { panic!("could not find lint `{old_name}`"); }; - let lint = &lints[lint_idx]; let old_name_prefixed = cx.str_buf.with(|buf| { buf.extend(["clippy::", old_name]); cx.arena.alloc_str(buf) }); - let new_name_prefixed = if uplift { - new_name - } else { - cx.str_buf.with(|buf| { - buf.extend(["clippy::", new_name]); - cx.arena.alloc_str(buf) - }) - }; + let new_name_prefixed = cx.str_buf.with(|buf| { + buf.extend(["clippy::", new_name]); + cx.arena.alloc_str(buf) + }); for lint in &mut renamed_lints { if lint.new_name == old_name_prefixed { @@ -77,31 +71,7 @@ pub fn rename<'cx>(cx: ParseCx<'cx>, clippy_version: Version, old_name: &'cx str let change_prefixed_tests = lints.get(lint_idx + 1).is_none_or(|l| !l.name.starts_with(old_name)); let mut mod_edit = ModEdit::None; - if uplift { - let is_unique_mod = lints[..lint_idx].iter().any(|l| l.module == lint.module) - || lints[lint_idx + 1..].iter().any(|l| l.module == lint.module); - if is_unique_mod { - if delete_file_if_exists(lint.path.as_ref()) { - mod_edit = ModEdit::Delete; - } - } else { - updater.update_file(&lint.path, &mut |_, src, dst| -> UpdateStatus { - let mut start = &src[..lint.declaration_range.start]; - if start.ends_with("\n\n") { - start = &start[..start.len() - 1]; - } - let mut end = &src[lint.declaration_range.end..]; - if end.starts_with("\n\n") { - end = &end[1..]; - } - dst.push_str(start); - dst.push_str(end); - UpdateStatus::Changed - }); - } - delete_test_files(old_name, change_prefixed_tests); - lints.remove(lint_idx); - } else if lints.binary_search_by(|x| x.name.cmp(new_name)).is_err() { + if lints.binary_search_by(|x| x.name.cmp(new_name)).is_err() { let lint = &mut lints[lint_idx]; if lint.module.ends_with(old_name) && lint @@ -139,19 +109,9 @@ pub fn rename<'cx>(cx: ParseCx<'cx>, clippy_version: Version, old_name: &'cx str } generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); - if uplift { - println!("Uplifted `clippy::{old_name}` as `{new_name}`"); - if matches!(mod_edit, ModEdit::None) { - println!("Only the rename has been registered, the code will need to be edited manually"); - } else { - println!("All the lint's code has been deleted"); - println!("Make sure to inspect the results as some things may have been missed"); - } - } else { - println!("Renamed `clippy::{old_name}` to `clippy::{new_name}`"); - println!("All code referencing the old name has been updated"); - println!("Make sure to inspect the results as some things may have been missed"); - } + println!("Renamed `clippy::{old_name}` to `clippy::{new_name}`"); + println!("All code referencing the old name has been updated"); + println!("Make sure to inspect the results as some things may have been missed"); println!("note: `cargo uibless` still needs to be run to update the test results"); } From d9fa6d95151ff267094da06781ef655dd0f693dd Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 12 Oct 2025 14:43:21 -0400 Subject: [PATCH 0589/1061] `clippy_dev`: Rename `deprecate_lint` module to `edit_lints`. --- clippy_dev/src/edit_lints.rs | 213 +++++++++++++++++++++++++++++++++++ clippy_dev/src/lib.rs | 2 +- clippy_dev/src/main.rs | 8 +- 3 files changed, 218 insertions(+), 5 deletions(-) create mode 100644 clippy_dev/src/edit_lints.rs diff --git a/clippy_dev/src/edit_lints.rs b/clippy_dev/src/edit_lints.rs new file mode 100644 index 000000000000..573bd1e44535 --- /dev/null +++ b/clippy_dev/src/edit_lints.rs @@ -0,0 +1,213 @@ +use crate::parse::{DeprecatedLint, Lint, ParseCx, RenamedLint}; +use crate::update_lints::generate_lint_files; +use crate::utils::{UpdateMode, Version}; +use std::ffi::OsStr; +use std::path::{Path, PathBuf}; +use std::{fs, io}; + +/// Runs the `deprecate` command +/// +/// This does the following: +/// * Adds an entry to `deprecated_lints.rs`. +/// * Removes the lint declaration (and the entire file if applicable) +/// +/// # Panics +/// +/// If a file path could not read from or written to +pub fn deprecate<'cx, 'env: 'cx>(cx: ParseCx<'cx>, clippy_version: Version, name: &'env str, reason: &'env str) { + let mut lints = cx.find_lint_decls(); + let (mut deprecated_lints, renamed_lints) = cx.read_deprecated_lints(); + + let Some(lint) = lints.iter().find(|l| l.name == name) else { + eprintln!("error: failed to find lint `{name}`"); + return; + }; + + let prefixed_name = cx.str_buf.with(|buf| { + buf.extend(["clippy::", name]); + cx.arena.alloc_str(buf) + }); + match deprecated_lints.binary_search_by(|x| x.name.cmp(prefixed_name)) { + Ok(_) => { + println!("`{name}` is already deprecated"); + return; + }, + Err(idx) => deprecated_lints.insert( + idx, + DeprecatedLint { + name: prefixed_name, + reason, + version: cx.str_buf.alloc_display(cx.arena, clippy_version.rust_display()), + }, + ), + } + + let mod_path = { + let mut mod_path = PathBuf::from(format!("clippy_lints/src/{}", lint.module)); + if mod_path.is_dir() { + mod_path = mod_path.join("mod"); + } + + mod_path.set_extension("rs"); + mod_path + }; + + if remove_lint_declaration(name, &mod_path, &mut lints).unwrap_or(false) { + generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); + println!("info: `{name}` has successfully been deprecated"); + println!("note: you must run `cargo uitest` to update the test results"); + } else { + eprintln!("error: lint not found"); + } +} + +pub fn uplift<'cx, 'env: 'cx>(cx: ParseCx<'cx>, clippy_version: Version, old_name: &'env str, new_name: &'env str) { + let mut lints = cx.find_lint_decls(); + let (deprecated_lints, mut renamed_lints) = cx.read_deprecated_lints(); + + let Some(lint) = lints.iter().find(|l| l.name == old_name) else { + eprintln!("error: failed to find lint `{old_name}`"); + return; + }; + + let old_name_prefixed = cx.str_buf.with(|buf| { + buf.extend(["clippy::", old_name]); + cx.arena.alloc_str(buf) + }); + for lint in &mut renamed_lints { + if lint.new_name == old_name_prefixed { + lint.new_name = new_name; + } + } + match renamed_lints.binary_search_by(|x| x.old_name.cmp(old_name_prefixed)) { + Ok(_) => { + println!("`{old_name}` is already deprecated"); + return; + }, + Err(idx) => renamed_lints.insert( + idx, + RenamedLint { + old_name: old_name_prefixed, + new_name, + version: cx.str_buf.alloc_display(cx.arena, clippy_version.rust_display()), + }, + ), + } + + let mod_path = { + let mut mod_path = PathBuf::from(format!("clippy_lints/src/{}", lint.module)); + if mod_path.is_dir() { + mod_path = mod_path.join("mod"); + } + + mod_path.set_extension("rs"); + mod_path + }; + + if remove_lint_declaration(old_name, &mod_path, &mut lints).unwrap_or(false) { + generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); + println!("info: `{old_name}` has successfully been uplifted"); + println!("note: you must run `cargo uitest` to update the test results"); + } else { + eprintln!("error: lint not found"); + } +} + +fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec>) -> io::Result { + fn remove_lint(name: &str, lints: &mut Vec>) { + lints.iter().position(|l| l.name == name).map(|pos| lints.remove(pos)); + } + + fn remove_test_assets(name: &str) { + let test_file_stem = format!("tests/ui/{name}"); + let path = Path::new(&test_file_stem); + + // Some lints have their own directories, delete them + if path.is_dir() { + let _ = fs::remove_dir_all(path); + return; + } + + // Remove all related test files + let _ = fs::remove_file(path.with_extension("rs")); + let _ = fs::remove_file(path.with_extension("stderr")); + let _ = fs::remove_file(path.with_extension("fixed")); + } + + fn remove_impl_lint_pass(lint_name_upper: &str, content: &mut String) { + let impl_lint_pass_start = content.find("impl_lint_pass!").unwrap_or_else(|| { + content + .find("declare_lint_pass!") + .unwrap_or_else(|| panic!("failed to find `impl_lint_pass`")) + }); + let mut impl_lint_pass_end = content[impl_lint_pass_start..] + .find(']') + .expect("failed to find `impl_lint_pass` terminator"); + + impl_lint_pass_end += impl_lint_pass_start; + if let Some(lint_name_pos) = content[impl_lint_pass_start..impl_lint_pass_end].find(lint_name_upper) { + let mut lint_name_end = impl_lint_pass_start + (lint_name_pos + lint_name_upper.len()); + for c in content[lint_name_end..impl_lint_pass_end].chars() { + // Remove trailing whitespace + if c == ',' || c.is_whitespace() { + lint_name_end += 1; + } else { + break; + } + } + + content.replace_range(impl_lint_pass_start + lint_name_pos..lint_name_end, ""); + } + } + + if path.exists() + && let Some(lint) = lints.iter().find(|l| l.name == name) + { + if lint.module == name { + // The lint name is the same as the file, we can just delete the entire file + fs::remove_file(path)?; + } else { + // We can't delete the entire file, just remove the declaration + + if let Some(Some("mod.rs")) = path.file_name().map(OsStr::to_str) { + // Remove clippy_lints/src/some_mod/some_lint.rs + let mut lint_mod_path = path.to_path_buf(); + lint_mod_path.set_file_name(name); + lint_mod_path.set_extension("rs"); + + let _ = fs::remove_file(lint_mod_path); + } + + let mut content = + fs::read_to_string(path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy())); + + eprintln!( + "warn: you will have to manually remove any code related to `{name}` from `{}`", + path.display() + ); + + assert!( + content[lint.declaration_range].contains(&name.to_uppercase()), + "error: `{}` does not contain lint `{}`'s declaration", + path.display(), + lint.name + ); + + // Remove lint declaration (declare_clippy_lint!) + content.replace_range(lint.declaration_range, ""); + + // Remove the module declaration (mod xyz;) + let mod_decl = format!("\nmod {name};"); + content = content.replacen(&mod_decl, "", 1); + + remove_impl_lint_pass(&lint.name.to_uppercase(), &mut content); + fs::write(path, content).unwrap_or_else(|_| panic!("failed to write to `{}`", path.to_string_lossy())); + } + + remove_test_assets(name); + remove_lint(name, lints); + return Ok(true); + } + + Ok(false) +} diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index cd103908be03..db9b230f6e59 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -23,8 +23,8 @@ extern crate rustc_arena; extern crate rustc_driver; extern crate rustc_lexer; -pub mod deprecate_lint; pub mod dogfood; +pub mod edit_lints; pub mod fmt; pub mod lint; pub mod new_lint; diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 9571dfde1877..e4e19a100c6e 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -4,8 +4,8 @@ use clap::{Args, Parser, Subcommand}; use clippy_dev::{ - ClippyInfo, UpdateMode, deprecate_lint, dogfood, fmt, lint, new_lint, new_parse_cx, release, rename_lint, serve, - setup, sync, update_lints, + ClippyInfo, UpdateMode, dogfood, edit_lints, fmt, lint, new_lint, new_parse_cx, release, rename_lint, serve, setup, + sync, update_lints, }; use std::env; @@ -78,10 +78,10 @@ fn main() { rename_lint::rename(cx, clippy.version, &old_name, &new_name); }), DevCommand::Uplift { old_name, new_name } => new_parse_cx(|cx| { - deprecate_lint::uplift(cx, clippy.version, &old_name, new_name.as_deref().unwrap_or(&old_name)); + edit_lints::uplift(cx, clippy.version, &old_name, new_name.as_deref().unwrap_or(&old_name)); }), DevCommand::Deprecate { name, reason } => { - new_parse_cx(|cx| deprecate_lint::deprecate(cx, clippy.version, &name, &reason)); + new_parse_cx(|cx| edit_lints::deprecate(cx, clippy.version, &name, &reason)); }, DevCommand::Sync(SyncCommand { subcommand }) => match subcommand { SyncSubcommand::UpdateNightly => sync::update_nightly(), From 8d4e435f492a54c14c8620ef665cdec4710abd19 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 12 Oct 2025 14:44:25 -0400 Subject: [PATCH 0590/1061] `clippy_dev`: Move `rename_lint` command to `edit_lints` module. --- clippy_dev/src/edit_lints.rs | 351 ++++++++++++++++++++++++++++++++- clippy_dev/src/lib.rs | 1 - clippy_dev/src/main.rs | 6 +- clippy_dev/src/rename_lint.rs | 353 ---------------------------------- 4 files changed, 352 insertions(+), 359 deletions(-) delete mode 100644 clippy_dev/src/rename_lint.rs diff --git a/clippy_dev/src/edit_lints.rs b/clippy_dev/src/edit_lints.rs index 573bd1e44535..8a5ba26fd215 100644 --- a/clippy_dev/src/edit_lints.rs +++ b/clippy_dev/src/edit_lints.rs @@ -1,7 +1,12 @@ +use crate::parse::cursor::{self, Capture, Cursor}; use crate::parse::{DeprecatedLint, Lint, ParseCx, RenamedLint}; use crate::update_lints::generate_lint_files; -use crate::utils::{UpdateMode, Version}; -use std::ffi::OsStr; +use crate::utils::{ + ErrAction, FileUpdater, UpdateMode, UpdateStatus, Version, delete_dir_if_exists, delete_file_if_exists, + expect_action, try_rename_dir, try_rename_file, walk_dir_no_dot_or_target, +}; +use rustc_lexer::TokenKind; +use std::ffi::{OsStr, OsString}; use std::path::{Path, PathBuf}; use std::{fs, io}; @@ -113,6 +118,111 @@ pub fn uplift<'cx, 'env: 'cx>(cx: ParseCx<'cx>, clippy_version: Version, old_nam } } +/// Runs the `rename_lint` command. +/// +/// This does the following: +/// * Adds an entry to `renamed_lints.rs`. +/// * Renames all lint attributes to the new name (e.g. `#[allow(clippy::lint_name)]`). +/// * Renames the lint struct to the new name. +/// * Renames the module containing the lint struct to the new name if it shares a name with the +/// lint. +/// +/// # Panics +/// Panics for the following conditions: +/// * If a file path could not read from or then written to +/// * If either lint name has a prefix +/// * If `old_name` doesn't name an existing lint. +/// * If `old_name` names a deprecated or renamed lint. +pub fn rename<'cx, 'env: 'cx>(cx: ParseCx<'cx>, clippy_version: Version, old_name: &'env str, new_name: &'env str) { + let mut updater = FileUpdater::default(); + let mut lints = cx.find_lint_decls(); + let (deprecated_lints, mut renamed_lints) = cx.read_deprecated_lints(); + + let Ok(lint_idx) = lints.binary_search_by(|x| x.name.cmp(old_name)) else { + panic!("could not find lint `{old_name}`"); + }; + + let old_name_prefixed = cx.str_buf.with(|buf| { + buf.extend(["clippy::", old_name]); + cx.arena.alloc_str(buf) + }); + let new_name_prefixed = cx.str_buf.with(|buf| { + buf.extend(["clippy::", new_name]); + cx.arena.alloc_str(buf) + }); + + for lint in &mut renamed_lints { + if lint.new_name == old_name_prefixed { + lint.new_name = new_name_prefixed; + } + } + match renamed_lints.binary_search_by(|x| x.old_name.cmp(old_name_prefixed)) { + Ok(_) => { + println!("`{old_name}` already has a rename registered"); + return; + }, + Err(idx) => { + renamed_lints.insert( + idx, + RenamedLint { + old_name: old_name_prefixed, + new_name: new_name_prefixed, + version: cx.str_buf.alloc_display(cx.arena, clippy_version.rust_display()), + }, + ); + }, + } + + // Some tests are named `lint_name_suffix` which should also be renamed, + // but we can't do that if the renamed lint's name overlaps with another + // lint. e.g. renaming 'foo' to 'bar' when a lint 'foo_bar' also exists. + let change_prefixed_tests = lints.get(lint_idx + 1).is_none_or(|l| !l.name.starts_with(old_name)); + + let mut mod_edit = ModEdit::None; + if lints.binary_search_by(|x| x.name.cmp(new_name)).is_err() { + let lint = &mut lints[lint_idx]; + if lint.module.ends_with(old_name) + && lint + .path + .file_stem() + .is_some_and(|x| x.as_encoded_bytes() == old_name.as_bytes()) + { + let mut new_path = lint.path.with_file_name(new_name).into_os_string(); + new_path.push(".rs"); + if try_rename_file(lint.path.as_ref(), new_path.as_ref()) { + mod_edit = ModEdit::Rename; + } + + lint.module = cx.str_buf.with(|buf| { + buf.push_str(&lint.module[..lint.module.len() - old_name.len()]); + buf.push_str(new_name); + cx.arena.alloc_str(buf) + }); + } + rename_test_files(old_name, new_name, change_prefixed_tests); + lints[lint_idx].name = new_name; + lints.sort_by(|lhs, rhs| lhs.name.cmp(rhs.name)); + } else { + println!("Renamed `clippy::{old_name}` to `clippy::{new_name}`"); + println!("Since `{new_name}` already exists the existing code has not been changed"); + return; + } + + let mut update_fn = file_update_fn(old_name, new_name, mod_edit); + for e in walk_dir_no_dot_or_target(".") { + let e = expect_action(e, ErrAction::Read, "."); + if e.path().as_os_str().as_encoded_bytes().ends_with(b".rs") { + updater.update_file(e.path(), &mut update_fn); + } + } + generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); + + println!("Renamed `clippy::{old_name}` to `clippy::{new_name}`"); + println!("All code referencing the old name has been updated"); + println!("Make sure to inspect the results as some things may have been missed"); + println!("note: `cargo uibless` still needs to be run to update the test results"); +} + fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec>) -> io::Result { fn remove_lint(name: &str, lints: &mut Vec>) { lints.iter().position(|l| l.name == name).map(|pos| lints.remove(pos)); @@ -211,3 +321,240 @@ fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec>) - Ok(false) } + +#[derive(Clone, Copy)] +enum ModEdit { + None, + Delete, + Rename, +} + +fn collect_ui_test_names(lint: &str, rename_prefixed: bool, dst: &mut Vec<(OsString, bool)>) { + for e in fs::read_dir("tests/ui").expect("error reading `tests/ui`") { + let e = e.expect("error reading `tests/ui`"); + let name = e.file_name(); + if let Some((name_only, _)) = name.as_encoded_bytes().split_once(|&x| x == b'.') { + if name_only.starts_with(lint.as_bytes()) && (rename_prefixed || name_only.len() == lint.len()) { + dst.push((name, true)); + } + } else if name.as_encoded_bytes().starts_with(lint.as_bytes()) && (rename_prefixed || name.len() == lint.len()) + { + dst.push((name, false)); + } + } +} + +fn collect_ui_toml_test_names(lint: &str, rename_prefixed: bool, dst: &mut Vec<(OsString, bool)>) { + if rename_prefixed { + for e in fs::read_dir("tests/ui-toml").expect("error reading `tests/ui-toml`") { + let e = e.expect("error reading `tests/ui-toml`"); + let name = e.file_name(); + if name.as_encoded_bytes().starts_with(lint.as_bytes()) && e.file_type().is_ok_and(|ty| ty.is_dir()) { + dst.push((name, false)); + } + } + } else { + dst.push((lint.into(), false)); + } +} + +/// Renames all test files for the given lint. +/// +/// If `rename_prefixed` is `true` this will also rename tests which have the lint name as a prefix. +fn rename_test_files(old_name: &str, new_name: &str, rename_prefixed: bool) { + let mut tests = Vec::new(); + + let mut old_buf = OsString::from("tests/ui/"); + let mut new_buf = OsString::from("tests/ui/"); + collect_ui_test_names(old_name, rename_prefixed, &mut tests); + for &(ref name, is_file) in &tests { + old_buf.push(name); + new_buf.extend([new_name.as_ref(), name.slice_encoded_bytes(old_name.len()..)]); + if is_file { + try_rename_file(old_buf.as_ref(), new_buf.as_ref()); + } else { + try_rename_dir(old_buf.as_ref(), new_buf.as_ref()); + } + old_buf.truncate("tests/ui/".len()); + new_buf.truncate("tests/ui/".len()); + } + + tests.clear(); + old_buf.truncate("tests/ui".len()); + new_buf.truncate("tests/ui".len()); + old_buf.push("-toml/"); + new_buf.push("-toml/"); + collect_ui_toml_test_names(old_name, rename_prefixed, &mut tests); + for (name, _) in &tests { + old_buf.push(name); + new_buf.extend([new_name.as_ref(), name.slice_encoded_bytes(old_name.len()..)]); + try_rename_dir(old_buf.as_ref(), new_buf.as_ref()); + old_buf.truncate("tests/ui/".len()); + new_buf.truncate("tests/ui/".len()); + } +} + +fn delete_test_files(lint: &str, rename_prefixed: bool) { + let mut tests = Vec::new(); + + let mut buf = OsString::from("tests/ui/"); + collect_ui_test_names(lint, rename_prefixed, &mut tests); + for &(ref name, is_file) in &tests { + buf.push(name); + if is_file { + delete_file_if_exists(buf.as_ref()); + } else { + delete_dir_if_exists(buf.as_ref()); + } + buf.truncate("tests/ui/".len()); + } + + buf.truncate("tests/ui".len()); + buf.push("-toml/"); + + tests.clear(); + collect_ui_toml_test_names(lint, rename_prefixed, &mut tests); + for (name, _) in &tests { + buf.push(name); + delete_dir_if_exists(buf.as_ref()); + buf.truncate("tests/ui/".len()); + } +} + +fn snake_to_pascal(s: &str) -> String { + let mut dst = Vec::with_capacity(s.len()); + let mut iter = s.bytes(); + || -> Option<()> { + dst.push(iter.next()?.to_ascii_uppercase()); + while let Some(c) = iter.next() { + if c == b'_' { + dst.push(iter.next()?.to_ascii_uppercase()); + } else { + dst.push(c); + } + } + Some(()) + }(); + String::from_utf8(dst).unwrap() +} + +#[expect(clippy::too_many_lines)] +fn file_update_fn<'a, 'b>( + old_name: &'a str, + new_name: &'b str, + mod_edit: ModEdit, +) -> impl use<'a, 'b> + FnMut(&Path, &str, &mut String) -> UpdateStatus { + let old_name_pascal = snake_to_pascal(old_name); + let new_name_pascal = snake_to_pascal(new_name); + let old_name_upper = old_name.to_ascii_uppercase(); + let new_name_upper = new_name.to_ascii_uppercase(); + move |_, src, dst| { + let mut copy_pos = 0u32; + let mut changed = false; + let mut cursor = Cursor::new(src); + let mut captures = [Capture::EMPTY]; + loop { + match cursor.peek() { + TokenKind::Eof => break, + TokenKind::Ident => { + let match_start = cursor.pos(); + let text = cursor.peek_text(); + cursor.step(); + match text { + // clippy::line_name or clippy::lint-name + "clippy" => { + if cursor.match_all(&[cursor::Pat::DoubleColon, cursor::Pat::CaptureIdent], &mut captures) + && cursor.get_text(captures[0]) == old_name + { + dst.push_str(&src[copy_pos as usize..captures[0].pos as usize]); + dst.push_str(new_name); + copy_pos = cursor.pos(); + changed = true; + } + }, + // mod lint_name + "mod" => { + if !matches!(mod_edit, ModEdit::None) + && let Some(pos) = cursor.find_ident(old_name) + { + match mod_edit { + ModEdit::Rename => { + dst.push_str(&src[copy_pos as usize..pos as usize]); + dst.push_str(new_name); + copy_pos = cursor.pos(); + changed = true; + }, + ModEdit::Delete if cursor.match_pat(cursor::Pat::Semi) => { + let mut start = &src[copy_pos as usize..match_start as usize]; + if start.ends_with("\n\n") { + start = &start[..start.len() - 1]; + } + dst.push_str(start); + copy_pos = cursor.pos(); + if src[copy_pos as usize..].starts_with("\n\n") { + copy_pos += 1; + } + changed = true; + }, + ModEdit::Delete | ModEdit::None => {}, + } + } + }, + // lint_name:: + name if matches!(mod_edit, ModEdit::Rename) && name == old_name => { + let name_end = cursor.pos(); + if cursor.match_pat(cursor::Pat::DoubleColon) { + dst.push_str(&src[copy_pos as usize..match_start as usize]); + dst.push_str(new_name); + copy_pos = name_end; + changed = true; + } + }, + // LINT_NAME or LintName + name => { + let replacement = if name == old_name_upper { + &new_name_upper + } else if name == old_name_pascal { + &new_name_pascal + } else { + continue; + }; + dst.push_str(&src[copy_pos as usize..match_start as usize]); + dst.push_str(replacement); + copy_pos = cursor.pos(); + changed = true; + }, + } + }, + // //~ lint_name + TokenKind::LineComment { doc_style: None } => { + let text = cursor.peek_text(); + if text.starts_with("//~") + && let Some(text) = text.strip_suffix(old_name) + && !text.ends_with(|c| matches!(c, 'a'..='z' | 'A'..='Z' | '0'..='9' | '_')) + { + dst.push_str(&src[copy_pos as usize..cursor.pos() as usize + text.len()]); + dst.push_str(new_name); + copy_pos = cursor.pos() + cursor.peek_len(); + changed = true; + } + cursor.step(); + }, + // ::lint_name + TokenKind::Colon + if cursor.match_all(&[cursor::Pat::DoubleColon, cursor::Pat::CaptureIdent], &mut captures) + && cursor.get_text(captures[0]) == old_name => + { + dst.push_str(&src[copy_pos as usize..captures[0].pos as usize]); + dst.push_str(new_name); + copy_pos = cursor.pos(); + changed = true; + }, + _ => cursor.step(), + } + } + + dst.push_str(&src[copy_pos as usize..]); + UpdateStatus::from_changed(changed) + } +} diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index db9b230f6e59..69309403c8d0 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -29,7 +29,6 @@ pub mod fmt; pub mod lint; pub mod new_lint; pub mod release; -pub mod rename_lint; pub mod serve; pub mod setup; pub mod sync; diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index e4e19a100c6e..8dc2290df8e4 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -4,8 +4,8 @@ use clap::{Args, Parser, Subcommand}; use clippy_dev::{ - ClippyInfo, UpdateMode, dogfood, edit_lints, fmt, lint, new_lint, new_parse_cx, release, rename_lint, serve, setup, - sync, update_lints, + ClippyInfo, UpdateMode, dogfood, edit_lints, fmt, lint, new_lint, new_parse_cx, release, serve, setup, sync, + update_lints, }; use std::env; @@ -75,7 +75,7 @@ fn main() { DevCommand::Serve { port, lint } => serve::run(port, lint), DevCommand::Lint { path, edition, args } => lint::run(&path, &edition, args.iter()), DevCommand::RenameLint { old_name, new_name } => new_parse_cx(|cx| { - rename_lint::rename(cx, clippy.version, &old_name, &new_name); + edit_lints::rename(cx, clippy.version, &old_name, &new_name); }), DevCommand::Uplift { old_name, new_name } => new_parse_cx(|cx| { edit_lints::uplift(cx, clippy.version, &old_name, new_name.as_deref().unwrap_or(&old_name)); diff --git a/clippy_dev/src/rename_lint.rs b/clippy_dev/src/rename_lint.rs deleted file mode 100644 index 9be4f2bdc970..000000000000 --- a/clippy_dev/src/rename_lint.rs +++ /dev/null @@ -1,353 +0,0 @@ -use crate::parse::cursor::{self, Capture, Cursor}; -use crate::parse::{ParseCx, RenamedLint}; -use crate::update_lints::generate_lint_files; -use crate::utils::{ - ErrAction, FileUpdater, UpdateMode, UpdateStatus, Version, delete_dir_if_exists, delete_file_if_exists, - expect_action, try_rename_dir, try_rename_file, walk_dir_no_dot_or_target, -}; -use rustc_lexer::TokenKind; -use std::ffi::OsString; -use std::fs; -use std::path::Path; - -/// Runs the `rename_lint` command. -/// -/// This does the following: -/// * Adds an entry to `renamed_lints.rs`. -/// * Renames all lint attributes to the new name (e.g. `#[allow(clippy::lint_name)]`). -/// * Renames the lint struct to the new name. -/// * Renames the module containing the lint struct to the new name if it shares a name with the -/// lint. -/// -/// # Panics -/// Panics for the following conditions: -/// * If a file path could not read from or then written to -/// * If either lint name has a prefix -/// * If `old_name` doesn't name an existing lint. -/// * If `old_name` names a deprecated or renamed lint. -pub fn rename<'cx>(cx: ParseCx<'cx>, clippy_version: Version, old_name: &'cx str, new_name: &'cx str) { - let mut updater = FileUpdater::default(); - let mut lints = cx.find_lint_decls(); - let (deprecated_lints, mut renamed_lints) = cx.read_deprecated_lints(); - - let Ok(lint_idx) = lints.binary_search_by(|x| x.name.cmp(old_name)) else { - panic!("could not find lint `{old_name}`"); - }; - - let old_name_prefixed = cx.str_buf.with(|buf| { - buf.extend(["clippy::", old_name]); - cx.arena.alloc_str(buf) - }); - let new_name_prefixed = cx.str_buf.with(|buf| { - buf.extend(["clippy::", new_name]); - cx.arena.alloc_str(buf) - }); - - for lint in &mut renamed_lints { - if lint.new_name == old_name_prefixed { - lint.new_name = new_name_prefixed; - } - } - match renamed_lints.binary_search_by(|x| x.old_name.cmp(old_name_prefixed)) { - Ok(_) => { - println!("`{old_name}` already has a rename registered"); - return; - }, - Err(idx) => { - renamed_lints.insert( - idx, - RenamedLint { - old_name: old_name_prefixed, - new_name: new_name_prefixed, - version: cx.str_buf.alloc_display(cx.arena, clippy_version.rust_display()), - }, - ); - }, - } - - // Some tests are named `lint_name_suffix` which should also be renamed, - // but we can't do that if the renamed lint's name overlaps with another - // lint. e.g. renaming 'foo' to 'bar' when a lint 'foo_bar' also exists. - let change_prefixed_tests = lints.get(lint_idx + 1).is_none_or(|l| !l.name.starts_with(old_name)); - - let mut mod_edit = ModEdit::None; - if lints.binary_search_by(|x| x.name.cmp(new_name)).is_err() { - let lint = &mut lints[lint_idx]; - if lint.module.ends_with(old_name) - && lint - .path - .file_stem() - .is_some_and(|x| x.as_encoded_bytes() == old_name.as_bytes()) - { - let mut new_path = lint.path.with_file_name(new_name).into_os_string(); - new_path.push(".rs"); - if try_rename_file(lint.path.as_ref(), new_path.as_ref()) { - mod_edit = ModEdit::Rename; - } - - lint.module = cx.str_buf.with(|buf| { - buf.push_str(&lint.module[..lint.module.len() - old_name.len()]); - buf.push_str(new_name); - cx.arena.alloc_str(buf) - }); - } - rename_test_files(old_name, new_name, change_prefixed_tests); - lints[lint_idx].name = new_name; - lints.sort_by(|lhs, rhs| lhs.name.cmp(rhs.name)); - } else { - println!("Renamed `clippy::{old_name}` to `clippy::{new_name}`"); - println!("Since `{new_name}` already exists the existing code has not been changed"); - return; - } - - let mut update_fn = file_update_fn(old_name, new_name, mod_edit); - for e in walk_dir_no_dot_or_target(".") { - let e = expect_action(e, ErrAction::Read, "."); - if e.path().as_os_str().as_encoded_bytes().ends_with(b".rs") { - updater.update_file(e.path(), &mut update_fn); - } - } - generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); - - println!("Renamed `clippy::{old_name}` to `clippy::{new_name}`"); - println!("All code referencing the old name has been updated"); - println!("Make sure to inspect the results as some things may have been missed"); - println!("note: `cargo uibless` still needs to be run to update the test results"); -} - -#[derive(Clone, Copy)] -enum ModEdit { - None, - Delete, - Rename, -} - -fn collect_ui_test_names(lint: &str, rename_prefixed: bool, dst: &mut Vec<(OsString, bool)>) { - for e in fs::read_dir("tests/ui").expect("error reading `tests/ui`") { - let e = e.expect("error reading `tests/ui`"); - let name = e.file_name(); - if let Some((name_only, _)) = name.as_encoded_bytes().split_once(|&x| x == b'.') { - if name_only.starts_with(lint.as_bytes()) && (rename_prefixed || name_only.len() == lint.len()) { - dst.push((name, true)); - } - } else if name.as_encoded_bytes().starts_with(lint.as_bytes()) && (rename_prefixed || name.len() == lint.len()) - { - dst.push((name, false)); - } - } -} - -fn collect_ui_toml_test_names(lint: &str, rename_prefixed: bool, dst: &mut Vec<(OsString, bool)>) { - if rename_prefixed { - for e in fs::read_dir("tests/ui-toml").expect("error reading `tests/ui-toml`") { - let e = e.expect("error reading `tests/ui-toml`"); - let name = e.file_name(); - if name.as_encoded_bytes().starts_with(lint.as_bytes()) && e.file_type().is_ok_and(|ty| ty.is_dir()) { - dst.push((name, false)); - } - } - } else { - dst.push((lint.into(), false)); - } -} - -/// Renames all test files for the given lint. -/// -/// If `rename_prefixed` is `true` this will also rename tests which have the lint name as a prefix. -fn rename_test_files(old_name: &str, new_name: &str, rename_prefixed: bool) { - let mut tests = Vec::new(); - - let mut old_buf = OsString::from("tests/ui/"); - let mut new_buf = OsString::from("tests/ui/"); - collect_ui_test_names(old_name, rename_prefixed, &mut tests); - for &(ref name, is_file) in &tests { - old_buf.push(name); - new_buf.extend([new_name.as_ref(), name.slice_encoded_bytes(old_name.len()..)]); - if is_file { - try_rename_file(old_buf.as_ref(), new_buf.as_ref()); - } else { - try_rename_dir(old_buf.as_ref(), new_buf.as_ref()); - } - old_buf.truncate("tests/ui/".len()); - new_buf.truncate("tests/ui/".len()); - } - - tests.clear(); - old_buf.truncate("tests/ui".len()); - new_buf.truncate("tests/ui".len()); - old_buf.push("-toml/"); - new_buf.push("-toml/"); - collect_ui_toml_test_names(old_name, rename_prefixed, &mut tests); - for (name, _) in &tests { - old_buf.push(name); - new_buf.extend([new_name.as_ref(), name.slice_encoded_bytes(old_name.len()..)]); - try_rename_dir(old_buf.as_ref(), new_buf.as_ref()); - old_buf.truncate("tests/ui/".len()); - new_buf.truncate("tests/ui/".len()); - } -} - -fn delete_test_files(lint: &str, rename_prefixed: bool) { - let mut tests = Vec::new(); - - let mut buf = OsString::from("tests/ui/"); - collect_ui_test_names(lint, rename_prefixed, &mut tests); - for &(ref name, is_file) in &tests { - buf.push(name); - if is_file { - delete_file_if_exists(buf.as_ref()); - } else { - delete_dir_if_exists(buf.as_ref()); - } - buf.truncate("tests/ui/".len()); - } - - buf.truncate("tests/ui".len()); - buf.push("-toml/"); - - tests.clear(); - collect_ui_toml_test_names(lint, rename_prefixed, &mut tests); - for (name, _) in &tests { - buf.push(name); - delete_dir_if_exists(buf.as_ref()); - buf.truncate("tests/ui/".len()); - } -} - -fn snake_to_pascal(s: &str) -> String { - let mut dst = Vec::with_capacity(s.len()); - let mut iter = s.bytes(); - || -> Option<()> { - dst.push(iter.next()?.to_ascii_uppercase()); - while let Some(c) = iter.next() { - if c == b'_' { - dst.push(iter.next()?.to_ascii_uppercase()); - } else { - dst.push(c); - } - } - Some(()) - }(); - String::from_utf8(dst).unwrap() -} - -#[expect(clippy::too_many_lines)] -fn file_update_fn<'a, 'b>( - old_name: &'a str, - new_name: &'b str, - mod_edit: ModEdit, -) -> impl use<'a, 'b> + FnMut(&Path, &str, &mut String) -> UpdateStatus { - let old_name_pascal = snake_to_pascal(old_name); - let new_name_pascal = snake_to_pascal(new_name); - let old_name_upper = old_name.to_ascii_uppercase(); - let new_name_upper = new_name.to_ascii_uppercase(); - move |_, src, dst| { - let mut copy_pos = 0u32; - let mut changed = false; - let mut cursor = Cursor::new(src); - let mut captures = [Capture::EMPTY]; - loop { - match cursor.peek() { - TokenKind::Eof => break, - TokenKind::Ident => { - let match_start = cursor.pos(); - let text = cursor.peek_text(); - cursor.step(); - match text { - // clippy::line_name or clippy::lint-name - "clippy" => { - if cursor.match_all(&[cursor::Pat::DoubleColon, cursor::Pat::CaptureIdent], &mut captures) - && cursor.get_text(captures[0]) == old_name - { - dst.push_str(&src[copy_pos as usize..captures[0].pos as usize]); - dst.push_str(new_name); - copy_pos = cursor.pos(); - changed = true; - } - }, - // mod lint_name - "mod" => { - if !matches!(mod_edit, ModEdit::None) - && let Some(pos) = cursor.find_ident(old_name) - { - match mod_edit { - ModEdit::Rename => { - dst.push_str(&src[copy_pos as usize..pos as usize]); - dst.push_str(new_name); - copy_pos = cursor.pos(); - changed = true; - }, - ModEdit::Delete if cursor.match_pat(cursor::Pat::Semi) => { - let mut start = &src[copy_pos as usize..match_start as usize]; - if start.ends_with("\n\n") { - start = &start[..start.len() - 1]; - } - dst.push_str(start); - copy_pos = cursor.pos(); - if src[copy_pos as usize..].starts_with("\n\n") { - copy_pos += 1; - } - changed = true; - }, - ModEdit::Delete | ModEdit::None => {}, - } - } - }, - // lint_name:: - name if matches!(mod_edit, ModEdit::Rename) && name == old_name => { - let name_end = cursor.pos(); - if cursor.match_pat(cursor::Pat::DoubleColon) { - dst.push_str(&src[copy_pos as usize..match_start as usize]); - dst.push_str(new_name); - copy_pos = name_end; - changed = true; - } - }, - // LINT_NAME or LintName - name => { - let replacement = if name == old_name_upper { - &new_name_upper - } else if name == old_name_pascal { - &new_name_pascal - } else { - continue; - }; - dst.push_str(&src[copy_pos as usize..match_start as usize]); - dst.push_str(replacement); - copy_pos = cursor.pos(); - changed = true; - }, - } - }, - // //~ lint_name - TokenKind::LineComment { doc_style: None } => { - let text = cursor.peek_text(); - if text.starts_with("//~") - && let Some(text) = text.strip_suffix(old_name) - && !text.ends_with(|c| matches!(c, 'a'..='z' | 'A'..='Z' | '0'..='9' | '_')) - { - dst.push_str(&src[copy_pos as usize..cursor.pos() as usize + text.len()]); - dst.push_str(new_name); - copy_pos = cursor.pos() + cursor.peek_len(); - changed = true; - } - cursor.step(); - }, - // ::lint_name - TokenKind::Colon - if cursor.match_all(&[cursor::Pat::DoubleColon, cursor::Pat::CaptureIdent], &mut captures) - && cursor.get_text(captures[0]) == old_name => - { - dst.push_str(&src[copy_pos as usize..captures[0].pos as usize]); - dst.push_str(new_name); - copy_pos = cursor.pos(); - changed = true; - }, - _ => cursor.step(), - } - } - - dst.push_str(&src[copy_pos as usize..]); - UpdateStatus::from_changed(changed) - } -} From 31db6aa5b24d9bf1751bf1017450abd4158bc06d Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 12 Oct 2025 22:42:33 -0400 Subject: [PATCH 0591/1061] `clippy_dev`: When renaming a lint better handle the case where the renamed lint is a prefix of another lint name. --- clippy_dev/src/edit_lints.rs | 79 ++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 36 deletions(-) diff --git a/clippy_dev/src/edit_lints.rs b/clippy_dev/src/edit_lints.rs index 8a5ba26fd215..14dd8b21df9a 100644 --- a/clippy_dev/src/edit_lints.rs +++ b/clippy_dev/src/edit_lints.rs @@ -173,11 +173,6 @@ pub fn rename<'cx, 'env: 'cx>(cx: ParseCx<'cx>, clippy_version: Version, old_nam }, } - // Some tests are named `lint_name_suffix` which should also be renamed, - // but we can't do that if the renamed lint's name overlaps with another - // lint. e.g. renaming 'foo' to 'bar' when a lint 'foo_bar' also exists. - let change_prefixed_tests = lints.get(lint_idx + 1).is_none_or(|l| !l.name.starts_with(old_name)); - let mut mod_edit = ModEdit::None; if lints.binary_search_by(|x| x.name.cmp(new_name)).is_err() { let lint = &mut lints[lint_idx]; @@ -199,7 +194,16 @@ pub fn rename<'cx, 'env: 'cx>(cx: ParseCx<'cx>, clippy_version: Version, old_nam cx.arena.alloc_str(buf) }); } - rename_test_files(old_name, new_name, change_prefixed_tests); + + rename_test_files( + old_name, + new_name, + &lints[lint_idx + 1..] + .iter() + .map(|l| l.name) + .take_while(|&n| n.starts_with(old_name)) + .collect::>(), + ); lints[lint_idx].name = new_name; lints.sort_by(|lhs, rhs| lhs.name.cmp(rhs.name)); } else { @@ -329,44 +333,45 @@ enum ModEdit { Rename, } -fn collect_ui_test_names(lint: &str, rename_prefixed: bool, dst: &mut Vec<(OsString, bool)>) { +fn collect_ui_test_names(lint: &str, ignored_prefixes: &[&str], dst: &mut Vec<(OsString, bool)>) { for e in fs::read_dir("tests/ui").expect("error reading `tests/ui`") { let e = e.expect("error reading `tests/ui`"); let name = e.file_name(); - if let Some((name_only, _)) = name.as_encoded_bytes().split_once(|&x| x == b'.') { - if name_only.starts_with(lint.as_bytes()) && (rename_prefixed || name_only.len() == lint.len()) { - dst.push((name, true)); - } - } else if name.as_encoded_bytes().starts_with(lint.as_bytes()) && (rename_prefixed || name.len() == lint.len()) + if name.as_encoded_bytes().starts_with(lint.as_bytes()) + && !ignored_prefixes + .iter() + .any(|&pre| name.as_encoded_bytes().starts_with(pre.as_bytes())) + && let Ok(ty) = e.file_type() + && (ty.is_file() || ty.is_dir()) + { + dst.push((name, ty.is_file())); + } + } +} + +fn collect_ui_toml_test_names(lint: &str, ignored_prefixes: &[&str], dst: &mut Vec<(OsString, bool)>) { + for e in fs::read_dir("tests/ui-toml").expect("error reading `tests/ui-toml`") { + let e = e.expect("error reading `tests/ui-toml`"); + let name = e.file_name(); + if name.as_encoded_bytes().starts_with(lint.as_bytes()) + && !ignored_prefixes + .iter() + .any(|&pre| name.as_encoded_bytes().starts_with(pre.as_bytes())) + && e.file_type().is_ok_and(|ty| ty.is_dir()) { dst.push((name, false)); } } } -fn collect_ui_toml_test_names(lint: &str, rename_prefixed: bool, dst: &mut Vec<(OsString, bool)>) { - if rename_prefixed { - for e in fs::read_dir("tests/ui-toml").expect("error reading `tests/ui-toml`") { - let e = e.expect("error reading `tests/ui-toml`"); - let name = e.file_name(); - if name.as_encoded_bytes().starts_with(lint.as_bytes()) && e.file_type().is_ok_and(|ty| ty.is_dir()) { - dst.push((name, false)); - } - } - } else { - dst.push((lint.into(), false)); - } -} - -/// Renames all test files for the given lint. -/// -/// If `rename_prefixed` is `true` this will also rename tests which have the lint name as a prefix. -fn rename_test_files(old_name: &str, new_name: &str, rename_prefixed: bool) { - let mut tests = Vec::new(); +/// Renames all test files for the given lint where the file name does not start with any +/// of the given prefixes. +fn rename_test_files(old_name: &str, new_name: &str, ignored_prefixes: &[&str]) { + let mut tests: Vec<(OsString, bool)> = Vec::new(); let mut old_buf = OsString::from("tests/ui/"); let mut new_buf = OsString::from("tests/ui/"); - collect_ui_test_names(old_name, rename_prefixed, &mut tests); + collect_ui_test_names(old_name, ignored_prefixes, &mut tests); for &(ref name, is_file) in &tests { old_buf.push(name); new_buf.extend([new_name.as_ref(), name.slice_encoded_bytes(old_name.len()..)]); @@ -384,7 +389,7 @@ fn rename_test_files(old_name: &str, new_name: &str, rename_prefixed: bool) { new_buf.truncate("tests/ui".len()); old_buf.push("-toml/"); new_buf.push("-toml/"); - collect_ui_toml_test_names(old_name, rename_prefixed, &mut tests); + collect_ui_toml_test_names(old_name, ignored_prefixes, &mut tests); for (name, _) in &tests { old_buf.push(name); new_buf.extend([new_name.as_ref(), name.slice_encoded_bytes(old_name.len()..)]); @@ -394,11 +399,13 @@ fn rename_test_files(old_name: &str, new_name: &str, rename_prefixed: bool) { } } -fn delete_test_files(lint: &str, rename_prefixed: bool) { +/// Deletes all test files for the given lint where the file name does not start with any +/// of the given prefixes. +fn delete_test_files(lint: &str, ignored_prefixes: &[&str]) { let mut tests = Vec::new(); let mut buf = OsString::from("tests/ui/"); - collect_ui_test_names(lint, rename_prefixed, &mut tests); + collect_ui_test_names(lint, ignored_prefixes, &mut tests); for &(ref name, is_file) in &tests { buf.push(name); if is_file { @@ -413,7 +420,7 @@ fn delete_test_files(lint: &str, rename_prefixed: bool) { buf.push("-toml/"); tests.clear(); - collect_ui_toml_test_names(lint, rename_prefixed, &mut tests); + collect_ui_toml_test_names(lint, ignored_prefixes, &mut tests); for (name, _) in &tests { buf.push(name); delete_dir_if_exists(buf.as_ref()); From 5e8d1b541c3e89587e8b07cd75208ea5e029af6a Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Mon, 13 Oct 2025 17:31:51 -0400 Subject: [PATCH 0592/1061] `clippy_dev`: Re-enable deleting the module declaration on deprecation and uplifting. --- clippy_dev/src/edit_lints.rs | 273 ++++++++++++--------------------- clippy_dev/src/parse/cursor.rs | 16 ++ 2 files changed, 117 insertions(+), 172 deletions(-) diff --git a/clippy_dev/src/edit_lints.rs b/clippy_dev/src/edit_lints.rs index 14dd8b21df9a..fb1c1458c50c 100644 --- a/clippy_dev/src/edit_lints.rs +++ b/clippy_dev/src/edit_lints.rs @@ -6,9 +6,9 @@ use crate::utils::{ expect_action, try_rename_dir, try_rename_file, walk_dir_no_dot_or_target, }; use rustc_lexer::TokenKind; -use std::ffi::{OsStr, OsString}; -use std::path::{Path, PathBuf}; -use std::{fs, io}; +use std::ffi::OsString; +use std::fs; +use std::path::Path; /// Runs the `deprecate` command /// @@ -23,7 +23,7 @@ pub fn deprecate<'cx, 'env: 'cx>(cx: ParseCx<'cx>, clippy_version: Version, name let mut lints = cx.find_lint_decls(); let (mut deprecated_lints, renamed_lints) = cx.read_deprecated_lints(); - let Some(lint) = lints.iter().find(|l| l.name == name) else { + let Some(lint_idx) = lints.iter().position(|l| l.name == name) else { eprintln!("error: failed to find lint `{name}`"); return; }; @@ -47,30 +47,17 @@ pub fn deprecate<'cx, 'env: 'cx>(cx: ParseCx<'cx>, clippy_version: Version, name ), } - let mod_path = { - let mut mod_path = PathBuf::from(format!("clippy_lints/src/{}", lint.module)); - if mod_path.is_dir() { - mod_path = mod_path.join("mod"); - } - - mod_path.set_extension("rs"); - mod_path - }; - - if remove_lint_declaration(name, &mod_path, &mut lints).unwrap_or(false) { - generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); - println!("info: `{name}` has successfully been deprecated"); - println!("note: you must run `cargo uitest` to update the test results"); - } else { - eprintln!("error: lint not found"); - } + remove_lint_declaration(lint_idx, &mut lints, &mut FileUpdater::default()); + generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); + println!("info: `{name}` has successfully been deprecated"); + println!("note: you must run `cargo uitest` to update the test results"); } pub fn uplift<'cx, 'env: 'cx>(cx: ParseCx<'cx>, clippy_version: Version, old_name: &'env str, new_name: &'env str) { let mut lints = cx.find_lint_decls(); let (deprecated_lints, mut renamed_lints) = cx.read_deprecated_lints(); - let Some(lint) = lints.iter().find(|l| l.name == old_name) else { + let Some(lint_idx) = lints.iter().position(|l| l.name == old_name) else { eprintln!("error: failed to find lint `{old_name}`"); return; }; @@ -99,23 +86,18 @@ pub fn uplift<'cx, 'env: 'cx>(cx: ParseCx<'cx>, clippy_version: Version, old_nam ), } - let mod_path = { - let mut mod_path = PathBuf::from(format!("clippy_lints/src/{}", lint.module)); - if mod_path.is_dir() { - mod_path = mod_path.join("mod"); + let mut updater = FileUpdater::default(); + let remove_mod = remove_lint_declaration(lint_idx, &mut lints, &mut updater); + let mut update_fn = uplift_update_fn(old_name, new_name, remove_mod); + for e in walk_dir_no_dot_or_target(".") { + let e = expect_action(e, ErrAction::Read, "."); + if e.path().as_os_str().as_encoded_bytes().ends_with(b".rs") { + updater.update_file(e.path(), &mut update_fn); } - - mod_path.set_extension("rs"); - mod_path - }; - - if remove_lint_declaration(old_name, &mod_path, &mut lints).unwrap_or(false) { - generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); - println!("info: `{old_name}` has successfully been uplifted"); - println!("note: you must run `cargo uitest` to update the test results"); - } else { - eprintln!("error: lint not found"); } + generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); + println!("info: `{old_name}` has successfully been uplifted as `{new_name}`"); + println!("note: you must run `cargo uitest` to update the test results"); } /// Runs the `rename_lint` command. @@ -173,7 +155,7 @@ pub fn rename<'cx, 'env: 'cx>(cx: ParseCx<'cx>, clippy_version: Version, old_nam }, } - let mut mod_edit = ModEdit::None; + let mut rename_mod = false; if lints.binary_search_by(|x| x.name.cmp(new_name)).is_err() { let lint = &mut lints[lint_idx]; if lint.module.ends_with(old_name) @@ -185,7 +167,7 @@ pub fn rename<'cx, 'env: 'cx>(cx: ParseCx<'cx>, clippy_version: Version, old_nam let mut new_path = lint.path.with_file_name(new_name).into_os_string(); new_path.push(".rs"); if try_rename_file(lint.path.as_ref(), new_path.as_ref()) { - mod_edit = ModEdit::Rename; + rename_mod = true; } lint.module = cx.str_buf.with(|buf| { @@ -212,7 +194,7 @@ pub fn rename<'cx, 'env: 'cx>(cx: ParseCx<'cx>, clippy_version: Version, old_nam return; } - let mut update_fn = file_update_fn(old_name, new_name, mod_edit); + let mut update_fn = rename_update_fn(old_name, new_name, rename_mod); for e in walk_dir_no_dot_or_target(".") { let e = expect_action(e, ErrAction::Read, "."); if e.path().as_os_str().as_encoded_bytes().ends_with(b".rs") { @@ -227,110 +209,38 @@ pub fn rename<'cx, 'env: 'cx>(cx: ParseCx<'cx>, clippy_version: Version, old_nam println!("note: `cargo uibless` still needs to be run to update the test results"); } -fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec>) -> io::Result { - fn remove_lint(name: &str, lints: &mut Vec>) { - lints.iter().position(|l| l.name == name).map(|pos| lints.remove(pos)); - } - - fn remove_test_assets(name: &str) { - let test_file_stem = format!("tests/ui/{name}"); - let path = Path::new(&test_file_stem); - - // Some lints have their own directories, delete them - if path.is_dir() { - let _ = fs::remove_dir_all(path); - return; - } - - // Remove all related test files - let _ = fs::remove_file(path.with_extension("rs")); - let _ = fs::remove_file(path.with_extension("stderr")); - let _ = fs::remove_file(path.with_extension("fixed")); - } - - fn remove_impl_lint_pass(lint_name_upper: &str, content: &mut String) { - let impl_lint_pass_start = content.find("impl_lint_pass!").unwrap_or_else(|| { - content - .find("declare_lint_pass!") - .unwrap_or_else(|| panic!("failed to find `impl_lint_pass`")) +/// Removes a lint's declaration and test files. Returns whether the module containing the +/// lint was deleted. +fn remove_lint_declaration(lint_idx: usize, lints: &mut Vec>, updater: &mut FileUpdater) -> bool { + let lint = lints.remove(lint_idx); + let delete_mod = if lints.iter().all(|l| l.module != lint.module) { + delete_file_if_exists(lint.path.as_ref()) + } else { + updater.update_file(&lint.path, &mut |_, src, dst| -> UpdateStatus { + let mut start = &src[..lint.declaration_range.start]; + if start.ends_with("\n\n") { + start = &start[..start.len() - 1]; + } + let mut end = &src[lint.declaration_range.end..]; + if end.starts_with("\n\n") { + end = &end[1..]; + } + dst.push_str(start); + dst.push_str(end); + UpdateStatus::Changed }); - let mut impl_lint_pass_end = content[impl_lint_pass_start..] - .find(']') - .expect("failed to find `impl_lint_pass` terminator"); + false + }; + delete_test_files( + lint.name, + &lints[lint_idx..] + .iter() + .map(|l| l.name) + .take_while(|&n| n.starts_with(lint.name)) + .collect::>(), + ); - impl_lint_pass_end += impl_lint_pass_start; - if let Some(lint_name_pos) = content[impl_lint_pass_start..impl_lint_pass_end].find(lint_name_upper) { - let mut lint_name_end = impl_lint_pass_start + (lint_name_pos + lint_name_upper.len()); - for c in content[lint_name_end..impl_lint_pass_end].chars() { - // Remove trailing whitespace - if c == ',' || c.is_whitespace() { - lint_name_end += 1; - } else { - break; - } - } - - content.replace_range(impl_lint_pass_start + lint_name_pos..lint_name_end, ""); - } - } - - if path.exists() - && let Some(lint) = lints.iter().find(|l| l.name == name) - { - if lint.module == name { - // The lint name is the same as the file, we can just delete the entire file - fs::remove_file(path)?; - } else { - // We can't delete the entire file, just remove the declaration - - if let Some(Some("mod.rs")) = path.file_name().map(OsStr::to_str) { - // Remove clippy_lints/src/some_mod/some_lint.rs - let mut lint_mod_path = path.to_path_buf(); - lint_mod_path.set_file_name(name); - lint_mod_path.set_extension("rs"); - - let _ = fs::remove_file(lint_mod_path); - } - - let mut content = - fs::read_to_string(path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy())); - - eprintln!( - "warn: you will have to manually remove any code related to `{name}` from `{}`", - path.display() - ); - - assert!( - content[lint.declaration_range].contains(&name.to_uppercase()), - "error: `{}` does not contain lint `{}`'s declaration", - path.display(), - lint.name - ); - - // Remove lint declaration (declare_clippy_lint!) - content.replace_range(lint.declaration_range, ""); - - // Remove the module declaration (mod xyz;) - let mod_decl = format!("\nmod {name};"); - content = content.replacen(&mod_decl, "", 1); - - remove_impl_lint_pass(&lint.name.to_uppercase(), &mut content); - fs::write(path, content).unwrap_or_else(|_| panic!("failed to write to `{}`", path.to_string_lossy())); - } - - remove_test_assets(name); - remove_lint(name, lints); - return Ok(true); - } - - Ok(false) -} - -#[derive(Clone, Copy)] -enum ModEdit { - None, - Delete, - Rename, + delete_mod } fn collect_ui_test_names(lint: &str, ignored_prefixes: &[&str], dst: &mut Vec<(OsString, bool)>) { @@ -445,12 +355,50 @@ fn snake_to_pascal(s: &str) -> String { String::from_utf8(dst).unwrap() } -#[expect(clippy::too_many_lines)] -fn file_update_fn<'a, 'b>( +/// Creates an update function which replaces all instances of `clippy::old_name` with +/// `new_name`. +fn uplift_update_fn<'a>( old_name: &'a str, - new_name: &'b str, - mod_edit: ModEdit, -) -> impl use<'a, 'b> + FnMut(&Path, &str, &mut String) -> UpdateStatus { + new_name: &'a str, + remove_mod: bool, +) -> impl use<'a> + FnMut(&Path, &str, &mut String) -> UpdateStatus { + move |_, src, dst| { + let mut copy_pos = 0u32; + let mut changed = false; + let mut cursor = Cursor::new(src); + while let Some(ident) = cursor.find_any_ident() { + match cursor.get_text(ident) { + "mod" + if remove_mod && cursor.match_all(&[cursor::Pat::Ident(old_name), cursor::Pat::Semi], &mut []) => + { + dst.push_str(&src[copy_pos as usize..ident.pos as usize]); + dst.push_str(new_name); + copy_pos = cursor.pos(); + if src[copy_pos as usize..].starts_with('\n') { + copy_pos += 1; + } + changed = true; + }, + "clippy" if cursor.match_all(&[cursor::Pat::DoubleColon, cursor::Pat::Ident(old_name)], &mut []) => { + dst.push_str(&src[copy_pos as usize..ident.pos as usize]); + dst.push_str(new_name); + copy_pos = cursor.pos(); + changed = true; + }, + + _ => {}, + } + } + dst.push_str(&src[copy_pos as usize..]); + UpdateStatus::from_changed(changed) + } +} + +fn rename_update_fn<'a>( + old_name: &'a str, + new_name: &'a str, + rename_mod: bool, +) -> impl use<'a> + FnMut(&Path, &str, &mut String) -> UpdateStatus { let old_name_pascal = snake_to_pascal(old_name); let new_name_pascal = snake_to_pascal(new_name); let old_name_upper = old_name.to_ascii_uppercase(); @@ -481,34 +429,15 @@ fn file_update_fn<'a, 'b>( }, // mod lint_name "mod" => { - if !matches!(mod_edit, ModEdit::None) - && let Some(pos) = cursor.find_ident(old_name) - { - match mod_edit { - ModEdit::Rename => { - dst.push_str(&src[copy_pos as usize..pos as usize]); - dst.push_str(new_name); - copy_pos = cursor.pos(); - changed = true; - }, - ModEdit::Delete if cursor.match_pat(cursor::Pat::Semi) => { - let mut start = &src[copy_pos as usize..match_start as usize]; - if start.ends_with("\n\n") { - start = &start[..start.len() - 1]; - } - dst.push_str(start); - copy_pos = cursor.pos(); - if src[copy_pos as usize..].starts_with("\n\n") { - copy_pos += 1; - } - changed = true; - }, - ModEdit::Delete | ModEdit::None => {}, - } + if rename_mod && let Some(pos) = cursor.match_ident(old_name) { + dst.push_str(&src[copy_pos as usize..pos as usize]); + dst.push_str(new_name); + copy_pos = cursor.pos(); + changed = true; } }, // lint_name:: - name if matches!(mod_edit, ModEdit::Rename) && name == old_name => { + name if rename_mod && name == old_name => { let name_end = cursor.pos(); if cursor.match_pat(cursor::Pat::DoubleColon) { dst.push_str(&src[copy_pos as usize..match_start as usize]); diff --git a/clippy_dev/src/parse/cursor.rs b/clippy_dev/src/parse/cursor.rs index 6dc003f326de..2c142af4883a 100644 --- a/clippy_dev/src/parse/cursor.rs +++ b/clippy_dev/src/parse/cursor.rs @@ -219,6 +219,22 @@ impl<'txt> Cursor<'txt> { } } + /// Consume the returns the position of the next non-whitespace token if it's an + /// identifier. Returns `None` otherwise. + pub fn match_ident(&mut self, s: &str) -> Option { + loop { + match self.next_token.kind { + TokenKind::Ident if s == self.peek_text() => { + let pos = self.pos; + self.step(); + return Some(pos); + }, + TokenKind::Whitespace => self.step(), + _ => return None, + } + } + } + /// Continually attempt to match the pattern on subsequent tokens until a match is /// found. Returns whether the pattern was successfully matched. /// From 2e556c490b67a4ea09cb39285b753bfc06a13604 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Sat, 10 Jan 2026 15:31:52 +0100 Subject: [PATCH 0593/1061] fix(unnecessary_map_or): respect reduced applicability --- clippy_lints/src/methods/unnecessary_map_or.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_map_or.rs b/clippy_lints/src/methods/unnecessary_map_or.rs index 0c01be4b1875..7377b43571ce 100644 --- a/clippy_lints/src/methods/unnecessary_map_or.rs +++ b/clippy_lints/src/methods/unnecessary_map_or.rs @@ -97,12 +97,12 @@ pub(super) fn check<'a>( // being converted to `Some(5) == Some(5).then(|| 1)` isn't // the same thing + let mut app = Applicability::MachineApplicable; let inner_non_binding = Sugg::NonParen(Cow::Owned(format!( "{wrap}({})", - Sugg::hir(cx, non_binding_location, "") + Sugg::hir_with_applicability(cx, non_binding_location, "", &mut app) ))); - let mut app = Applicability::MachineApplicable; let binop = make_binop( op.node, &Sugg::hir_with_applicability(cx, recv, "..", &mut app), From c8271c1daffb9f847147f852a6325304269d064e Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Sat, 10 Jan 2026 02:07:15 +0900 Subject: [PATCH 0594/1061] Added mGCA tests that were resolved --- .../mgca/assoc-const-projection-in-bound.rs | 27 ++++++++++++++++ .../mgca/cast-with-type-mismatched.rs | 14 ++++++++ .../mgca/cast-with-type-mismatched.stderr | 20 ++++++++++++ .../mgca/const-eval-with-invalid-args.rs | 26 +++++++++++++++ .../mgca/const-eval-with-invalid-args.stderr | 32 +++++++++++++++++++ .../recursive-self-referencing-const-param.rs | 11 +++++++ ...ursive-self-referencing-const-param.stderr | 23 +++++++++++++ .../mgca/size-of-generic-ptr-in-array-len.rs | 10 ++++++ .../size-of-generic-ptr-in-array-len.stderr | 8 +++++ 9 files changed, 171 insertions(+) create mode 100644 tests/ui/const-generics/mgca/assoc-const-projection-in-bound.rs create mode 100644 tests/ui/const-generics/mgca/cast-with-type-mismatched.rs create mode 100644 tests/ui/const-generics/mgca/cast-with-type-mismatched.stderr create mode 100644 tests/ui/const-generics/mgca/const-eval-with-invalid-args.rs create mode 100644 tests/ui/const-generics/mgca/const-eval-with-invalid-args.stderr create mode 100644 tests/ui/const-generics/mgca/recursive-self-referencing-const-param.rs create mode 100644 tests/ui/const-generics/mgca/recursive-self-referencing-const-param.stderr create mode 100644 tests/ui/const-generics/mgca/size-of-generic-ptr-in-array-len.rs create mode 100644 tests/ui/const-generics/mgca/size-of-generic-ptr-in-array-len.stderr diff --git a/tests/ui/const-generics/mgca/assoc-const-projection-in-bound.rs b/tests/ui/const-generics/mgca/assoc-const-projection-in-bound.rs new file mode 100644 index 000000000000..460e14359483 --- /dev/null +++ b/tests/ui/const-generics/mgca/assoc-const-projection-in-bound.rs @@ -0,0 +1,27 @@ +//! regression test for +//@ run-pass +#![expect(incomplete_features)] +#![feature(min_generic_const_args)] +#![allow(dead_code)] + +trait Abc {} + +trait A { + #[type_const] + const VALUE: usize; +} + +impl A for T { + #[type_const] + const VALUE: usize = 0; +} + +trait S {} + +trait Handler +where + (): S<{ ::VALUE }>, +{ +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/cast-with-type-mismatched.rs b/tests/ui/const-generics/mgca/cast-with-type-mismatched.rs new file mode 100644 index 000000000000..1f499c222e7f --- /dev/null +++ b/tests/ui/const-generics/mgca/cast-with-type-mismatched.rs @@ -0,0 +1,14 @@ +//! regression test for +#![expect(incomplete_features)] +#![feature(generic_const_exprs)] +#![feature(min_generic_const_args)] + +fn foo(a: [(); N as usize]) {} +//~^ ERROR: complex const arguments must be placed inside of a `const` block + +const C: f32 = 1.0; + +fn main() { + foo::([]); + //~^ ERROR: the constant `C` is not of type `u32` +} diff --git a/tests/ui/const-generics/mgca/cast-with-type-mismatched.stderr b/tests/ui/const-generics/mgca/cast-with-type-mismatched.stderr new file mode 100644 index 000000000000..7e1b21138ec8 --- /dev/null +++ b/tests/ui/const-generics/mgca/cast-with-type-mismatched.stderr @@ -0,0 +1,20 @@ +error: complex const arguments must be placed inside of a `const` block + --> $DIR/cast-with-type-mismatched.rs:6:30 + | +LL | fn foo(a: [(); N as usize]) {} + | ^^^^^^^^^^ + +error: the constant `C` is not of type `u32` + --> $DIR/cast-with-type-mismatched.rs:12:11 + | +LL | foo::([]); + | ^ expected `u32`, found `f32` + | +note: required by a const generic parameter in `foo` + --> $DIR/cast-with-type-mismatched.rs:6:8 + | +LL | fn foo(a: [(); N as usize]) {} + | ^^^^^^^^^^^^ required by this const generic parameter in `foo` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/const-generics/mgca/const-eval-with-invalid-args.rs b/tests/ui/const-generics/mgca/const-eval-with-invalid-args.rs new file mode 100644 index 000000000000..3bf951e0c212 --- /dev/null +++ b/tests/ui/const-generics/mgca/const-eval-with-invalid-args.rs @@ -0,0 +1,26 @@ +//! regression test for +#![expect(incomplete_features)] +#![feature(generic_const_exprs)] +#![feature(min_generic_const_args)] + +// The previous ICE was an "invalid field access on immediate". +// If we remove `val: i32` from the field, another ICE occurs. +// "assertion `left == right` failed: invalid field type in +// Immediate::offset: scalar value has wrong size" +struct A { + arr: usize, + val: i32, +} + +struct B { + //~^ ERROR: `A` is forbidden as the type of a const generic parameter + arr: [u8; N.arr], + //~^ ERROR: complex const arguments must be placed inside of a `const` block +} + +const C: u32 = 1; +fn main() { + let b = B:: {arr: [1]}; + //~^ ERROR: the constant `C` is not of type `A` + let _ = b.arr.len(); +} diff --git a/tests/ui/const-generics/mgca/const-eval-with-invalid-args.stderr b/tests/ui/const-generics/mgca/const-eval-with-invalid-args.stderr new file mode 100644 index 000000000000..a226718ccf1b --- /dev/null +++ b/tests/ui/const-generics/mgca/const-eval-with-invalid-args.stderr @@ -0,0 +1,32 @@ +error: complex const arguments must be placed inside of a `const` block + --> $DIR/const-eval-with-invalid-args.rs:17:15 + | +LL | arr: [u8; N.arr], + | ^^^^^ + +error: `A` is forbidden as the type of a const generic parameter + --> $DIR/const-eval-with-invalid-args.rs:15:19 + | +LL | struct B { + | ^ + | + = note: the only supported types are integers, `bool`, and `char` +help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types + | +LL + #![feature(adt_const_params)] + | + +error: the constant `C` is not of type `A` + --> $DIR/const-eval-with-invalid-args.rs:23:17 + | +LL | let b = B:: {arr: [1]}; + | ^ expected `A`, found `u32` + | +note: required by a const generic parameter in `B` + --> $DIR/const-eval-with-invalid-args.rs:15:10 + | +LL | struct B { + | ^^^^^^^^^^ required by this const generic parameter in `B` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/const-generics/mgca/recursive-self-referencing-const-param.rs b/tests/ui/const-generics/mgca/recursive-self-referencing-const-param.rs new file mode 100644 index 000000000000..37dcc58ff468 --- /dev/null +++ b/tests/ui/const-generics/mgca/recursive-self-referencing-const-param.rs @@ -0,0 +1,11 @@ +//! regression test for +#![expect(incomplete_features)] +#![feature(generic_const_exprs)] +#![feature(min_generic_const_args)] + +fn identity }>() }>>(); +//~^ ERROR: free function without a body +//~| ERROR: expected type, found function `identity` +//~| ERROR: complex const arguments must be placed inside of a `const` block + +fn main() {} diff --git a/tests/ui/const-generics/mgca/recursive-self-referencing-const-param.stderr b/tests/ui/const-generics/mgca/recursive-self-referencing-const-param.stderr new file mode 100644 index 000000000000..d1899c476ec6 --- /dev/null +++ b/tests/ui/const-generics/mgca/recursive-self-referencing-const-param.stderr @@ -0,0 +1,23 @@ +error: free function without a body + --> $DIR/recursive-self-referencing-const-param.rs:6:1 + | +LL | fn identity }>() }>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- + | | + | help: provide a definition for the function: `{ }` + +error[E0573]: expected type, found function `identity` + --> $DIR/recursive-self-referencing-const-param.rs:6:22 + | +LL | fn identity }>() }>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a type + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/recursive-self-referencing-const-param.rs:6:57 + | +LL | fn identity }>() }>>(); + | ^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0573`. diff --git a/tests/ui/const-generics/mgca/size-of-generic-ptr-in-array-len.rs b/tests/ui/const-generics/mgca/size-of-generic-ptr-in-array-len.rs new file mode 100644 index 000000000000..2a7c23929845 --- /dev/null +++ b/tests/ui/const-generics/mgca/size-of-generic-ptr-in-array-len.rs @@ -0,0 +1,10 @@ +//! regression test for +#![expect(incomplete_features)] +#![feature(min_generic_const_args)] + +fn foo() { + [0; size_of::<*mut T>()]; + //~^ ERROR: tuple constructor with invalid base path +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/size-of-generic-ptr-in-array-len.stderr b/tests/ui/const-generics/mgca/size-of-generic-ptr-in-array-len.stderr new file mode 100644 index 000000000000..dcdc56a1cf47 --- /dev/null +++ b/tests/ui/const-generics/mgca/size-of-generic-ptr-in-array-len.stderr @@ -0,0 +1,8 @@ +error: tuple constructor with invalid base path + --> $DIR/size-of-generic-ptr-in-array-len.rs:6:9 + | +LL | [0; size_of::<*mut T>()]; + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + From c451e9bac648c9c6adcdbd9b4aa6067e38b606cb Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 19 Sep 2021 15:18:05 +0200 Subject: [PATCH 0595/1061] Remove a workaround for a bug I don't think it is necessary anymore. As I understand it from issue 39504 the original problem was that rustbuild changed a hardlink in the cargo build dir to point to copy in the sysroot while cargo may have hardlinked it to the original first. I don't think this happens anymore and as such this workaround is no longer necessary. --- compiler/rustc_metadata/src/locator.rs | 29 -------------------------- 1 file changed, 29 deletions(-) diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 6c30ce0ddb3d..004d73da8cbd 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -242,7 +242,6 @@ use crate::rmeta::{METADATA_HEADER, MetadataBlob, rustc_version}; pub(crate) struct CrateLocator<'a> { // Immutable per-session configuration. only_needs_metadata: bool, - sysroot: &'a Path, metadata_loader: &'a dyn MetadataLoader, cfg_version: &'static str, @@ -318,7 +317,6 @@ impl<'a> CrateLocator<'a> { CrateLocator { only_needs_metadata, - sysroot: sess.opts.sysroot.path(), metadata_loader, cfg_version: sess.cfg_version, crate_name, @@ -670,33 +668,6 @@ impl<'a> CrateLocator<'a> { continue; } - // Ok so at this point we've determined that `(lib, kind)` above is - // a candidate crate to load, and that `slot` is either none (this - // is the first crate of its kind) or if some the previous path has - // the exact same hash (e.g., it's the exact same crate). - // - // In principle these two candidate crates are exactly the same so - // we can choose either of them to link. As a stupidly gross hack, - // however, we favor crate in the sysroot. - // - // You can find more info in rust-lang/rust#39518 and various linked - // issues, but the general gist is that during testing libstd the - // compilers has two candidates to choose from: one in the sysroot - // and one in the deps folder. These two crates are the exact same - // crate but if the compiler chooses the one in the deps folder - // it'll cause spurious errors on Windows. - // - // As a result, we favor the sysroot crate here. Note that the - // candidates are all canonicalized, so we canonicalize the sysroot - // as well. - if let Some(prev) = &ret { - let sysroot = self.sysroot; - let sysroot = try_canonicalize(sysroot).unwrap_or_else(|_| sysroot.to_path_buf()); - if prev.starts_with(&sysroot) { - continue; - } - } - // We error eagerly here. If we're locating a rlib, then in theory the full metadata // could still be in a (later resolved) dylib. In practice, if the rlib and dylib // were produced in a way where one has full metadata and the other hasn't, it would From 6fa61dfd995fee8ec2f766964899b55c6f304fa1 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sun, 11 Jan 2026 09:06:44 +0100 Subject: [PATCH 0596/1061] Do not ignore statements before a `break` when simplifying loop The previous tests ignored statements in a block and only looked at the final expression to determine if the block was made of a single `break`. --- clippy_lints/src/loops/while_let_loop.rs | 30 ++++++++++++++---------- tests/ui/while_let_loop.rs | 21 +++++++++++++++++ 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/clippy_lints/src/loops/while_let_loop.rs b/clippy_lints/src/loops/while_let_loop.rs index d4285db0abfc..e2ea24c39980 100644 --- a/clippy_lints/src/loops/while_let_loop.rs +++ b/clippy_lints/src/loops/while_let_loop.rs @@ -40,7 +40,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_blo let_info, Some(if_let.if_then), ); - } else if els.and_then(|x| x.expr).is_some_and(is_simple_break_expr) + } else if els.is_some_and(is_simple_break_block) && let Some((pat, _)) = let_info { could_be_while_let(cx, expr, pat, init, has_trailing_exprs, let_info, None); @@ -61,17 +61,23 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_blo } } -/// Returns `true` if expr contains a single break expression without a label or sub-expression, -/// possibly embedded in blocks. -fn is_simple_break_expr(e: &Expr<'_>) -> bool { - if let ExprKind::Block(b, _) = e.kind { - match (b.stmts, b.expr) { - ([s], None) => matches!(s.kind, StmtKind::Expr(e) | StmtKind::Semi(e) if is_simple_break_expr(e)), - ([], Some(e)) => is_simple_break_expr(e), - _ => false, - } - } else { - matches!(e.kind, ExprKind::Break(dest, None) if dest.label.is_none()) +/// Checks if `block` contains a single unlabeled `break` expression or statement, possibly embedded +/// inside other blocks. +fn is_simple_break_block(block: &Block<'_>) -> bool { + match (block.stmts, block.expr) { + ([s], None) => matches!(s.kind, StmtKind::Expr(e) | StmtKind::Semi(e) if is_simple_break_expr(e)), + ([], Some(e)) => is_simple_break_expr(e), + _ => false, + } +} + +/// Checks if `expr` contains a single unlabeled `break` expression or statement, possibly embedded +/// inside other blocks. +fn is_simple_break_expr(expr: &Expr<'_>) -> bool { + match expr.kind { + ExprKind::Block(b, _) => is_simple_break_block(b), + ExprKind::Break(dest, None) => dest.label.is_none(), + _ => false, } } diff --git a/tests/ui/while_let_loop.rs b/tests/ui/while_let_loop.rs index f28c504742fd..b5a362669ce2 100644 --- a/tests/ui/while_let_loop.rs +++ b/tests/ui/while_let_loop.rs @@ -253,3 +253,24 @@ fn let_assign() { } } } + +fn issue16378() { + // This does not lint today because of the extra statement(s) + // before the `break`. + // TODO: When the `break` statement/expr in the `let`/`else` is the + // only way to leave the loop, the lint could trigger and move + // the statements preceeding the `break` after the loop, as in: + // ```rust + // while let Some(x) = std::hint::black_box(None::) { + // println!("x = {x}"); + // } + // println!("fail"); + // ``` + loop { + let Some(x) = std::hint::black_box(None::) else { + println!("fail"); + break; + }; + println!("x = {x}"); + } +} From 2b50456eb4b3b5abdb13a36b62a92a268b740d4e Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Sun, 23 Nov 2025 20:48:47 +0100 Subject: [PATCH 0597/1061] clean-up `unnecessary_map_or` and `manual_is_variant_and` - manual_is_variant_and: create `Flavor` using a function - removes one level of `for` --- .../src/methods/manual_is_variant_and.rs | 129 ++++++++++-------- clippy_lints/src/methods/mod.rs | 5 +- .../src/methods/unnecessary_map_or.rs | 34 ++--- tests/ui/unnecessary_map_or.fixed | 2 +- tests/ui/unnecessary_map_or.rs | 2 +- tests/ui/unnecessary_map_or.stderr | 38 +++--- 6 files changed, 111 insertions(+), 99 deletions(-) diff --git a/clippy_lints/src/methods/manual_is_variant_and.rs b/clippy_lints/src/methods/manual_is_variant_and.rs index 8f65858987b9..5ce9d364cdd8 100644 --- a/clippy_lints/src/methods/manual_is_variant_and.rs +++ b/clippy_lints/src/methods/manual_is_variant_and.rs @@ -1,12 +1,13 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeDef; -use clippy_utils::source::{snippet, snippet_with_applicability}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use clippy_utils::{get_parent_expr, sym}; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; +use rustc_hir::def_id::DefId; use rustc_hir::{BinOpKind, Closure, Expr, ExprKind, QPath}; use rustc_lint::LateContext; use rustc_middle::ty; @@ -14,7 +15,37 @@ use rustc_span::{Span, Symbol}; use super::MANUAL_IS_VARIANT_AND; -pub(super) fn check( +#[derive(Clone, Copy, PartialEq)] +enum Flavor { + Option, + Result, +} + +impl Flavor { + fn new(cx: &LateContext<'_>, def_id: DefId) -> Option { + match cx.tcx.get_diagnostic_name(def_id)? { + sym::Option => Some(Self::Option), + sym::Result => Some(Self::Result), + _ => None, + } + } + + const fn diag_sym(self) -> Symbol { + match self { + Self::Option => sym::Option, + Self::Result => sym::Result, + } + } + + const fn positive_variant_name(self) -> Symbol { + match self { + Self::Option => sym::Some, + Self::Result => sym::Ok, + } + } +} + +pub(super) fn check_map_unwrap_or_default( cx: &LateContext<'_>, expr: &Expr<'_>, map_recv: &Expr<'_>, @@ -30,11 +61,13 @@ pub(super) fn check( } // 2. the caller of `map()` is neither `Option` nor `Result` - let is_option = cx.typeck_results().expr_ty(map_recv).is_diag_item(cx, sym::Option); - let is_result = cx.typeck_results().expr_ty(map_recv).is_diag_item(cx, sym::Result); - if !is_option && !is_result { + let Some(flavor) = (cx.typeck_results()) + .expr_ty(map_recv) + .opt_def_id() + .and_then(|did| Flavor::new(cx, did)) + else { return; - } + }; // 3. the caller of `unwrap_or_default` is neither `Option` nor `Result` if !cx.typeck_results().expr_ty(expr).is_bool() { @@ -46,44 +79,23 @@ pub(super) fn check( return; } - let lint_msg = if is_option { - "called `map().unwrap_or_default()` on an `Option` value" - } else { - "called `map().unwrap_or_default()` on a `Result` value" + let lint_span = expr.span.with_lo(map_span.lo()); + let lint_msg = match flavor { + Flavor::Option => "called `map().unwrap_or_default()` on an `Option` value", + Flavor::Result => "called `map().unwrap_or_default()` on a `Result` value", }; - let suggestion = if is_option { "is_some_and" } else { "is_ok_and" }; - span_lint_and_sugg( - cx, - MANUAL_IS_VARIANT_AND, - expr.span.with_lo(map_span.lo()), - lint_msg, - "use", - format!("{}({})", suggestion, snippet(cx, map_arg.span, "..")), - Applicability::MachineApplicable, - ); -} + span_lint_and_then(cx, MANUAL_IS_VARIANT_AND, lint_span, lint_msg, |diag| { + let method = match flavor { + Flavor::Option => "is_some_and", + Flavor::Result => "is_ok_and", + }; -#[derive(Clone, Copy, PartialEq)] -enum Flavor { - Option, - Result, -} + let mut app = Applicability::MachineApplicable; + let map_arg_snippet = snippet_with_applicability(cx, map_arg.span, "_", &mut app); -impl Flavor { - const fn symbol(self) -> Symbol { - match self { - Self::Option => sym::Option, - Self::Result => sym::Result, - } - } - - const fn positive(self) -> Symbol { - match self { - Self::Option => sym::Some, - Self::Result => sym::Ok, - } - } + diag.span_suggestion(lint_span, "use", format!("{method}({map_arg_snippet})"), app); + }); } #[derive(Clone, Copy, PartialEq)] @@ -178,7 +190,7 @@ fn emit_lint<'tcx>( cx, MANUAL_IS_VARIANT_AND, span, - format!("called `.map() {op} {pos}()`", pos = flavor.positive(),), + format!("called `.map() {op} {pos}()`", pos = flavor.positive_variant_name()), "use", format!( "{inversion}{recv}.{method}({body})", @@ -195,24 +207,23 @@ pub(super) fn check_map(cx: &LateContext<'_>, expr: &Expr<'_>) { && op.span.eq_ctxt(expr.span) && let Ok(op) = Op::try_from(op.node) { - // Check `left` and `right` expression in any order, and for `Option` and `Result` + // Check `left` and `right` expression in any order for (expr1, expr2) in [(left, right), (right, left)] { - for flavor in [Flavor::Option, Flavor::Result] { - if let ExprKind::Call(call, [arg]) = expr1.kind - && let ExprKind::Lit(lit) = arg.kind - && let LitKind::Bool(bool_cst) = lit.node - && let ExprKind::Path(QPath::Resolved(_, path)) = call.kind - && let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), _) = path.res - && let ty = cx.typeck_results().expr_ty(expr1) - && let ty::Adt(adt, args) = ty.kind() - && cx.tcx.is_diagnostic_item(flavor.symbol(), adt.did()) - && args.type_at(0).is_bool() - && let ExprKind::MethodCall(_, recv, [map_expr], _) = expr2.kind - && cx.typeck_results().expr_ty(recv).is_diag_item(cx, flavor.symbol()) - && let Ok(map_func) = MapFunc::try_from(map_expr) - { - return emit_lint(cx, parent_expr.span, op, flavor, bool_cst, map_func, recv); - } + if let ExprKind::Call(call, [arg]) = expr1.kind + && let ExprKind::Lit(lit) = arg.kind + && let LitKind::Bool(bool_cst) = lit.node + && let ExprKind::Path(QPath::Resolved(_, path)) = call.kind + && let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), _) = path.res + && let ExprKind::MethodCall(_, recv, [map_expr], _) = expr2.kind + && let ty = cx.typeck_results().expr_ty(expr1) + && let ty::Adt(adt, args) = ty.kind() + && let Some(flavor) = Flavor::new(cx, adt.did()) + && args.type_at(0).is_bool() + && cx.typeck_results().expr_ty(recv).is_diag_item(cx, flavor.diag_sym()) + && let Ok(map_func) = MapFunc::try_from(map_expr) + { + emit_lint(cx, parent_expr.span, op, flavor, bool_cst, map_func, recv); + return; } } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index ee0cd95a5021..659a704a1ecb 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3933,7 +3933,8 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usage of `option.map(f).unwrap_or_default()` and `result.map(f).unwrap_or_default()` where f is a function or closure that returns the `bool` type. + /// Checks for usage of `option.map(f).unwrap_or_default()` and `result.map(f).unwrap_or_default()` where `f` is a function or closure that returns the `bool` type. + /// /// Also checks for equality comparisons like `option.map(f) == Some(true)` and `result.map(f) == Ok(true)`. /// /// ### Why is this bad? @@ -5629,7 +5630,7 @@ impl Methods { manual_saturating_arithmetic::check_sub_unwrap_or_default(cx, expr, lhs, rhs); }, Some((sym::map, m_recv, [arg], span, _)) => { - manual_is_variant_and::check(cx, expr, m_recv, arg, span, self.msrv); + manual_is_variant_and::check_map_unwrap_or_default(cx, expr, m_recv, arg, span, self.msrv); }, Some((then_method @ (sym::then | sym::then_some), t_recv, [t_arg], _, _)) => { obfuscated_if_else::check( diff --git a/clippy_lints/src/methods/unnecessary_map_or.rs b/clippy_lints/src/methods/unnecessary_map_or.rs index 7377b43571ce..21e112360aaf 100644 --- a/clippy_lints/src/methods/unnecessary_map_or.rs +++ b/clippy_lints/src/methods/unnecessary_map_or.rs @@ -8,7 +8,7 @@ use clippy_utils::sugg::{Sugg, make_binop}; use clippy_utils::ty::{implements_trait, is_copy}; use clippy_utils::visitors::is_local_used; use clippy_utils::{get_parent_expr, is_from_proc_macro}; -use rustc_ast::LitKind::Bool; +use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PatKind}; use rustc_lint::LateContext; @@ -48,13 +48,14 @@ pub(super) fn check<'a>( let ExprKind::Lit(def_kind) = def.kind else { return; }; - - let recv_ty = cx.typeck_results().expr_ty_adjusted(recv); - - let Bool(def_bool) = def_kind.node else { + let LitKind::Bool(def_bool) = def_kind.node else { return; }; + let typeck = cx.typeck_results(); + + let recv_ty = typeck.expr_ty_adjusted(recv); + let variant = match recv_ty.opt_diag_name(cx) { Some(sym::Option) => Variant::Some, Some(sym::Result) => Variant::Ok, @@ -63,12 +64,12 @@ pub(super) fn check<'a>( let ext_def_span = def.span.until(map.span); - let (sugg, method, applicability) = if cx.typeck_results().expr_adjustments(recv).is_empty() + let (sugg, method, applicability): (_, Cow<'_, _>, _) = if typeck.expr_adjustments(recv).is_empty() && let ExprKind::Closure(map_closure) = map.kind && let closure_body = cx.tcx.hir_body(map_closure.body) && let closure_body_value = closure_body.value.peel_blocks() && let ExprKind::Binary(op, l, r) = closure_body_value.kind - && let Some(param) = closure_body.params.first() + && let [param] = closure_body.params && let PatKind::Binding(_, hir_id, _, _) = param.pat.kind // checking that map_or is one of the following: // .map_or(false, |x| x == y) @@ -78,14 +79,13 @@ pub(super) fn check<'a>( && ((BinOpKind::Eq == op.node && !def_bool) || (BinOpKind::Ne == op.node && def_bool)) && let non_binding_location = if l.res_local_id() == Some(hir_id) { r } else { l } && switch_to_eager_eval(cx, non_binding_location) - // if its both then that's a strange edge case and + // if it's both then that's a strange edge case and // we can just ignore it, since by default clippy will error on this && (l.res_local_id() == Some(hir_id)) != (r.res_local_id() == Some(hir_id)) && !is_local_used(cx, non_binding_location, hir_id) - && let typeck_results = cx.typeck_results() - && let l_ty = typeck_results.expr_ty(l) - && l_ty == typeck_results.expr_ty(r) - && let Some(partial_eq) = cx.tcx.get_diagnostic_item(sym::PartialEq) + && let l_ty = typeck.expr_ty(l) + && l_ty == typeck.expr_ty(r) + && let Some(partial_eq) = cx.tcx.lang_items().eq_trait() && implements_trait(cx, recv_ty, partial_eq, &[recv_ty.into()]) && is_copy(cx, l_ty) { @@ -126,18 +126,18 @@ pub(super) fn check<'a>( } .into_string(); - (vec![(expr.span, sugg)], "a standard comparison", app) + (vec![(expr.span, sugg)], "a standard comparison".into(), app) } else if !def_bool && msrv.meets(cx, msrvs::OPTION_RESULT_IS_VARIANT_AND) { let suggested_name = variant.method_name(); ( - vec![(method_span, suggested_name.into()), (ext_def_span, String::default())], - suggested_name, + vec![(method_span, suggested_name.into()), (ext_def_span, String::new())], + format!("`{suggested_name}`").into(), Applicability::MachineApplicable, ) } else if def_bool && matches!(variant, Variant::Some) && msrv.meets(cx, msrvs::IS_NONE_OR) { ( - vec![(method_span, "is_none_or".into()), (ext_def_span, String::default())], - "is_none_or", + vec![(method_span, "is_none_or".into()), (ext_def_span, String::new())], + "`is_none_or`".into(), Applicability::MachineApplicable, ) } else { diff --git a/tests/ui/unnecessary_map_or.fixed b/tests/ui/unnecessary_map_or.fixed index 10552431d65d..52c114339292 100644 --- a/tests/ui/unnecessary_map_or.fixed +++ b/tests/ui/unnecessary_map_or.fixed @@ -70,7 +70,7 @@ fn main() { let _ = r.is_ok_and(|x| x == 7); //~^ unnecessary_map_or - // lint constructs that are not comparaisons as well + // lint constructs that are not comparisons as well let func = |_x| true; let r: Result = Ok(3); let _ = r.is_ok_and(func); diff --git a/tests/ui/unnecessary_map_or.rs b/tests/ui/unnecessary_map_or.rs index 4b406ec2998b..dd2e1a569469 100644 --- a/tests/ui/unnecessary_map_or.rs +++ b/tests/ui/unnecessary_map_or.rs @@ -74,7 +74,7 @@ fn main() { let _ = r.map_or(false, |x| x == 7); //~^ unnecessary_map_or - // lint constructs that are not comparaisons as well + // lint constructs that are not comparisons as well let func = |_x| true; let r: Result = Ok(3); let _ = r.map_or(false, func); diff --git a/tests/ui/unnecessary_map_or.stderr b/tests/ui/unnecessary_map_or.stderr index b8a22346c378..d11e7179f921 100644 --- a/tests/ui/unnecessary_map_or.stderr +++ b/tests/ui/unnecessary_map_or.stderr @@ -56,7 +56,7 @@ LL | | 6 >= 5 LL | | }); | |______^ | -help: use is_some_and instead +help: use `is_some_and` instead | LL - let _ = Some(5).map_or(false, |n| { LL + let _ = Some(5).is_some_and(|n| { @@ -68,7 +68,7 @@ error: this `map_or` can be simplified LL | let _ = Some(vec![5]).map_or(false, |n| n == [5]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use is_some_and instead +help: use `is_some_and` instead | LL - let _ = Some(vec![5]).map_or(false, |n| n == [5]); LL + let _ = Some(vec![5]).is_some_and(|n| n == [5]); @@ -80,7 +80,7 @@ error: this `map_or` can be simplified LL | let _ = Some(vec![1]).map_or(false, |n| vec![2] == n); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use is_some_and instead +help: use `is_some_and` instead | LL - let _ = Some(vec![1]).map_or(false, |n| vec![2] == n); LL + let _ = Some(vec![1]).is_some_and(|n| vec![2] == n); @@ -92,7 +92,7 @@ error: this `map_or` can be simplified LL | let _ = Some(5).map_or(false, |n| n == n); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use is_some_and instead +help: use `is_some_and` instead | LL - let _ = Some(5).map_or(false, |n| n == n); LL + let _ = Some(5).is_some_and(|n| n == n); @@ -104,7 +104,7 @@ error: this `map_or` can be simplified LL | let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use is_some_and instead +help: use `is_some_and` instead | LL - let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 }); LL + let _ = Some(5).is_some_and(|n| n == if 2 > 1 { n } else { 0 }); @@ -116,7 +116,7 @@ error: this `map_or` can be simplified LL | let _ = Ok::, i32>(vec![5]).map_or(false, |n| n == [5]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use is_ok_and instead +help: use `is_ok_and` instead | LL - let _ = Ok::, i32>(vec![5]).map_or(false, |n| n == [5]); LL + let _ = Ok::, i32>(vec![5]).is_ok_and(|n| n == [5]); @@ -152,7 +152,7 @@ error: this `map_or` can be simplified LL | let _ = Some(5).map_or(true, |n| n == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use is_none_or instead +help: use `is_none_or` instead | LL - let _ = Some(5).map_or(true, |n| n == 5); LL + let _ = Some(5).is_none_or(|n| n == 5); @@ -164,7 +164,7 @@ error: this `map_or` can be simplified LL | let _ = Some(5).map_or(true, |n| 5 == n); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use is_none_or instead +help: use `is_none_or` instead | LL - let _ = Some(5).map_or(true, |n| 5 == n); LL + let _ = Some(5).is_none_or(|n| 5 == n); @@ -212,7 +212,7 @@ error: this `map_or` can be simplified LL | let _ = r.map_or(false, |x| x == 7); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use is_ok_and instead +help: use `is_ok_and` instead | LL - let _ = r.map_or(false, |x| x == 7); LL + let _ = r.is_ok_and(|x| x == 7); @@ -224,7 +224,7 @@ error: this `map_or` can be simplified LL | let _ = r.map_or(false, func); | ^^^^^^^^^^^^^^^^^^^^^ | -help: use is_ok_and instead +help: use `is_ok_and` instead | LL - let _ = r.map_or(false, func); LL + let _ = r.is_ok_and(func); @@ -236,7 +236,7 @@ error: this `map_or` can be simplified LL | let _ = Some(5).map_or(false, func); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use is_some_and instead +help: use `is_some_and` instead | LL - let _ = Some(5).map_or(false, func); LL + let _ = Some(5).is_some_and(func); @@ -248,7 +248,7 @@ error: this `map_or` can be simplified LL | let _ = Some(5).map_or(true, func); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use is_none_or instead +help: use `is_none_or` instead | LL - let _ = Some(5).map_or(true, func); LL + let _ = Some(5).is_none_or(func); @@ -272,7 +272,7 @@ error: this `map_or` can be simplified LL | o.map_or(true, |n| n > 5) || (o as &Option).map_or(true, |n| n < 5) | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use is_none_or instead +help: use `is_none_or` instead | LL - o.map_or(true, |n| n > 5) || (o as &Option).map_or(true, |n| n < 5) LL + o.is_none_or(|n| n > 5) || (o as &Option).map_or(true, |n| n < 5) @@ -284,7 +284,7 @@ error: this `map_or` can be simplified LL | o.map_or(true, |n| n > 5) || (o as &Option).map_or(true, |n| n < 5) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use is_none_or instead +help: use `is_none_or` instead | LL - o.map_or(true, |n| n > 5) || (o as &Option).map_or(true, |n| n < 5) LL + o.map_or(true, |n| n > 5) || (o as &Option).is_none_or(|n| n < 5) @@ -296,7 +296,7 @@ error: this `map_or` can be simplified LL | o.map_or(true, |n| n > 5) | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use is_none_or instead +help: use `is_none_or` instead | LL - o.map_or(true, |n| n > 5) LL + o.is_none_or(|n| n > 5) @@ -308,7 +308,7 @@ error: this `map_or` can be simplified LL | let x = a.map_or(false, |a| a == *s); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use is_some_and instead +help: use `is_some_and` instead | LL - let x = a.map_or(false, |a| a == *s); LL + let x = a.is_some_and(|a| a == *s); @@ -320,7 +320,7 @@ error: this `map_or` can be simplified LL | let y = b.map_or(true, |b| b == *s); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use is_none_or instead +help: use `is_none_or` instead | LL - let y = b.map_or(true, |b| b == *s); LL + let y = b.is_none_or(|b| b == *s); @@ -356,7 +356,7 @@ error: this `map_or` can be simplified LL | _ = s.lock().unwrap().map_or(false, |s| s == "foo"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use is_some_and instead +help: use `is_some_and` instead | LL - _ = s.lock().unwrap().map_or(false, |s| s == "foo"); LL + _ = s.lock().unwrap().is_some_and(|s| s == "foo"); @@ -368,7 +368,7 @@ error: this `map_or` can be simplified LL | _ = s.map_or(false, |s| s == "foo"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use is_some_and instead +help: use `is_some_and` instead | LL - _ = s.map_or(false, |s| s == "foo"); LL + _ = s.is_some_and(|s| s == "foo"); From 41939ae3b31848a9d854c25ce2c1973de5e64e6c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Jan 2026 11:48:16 +0100 Subject: [PATCH 0598/1061] test closing std streams separately, and in two configurations --- .../miri/tests/pass-dep/libc/close-std-streams.rs | 13 +++++++++++++ src/tools/miri/tests/pass-dep/libc/libc-fs.rs | 11 +---------- 2 files changed, 14 insertions(+), 10 deletions(-) create mode 100644 src/tools/miri/tests/pass-dep/libc/close-std-streams.rs diff --git a/src/tools/miri/tests/pass-dep/libc/close-std-streams.rs b/src/tools/miri/tests/pass-dep/libc/close-std-streams.rs new file mode 100644 index 000000000000..cc30d9557fc6 --- /dev/null +++ b/src/tools/miri/tests/pass-dep/libc/close-std-streams.rs @@ -0,0 +1,13 @@ +//@ignore-target: windows # no libc +//@ revisions: default null +//@[null] compile-flags: -Zmiri-mute-stdout-stderr + +fn main() { + // This is std library UB, but that's not relevant since we're + // only interacting with libc here. + unsafe { + libc::close(0); + libc::close(1); + libc::close(2); + } +} diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs index 8c860b5db7ba..00d5f7d97e28 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs @@ -1,4 +1,4 @@ -//@ignore-target: windows # File handling is not implemented yet +//@ignore-target: windows # no libc //@compile-flags: -Zmiri-disable-isolation #![feature(io_error_more)] @@ -48,7 +48,6 @@ fn main() { test_nofollow_not_symlink(); #[cfg(target_os = "macos")] test_ioctl(); - test_close_stdout(); } fn test_file_open_unix_allow_two_args() { @@ -580,11 +579,3 @@ fn test_ioctl() { assert_eq!(libc::ioctl(fd, libc::FIOCLEX), 0); } } - -fn test_close_stdout() { - // This is std library UB, but that's not relevant since we're - // only interacting with libc here. - unsafe { - libc::close(1); - } -} From 90b32e731b7899adf31067716883cbf483b6f72f Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Mon, 12 Jan 2026 14:56:04 +0100 Subject: [PATCH 0599/1061] Fix typo in `MaybeUninit` docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit –- → – (extra ASCII minus after endash) Introduced in https://github.com/rust-lang/rust/pull/140463 (11627f00c0599c5d033b3e38e3196786537c439b). --- library/core/src/mem/maybe_uninit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index e0001153a6e7..320eb97f83a4 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -256,7 +256,7 @@ use crate::{fmt, intrinsics, ptr, slice}; /// /// # Validity /// -/// `MaybeUninit` has no validity requirements –- any sequence of [bytes] of +/// `MaybeUninit` has no validity requirements – any sequence of [bytes] of /// the appropriate length, initialized or uninitialized, are a valid /// representation. /// From 50b60aaff331e6d938c18ee6d2f08691b36db9d0 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Mon, 12 Jan 2026 11:31:20 +0530 Subject: [PATCH 0600/1061] std: sys: net: uefi: Make TcpStream Send - Since UEFI has no threads, this should be safe. - Makes compiling remote-test-server simpler. Signed-off-by: Ayush Singh --- library/std/src/sys/net/connection/uefi/tcp.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/std/src/sys/net/connection/uefi/tcp.rs b/library/std/src/sys/net/connection/uefi/tcp.rs index 3e79aa049187..1e58db0d7046 100644 --- a/library/std/src/sys/net/connection/uefi/tcp.rs +++ b/library/std/src/sys/net/connection/uefi/tcp.rs @@ -9,6 +9,9 @@ pub(crate) enum Tcp { V4(tcp4::Tcp4), } +// SAFETY: UEFI has no threads. +unsafe impl Send for Tcp {} + impl Tcp { pub(crate) fn connect(addr: &SocketAddr, timeout: Option) -> io::Result { match addr { From d2e8aaa42fd3a2107fecbfc700863469909fc996 Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 12 Jan 2026 17:16:49 +0100 Subject: [PATCH 0601/1061] std: use `ByteStr`'s `Display` for `OsStr` --- library/std/src/sys/os_str/bytes.rs | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs index 7ba6c46eaef4..5482663ef007 100644 --- a/library/std/src/sys/os_str/bytes.rs +++ b/library/std/src/sys/os_str/bytes.rs @@ -4,8 +4,8 @@ use core::clone::CloneToUninit; use crate::borrow::Cow; +use crate::bstr::ByteStr; use crate::collections::TryReserveError; -use crate::fmt::Write; use crate::rc::Rc; use crate::sync::Arc; use crate::sys::{AsInner, FromInner, IntoInner}; @@ -64,25 +64,7 @@ impl fmt::Debug for Slice { impl fmt::Display for Slice { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // If we're the empty string then our iterator won't actually yield - // anything, so perform the formatting manually - if self.inner.is_empty() { - return "".fmt(f); - } - - for chunk in self.inner.utf8_chunks() { - let valid = chunk.valid(); - // If we successfully decoded the whole chunk as a valid string then - // we can return a direct formatting of the string which will also - // respect various formatting flags if possible. - if chunk.invalid().is_empty() { - return valid.fmt(f); - } - - f.write_str(valid)?; - f.write_char(char::REPLACEMENT_CHARACTER)?; - } - Ok(()) + fmt::Display::fmt(ByteStr::new(&self.inner), f) } } From 3badf708c41402254349861d1a49cd3d9e128e99 Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Mon, 8 Dec 2025 18:22:33 +0300 Subject: [PATCH 0602/1061] Mention an extra argument required to check tests Add a note to tests-related lint descriptions that clippy needs to be run with e.g. `--tests` argument to actually check tests, which is not quite obvious. --- clippy_lints/src/attrs/mod.rs | 4 ++++ clippy_lints/src/redundant_test_prefix.rs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index 42c321df61c1..fa2951d91934 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -468,6 +468,10 @@ declare_clippy_lint! { /// #[ignore = "Some good reason"] /// fn test() {} /// ``` + /// + /// ### Note + /// Clippy can only lint compiled code. For this lint to trigger, you must configure `cargo clippy` + /// to include test compilation, for instance, by using flags such as `--tests` or `--all-targets`. #[clippy::version = "1.88.0"] pub IGNORE_WITHOUT_REASON, pedantic, diff --git a/clippy_lints/src/redundant_test_prefix.rs b/clippy_lints/src/redundant_test_prefix.rs index 84276e321657..602093259eae 100644 --- a/clippy_lints/src/redundant_test_prefix.rs +++ b/clippy_lints/src/redundant_test_prefix.rs @@ -47,6 +47,10 @@ declare_clippy_lint! { /// } /// } /// ``` + /// + /// ### Note + /// Clippy can only lint compiled code. For this lint to trigger, you must configure `cargo clippy` + /// to include test compilation, for instance, by using flags such as `--tests` or `--all-targets`. #[clippy::version = "1.88.0"] pub REDUNDANT_TEST_PREFIX, restriction, From 439da0745347783ed5516caaccf3b96468ff858f Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Mon, 12 Jan 2026 18:01:10 +0100 Subject: [PATCH 0603/1061] Update books --- src/doc/nomicon | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/nomicon b/src/doc/nomicon index 5b3a9d084cbc..050c002a360f 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 5b3a9d084cbc64e54da87e3eec7c7faae0e48ba9 +Subproject commit 050c002a360fa45b701ea34feed7a860dc8a41bf diff --git a/src/doc/reference b/src/doc/reference index 6363385ac4eb..28b5a5441998 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 6363385ac4ebe1763f1e6fb2063c0b1db681a072 +Subproject commit 28b5a54419985f03db5294de5eede71b6665b594 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 2e02f22a10e7..8de6ff811315 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 2e02f22a10e7eeb758e6aba484f13d0f1988a3e5 +Subproject commit 8de6ff811315ac3a96ebe01d74057382e42ffdee From 418cff3ec04a836490a71e9853b9fff48847d32e Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Sun, 11 Jan 2026 00:23:45 +0100 Subject: [PATCH 0604/1061] Port `#[must_not_suspend]` to attribute parser --- .../rustc_attr_parsing/src/attributes/mod.rs | 1 + .../src/attributes/must_not_suspend.rs | 35 +++++++++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 3 +- .../rustc_hir/src/attrs/data_structures.rs | 3 ++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_mir_transform/src/coroutine.rs | 15 ++++---- compiler/rustc_mir_transform/src/errors.rs | 2 +- compiler/rustc_passes/messages.ftl | 4 --- compiler/rustc_passes/src/check_attr.rs | 12 +------ compiler/rustc_passes/src/errors.rs | 9 ----- tests/ui/attributes/malformed-attrs.stderr | 31 ++++++++-------- tests/ui/lint/must_not_suspend/other_items.rs | 2 +- .../lint/must_not_suspend/other_items.stderr | 6 ++-- tests/ui/lint/must_not_suspend/return.rs | 2 +- tests/ui/lint/must_not_suspend/return.stderr | 12 +++---- 15 files changed, 77 insertions(+), 61 deletions(-) create mode 100644 compiler/rustc_attr_parsing/src/attributes/must_not_suspend.rs diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index fafac7ea909d..e02d71a26158 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -47,6 +47,7 @@ pub(crate) mod link_attrs; pub(crate) mod lint_helpers; pub(crate) mod loop_match; pub(crate) mod macro_attrs; +pub(crate) mod must_not_suspend; pub(crate) mod must_use; pub(crate) mod no_implicit_prelude; pub(crate) mod no_link; diff --git a/compiler/rustc_attr_parsing/src/attributes/must_not_suspend.rs b/compiler/rustc_attr_parsing/src/attributes/must_not_suspend.rs new file mode 100644 index 000000000000..8456ce797758 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/must_not_suspend.rs @@ -0,0 +1,35 @@ +use super::prelude::*; + +pub(crate) struct MustNotSuspendParser; + +impl SingleAttributeParser for MustNotSuspendParser { + const PATH: &[rustc_span::Symbol] = &[sym::must_not_suspend]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Struct), + Allow(Target::Enum), + Allow(Target::Union), + Allow(Target::Trait), + ]); + const TEMPLATE: AttributeTemplate = template!(Word, List: &["count"]); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { + let reason = match args { + ArgParser::NameValue(reason) => match reason.value_as_str() { + Some(val) => Some(val), + None => { + cx.expected_nv_or_no_args(reason.value_span); + return None; + } + }, + ArgParser::NoArgs => None, + ArgParser::List(list) => { + cx.expected_nv_or_no_args(list.span); + return None; + } + }; + + Some(AttributeKind::MustNotSupend { reason }) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 835bf8ae5c9c..0217b6370408 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -51,6 +51,7 @@ use crate::attributes::macro_attrs::{ AllowInternalUnsafeParser, CollapseDebugInfoParser, MacroEscapeParser, MacroExportParser, MacroUseParser, }; +use crate::attributes::must_not_suspend::MustNotSuspendParser; use crate::attributes::must_use::MustUseParser; use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser; use crate::attributes::no_link::NoLinkParser; @@ -89,7 +90,6 @@ use crate::session_diagnostics::{ AttributeParseError, AttributeParseErrorReason, ParsedDescription, }; use crate::target_checking::AllowedTargets; - type GroupType = LazyLock>; pub(super) struct GroupTypeInner { @@ -208,6 +208,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, Single, Single, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index a5ecfa45fb40..b3c1974c0031 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -824,6 +824,9 @@ pub enum AttributeKind { /// Represents `#[move_size_limit]` MoveSizeLimit { attr_span: Span, limit_span: Span, limit: Limit }, + /// Represents `#[must_not_suspend]` + MustNotSupend { reason: Option }, + /// Represents `#[must_use]`. MustUse { span: Span, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index efdb4f2f22b2..e02e954c94a5 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -71,6 +71,7 @@ impl AttributeKind { Marker(..) => No, MayDangle(..) => No, MoveSizeLimit { .. } => No, + MustNotSupend { .. } => Yes, MustUse { .. } => Yes, Naked(..) => No, NoCore(..) => No, diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 7fad380ba5a1..705551c58f32 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -64,9 +64,9 @@ use itertools::izip; use rustc_abi::{FieldIdx, VariantIdx}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::pluralize; -use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; use rustc_hir::lang_items::LangItem; -use rustc_hir::{CoroutineDesugaring, CoroutineKind}; +use rustc_hir::{self as hir, CoroutineDesugaring, CoroutineKind, find_attr}; use rustc_index::bit_set::{BitMatrix, DenseBitSet, GrowableBitSet}; use rustc_index::{Idx, IndexVec, indexvec}; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; @@ -85,7 +85,6 @@ use rustc_mir_dataflow::{ }; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::source_map::dummy_spanned; -use rustc_span::symbol::sym; use rustc_span::{DUMMY_SP, Span}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::TyCtxtInferExt as _; @@ -1989,11 +1988,11 @@ fn check_must_not_suspend_def( hir_id: hir::HirId, data: SuspendCheckData<'_>, ) -> bool { - if let Some(attr) = tcx.get_attr(def_id, sym::must_not_suspend) { - let reason = attr.value_str().map(|s| errors::MustNotSuspendReason { - span: data.source_span, - reason: s.as_str().to_string(), - }); + if let Some(reason_str) = + find_attr!(tcx.get_all_attrs(def_id), AttributeKind::MustNotSupend {reason} => reason) + { + let reason = + reason_str.map(|s| errors::MustNotSuspendReason { span: data.source_span, reason: s }); tcx.emit_node_span_lint( rustc_session::lint::builtin::MUST_NOT_SUSPEND, hir_id, diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 21a6c4d653bc..d4c58f7fe05d 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -323,7 +323,7 @@ impl<'a> LintDiagnostic<'a, ()> for MustNotSupend<'_, '_> { pub(crate) struct MustNotSuspendReason { #[primary_span] pub span: Span, - pub reason: String, + pub reason: Symbol, } #[derive(Diagnostic)] diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 39ad541ee85a..9628e6d4efe9 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -376,10 +376,6 @@ passes_must_implement_not_function_note = all `#[rustc_must_implement_one_of]` a passes_must_implement_not_function_span_note = required by this annotation -passes_must_not_suspend = - `must_not_suspend` attribute should be applied to a struct, enum, union, or trait - .label = is not a struct, enum, union, or trait - passes_no_main_function = `main` function not found in crate `{$crate_name}` .here_is_main = here is a function named `main` diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 717a0e54d0c6..c9357b99cea2 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -308,6 +308,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::ThreadLocal | AttributeKind::CfiEncoding { .. } | AttributeKind::RustcHasIncoherentInherentImpls + | AttributeKind::MustNotSupend { .. } ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); @@ -325,7 +326,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | [sym::rustc_dirty, ..] | [sym::rustc_if_this_changed, ..] | [sym::rustc_then_this_would_need, ..] => self.check_rustc_dirty_clean(attr), - [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target), [sym::autodiff_forward, ..] | [sym::autodiff_reverse, ..] => { self.check_autodiff(hir_id, attr, span, target) } @@ -1197,16 +1197,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks if `#[must_not_suspend]` is applied to a struct, enum, union, or trait. - fn check_must_not_suspend(&self, attr: &Attribute, span: Span, target: Target) { - match target { - Target::Struct | Target::Enum | Target::Union | Target::Trait => {} - _ => { - self.dcx().emit_err(errors::MustNotSuspend { attr_span: attr.span(), span }); - } - } - } - /// Checks if `#[may_dangle]` is applied to a lifetime or type generic parameter in `Drop` impl. fn check_may_dangle(&self, hir_id: HirId, attr_span: Span) { if let hir::Node::GenericParam(param) = self.tcx.hir_node(hir_id) diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index ace738c559a4..49b9618ef2af 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -194,15 +194,6 @@ pub(crate) struct BothFfiConstAndPure { pub attr_span: Span, } -#[derive(Diagnostic)] -#[diag(passes_must_not_suspend)] -pub(crate) struct MustNotSuspend { - #[primary_span] - pub attr_span: Span, - #[label] - pub span: Span, -} - #[derive(LintDiagnostic)] #[diag(passes_link)] #[warning] diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index fd6f34fb45e2..fc644668735e 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -32,21 +32,6 @@ error: malformed `patchable_function_entry` attribute input LL | #[patchable_function_entry] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` -error: malformed `must_not_suspend` attribute input - --> $DIR/malformed-attrs.rs:138:1 - | -LL | #[must_not_suspend()] - | ^^^^^^^^^^^^^^^^^^^^^ - | -help: the following are the possible correct uses - | -LL - #[must_not_suspend()] -LL + #[must_not_suspend = "reason"] - | -LL - #[must_not_suspend()] -LL + #[must_not_suspend] - | - error: malformed `allow` attribute input --> $DIR/malformed-attrs.rs:184:1 | @@ -527,6 +512,22 @@ 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[E0539]: malformed `must_not_suspend` attribute input + --> $DIR/malformed-attrs.rs:138:1 + | +LL | #[must_not_suspend()] + | ^^^^^^^^^^^^^^^^^^--^ + | | + | didn't expect a list here + | +help: try changing it to one of the following valid forms of the attribute + | +LL | #[must_not_suspend(count)] + | +++++ +LL - #[must_not_suspend()] +LL + #[must_not_suspend] + | + error[E0539]: malformed `cfi_encoding` attribute input --> $DIR/malformed-attrs.rs:140:1 | diff --git a/tests/ui/lint/must_not_suspend/other_items.rs b/tests/ui/lint/must_not_suspend/other_items.rs index 7a42a2bba03b..1c46cce7ed3a 100644 --- a/tests/ui/lint/must_not_suspend/other_items.rs +++ b/tests/ui/lint/must_not_suspend/other_items.rs @@ -2,7 +2,7 @@ #![feature(must_not_suspend)] #![deny(must_not_suspend)] -#[must_not_suspend] //~ ERROR attribute should be +#[must_not_suspend] //~ ERROR attribute cannot be used on modules mod inner {} fn main() {} diff --git a/tests/ui/lint/must_not_suspend/other_items.stderr b/tests/ui/lint/must_not_suspend/other_items.stderr index dff5210b7e47..999a9d2fb3dc 100644 --- a/tests/ui/lint/must_not_suspend/other_items.stderr +++ b/tests/ui/lint/must_not_suspend/other_items.stderr @@ -1,10 +1,10 @@ -error: `must_not_suspend` attribute should be applied to a struct, enum, union, or trait +error: `#[must_not_suspend]` attribute cannot be used on modules --> $DIR/other_items.rs:5:1 | LL | #[must_not_suspend] | ^^^^^^^^^^^^^^^^^^^ -LL | mod inner {} - | ------------ is not a struct, enum, union, or trait + | + = help: `#[must_not_suspend]` can be applied to data types, traits, and unions error: aborting due to 1 previous error diff --git a/tests/ui/lint/must_not_suspend/return.rs b/tests/ui/lint/must_not_suspend/return.rs index a04f6a4cfb43..de78ee0f9299 100644 --- a/tests/ui/lint/must_not_suspend/return.rs +++ b/tests/ui/lint/must_not_suspend/return.rs @@ -2,7 +2,7 @@ #![feature(must_not_suspend)] #![deny(must_not_suspend)] -#[must_not_suspend] //~ ERROR attribute should be +#[must_not_suspend] //~ ERROR attribute cannot be used on functions fn foo() -> i32 { 0 } diff --git a/tests/ui/lint/must_not_suspend/return.stderr b/tests/ui/lint/must_not_suspend/return.stderr index 440f81656862..1a81b1a39f0c 100644 --- a/tests/ui/lint/must_not_suspend/return.stderr +++ b/tests/ui/lint/must_not_suspend/return.stderr @@ -1,12 +1,10 @@ -error: `must_not_suspend` attribute should be applied to a struct, enum, union, or trait +error: `#[must_not_suspend]` attribute cannot be used on functions --> $DIR/return.rs:5:1 | -LL | #[must_not_suspend] - | ^^^^^^^^^^^^^^^^^^^ -LL | / fn foo() -> i32 { -LL | | 0 -LL | | } - | |_- is not a struct, enum, union, or trait +LL | #[must_not_suspend] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: `#[must_not_suspend]` can be applied to data types, traits, and unions error: aborting due to 1 previous error From 573c3097a335148ba58bc9e350a9b2a1f0fd663e Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 12 Jan 2026 18:42:17 +0100 Subject: [PATCH 0605/1061] Fix perf of `check_crate_level` refactor --- compiler/rustc_attr_parsing/src/target_checking.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index 52c2d10f4797..79aa06e9475c 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -10,6 +10,7 @@ use rustc_span::sym; use crate::AttributeParser; use crate::context::{AcceptContext, Stage}; use crate::session_diagnostics::InvalidTarget; +use crate::target_checking::Policy::Allow; #[derive(Debug)] pub(crate) enum AllowedTargets { @@ -88,7 +89,9 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { target: Target, cx: &mut AcceptContext<'_, 'sess, S>, ) { - if allowed_targets.allowed_targets() == &[Target::Crate] { + // For crate-level attributes we emit a specific set of lints to warn + // people about accidentally not using them on the crate. + if let &AllowedTargets::AllowList(&[Allow(Target::Crate)]) = allowed_targets { Self::check_crate_level(target, cx); return; } @@ -146,8 +149,6 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { } pub(crate) fn check_crate_level(target: Target, cx: &mut AcceptContext<'_, 'sess, S>) { - // For crate-level attributes we emit a specific set of lints to warn - // people about accidentally not using them on the crate. if target == Target::Crate { return; } From ffe359fe2b61a48b7b0e13dfbdbdbbc1abeab654 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 20:07:26 +0200 Subject: [PATCH 0606/1061] another corner case --- src/doc/rustc-dev-guide/ci/sembr/src/main.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs index d41a57d6f747..ebcd472d7012 100644 --- a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs +++ b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs @@ -80,6 +80,7 @@ fn ignore(line: &str, in_code_block: bool) -> bool { in_code_block || line.to_lowercase().contains("e.g.") || line.to_lowercase().contains("n.b.") + || line.contains(" etc.") || line.contains("i.e.") || line.contains("et. al") || line.contains('|') @@ -189,6 +190,7 @@ must! be. split? ignore | tables ignore e.g. and ignore i.e. and +ignore etc. and ignore E.g. too - list. entry * list. entry @@ -212,6 +214,7 @@ split? ignore | tables ignore e.g. and ignore i.e. and +ignore etc. and ignore E.g. too - list. entry From 52a5023e762475c7384c8711489dba916dd7fd3d Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 20:08:03 +0200 Subject: [PATCH 0607/1061] sembr src/external-repos.md --- src/doc/rustc-dev-guide/src/external-repos.md | 48 +++++++++++-------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/external-repos.md b/src/doc/rustc-dev-guide/src/external-repos.md index c43c1f680acf..3d5a0075389e 100644 --- a/src/doc/rustc-dev-guide/src/external-repos.md +++ b/src/doc/rustc-dev-guide/src/external-repos.md @@ -30,8 +30,8 @@ The following external projects are managed using some form of a `subtree`: In contrast to `submodule` dependencies (see below for those), the `subtree` dependencies are just regular files and directories which can be updated in tree. However, if possible, enhancements, bug fixes, etc. specific -to these tools should be filed against the tools directly in their respective -upstream repositories. The exception is that when rustc changes are required to +to these tools should be filed against the tools directly in their respective upstream repositories. +The exception is that when rustc changes are required to implement a new tool feature or test, that should happen in one collective rustc PR. `subtree` dependencies are currently managed by two distinct approaches: @@ -51,7 +51,9 @@ implement a new tool feature or test, that should happen in one collective rustc ### Josh subtrees -The [josh] tool is an alternative to git subtrees, which manages git history in a different way and scales better to larger repositories. Specific tooling is required to work with josh. We provide a helper [`rustc-josh-sync`][josh-sync] tool to help with the synchronization, described [below](#synchronizing-a-josh-subtree). +The [josh] tool is an alternative to git subtrees, which manages git history in a different way and scales better to larger repositories. +Specific tooling is required to work with josh. +We provide a helper [`rustc-josh-sync`][josh-sync] tool to help with the synchronization, described [below](#synchronizing-a-josh-subtree). ### Synchronizing a Josh subtree @@ -69,8 +71,7 @@ changes from the subtree to rust-lang/rust) are performed from the subtree repos switch to its repository checkout directory in your terminal). #### Performing pull -1) Checkout a new branch that will be used to create a PR into the subtree -2) Run the pull command +1) Checkout a new branch that will be used to create a PR into the subtree 2) Run the pull command ``` rustc-josh-sync pull ``` @@ -97,7 +98,8 @@ If you want to migrate a repository dependency from `git subtree` or `git submod Periodically the changes made to subtree based dependencies need to be synchronized between this repository and the upstream tool repositories. -Subtree synchronizations are typically handled by the respective tool maintainers. Other users +Subtree synchronizations are typically handled by the respective tool maintainers. +Other users are welcome to submit synchronization PRs, however, in order to do so you will need to modify your local git installation and follow a very precise set of instructions. These instructions are documented, along with several useful tips and tricks, in the @@ -108,8 +110,8 @@ use the correct corresponding subtree directory and remote repository. The synchronization process goes in two directions: `subtree push` and `subtree pull`. A `subtree push` takes all the changes that happened to the copy in this repo and creates commits -on the remote repo that match the local changes. Every local -commit that touched the subtree causes a commit on the remote repo, but +on the remote repo that match the local changes. +Every local commit that touched the subtree causes a commit on the remote repo, but is modified to move the files from the specified directory to the tool repo root. A `subtree pull` takes all changes since the last `subtree pull` @@ -119,14 +121,17 @@ the tool changes into the specified directory in the Rust repository. It is recommended that you always do a push first and get that merged to the default branch of the tool. Then, when you do a pull, the merge works without conflicts. While it's definitely possible to resolve conflicts during a pull, you may have to redo the conflict -resolution if your PR doesn't get merged fast enough and there are new conflicts. Do not try to +resolution if your PR doesn't get merged fast enough and there are new conflicts. +Do not try to rebase the result of a `git subtree pull`, rebasing merge commits is a bad idea in general. You always need to specify the `-P` prefix to the subtree directory and the corresponding remote -repository. If you specify the wrong directory or repository +repository. +If you specify the wrong directory or repository you'll get very fun merges that try to push the wrong directory to the wrong remote repository. Luckily you can just abort this without any consequences by throwing away either the pulled commits -in rustc or the pushed branch on the remote and try again. It is usually fairly obvious +in rustc or the pushed branch on the remote and try again. +It is usually fairly obvious that this is happening because you suddenly get thousands of commits that want to be synchronized. [clippy-sync-docs]: https://doc.rust-lang.org/nightly/clippy/development/infrastructure/sync.html @@ -140,8 +145,8 @@ repository's root directory!) git subtree add -P src/tools/clippy https://github.com/rust-lang/rust-clippy.git master ``` -This will create a new commit, which you may not rebase under any circumstances! Delete the commit -and redo the operation if you need to rebase. +This will create a new commit, which you may not rebase under any circumstances! +Delete the commit and redo the operation if you need to rebase. Now you're done, the `src/tools/clippy` directory behaves as if Clippy were part of the rustc monorepo, so no one but you (or others that synchronize @@ -149,24 +154,25 @@ subtrees) actually needs to use `git subtree`. ## External Dependencies (submodules) -Building Rust will also use external git repositories tracked using [git -submodules]. The complete list may be found in the [`.gitmodules`] file. Some -of these projects are required (like `stdarch` for the standard library) and +Building Rust will also use external git repositories tracked using [git submodules]. +The complete list may be found in the [`.gitmodules`] file. +Some of these projects are required (like `stdarch` for the standard library) and some of them are optional (like `src/doc/book`). Usage of submodules is discussed more in the [Using Git chapter](git.md#git-submodules). Some of the submodules are allowed to be in a "broken" state where they either don't build or their tests don't pass, e.g. the documentation books -like [The Rust Reference]. Maintainers of these projects will be notified -when the project is in a broken state, and they should fix them as soon -as possible. The current status is tracked on the [toolstate website]. +like [The Rust Reference]. +Maintainers of these projects will be notified +when the project is in a broken state, and they should fix them as soon as possible. +The current status is tracked on the [toolstate website]. More information may be found on the Forge [Toolstate chapter]. In practice, it is very rare for documentation to have broken toolstate. Breakage is not allowed in the beta and stable channels, and must be addressed -before the PR is merged. They are also not allowed to be broken on `main` in -the week leading up to the beta cut. +before the PR is merged. +They are also not allowed to be broken on `main` in the week leading up to the beta cut. [git submodules]: https://git-scm.com/book/en/v2/Git-Tools-Submodules [`.gitmodules`]: https://github.com/rust-lang/rust/blob/HEAD/.gitmodules From 2204cbd9871e6052d4f7ffcddf0de0bbdeb879ad Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 20:14:36 +0200 Subject: [PATCH 0608/1061] "in tree" should be "in-tree" --- src/doc/rustc-dev-guide/src/external-repos.md | 2 +- src/doc/rustc-dev-guide/src/tests/directives.md | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/external-repos.md b/src/doc/rustc-dev-guide/src/external-repos.md index 3d5a0075389e..c5e5b40e5a25 100644 --- a/src/doc/rustc-dev-guide/src/external-repos.md +++ b/src/doc/rustc-dev-guide/src/external-repos.md @@ -29,7 +29,7 @@ The following external projects are managed using some form of a `subtree`: In contrast to `submodule` dependencies (see below for those), the `subtree` dependencies are just regular files and directories which can -be updated in tree. However, if possible, enhancements, bug fixes, etc. specific +be updated in-tree. However, if possible, enhancements, bug fixes, etc. specific to these tools should be filed against the tools directly in their respective upstream repositories. The exception is that when rustc changes are required to implement a new tool feature or test, that should happen in one collective rustc PR. diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 52e1f09dca0f..83272a769a54 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -130,7 +130,7 @@ means the test won't be compiled or run. main test files but that `compiletest` should not try to build the file itself. Please backlink to which main test is actually using the auxiliary file. * `ignore-test` always ignores the test. This can be used to temporarily disable - a test if it is currently not working, but you want to keep it in tree to + a test if it is currently not working, but you want to keep it in-tree to re-enable it later. Some examples of `X` in `ignore-X` or `only-X`: @@ -211,7 +211,7 @@ settings: - `needs-target-std` — ignores if target platform does not have std support. - `ignore-backends` — ignores the listed backends, separated by whitespace characters. Please note that this directive can be overriden with the `--bypass-ignore-backends=[BACKEND]` command line - flag. + flag. - `needs-backends` — only runs the test if current codegen backend is listed. - `needs-offload` — ignores if our LLVM backend was not built with offload support. - `needs-enzyme` — ignores if our Enzyme submodule was not built. @@ -290,9 +290,9 @@ You can also force `./x test` to use a specific edition by passing the `-- --edi However, tests with the `//@ edition` directive will clamp the value passed to the argument. For example, if we run `./x test -- --edition=2015`: -- A test with the `//@ edition: 2018` will run with the 2018 edition. -- A test with the `//@ edition: 2015..2021` will be run with the 2015 edition. -- A test with the `//@ edition: 2018..` will run with the 2018 edition. +- A test with the `//@ edition: 2018` will run with the 2018 edition. +- A test with the `//@ edition: 2015..2021` will be run with the 2015 edition. +- A test with the `//@ edition: 2018..` will run with the 2018 edition. ### Rustdoc From c4b05c3883e00eaa7eeec854ded90a9f9576c4fd Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 20:24:28 +0200 Subject: [PATCH 0609/1061] fix sembr tool limitation --- src/doc/rustc-dev-guide/src/external-repos.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/external-repos.md b/src/doc/rustc-dev-guide/src/external-repos.md index c5e5b40e5a25..7c8cc3b5d62c 100644 --- a/src/doc/rustc-dev-guide/src/external-repos.md +++ b/src/doc/rustc-dev-guide/src/external-repos.md @@ -71,11 +71,12 @@ changes from the subtree to rust-lang/rust) are performed from the subtree repos switch to its repository checkout directory in your terminal). #### Performing pull -1) Checkout a new branch that will be used to create a PR into the subtree 2) Run the pull command +1. Checkout a new branch that will be used to create a PR into the subtree +2. Run the pull command ``` rustc-josh-sync pull ``` -3) Push the branch to your fork and create a PR into the subtree repository +3. Push the branch to your fork and create a PR into the subtree repository - If you have `gh` CLI installed, `rustc-josh-sync` can create the PR for you. #### Performing push @@ -83,11 +84,11 @@ switch to its repository checkout directory in your terminal). > NOTE: > Before you proceed, look at some guidance related to Git [on josh-sync README]. -1) Run the push command to create a branch named `` in a `rustc` fork under the `` account +1. Run the push command to create a branch named `` in a `rustc` fork under the `` account ``` rustc-josh-sync push ``` -2) Create a PR from `` into `rust-lang/rust` +2. Create a PR from `` into `rust-lang/rust` ### Creating a new Josh subtree dependency From 9a81699f061c0ec39efda7cb5c959a309ad7f71f Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 20:24:52 +0200 Subject: [PATCH 0610/1061] use a stronger pause --- src/doc/rustc-dev-guide/src/external-repos.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/external-repos.md b/src/doc/rustc-dev-guide/src/external-repos.md index 7c8cc3b5d62c..2e32fcfe78c1 100644 --- a/src/doc/rustc-dev-guide/src/external-repos.md +++ b/src/doc/rustc-dev-guide/src/external-repos.md @@ -124,7 +124,7 @@ Then, when you do a pull, the merge works without conflicts. While it's definitely possible to resolve conflicts during a pull, you may have to redo the conflict resolution if your PR doesn't get merged fast enough and there are new conflicts. Do not try to -rebase the result of a `git subtree pull`, rebasing merge commits is a bad idea in general. +rebase the result of a `git subtree pull`; rebasing merge commits is a bad idea in general. You always need to specify the `-P` prefix to the subtree directory and the corresponding remote repository. From 98e65aa454b6bfc157ca719551e387c20e0367c6 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 20:42:16 +0200 Subject: [PATCH 0611/1061] handle another numbered list notation --- src/doc/rustc-dev-guide/ci/sembr/src/main.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs index ebcd472d7012..6f4ce4415f04 100644 --- a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs +++ b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs @@ -27,7 +27,7 @@ static REGEX_SPLIT: LazyLock = LazyLock::new(|| Regex::new(r"([^\.\d\-\*]\.|[^r]\?|!)\s").unwrap()); // list elements, numbered (1.) or not (- and *) static REGEX_LIST_ENTRY: LazyLock = - LazyLock::new(|| Regex::new(r"^\s*(\d\.|\-|\*)\s+").unwrap()); + LazyLock::new(|| Regex::new(r"^\s*(\d\.|\-|\*|\d\))\s+").unwrap()); fn main() -> Result<()> { let cli = Cli::parse(); @@ -194,6 +194,7 @@ ignore etc. and ignore E.g. too - list. entry * list. entry + 1) list. entry ``` some code. block ``` @@ -220,6 +221,8 @@ ignore E.g. too entry * list. entry + 1) list. + entry ``` some code. block ``` From 419655be815b3e46b38c2b76dc0818a77f9581f6 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 20:52:54 +0200 Subject: [PATCH 0612/1061] sembr src/tests/directives.md --- .../rustc-dev-guide/src/tests/directives.md | 167 ++++++++---------- 1 file changed, 77 insertions(+), 90 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 83272a769a54..0852f300b9be 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -7,8 +7,8 @@ FIXME(jieyouxu) completely revise this chapter. Directives are special comments that tell compiletest how to build and interpret a test. They may also appear in `rmake.rs` [run-make tests](compiletest.md#run-make-tests). -They are normally put after the short comment that explains the point of this -test. Compiletest test suites use `//@` to signal that a comment is a directive. +They are normally put after the short comment that explains the point of this test. +Compiletest test suites use `//@` to signal that a comment is a directive. For example, this test uses the `//@ compile-flags` command to specify a custom flag to give to rustc when the test is compiled: @@ -27,15 +27,16 @@ Directives can be standalone (like `//@ run-pass`) or take a value (like `//@ compile-flags: -C overflow-checks=off`). Directives are written one directive per line: you cannot write multiple -directives on the same line. For example, if you write `//@ only-x86 -only-windows` then `only-windows` is interpreted as a comment, not a separate -directive. +directives on the same line. +For example, if you write `//@ only-x86 +only-windows` then `only-windows` is interpreted as a comment, not a separate directive. ## Listing of compiletest directives -The following is a list of compiletest directives. Directives are linked to -sections that describe the command in more detail if available. This list may -not be exhaustive. Directives can generally be found by browsing the +The following is a list of compiletest directives. +Directives are linked to sections that describe the command in more detail if available. +This list may not be exhaustive. +Directives can generally be found by browsing the `TestProps` structure found in [`directives.rs`] from the compiletest source. [`directives.rs`]: https://github.com/rust-lang/rust/tree/HEAD/src/tools/compiletest/src/directives.rs @@ -65,8 +66,7 @@ See [Building auxiliary crates](compiletest.html#building-auxiliary-crates) ### Controlling outcome expectations -See [Controlling pass/fail -expectations](ui.md#controlling-passfail-expectations). +See [Controlling pass/fail expectations](ui.md#controlling-passfail-expectations). | Directive | Explanation | Supported test suites | Possible values | |-----------------------------|---------------------------------------------|-------------------------------------------|-----------------| @@ -87,8 +87,7 @@ expectations](ui.md#controlling-passfail-expectations). ### Controlling output snapshots and normalizations See [Normalization](ui.md#normalization), [Output -comparison](ui.md#output-comparison) and [Rustfix tests](ui.md#rustfix-tests) -for more details. +comparison](ui.md#output-comparison) and [Rustfix tests](ui.md#rustfix-tests) for more details. | Directive | Explanation | Supported test suites | Possible values | |-----------------------------------|--------------------------------------------------------------------------------------------------------------------------|----------------------------------------------|-----------------------------------------------------------------------------------------| @@ -115,8 +114,8 @@ for more details. [^check_stdout]: presently this has a weird quirk where the test binary's stdout and stderr gets concatenated and then - `error-pattern`s are matched on this combined output, which is ??? slightly - questionable to say the least. + `error-pattern`s are matched on this combined output, which is ??? + slightly questionable to say the least. ### Controlling when tests are run @@ -124,14 +123,13 @@ These directives are used to ignore the test in some situations, which means the test won't be compiled or run. * `ignore-X` where `X` is a target detail or other criteria on which to ignore the test (see below) -* `only-X` is like `ignore-X`, but will *only* run the test on that target or - stage +* `only-X` is like `ignore-X`, but will *only* run the test on that target or stage * `ignore-auxiliary` is intended for files that *participate* in one or more other main test files but that `compiletest` should not try to build the file itself. Please backlink to which main test is actually using the auxiliary file. -* `ignore-test` always ignores the test. This can be used to temporarily disable - a test if it is currently not working, but you want to keep it in-tree to - re-enable it later. +* `ignore-test` always ignores the test. + This can be used to temporarily disable + a test if it is currently not working, but you want to keep it in-tree to re-enable it later. Some examples of `X` in `ignore-X` or `only-X`: @@ -158,16 +156,15 @@ Some examples of `X` in `ignore-X` or `only-X`: - This needs to be enabled with `COMPILETEST_ENABLE_DIST_TESTS=1` - The `rustc_abi` of the target: e.g. `rustc_abi-x86_64-sse2` -The following directives will check rustc build settings and target -settings: +The following directives will check rustc build settings and target settings: - `needs-asm-support` — ignores if the **host** architecture doesn't have - stable support for `asm!`. For tests that cross-compile to explicit targets + stable support for `asm!`. + For tests that cross-compile to explicit targets via `--target`, use `needs-llvm-components` instead to ensure the appropriate backend is available. - `needs-profiler-runtime` — ignores the test if the profiler runtime was not - enabled for the target - (`build.profiler = true` in rustc's `bootstrap.toml`) + enabled for the target (`build.profiler = true` in rustc's `bootstrap.toml`) - `needs-sanitizer-support` — ignores if the sanitizer support was not enabled for the target (`sanitizers = true` in rustc's `bootstrap.toml`) - `needs-sanitizer-{address,hwaddress,leak,memory,thread}` — ignores if the @@ -175,41 +172,36 @@ settings: hardware-assisted AddressSanitizer, LeakSanitizer, MemorySanitizer or ThreadSanitizer respectively) - `needs-run-enabled` — ignores if it is a test that gets executed, and running - has been disabled. Running tests can be disabled with the `x test --run=never` - flag, or running on fuchsia. + has been disabled. + Running tests can be disabled with the `x test --run=never` flag, or running on fuchsia. - `needs-unwind` — ignores if the target does not support unwinding - `needs-rust-lld` — ignores if the rust lld support is not enabled (`rust.lld = true` in `bootstrap.toml`) - `needs-threads` — ignores if the target does not have threading support - `needs-subprocess` — ignores if the target does not have subprocess support -- `needs-symlink` — ignores if the target does not support symlinks. This can be - the case on Windows if the developer did not enable privileged symlink +- `needs-symlink` — ignores if the target does not support symlinks. + This can be the case on Windows if the developer did not enable privileged symlink permissions. -- `ignore-std-debug-assertions` — ignores if std was built with debug - assertions. -- `needs-std-debug-assertions` — ignores if std was not built with debug - assertions. -- `ignore-std-remap-debuginfo` — ignores if std was built with remapping of - it's sources. -- `needs-std-remap-debugino` — ignores if std was not built with remapping of - it's sources. -- `ignore-rustc-debug-assertions` — ignores if rustc was built with debug - assertions. -- `needs-rustc-debug-assertions` — ignores if rustc was not built with debug - assertions. +- `ignore-std-debug-assertions` — ignores if std was built with debug assertions. +- `needs-std-debug-assertions` — ignores if std was not built with debug assertions. +- `ignore-std-remap-debuginfo` — ignores if std was built with remapping of it's sources. +- `needs-std-remap-debugino` — ignores if std was not built with remapping of it's sources. +- `ignore-rustc-debug-assertions` — ignores if rustc was built with debug assertions. +- `needs-rustc-debug-assertions` — ignores if rustc was not built with debug assertions. - `needs-target-has-atomic` — ignores if target does not have support for all specified atomic widths, e.g. the test with `//@ needs-target-has-atomic: 8, - 16, ptr` will only run if it supports the comma-separated list of atomic - widths. + 16, ptr` will only run if it supports the comma-separated list of atomic widths. - `needs-dynamic-linking` — ignores if target does not support dynamic linking (which is orthogonal to it being unable to create `dylib` and `cdylib` crate types) - `needs-crate-type` — ignores if target platform does not support one or more - of the comma-delimited list of specified crate types. For example, + of the comma-delimited list of specified crate types. + For example, `//@ needs-crate-type: cdylib, proc-macro` will cause the test to be ignored on `wasm32-unknown-unknown` target because the target does not support the `proc-macro` crate type. - `needs-target-std` — ignores if target platform does not have std support. -- `ignore-backends` — ignores the listed backends, separated by whitespace characters. Please note +- `ignore-backends` — ignores the listed backends, separated by whitespace characters. + Please note that this directive can be overriden with the `--bypass-ignore-backends=[BACKEND]` command line flag. - `needs-backends` — only runs the test if current codegen backend is listed. @@ -220,29 +212,23 @@ The following directives will check LLVM support: - `exact-llvm-major-version: 19` — ignores if the llvm major version does not match the specified llvm major version. -- `min-llvm-version: 13.0` — ignored if the LLVM version is less than the given - value +- `min-llvm-version: 13.0` — ignored if the LLVM version is less than the given value - `min-system-llvm-version: 12.0` — ignored if using a system LLVM and its version is less than the given value - `max-llvm-major-version: 19` — ignored if the LLVM major version is higher than the given major version - `ignore-llvm-version: 9.0` — ignores a specific LLVM version -- `ignore-llvm-version: 7.0 - 9.9.9` — ignores LLVM versions in a range - (inclusive) -- `needs-llvm-components: powerpc` — ignores if the specific LLVM component was - not built. Note: The test will fail on CI (when - `COMPILETEST_REQUIRE_ALL_LLVM_COMPONENTS` is set) if the component does not - exist. +- `ignore-llvm-version: 7.0 - 9.9.9` — ignores LLVM versions in a range (inclusive) +- `needs-llvm-components: powerpc` — ignores if the specific LLVM component was not built. + Note: The test will fail on CI (when + `COMPILETEST_REQUIRE_ALL_LLVM_COMPONENTS` is set) if the component does not exist. - `needs-forced-clang-based-tests` — test is ignored unless the environment - variable `RUSTBUILD_FORCE_CLANG_BASED_TESTS` is set, which enables building - clang alongside LLVM + variable `RUSTBUILD_FORCE_CLANG_BASED_TESTS` is set, which enables building clang alongside LLVM - This is only set in two CI jobs ([`x86_64-gnu-debug`] and - [`aarch64-gnu-debug`]), which only runs a - subset of `run-make` tests. Other tests with this directive will not - run at all, which is usually not what you want. + [`aarch64-gnu-debug`]), which only runs a subset of `run-make` tests. + Other tests with this directive will not run at all, which is usually not what you want. -See also [Debuginfo tests](compiletest.md#debuginfo-tests) for directives for -ignoring debuggers. +See also [Debuginfo tests](compiletest.md#debuginfo-tests) for directives for ignoring debuggers. [remote testing]: running.md#running-tests-on-a-remote-machine [compare modes]: ui.md#compare-modes @@ -311,7 +297,8 @@ Asked in The test suites [`rustdoc-html`][rustdoc-html-tests], [`rustdoc-js`/`rustdoc-js-std`][rustdoc-js-tests] and [`rustdoc-json`][rustdoc-json-tests] each feature an additional set of directives whose basic syntax resembles the one of compiletest directives but which are ultimately read and checked by -separate tools. For more information, please read their respective chapters as linked above. +separate tools. +For more information, please read their respective chapters as linked above. [rustdoc-html-tests]: ../rustdoc-internals/rustdoc-html-test-suite.md [rustdoc-js-tests]: ../rustdoc-internals/search.html#testing-the-search-engine @@ -327,8 +314,7 @@ See [Pretty-printer](compiletest.md#pretty-printer-tests). - [`revisions`](compiletest.md#revisions) — compile multiple times -[`forbid-output`](compiletest.md#incremental-tests) — incremental cfail rejects output pattern -- [`should-ice`](compiletest.md#incremental-tests) — incremental cfail should - ICE +- [`should-ice`](compiletest.md#incremental-tests) — incremental cfail should ICE - [`reference`] — an annotation linking to a rule in the reference - `disable-gdb-pretty-printers` — disable gdb pretty printers for debuginfo tests @@ -348,40 +334,37 @@ test suites that use those tools: ### Tidy specific directives -The following directives control how the [tidy script](../conventions.md#formatting) -verifies tests. +The following directives control how the [tidy script](../conventions.md#formatting) verifies tests. - `ignore-tidy-target-specific-tests` disables checking that the appropriate LLVM component is required (via a `needs-llvm-components` directive) when a - test is compiled for a specific target (via the `--target` flag in a - `compile-flag` directive). + test is compiled for a specific target (via the `--target` flag in a `compile-flag` directive). - [`unused-revision-names`](compiletest.md#ignoring-unused-revision-names) - suppress tidy checks for mentioning unknown revision names. ## Substitutions Directive values support substituting a few variables which will be replaced -with their corresponding value. For example, if you need to pass a compiler flag +with their corresponding value. +For example, if you need to pass a compiler flag with a path to a specific file, something like the following could work: ```rust,ignore //@ compile-flags: --remap-path-prefix={{src-base}}=/the/src ``` -Where the sentinel `{{src-base}}` will be replaced with the appropriate path -described below: +Where the sentinel `{{src-base}}` will be replaced with the appropriate path described below: -- `{{cwd}}`: The directory where compiletest is run from. This may not be the - root of the checkout, so you should avoid using it where possible. +- `{{cwd}}`: The directory where compiletest is run from. + This may not be the root of the checkout, so you should avoid using it where possible. - Examples: `/path/to/rust`, `/path/to/build/root` -- `{{src-base}}`: The directory where the test is defined. This is equivalent to - `$DIR` for [output normalization]. +- `{{src-base}}`: The directory where the test is defined. + This is equivalent to `$DIR` for [output normalization]. - Example: `/path/to/rust/tests/ui/error-codes` -- `{{build-base}}`: The base directory where the test's output goes. This is - equivalent to `$TEST_BUILD_DIR` for [output normalization]. +- `{{build-base}}`: The base directory where the test's output goes. + This is equivalent to `$TEST_BUILD_DIR` for [output normalization]. - Example: `/path/to/rust/build/x86_64-unknown-linux-gnu/test/ui` -- `{{rust-src-base}}`: The sysroot directory where libstd/libcore/... are - located +- `{{rust-src-base}}`: The sysroot directory where libstd/libcore/... are located - `{{sysroot-base}}`: Path of the sysroot directory used to build the test. - Mainly intended for `ui-fulldeps` tests that run the compiler via API. - `{{target-linker}}`: Linker that would be passed to `-Clinker` for this test, @@ -400,7 +383,8 @@ for an example of a test that uses this substitution. ## Adding a directive One would add a new directive if there is a need to define some test property or -behavior on an individual, test-by-test basis. A directive property serves as +behavior on an individual, test-by-test basis. +A directive property serves as the directive's backing store (holds the command's current value) at runtime. To add a new directive property: @@ -420,19 +404,21 @@ declaration block is found in [`src/tools/compiletest/src/common.rs`]). `TestProps`'s `load_from()` method will try passing the current line of text to each parser, which, in turn typically checks to see if the line begins with a particular commented (`//@`) directive such as `//@ must-compile-successfully` -or `//@ failure-status`. Whitespace after the comment marker is optional. +or `//@ failure-status`. +Whitespace after the comment marker is optional. Parsers will override a given directive property's default value merely by being specified in the test file as a directive or by having a parameter value specified in the test file, depending on the directive. Parsers defined in `impl Config` are typically named `parse_` -(note kebab-case `` transformed to snake-case -``). `impl Config` also defines several 'low-level' parsers +(note kebab-case `` transformed to snake-case ``). +`impl Config` also defines several 'low-level' parsers which make it simple to parse common patterns like simple presence or not (`parse_name_directive()`), `directive:parameter(s)` (`parse_name_value_directive()`), optional parsing only if a particular `cfg` -attribute is defined (`has_cfg_prefix()`) and many more. The low-level parsers +attribute is defined (`has_cfg_prefix()`) and many more. +The low-level parsers are found near the end of the `impl Config` block; be sure to look through them and their associated parsers immediately above to see how they are used to avoid writing additional parsing code unnecessarily. @@ -483,15 +469,16 @@ As a concrete example, here is the implementation for the ### Implementing the behavior change When a test invokes a particular directive, it is expected that some behavior -will change as a result. What behavior, obviously, will depend on the purpose of -the directive. In the case of `failure-status`, the behavior that changes is +will change as a result. +What behavior, obviously, will depend on the purpose of the directive. +In the case of `failure-status`, the behavior that changes is that `compiletest` expects the failure code defined by the directive invoked in the test, rather than the default value. Although specific to `failure-status` (as every directive will have a different implementation in order to invoke behavior change) perhaps it is helpful to see -the behavior change implementation of one case, simply as an example. To -implement `failure-status`, the `check_correct_failure_status()` function found +the behavior change implementation of one case, simply as an example. +To implement `failure-status`, the `check_correct_failure_status()` function found in the `TestCx` implementation block, located in [`src/tools/compiletest/src/runtest.rs`], was modified as per below: @@ -532,10 +519,10 @@ in the `TestCx` implementation block, located in } ``` -Note the use of `self.props.failure_status` to access the directive property. In -tests which do not specify the failure status directive, -`self.props.failure_status` will evaluate to the default value of 101 at the -time of this writing. But for a test which specifies a directive of, for +Note the use of `self.props.failure_status` to access the directive property. +In tests which do not specify the failure status directive, +`self.props.failure_status` will evaluate to the default value of 101 at the time of this writing. +But for a test which specifies a directive of, for example, `//@ failure-status: 1`, `self.props.failure_status` will evaluate to 1, as `parse_failure_status()` will have overridden the `TestProps` default value, for that test specifically. From 6b5a1a51e5f3f1cf1bffb072c4d6ebaa04400744 Mon Sep 17 00:00:00 2001 From: Guilherme Luiz Date: Mon, 12 Jan 2026 16:39:54 -0300 Subject: [PATCH 0613/1061] =?UTF-8?q?Switch=20from=20=EF=AC=83=20to=20?= =?UTF-8?q?=EF=AC=85=20ligature=20for=20better=20visual=20clarity?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- library/core/src/char/methods.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 0acb3e964f54..87b328c91287 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -1143,12 +1143,12 @@ impl char { /// [Unicode Standard]: https://www.unicode.org/versions/latest/ /// /// # Examples - /// `'ffi'` (U+FB03) is a single Unicode code point (a ligature) that maps to "FFI" in uppercase. + /// `'ſt'` (U+FB05) is a single Unicode code point (a ligature) that maps to "ST" in uppercase. /// /// As an iterator: /// /// ``` - /// for c in 'ffi'.to_uppercase() { + /// for c in 'ſt'.to_uppercase() { /// print!("{c}"); /// } /// println!(); @@ -1157,13 +1157,13 @@ impl char { /// Using `println!` directly: /// /// ``` - /// println!("{}", 'ffi'.to_uppercase()); + /// println!("{}", 'ſt'.to_uppercase()); /// ``` /// /// Both are equivalent to: /// /// ``` - /// println!("FFI"); + /// println!("ST"); /// ``` /// /// Using [`to_string`](../std/string/trait.ToString.html#tymethod.to_string): @@ -1172,7 +1172,7 @@ impl char { /// assert_eq!('c'.to_uppercase().to_string(), "C"); /// /// // Sometimes the result is more than one character: - /// assert_eq!('ffi'.to_uppercase().to_string(), "FFI"); + /// assert_eq!('ſt'.to_uppercase().to_string(), "ST"); /// /// // Characters that do not have both uppercase and lowercase /// // convert into themselves. From b57c2493339dd2d0dd4a8df6ed7ee81b81e84816 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 12 Jan 2026 14:42:00 -0500 Subject: [PATCH 0614/1061] fix: make `Type::of` supported unsized types --- library/core/src/mem/type_info.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index 7938e2b52ed0..6b16bfadc233 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -31,7 +31,7 @@ impl Type { #[unstable(feature = "type_info", issue = "146922")] #[rustc_const_unstable(feature = "type_info", issue = "146922")] // FIXME(reflection): don't require the 'static bound - pub const fn of() -> Self { + pub const fn of() -> Self { const { TypeId::of::().info() } } } From 1bde2f4705d351e24eb556604c0da5511a277e15 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 12 Jan 2026 14:43:21 -0500 Subject: [PATCH 0615/1061] chore: test `Type::of` on unsized types I chose to simply extend `dump.rs`, rather than create a new UI test. --- tests/ui/reflection/dump.rs | 2 ++ tests/ui/reflection/dump.run.stdout | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/ui/reflection/dump.rs b/tests/ui/reflection/dump.rs index 3bf4f32b6641..efc3024a84e9 100644 --- a/tests/ui/reflection/dump.rs +++ b/tests/ui/reflection/dump.rs @@ -27,4 +27,6 @@ fn main() { println!("{:#?}", const { Type::of::<&Unsized>() }.kind); println!("{:#?}", const { Type::of::<&str>() }.kind); println!("{:#?}", const { Type::of::<&[u8]>() }.kind); + println!("{:#?}", const { Type::of::() }.kind); + println!("{:#?}", const { Type::of::<[u8]>() }.kind); } diff --git a/tests/ui/reflection/dump.run.stdout b/tests/ui/reflection/dump.run.stdout index 71fd80b46658..e9db772e8eba 100644 --- a/tests/ui/reflection/dump.run.stdout +++ b/tests/ui/reflection/dump.run.stdout @@ -21,3 +21,5 @@ Other Other Other Other +Other +Other From 815407acb45eb42366995bf31b6ecfa9960af28f Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Mon, 12 Jan 2026 15:41:02 +0100 Subject: [PATCH 0616/1061] clean-up early-return earlier, and create suggestion-related things later --- clippy_lints/src/strlen_on_c_strings.rs | 32 ++++++++++++------------- tests/ui/strlen_on_c_strings.fixed | 3 +-- tests/ui/strlen_on_c_strings.rs | 3 +-- tests/ui/strlen_on_c_strings.stderr | 28 +++++++++++----------- 4 files changed, 32 insertions(+), 34 deletions(-) diff --git a/clippy_lints/src/strlen_on_c_strings.rs b/clippy_lints/src/strlen_on_c_strings.rs index 0d50bd547652..2b3e0ce611ff 100644 --- a/clippy_lints/src/strlen_on_c_strings.rs +++ b/clippy_lints/src/strlen_on_c_strings.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeDef; use clippy_utils::source::snippet_with_context; use clippy_utils::visitors::is_expr_unsafe; @@ -48,6 +48,15 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings { && !recv.span.from_expansion() && path.ident.name == sym::as_ptr { + let ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); + let method_name = if ty.is_diag_item(cx, sym::cstring_type) { + "as_bytes" + } else if ty.is_lang_item(cx, LangItem::CStr) { + "to_bytes" + } else { + return; + }; + let ctxt = expr.span.ctxt(); let span = match cx.tcx.parent_hir_node(expr.hir_id) { Node::Block(&Block { @@ -58,25 +67,16 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings { _ => expr.span, }; - let ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); - let mut app = Applicability::MachineApplicable; - let val_name = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0; - let method_name = if ty.is_diag_item(cx, sym::cstring_type) { - "as_bytes" - } else if ty.is_lang_item(cx, LangItem::CStr) { - "to_bytes" - } else { - return; - }; - - span_lint_and_sugg( + span_lint_and_then( cx, STRLEN_ON_C_STRINGS, span, "using `libc::strlen` on a `CString` or `CStr` value", - "try", - format!("{val_name}.{method_name}().len()"), - app, + |diag| { + let mut app = Applicability::MachineApplicable; + let val_name = snippet_with_context(cx, self_arg.span, ctxt, "_", &mut app).0; + diag.span_suggestion(span, "use", format!("{val_name}.{method_name}().len()"), app); + }, ); } } diff --git a/tests/ui/strlen_on_c_strings.fixed b/tests/ui/strlen_on_c_strings.fixed index 17c1b541f77c..f52c571c1088 100644 --- a/tests/ui/strlen_on_c_strings.fixed +++ b/tests/ui/strlen_on_c_strings.fixed @@ -1,7 +1,6 @@ #![warn(clippy::strlen_on_c_strings)] -#![allow(dead_code, clippy::manual_c_str_literals)] +#![allow(clippy::manual_c_str_literals)] -#[allow(unused)] use libc::strlen; use std::ffi::{CStr, CString}; diff --git a/tests/ui/strlen_on_c_strings.rs b/tests/ui/strlen_on_c_strings.rs index c641422f5df4..39366d08c1a2 100644 --- a/tests/ui/strlen_on_c_strings.rs +++ b/tests/ui/strlen_on_c_strings.rs @@ -1,7 +1,6 @@ #![warn(clippy::strlen_on_c_strings)] -#![allow(dead_code, clippy::manual_c_str_literals)] +#![allow(clippy::manual_c_str_literals)] -#[allow(unused)] use libc::strlen; use std::ffi::{CStr, CString}; diff --git a/tests/ui/strlen_on_c_strings.stderr b/tests/ui/strlen_on_c_strings.stderr index 84a93b99ee33..eecce8d97865 100644 --- a/tests/ui/strlen_on_c_strings.stderr +++ b/tests/ui/strlen_on_c_strings.stderr @@ -1,47 +1,47 @@ error: using `libc::strlen` on a `CString` or `CStr` value - --> tests/ui/strlen_on_c_strings.rs:11:13 + --> tests/ui/strlen_on_c_strings.rs:10:13 | LL | let _ = unsafe { libc::strlen(cstring.as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cstring.as_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `cstring.as_bytes().len()` | = note: `-D clippy::strlen-on-c-strings` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::strlen_on_c_strings)]` error: using `libc::strlen` on a `CString` or `CStr` value - --> tests/ui/strlen_on_c_strings.rs:16:13 + --> tests/ui/strlen_on_c_strings.rs:15:13 | LL | let _ = unsafe { libc::strlen(cstr.as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cstr.to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `cstr.to_bytes().len()` error: using `libc::strlen` on a `CString` or `CStr` value - --> tests/ui/strlen_on_c_strings.rs:19:13 + --> tests/ui/strlen_on_c_strings.rs:18:13 | LL | let _ = unsafe { strlen(cstr.as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cstr.to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `cstr.to_bytes().len()` error: using `libc::strlen` on a `CString` or `CStr` value - --> tests/ui/strlen_on_c_strings.rs:23:22 + --> tests/ui/strlen_on_c_strings.rs:22:22 | LL | let _ = unsafe { strlen((*pcstr).as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*pcstr).to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `(*pcstr).to_bytes().len()` error: using `libc::strlen` on a `CString` or `CStr` value - --> tests/ui/strlen_on_c_strings.rs:29:22 + --> tests/ui/strlen_on_c_strings.rs:28:22 | LL | let _ = unsafe { strlen(unsafe_identity(cstr).as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unsafe_identity(cstr).to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `unsafe_identity(cstr).to_bytes().len()` error: using `libc::strlen` on a `CString` or `CStr` value - --> tests/ui/strlen_on_c_strings.rs:31:13 + --> tests/ui/strlen_on_c_strings.rs:30:13 | LL | let _ = unsafe { strlen(unsafe { unsafe_identity(cstr) }.as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unsafe { unsafe_identity(cstr) }.to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `unsafe { unsafe_identity(cstr) }.to_bytes().len()` error: using `libc::strlen` on a `CString` or `CStr` value - --> tests/ui/strlen_on_c_strings.rs:35:22 + --> tests/ui/strlen_on_c_strings.rs:34:22 | LL | let _ = unsafe { strlen(f(cstr).as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `f(cstr).to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `f(cstr).to_bytes().len()` error: aborting due to 7 previous errors From 7cdfee9de8d7d9c627c4b5be3c5a6e4a7c192d13 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Mon, 12 Jan 2026 15:44:20 +0100 Subject: [PATCH 0617/1061] feat: specify the type --- clippy_lints/src/strlen_on_c_strings.rs | 8 ++++---- tests/ui/strlen_on_c_strings.fixed | 14 +++++++------- tests/ui/strlen_on_c_strings.rs | 14 +++++++------- tests/ui/strlen_on_c_strings.stderr | 14 +++++++------- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/clippy_lints/src/strlen_on_c_strings.rs b/clippy_lints/src/strlen_on_c_strings.rs index 2b3e0ce611ff..ec0fc08ea552 100644 --- a/clippy_lints/src/strlen_on_c_strings.rs +++ b/clippy_lints/src/strlen_on_c_strings.rs @@ -49,10 +49,10 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings { && path.ident.name == sym::as_ptr { let ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); - let method_name = if ty.is_diag_item(cx, sym::cstring_type) { - "as_bytes" + let (ty_name, method_name) = if ty.is_diag_item(cx, sym::cstring_type) { + ("CString", "as_bytes") } else if ty.is_lang_item(cx, LangItem::CStr) { - "to_bytes" + ("CStr", "to_bytes") } else { return; }; @@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings { cx, STRLEN_ON_C_STRINGS, span, - "using `libc::strlen` on a `CString` or `CStr` value", + format!("using `libc::strlen` on a `{ty_name}` value"), |diag| { let mut app = Applicability::MachineApplicable; let val_name = snippet_with_context(cx, self_arg.span, ctxt, "_", &mut app).0; diff --git a/tests/ui/strlen_on_c_strings.fixed b/tests/ui/strlen_on_c_strings.fixed index f52c571c1088..68cf1ba2edc5 100644 --- a/tests/ui/strlen_on_c_strings.fixed +++ b/tests/ui/strlen_on_c_strings.fixed @@ -8,29 +8,29 @@ fn main() { // CString let cstring = CString::new("foo").expect("CString::new failed"); let _ = cstring.as_bytes().len(); - //~^ strlen_on_c_strings + //~^ ERROR: using `libc::strlen` on a `CString` value // CStr let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); let _ = cstr.to_bytes().len(); - //~^ strlen_on_c_strings + //~^ ERROR: using `libc::strlen` on a `CStr` value let _ = cstr.to_bytes().len(); - //~^ strlen_on_c_strings + //~^ ERROR: using `libc::strlen` on a `CStr` value let pcstr: *const &CStr = &cstr; let _ = unsafe { (*pcstr).to_bytes().len() }; - //~^ strlen_on_c_strings + //~^ ERROR: using `libc::strlen` on a `CStr` value unsafe fn unsafe_identity(x: T) -> T { x } let _ = unsafe { unsafe_identity(cstr).to_bytes().len() }; - //~^ strlen_on_c_strings + //~^ ERROR: using `libc::strlen` on a `CStr` value let _ = unsafe { unsafe_identity(cstr) }.to_bytes().len(); - //~^ strlen_on_c_strings + //~^ ERROR: using `libc::strlen` on a `CStr` value let f: unsafe fn(_) -> _ = unsafe_identity; let _ = unsafe { f(cstr).to_bytes().len() }; - //~^ strlen_on_c_strings + //~^ ERROR: using `libc::strlen` on a `CStr` value } diff --git a/tests/ui/strlen_on_c_strings.rs b/tests/ui/strlen_on_c_strings.rs index 39366d08c1a2..6d6eb0b5c152 100644 --- a/tests/ui/strlen_on_c_strings.rs +++ b/tests/ui/strlen_on_c_strings.rs @@ -8,29 +8,29 @@ fn main() { // CString let cstring = CString::new("foo").expect("CString::new failed"); let _ = unsafe { libc::strlen(cstring.as_ptr()) }; - //~^ strlen_on_c_strings + //~^ ERROR: using `libc::strlen` on a `CString` value // CStr let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); let _ = unsafe { libc::strlen(cstr.as_ptr()) }; - //~^ strlen_on_c_strings + //~^ ERROR: using `libc::strlen` on a `CStr` value let _ = unsafe { strlen(cstr.as_ptr()) }; - //~^ strlen_on_c_strings + //~^ ERROR: using `libc::strlen` on a `CStr` value let pcstr: *const &CStr = &cstr; let _ = unsafe { strlen((*pcstr).as_ptr()) }; - //~^ strlen_on_c_strings + //~^ ERROR: using `libc::strlen` on a `CStr` value unsafe fn unsafe_identity(x: T) -> T { x } let _ = unsafe { strlen(unsafe_identity(cstr).as_ptr()) }; - //~^ strlen_on_c_strings + //~^ ERROR: using `libc::strlen` on a `CStr` value let _ = unsafe { strlen(unsafe { unsafe_identity(cstr) }.as_ptr()) }; - //~^ strlen_on_c_strings + //~^ ERROR: using `libc::strlen` on a `CStr` value let f: unsafe fn(_) -> _ = unsafe_identity; let _ = unsafe { strlen(f(cstr).as_ptr()) }; - //~^ strlen_on_c_strings + //~^ ERROR: using `libc::strlen` on a `CStr` value } diff --git a/tests/ui/strlen_on_c_strings.stderr b/tests/ui/strlen_on_c_strings.stderr index eecce8d97865..f2ccc91aabf1 100644 --- a/tests/ui/strlen_on_c_strings.stderr +++ b/tests/ui/strlen_on_c_strings.stderr @@ -1,4 +1,4 @@ -error: using `libc::strlen` on a `CString` or `CStr` value +error: using `libc::strlen` on a `CString` value --> tests/ui/strlen_on_c_strings.rs:10:13 | LL | let _ = unsafe { libc::strlen(cstring.as_ptr()) }; @@ -7,37 +7,37 @@ LL | let _ = unsafe { libc::strlen(cstring.as_ptr()) }; = note: `-D clippy::strlen-on-c-strings` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::strlen_on_c_strings)]` -error: using `libc::strlen` on a `CString` or `CStr` value +error: using `libc::strlen` on a `CStr` value --> tests/ui/strlen_on_c_strings.rs:15:13 | LL | let _ = unsafe { libc::strlen(cstr.as_ptr()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `cstr.to_bytes().len()` -error: using `libc::strlen` on a `CString` or `CStr` value +error: using `libc::strlen` on a `CStr` value --> tests/ui/strlen_on_c_strings.rs:18:13 | LL | let _ = unsafe { strlen(cstr.as_ptr()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `cstr.to_bytes().len()` -error: using `libc::strlen` on a `CString` or `CStr` value +error: using `libc::strlen` on a `CStr` value --> tests/ui/strlen_on_c_strings.rs:22:22 | LL | let _ = unsafe { strlen((*pcstr).as_ptr()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `(*pcstr).to_bytes().len()` -error: using `libc::strlen` on a `CString` or `CStr` value +error: using `libc::strlen` on a `CStr` value --> tests/ui/strlen_on_c_strings.rs:28:22 | LL | let _ = unsafe { strlen(unsafe_identity(cstr).as_ptr()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `unsafe_identity(cstr).to_bytes().len()` -error: using `libc::strlen` on a `CString` or `CStr` value +error: using `libc::strlen` on a `CStr` value --> tests/ui/strlen_on_c_strings.rs:30:13 | LL | let _ = unsafe { strlen(unsafe { unsafe_identity(cstr) }.as_ptr()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `unsafe { unsafe_identity(cstr) }.to_bytes().len()` -error: using `libc::strlen` on a `CString` or `CStr` value +error: using `libc::strlen` on a `CStr` value --> tests/ui/strlen_on_c_strings.rs:34:22 | LL | let _ = unsafe { strlen(f(cstr).as_ptr()) }; From 49c86140fb2326ea58655c0fc3e46d52bcacce89 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Mon, 12 Jan 2026 17:54:50 +0100 Subject: [PATCH 0618/1061] feat: also lint types that dereference to `CStr` For simplicity's sake, this also changes the lint to always suggest `to_bytes`, as it is somewhat hard to find out whether a type could dereference to `CString` (which is what `as_bytes` would require) --- clippy_lints/src/strlen_on_c_strings.rs | 19 ++++++++++++------- tests/ui/strlen_on_c_strings.fixed | 14 ++++++++++++-- tests/ui/strlen_on_c_strings.rs | 12 +++++++++++- tests/ui/strlen_on_c_strings.stderr | 22 ++++++++++++++++++++-- 4 files changed, 55 insertions(+), 12 deletions(-) diff --git a/clippy_lints/src/strlen_on_c_strings.rs b/clippy_lints/src/strlen_on_c_strings.rs index ec0fc08ea552..5eb160720c52 100644 --- a/clippy_lints/src/strlen_on_c_strings.rs +++ b/clippy_lints/src/strlen_on_c_strings.rs @@ -47,14 +47,19 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings { && let ExprKind::MethodCall(path, self_arg, [], _) = recv.kind && !recv.span.from_expansion() && path.ident.name == sym::as_ptr + && let typeck = cx.typeck_results() + && typeck + .expr_ty_adjusted(self_arg) + .peel_refs() + .is_lang_item(cx, LangItem::CStr) { - let ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); - let (ty_name, method_name) = if ty.is_diag_item(cx, sym::cstring_type) { - ("CString", "as_bytes") + let ty = typeck.expr_ty(self_arg).peel_refs(); + let ty_kind = if ty.is_diag_item(cx, sym::cstring_type) { + "`CString` value" } else if ty.is_lang_item(cx, LangItem::CStr) { - ("CStr", "to_bytes") + "`CStr` value" } else { - return; + "type that dereferences to `CStr`" }; let ctxt = expr.span.ctxt(); @@ -71,11 +76,11 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings { cx, STRLEN_ON_C_STRINGS, span, - format!("using `libc::strlen` on a `{ty_name}` value"), + format!("using `libc::strlen` on a {ty_kind}"), |diag| { let mut app = Applicability::MachineApplicable; let val_name = snippet_with_context(cx, self_arg.span, ctxt, "_", &mut app).0; - diag.span_suggestion(span, "use", format!("{val_name}.{method_name}().len()"), app); + diag.span_suggestion(span, "use", format!("{val_name}.to_bytes().len()"), app); }, ); } diff --git a/tests/ui/strlen_on_c_strings.fixed b/tests/ui/strlen_on_c_strings.fixed index 68cf1ba2edc5..33a328af6df4 100644 --- a/tests/ui/strlen_on_c_strings.fixed +++ b/tests/ui/strlen_on_c_strings.fixed @@ -1,5 +1,5 @@ #![warn(clippy::strlen_on_c_strings)] -#![allow(clippy::manual_c_str_literals)] +#![allow(clippy::manual_c_str_literals, clippy::boxed_local)] use libc::strlen; use std::ffi::{CStr, CString}; @@ -7,7 +7,7 @@ use std::ffi::{CStr, CString}; fn main() { // CString let cstring = CString::new("foo").expect("CString::new failed"); - let _ = cstring.as_bytes().len(); + let _ = cstring.to_bytes().len(); //~^ ERROR: using `libc::strlen` on a `CString` value // CStr @@ -34,3 +34,13 @@ fn main() { let _ = unsafe { f(cstr).to_bytes().len() }; //~^ ERROR: using `libc::strlen` on a `CStr` value } + +// make sure we lint types that _adjust_ to `CStr` +fn adjusted(box_cstring: Box, box_cstr: Box, arc_cstring: std::sync::Arc) { + let _ = box_cstring.to_bytes().len(); + //~^ ERROR: using `libc::strlen` on a type that dereferences to `CStr` + let _ = box_cstr.to_bytes().len(); + //~^ ERROR: using `libc::strlen` on a type that dereferences to `CStr` + let _ = arc_cstring.to_bytes().len(); + //~^ ERROR: using `libc::strlen` on a type that dereferences to `CStr` +} diff --git a/tests/ui/strlen_on_c_strings.rs b/tests/ui/strlen_on_c_strings.rs index 6d6eb0b5c152..3c11c3a05269 100644 --- a/tests/ui/strlen_on_c_strings.rs +++ b/tests/ui/strlen_on_c_strings.rs @@ -1,5 +1,5 @@ #![warn(clippy::strlen_on_c_strings)] -#![allow(clippy::manual_c_str_literals)] +#![allow(clippy::manual_c_str_literals, clippy::boxed_local)] use libc::strlen; use std::ffi::{CStr, CString}; @@ -34,3 +34,13 @@ fn main() { let _ = unsafe { strlen(f(cstr).as_ptr()) }; //~^ ERROR: using `libc::strlen` on a `CStr` value } + +// make sure we lint types that _adjust_ to `CStr` +fn adjusted(box_cstring: Box, box_cstr: Box, arc_cstring: std::sync::Arc) { + let _ = unsafe { libc::strlen(box_cstring.as_ptr()) }; + //~^ ERROR: using `libc::strlen` on a type that dereferences to `CStr` + let _ = unsafe { libc::strlen(box_cstr.as_ptr()) }; + //~^ ERROR: using `libc::strlen` on a type that dereferences to `CStr` + let _ = unsafe { libc::strlen(arc_cstring.as_ptr()) }; + //~^ ERROR: using `libc::strlen` on a type that dereferences to `CStr` +} diff --git a/tests/ui/strlen_on_c_strings.stderr b/tests/ui/strlen_on_c_strings.stderr index f2ccc91aabf1..2b059872a2da 100644 --- a/tests/ui/strlen_on_c_strings.stderr +++ b/tests/ui/strlen_on_c_strings.stderr @@ -2,7 +2,7 @@ error: using `libc::strlen` on a `CString` value --> tests/ui/strlen_on_c_strings.rs:10:13 | LL | let _ = unsafe { libc::strlen(cstring.as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `cstring.as_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `cstring.to_bytes().len()` | = note: `-D clippy::strlen-on-c-strings` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::strlen_on_c_strings)]` @@ -43,5 +43,23 @@ error: using `libc::strlen` on a `CStr` value LL | let _ = unsafe { strlen(f(cstr).as_ptr()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `f(cstr).to_bytes().len()` -error: aborting due to 7 previous errors +error: using `libc::strlen` on a type that dereferences to `CStr` + --> tests/ui/strlen_on_c_strings.rs:40:13 + | +LL | let _ = unsafe { libc::strlen(box_cstring.as_ptr()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `box_cstring.to_bytes().len()` + +error: using `libc::strlen` on a type that dereferences to `CStr` + --> tests/ui/strlen_on_c_strings.rs:42:13 + | +LL | let _ = unsafe { libc::strlen(box_cstr.as_ptr()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `box_cstr.to_bytes().len()` + +error: using `libc::strlen` on a type that dereferences to `CStr` + --> tests/ui/strlen_on_c_strings.rs:44:13 + | +LL | let _ = unsafe { libc::strlen(arc_cstring.as_ptr()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `arc_cstring.to_bytes().len()` + +error: aborting due to 10 previous errors From e0d9c079ee616f7f6ef6a0b81d9e12962689bfb5 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 22:06:43 +0200 Subject: [PATCH 0619/1061] add missing pause --- src/doc/rustc-dev-guide/src/tests/directives.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 0852f300b9be..ae341599f15a 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -28,8 +28,8 @@ compile-flags: -C overflow-checks=off`). Directives are written one directive per line: you cannot write multiple directives on the same line. -For example, if you write `//@ only-x86 -only-windows` then `only-windows` is interpreted as a comment, not a separate directive. +For example, if you write `//@ only-x86 only-windows`, +then `only-windows` is interpreted as a comment, not a separate directive. ## Listing of compiletest directives From 31c019139531de6cab03cdf3476c71145b635848 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 22:10:04 +0200 Subject: [PATCH 0620/1061] sembr src/building/new-target.md --- .../src/building/new-target.md | 51 +++++++++---------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/building/new-target.md b/src/doc/rustc-dev-guide/src/building/new-target.md index 8465a1388870..d0ed787f520a 100644 --- a/src/doc/rustc-dev-guide/src/building/new-target.md +++ b/src/doc/rustc-dev-guide/src/building/new-target.md @@ -1,7 +1,7 @@ # Adding a new target -These are a set of steps to add support for a new target. There are -numerous end states and paths to get there, so not all sections may be +These are a set of steps to add support for a new target. +There are numerous end states and paths to get there, so not all sections may be relevant to your desired goal. See also the associated documentation in the [target tier policy]. @@ -11,8 +11,8 @@ See also the associated documentation in the [target tier policy]. ## Specifying a new LLVM For very new targets, you may need to use a different fork of LLVM -than what is currently shipped with Rust. In that case, navigate to -the `src/llvm-project` git submodule (you might need to run `./x +than what is currently shipped with Rust. +In that case, navigate to the `src/llvm-project` git submodule (you might need to run `./x check` at least once so the submodule is updated), check out the appropriate commit for your fork, then commit that new submodule reference in the main Rust repository. @@ -31,11 +31,9 @@ git commit -m 'Use my custom LLVM' ### Using pre-built LLVM If you have a local LLVM checkout that is already built, you may be -able to configure Rust to treat your build as the system LLVM to avoid -redundant builds. +able to configure Rust to treat your build as the system LLVM to avoid redundant builds. -You can tell Rust to use a pre-built version of LLVM using the `target` section -of `bootstrap.toml`: +You can tell Rust to use a pre-built version of LLVM using the `target` section of `bootstrap.toml`: ```toml [target.x86_64-unknown-linux-gnu] @@ -48,8 +46,8 @@ before, though they may be different from your system: - `/usr/bin/llvm-config-8` - `/usr/lib/llvm-8/bin/llvm-config` -Note that you need to have the LLVM `FileCheck` tool installed, which is used -for codegen tests. This tool is normally built with LLVM, but if you use your +Note that you need to have the LLVM `FileCheck` tool installed, which is used for codegen tests. +This tool is normally built with LLVM, but if you use your own preinstalled LLVM, you will need to provide `FileCheck` in some other way. On Debian-based systems, you can install the `llvm-N-tools` package (where `N` is the LLVM version number, e.g. `llvm-8-tools`). Alternately, you can specify @@ -58,8 +56,8 @@ or you can disable codegen test with the `codegen-tests` item in `bootstrap.toml ## Creating a target specification -You should start with a target JSON file. You can see the specification -for an existing target using `--print target-spec-json`: +You should start with a target JSON file. +You can see the specification for an existing target using `--print target-spec-json`: ``` rustc -Z unstable-options --target=wasm32-unknown-unknown --print target-spec-json @@ -70,20 +68,20 @@ Save that JSON to a file and modify it as appropriate for your target. ### Adding a target specification Once you have filled out a JSON specification and been able to compile -somewhat successfully, you can copy the specification into the -compiler itself. +somewhat successfully, you can copy the specification into the compiler itself. You will need to add a line to the big table inside of the -`supported_targets` macro in the `rustc_target::spec` module. You -will then add a corresponding file for your new target containing a +`supported_targets` macro in the `rustc_target::spec` module. +You will then add a corresponding file for your new target containing a `target` function. Look for existing targets to use as examples. To use this target in bootstrap, we need to explicitly add the target triple to -the `STAGE0_MISSING_TARGETS` list in `src/bootstrap/src/core/sanity.rs`. This -is necessary because the default bootstrap compiler (typically a beta compiler) -does not recognize the new target we just added. Therefore, it should be added to +the `STAGE0_MISSING_TARGETS` list in `src/bootstrap/src/core/sanity.rs`. +This is necessary because the default bootstrap compiler (typically a beta compiler) +does not recognize the new target we just added. +Therefore, it should be added to `STAGE0_MISSING_TARGETS` so that the bootstrap is aware that this target is not yet supported by the stage0 compiler. @@ -96,9 +94,9 @@ const STAGE0_MISSING_TARGETS: &[&str] = &[ ## Patching crates You may need to make changes to crates that the compiler depends on, -such as [`libc`][] or [`cc`][]. If so, you can use Cargo's -[`[patch]`][patch] ability. For example, if you want to use an -unreleased version of `libc`, you can add it to the top-level +such as [`libc`][] or [`cc`][]. +If so, you can use Cargo's [`[patch]`][patch] ability. +For example, if you want to use an unreleased version of `libc`, you can add it to the top-level `Cargo.toml` file: ```diff @@ -118,9 +116,9 @@ index 1e83f05e0ca..4d0172071c1 100644 After this, run `cargo update -p libc` to update the lockfiles. Beware that if you patch to a local `path` dependency, this will enable -warnings for that dependency. Some dependencies are not warning-free, and due -to the `deny-warnings` setting in `bootstrap.toml`, the build may suddenly start -to fail. +warnings for that dependency. +Some dependencies are not warning-free, and due +to the `deny-warnings` setting in `bootstrap.toml`, the build may suddenly start to fail. To work around warnings, you may want to: - Modify the dependency to remove the warnings - Or for local development purposes, suppress the warnings by setting deny-warnings = false in bootstrap.toml. @@ -137,8 +135,7 @@ deny-warnings = false ## Cross-compiling -Once you have a target specification in JSON and in the code, you can -cross-compile `rustc`: +Once you have a target specification in JSON and in the code, you can cross-compile `rustc`: ``` DESTDIR=/path/to/install/in \ From d442a793b23e2d55f6285abaf08ca2f93bd850df Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 22:13:40 +0200 Subject: [PATCH 0621/1061] sembr src/rustdoc-internals/rustdoc-html-test-suite.md --- .../rustdoc-internals/rustdoc-html-test-suite.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-html-test-suite.md b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-html-test-suite.md index b74405d310eb..a88e60c183b0 100644 --- a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-html-test-suite.md +++ b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-html-test-suite.md @@ -34,8 +34,8 @@ pub type Alias = Option; Here, we check that documentation generated for crate `file` contains a page for the public type alias `Alias` where the code block that is found at the top contains the -expected rendering of the item. The `//*[@class="rust item-decl"]//code` is an XPath -expression. +expected rendering of the item. +The `//*[@class="rust item-decl"]//code` is an XPath expression. Conventionally, you place these directives directly above the thing they are meant to test. Technically speaking however, they don't need to be as HtmlDocCk only looks for the directives. @@ -120,8 +120,8 @@ pre-recorded subtree or text (the "snapshot") in file `FILE_STEM.NAME.html` wher is the file stem of the test file. Pass the `--bless` option to `compiletest` to accept the current subtree/text as expected. -This will overwrite the aforementioned file (or create it if it doesn't exist). It will -automatically normalize the channel-dependent URL `https://doc.rust-lang.org/CHANNEL` to +This will overwrite the aforementioned file (or create it if it doesn't exist). +It will automatically normalize the channel-dependent URL `https://doc.rust-lang.org/CHANNEL` to the special string `{{channel}}`. ### `has-dir` @@ -152,7 +152,8 @@ It's *strongly recommended* to read that chapter if you don't know anything abou Here are some details that are relevant to this test suite specifically: * While you can use both `//@ compile-flags` and `//@ doc-flags` to pass flags to `rustdoc`, - prefer to user the latter to show intent. The former is meant for `rustc`. + prefer to user the latter to show intent. + The former is meant for `rustc`. * Add `//@ build-aux-docs` to the test file that has auxiliary crates to not only compile the auxiliaries with `rustc` but to also document them with `rustdoc`. @@ -169,7 +170,8 @@ thus continue to test the correct thing or they won't in which case they would f forcing the author of the change to look at them. Compare that to *negative* checks (e.g., `//@ !has PATH XPATH PATTERN`) which won't fail if their -XPath expression "no longer" matches. The author who changed "the shape" thus won't get notified and +XPath expression "no longer" matches. +The author who changed "the shape" thus won't get notified and as a result someone else can unintentionally reintroduce `PATTERN` into the generated docs without the original negative check failing. From 328942672da88fecfdc04b488307d39ac2b5baf4 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 22:15:18 +0200 Subject: [PATCH 0622/1061] sembr src/profiling/with_rustc_perf.md --- .../src/profiling/with_rustc_perf.md | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md b/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md index 7c7639a1ac3d..de4cb9eae930 100644 --- a/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md +++ b/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md @@ -1,9 +1,11 @@ # Profiling with rustc-perf The [Rust benchmark suite][rustc-perf] provides a comprehensive way of profiling and benchmarking -the Rust compiler. You can find instructions on how to use the suite in its [manual][rustc-perf-readme]. +the Rust compiler. +You can find instructions on how to use the suite in its [manual][rustc-perf-readme]. -However, using the suite manually can be a bit cumbersome. To make this easier for `rustc` contributors, +However, using the suite manually can be a bit cumbersome. +To make this easier for `rustc` contributors, the compiler build system (`bootstrap`) also provides built-in integration with the benchmarking suite, which will download and build the suite for you, build a local compiler toolchain and let you profile it using a simplified command-line interface. @@ -14,8 +16,9 @@ You can use normal bootstrap flags for this command, such as `--stage 1` or `--s `x perf` currently supports the following commands: - `benchmark `: Benchmark the compiler and store the results under the passed `id`. - `compare `: Compare the benchmark results of two compilers with the two passed `id`s. -- `eprintln`: Just run the compiler and capture its `stderr` output. Note that the compiler normally does not print - anything to `stderr`, you might want to add some `eprintln!` calls to get any output. +- `eprintln`: Just run the compiler and capture its `stderr` output. + Note that the compiler normally does not print + anything to `stderr`, you might want to add some `eprintln!` calls to get any output. - `samply`: Profile the compiler using the [samply][samply] sampling profiler. - `cachegrind`: Use [Cachegrind][cachegrind] to generate a detailed simulated trace of the compiler's execution. @@ -29,15 +32,18 @@ You can use the following options for the `x perf` command, which mirror the cor - `--scenarios`: Select scenarios (`Full`, `IncrFull`, `IncrPatched`, `IncrUnchanged`) which should be profiled/benchmarked. ## Example profiling diff for external crates -It can be of interest to generate a local diff for two commits of the compiler for external crates. +It can be of interest to generate a local diff for two commits of the compiler for external crates. To start, in the `rustc-perf` repo, build the collector, which runs the Rust compiler benchmarks as follows. ``` cargo build --release -p collector ``` -The collector can then be run using cargo, specifying the collector binary. It expects the following arguments: -- ``: Profiler selection for how performance should be measured. For this example we will use Cachegrind. +The collector can then be run using cargo, specifying the collector binary. +It expects the following arguments: +- ``: Profiler selection for how performance should be measured. + For this example we will use Cachegrind. - ``: The Rust compiler revision to benchmark, specified as a commit SHA from `rust-lang/rust`. -Optional arguments allow running profiles and scenarios as described above. More information regarding the mandatory and +Optional arguments allow running profiles and scenarios as described above. +More information regarding the mandatory and optional arguments can be found in the [rustc-perf-readme-profilers]. Then, for the case of generating a profile diff for the crate `serve_derive-1.0.136`, for two commits `` and `` from the `rust-lang/rust` repository, From c451d97ce1401384a7106892e8b4dfdd2768b82a Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 22:18:18 +0200 Subject: [PATCH 0623/1061] a more natural continuation --- src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md b/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md index de4cb9eae930..55fc0556463c 100644 --- a/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md +++ b/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md @@ -18,7 +18,7 @@ You can use normal bootstrap flags for this command, such as `--stage 1` or `--s - `compare `: Compare the benchmark results of two compilers with the two passed `id`s. - `eprintln`: Just run the compiler and capture its `stderr` output. Note that the compiler normally does not print - anything to `stderr`, you might want to add some `eprintln!` calls to get any output. + anything to `stderr`, so you might want to add some `eprintln!` calls to get any output. - `samply`: Profile the compiler using the [samply][samply] sampling profiler. - `cachegrind`: Use [Cachegrind][cachegrind] to generate a detailed simulated trace of the compiler's execution. From 2d9616a5d78bc26df42f29c74635edef57fdf743 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 22:18:33 +0200 Subject: [PATCH 0624/1061] add missing pause --- src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md b/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md index 55fc0556463c..2158b655b3e2 100644 --- a/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md +++ b/src/doc/rustc-dev-guide/src/profiling/with_rustc_perf.md @@ -40,13 +40,13 @@ cargo build --release -p collector The collector can then be run using cargo, specifying the collector binary. It expects the following arguments: - ``: Profiler selection for how performance should be measured. - For this example we will use Cachegrind. + For this example, we will use Cachegrind. - ``: The Rust compiler revision to benchmark, specified as a commit SHA from `rust-lang/rust`. Optional arguments allow running profiles and scenarios as described above. More information regarding the mandatory and optional arguments can be found in the [rustc-perf-readme-profilers]. -Then, for the case of generating a profile diff for the crate `serve_derive-1.0.136`, for two commits `` and `` from the `rust-lang/rust` repository, +Then, for the case of generating a profile diff for the crate `serve_derive-1.0.136`, for two commits `` and `` from the `rust-lang/rust` repository, run the following in the `rustc-perf` repo: ``` cargo run --release --bin collector profile_local cachegrind + --rustc2 + --exact-match serde_derive-1.0.136 --profiles Check --scenarios IncrUnchanged From d89da8044855c064be93f66293bbb97392b5ed65 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 22:19:30 +0200 Subject: [PATCH 0625/1061] sembr src/tests/best-practices.md --- .../src/tests/best-practices.md | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/best-practices.md b/src/doc/rustc-dev-guide/src/tests/best-practices.md index ff4ea11bbc7a..3a029763db8c 100644 --- a/src/doc/rustc-dev-guide/src/tests/best-practices.md +++ b/src/doc/rustc-dev-guide/src/tests/best-practices.md @@ -7,8 +7,8 @@ a bunch of git archeology. It's good practice to review the test that you authored by pretending that you are a different contributor who is looking at the test that failed several years -later without much context (this also helps yourself even a few days or months -later!). Then ask yourself: how can I make my life and their lives easier? +later without much context (this also helps yourself even a few days or months later!). +Then ask yourself: how can I make my life and their lives easier? To help put this into perspective, let's start with an aside on how to write a test that makes the life of another contributor as hard as possible. @@ -35,15 +35,14 @@ test that makes the life of another contributor as hard as possible. Make it easy for the reader to immediately understand what the test is exercising, instead of having to type in the issue number and dig through github -search for what the test is trying to exercise. This has an additional benefit -of making the test possible to be filtered via `--test-args` as a collection of -related tests. +search for what the test is trying to exercise. +This has an additional benefit +of making the test possible to be filtered via `--test-args` as a collection of related tests. - Name the test after what it's trying to exercise or prevent regressions of. - Keep it concise. - Avoid using issue numbers alone as test names. -- Avoid starting the test name with `issue-xxxxx` prefix as it degrades - auto-completion. +- Avoid starting the test name with `issue-xxxxx` prefix as it degrades auto-completion. > **Avoid using only issue numbers as test names** > @@ -78,21 +77,22 @@ related tests. ## Test organization -- For most test suites, try to find a semantically meaningful subdirectory to - home the test. +- For most test suites, try to find a semantically meaningful subdirectory to home the test. - E.g. for an implementation of RFC 2093 specifically, we can group a - collection of tests under `tests/ui/rfc-2093-infer-outlives/`. For the - directory name, include what the RFC is about. + collection of tests under `tests/ui/rfc-2093-infer-outlives/`. + For the directory name, include what the RFC is about. - For the [`run-make`]/`run-make-support` test suites, each `rmake.rs` must be contained within an immediate subdirectory under `tests/run-make/` or - `tests/run-make-cargo/` respectively. Further nesting is not presently - supported. Avoid using _only_ an issue number for the test name as well. + `tests/run-make-cargo/` respectively. + Further nesting is not presently supported. + Avoid using _only_ an issue number for the test name as well. ## Test descriptions To help other contributors understand what the test is about if their changes lead to the test failing, we should make sure a test has sufficient docs about -its intent/purpose, links to relevant context (incl. issue numbers or other +its intent/purpose, links to relevant context (incl. +issue numbers or other discussions) and possibly relevant resources (e.g. can be helpful to link to Win32 APIs for specific behavior). @@ -136,8 +136,8 @@ fn main() { } ``` -For how much context/explanation is needed, it is up to the author and -reviewer's discretion. A good rule of thumb is non-trivial things exercised in +For how much context/explanation is needed, it is up to the author and reviewer's discretion. +A good rule of thumb is non-trivial things exercised in the test deserves some explanation to help other contributors to understand. This may include remarks on: @@ -159,17 +159,17 @@ This may include remarks on: ## Flaky tests -All tests need to strive to be reproducible and reliable. Flaky tests are the -worst kind of tests, arguably even worse than not having the test in the first +All tests need to strive to be reproducible and reliable. +Flaky tests are the worst kind of tests, arguably even worse than not having the test in the first place. - Flaky tests can fail in completely unrelated PRs which can confuse other - contributors and waste their time trying to figure out if test failure is - related. + contributors and waste their time trying to figure out if test failure is related. - Flaky tests provide no useful information from its test results other than - it's flaky and not reliable: if a test passed but it's flakey, did I just get - lucky? if a test is flakey but it failed, was it just spurious? -- Flaky tests degrade confidence in the whole test suite. If a test suite can + it's flaky and not reliable: if a test passed but it's flakey, did I just get lucky? + if a test is flakey but it failed, was it just spurious? +- Flaky tests degrade confidence in the whole test suite. + If a test suite can randomly spuriously fail due to flaky tests, did the whole test suite pass or did I just get lucky/unlucky? - Flaky tests can randomly fail in full CI, wasting previous full CI resources. @@ -189,8 +189,8 @@ See [compiletest directives] for a listing of directives. See [LLVM FileCheck guide][FileCheck] for details. - Avoid matching on specific register numbers or basic block numbers unless - they're special or critical for the test. Consider using patterns to match - them where suitable. + they're special or critical for the test. + Consider using patterns to match them where suitable. > **TODO** > From 579e2b3009501d33a1636e84f2b8b48c68e9cdd0 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 22:26:30 +0200 Subject: [PATCH 0626/1061] some improvements to tests/best-practices.md --- src/doc/rustc-dev-guide/src/tests/best-practices.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/best-practices.md b/src/doc/rustc-dev-guide/src/tests/best-practices.md index 3a029763db8c..b6daffa6683c 100644 --- a/src/doc/rustc-dev-guide/src/tests/best-practices.md +++ b/src/doc/rustc-dev-guide/src/tests/best-practices.md @@ -91,9 +91,8 @@ of making the test possible to be filtered via `--test-args` as a collection of To help other contributors understand what the test is about if their changes lead to the test failing, we should make sure a test has sufficient docs about -its intent/purpose, links to relevant context (incl. -issue numbers or other -discussions) and possibly relevant resources (e.g. can be helpful to link to +its intent/purpose, links to relevant context (including issue numbers or other discussions) +and possibly relevant resources (e.g. it can be helpful to link to Win32 APIs for specific behavior). **Synopsis of a test with good comments** @@ -146,7 +145,7 @@ This may include remarks on: separate because...). - Platform-specific behaviors. - Behavior of external dependencies and APIs: syscalls, linkers, tools, - environments and the likes. + environments and the like. ## Test content @@ -167,7 +166,7 @@ place. contributors and waste their time trying to figure out if test failure is related. - Flaky tests provide no useful information from its test results other than it's flaky and not reliable: if a test passed but it's flakey, did I just get lucky? - if a test is flakey but it failed, was it just spurious? + If a test is flakey but it failed, was it just spurious? - Flaky tests degrade confidence in the whole test suite. If a test suite can randomly spuriously fail due to flaky tests, did the whole test suite pass or From da5aa2825a5413d9120cef7b9d359bfa1110e2a0 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 22:26:55 +0200 Subject: [PATCH 0627/1061] sembr src/tests/perf.md --- src/doc/rustc-dev-guide/src/tests/perf.md | 26 +++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/perf.md b/src/doc/rustc-dev-guide/src/tests/perf.md index 18762556137e..a0aa3c033174 100644 --- a/src/doc/rustc-dev-guide/src/tests/perf.md +++ b/src/doc/rustc-dev-guide/src/tests/perf.md @@ -6,12 +6,13 @@ A lot of work is put into improving the performance of the compiler and preventing performance regressions. The [rustc-perf](https://github.com/rust-lang/rustc-perf) project provides -several services for testing and tracking performance. It provides hosted -infrastructure for running benchmarks as a service. At this time, only -`x86_64-unknown-linux-gnu` builds are tracked. +several services for testing and tracking performance. +It provides hosted infrastructure for running benchmarks as a service. +At this time, only `x86_64-unknown-linux-gnu` builds are tracked. A "perf run" is used to compare the performance of the compiler in different -configurations for a large collection of popular crates. Different +configurations for a large collection of popular crates. +Different configurations include "fresh builds", builds with incremental compilation, etc. The result of a perf run is a comparison between two versions of the compiler @@ -28,8 +29,8 @@ Any changes are noted in a comment on the PR. ### Manual perf runs -Additionally, performance tests can be ran before a PR is merged on an as-needed -basis. You should request a perf run if your PR may affect performance, +Additionally, performance tests can be ran before a PR is merged on an as-needed basis. +You should request a perf run if your PR may affect performance, especially if it can affect performance adversely. To evaluate the performance impact of a PR, write this comment on the PR: @@ -46,10 +47,10 @@ To evaluate the performance impact of a PR, write this comment on the PR: [perf run]: https://rust-lang.zulipchat.com/#narrow/channel/182449-t-compiler.2Fhelp/topic/perf.20run This will first tell bors to do a "try" build which do a full release build for -`x86_64-unknown-linux-gnu`. After the build finishes, it will place it in the -queue to run the performance suite against it. After the performance tests -finish, the bot will post a comment on the PR with a summary and a link to a -full report. +`x86_64-unknown-linux-gnu`. +After the build finishes, it will place it in the queue to run the performance suite against it. +After the performance tests +finish, the bot will post a comment on the PR with a summary and a link to a full report. If you want to do a perf run for an already built artifact (e.g. for a previous try build that wasn't benchmarked yet), you can run this instead: @@ -59,8 +60,7 @@ try build that wasn't benchmarked yet), you can run this instead: You cannot benchmark the same artifact twice though. More information about the available perf bot commands can be found -[here](https://perf.rust-lang.org/help.html). +[here](https://perf.rust-lang.org/help.html). -More details about the benchmarking process itself are available in the [perf -collector +More details about the benchmarking process itself are available in the [perf collector documentation](https://github.com/rust-lang/rustc-perf/blob/master/collector/README.md). From 97a06feab0869c9a57a3a63c840d9e3e6664aea8 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Jan 2026 22:33:08 +0200 Subject: [PATCH 0628/1061] add range-diff triagebot option --- src/doc/rustc-dev-guide/triagebot.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/doc/rustc-dev-guide/triagebot.toml b/src/doc/rustc-dev-guide/triagebot.toml index 974f4cd3dd96..f894456d0de3 100644 --- a/src/doc/rustc-dev-guide/triagebot.toml +++ b/src/doc/rustc-dev-guide/triagebot.toml @@ -86,3 +86,6 @@ rustc-dev-guide = [ "@jyn514", "@tshepang", ] + +# Make rebases more easy to read: https://forge.rust-lang.org/triagebot/range-diff.html +[range-diff] From 2d49cfe6aa0f613dbbd35ea3a0542bfe04957a50 Mon Sep 17 00:00:00 2001 From: Jayan Sunil <73993003+JayanAXHF@users.noreply.github.com> Date: Tue, 13 Jan 2026 03:17:32 +0530 Subject: [PATCH 0629/1061] fix: added missing type in triagebot.toml --- triagebot.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 89118fdb5948..f00b4b9daffc 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1006,7 +1006,7 @@ cc = ["@fmease"] [mentions."library/core/src/mem/type_info.rs"] message = """ The reflection data structures are tied exactly to the implementation -in the compiler. Make sure to also adjust `rustc_const_eval/src/const_eval/type_info.rs +in the compiler. Make sure to also adjust `rustc_const_eval/src/const_eval/type_info.rs` """ cc = ["@oli-obk"] From c98b90eaadc1a4ba4fca60572f3ce75f6f44b216 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Mon, 12 Jan 2026 17:26:23 -0500 Subject: [PATCH 0630/1061] std: Change UEFI env vars to volatile storage The UEFI variables set by the env vars should be volatile, otherwise they will persist after reboot and use up scarce non-volatile storage. --- library/std/src/sys/env/uefi.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/env/uefi.rs b/library/std/src/sys/env/uefi.rs index 5fe29a47a2ea..af16a02642a4 100644 --- a/library/std/src/sys/env/uefi.rs +++ b/library/std/src/sys/env/uefi.rs @@ -95,8 +95,8 @@ mod uefi_env { val_ptr: *mut r_efi::efi::Char16, ) -> io::Result<()> { let shell = helpers::open_shell().ok_or(unsupported_err())?; - let r = - unsafe { ((*shell.as_ptr()).set_env)(key_ptr, val_ptr, r_efi::efi::Boolean::FALSE) }; + let volatile = r_efi::efi::Boolean::TRUE; + let r = unsafe { ((*shell.as_ptr()).set_env)(key_ptr, val_ptr, volatile) }; if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } } } From feb44c3f4806069c76b8a06e4393ecb722dd17a1 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 8 Jan 2026 22:06:45 +0100 Subject: [PATCH 0631/1061] Make `--print=check-cfg` output compatible `--check-cfg` arguments --- compiler/rustc_driver_impl/src/lib.rs | 35 +++++----- .../src/compiler-flags/print-check-cfg.md | 27 ++++---- tests/run-make/print-check-cfg/rmake.rs | 66 ++++++++++--------- 3 files changed, 72 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 7820198f2dcf..a328298d3b15 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -765,30 +765,35 @@ fn print_crate_info( for (name, expected_values) in &sess.psess.check_config.expecteds { use crate::config::ExpectedValues; match expected_values { - ExpectedValues::Any => check_cfgs.push(format!("{name}=any()")), + ExpectedValues::Any => { + check_cfgs.push(format!("cfg({name}, values(any()))")) + } ExpectedValues::Some(values) => { - if !values.is_empty() { - check_cfgs.extend(values.iter().map(|value| { + let mut values: Vec<_> = values + .iter() + .map(|value| { if let Some(value) = value { - format!("{name}=\"{value}\"") + format!("\"{value}\"") } else { - name.to_string() + "none()".to_string() } - })) - } else { - check_cfgs.push(format!("{name}=")) - } + }) + .collect(); + + values.sort_unstable(); + + let values = values.join(", "); + + check_cfgs.push(format!("cfg({name}, values({values}))")) } } } check_cfgs.sort_unstable(); - if !sess.psess.check_config.exhaustive_names { - if !sess.psess.check_config.exhaustive_values { - println_info!("any()=any()"); - } else { - println_info!("any()"); - } + if !sess.psess.check_config.exhaustive_names + && sess.psess.check_config.exhaustive_values + { + println_info!("cfg(any())"); } for check_cfg in check_cfgs { println_info!("{check_cfg}"); diff --git a/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md b/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md index 8d314aa62d4c..1b41a0cd728f 100644 --- a/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md +++ b/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md @@ -9,18 +9,20 @@ This option of the `--print` flag print the list of all the expected cfgs. This is related to the [`--check-cfg` flag][check-cfg] which allows specifying arbitrary expected names and values. -This print option works similarly to `--print=cfg` (modulo check-cfg specifics). +This print option outputs compatible `--check-cfg` arguments with a reduced syntax where all the +expected values are on the same line and `values(...)` is always explicit. -| `--check-cfg` | `--print=check-cfg` | -|-----------------------------------|-----------------------------| -| `cfg(foo)` | `foo` | -| `cfg(foo, values("bar"))` | `foo="bar"` | -| `cfg(foo, values(none(), "bar"))` | `foo` & `foo="bar"` | -| | *check-cfg specific syntax* | -| `cfg(foo, values(any())` | `foo=any()` | -| `cfg(foo, values())` | `foo=` | -| `cfg(any())` | `any()` | -| *none* | `any()=any()` | +| `--check-cfg` | `--print=check-cfg` | +|-----------------------------------|-----------------------------------| +| `cfg(foo)` | `cfg(foo, values(none())) | +| `cfg(foo, values("bar"))` | `cfg(foo, values("bar"))` | +| `cfg(foo, values(none(), "bar"))` | `cfg(foo, values(none(), "bar"))` | +| `cfg(foo, values(any())` | `cfg(foo, values(any())` | +| `cfg(foo, values())` | `cfg(foo, values())` | +| `cfg(any())` | `cfg(any())` | +| *nothing* | *nothing* | + +The print option includes well known cfgs. To be used like this: @@ -28,4 +30,7 @@ To be used like this: rustc --print=check-cfg -Zunstable-options lib.rs ``` +> **Note:** Users should be resilient when parsing, in particular against new predicates that +may be added in the future. + [check-cfg]: https://doc.rust-lang.org/nightly/rustc/check-cfg.html diff --git a/tests/run-make/print-check-cfg/rmake.rs b/tests/run-make/print-check-cfg/rmake.rs index f6f7f7cece6e..e102d2904a80 100644 --- a/tests/run-make/print-check-cfg/rmake.rs +++ b/tests/run-make/print-check-cfg/rmake.rs @@ -14,51 +14,55 @@ struct CheckCfg { enum Contains { Some { contains: &'static [&'static str], doesnt_contain: &'static [&'static str] }, - Only(&'static str), + Nothing, } fn main() { - check(CheckCfg { args: &[], contains: Contains::Only("any()=any()") }); + check(CheckCfg { args: &[], contains: Contains::Nothing }); check(CheckCfg { args: &["--check-cfg=cfg()"], contains: Contains::Some { - contains: &["unix", "miri"], - doesnt_contain: &["any()", "any()=any()"], + contains: &["cfg(unix, values(none()))", "cfg(miri, values(none()))"], + doesnt_contain: &["cfg(any())"], }, }); check(CheckCfg { args: &["--check-cfg=cfg(any())"], contains: Contains::Some { - contains: &["any()", "unix", r#"target_feature="crt-static""#], + contains: &["cfg(any())", "cfg(unix, values(none()))"], doesnt_contain: &["any()=any()"], }, }); check(CheckCfg { args: &["--check-cfg=cfg(feature)"], contains: Contains::Some { - contains: &["unix", "miri", "feature"], - doesnt_contain: &["any()", "any()=any()", "feature=none()", "feature="], + contains: &[ + "cfg(unix, values(none()))", + "cfg(miri, values(none()))", + "cfg(feature, values(none()))", + ], + doesnt_contain: &["cfg(any())", "cfg(feature)"], }, }); check(CheckCfg { args: &[r#"--check-cfg=cfg(feature, values(none(), "", "test", "lol"))"#], contains: Contains::Some { - contains: &["feature", "feature=\"\"", "feature=\"test\"", "feature=\"lol\""], - doesnt_contain: &["any()", "any()=any()", "feature=none()", "feature="], + contains: &[r#"cfg(feature, values("", "lol", "test", none()))"#], + doesnt_contain: &["cfg(any())", "cfg(feature, values(none()))", "cfg(feature)"], }, }); check(CheckCfg { args: &["--check-cfg=cfg(feature, values())"], contains: Contains::Some { - contains: &["feature="], - doesnt_contain: &["any()", "any()=any()", "feature=none()", "feature"], + contains: &["cfg(feature, values())"], + doesnt_contain: &["cfg(any())", "cfg(feature, values(none()))", "cfg(feature)"], }, }); check(CheckCfg { args: &["--check-cfg=cfg(feature, values())", "--check-cfg=cfg(feature, values(none()))"], contains: Contains::Some { - contains: &["feature"], - doesnt_contain: &["any()", "any()=any()", "feature=none()", "feature="], + contains: &["cfg(feature, values(none()))"], + doesnt_contain: &["cfg(any())", "cfg(feature, values())"], }, }); check(CheckCfg { @@ -67,8 +71,8 @@ fn main() { r#"--check-cfg=cfg(feature, values("tmp"))"#, ], contains: Contains::Some { - contains: &["unix", "miri", "feature=any()"], - doesnt_contain: &["any()", "any()=any()", "feature", "feature=", "feature=\"tmp\""], + contains: &["cfg(feature, values(any()))"], + doesnt_contain: &["cfg(any())", r#"cfg(feature, values("tmp"))"#], }, }); check(CheckCfg { @@ -78,8 +82,12 @@ fn main() { r#"--check-cfg=cfg(feature, values("tmp"))"#, ], contains: Contains::Some { - contains: &["has_foo", "has_bar", "feature=\"tmp\""], - doesnt_contain: &["any()", "any()=any()", "feature"], + contains: &[ + "cfg(has_foo, values(none()))", + "cfg(has_bar, values(none()))", + r#"cfg(feature, values("tmp"))"#, + ], + doesnt_contain: &["cfg(any())", "cfg(feature)"], }, }); } @@ -94,16 +102,15 @@ fn check(CheckCfg { args, contains }: CheckCfg) { for l in stdout.lines() { assert!(l == l.trim()); - if let Some((left, right)) = l.split_once('=') { - if right != "any()" && right != "" { - assert!(right.starts_with("\"")); - assert!(right.ends_with("\"")); - } - assert!(!left.contains("\"")); - } else { - assert!(!l.contains("\"")); - } - assert!(found.insert(l.to_string()), "{}", &l); + assert!(l.starts_with("cfg("), "{l}"); + assert!(l.ends_with(")"), "{l}"); + assert_eq!( + l.chars().filter(|c| *c == '(').count(), + l.chars().filter(|c| *c == ')').count(), + "{l}" + ); + assert!(l.chars().filter(|c| *c == '"').count() % 2 == 0, "{l}"); + assert!(found.insert(l.to_string()), "{l}"); } match contains { @@ -131,9 +138,8 @@ fn check(CheckCfg { args, contains }: CheckCfg) { ); } } - Contains::Only(only) => { - assert!(found.contains(&only.to_string()), "{:?} != {:?}", &only, &found); - assert!(found.len() == 1, "len: {}, instead of 1", found.len()); + Contains::Nothing => { + assert!(found.len() == 0, "len: {}, instead of 0", found.len()); } } } From dd2b0a8e9299512a2c8866edf8f67e301aa6d988 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 8 Jan 2026 22:07:24 +0100 Subject: [PATCH 0632/1061] Update compiletest for new `--print=check-cfg` output --- src/tools/compiletest/src/common.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 450fde3bbc38..d2abc9dab148 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -1065,11 +1065,27 @@ fn builtin_cfg_names(config: &Config) -> HashSet { Default::default(), ) .lines() - .map(|l| if let Some((name, _)) = l.split_once('=') { name.to_string() } else { l.to_string() }) + .map(|l| extract_cfg_name(&l).unwrap().to_string()) .chain(std::iter::once(String::from("test"))) .collect() } +/// Extract the cfg name from `cfg(name, values(...))` lines +fn extract_cfg_name(check_cfg_line: &str) -> Result<&str, &'static str> { + let trimmed = check_cfg_line.trim(); + + #[rustfmt::skip] + let inner = trimmed + .strip_prefix("cfg(") + .ok_or("missing cfg(")? + .strip_suffix(")") + .ok_or("missing )")?; + + let first_comma = inner.find(',').ok_or("no comma found")?; + + Ok(inner[..first_comma].trim()) +} + pub const KNOWN_CRATE_TYPES: &[&str] = &["bin", "cdylib", "dylib", "lib", "proc-macro", "rlib", "staticlib"]; From d697b4d7abf5573d63a9e3e5d7f84479eb554e67 Mon Sep 17 00:00:00 2001 From: KaiTomotake Date: Mon, 5 Jan 2026 01:32:34 +0900 Subject: [PATCH 0633/1061] Improve std::path::Path::join documentation Adapt `PathBuf::push` documentation for `Path::join` and add it to `join`'s docs Fix to comply with tidy Remove unnecessary whitespace --- library/std/src/path.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index e8eda3c5f76b..25bd7005b994 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2972,6 +2972,15 @@ impl Path { /// /// If `path` is absolute, it replaces the current path. /// + /// On Windows: + /// + /// * if `path` has a root but no prefix (e.g., `\windows`), it + /// replaces and returns everything except for the prefix (if any) of `self`. + /// * if `path` has a prefix but no root, `self` is ignored and `path` is returned. + /// * if `self` has a verbatim prefix (e.g. `\\?\C:\windows`) + /// and `path` is not empty, the new path is normalized: all references + /// to `.` and `..` are removed. + /// /// See [`PathBuf::push`] for more details on what it means to adjoin a path. /// /// # Examples From afe76df79cd43d510cc7e746e7402edf8f8eed58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heath=20Dutton=F0=9F=95=B4=EF=B8=8F?= Date: Mon, 12 Jan 2026 18:04:32 -0500 Subject: [PATCH 0634/1061] Don't suggest replacing closure parameter with type name When a closure has an inferred parameter type like `|ch|` and the expected type differs in borrowing (e.g., `char` vs `&char`), the suggestion code would incorrectly suggest `|char|` instead of the valid `|ch: char|`. This happened because the code couldn't walk explicit `&` references in the HIR when the type is inferred, and fell back to replacing the entire parameter span with the expected type name. Fix by only emitting the suggestion when we can properly identify the `&` syntax to remove. --- .../src/error_reporting/traits/suggestions.rs | 9 +++------ tests/ui/closures/multiple-fn-bounds.stderr | 5 ----- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 511e9e85b5f6..81b921b3744f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -5323,12 +5323,9 @@ fn hint_missing_borrow<'tcx>( ty = mut_ty.ty; left -= 1; } - let sugg = if left == 0 { - (span, String::new()) - } else { - (arg.span, expected_arg.to_string()) - }; - remove_borrow.push(sugg); + if left == 0 { + remove_borrow.push((span, String::new())); + } } } } diff --git a/tests/ui/closures/multiple-fn-bounds.stderr b/tests/ui/closures/multiple-fn-bounds.stderr index 9b824fa0eefb..c99cbac01faf 100644 --- a/tests/ui/closures/multiple-fn-bounds.stderr +++ b/tests/ui/closures/multiple-fn-bounds.stderr @@ -19,11 +19,6 @@ note: required by a bound in `foo` | LL | fn foo bool + Fn(char) -> bool>(f: F) { | ^^^^^^^^^^^^^^^^ required by this bound in `foo` -help: consider adjusting the signature so it does not borrow its argument - | -LL - foo(move |x| v); -LL + foo(move |char| v); - | error: aborting due to 1 previous error From cafe91749f491d8d4c10893f1dfa6298951dc9e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 12 Jan 2026 22:38:32 +0000 Subject: [PATCH 0635/1061] On unmet trait bound, mention if trait is unstable --- .../error_reporting/traits/fulfillment_errors.rs | 2 +- .../src/error_reporting/traits/suggestions.rs | 9 ++++++++- tests/ui/abi/issues/issue-22565-rust-call.stderr | 4 ++-- tests/ui/async-await/coroutine-not-future.stderr | 6 +++--- tests/ui/async-await/issue-61076.rs | 4 ++-- tests/ui/async-await/issue-61076.stderr | 4 ++-- tests/ui/async-await/issue-84841.stderr | 2 +- tests/ui/async-await/try-in-sync.stderr | 2 +- .../adt_const_params/const_param_ty_bad.stderr | 12 ++++++------ .../const_param_ty_bad_empty_array.stderr | 2 +- ...st_param_ty_generic_bounds_do_not_hold.stderr | 6 +++--- .../const_param_ty_impl_no_structural_eq.stderr | 4 ++-- tests/ui/coroutine/gen_block_is_coro.stderr | 6 +++--- tests/ui/error-codes/E0059.stderr | 4 ++-- tests/ui/extern/extern-types-unsized.stderr | 4 ++-- tests/ui/extern/unsized-extern-derefmove.stderr | 6 +++--- .../feature-gate-sized-hierarchy.stderr | 2 +- .../rust-call-abi-not-a-tuple-ice-81974.stderr | 16 ++++++++-------- .../ui/mir/validate/validate-unsize-cast.stderr | 2 +- .../overloaded/overloaded-calls-nontuple.stderr | 12 ++++++------ .../deref-patterns/recursion-limit.stderr | 2 +- .../deref-patterns/unsatisfied-bounds.stderr | 2 +- tests/ui/proc-macro/quote/not-quotable.stderr | 2 +- tests/ui/range/range-1.stderr | 2 +- .../disallowed-positions.e2021.stderr | 6 +++--- .../disallowed-positions.e2024.stderr | 6 +++--- tests/ui/sized-hierarchy/default-bound.stderr | 2 +- tests/ui/sized-hierarchy/impls.stderr | 10 +++++----- .../sized-hierarchy/pretty-print-opaque.stderr | 6 +++--- tests/ui/specialization/issue-44861.stderr | 2 +- tests/ui/suggestions/fn-trait-notation.stderr | 4 ++-- tests/ui/suggestions/issue-72766.stderr | 2 +- tests/ui/suggestions/issue-97704.stderr | 2 +- .../unstable-trait-suggestion.stderr | 4 ++-- tests/ui/traits/issue-71036.rs | 2 +- tests/ui/traits/issue-71036.stderr | 2 +- .../ui/traits/next-solver/coroutine.fail.stderr | 2 +- .../higher-ranked-upcasting-ub.next.stderr | 2 +- .../unsize-goal-escaping-bounds.current.stderr | 2 +- tests/ui/transmutability/assoc-bound.stderr | 2 +- .../dont-assume-err-is-yes-issue-126377.stderr | 2 +- .../transmutability/references/unsafecell.stderr | 8 ++++---- .../try-block-bad-type-heterogeneous.stderr | 4 ++-- tests/ui/try-block/try-block-bad-type.stderr | 4 ++-- tests/ui/try-block/try-block-in-while.stderr | 2 +- tests/ui/try-trait/try-operator-on-main.stderr | 6 +++--- tests/ui/tuple/builtin-fail.stderr | 8 ++++---- tests/ui/type/pattern_types/nested.stderr | 14 +++++++------- tests/ui/typeck/issue-57404.stderr | 2 +- .../non-tupled-arg-mismatch.stderr | 2 +- 50 files changed, 116 insertions(+), 109 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 8762607edf5d..00d06779e652 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -681,7 +681,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Ambiguous predicates should never error | ty::PredicateKind::Ambiguous // We never return Err when proving UnstableFeature goal. - | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature{ .. }) + | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature { .. }) | ty::PredicateKind::NormalizesTo { .. } | ty::PredicateKind::AliasRelate { .. } | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType { .. }) => { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 511e9e85b5f6..c9e07175773b 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -5515,7 +5515,14 @@ pub(super) fn get_explanation_based_on_obligation<'tcx>( }; if let ty::PredicatePolarity::Positive = trait_predicate.polarity() { format!( - "{pre_message}the trait `{}` is not implemented for{desc} `{}`", + "{pre_message}the {}trait `{}` is not implemented for{desc} `{}`", + if tcx.lookup_stability(trait_predicate.def_id()).map(|s| s.level.is_stable()) + == Some(false) + { + "nightly-only, unstable " + } else { + "" + }, trait_predicate.print_modifiers_and_trait_path(), tcx.short_string(trait_predicate.self_ty().skip_binder(), long_ty_path), ) diff --git a/tests/ui/abi/issues/issue-22565-rust-call.stderr b/tests/ui/abi/issues/issue-22565-rust-call.stderr index 3e296bdaea41..90fa210fa2fa 100644 --- a/tests/ui/abi/issues/issue-22565-rust-call.stderr +++ b/tests/ui/abi/issues/issue-22565-rust-call.stderr @@ -2,7 +2,7 @@ error[E0277]: functions with the "rust-call" ABI must take a single non-self tup --> $DIR/issue-22565-rust-call.rs:3:1 | LL | extern "rust-call" fn b(_i: i32) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `i32` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `i32` error: functions with the "rust-call" ABI must take a single non-self tuple argument --> $DIR/issue-22565-rust-call.rs:17:5 @@ -32,7 +32,7 @@ error[E0277]: functions with the "rust-call" ABI must take a single non-self tup --> $DIR/issue-22565-rust-call.rs:27:7 | LL | b(10); - | ^^ the trait `std::marker::Tuple` is not implemented for `i32` + | ^^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `i32` error: functions with the "rust-call" ABI must take a single non-self tuple argument --> $DIR/issue-22565-rust-call.rs:29:5 diff --git a/tests/ui/async-await/coroutine-not-future.stderr b/tests/ui/async-await/coroutine-not-future.stderr index b0f371f6706d..b55faf39ce69 100644 --- a/tests/ui/async-await/coroutine-not-future.stderr +++ b/tests/ui/async-await/coroutine-not-future.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `impl Future: Coroutine<_>` is not sa --> $DIR/coroutine-not-future.rs:36:21 | LL | takes_coroutine(async_fn()); - | --------------- ^^^^^^^^^^ the trait `Coroutine<_>` is not implemented for `impl Future` + | --------------- ^^^^^^^^^^ the nightly-only, unstable trait `Coroutine<_>` is not implemented for `impl Future` | | | required by a bound introduced by this call | @@ -16,7 +16,7 @@ error[E0277]: the trait bound `impl Future: Coroutine<_>` is not sa --> $DIR/coroutine-not-future.rs:38:21 | LL | takes_coroutine(returns_async_block()); - | --------------- ^^^^^^^^^^^^^^^^^^^^^ the trait `Coroutine<_>` is not implemented for `impl Future` + | --------------- ^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `Coroutine<_>` is not implemented for `impl Future` | | | required by a bound introduced by this call | @@ -30,7 +30,7 @@ error[E0277]: the trait bound `{async block@$DIR/coroutine-not-future.rs:40:21: --> $DIR/coroutine-not-future.rs:40:21 | LL | takes_coroutine(async {}); - | --------------- ^^^^^^^^ the trait `Coroutine<_>` is not implemented for `{async block@$DIR/coroutine-not-future.rs:40:21: 40:26}` + | --------------- ^^^^^^^^ the nightly-only, unstable trait `Coroutine<_>` is not implemented for `{async block@$DIR/coroutine-not-future.rs:40:21: 40:26}` | | | required by a bound introduced by this call | diff --git a/tests/ui/async-await/issue-61076.rs b/tests/ui/async-await/issue-61076.rs index 0a679a95970a..6fe7846ea8d9 100644 --- a/tests/ui/async-await/issue-61076.rs +++ b/tests/ui/async-await/issue-61076.rs @@ -4,7 +4,7 @@ use core::future::Future; use core::pin::Pin; use core::task::{Context, Poll}; -struct T; //~ HELP the trait `Try` is not implemented for `T` +struct T; //~ HELP the nightly-only, unstable trait `Try` is not implemented for `T` struct Tuple(i32); @@ -41,7 +41,7 @@ async fn foo() -> Result<(), ()> { async fn bar() -> Result<(), ()> { foo()?; //~ ERROR the `?` operator can only be applied to values that implement `Try` //~^ NOTE the `?` operator cannot be applied to type `impl Future>` - //~| HELP the trait `Try` is not implemented for `impl Future>` + //~| HELP the nightly-only, unstable trait `Try` is not implemented for `impl Future>` //~| HELP consider `await`ing on the `Future` //~| NOTE in this expansion of desugaring of operator `?` //~| NOTE in this expansion of desugaring of operator `?` diff --git a/tests/ui/async-await/issue-61076.stderr b/tests/ui/async-await/issue-61076.stderr index 7d46abe4a66b..dd49d00246cd 100644 --- a/tests/ui/async-await/issue-61076.stderr +++ b/tests/ui/async-await/issue-61076.stderr @@ -4,7 +4,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | foo()?; | ^^^^^^ the `?` operator cannot be applied to type `impl Future>` | - = help: the trait `Try` is not implemented for `impl Future>` + = help: the nightly-only, unstable trait `Try` is not implemented for `impl Future>` help: consider `await`ing on the `Future` | LL | foo().await?; @@ -16,7 +16,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | t?; | ^^ the `?` operator cannot be applied to type `T` | -help: the trait `Try` is not implemented for `T` +help: the nightly-only, unstable trait `Try` is not implemented for `T` --> $DIR/issue-61076.rs:7:1 | LL | struct T; diff --git a/tests/ui/async-await/issue-84841.stderr b/tests/ui/async-await/issue-84841.stderr index 0d008477310a..6c714ce7828c 100644 --- a/tests/ui/async-await/issue-84841.stderr +++ b/tests/ui/async-await/issue-84841.stderr @@ -4,7 +4,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | test()?; | ^^^^^^^ the `?` operator cannot be applied to type `impl Future` | - = help: the trait `Try` is not implemented for `impl Future` + = help: the nightly-only, unstable trait `Try` is not implemented for `impl Future` error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/issue-84841.rs:9:11 diff --git a/tests/ui/async-await/try-in-sync.stderr b/tests/ui/async-await/try-in-sync.stderr index bc7a6bd01512..0957339a4dc5 100644 --- a/tests/ui/async-await/try-in-sync.stderr +++ b/tests/ui/async-await/try-in-sync.stderr @@ -4,7 +4,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | foo()?; | ^^^^^^ the `?` operator cannot be applied to type `impl Future>` | - = help: the trait `Try` is not implemented for `impl Future>` + = help: the nightly-only, unstable trait `Try` is not implemented for `impl Future>` note: this implements `Future` and its output type supports `?`, but the future cannot be awaited in a synchronous function --> $DIR/try-in-sync.rs:6:10 | diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr index 5109dccd96a1..be63c9e5c046 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr @@ -2,7 +2,7 @@ error[E0277]: `fn() {main}` can't be used as a const parameter type --> $DIR/const_param_ty_bad.rs:7:11 | LL | check(main); - | ----- ^^^^ the trait `ConstParamTy_` is not implemented for fn item `fn() {main}` + | ----- ^^^^ the nightly-only, unstable trait `ConstParamTy_` is not implemented for fn item `fn() {main}` | | | required by a bound introduced by this call | @@ -24,7 +24,7 @@ LL | check(|| {}); | | | required by a bound introduced by this call | - = help: the trait `ConstParamTy_` is not implemented for closure `{closure@$DIR/const_param_ty_bad.rs:8:11: 8:13}` + = help: the nightly-only, unstable trait `ConstParamTy_` is not implemented for closure `{closure@$DIR/const_param_ty_bad.rs:8:11: 8:13}` note: required by a bound in `check` --> $DIR/const_param_ty_bad.rs:4:18 | @@ -40,7 +40,7 @@ error[E0277]: `fn()` can't be used as a const parameter type --> $DIR/const_param_ty_bad.rs:9:11 | LL | check(main as fn()); - | ----- ^^^^^^^^^^^^ the trait `ConstParamTy_` is not implemented for `fn()` + | ----- ^^^^^^^^^^^^ the nightly-only, unstable trait `ConstParamTy_` is not implemented for `fn()` | | | required by a bound introduced by this call | @@ -58,7 +58,7 @@ error[E0277]: `&mut ()` can't be used as a const parameter type --> $DIR/const_param_ty_bad.rs:10:11 | LL | check(&mut ()); - | ----- ^^^^^^^ the trait `ConstParamTy_` is not implemented for `&mut ()` + | ----- ^^^^^^^ the nightly-only, unstable trait `ConstParamTy_` is not implemented for `&mut ()` | | | required by a bound introduced by this call | @@ -78,7 +78,7 @@ error[E0277]: `*mut ()` can't be used as a const parameter type --> $DIR/const_param_ty_bad.rs:11:11 | LL | check(&mut () as *mut ()); - | ----- ^^^^^^^^^^^^^^^^^^ the trait `ConstParamTy_` is not implemented for `*mut ()` + | ----- ^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `ConstParamTy_` is not implemented for `*mut ()` | | | required by a bound introduced by this call | @@ -98,7 +98,7 @@ error[E0277]: `*const ()` can't be used as a const parameter type --> $DIR/const_param_ty_bad.rs:12:11 | LL | check(&() as *const ()); - | ----- ^^^^^^^^^^^^^^^^ the trait `ConstParamTy_` is not implemented for `*const ()` + | ----- ^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `ConstParamTy_` is not implemented for `*const ()` | | | required by a bound introduced by this call | diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr index 373ac9435daf..460b7420e8c0 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr @@ -4,7 +4,7 @@ error[E0277]: `NotParam` can't be used as a const parameter type LL | check::<[NotParam; 0]>(); | ^^^^^^^^^^^^^ unsatisfied trait bound | -help: the trait `ConstParamTy_` is not implemented for `NotParam` +help: the nightly-only, unstable trait `ConstParamTy_` is not implemented for `NotParam` --> $DIR/const_param_ty_bad_empty_array.rs:5:1 | LL | struct NotParam; diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr index ca2aa3adcb7a..fd1162fe08e3 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr @@ -4,7 +4,7 @@ error[E0277]: `NotParam` can't be used as a const parameter type LL | check::<&NotParam>(); | ^^^^^^^^^ unsatisfied trait bound | -help: the trait `ConstParamTy_` is not implemented for `NotParam` +help: the nightly-only, unstable trait `ConstParamTy_` is not implemented for `NotParam` --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:5:1 | LL | struct NotParam; @@ -22,7 +22,7 @@ error[E0277]: `NotParam` can't be used as a const parameter type LL | check::<[NotParam]>(); | ^^^^^^^^^^ unsatisfied trait bound | -help: the trait `ConstParamTy_` is not implemented for `NotParam` +help: the nightly-only, unstable trait `ConstParamTy_` is not implemented for `NotParam` --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:5:1 | LL | struct NotParam; @@ -40,7 +40,7 @@ error[E0277]: `NotParam` can't be used as a const parameter type LL | check::<[NotParam; 17]>(); | ^^^^^^^^^^^^^^ unsatisfied trait bound | -help: the trait `ConstParamTy_` is not implemented for `NotParam` +help: the nightly-only, unstable trait `ConstParamTy_` is not implemented for `NotParam` --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:5:1 | LL | struct NotParam; diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr index c6b791ed9674..ca2a693d48ce 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr @@ -18,7 +18,7 @@ error[E0277]: the type `CantParam` does not `#[derive(PartialEq)]` LL | impl std::marker::ConstParamTy_ for CantParam {} | ^^^^^^^^^ unsatisfied trait bound | -help: the trait `StructuralPartialEq` is not implemented for `CantParam` +help: the nightly-only, unstable trait `StructuralPartialEq` is not implemented for `CantParam` --> $DIR/const_param_ty_impl_no_structural_eq.rs:8:1 | LL | struct CantParam(ImplementsConstParamTy); @@ -46,7 +46,7 @@ error[E0277]: the type `CantParamDerive` does not `#[derive(PartialEq)]` LL | #[derive(std::marker::ConstParamTy)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound | -help: the trait `StructuralPartialEq` is not implemented for `CantParamDerive` +help: the nightly-only, unstable trait `StructuralPartialEq` is not implemented for `CantParamDerive` --> $DIR/const_param_ty_impl_no_structural_eq.rs:17:1 | LL | struct CantParamDerive(ImplementsConstParamTy); diff --git a/tests/ui/coroutine/gen_block_is_coro.stderr b/tests/ui/coroutine/gen_block_is_coro.stderr index 444f0eca1d54..fac09f600059 100644 --- a/tests/ui/coroutine/gen_block_is_coro.stderr +++ b/tests/ui/coroutine/gen_block_is_coro.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `{gen block@$DIR/gen_block_is_coro.rs:8:5: 8:8}: C --> $DIR/gen_block_is_coro.rs:7:13 | LL | fn foo() -> impl Coroutine { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Coroutine` is not implemented for `{gen block@$DIR/gen_block_is_coro.rs:8:5: 8:8}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `Coroutine` is not implemented for `{gen block@$DIR/gen_block_is_coro.rs:8:5: 8:8}` LL | gen { yield 42 } | ---------------- return type was inferred to be `{gen block@$DIR/gen_block_is_coro.rs:8:5: 8:8}` here @@ -10,7 +10,7 @@ error[E0277]: the trait bound `{gen block@$DIR/gen_block_is_coro.rs:12:5: 12:8}: --> $DIR/gen_block_is_coro.rs:11:13 | LL | fn bar() -> impl Coroutine { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Coroutine` is not implemented for `{gen block@$DIR/gen_block_is_coro.rs:12:5: 12:8}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `Coroutine` is not implemented for `{gen block@$DIR/gen_block_is_coro.rs:12:5: 12:8}` LL | gen { yield 42 } | ---------------- return type was inferred to be `{gen block@$DIR/gen_block_is_coro.rs:12:5: 12:8}` here @@ -18,7 +18,7 @@ error[E0277]: the trait bound `{gen block@$DIR/gen_block_is_coro.rs:16:5: 16:8}: --> $DIR/gen_block_is_coro.rs:15:13 | LL | fn baz() -> impl Coroutine { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Coroutine` is not implemented for `{gen block@$DIR/gen_block_is_coro.rs:16:5: 16:8}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `Coroutine` is not implemented for `{gen block@$DIR/gen_block_is_coro.rs:16:5: 16:8}` LL | gen { yield 42 } | ---------------- return type was inferred to be `{gen block@$DIR/gen_block_is_coro.rs:16:5: 16:8}` here diff --git a/tests/ui/error-codes/E0059.stderr b/tests/ui/error-codes/E0059.stderr index 698ee0a2a902..43191db8be10 100644 --- a/tests/ui/error-codes/E0059.stderr +++ b/tests/ui/error-codes/E0059.stderr @@ -2,7 +2,7 @@ error[E0059]: type parameter to bare `Fn` trait must be a tuple --> $DIR/E0059.rs:3:11 | LL | fn foo>(f: F) -> F::Output { f(3) } - | ^^^^^^^ the trait `std::marker::Tuple` is not implemented for `i32` + | ^^^^^^^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `i32` | note: required by a bound in `Fn` --> $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -11,7 +11,7 @@ error[E0277]: `i32` is not a tuple --> $DIR/E0059.rs:3:41 | LL | fn foo>(f: F) -> F::Output { f(3) } - | ^^^^ the trait `std::marker::Tuple` is not implemented for `i32` + | ^^^^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `i32` error[E0059]: cannot use call notation; the first type parameter for the function trait is neither a tuple nor unit --> $DIR/E0059.rs:3:41 diff --git a/tests/ui/extern/extern-types-unsized.stderr b/tests/ui/extern/extern-types-unsized.stderr index 43dd9800d6d3..9953e5686632 100644 --- a/tests/ui/extern/extern-types-unsized.stderr +++ b/tests/ui/extern/extern-types-unsized.stderr @@ -65,7 +65,7 @@ error[E0277]: the size for values of type `A` cannot be known LL | assert_sized::>(); | ^^^^^^ doesn't have a known size | - = help: the trait `MetaSized` is not implemented for `A` + = help: the nightly-only, unstable trait `MetaSized` is not implemented for `A` note: required by a bound in `Bar` --> $DIR/extern-types-unsized.rs:14:12 | @@ -100,7 +100,7 @@ error[E0277]: the size for values of type `A` cannot be known LL | assert_sized::>>(); | ^^^^^^^^^^^ doesn't have a known size | - = help: the trait `MetaSized` is not implemented for `A` + = help: the nightly-only, unstable trait `MetaSized` is not implemented for `A` note: required by a bound in `Bar` --> $DIR/extern-types-unsized.rs:14:12 | diff --git a/tests/ui/extern/unsized-extern-derefmove.stderr b/tests/ui/extern/unsized-extern-derefmove.stderr index a9efc2e66e3b..7eb9c6800dc6 100644 --- a/tests/ui/extern/unsized-extern-derefmove.stderr +++ b/tests/ui/extern/unsized-extern-derefmove.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `Device` cannot be known LL | unsafe fn make_device() -> Box { | ^^^^^^^^^^^ doesn't have a known size | - = help: the trait `MetaSized` is not implemented for `Device` + = help: the nightly-only, unstable trait `MetaSized` is not implemented for `Device` note: required by a bound in `Box` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL @@ -32,7 +32,7 @@ error[E0277]: the size for values of type `Device` cannot be known LL | Box::from_raw(0 as *mut _) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a known size | - = help: the trait `MetaSized` is not implemented for `Device` + = help: the nightly-only, unstable trait `MetaSized` is not implemented for `Device` note: required by a bound in `Box` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL @@ -55,7 +55,7 @@ error[E0277]: the size for values of type `Device` cannot be known LL | let d: Device = unsafe { *make_device() }; | ^^^^^^^^^^^^^ doesn't have a known size | - = help: the trait `MetaSized` is not implemented for `Device` + = help: the nightly-only, unstable trait `MetaSized` is not implemented for `Device` note: required by a bound in `Box` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL diff --git a/tests/ui/feature-gates/feature-gate-sized-hierarchy.stderr b/tests/ui/feature-gates/feature-gate-sized-hierarchy.stderr index 6a35fcfb0e8e..8e97c73c7d21 100644 --- a/tests/ui/feature-gates/feature-gate-sized-hierarchy.stderr +++ b/tests/ui/feature-gates/feature-gate-sized-hierarchy.stderr @@ -17,7 +17,7 @@ error[E0277]: the size for values of type `main::Foo` cannot be known LL | needs_metasized::(); | ^^^ doesn't have a known size | - = help: the trait `MetaSized` is not implemented for `main::Foo` + = help: the nightly-only, unstable trait `MetaSized` is not implemented for `main::Foo` note: required by a bound in `needs_metasized` --> $DIR/feature-gate-sized-hierarchy.rs:7:23 | diff --git a/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.stderr b/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.stderr index e7cb82687fa7..6d7f46fae805 100644 --- a/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.stderr +++ b/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.stderr @@ -2,7 +2,7 @@ error[E0059]: type parameter to bare `FnOnce` trait must be a tuple --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:31:5 | LL | extern "rust-call" fn call_once(mut self, a: A) -> Self::Output { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `A` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `A` | note: required by a bound in `FnOnce` --> $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -15,7 +15,7 @@ error[E0059]: type parameter to bare `FnOnce` trait must be a tuple --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:24:12 | LL | impl FnOnce for CachedFun - | ^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `A` + | ^^^^^^^^^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `A` | note: required by a bound in `FnOnce` --> $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -28,7 +28,7 @@ error[E0059]: type parameter to bare `FnOnce` trait must be a tuple --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:45:5 | LL | extern "rust-call" fn call_mut(&mut self, a: A) -> Self::Output { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `A` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `A` | note: required by a bound in `FnOnce` --> $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -41,7 +41,7 @@ error[E0059]: type parameter to bare `FnMut` trait must be a tuple --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:39:12 | LL | impl FnMut for CachedFun - | ^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `A` + | ^^^^^^^^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `A` | note: required by a bound in `FnMut` --> $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -54,7 +54,7 @@ error[E0277]: functions with the "rust-call" ABI must take a single non-self tup --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:31:5 | LL | extern "rust-call" fn call_once(mut self, a: A) -> Self::Output { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `A` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `A` | help: consider further restricting type parameter `A` with unstable trait `Tuple` | @@ -65,7 +65,7 @@ error[E0277]: functions with the "rust-call" ABI must take a single non-self tup --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:45:5 | LL | extern "rust-call" fn call_mut(&mut self, a: A) -> Self::Output { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `A` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `A` | help: consider further restricting type parameter `A` with unstable trait `Tuple` | @@ -76,7 +76,7 @@ error[E0277]: `A` is not a tuple --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:34:19 | LL | self.call_mut(a) - | -------- ^ the trait `std::marker::Tuple` is not implemented for `A` + | -------- ^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `A` | | | required by a bound introduced by this call | @@ -91,7 +91,7 @@ error[E0277]: `i32` is not a tuple --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:59:26 | LL | cachedcoso.call_once(1); - | --------- ^ the trait `std::marker::Tuple` is not implemented for `i32` + | --------- ^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `i32` | | | required by a bound introduced by this call | diff --git a/tests/ui/mir/validate/validate-unsize-cast.stderr b/tests/ui/mir/validate/validate-unsize-cast.stderr index 8449c6a24bd3..66dd5716826f 100644 --- a/tests/ui/mir/validate/validate-unsize-cast.stderr +++ b/tests/ui/mir/validate/validate-unsize-cast.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: Unsize` is not satisfied --> $DIR/validate-unsize-cast.rs:10:42 | LL | impl CastTo for T {} - | ^ the trait `Unsize` is not implemented for `T` + | ^ the nightly-only, unstable trait `Unsize` is not implemented for `T` | = note: all implementations of `Unsize` are provided automatically by the compiler, see for more information note: required by a bound in `CastTo` diff --git a/tests/ui/overloaded/overloaded-calls-nontuple.stderr b/tests/ui/overloaded/overloaded-calls-nontuple.stderr index 54a9d1f09b52..b898288c3e4b 100644 --- a/tests/ui/overloaded/overloaded-calls-nontuple.stderr +++ b/tests/ui/overloaded/overloaded-calls-nontuple.stderr @@ -2,7 +2,7 @@ error[E0059]: type parameter to bare `FnMut` trait must be a tuple --> $DIR/overloaded-calls-nontuple.rs:10:6 | LL | impl FnMut for S { - | ^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `isize` + | ^^^^^^^^^^^^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `isize` | note: required by a bound in `FnMut` --> $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -11,7 +11,7 @@ error[E0059]: type parameter to bare `FnOnce` trait must be a tuple --> $DIR/overloaded-calls-nontuple.rs:18:6 | LL | impl FnOnce for S { - | ^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `isize` + | ^^^^^^^^^^^^^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `isize` | note: required by a bound in `FnOnce` --> $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -20,19 +20,19 @@ error[E0277]: functions with the "rust-call" ABI must take a single non-self tup --> $DIR/overloaded-calls-nontuple.rs:12:5 | LL | extern "rust-call" fn call_mut(&mut self, z: isize) -> isize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `isize` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `isize` error[E0277]: functions with the "rust-call" ABI must take a single non-self tuple argument --> $DIR/overloaded-calls-nontuple.rs:21:5 | LL | extern "rust-call" fn call_once(mut self, z: isize) -> isize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `isize` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `isize` error[E0277]: `isize` is not a tuple --> $DIR/overloaded-calls-nontuple.rs:23:23 | LL | self.call_mut(z) - | -------- ^ the trait `std::marker::Tuple` is not implemented for `isize` + | -------- ^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `isize` | | | required by a bound introduced by this call | @@ -53,7 +53,7 @@ error[E0277]: `isize` is not a tuple --> $DIR/overloaded-calls-nontuple.rs:29:10 | LL | drop(s(3)) - | ^^^^ the trait `std::marker::Tuple` is not implemented for `isize` + | ^^^^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `isize` error: aborting due to 7 previous errors diff --git a/tests/ui/pattern/deref-patterns/recursion-limit.stderr b/tests/ui/pattern/deref-patterns/recursion-limit.stderr index f6aa92b23adb..7c140e4493e7 100644 --- a/tests/ui/pattern/deref-patterns/recursion-limit.stderr +++ b/tests/ui/pattern/deref-patterns/recursion-limit.stderr @@ -12,7 +12,7 @@ error[E0277]: the trait bound `Cyclic: DerefPure` is not satisfied LL | () => {} | ^^ unsatisfied trait bound | -help: the trait `DerefPure` is not implemented for `Cyclic` +help: the nightly-only, unstable trait `DerefPure` is not implemented for `Cyclic` --> $DIR/recursion-limit.rs:8:1 | LL | struct Cyclic; diff --git a/tests/ui/pattern/deref-patterns/unsatisfied-bounds.stderr b/tests/ui/pattern/deref-patterns/unsatisfied-bounds.stderr index 0b1e8ef49780..3ee6efefe697 100644 --- a/tests/ui/pattern/deref-patterns/unsatisfied-bounds.stderr +++ b/tests/ui/pattern/deref-patterns/unsatisfied-bounds.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `MyPointer: DerefPure` is not satisfied LL | () => {} | ^^ unsatisfied trait bound | -help: the trait `DerefPure` is not implemented for `MyPointer` +help: the nightly-only, unstable trait `DerefPure` is not implemented for `MyPointer` --> $DIR/unsatisfied-bounds.rs:4:1 | LL | struct MyPointer; diff --git a/tests/ui/proc-macro/quote/not-quotable.stderr b/tests/ui/proc-macro/quote/not-quotable.stderr index 62a02638e548..b00d029946d6 100644 --- a/tests/ui/proc-macro/quote/not-quotable.stderr +++ b/tests/ui/proc-macro/quote/not-quotable.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `Ipv4Addr: ToTokens` is not satisfied LL | let _ = quote! { $ip }; | ^^^^^^^^^^^^^^ | | - | the trait `ToTokens` is not implemented for `Ipv4Addr` + | the nightly-only, unstable trait `ToTokens` is not implemented for `Ipv4Addr` | required by a bound introduced by this call | = help: the following other types implement trait `ToTokens`: diff --git a/tests/ui/range/range-1.stderr b/tests/ui/range/range-1.stderr index 8878ba143097..f2d603b32af0 100644 --- a/tests/ui/range/range-1.stderr +++ b/tests/ui/range/range-1.stderr @@ -8,7 +8,7 @@ error[E0277]: the trait bound `bool: Step` is not satisfied --> $DIR/range-1.rs:9:14 | LL | for i in false..true {} - | ^^^^^^^^^^^ the trait `Step` is not implemented for `bool` + | ^^^^^^^^^^^ the nightly-only, unstable trait `Step` is not implemented for `bool` | = note: required for `std::ops::Range` to implement `Iterator` = note: required for `std::ops::Range` to implement `IntoIterator` diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.e2021.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.e2021.stderr index 15e7be8c65f2..40a32880f407 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.e2021.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.e2021.stderr @@ -1137,7 +1137,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | if let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` | - = help: the trait `Try` is not implemented for `{integer}` + = help: the nightly-only, unstable trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:224:11 @@ -1198,7 +1198,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | while let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` | - = help: the trait `Try` is not implemented for `{integer}` + = help: the nightly-only, unstable trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:333:10 @@ -1217,7 +1217,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | let 0 = 0?; | ^^ the `?` operator cannot be applied to type `{integer}` | - = help: the trait `Try` is not implemented for `{integer}` + = help: the nightly-only, unstable trait `Try` is not implemented for `{integer}` error: aborting due to 134 previous errors diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.e2024.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.e2024.stderr index 20af65cf89a2..21167cf63d17 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.e2024.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.e2024.stderr @@ -1083,7 +1083,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | if let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` | - = help: the trait `Try` is not implemented for `{integer}` + = help: the nightly-only, unstable trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:224:11 @@ -1144,7 +1144,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | while let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` | - = help: the trait `Try` is not implemented for `{integer}` + = help: the nightly-only, unstable trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:333:10 @@ -1163,7 +1163,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | let 0 = 0?; | ^^ the `?` operator cannot be applied to type `{integer}` | - = help: the trait `Try` is not implemented for `{integer}` + = help: the nightly-only, unstable trait `Try` is not implemented for `{integer}` error: aborting due to 125 previous errors diff --git a/tests/ui/sized-hierarchy/default-bound.stderr b/tests/ui/sized-hierarchy/default-bound.stderr index 0a4ea6f44d8e..9929e2dba524 100644 --- a/tests/ui/sized-hierarchy/default-bound.stderr +++ b/tests/ui/sized-hierarchy/default-bound.stderr @@ -76,7 +76,7 @@ error[E0277]: the size for values of type `main::Foo` cannot be known LL | metasized::(); | ^^^ doesn't have a known size | - = help: the trait `MetaSized` is not implemented for `main::Foo` + = help: the nightly-only, unstable trait `MetaSized` is not implemented for `main::Foo` note: required by a bound in `metasized` --> $DIR/default-bound.rs:14:17 | diff --git a/tests/ui/sized-hierarchy/impls.stderr b/tests/ui/sized-hierarchy/impls.stderr index ca70822aad28..25c6c933149f 100644 --- a/tests/ui/sized-hierarchy/impls.stderr +++ b/tests/ui/sized-hierarchy/impls.stderr @@ -164,7 +164,7 @@ error[E0277]: the size for values of type `main::Foo` cannot be known LL | needs_metasized::(); | ^^^ doesn't have a known size | - = help: the trait `MetaSized` is not implemented for `main::Foo` + = help: the nightly-only, unstable trait `MetaSized` is not implemented for `main::Foo` note: required by a bound in `needs_metasized` --> $DIR/impls.rs:16:23 | @@ -222,7 +222,7 @@ error[E0277]: the size for values of type `main::Foo` cannot be known LL | needs_metasized::<(Foo, Foo)>(); | ^^^^^^^^^^ doesn't have a known size | - = help: within `(main::Foo, main::Foo)`, the trait `MetaSized` is not implemented for `main::Foo` + = help: within `(main::Foo, main::Foo)`, the nightly-only, unstable trait `MetaSized` is not implemented for `main::Foo` = note: required because it appears within the type `(main::Foo, main::Foo)` note: required by a bound in `needs_metasized` --> $DIR/impls.rs:16:23 @@ -273,7 +273,7 @@ error[E0277]: the size for values of type `main::Foo` cannot be known LL | needs_metasized::<(u32, Foo)>(); | ^^^^^^^^^^ doesn't have a known size | - = help: within `(u32, main::Foo)`, the trait `MetaSized` is not implemented for `main::Foo` + = help: within `(u32, main::Foo)`, the nightly-only, unstable trait `MetaSized` is not implemented for `main::Foo` = note: required because it appears within the type `(u32, main::Foo)` note: required by a bound in `needs_metasized` --> $DIR/impls.rs:16:23 @@ -323,7 +323,7 @@ error[E0277]: the size for values of type `main::Foo` cannot be known LL | needs_metasized::(); | ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a known size | - = help: within `StructAllFieldsUnsized`, the trait `MetaSized` is not implemented for `main::Foo` + = help: within `StructAllFieldsUnsized`, the nightly-only, unstable trait `MetaSized` is not implemented for `main::Foo` note: required because it appears within the type `StructAllFieldsUnsized` --> $DIR/impls.rs:243:12 | @@ -377,7 +377,7 @@ error[E0277]: the size for values of type `main::Foo` cannot be known LL | needs_metasized::(); | ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a known size | - = help: within `StructLastFieldUnsized`, the trait `MetaSized` is not implemented for `main::Foo` + = help: within `StructLastFieldUnsized`, the nightly-only, unstable trait `MetaSized` is not implemented for `main::Foo` note: required because it appears within the type `StructLastFieldUnsized` --> $DIR/impls.rs:259:12 | diff --git a/tests/ui/sized-hierarchy/pretty-print-opaque.stderr b/tests/ui/sized-hierarchy/pretty-print-opaque.stderr index ecf4d912be8f..9f9289d0f391 100644 --- a/tests/ui/sized-hierarchy/pretty-print-opaque.stderr +++ b/tests/ui/sized-hierarchy/pretty-print-opaque.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `impl Tr + PointeeSized` cannot be kno LL | pub fn pointeesized() -> Box { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a known size | - = help: the trait `MetaSized` is not implemented for `impl Tr + PointeeSized` + = help: the nightly-only, unstable trait `MetaSized` is not implemented for `impl Tr + PointeeSized` note: required by a bound in `Box` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL @@ -32,7 +32,7 @@ error[E0277]: the size for values of type `impl Tr + PointeeSized` cannot be kno LL | let x = pointeesized(); | ^^^^^^^^^^^^^^ doesn't have a known size | - = help: the trait `MetaSized` is not implemented for `impl Tr + PointeeSized` + = help: the nightly-only, unstable trait `MetaSized` is not implemented for `impl Tr + PointeeSized` note: required by a bound in `Box` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL @@ -51,7 +51,7 @@ error[E0277]: the size for values of type `impl Tr + PointeeSized` cannot be kno LL | let y: Box = x; | ^ doesn't have a known size | - = help: the trait `MetaSized` is not implemented for `impl Tr + PointeeSized` + = help: the nightly-only, unstable trait `MetaSized` is not implemented for `impl Tr + PointeeSized` = note: required for the cast from `Box` to `Box` error: aborting due to 6 previous errors diff --git a/tests/ui/specialization/issue-44861.stderr b/tests/ui/specialization/issue-44861.stderr index d184c4468b68..e480f65333fd 100644 --- a/tests/ui/specialization/issue-44861.stderr +++ b/tests/ui/specialization/issue-44861.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `(): CoerceUnsized<*const [u8]>` is not satisfied --> $DIR/issue-44861.rs:21:26 | LL | default type Data2 = (); - | ^^ the trait `CoerceUnsized<*const [u8]>` is not implemented for `()` + | ^^ the nightly-only, unstable trait `CoerceUnsized<*const [u8]>` is not implemented for `()` | note: required by a bound in `Smartass::Data2` --> $DIR/issue-44861.rs:12:17 diff --git a/tests/ui/suggestions/fn-trait-notation.stderr b/tests/ui/suggestions/fn-trait-notation.stderr index 9d0845478527..ef7d5fe36282 100644 --- a/tests/ui/suggestions/fn-trait-notation.stderr +++ b/tests/ui/suggestions/fn-trait-notation.stderr @@ -32,7 +32,7 @@ error[E0059]: type parameter to bare `Fn` trait must be a tuple --> $DIR/fn-trait-notation.rs:4:8 | LL | F: Fn, - | ^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `i32` + | ^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `i32` | note: required by a bound in `Fn` --> $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -47,7 +47,7 @@ error[E0277]: `i32` is not a tuple --> $DIR/fn-trait-notation.rs:9:5 | LL | f(3); - | ^^^^ the trait `std::marker::Tuple` is not implemented for `i32` + | ^^^^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `i32` error[E0308]: mismatched types --> $DIR/fn-trait-notation.rs:17:5 diff --git a/tests/ui/suggestions/issue-72766.stderr b/tests/ui/suggestions/issue-72766.stderr index f0680dfe19f7..03aad995b966 100644 --- a/tests/ui/suggestions/issue-72766.stderr +++ b/tests/ui/suggestions/issue-72766.stderr @@ -4,7 +4,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | SadGirl {}.call()?; | ^^^^^^^^^^^^^^^^^^ the `?` operator cannot be applied to type `impl Future>` | - = help: the trait `Try` is not implemented for `impl Future>` + = help: the nightly-only, unstable trait `Try` is not implemented for `impl Future>` help: consider `await`ing on the `Future` | LL | SadGirl {}.call().await?; diff --git a/tests/ui/suggestions/issue-97704.stderr b/tests/ui/suggestions/issue-97704.stderr index a7284db1d956..e20c68057eb7 100644 --- a/tests/ui/suggestions/issue-97704.stderr +++ b/tests/ui/suggestions/issue-97704.stderr @@ -4,7 +4,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | func(async { Ok::<_, i32>(()) })?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `?` operator cannot be applied to type `impl Future>` | - = help: the trait `Try` is not implemented for `impl Future>` + = help: the nightly-only, unstable trait `Try` is not implemented for `impl Future>` help: consider `await`ing on the `Future` | LL | func(async { Ok::<_, i32>(()) }).await?; diff --git a/tests/ui/trait-bounds/unstable-trait-suggestion.stderr b/tests/ui/trait-bounds/unstable-trait-suggestion.stderr index dfa47f2ab468..6df61e7bd1de 100644 --- a/tests/ui/trait-bounds/unstable-trait-suggestion.stderr +++ b/tests/ui/trait-bounds/unstable-trait-suggestion.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: Unstable` is not satisfied --> $DIR/unstable-trait-suggestion.rs:13:9 | LL | foo(t) - | --- ^ the trait `Unstable` is not implemented for `T` + | --- ^ the nightly-only, unstable trait `Unstable` is not implemented for `T` | | | required by a bound introduced by this call | @@ -20,7 +20,7 @@ error[E0277]: the trait bound `T: Step` is not satisfied --> $DIR/unstable-trait-suggestion.rs:17:14 | LL | for _ in t {} - | ^ the trait `Step` is not implemented for `T` + | ^ the nightly-only, unstable trait `Step` is not implemented for `T` | = note: required for `std::ops::Range` to implement `Iterator` = note: required for `std::ops::Range` to implement `IntoIterator` diff --git a/tests/ui/traits/issue-71036.rs b/tests/ui/traits/issue-71036.rs index 69eed0c0462f..9593503240b2 100644 --- a/tests/ui/traits/issue-71036.rs +++ b/tests/ui/traits/issue-71036.rs @@ -10,7 +10,7 @@ struct Foo<'a, T: ?Sized> { impl<'a, T: ?Sized + Unsize, U: ?Sized> DispatchFromDyn> for Foo<'a, T> {} //~^ ERROR the trait bound `&'a T: Unsize<&'a U>` is not satisfied -//~| NOTE the trait `Unsize<&'a U>` is not implemented for `&'a T` +//~| NOTE the nightly-only, unstable trait `Unsize<&'a U>` is not implemented for `&'a T` //~| NOTE all implementations of `Unsize` are provided automatically by the compiler //~| NOTE required for diff --git a/tests/ui/traits/issue-71036.stderr b/tests/ui/traits/issue-71036.stderr index 2452731f19f1..d2d88584f104 100644 --- a/tests/ui/traits/issue-71036.stderr +++ b/tests/ui/traits/issue-71036.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `&'a T: Unsize<&'a U>` is not satisfied --> $DIR/issue-71036.rs:11:1 | LL | impl<'a, T: ?Sized + Unsize, U: ?Sized> DispatchFromDyn> for Foo<'a, T> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unsize<&'a U>` is not implemented for `&'a T` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `Unsize<&'a U>` is not implemented for `&'a T` | = note: all implementations of `Unsize` are provided automatically by the compiler, see for more information = note: required for `&'a &'a T` to implement `DispatchFromDyn<&'a &'a U>` diff --git a/tests/ui/traits/next-solver/coroutine.fail.stderr b/tests/ui/traits/next-solver/coroutine.fail.stderr index 8c263e8644bd..a289e9839b23 100644 --- a/tests/ui/traits/next-solver/coroutine.fail.stderr +++ b/tests/ui/traits/next-solver/coroutine.fail.stderr @@ -8,7 +8,7 @@ LL | / || { LL | | LL | | yield (); LL | | }, - | |_________^ the trait `Coroutine` is not implemented for `{coroutine@$DIR/coroutine.rs:20:9: 20:11}` + | |_________^ the nightly-only, unstable trait `Coroutine` is not implemented for `{coroutine@$DIR/coroutine.rs:20:9: 20:11}` | note: required by a bound in `needs_coroutine` --> $DIR/coroutine.rs:14:28 diff --git a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.next.stderr b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.next.stderr index 392680aa5064..1087fac50fd0 100644 --- a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.next.stderr +++ b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.next.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `&dyn for<'a> Subtrait<'a, 'a>: CoerceUnsized<&dyn --> $DIR/higher-ranked-upcasting-ub.rs:22:5 | LL | x - | ^ the trait `Unsize Supertrait<'a, 'b>>` is not implemented for `dyn for<'a> Subtrait<'a, 'a>` + | ^ the nightly-only, unstable trait `Unsize Supertrait<'a, 'b>>` is not implemented for `dyn for<'a> Subtrait<'a, 'a>` | = note: all implementations of `Unsize` are provided automatically by the compiler, see for more information = note: required for `&dyn for<'a> Subtrait<'a, 'a>` to implement `CoerceUnsized<&dyn for<'a, 'b> Supertrait<'a, 'b>>` diff --git a/tests/ui/traits/unsize-goal-escaping-bounds.current.stderr b/tests/ui/traits/unsize-goal-escaping-bounds.current.stderr index e63a0bf50b7a..d2d679243ee7 100644 --- a/tests/ui/traits/unsize-goal-escaping-bounds.current.stderr +++ b/tests/ui/traits/unsize-goal-escaping-bounds.current.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `for<'a> (): Unsize<(dyn Trait + 'a)>` is not sati --> $DIR/unsize-goal-escaping-bounds.rs:20:5 | LL | foo(); - | ^^^^^ the trait `for<'a> Unsize<(dyn Trait + 'a)>` is not implemented for `()` + | ^^^^^ the nightly-only, unstable trait `for<'a> Unsize<(dyn Trait + 'a)>` is not implemented for `()` | = note: all implementations of `Unsize` are provided automatically by the compiler, see for more information note: required by a bound in `foo` diff --git a/tests/ui/transmutability/assoc-bound.stderr b/tests/ui/transmutability/assoc-bound.stderr index 4dff24e2002a..66a81f353815 100644 --- a/tests/ui/transmutability/assoc-bound.stderr +++ b/tests/ui/transmutability/assoc-bound.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `::AssocA: TransmuteFrom<(), Assume { alig LL | type AssocB = T::AssocA; | ^^^^^^^^^ unsatisfied trait bound | - = help: the trait `TransmuteFrom<(), Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `::AssocA` + = help: the nightly-only, unstable trait `TransmuteFrom<(), Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `::AssocA` note: required by a bound in `B::AssocB` --> $DIR/assoc-bound.rs:9:18 | diff --git a/tests/ui/transmutability/dont-assume-err-is-yes-issue-126377.stderr b/tests/ui/transmutability/dont-assume-err-is-yes-issue-126377.stderr index 6cb6a85c78a6..6f7e9e1bfa33 100644 --- a/tests/ui/transmutability/dont-assume-err-is-yes-issue-126377.stderr +++ b/tests/ui/transmutability/dont-assume-err-is-yes-issue-126377.stderr @@ -17,7 +17,7 @@ error[E0277]: the trait bound `(): TransmuteFrom<(), { Assume::SAFETY }>` is not --> $DIR/dont-assume-err-is-yes-issue-126377.rs:14:23 | LL | is_transmutable::<{}>(); - | ^^ the trait `TransmuteFrom<(), { Assume::SAFETY }>` is not implemented for `()` + | ^^ the nightly-only, unstable trait `TransmuteFrom<(), { Assume::SAFETY }>` is not implemented for `()` | note: required by a bound in `is_transmutable` --> $DIR/dont-assume-err-is-yes-issue-126377.rs:9:9 diff --git a/tests/ui/transmutability/references/unsafecell.stderr b/tests/ui/transmutability/references/unsafecell.stderr index 02a0935e84ea..85d6724b03fa 100644 --- a/tests/ui/transmutability/references/unsafecell.stderr +++ b/tests/ui/transmutability/references/unsafecell.stderr @@ -2,7 +2,7 @@ error[E0277]: `&u8` cannot be safely transmuted into `&UnsafeCell` --> $DIR/unsafecell.rs:27:50 | LL | assert::is_maybe_transmutable::<&'static u8, &'static UnsafeCell>(); - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Freeze` is not implemented for `UnsafeCell` + | ^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `Freeze` is not implemented for `UnsafeCell` | note: required by a bound in `is_maybe_transmutable` --> $DIR/unsafecell.rs:12:14 @@ -17,7 +17,7 @@ error[E0277]: `&UnsafeCell` cannot be safely transmuted into `&UnsafeCell $DIR/unsafecell.rs:29:62 | LL | assert::is_maybe_transmutable::<&'static UnsafeCell, &'static UnsafeCell>(); - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Freeze` is not implemented for `UnsafeCell` + | ^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `Freeze` is not implemented for `UnsafeCell` | note: required by a bound in `is_maybe_transmutable` --> $DIR/unsafecell.rs:12:14 @@ -32,7 +32,7 @@ error[E0277]: `&mut bool` cannot be safely transmuted into `&UnsafeCell` --> $DIR/unsafecell.rs:45:56 | LL | assert::is_maybe_transmutable::<&'static mut bool, &'static UnsafeCell>(); - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Freeze` is not implemented for `UnsafeCell` + | ^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `Freeze` is not implemented for `UnsafeCell` | note: required by a bound in `is_maybe_transmutable` --> $DIR/unsafecell.rs:12:14 @@ -47,7 +47,7 @@ error[E0277]: `&mut UnsafeCell` cannot be safely transmuted into `&UnsafeC --> $DIR/unsafecell.rs:46:68 | LL | assert::is_maybe_transmutable::<&'static mut UnsafeCell, &'static UnsafeCell>(); - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Freeze` is not implemented for `UnsafeCell` + | ^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `Freeze` is not implemented for `UnsafeCell` | note: required by a bound in `is_maybe_transmutable` --> $DIR/unsafecell.rs:12:14 diff --git a/tests/ui/try-block/try-block-bad-type-heterogeneous.stderr b/tests/ui/try-block/try-block-bad-type-heterogeneous.stderr index 7c7cedd392e6..4962534cf294 100644 --- a/tests/ui/try-block/try-block-bad-type-heterogeneous.stderr +++ b/tests/ui/try-block/try-block-bad-type-heterogeneous.stderr @@ -30,7 +30,7 @@ error[E0277]: a `try` block must return `Result` or `Option` (or another type th LL | let res = try bikeshed () { }; | ^ could not wrap the final value of the block as `()` doesn't implement `Try` | - = help: the trait `Try` is not implemented for `()` + = help: the nightly-only, unstable trait `Try` is not implemented for `()` error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-block-bad-type-heterogeneous.rs:20:34 @@ -38,7 +38,7 @@ error[E0277]: a `try` block must return `Result` or `Option` (or another type th LL | let res = try bikeshed i32 { 5 }; | ^ could not wrap the final value of the block as `i32` doesn't implement `Try` | - = help: the trait `Try` is not implemented for `i32` + = help: the nightly-only, unstable trait `Try` is not implemented for `i32` error: aborting due to 5 previous errors diff --git a/tests/ui/try-block/try-block-bad-type.stderr b/tests/ui/try-block/try-block-bad-type.stderr index 9df01a4cf5b1..6f806da088b6 100644 --- a/tests/ui/try-block/try-block-bad-type.stderr +++ b/tests/ui/try-block/try-block-bad-type.stderr @@ -29,7 +29,7 @@ error[E0277]: a `try` block must return `Result` or `Option` (or another type th LL | let res: () = try { }; | ^ could not wrap the final value of the block as `()` doesn't implement `Try` | - = help: the trait `Try` is not implemented for `()` + = help: the nightly-only, unstable trait `Try` is not implemented for `()` error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-block-bad-type.rs:20:26 @@ -37,7 +37,7 @@ error[E0277]: a `try` block must return `Result` or `Option` (or another type th LL | let res: i32 = try { 5 }; | ^ could not wrap the final value of the block as `i32` doesn't implement `Try` | - = help: the trait `Try` is not implemented for `i32` + = help: the nightly-only, unstable trait `Try` is not implemented for `i32` error: aborting due to 5 previous errors diff --git a/tests/ui/try-block/try-block-in-while.stderr b/tests/ui/try-block/try-block-in-while.stderr index 2760e930102b..6d6917362bc7 100644 --- a/tests/ui/try-block/try-block-in-while.stderr +++ b/tests/ui/try-block/try-block-in-while.stderr @@ -4,7 +4,7 @@ error[E0277]: a `try` block must return `Result` or `Option` (or another type th LL | while try { false } {} | ^^^^^ could not wrap the final value of the block as `bool` doesn't implement `Try` | - = help: the trait `Try` is not implemented for `bool` + = help: the nightly-only, unstable trait `Try` is not implemented for `bool` error: aborting due to 1 previous error diff --git a/tests/ui/try-trait/try-operator-on-main.stderr b/tests/ui/try-trait/try-operator-on-main.stderr index 9c2526442ab5..d58720638aec 100644 --- a/tests/ui/try-trait/try-operator-on-main.stderr +++ b/tests/ui/try-trait/try-operator-on-main.stderr @@ -22,7 +22,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | ()?; | ^^^ the `?` operator cannot be applied to type `()` | - = help: the trait `Try` is not implemented for `()` + = help: the nightly-only, unstable trait `Try` is not implemented for `()` error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/try-operator-on-main.rs:10:7 @@ -37,7 +37,7 @@ error[E0277]: the trait bound `(): Try` is not satisfied --> $DIR/try-operator-on-main.rs:14:25 | LL | try_trait_generic::<()>(); - | ^^ the trait `Try` is not implemented for `()` + | ^^ the nightly-only, unstable trait `Try` is not implemented for `()` | note: required by a bound in `try_trait_generic` --> $DIR/try-operator-on-main.rs:17:25 @@ -51,7 +51,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | ()?; | ^^^ the `?` operator cannot be applied to type `()` | - = help: the trait `Try` is not implemented for `()` + = help: the nightly-only, unstable trait `Try` is not implemented for `()` error: aborting due to 5 previous errors diff --git a/tests/ui/tuple/builtin-fail.stderr b/tests/ui/tuple/builtin-fail.stderr index 0dec88ded7ce..5e84dbff454d 100644 --- a/tests/ui/tuple/builtin-fail.stderr +++ b/tests/ui/tuple/builtin-fail.stderr @@ -2,7 +2,7 @@ error[E0277]: `T` is not a tuple --> $DIR/builtin-fail.rs:8:23 | LL | assert_is_tuple::(); - | ^ the trait `std::marker::Tuple` is not implemented for `T` + | ^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `T` | note: required by a bound in `assert_is_tuple` --> $DIR/builtin-fail.rs:3:23 @@ -18,7 +18,7 @@ error[E0277]: `i32` is not a tuple --> $DIR/builtin-fail.rs:13:23 | LL | assert_is_tuple::(); - | ^^^ the trait `std::marker::Tuple` is not implemented for `i32` + | ^^^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `i32` | note: required by a bound in `assert_is_tuple` --> $DIR/builtin-fail.rs:3:23 @@ -30,7 +30,7 @@ error[E0277]: `i32` is not a tuple --> $DIR/builtin-fail.rs:15:24 | LL | assert_is_tuple::<(i32)>(); - | ^^^ the trait `std::marker::Tuple` is not implemented for `i32` + | ^^^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `i32` | note: required by a bound in `assert_is_tuple` --> $DIR/builtin-fail.rs:3:23 @@ -44,7 +44,7 @@ error[E0277]: `TupleStruct` is not a tuple LL | assert_is_tuple::(); | ^^^^^^^^^^^ unsatisfied trait bound | -help: the trait `std::marker::Tuple` is not implemented for `TupleStruct` +help: the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `TupleStruct` --> $DIR/builtin-fail.rs:5:1 | LL | struct TupleStruct(i32, i32); diff --git a/tests/ui/type/pattern_types/nested.stderr b/tests/ui/type/pattern_types/nested.stderr index bb206d9db3db..7893cc849248 100644 --- a/tests/ui/type/pattern_types/nested.stderr +++ b/tests/ui/type/pattern_types/nested.stderr @@ -13,7 +13,7 @@ error[E0277]: `(u32) is 1..` is not a valid base type for range patterns LL | const BAD_NESTING: pattern_type!(pattern_type!(u32 is 1..) is 0..) = todo!(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ only integer types and `char` are supported | - = help: the trait `core::pat::RangePattern` is not implemented for `(u32) is 1..` + = help: the nightly-only, unstable trait `core::pat::RangePattern` is not implemented for `(u32) is 1..` = help: the following other types implement trait `core::pat::RangePattern`: char i128 @@ -31,7 +31,7 @@ error[E0277]: `(i32) is 1..` is not a valid base type for range patterns LL | const BAD_NESTING2: pattern_type!(pattern_type!(i32 is 1..) is ..=-1) = todo!(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ only integer types and `char` are supported | - = help: the trait `core::pat::RangePattern` is not implemented for `(i32) is 1..` + = help: the nightly-only, unstable trait `core::pat::RangePattern` is not implemented for `(i32) is 1..` = help: the following other types implement trait `core::pat::RangePattern`: char i128 @@ -55,7 +55,7 @@ error[E0277]: `(i32) is 1..` is not a valid base type for range patterns LL | const BAD_NESTING3: pattern_type!(pattern_type!(i32 is 1..) is ..0) = todo!(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ only integer types and `char` are supported | - = help: the trait `core::pat::RangePattern` is not implemented for `(i32) is 1..` + = help: the nightly-only, unstable trait `core::pat::RangePattern` is not implemented for `(i32) is 1..` = help: the following other types implement trait `core::pat::RangePattern`: char i128 @@ -92,7 +92,7 @@ error[E0277]: `(i32) is 1..` is not a valid base type for range patterns LL | const BAD_NESTING3: pattern_type!(pattern_type!(i32 is 1..) is ..0) = todo!(); | ^ only integer types and `char` are supported | - = help: the trait `core::pat::RangePattern` is not implemented for `(i32) is 1..` + = help: the nightly-only, unstable trait `core::pat::RangePattern` is not implemented for `(i32) is 1..` = help: the following other types implement trait `core::pat::RangePattern`: char i128 @@ -110,7 +110,7 @@ error[E0277]: `()` is not a valid base type for range patterns LL | const BAD_NESTING4: pattern_type!(() is ..0) = todo!(); | ^^ only integer types and `char` are supported | - = help: the trait `core::pat::RangePattern` is not implemented for `()` + = help: the nightly-only, unstable trait `core::pat::RangePattern` is not implemented for `()` = help: the following other types implement trait `core::pat::RangePattern`: char i128 @@ -145,7 +145,7 @@ error[E0277]: `()` is not a valid base type for range patterns LL | const BAD_NESTING4: pattern_type!(() is ..0) = todo!(); | ^ only integer types and `char` are supported | - = help: the trait `core::pat::RangePattern` is not implemented for `()` + = help: the nightly-only, unstable trait `core::pat::RangePattern` is not implemented for `()` = help: the following other types implement trait `core::pat::RangePattern`: char i128 @@ -163,7 +163,7 @@ error[E0277]: `f32` is not a valid base type for range patterns LL | const BAD_NESTING5: pattern_type!(f32 is 1.0 .. 2.0) = todo!(); | ^^^ only integer types and `char` are supported | - = help: the trait `core::pat::RangePattern` is not implemented for `f32` + = help: the nightly-only, unstable trait `core::pat::RangePattern` is not implemented for `f32` = help: the following other types implement trait `core::pat::RangePattern`: i128 i16 diff --git a/tests/ui/typeck/issue-57404.stderr b/tests/ui/typeck/issue-57404.stderr index f1d28e475a07..7f8a99ebb917 100644 --- a/tests/ui/typeck/issue-57404.stderr +++ b/tests/ui/typeck/issue-57404.stderr @@ -2,7 +2,7 @@ error[E0277]: `&mut ()` is not a tuple --> $DIR/issue-57404.rs:6:41 | LL | handlers.unwrap().as_mut().call_mut(&mut ()); - | -------- ^^^^^^^ the trait `std::marker::Tuple` is not implemented for `&mut ()` + | -------- ^^^^^^^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `&mut ()` | | | required by a bound introduced by this call | diff --git a/tests/ui/unboxed-closures/non-tupled-arg-mismatch.stderr b/tests/ui/unboxed-closures/non-tupled-arg-mismatch.stderr index 621a533dd1c5..488dff646793 100644 --- a/tests/ui/unboxed-closures/non-tupled-arg-mismatch.stderr +++ b/tests/ui/unboxed-closures/non-tupled-arg-mismatch.stderr @@ -2,7 +2,7 @@ error[E0059]: type parameter to bare `Fn` trait must be a tuple --> $DIR/non-tupled-arg-mismatch.rs:3:9 | LL | fn a>(f: F) {} - | ^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `usize` + | ^^^^^^^^^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `usize` | note: required by a bound in `Fn` --> $SRC_DIR/core/src/ops/function.rs:LL:COL From 89713fcef5b36e92db77bfea40378252607edf67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 12 Jan 2026 23:05:08 +0000 Subject: [PATCH 0636/1061] Mention `Range` when `Step` trait bound is unmet --- library/core/src/iter/range.rs | 5 +++++ tests/ui/range/range-1.stderr | 1 + tests/ui/trait-bounds/unstable-trait-suggestion.stderr | 1 + 3 files changed, 7 insertions(+) diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 9e43d5688cec..39e218a5f4b3 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -21,6 +21,11 @@ unsafe_impl_trusted_step![AsciiChar char i8 i16 i32 i64 i128 isize u8 u16 u32 u6 /// The *successor* operation moves towards values that compare greater. /// The *predecessor* operation moves towards values that compare lesser. #[rustc_diagnostic_item = "range_step"] +#[rustc_on_unimplemented( + note = "`Range` only implements `Iterator` for select types in the standard library, \ + particularly integers; to see the full list of types, see the documentation for the \ + unstable `Step` trait" +)] #[unstable(feature = "step_trait", issue = "42168")] pub trait Step: Clone + PartialOrd + Sized { /// Returns the bounds on the number of *successor* steps required to get from `start` to `end` diff --git a/tests/ui/range/range-1.stderr b/tests/ui/range/range-1.stderr index f2d603b32af0..a5001a70eae6 100644 --- a/tests/ui/range/range-1.stderr +++ b/tests/ui/range/range-1.stderr @@ -10,6 +10,7 @@ error[E0277]: the trait bound `bool: Step` is not satisfied LL | for i in false..true {} | ^^^^^^^^^^^ the nightly-only, unstable trait `Step` is not implemented for `bool` | + = note: `Range` only implements `Iterator` for select types in the standard library, particularly integers; to see the full list of types, see the documentation for the unstable `Step` trait = note: required for `std::ops::Range` to implement `Iterator` = note: required for `std::ops::Range` to implement `IntoIterator` diff --git a/tests/ui/trait-bounds/unstable-trait-suggestion.stderr b/tests/ui/trait-bounds/unstable-trait-suggestion.stderr index 6df61e7bd1de..5820074b41cc 100644 --- a/tests/ui/trait-bounds/unstable-trait-suggestion.stderr +++ b/tests/ui/trait-bounds/unstable-trait-suggestion.stderr @@ -22,6 +22,7 @@ error[E0277]: the trait bound `T: Step` is not satisfied LL | for _ in t {} | ^ the nightly-only, unstable trait `Step` is not implemented for `T` | + = note: `Range` only implements `Iterator` for select types in the standard library, particularly integers; to see the full list of types, see the documentation for the unstable `Step` trait = note: required for `std::ops::Range` to implement `Iterator` = note: required for `std::ops::Range` to implement `IntoIterator` help: consider restricting type parameter `T` with unstable trait `Step` From 45edce26d36b4d05e350c7b75419159e7f750e5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 13 Jan 2026 01:28:28 +0000 Subject: [PATCH 0637/1061] Update rustc_on_unimplemented message for `Step` --- library/core/src/iter/range.rs | 1 + tests/ui/range/range-1.rs | 2 +- tests/ui/range/range-1.stderr | 2 +- tests/ui/trait-bounds/unstable-trait-suggestion.stderr | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 39e218a5f4b3..0be1e8699bf5 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -22,6 +22,7 @@ unsafe_impl_trusted_step![AsciiChar char i8 i16 i32 i64 i128 isize u8 u16 u32 u6 /// The *predecessor* operation moves towards values that compare lesser. #[rustc_diagnostic_item = "range_step"] #[rustc_on_unimplemented( + message = "`std::ops::Range<{Self}>` is not an iterator", note = "`Range` only implements `Iterator` for select types in the standard library, \ particularly integers; to see the full list of types, see the documentation for the \ unstable `Step` trait" diff --git a/tests/ui/range/range-1.rs b/tests/ui/range/range-1.rs index 192426fe228f..8fbfae55b8a6 100644 --- a/tests/ui/range/range-1.rs +++ b/tests/ui/range/range-1.rs @@ -7,7 +7,7 @@ pub fn main() { // Bool => does not implement iterator. for i in false..true {} - //~^ ERROR `bool: Step` is not satisfied + //~^ ERROR `std::ops::Range` is not an iterator // Unsized type. let arr: &[_] = &[1, 2, 3]; diff --git a/tests/ui/range/range-1.stderr b/tests/ui/range/range-1.stderr index a5001a70eae6..5491d06aee09 100644 --- a/tests/ui/range/range-1.stderr +++ b/tests/ui/range/range-1.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | let _ = 0u32..10i32; | ^^^^^ expected `u32`, found `i32` -error[E0277]: the trait bound `bool: Step` is not satisfied +error[E0277]: `std::ops::Range` is not an iterator --> $DIR/range-1.rs:9:14 | LL | for i in false..true {} diff --git a/tests/ui/trait-bounds/unstable-trait-suggestion.stderr b/tests/ui/trait-bounds/unstable-trait-suggestion.stderr index 5820074b41cc..011e56044bfe 100644 --- a/tests/ui/trait-bounds/unstable-trait-suggestion.stderr +++ b/tests/ui/trait-bounds/unstable-trait-suggestion.stderr @@ -16,7 +16,7 @@ help: consider restricting type parameter `T` with unstable trait `Unstable` LL | pub fn bar(t: T) { | ++++++++++ -error[E0277]: the trait bound `T: Step` is not satisfied +error[E0277]: `std::ops::Range` is not an iterator --> $DIR/unstable-trait-suggestion.rs:17:14 | LL | for _ in t {} From 47089856ab3200d08f561714d87159660be8a2dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 13 Jan 2026 02:14:31 +0000 Subject: [PATCH 0638/1061] Update run-make test output --- .../missing-unstable-trait-bound/missing-bound.stderr | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/run-make/missing-unstable-trait-bound/missing-bound.stderr b/tests/run-make/missing-unstable-trait-bound/missing-bound.stderr index 7196a1a6fed7..e8a7d808bbee 100644 --- a/tests/run-make/missing-unstable-trait-bound/missing-bound.stderr +++ b/tests/run-make/missing-unstable-trait-bound/missing-bound.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `T: Step` is not satisfied +error[E0277]: `std::ops::Range` is not an iterator --> missing-bound.rs:2:14 | 2 | for _ in t {} - | ^ the trait `Step` is not implemented for `T` + | ^ the nightly-only, unstable trait `Step` is not implemented for `T` | + = note: `Range` only implements `Iterator` for select types in the standard library, particularly integers; to see the full list of types, see the documentation for the unstable `Step` trait = note: required for `std::ops::Range` to implement `Iterator` = note: required for `std::ops::Range` to implement `IntoIterator` From 112317749850f1c3f09f9ee9b0a7d872c7324d5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Augusto=20C=C3=A9sar=20Perin?= Date: Mon, 12 Jan 2026 23:49:20 -0300 Subject: [PATCH 0639/1061] Unify and deduplicate From float tests Co-authored-by: ericinB --- library/coretests/tests/floats/f128.rs | 50 ----------------- library/coretests/tests/floats/f16.rs | 35 ------------ library/coretests/tests/floats/mod.rs | 78 +++++++++++++++++++++++++- 3 files changed, 75 insertions(+), 88 deletions(-) delete mode 100644 library/coretests/tests/floats/f128.rs delete mode 100644 library/coretests/tests/floats/f16.rs diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs deleted file mode 100644 index 8e4f0c9899e1..000000000000 --- a/library/coretests/tests/floats/f128.rs +++ /dev/null @@ -1,50 +0,0 @@ -// FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy -#![cfg(target_has_reliable_f128)] - -use super::assert_biteq; - -// Note these tolerances make sense around zero, but not for more extreme exponents. - -/// Default tolerances. Works for values that should be near precise but not exact. Roughly -/// the precision carried by `100 * 100`. -#[allow(unused)] -const TOL: f128 = 1e-12; - -/// For operations that are near exact, usually not involving math of different -/// signs. -#[allow(unused)] -const TOL_PRECISE: f128 = 1e-28; - -// FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support -// the intrinsics. - -#[test] -fn test_from() { - assert_biteq!(f128::from(false), 0.0); - assert_biteq!(f128::from(true), 1.0); - assert_biteq!(f128::from(u8::MIN), 0.0); - assert_biteq!(f128::from(42_u8), 42.0); - assert_biteq!(f128::from(u8::MAX), 255.0); - assert_biteq!(f128::from(i8::MIN), -128.0); - assert_biteq!(f128::from(42_i8), 42.0); - assert_biteq!(f128::from(i8::MAX), 127.0); - assert_biteq!(f128::from(u16::MIN), 0.0); - assert_biteq!(f128::from(42_u16), 42.0); - assert_biteq!(f128::from(u16::MAX), 65535.0); - assert_biteq!(f128::from(i16::MIN), -32768.0); - assert_biteq!(f128::from(42_i16), 42.0); - assert_biteq!(f128::from(i16::MAX), 32767.0); - assert_biteq!(f128::from(u32::MIN), 0.0); - assert_biteq!(f128::from(42_u32), 42.0); - assert_biteq!(f128::from(u32::MAX), 4294967295.0); - assert_biteq!(f128::from(i32::MIN), -2147483648.0); - assert_biteq!(f128::from(42_i32), 42.0); - assert_biteq!(f128::from(i32::MAX), 2147483647.0); - // FIXME(f16_f128): Uncomment these tests once the From<{u64,i64}> impls are added. - // assert_eq!(f128::from(u64::MIN), 0.0); - // assert_eq!(f128::from(42_u64), 42.0); - // assert_eq!(f128::from(u64::MAX), 18446744073709551615.0); - // assert_eq!(f128::from(i64::MIN), -9223372036854775808.0); - // assert_eq!(f128::from(42_i64), 42.0); - // assert_eq!(f128::from(i64::MAX), 9223372036854775807.0); -} diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs deleted file mode 100644 index 3cff4259de54..000000000000 --- a/library/coretests/tests/floats/f16.rs +++ /dev/null @@ -1,35 +0,0 @@ -// FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy -#![cfg(target_has_reliable_f16)] - -use super::assert_biteq; - -/// Tolerance for results on the order of 10.0e-2 -#[allow(unused)] -const TOL_N2: f16 = 0.0001; - -/// Tolerance for results on the order of 10.0e+0 -#[allow(unused)] -const TOL_0: f16 = 0.01; - -/// Tolerance for results on the order of 10.0e+2 -#[allow(unused)] -const TOL_P2: f16 = 0.5; - -/// Tolerance for results on the order of 10.0e+4 -#[allow(unused)] -const TOL_P4: f16 = 10.0; - -// FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support -// the intrinsics. - -#[test] -fn test_from() { - assert_biteq!(f16::from(false), 0.0); - assert_biteq!(f16::from(true), 1.0); - assert_biteq!(f16::from(u8::MIN), 0.0); - assert_biteq!(f16::from(42_u8), 42.0); - assert_biteq!(f16::from(u8::MAX), 255.0); - assert_biteq!(f16::from(i8::MIN), -128.0); - assert_biteq!(f16::from(42_i8), 42.0); - assert_biteq!(f16::from(i8::MAX), 127.0); -} diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 63d5b8fb2c6e..87e21b21f310 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -375,9 +375,6 @@ macro_rules! float_test { }; } -mod f128; -mod f16; - float_test! { name: num, attrs: { @@ -1582,3 +1579,78 @@ float_test! { assert_biteq!((flt(-3.2)).mul_add(2.4, neg_inf), neg_inf); } } + +float_test! { + name: from, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + assert_biteq!(Float::from(false), Float::ZERO); + assert_biteq!(Float::from(true), Float::ONE); + + assert_biteq!(Float::from(u8::MIN), Float::ZERO); + assert_biteq!(Float::from(42_u8), 42.0); + assert_biteq!(Float::from(u8::MAX), 255.0); + + assert_biteq!(Float::from(i8::MIN), -128.0); + assert_biteq!(Float::from(42_i8), 42.0); + assert_biteq!(Float::from(i8::MAX), 127.0); + } +} + +float_test! { + name: from_u16_i16, + attrs: { + f16: #[cfg(false)], + const f16: #[cfg(false)], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + assert_biteq!(Float::from(u16::MIN), Float::ZERO); + assert_biteq!(Float::from(42_u16), 42.0); + assert_biteq!(Float::from(u16::MAX), 65535.0); + assert_biteq!(Float::from(i16::MIN), -32768.0); + assert_biteq!(Float::from(42_i16), 42.0); + assert_biteq!(Float::from(i16::MAX), 32767.0); + } +} + +float_test! { + name: from_u32_i32, + attrs: { + f16: #[cfg(false)], + const f16: #[cfg(false)], + f32: #[cfg(false)], + const f32: #[cfg(false)], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + assert_biteq!(Float::from(u32::MIN), Float::ZERO); + assert_biteq!(Float::from(42_u32), 42.0); + assert_biteq!(Float::from(u32::MAX), 4294967295.0); + assert_biteq!(Float::from(i32::MIN), -2147483648.0); + assert_biteq!(Float::from(42_i32), 42.0); + assert_biteq!(Float::from(i32::MAX), 2147483647.0); + } +} + +// FIXME(f16_f128): Uncomment and adapt these tests once the From<{u64,i64}> impls are added. +// float_test! { +// name: from_u64_i64, +// attrs: { +// f16: #[cfg(false)], +// f32: #[cfg(false)], +// f64: #[cfg(false)], +// f128: #[cfg(any(miri, target_has_reliable_f128))], +// }, +// test { +// assert_biteq!(Float::from(u64::MIN), Float::ZERO); +// assert_biteq!(Float::from(42_u64), 42.0); +// assert_biteq!(Float::from(u64::MAX), 18446744073709551615.0); +// assert_biteq!(Float::from(i64::MIN), -9223372036854775808.0); +// assert_biteq!(Float::from(42_i64), 42.0); +// assert_biteq!(Float::from(i64::MAX), 9223372036854775807.0); +// } +// } From 9b7f612d44057840d41bdae399d0b491820647a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 13 Jan 2026 02:57:40 +0000 Subject: [PATCH 0640/1061] Update main label --- library/core/src/iter/range.rs | 1 + .../run-make/missing-unstable-trait-bound/missing-bound.stderr | 2 +- tests/ui/range/range-1.stderr | 3 ++- tests/ui/trait-bounds/unstable-trait-suggestion.stderr | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 0be1e8699bf5..7880e18d7d31 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -23,6 +23,7 @@ unsafe_impl_trusted_step![AsciiChar char i8 i16 i32 i64 i128 isize u8 u16 u32 u6 #[rustc_diagnostic_item = "range_step"] #[rustc_on_unimplemented( message = "`std::ops::Range<{Self}>` is not an iterator", + label = "not an iterator", note = "`Range` only implements `Iterator` for select types in the standard library, \ particularly integers; to see the full list of types, see the documentation for the \ unstable `Step` trait" diff --git a/tests/run-make/missing-unstable-trait-bound/missing-bound.stderr b/tests/run-make/missing-unstable-trait-bound/missing-bound.stderr index e8a7d808bbee..d503751a2e93 100644 --- a/tests/run-make/missing-unstable-trait-bound/missing-bound.stderr +++ b/tests/run-make/missing-unstable-trait-bound/missing-bound.stderr @@ -2,7 +2,7 @@ error[E0277]: `std::ops::Range` is not an iterator --> missing-bound.rs:2:14 | 2 | for _ in t {} - | ^ the nightly-only, unstable trait `Step` is not implemented for `T` + | ^ not an iterator | = note: `Range` only implements `Iterator` for select types in the standard library, particularly integers; to see the full list of types, see the documentation for the unstable `Step` trait = note: required for `std::ops::Range` to implement `Iterator` diff --git a/tests/ui/range/range-1.stderr b/tests/ui/range/range-1.stderr index 5491d06aee09..9682122539c5 100644 --- a/tests/ui/range/range-1.stderr +++ b/tests/ui/range/range-1.stderr @@ -8,8 +8,9 @@ error[E0277]: `std::ops::Range` is not an iterator --> $DIR/range-1.rs:9:14 | LL | for i in false..true {} - | ^^^^^^^^^^^ the nightly-only, unstable trait `Step` is not implemented for `bool` + | ^^^^^^^^^^^ not an iterator | + = help: the nightly-only, unstable trait `Step` is not implemented for `bool` = note: `Range` only implements `Iterator` for select types in the standard library, particularly integers; to see the full list of types, see the documentation for the unstable `Step` trait = note: required for `std::ops::Range` to implement `Iterator` = note: required for `std::ops::Range` to implement `IntoIterator` diff --git a/tests/ui/trait-bounds/unstable-trait-suggestion.stderr b/tests/ui/trait-bounds/unstable-trait-suggestion.stderr index 011e56044bfe..5edaed0f4dfe 100644 --- a/tests/ui/trait-bounds/unstable-trait-suggestion.stderr +++ b/tests/ui/trait-bounds/unstable-trait-suggestion.stderr @@ -20,7 +20,7 @@ error[E0277]: `std::ops::Range` is not an iterator --> $DIR/unstable-trait-suggestion.rs:17:14 | LL | for _ in t {} - | ^ the nightly-only, unstable trait `Step` is not implemented for `T` + | ^ not an iterator | = note: `Range` only implements `Iterator` for select types in the standard library, particularly integers; to see the full list of types, see the documentation for the unstable `Step` trait = note: required for `std::ops::Range` to implement `Iterator` From e5dbb3b1a2234c49f7134b3a305ca004b993536b Mon Sep 17 00:00:00 2001 From: Marco Trevisan Date: Tue, 13 Jan 2026 04:01:45 +0100 Subject: [PATCH 0641/1061] armv7-unknown-linux-uclibceabihf.md: Fix build-toml syntax With the suggested value we were getting instead: ``` ERROR: Failed to parse '/tmp/rust/bootstrap.toml': unknown field `stage`, expected one of `build`, `description`, `host`, `target`, `build-dir`, `cargo`, `rustc`, `rustfmt`, `cargo-clippy`, `docs`, `compiler-docs`, `library-docs-private-items`, `docs-minification`, `submodules`, `gdb`, `lldb`, `nodejs`, `npm`, `yarn`, `python`, `windows-rc`, `reuse`, `locked-deps`, `vendor`, `full-bootstrap`, `bootstrap-cache-path`, `extended`, `tools`, `tool`, `verbose`, `sanitizers`, `profiler`, `cargo-native-static`, `low-priority`, `configure-args`, `local-rebuild`, `print-step-timings`, `print-step-rusage`, `check-stage`, `doc-stage`, `build-stage`, `test-stage`, `install-stage`, `dist-stage`, `bench-stage`, `patch-binaries-for-nix`, `metrics`, `android-ndk`, `optimized-compiler-builtins`, `jobs`, `compiletest-diff-tool`, `compiletest-allow-stage0`, `compiletest-use-stage0-libtest`, `tidy-extra-checks`, `ccache`, `exclude` for key `build` ``` --- .../src/platform-support/armv7-unknown-linux-uclibceabihf.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md index 9fb24906b4fc..249c8fc23a0c 100644 --- a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md +++ b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md @@ -30,7 +30,7 @@ The target can be built by enabling it for a `rustc` build, by placing the follo ```toml [build] target = ["armv7-unknown-linux-uclibceabihf"] -stage = 2 +build-stage = 2 [target.armv7-unknown-linux-uclibceabihf] # ADJUST THIS PATH TO POINT AT YOUR TOOLCHAIN From 02333ad8a2805b333d2d0a944fc04a2ff3b37b90 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 13 Jan 2026 14:10:53 +1100 Subject: [PATCH 0642/1061] Simplify some literal-value negations with `u128::wrapping_neg` --- compiler/rustc_mir_build/src/builder/expr/as_constant.rs | 4 +++- compiler/rustc_mir_build/src/thir/constant.rs | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs index 1772d66f5285..8a242445f175 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs @@ -157,7 +157,9 @@ fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx> } (ast::LitKind::Int(n, _), ty::Uint(_)) if !neg => trunc(n.get()), (ast::LitKind::Int(n, _), ty::Int(_)) => { - trunc(if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() }) + // Unsigned "negation" has the same bitwise effect as signed negation, + // which gets the result we want without additional casts. + trunc(if neg { u128::wrapping_neg(n.get()) } else { n.get() }) } (ast::LitKind::Float(n, _), ty::Float(fty)) => { parse_float_into_constval(n, *fty, neg).unwrap() diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index 7964a58a7ab0..96248499044a 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -72,10 +72,10 @@ pub(crate) fn lit_to_const<'tcx>( ty::ValTree::from_scalar_int(tcx, scalar_int) } (ast::LitKind::Int(n, _), ty::Int(i)) => { - let scalar_int = trunc( - if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() }, - i.to_unsigned(), - ); + // Unsigned "negation" has the same bitwise effect as signed negation, + // which gets the result we want without additional casts. + let scalar_int = + trunc(if neg { u128::wrapping_neg(n.get()) } else { n.get() }, i.to_unsigned()); ty::ValTree::from_scalar_int(tcx, scalar_int) } (ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int(tcx, b.into()), From 1e6909140356a20c9301523a03176b38325cd7eb Mon Sep 17 00:00:00 2001 From: Marco Trevisan Date: Tue, 13 Jan 2026 04:17:51 +0100 Subject: [PATCH 0643/1061] armv7-unknown-linux-uclibceabihf.md: Update toolchain download link The old toolchain is not working with recent rustc, as it does not defining `getauxval` --- .../src/platform-support/armv7-unknown-linux-uclibceabihf.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md index 249c8fc23a0c..d2635f12db21 100644 --- a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md +++ b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md @@ -21,7 +21,7 @@ This target is cross compiled, and requires a cross toolchain. You can find sui Compiling rust for this target has been tested on `x86_64` linux hosts. Other host types have not been tested, but may work, if you can find a suitable cross compilation toolchain for them. -If you don't already have a suitable toolchain, download one [here](https://toolchains.bootlin.com/downloads/releases/toolchains/armv7-eabihf/tarballs/armv7-eabihf--uclibc--bleeding-edge-2021.11-1.tar.bz2), and unpack it into a directory. +If you don't already have a suitable toolchain, download one [here](https://toolchains.bootlin.com/downloads/releases/toolchains/armv7-eabihf/tarballs/armv7-eabihf--uclibc--bleeding-edge-2025.08-1.tar.xz), and unpack it into a directory. ### Configure rust From 8a8b31a4d1e971044b7904acd711191d7f6b200c Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Mon, 12 Jan 2026 06:53:19 +0100 Subject: [PATCH 0644/1061] compiler: Make Externally Implementable Item (eii) macros "semiopaque" Otherwise eiis defined by std will produce large amounts of `missing stability attribute` errors. --- compiler/rustc_builtin_macros/src/eii.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index 0ebd3dc826d4..b1cd35c0433d 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -425,6 +425,9 @@ fn generate_attribute_macro_to_implement( // errors for eii's in std. macro_attrs.extend_from_slice(attrs_from_decl); + // Avoid "missing stability attribute" errors for eiis in std. See #146993. + macro_attrs.push(ecx.attr_name_value_str(sym::rustc_macro_transparency, sym::semiopaque, span)); + // #[builtin_macro(eii_shared_macro)] macro_attrs.push(ecx.attr_nested_word(sym::rustc_builtin_macro, sym::eii_shared_macro, span)); From c263d36539d2859b9fd6f433e6a23a99a3d09d16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 13 Jan 2026 07:35:24 +0100 Subject: [PATCH 0645/1061] Fix citool tests --- src/ci/citool/tests/jobs.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ci/citool/tests/jobs.rs b/src/ci/citool/tests/jobs.rs index 5231d4616e04..6787f00d9af8 100644 --- a/src/ci/citool/tests/jobs.rs +++ b/src/ci/citool/tests/jobs.rs @@ -4,7 +4,7 @@ const TEST_JOBS_YML_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/tes #[test] fn auto_jobs() { - let stdout = get_matrix("push", "commit", "refs/heads/auto"); + let stdout = get_matrix("push", "commit", "refs/heads/automation/bors/auto"); insta::assert_snapshot!(stdout, @r#" jobs=[{"name":"aarch64-gnu","full_name":"auto - aarch64-gnu","os":"ubuntu-22.04-arm","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","DEPLOY_BUCKET":"rust-lang-ci2","TOOLSTATE_PUBLISH":1},"free_disk":true},{"name":"x86_64-gnu-llvm-18-1","full_name":"auto - x86_64-gnu-llvm-18-1","os":"ubuntu-24.04","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","DEPLOY_BUCKET":"rust-lang-ci2","DOCKER_SCRIPT":"stage_2_test_set1.sh","IMAGE":"x86_64-gnu-llvm-18","READ_ONLY_SRC":"0","RUST_BACKTRACE":1,"TOOLSTATE_PUBLISH":1},"free_disk":true},{"name":"aarch64-apple","full_name":"auto - aarch64-apple","os":"macos-14","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","DEPLOY_BUCKET":"rust-lang-ci2","MACOSX_DEPLOYMENT_TARGET":11.0,"MACOSX_STD_DEPLOYMENT_TARGET":11.0,"NO_DEBUG_ASSERTIONS":1,"NO_LLVM_ASSERTIONS":1,"NO_OVERFLOW_CHECKS":1,"RUSTC_RETRY_LINKER_ON_SEGFAULT":1,"RUST_CONFIGURE_ARGS":"--enable-sanitizers --enable-profiler --set rust.jemalloc","SCRIPT":"./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin","SELECT_XCODE":"/Applications/Xcode_15.4.app","TOOLSTATE_PUBLISH":1,"USE_XCODE_CLANG":1}},{"name":"dist-i686-msvc","full_name":"auto - dist-i686-msvc","os":"windows-2022","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","CODEGEN_BACKENDS":"llvm,cranelift","DEPLOY_BUCKET":"rust-lang-ci2","DIST_REQUIRE_ALL_TOOLS":1,"RUST_CONFIGURE_ARGS":"--build=i686-pc-windows-msvc --host=i686-pc-windows-msvc --target=i686-pc-windows-msvc,i586-pc-windows-msvc --enable-full-tools --enable-profiler","SCRIPT":"python x.py dist bootstrap --include-default-paths","TOOLSTATE_PUBLISH":1}},{"name":"pr-check-1","full_name":"auto - pr-check-1","os":"ubuntu-24.04","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","DEPLOY_BUCKET":"rust-lang-ci2","TOOLSTATE_PUBLISH":1},"continue_on_error":false,"free_disk":true},{"name":"pr-check-2","full_name":"auto - pr-check-2","os":"ubuntu-24.04","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","DEPLOY_BUCKET":"rust-lang-ci2","TOOLSTATE_PUBLISH":1},"continue_on_error":false,"free_disk":true},{"name":"tidy","full_name":"auto - tidy","os":"ubuntu-24.04","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","DEPLOY_BUCKET":"rust-lang-ci2","TOOLSTATE_PUBLISH":1},"continue_on_error":false,"free_disk":true,"doc_url":"https://foo.bar"}] run_type=auto @@ -13,7 +13,7 @@ fn auto_jobs() { #[test] fn try_jobs() { - let stdout = get_matrix("push", "commit", "refs/heads/try"); + let stdout = get_matrix("push", "commit", "refs/heads/automation/bors/try"); insta::assert_snapshot!(stdout, @r###" jobs=[{"name":"dist-x86_64-linux","full_name":"try - dist-x86_64-linux","os":"ubuntu-22.04-16core-64gb","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","CODEGEN_BACKENDS":"llvm,cranelift","DEPLOY_BUCKET":"rust-lang-ci2","DIST_TRY_BUILD":1,"TOOLSTATE_PUBLISH":1}}] run_type=try @@ -28,7 +28,7 @@ fn try_custom_jobs() { try-job: aarch64-gnu try-job: dist-i686-msvc"#, - "refs/heads/try", + "refs/heads/automation/bors/try", ); insta::assert_snapshot!(stdout, @r###" jobs=[{"name":"aarch64-gnu","full_name":"try - aarch64-gnu","os":"ubuntu-22.04-arm","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","DEPLOY_BUCKET":"rust-lang-ci2","TOOLSTATE_PUBLISH":1},"free_disk":true},{"name":"dist-i686-msvc","full_name":"try - dist-i686-msvc","os":"windows-2022","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","CODEGEN_BACKENDS":"llvm,cranelift","DEPLOY_BUCKET":"rust-lang-ci2","DIST_REQUIRE_ALL_TOOLS":1,"RUST_CONFIGURE_ARGS":"--build=i686-pc-windows-msvc --host=i686-pc-windows-msvc --target=i686-pc-windows-msvc,i586-pc-windows-msvc --enable-full-tools --enable-profiler","SCRIPT":"python x.py dist bootstrap --include-default-paths","TOOLSTATE_PUBLISH":1}}] From 506762f3ff5ecdc25725e68b9669dff2e452582b Mon Sep 17 00:00:00 2001 From: Lukas Bergdoll Date: Sun, 28 Dec 2025 11:22:41 +0100 Subject: [PATCH 0646/1061] Explicitly export core and std macros Currently all core and std macros are automatically added to the prelude via #[macro_use]. However a situation arose where we want to add a new macro `assert_matches` but don't want to pull it into the standard prelude for compatibility reasons. By explicitly exporting the macros found in the core and std crates we get to decide on a per macro basis and can later add them via the rust_20xx preludes. --- .../src/standard_library_imports.rs | 2 +- compiler/rustc_lint_defs/src/builtin.rs | 37 ++++++++++ compiler/rustc_resolve/src/diagnostics.rs | 26 +++---- compiler/rustc_resolve/src/ident.rs | 23 +++++-- compiler/rustc_resolve/src/imports.rs | 7 +- compiler/rustc_resolve/src/lib.rs | 14 +++- compiler/rustc_resolve/src/macros.rs | 10 +-- library/alloctests/lib.rs | 12 +++- library/core/src/prelude/v1.rs | 49 ++++++++++++- library/std/src/prelude/mod.rs | 21 +++++- library/std/src/prelude/v1.rs | 59 ++++++++++++++-- library/std/src/process.rs | 2 +- tests/pretty/asm.pp | 1 - tests/pretty/autodiff/autodiff_forward.pp | 1 - tests/pretty/autodiff/autodiff_reverse.pp | 1 - tests/pretty/autodiff/inherent_impl.pp | 1 - tests/pretty/cast-lt.pp | 1 - tests/pretty/delegation-impl-reuse.pp | 1 - tests/pretty/delegation-inherit-attributes.pp | 1 - tests/pretty/delegation-inline-attribute.pp | 1 - tests/pretty/dollar-crate.pp | 1 - tests/pretty/expanded-and-path-remap-80832.pp | 1 - tests/pretty/format-args-str-escape.pp | 1 - tests/pretty/hir-delegation.pp | 1 - tests/pretty/hir-fn-params.pp | 1 - tests/pretty/hir-fn-variadic.pp | 1 - tests/pretty/hir-if-else.pp | 1 - tests/pretty/hir-lifetimes.pp | 1 - tests/pretty/hir-pretty-attr.pp | 1 - tests/pretty/hir-pretty-loop.pp | 1 - tests/pretty/hir-struct-expr.pp | 1 - tests/pretty/if-else.pp | 1 - tests/pretty/issue-12590-c.pp | 1 - tests/pretty/issue-4264.pp | 1 - tests/pretty/issue-85089.pp | 1 - tests/pretty/never-pattern.pp | 1 - tests/pretty/pin-ergonomics-hir.pp | 1 - tests/pretty/postfix-match/precedence.pp | 1 - tests/pretty/shebang-at-top.pp | 1 - tests/pretty/tests-are-sorted.pp | 1 - tests/rustdoc-js-std/println-typo.js | 3 + tests/ui/asm/unpretty-expanded.stdout | 1 - .../unpretty-parenthesized.stdout | 1 - .../ui/codemap_tests/unicode.expanded.stdout | 1 - .../defaults/pretty-printing-ast.stdout | 1 - .../deriving/built-in-proc-macro-scope.stdout | 1 - tests/ui/deriving/deriving-all-codegen.stdout | 1 - .../deriving-coerce-pointee-expanded.stdout | 1 - .../proc-macro-attribute-mixing.stdout | 1 - .../feature-gate-format_args_nl.rs | 2 + .../feature-gate-format_args_nl.stderr | 13 +++- tests/ui/hygiene/format-args.rs | 2 + .../ambiguous-panic-glob-vs-multiouter.rs | 16 +++++ .../ambiguous-panic-glob-vs-multiouter.stderr | 23 +++++++ .../ui/imports/ambiguous-panic-globvsglob.rs | 23 +++++++ .../imports/ambiguous-panic-globvsglob.stderr | 68 +++++++++++++++++++ .../ambiguous-panic-no-implicit-prelude.rs | 16 +++++ ...ambiguous-panic-no-implicit-prelude.stderr | 19 ++++++ .../ambiguous-panic-non-prelude-core-glob.rs | 11 +++ ...biguous-panic-non-prelude-core-glob.stderr | 22 ++++++ .../ambiguous-panic-non-prelude-std-glob.rs | 12 ++++ ...mbiguous-panic-non-prelude-std-glob.stderr | 22 ++++++ tests/ui/imports/ambiguous-panic-pick-core.rs | 11 +++ .../imports/ambiguous-panic-pick-core.stderr | 37 ++++++++++ tests/ui/imports/ambiguous-panic-pick-std.rs | 14 ++++ .../imports/ambiguous-panic-pick-std.stderr | 37 ++++++++++ tests/ui/imports/ambiguous-panic-re-emit.rs | 23 +++++++ .../ui/imports/ambiguous-panic-re-emit.stderr | 29 ++++++++ .../imports/ambiguous-panic-rename-builtin.rs | 15 ++++ .../ambiguous-panic-rename-builtin.stderr | 26 +++++++ .../imports/ambiguous-panic-rename-panics.rs | 17 +++++ .../ambiguous-panic-rename-panics.stderr | 23 +++++++ tests/ui/imports/ambiguous-panic.rs | 12 ++++ tests/ui/imports/ambiguous-panic.stderr | 26 +++++++ tests/ui/imports/glob-shadowing.stderr | 10 +-- .../local-modularized-tricky-fail-1.stderr | 10 +-- tests/ui/imports/shadow_builtin_macros.stderr | 15 ++-- tests/ui/lint/dead-code/with-core-crate.rs | 1 - .../ui/lint/dead-code/with-core-crate.stderr | 2 +- .../no_ice_for_partial_compiler_runs.stdout | 1 - .../genercs-in-path-with-prettry-hir.stdout | 1 - ...ming-methods-have-optimized-codegen.stdout | 1 - tests/ui/match/issue-82392.stdout | 1 - tests/ui/proc-macro/meta-macro-hygiene.stdout | 1 - .../nonterminal-token-hygiene.stdout | 1 - tests/ui/proc-macro/quote/debug.stdout | 1 - .../ast-pretty-check.stdout | 1 - tests/ui/stats/input-stats.stderr | 12 ++-- .../type-alias-impl-trait/issue-60662.stdout | 1 - tests/ui/unpretty/bad-literal.stdout | 1 - tests/ui/unpretty/debug-fmt-hir.stdout | 1 - tests/ui/unpretty/deprecated-attr.stdout | 1 - tests/ui/unpretty/diagnostic-attr.stdout | 1 - .../unpretty/exhaustive-asm.expanded.stdout | 1 - tests/ui/unpretty/exhaustive-asm.hir.stdout | 1 - tests/ui/unpretty/exhaustive.expanded.stdout | 1 - tests/ui/unpretty/exhaustive.hir.stdout | 1 - .../ui/unpretty/flattened-format-args.stdout | 1 - .../ui/unpretty/interpolation-expanded.stdout | 1 - tests/ui/unpretty/let-else-hir.stdout | 1 - tests/ui/unpretty/self-hir.stdout | 1 - ...ct-exprs-tuple-call-pretty-printing.stdout | 1 - tests/ui/unpretty/unpretty-expr-fn-arg.stdout | 1 - 103 files changed, 770 insertions(+), 123 deletions(-) create mode 100644 tests/ui/imports/ambiguous-panic-glob-vs-multiouter.rs create mode 100644 tests/ui/imports/ambiguous-panic-glob-vs-multiouter.stderr create mode 100644 tests/ui/imports/ambiguous-panic-globvsglob.rs create mode 100644 tests/ui/imports/ambiguous-panic-globvsglob.stderr create mode 100644 tests/ui/imports/ambiguous-panic-no-implicit-prelude.rs create mode 100644 tests/ui/imports/ambiguous-panic-no-implicit-prelude.stderr create mode 100644 tests/ui/imports/ambiguous-panic-non-prelude-core-glob.rs create mode 100644 tests/ui/imports/ambiguous-panic-non-prelude-core-glob.stderr create mode 100644 tests/ui/imports/ambiguous-panic-non-prelude-std-glob.rs create mode 100644 tests/ui/imports/ambiguous-panic-non-prelude-std-glob.stderr create mode 100644 tests/ui/imports/ambiguous-panic-pick-core.rs create mode 100644 tests/ui/imports/ambiguous-panic-pick-core.stderr create mode 100644 tests/ui/imports/ambiguous-panic-pick-std.rs create mode 100644 tests/ui/imports/ambiguous-panic-pick-std.stderr create mode 100644 tests/ui/imports/ambiguous-panic-re-emit.rs create mode 100644 tests/ui/imports/ambiguous-panic-re-emit.stderr create mode 100644 tests/ui/imports/ambiguous-panic-rename-builtin.rs create mode 100644 tests/ui/imports/ambiguous-panic-rename-builtin.stderr create mode 100644 tests/ui/imports/ambiguous-panic-rename-panics.rs create mode 100644 tests/ui/imports/ambiguous-panic-rename-panics.stderr create mode 100644 tests/ui/imports/ambiguous-panic.rs create mode 100644 tests/ui/imports/ambiguous-panic.stderr diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index 2068b5ca54dd..9f22d9eacb33 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -43,7 +43,7 @@ pub fn inject( let item = cx.item( span, - thin_vec![cx.attr_word(sym::macro_use, span)], + ast::AttrVec::new(), ast::ItemKind::ExternCrate(None, Ident::new(name, ident_span)), ); diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 8c69cc089caf..4230aa7568e2 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -19,6 +19,7 @@ declare_lint_pass! { AMBIGUOUS_ASSOCIATED_ITEMS, AMBIGUOUS_GLOB_IMPORTS, AMBIGUOUS_GLOB_REEXPORTS, + AMBIGUOUS_PANIC_IMPORTS, ARITHMETIC_OVERFLOW, ASM_SUB_REGISTER, BAD_ASM_STYLE, @@ -4472,6 +4473,42 @@ declare_lint! { }; } +declare_lint! { + /// The `ambiguous_panic_imports` lint detects ambiguous core and std panic imports, but + /// previously didn't do that due to `#[macro_use]` prelude macro import. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(ambiguous_panic_imports)] + /// #![no_std] + /// + /// extern crate std; + /// use std::prelude::v1::*; + /// + /// fn xx() { + /// panic!(); // resolves to core::panic + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Future versions of Rust will no longer accept the ambiguous resolution. + /// + /// This is a [future-incompatible] lint to transition this to a hard error in the future. + /// + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub AMBIGUOUS_PANIC_IMPORTS, + Warn, + "detects ambiguous core and std panic imports", + @future_incompatible = FutureIncompatibleInfo { + reason: fcw!(FutureReleaseError #147319), + report_in_deps: false, + }; +} + declare_lint! { /// The `refining_impl_trait_reachable` lint detects `impl Trait` return /// types in method signatures that are refined by a publically reachable diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 9781a77871f6..7bc08f1de546 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -24,7 +24,7 @@ use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ - ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, AMBIGUOUS_GLOB_IMPORTS, + ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, AMBIGUOUS_GLOB_IMPORTS, AMBIGUOUS_PANIC_IMPORTS, MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, }; use rustc_session::utils::was_invoked_from_cargo; @@ -44,10 +44,11 @@ use crate::errors::{ use crate::imports::{Import, ImportKind}; use crate::late::{DiagMetadata, PatternSource, Rib}; use crate::{ - AmbiguityError, AmbiguityKind, BindingError, BindingKey, Decl, DeclKind, Finalize, - ForwardGenericParamBanReason, HasGenericParams, LateDecl, MacroRulesScope, Module, ModuleKind, - ModuleOrUniformRoot, ParentScope, PathResult, PrivacyError, ResolutionError, Resolver, Scope, - ScopeSet, Segment, UseError, Used, VisResolutionError, errors as errs, path_names_to_string, + AmbiguityError, AmbiguityKind, AmbiguityWarning, BindingError, BindingKey, Decl, DeclKind, + Finalize, ForwardGenericParamBanReason, HasGenericParams, LateDecl, MacroRulesScope, Module, + ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, PrivacyError, ResolutionError, + Resolver, Scope, ScopeSet, Segment, UseError, Used, VisResolutionError, errors as errs, + path_names_to_string, }; type Res = def::Res; @@ -146,17 +147,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for ambiguity_error in &self.ambiguity_errors { let diag = self.ambiguity_diagnostic(ambiguity_error); - if ambiguity_error.warning { + if let Some(ambiguity_warning) = ambiguity_error.warning { let node_id = match ambiguity_error.b1.0.kind { DeclKind::Import { import, .. } => import.root_id, DeclKind::Def(_) => CRATE_NODE_ID, }; - self.lint_buffer.buffer_lint( - AMBIGUOUS_GLOB_IMPORTS, - node_id, - diag.ident.span, - diag, - ); + + let lint = match ambiguity_warning { + AmbiguityWarning::GlobImport => AMBIGUOUS_GLOB_IMPORTS, + AmbiguityWarning::PanicImport => AMBIGUOUS_PANIC_IMPORTS, + }; + + self.lint_buffer.buffer_lint(lint, node_id, diag.ident.span, diag); } else { self.dcx().emit_err(diag); } diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 91fe6741950b..7f04216c5553 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -8,6 +8,7 @@ use rustc_hir::def::{DefKind, MacroKinds, Namespace, NonMacroAttrKind, PartialRe use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK; use rustc_session::parse::feature_err; +use rustc_span::edition::Edition; use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext}; use rustc_span::{Ident, Macros20NormalizedIdent, Span, kw, sym}; use smallvec::SmallVec; @@ -20,9 +21,10 @@ use crate::late::{ }; use crate::macros::{MacroRulesScope, sub_namespace_match}; use crate::{ - AmbiguityError, AmbiguityKind, BindingKey, CmResolver, Decl, DeclKind, Determinacy, Finalize, - ImportKind, LateDecl, Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, - PrivacyError, Res, ResolutionError, Resolver, Scope, ScopeSet, Segment, Stage, Used, errors, + AmbiguityError, AmbiguityKind, AmbiguityWarning, BindingKey, CmResolver, Decl, DeclKind, + Determinacy, Finalize, ImportKind, LateDecl, Module, ModuleKind, ModuleOrUniformRoot, + ParentScope, PathResult, PrivacyError, Res, ResolutionError, Resolver, Scope, ScopeSet, + Segment, Stage, Used, errors, }; #[derive(Copy, Clone)] @@ -841,6 +843,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if issue_145575_hack || issue_149681_hack { self.issue_145575_hack_applied = true; } else { + // Turn ambiguity errors for core vs std panic into warnings. + // FIXME: Remove with lang team approval. + let is_issue_147319_hack = orig_ident.span.edition() <= Edition::Edition2024 + && matches!(orig_ident.name, sym::panic) + && matches!(scope, Scope::StdLibPrelude) + && matches!(innermost_scope, Scope::ModuleGlobs(_, _)) + && ((self.is_specific_builtin_macro(res, sym::std_panic) + && self.is_specific_builtin_macro(innermost_res, sym::core_panic)) + || (self.is_specific_builtin_macro(res, sym::core_panic) + && self.is_specific_builtin_macro(innermost_res, sym::std_panic))); + + let warning = is_issue_147319_hack.then_some(AmbiguityWarning::PanicImport); + self.ambiguity_errors.push(AmbiguityError { kind, ident: orig_ident, @@ -848,7 +863,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { b2: decl, scope1: innermost_scope, scope2: scope, - warning: false, + warning, }); return true; } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index b98061ea8130..4447374b8b06 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -959,8 +959,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ImportKind::Single { decls, .. } => decls[TypeNS].get().decl(), _ => None, }; - let ambiguity_errors_len = - |errors: &Vec>| errors.iter().filter(|error| !error.warning).count(); + let ambiguity_errors_len = |errors: &Vec>| { + errors.iter().filter(|error| error.warning.is_none()).count() + }; let prev_ambiguity_errors_len = ambiguity_errors_len(&self.ambiguity_errors); let finalize = Finalize::with_root_span(import.root_id, import.span, import.root_span); @@ -1176,7 +1177,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }); let res = binding.res(); let has_ambiguity_error = - this.ambiguity_errors.iter().any(|error| !error.warning); + this.ambiguity_errors.iter().any(|error| error.warning.is_none()); if res == Res::Err || has_ambiguity_error { this.dcx() .span_delayed_bug(import.span, "some error happened for an import"); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index d82fad3861d5..c4c1e06f94ae 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -911,6 +911,12 @@ impl AmbiguityKind { } } +#[derive(Clone, Copy, PartialEq)] +enum AmbiguityWarning { + GlobImport, + PanicImport, +} + struct AmbiguityError<'ra> { kind: AmbiguityKind, ident: Ident, @@ -919,7 +925,7 @@ struct AmbiguityError<'ra> { // `empty_module` in module scope serves as an unknown module here. scope1: Scope<'ra>, scope2: Scope<'ra>, - warning: bool, + warning: Option, } impl<'ra> DeclData<'ra> { @@ -1871,6 +1877,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.get_macro(res).is_some_and(|macro_data| macro_data.ext.builtin_name.is_some()) } + fn is_specific_builtin_macro(&self, res: Res, symbol: Symbol) -> bool { + self.get_macro(res).is_some_and(|macro_data| macro_data.ext.builtin_name == Some(symbol)) + } + fn macro_def(&self, mut ctxt: SyntaxContext) -> DefId { loop { match ctxt.outer_expn_data().macro_def_id { @@ -2063,7 +2073,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { b2, scope1: Scope::ModuleGlobs(self.empty_module, None), scope2: Scope::ModuleGlobs(self.empty_module, None), - warning: warn_ambiguity, + warning: if warn_ambiguity { Some(AmbiguityWarning::GlobImport) } else { None }, }; if !self.matches_previous_ambiguity_error(&ambiguity_error) { // avoid duplicated span information to be emit out diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 32d686d4f702..38628332f43e 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -835,10 +835,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { res: Res| { if let Some(initial_res) = initial_res { if res != initial_res { - // Make sure compilation does not succeed if preferred macro resolution - // has changed after the macro had been expanded. In theory all such - // situations should be reported as errors, so this is a bug. - this.dcx().span_delayed_bug(span, "inconsistent resolution for a macro"); + if this.ambiguity_errors.is_empty() { + // Make sure compilation does not succeed if preferred macro resolution + // has changed after the macro had been expanded. In theory all such + // situations should be reported as errors, so this is a bug. + this.dcx().span_delayed_bug(span, "inconsistent resolution for a macro"); + } } } else if this.tcx.dcx().has_errors().is_none() && this.privacy_errors.is_empty() { // It's possible that the macro was unresolved (indeterminate) and silently diff --git a/library/alloctests/lib.rs b/library/alloctests/lib.rs index b85fc8eb9970..02364c01d4d6 100644 --- a/library/alloctests/lib.rs +++ b/library/alloctests/lib.rs @@ -65,6 +65,7 @@ #![feature(negative_impls)] #![feature(never_type)] #![feature(optimize_attribute)] +#![feature(prelude_import)] #![feature(rustc_allow_const_fn_unstable)] #![feature(rustc_attrs)] #![feature(staged_api)] @@ -74,11 +75,17 @@ // Allow testing this library extern crate alloc as realalloc; -#[macro_use] + +// This is needed to provide macros to the directly imported alloc modules below. extern crate std; +#[prelude_import] +#[allow(unused_imports)] +use std::prelude::rust_2024::*; + #[cfg(test)] extern crate test; mod testing; + use realalloc::*; // We are directly including collections, raw_vec, and wtf8 here as they use non-public @@ -102,8 +109,7 @@ pub(crate) mod test_helpers { let mut hasher = std::hash::RandomState::new().build_hasher(); std::panic::Location::caller().hash(&mut hasher); let hc64 = hasher.finish(); - let seed_vec = - hc64.to_le_bytes().into_iter().chain(0u8..8).collect::>(); + let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::>(); let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap(); rand::SeedableRng::from_seed(seed) } diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index 7e0a84df5118..354be271ff13 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -59,12 +59,31 @@ pub use crate::hash::macros::Hash; #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[doc(no_inline)] +#[expect(deprecated)] pub use crate::{ - assert, cfg, column, compile_error, concat, env, file, format_args, - format_args_nl, include, include_bytes, include_str, line, log_syntax, module_path, option_env, - stringify, trace_macros, + assert, assert_eq, assert_ne, cfg, column, compile_error, concat, debug_assert, debug_assert_eq, + debug_assert_ne, file, format_args, include, include_bytes, include_str, line, matches, + module_path, option_env, stringify, todo, r#try, unimplemented, unreachable, write, writeln, }; +// These macros need special handling, so that we don't export them *and* the modules of the same +// name. We only want the macros in the prelude so we shadow the original modules with private +// modules with the same names. +mod ambiguous_macros_only { + mod env {} + #[expect(hidden_glob_reexports)] + mod panic {} + #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] + pub use crate::*; +} +#[stable(feature = "builtin_macro_prelude", since = "1.38.0")] +#[doc(no_inline)] +pub use self::ambiguous_macros_only::{env, panic}; + +#[unstable(feature = "cfg_select", issue = "115585")] +#[doc(no_inline)] +pub use crate::cfg_select; + #[unstable( feature = "concat_bytes", issue = "87555", @@ -73,6 +92,30 @@ pub use crate::{ #[doc(no_inline)] pub use crate::concat_bytes; +#[unstable(feature = "const_format_args", issue = "none")] +#[doc(no_inline)] +pub use crate::const_format_args; + +#[unstable( + feature = "log_syntax", + issue = "29598", + reason = "`log_syntax!` is not stable enough for use and is subject to change" +)] +#[doc(no_inline)] +pub use crate::log_syntax; + +#[unstable(feature = "pattern_type_macro", issue = "123646")] +#[doc(no_inline)] +pub use crate::pattern_type; + +#[unstable( + feature = "trace_macros", + issue = "29598", + reason = "`trace_macros` is not stable enough for use and is subject to change" +)] +#[doc(no_inline)] +pub use crate::trace_macros; + // Do not `doc(no_inline)` so that they become doc items on their own // (no public module for them to be re-exported from). #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs index 5f7097c26e22..78eb79ac666a 100644 --- a/library/std/src/prelude/mod.rs +++ b/library/std/src/prelude/mod.rs @@ -54,9 +54,9 @@ //! * [std::convert]::{[AsRef], [AsMut], [Into], [From]}, generic //! conversions, used by savvy API authors to create overloaded methods. //! * [std::default]::[Default], types that have default values. -//! * [std::iter]::{[Iterator], [Extend], [IntoIterator], [DoubleEndedIterator], [ExactSizeIterator]}, -//! iterators of various -//! kinds. +//! * [std::iter]::{[Iterator], [Extend], [IntoIterator], [DoubleEndedIterator], +//! [ExactSizeIterator]}, iterators of various kinds. +//! * Most of the standard macros. //! * [std::option]::[Option]::{[self][Option], [Some], [None]}, a //! type which expresses the presence or absence of a value. This type is so //! commonly used, its variants are also exported. @@ -145,6 +145,11 @@ pub mod rust_2021 { #[stable(feature = "prelude_2021", since = "1.55.0")] #[doc(no_inline)] pub use core::prelude::rust_2021::*; + + // There are two different panic macros, one in `core` and one in `std`. They are slightly + // different. For `std` we explicitly want the one defined in `std`. + #[stable(feature = "prelude_2021", since = "1.55.0")] + pub use super::v1::panic; } /// The 2024 version of the prelude of The Rust Standard Library. @@ -159,6 +164,11 @@ pub mod rust_2024 { #[stable(feature = "prelude_2024", since = "1.85.0")] #[doc(no_inline)] pub use core::prelude::rust_2024::*; + + // There are two different panic macros, one in `core` and one in `std`. They are slightly + // different. For `std` we explicitly want the one defined in `std`. + #[stable(feature = "prelude_2024", since = "1.85.0")] + pub use super::v1::panic; } /// The Future version of the prelude of The Rust Standard Library. @@ -174,4 +184,9 @@ pub mod rust_future { #[unstable(feature = "prelude_next", issue = "none")] #[doc(no_inline)] pub use core::prelude::rust_future::*; + + // There are two different panic macros, one in `core` and one in `std`. They are slightly + // different. For `std` we explicitly want the one defined in `std`. + #[unstable(feature = "prelude_next", issue = "none")] + pub use super::v1::panic; } diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 0f0841379b29..af9d28ebad35 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -43,15 +43,46 @@ pub use crate::option::Option::{self, None, Some}; #[doc(no_inline)] pub use crate::result::Result::{self, Err, Ok}; -// Re-exported built-in macros +// Re-exported built-in macros and traits #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[doc(no_inline)] +#[expect(deprecated)] pub use core::prelude::v1::{ - assert, cfg, column, compile_error, concat, env, file, format_args, - format_args_nl, include, include_bytes, include_str, line, log_syntax, module_path, option_env, - stringify, trace_macros, Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, + assert, assert_eq, assert_ne, cfg, column, compile_error, concat, debug_assert, debug_assert_eq, + debug_assert_ne, env, file, format_args, include, include_bytes, include_str, line, matches, + module_path, option_env, stringify, todo, r#try, unimplemented, unreachable, write, + writeln, Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, }; +#[stable(feature = "builtin_macro_prelude", since = "1.38.0")] +#[doc(no_inline)] +pub use crate::{ + dbg, eprint, eprintln, format, is_x86_feature_detected, print, println, thread_local +}; + +// These macros need special handling, so that we don't export them *and* the modules of the same +// name. We only want the macros in the prelude so we shadow the original modules with private +// modules with the same names. +mod ambiguous_macros_only { + #[expect(hidden_glob_reexports)] + mod vec {} + #[expect(hidden_glob_reexports)] + mod panic {} + // Building std without the expect exported_private_dependencies will create warnings, but then + // clippy claims its a useless_attribute. So silence both. + #[expect(clippy::useless_attribute)] + #[expect(exported_private_dependencies)] + #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] + pub use crate::*; +} +#[stable(feature = "builtin_macro_prelude", since = "1.38.0")] +#[doc(no_inline)] +pub use self::ambiguous_macros_only::{vec, panic}; + +#[unstable(feature = "cfg_select", issue = "115585")] +#[doc(no_inline)] +pub use core::prelude::v1::cfg_select; + #[unstable( feature = "concat_bytes", issue = "87555", @@ -60,6 +91,26 @@ pub use core::prelude::v1::{ #[doc(no_inline)] pub use core::prelude::v1::concat_bytes; +#[unstable(feature = "const_format_args", issue = "none")] +#[doc(no_inline)] +pub use core::prelude::v1::const_format_args; + +#[unstable( + feature = "log_syntax", + issue = "29598", + reason = "`log_syntax!` is not stable enough for use and is subject to change" +)] +#[doc(no_inline)] +pub use core::prelude::v1::log_syntax; + +#[unstable( + feature = "trace_macros", + issue = "29598", + reason = "`trace_macros` is not stable enough for use and is subject to change" +)] +#[doc(no_inline)] +pub use core::prelude::v1::trace_macros; + // Do not `doc(no_inline)` so that they become doc items on their own // (no public module for them to be re-exported from). #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 720ba0ad73e2..6838bb422b0e 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -167,7 +167,7 @@ use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::num::NonZero; use crate::path::Path; use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner, process as imp}; -use crate::{fmt, fs, str}; +use crate::{fmt, format_args_nl, fs, str}; /// Representation of a running or exited child process. /// diff --git a/tests/pretty/asm.pp b/tests/pretty/asm.pp index dca28f99a37d..f1f020a68fb6 100644 --- a/tests/pretty/asm.pp +++ b/tests/pretty/asm.pp @@ -1,6 +1,5 @@ #![feature(prelude_import)] #![no_std] -#[macro_use] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/autodiff/autodiff_forward.pp b/tests/pretty/autodiff/autodiff_forward.pp index ea4e294f1ac3..c64da3f60884 100644 --- a/tests/pretty/autodiff/autodiff_forward.pp +++ b/tests/pretty/autodiff/autodiff_forward.pp @@ -3,7 +3,6 @@ //@ only-nightly #![feature(autodiff)] -#[macro_use] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/autodiff/autodiff_reverse.pp b/tests/pretty/autodiff/autodiff_reverse.pp index 9202e0a76635..61ab121b31bc 100644 --- a/tests/pretty/autodiff/autodiff_reverse.pp +++ b/tests/pretty/autodiff/autodiff_reverse.pp @@ -3,7 +3,6 @@ //@ only-nightly #![feature(autodiff)] -#[macro_use] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/autodiff/inherent_impl.pp b/tests/pretty/autodiff/inherent_impl.pp index bc70c4076121..1c83c66c8edf 100644 --- a/tests/pretty/autodiff/inherent_impl.pp +++ b/tests/pretty/autodiff/inherent_impl.pp @@ -3,7 +3,6 @@ //@ only-nightly #![feature(autodiff)] -#[macro_use] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/cast-lt.pp b/tests/pretty/cast-lt.pp index e82636edca7e..deca38fc0962 100644 --- a/tests/pretty/cast-lt.pp +++ b/tests/pretty/cast-lt.pp @@ -1,6 +1,5 @@ #![feature(prelude_import)] #![no_std] -#[macro_use] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/delegation-impl-reuse.pp b/tests/pretty/delegation-impl-reuse.pp index 72f62de0eacb..6c6c8a594fc8 100644 --- a/tests/pretty/delegation-impl-reuse.pp +++ b/tests/pretty/delegation-impl-reuse.pp @@ -6,7 +6,6 @@ #![allow(incomplete_features)] #![feature(fn_delegation)] -#[macro_use] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/delegation-inherit-attributes.pp b/tests/pretty/delegation-inherit-attributes.pp index 8e30da1ad589..2398cae90fdb 100644 --- a/tests/pretty/delegation-inherit-attributes.pp +++ b/tests/pretty/delegation-inherit-attributes.pp @@ -6,7 +6,6 @@ #![allow(incomplete_features)] #![feature(fn_delegation)] -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use std::prelude::rust_2021::*; diff --git a/tests/pretty/delegation-inline-attribute.pp b/tests/pretty/delegation-inline-attribute.pp index 826d099e8155..5235fd8d0ef2 100644 --- a/tests/pretty/delegation-inline-attribute.pp +++ b/tests/pretty/delegation-inline-attribute.pp @@ -4,7 +4,6 @@ #![allow(incomplete_features)] #![feature(fn_delegation)] -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/dollar-crate.pp b/tests/pretty/dollar-crate.pp index 31a55ec2bdaa..f7f6e5c3d493 100644 --- a/tests/pretty/dollar-crate.pp +++ b/tests/pretty/dollar-crate.pp @@ -1,6 +1,5 @@ #![feature(prelude_import)] #![no_std] -#[macro_use] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/expanded-and-path-remap-80832.pp b/tests/pretty/expanded-and-path-remap-80832.pp index 6206498e4a2b..d434633b7c4b 100644 --- a/tests/pretty/expanded-and-path-remap-80832.pp +++ b/tests/pretty/expanded-and-path-remap-80832.pp @@ -1,6 +1,5 @@ #![feature(prelude_import)] #![no_std] -#[macro_use] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/format-args-str-escape.pp b/tests/pretty/format-args-str-escape.pp index d0bd7cf0c72a..bf944f445e1c 100644 --- a/tests/pretty/format-args-str-escape.pp +++ b/tests/pretty/format-args-str-escape.pp @@ -1,6 +1,5 @@ #![feature(prelude_import)] #![no_std] -#[macro_use] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/hir-delegation.pp b/tests/pretty/hir-delegation.pp index b5f7a14eb2fc..44a1deb750dc 100644 --- a/tests/pretty/hir-delegation.pp +++ b/tests/pretty/hir-delegation.pp @@ -4,7 +4,6 @@ #![allow(incomplete_features)] #![feature(fn_delegation)] -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/hir-fn-params.pp b/tests/pretty/hir-fn-params.pp index fb4ea0304e5a..52310d5024cd 100644 --- a/tests/pretty/hir-fn-params.pp +++ b/tests/pretty/hir-fn-params.pp @@ -1,4 +1,3 @@ -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/hir-fn-variadic.pp b/tests/pretty/hir-fn-variadic.pp index 8cbd8f41b646..6356eec80e0e 100644 --- a/tests/pretty/hir-fn-variadic.pp +++ b/tests/pretty/hir-fn-variadic.pp @@ -3,7 +3,6 @@ //@ pp-exact:hir-fn-variadic.pp #![feature(c_variadic)] -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/hir-if-else.pp b/tests/pretty/hir-if-else.pp index af5d31b07cb1..d3721e175815 100644 --- a/tests/pretty/hir-if-else.pp +++ b/tests/pretty/hir-if-else.pp @@ -1,4 +1,3 @@ -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/hir-lifetimes.pp b/tests/pretty/hir-lifetimes.pp index e8b174189130..ceb0f6e3b7c2 100644 --- a/tests/pretty/hir-lifetimes.pp +++ b/tests/pretty/hir-lifetimes.pp @@ -5,7 +5,6 @@ // This tests the pretty-printing of lifetimes in lots of ways. #![allow(unused)] -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/hir-pretty-attr.pp b/tests/pretty/hir-pretty-attr.pp index 01bfe2c09547..a9d8b5e7e577 100644 --- a/tests/pretty/hir-pretty-attr.pp +++ b/tests/pretty/hir-pretty-attr.pp @@ -1,4 +1,3 @@ -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/hir-pretty-loop.pp b/tests/pretty/hir-pretty-loop.pp index a0830c5188ad..e6614ce318cc 100644 --- a/tests/pretty/hir-pretty-loop.pp +++ b/tests/pretty/hir-pretty-loop.pp @@ -1,4 +1,3 @@ -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/hir-struct-expr.pp b/tests/pretty/hir-struct-expr.pp index bb222dc2e5f1..198d7ad6a9b6 100644 --- a/tests/pretty/hir-struct-expr.pp +++ b/tests/pretty/hir-struct-expr.pp @@ -1,4 +1,3 @@ -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/if-else.pp b/tests/pretty/if-else.pp index f29b693e571e..6ca71a3a3d34 100644 --- a/tests/pretty/if-else.pp +++ b/tests/pretty/if-else.pp @@ -1,6 +1,5 @@ #![feature(prelude_import)] #![no_std] -#[macro_use] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/issue-12590-c.pp b/tests/pretty/issue-12590-c.pp index 0df095b0ee55..b79b73337adb 100644 --- a/tests/pretty/issue-12590-c.pp +++ b/tests/pretty/issue-12590-c.pp @@ -1,6 +1,5 @@ #![feature(prelude_import)] #![no_std] -#[macro_use] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/issue-4264.pp b/tests/pretty/issue-4264.pp index 4eee6655cf6f..568269644bb8 100644 --- a/tests/pretty/issue-4264.pp +++ b/tests/pretty/issue-4264.pp @@ -1,4 +1,3 @@ -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/issue-85089.pp b/tests/pretty/issue-85089.pp index 28a85bdf4ad8..919573220fdd 100644 --- a/tests/pretty/issue-85089.pp +++ b/tests/pretty/issue-85089.pp @@ -1,4 +1,3 @@ -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/never-pattern.pp b/tests/pretty/never-pattern.pp index 1ce332ea5064..bb95a1ed442a 100644 --- a/tests/pretty/never-pattern.pp +++ b/tests/pretty/never-pattern.pp @@ -7,7 +7,6 @@ #![allow(incomplete_features)] #![feature(never_patterns)] #![feature(never_type)] -#[macro_use] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/pin-ergonomics-hir.pp b/tests/pretty/pin-ergonomics-hir.pp index 127cb531cece..cf9b6707ed2f 100644 --- a/tests/pretty/pin-ergonomics-hir.pp +++ b/tests/pretty/pin-ergonomics-hir.pp @@ -4,7 +4,6 @@ #![feature(pin_ergonomics)] #![allow(dead_code, incomplete_features)] -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/postfix-match/precedence.pp b/tests/pretty/postfix-match/precedence.pp index b6ff45daea12..56ee1f1061af 100644 --- a/tests/pretty/postfix-match/precedence.pp +++ b/tests/pretty/postfix-match/precedence.pp @@ -1,7 +1,6 @@ #![feature(prelude_import)] #![no_std] #![feature(postfix_match)] -#[macro_use] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/shebang-at-top.pp b/tests/pretty/shebang-at-top.pp index 197def4a154b..0c19c0c44e45 100644 --- a/tests/pretty/shebang-at-top.pp +++ b/tests/pretty/shebang-at-top.pp @@ -1,7 +1,6 @@ #!/usr/bin/env rust #![feature(prelude_import)] #![no_std] -#[macro_use] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/tests-are-sorted.pp b/tests/pretty/tests-are-sorted.pp index 9e1566b2eff3..43f9838e68ce 100644 --- a/tests/pretty/tests-are-sorted.pp +++ b/tests/pretty/tests-are-sorted.pp @@ -1,6 +1,5 @@ #![feature(prelude_import)] #![no_std] -#[macro_use] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/rustdoc-js-std/println-typo.js b/tests/rustdoc-js-std/println-typo.js index a4dd90a44d5b..b91e7883b995 100644 --- a/tests/rustdoc-js-std/println-typo.js +++ b/tests/rustdoc-js-std/println-typo.js @@ -6,7 +6,10 @@ const EXPECTED = { 'query': 'prinltn', 'others': [ { 'path': 'std', 'name': 'println' }, + { 'path': 'std::prelude::v1', 'name': 'println' }, { 'path': 'std', 'name': 'print' }, + { 'path': 'std::prelude::v1', 'name': 'print' }, { 'path': 'std', 'name': 'eprintln' }, + { 'path': 'std::prelude::v1', 'name': 'eprintln' }, ], }; diff --git a/tests/ui/asm/unpretty-expanded.stdout b/tests/ui/asm/unpretty-expanded.stdout index 7678f6bc3450..ce636c150c1c 100644 --- a/tests/ui/asm/unpretty-expanded.stdout +++ b/tests/ui/asm/unpretty-expanded.stdout @@ -1,6 +1,5 @@ #![feature(prelude_import)] #![no_std] -#[macro_use] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/ui/associated-type-bounds/return-type-notation/unpretty-parenthesized.stdout b/tests/ui/associated-type-bounds/return-type-notation/unpretty-parenthesized.stdout index 7499df5be5da..c53491a6747c 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/unpretty-parenthesized.stdout +++ b/tests/ui/associated-type-bounds/return-type-notation/unpretty-parenthesized.stdout @@ -1,5 +1,4 @@ #![feature(prelude_import)] -#[macro_use] extern crate std; #[prelude_import] use std::prelude::rust_2021::*; diff --git a/tests/ui/codemap_tests/unicode.expanded.stdout b/tests/ui/codemap_tests/unicode.expanded.stdout index af375108b478..4a29277fe3bf 100644 --- a/tests/ui/codemap_tests/unicode.expanded.stdout +++ b/tests/ui/codemap_tests/unicode.expanded.stdout @@ -1,6 +1,5 @@ #![feature(prelude_import)] #![no_std] -#[macro_use] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/ui/const-generics/defaults/pretty-printing-ast.stdout b/tests/ui/const-generics/defaults/pretty-printing-ast.stdout index 030fcec9cf2a..efd703b24b43 100644 --- a/tests/ui/const-generics/defaults/pretty-printing-ast.stdout +++ b/tests/ui/const-generics/defaults/pretty-printing-ast.stdout @@ -6,7 +6,6 @@ //@ edition: 2015 #![crate_type = "lib"] -#[macro_use] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/ui/deriving/built-in-proc-macro-scope.stdout b/tests/ui/deriving/built-in-proc-macro-scope.stdout index 4fbce5edb819..e2a9119af3d6 100644 --- a/tests/ui/deriving/built-in-proc-macro-scope.stdout +++ b/tests/ui/deriving/built-in-proc-macro-scope.stdout @@ -6,7 +6,6 @@ //@ edition:2015 #![feature(derive_coerce_pointee)] -#[macro_use] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout index a40dece22a26..b778eab60596 100644 --- a/tests/ui/deriving/deriving-all-codegen.stdout +++ b/tests/ui/deriving/deriving-all-codegen.stdout @@ -18,7 +18,6 @@ #![allow(dead_code)] #![allow(deprecated)] #![feature(derive_from)] -#[macro_use] extern crate std; #[prelude_import] use std::prelude::rust_2021::*; diff --git a/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout b/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout index 89300a5c6d0c..ace45c4d760f 100644 --- a/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout +++ b/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout @@ -4,7 +4,6 @@ //@ compile-flags: -Zunpretty=expanded //@ edition: 2015 #![feature(derive_coerce_pointee)] -#[macro_use] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/ui/deriving/proc-macro-attribute-mixing.stdout b/tests/ui/deriving/proc-macro-attribute-mixing.stdout index b81110682d68..e82f1780d095 100644 --- a/tests/ui/deriving/proc-macro-attribute-mixing.stdout +++ b/tests/ui/deriving/proc-macro-attribute-mixing.stdout @@ -12,7 +12,6 @@ //@ edition: 2015 #![feature(derive_coerce_pointee)] -#[macro_use] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/ui/feature-gates/feature-gate-format_args_nl.rs b/tests/ui/feature-gates/feature-gate-format_args_nl.rs index aeee2fbad907..4749eea13a6d 100644 --- a/tests/ui/feature-gates/feature-gate-format_args_nl.rs +++ b/tests/ui/feature-gates/feature-gate-format_args_nl.rs @@ -1,3 +1,5 @@ +use std::format_args_nl; //~ ERROR `format_args_nl` is only for internal language use + fn main() { format_args_nl!(""); //~ ERROR `format_args_nl` is only for internal language use } diff --git a/tests/ui/feature-gates/feature-gate-format_args_nl.stderr b/tests/ui/feature-gates/feature-gate-format_args_nl.stderr index c7e8f8c686f9..1265bd447f40 100644 --- a/tests/ui/feature-gates/feature-gate-format_args_nl.stderr +++ b/tests/ui/feature-gates/feature-gate-format_args_nl.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature `format_args_nl`: `format_args_nl` is only for internal language use and is subject to change - --> $DIR/feature-gate-format_args_nl.rs:2:5 + --> $DIR/feature-gate-format_args_nl.rs:4:5 | LL | format_args_nl!(""); | ^^^^^^^^^^^^^^ @@ -7,6 +7,15 @@ LL | format_args_nl!(""); = help: add `#![feature(format_args_nl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 1 previous error +error[E0658]: use of unstable library feature `format_args_nl`: `format_args_nl` is only for internal language use and is subject to change + --> $DIR/feature-gate-format_args_nl.rs:1:5 + | +LL | use std::format_args_nl; + | ^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(format_args_nl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/hygiene/format-args.rs b/tests/ui/hygiene/format-args.rs index ff08aecfd9eb..f845f5d8a4c8 100644 --- a/tests/ui/hygiene/format-args.rs +++ b/tests/ui/hygiene/format-args.rs @@ -3,6 +3,8 @@ #![allow(non_upper_case_globals)] #![feature(format_args_nl)] +use std::format_args_nl; + static arg0: () = (); fn main() { diff --git a/tests/ui/imports/ambiguous-panic-glob-vs-multiouter.rs b/tests/ui/imports/ambiguous-panic-glob-vs-multiouter.rs new file mode 100644 index 000000000000..6d37fbb7fdea --- /dev/null +++ b/tests/ui/imports/ambiguous-panic-glob-vs-multiouter.rs @@ -0,0 +1,16 @@ +//@ edition: 2024 +#![crate_type = "lib"] +mod m1 { + pub use core::prelude::v1::*; +} + +mod m2 { + pub use std::prelude::v1::*; +} + +use m2::*; +fn foo() { + use m1::*; + + panic!(); //~ ERROR: `panic` is ambiguous [E0659] +} diff --git a/tests/ui/imports/ambiguous-panic-glob-vs-multiouter.stderr b/tests/ui/imports/ambiguous-panic-glob-vs-multiouter.stderr new file mode 100644 index 000000000000..450a18478092 --- /dev/null +++ b/tests/ui/imports/ambiguous-panic-glob-vs-multiouter.stderr @@ -0,0 +1,23 @@ +error[E0659]: `panic` is ambiguous + --> $DIR/ambiguous-panic-glob-vs-multiouter.rs:15:5 + | +LL | panic!(); + | ^^^^^ ambiguous name + | + = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution +note: `panic` could refer to the macro imported here + --> $DIR/ambiguous-panic-glob-vs-multiouter.rs:13:9 + | +LL | use m1::*; + | ^^^^^ + = help: consider adding an explicit import of `panic` to disambiguate +note: `panic` could also refer to the macro imported here + --> $DIR/ambiguous-panic-glob-vs-multiouter.rs:11:5 + | +LL | use m2::*; + | ^^^^^ + = help: use `crate::panic` to refer to this macro unambiguously + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/imports/ambiguous-panic-globvsglob.rs b/tests/ui/imports/ambiguous-panic-globvsglob.rs new file mode 100644 index 000000000000..4ff3cc822535 --- /dev/null +++ b/tests/ui/imports/ambiguous-panic-globvsglob.rs @@ -0,0 +1,23 @@ +//@ edition: 2024 +#![crate_type = "lib"] +mod m1 { + pub use core::prelude::v1::*; +} + +mod m2 { + pub use std::prelude::v1::*; +} + +fn foo() { + use m1::*; + use m2::*; + + // I had hoped that this would not produce the globvsglob error because it would never be + // resolving `panic` via one of the ambiguous glob imports above but it appears to do so, not + // sure why + panic!(); + //~^ WARN: `panic` is ambiguous [ambiguous_panic_imports] + //~| WARN: this was previously accepted by the compiler + //~| ERROR: `panic` is ambiguous [ambiguous_glob_imports] + //~| WARN: this was previously accepted by the compiler +} diff --git a/tests/ui/imports/ambiguous-panic-globvsglob.stderr b/tests/ui/imports/ambiguous-panic-globvsglob.stderr new file mode 100644 index 000000000000..455c58bb6c02 --- /dev/null +++ b/tests/ui/imports/ambiguous-panic-globvsglob.stderr @@ -0,0 +1,68 @@ +error: `panic` is ambiguous + --> $DIR/ambiguous-panic-globvsglob.rs:18:5 + | +LL | panic!(); + | ^^^^^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `panic` could refer to the macro imported here + --> $DIR/ambiguous-panic-globvsglob.rs:12:9 + | +LL | use m1::*; + | ^^^^^ + = help: consider adding an explicit import of `panic` to disambiguate +note: `panic` could also refer to the macro imported here + --> $DIR/ambiguous-panic-globvsglob.rs:13:9 + | +LL | use m2::*; + | ^^^^^ + = help: consider adding an explicit import of `panic` to disambiguate + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + +warning: `panic` is ambiguous + --> $DIR/ambiguous-panic-globvsglob.rs:18:5 + | +LL | panic!(); + | ^^^^^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #147319 + = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution +note: `panic` could refer to the macro imported here + --> $DIR/ambiguous-panic-globvsglob.rs:12:9 + | +LL | use m1::*; + | ^^^^^ + = help: consider adding an explicit import of `panic` to disambiguate +note: `panic` could also refer to a macro from prelude + --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL + = note: `#[warn(ambiguous_panic_imports)]` (part of `#[warn(future_incompatible)]`) on by default + +error: aborting due to 1 previous error; 1 warning emitted + +Future incompatibility report: Future breakage diagnostic: +error: `panic` is ambiguous + --> $DIR/ambiguous-panic-globvsglob.rs:18:5 + | +LL | panic!(); + | ^^^^^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `panic` could refer to the macro imported here + --> $DIR/ambiguous-panic-globvsglob.rs:12:9 + | +LL | use m1::*; + | ^^^^^ + = help: consider adding an explicit import of `panic` to disambiguate +note: `panic` could also refer to the macro imported here + --> $DIR/ambiguous-panic-globvsglob.rs:13:9 + | +LL | use m2::*; + | ^^^^^ + = help: consider adding an explicit import of `panic` to disambiguate + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + diff --git a/tests/ui/imports/ambiguous-panic-no-implicit-prelude.rs b/tests/ui/imports/ambiguous-panic-no-implicit-prelude.rs new file mode 100644 index 000000000000..1239cc67cd39 --- /dev/null +++ b/tests/ui/imports/ambiguous-panic-no-implicit-prelude.rs @@ -0,0 +1,16 @@ +//@ edition: 2024 +#![crate_type = "lib"] +#![no_implicit_prelude] + +mod m1 { + macro_rules! panic { + () => {}; + } + + pub(crate) use panic; +} + +fn foo() { + use m1::*; + panic!(); //~ERROR: `panic` is ambiguous [E0659] +} diff --git a/tests/ui/imports/ambiguous-panic-no-implicit-prelude.stderr b/tests/ui/imports/ambiguous-panic-no-implicit-prelude.stderr new file mode 100644 index 000000000000..fa41409acb2c --- /dev/null +++ b/tests/ui/imports/ambiguous-panic-no-implicit-prelude.stderr @@ -0,0 +1,19 @@ +error[E0659]: `panic` is ambiguous + --> $DIR/ambiguous-panic-no-implicit-prelude.rs:15:5 + | +LL | panic!(); + | ^^^^^ ambiguous name + | + = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution +note: `panic` could refer to the macro imported here + --> $DIR/ambiguous-panic-no-implicit-prelude.rs:14:9 + | +LL | use m1::*; + | ^^^^^ + = help: consider adding an explicit import of `panic` to disambiguate +note: `panic` could also refer to a macro from prelude + --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/imports/ambiguous-panic-non-prelude-core-glob.rs b/tests/ui/imports/ambiguous-panic-non-prelude-core-glob.rs new file mode 100644 index 000000000000..e8b6e208c08b --- /dev/null +++ b/tests/ui/imports/ambiguous-panic-non-prelude-core-glob.rs @@ -0,0 +1,11 @@ +//@ edition: 2024 +//@ check-pass +#![crate_type = "lib"] + +use ::core::*; + +fn f() { + panic!(); + //~^ WARN: `panic` is ambiguous [ambiguous_panic_imports] + //~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +} diff --git a/tests/ui/imports/ambiguous-panic-non-prelude-core-glob.stderr b/tests/ui/imports/ambiguous-panic-non-prelude-core-glob.stderr new file mode 100644 index 000000000000..5317d8d6d312 --- /dev/null +++ b/tests/ui/imports/ambiguous-panic-non-prelude-core-glob.stderr @@ -0,0 +1,22 @@ +warning: `panic` is ambiguous + --> $DIR/ambiguous-panic-non-prelude-core-glob.rs:8:5 + | +LL | panic!(); + | ^^^^^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #147319 + = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution +note: `panic` could refer to the macro imported here + --> $DIR/ambiguous-panic-non-prelude-core-glob.rs:5:5 + | +LL | use ::core::*; + | ^^^^^^^^^ + = help: consider adding an explicit import of `panic` to disambiguate + = help: or use `crate::panic` to refer to this macro unambiguously +note: `panic` could also refer to a macro from prelude + --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL + = note: `#[warn(ambiguous_panic_imports)]` (part of `#[warn(future_incompatible)]`) on by default + +warning: 1 warning emitted + diff --git a/tests/ui/imports/ambiguous-panic-non-prelude-std-glob.rs b/tests/ui/imports/ambiguous-panic-non-prelude-std-glob.rs new file mode 100644 index 000000000000..0e63f97ec98a --- /dev/null +++ b/tests/ui/imports/ambiguous-panic-non-prelude-std-glob.rs @@ -0,0 +1,12 @@ +//@ check-pass +#![crate_type = "lib"] +#![no_std] + +extern crate std; +use ::std::*; + +fn f() { + panic!(); + //~^ WARN: `panic` is ambiguous [ambiguous_panic_imports] + //~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +} diff --git a/tests/ui/imports/ambiguous-panic-non-prelude-std-glob.stderr b/tests/ui/imports/ambiguous-panic-non-prelude-std-glob.stderr new file mode 100644 index 000000000000..b7434e3737b8 --- /dev/null +++ b/tests/ui/imports/ambiguous-panic-non-prelude-std-glob.stderr @@ -0,0 +1,22 @@ +warning: `panic` is ambiguous + --> $DIR/ambiguous-panic-non-prelude-std-glob.rs:9:5 + | +LL | panic!(); + | ^^^^^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #147319 + = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution +note: `panic` could refer to the macro imported here + --> $DIR/ambiguous-panic-non-prelude-std-glob.rs:6:5 + | +LL | use ::std::*; + | ^^^^^^^^ + = help: consider adding an explicit import of `panic` to disambiguate + = help: or use `crate::panic` to refer to this macro unambiguously +note: `panic` could also refer to a macro from prelude + --> $SRC_DIR/core/src/prelude/mod.rs:LL:COL + = note: `#[warn(ambiguous_panic_imports)]` (part of `#[warn(future_incompatible)]`) on by default + +warning: 1 warning emitted + diff --git a/tests/ui/imports/ambiguous-panic-pick-core.rs b/tests/ui/imports/ambiguous-panic-pick-core.rs new file mode 100644 index 000000000000..bcb8494b10d7 --- /dev/null +++ b/tests/ui/imports/ambiguous-panic-pick-core.rs @@ -0,0 +1,11 @@ +//@ edition: 2018 +//@ check-pass +#![crate_type = "lib"] +use ::core::prelude::v1::*; + +fn f() { + panic!(&std::string::String::new()); + //~^ WARN: `panic` is ambiguous [ambiguous_panic_imports] + //~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| WARN: panic message is not a string literal [non_fmt_panics] +} diff --git a/tests/ui/imports/ambiguous-panic-pick-core.stderr b/tests/ui/imports/ambiguous-panic-pick-core.stderr new file mode 100644 index 000000000000..5729311fabd0 --- /dev/null +++ b/tests/ui/imports/ambiguous-panic-pick-core.stderr @@ -0,0 +1,37 @@ +warning: `panic` is ambiguous + --> $DIR/ambiguous-panic-pick-core.rs:7:5 + | +LL | panic!(&std::string::String::new()); + | ^^^^^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #147319 + = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution +note: `panic` could refer to the macro imported here + --> $DIR/ambiguous-panic-pick-core.rs:4:5 + | +LL | use ::core::prelude::v1::*; + | ^^^^^^^^^^^^^^^^^^^^^^ + = help: consider adding an explicit import of `panic` to disambiguate + = help: or use `crate::panic` to refer to this macro unambiguously +note: `panic` could also refer to a macro from prelude + --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL + = note: `#[warn(ambiguous_panic_imports)]` (part of `#[warn(future_incompatible)]`) on by default + +warning: panic message is not a string literal + --> $DIR/ambiguous-panic-pick-core.rs:7:12 + | +LL | panic!(&std::string::String::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 + = note: for more information, see + = note: `#[warn(non_fmt_panics)]` (part of `#[warn(rust_2021_compatibility)]`) on by default +help: add a "{}" format string to `Display` the message + | +LL | panic!("{}", &std::string::String::new()); + | +++++ + +warning: 2 warnings emitted + diff --git a/tests/ui/imports/ambiguous-panic-pick-std.rs b/tests/ui/imports/ambiguous-panic-pick-std.rs new file mode 100644 index 000000000000..67b285ee430a --- /dev/null +++ b/tests/ui/imports/ambiguous-panic-pick-std.rs @@ -0,0 +1,14 @@ +//@ edition: 2018 +//@ check-pass +#![crate_type = "lib"] +#![no_std] + +extern crate std; +use ::std::prelude::v1::*; + +fn f() { + panic!(std::string::String::new()); + //~^ WARN: `panic` is ambiguous [ambiguous_panic_imports] + //~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| WARN: panic message is not a string literal [non_fmt_panics] +} diff --git a/tests/ui/imports/ambiguous-panic-pick-std.stderr b/tests/ui/imports/ambiguous-panic-pick-std.stderr new file mode 100644 index 000000000000..1b5b508a7965 --- /dev/null +++ b/tests/ui/imports/ambiguous-panic-pick-std.stderr @@ -0,0 +1,37 @@ +warning: `panic` is ambiguous + --> $DIR/ambiguous-panic-pick-std.rs:10:5 + | +LL | panic!(std::string::String::new()); + | ^^^^^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #147319 + = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution +note: `panic` could refer to the macro imported here + --> $DIR/ambiguous-panic-pick-std.rs:7:5 + | +LL | use ::std::prelude::v1::*; + | ^^^^^^^^^^^^^^^^^^^^^ + = help: consider adding an explicit import of `panic` to disambiguate + = help: or use `crate::panic` to refer to this macro unambiguously +note: `panic` could also refer to a macro from prelude + --> $SRC_DIR/core/src/prelude/mod.rs:LL:COL + = note: `#[warn(ambiguous_panic_imports)]` (part of `#[warn(future_incompatible)]`) on by default + +warning: panic message is not a string literal + --> $DIR/ambiguous-panic-pick-std.rs:10:12 + | +LL | panic!(std::string::String::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 + = note: for more information, see + = note: `#[warn(non_fmt_panics)]` (part of `#[warn(rust_2021_compatibility)]`) on by default +help: add a "{}" format string to `Display` the message + | +LL | panic!("{}", std::string::String::new()); + | +++++ + +warning: 2 warnings emitted + diff --git a/tests/ui/imports/ambiguous-panic-re-emit.rs b/tests/ui/imports/ambiguous-panic-re-emit.rs new file mode 100644 index 000000000000..dd3c0211b3a7 --- /dev/null +++ b/tests/ui/imports/ambiguous-panic-re-emit.rs @@ -0,0 +1,23 @@ +#![crate_type = "lib"] +#![no_std] + +macro_rules! re_emit { + ($($i:item)*) => ($($i)*) +} + +// By re-emitting the prelude import via a macro, we run into the delayed bugs code path. +re_emit! { + extern crate std; + use std::prelude::v1::*; +} + +fn xx() { + panic!(); + //~^ WARNING `panic` is ambiguous + //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + + // We can't deny the above lint, or else it *won't* run into the problematic issue of *not* + // having reported an error. So we crate a dummy error. + let _ = unknown_item; + //~^ ERROR: cannot find value `unknown_item` +} diff --git a/tests/ui/imports/ambiguous-panic-re-emit.stderr b/tests/ui/imports/ambiguous-panic-re-emit.stderr new file mode 100644 index 000000000000..ca30c54b84fe --- /dev/null +++ b/tests/ui/imports/ambiguous-panic-re-emit.stderr @@ -0,0 +1,29 @@ +error[E0425]: cannot find value `unknown_item` in this scope + --> $DIR/ambiguous-panic-re-emit.rs:21:13 + | +LL | let _ = unknown_item; + | ^^^^^^^^^^^^ not found in this scope + +warning: `panic` is ambiguous + --> $DIR/ambiguous-panic-re-emit.rs:15:5 + | +LL | panic!(); + | ^^^^^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #147319 + = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution +note: `panic` could refer to the macro imported here + --> $DIR/ambiguous-panic-re-emit.rs:11:9 + | +LL | use std::prelude::v1::*; + | ^^^^^^^^^^^^^^^^^^^ + = help: consider adding an explicit import of `panic` to disambiguate + = help: or use `crate::panic` to refer to this macro unambiguously +note: `panic` could also refer to a macro from prelude + --> $SRC_DIR/core/src/prelude/mod.rs:LL:COL + = note: `#[warn(ambiguous_panic_imports)]` (part of `#[warn(future_incompatible)]`) on by default + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/imports/ambiguous-panic-rename-builtin.rs b/tests/ui/imports/ambiguous-panic-rename-builtin.rs new file mode 100644 index 000000000000..63dfa540c2a2 --- /dev/null +++ b/tests/ui/imports/ambiguous-panic-rename-builtin.rs @@ -0,0 +1,15 @@ +//@ edition: 2024 +#![crate_type = "lib"] +#![no_std] + +extern crate std; +mod m1 { + pub use std::prelude::v1::env as panic; +} +use m1::*; + +fn xx() { + panic!(); + //~^ ERROR: `env!()` takes 1 or 2 arguments + //~| ERROR: `panic` is ambiguous [E0659] +} diff --git a/tests/ui/imports/ambiguous-panic-rename-builtin.stderr b/tests/ui/imports/ambiguous-panic-rename-builtin.stderr new file mode 100644 index 000000000000..146863762eaf --- /dev/null +++ b/tests/ui/imports/ambiguous-panic-rename-builtin.stderr @@ -0,0 +1,26 @@ +error: `env!()` takes 1 or 2 arguments + --> $DIR/ambiguous-panic-rename-builtin.rs:12:5 + | +LL | panic!(); + | ^^^^^^^^ + +error[E0659]: `panic` is ambiguous + --> $DIR/ambiguous-panic-rename-builtin.rs:12:5 + | +LL | panic!(); + | ^^^^^ ambiguous name + | + = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution +note: `panic` could refer to the macro imported here + --> $DIR/ambiguous-panic-rename-builtin.rs:9:5 + | +LL | use m1::*; + | ^^^^^ + = help: consider adding an explicit import of `panic` to disambiguate + = help: or use `crate::panic` to refer to this macro unambiguously +note: `panic` could also refer to a macro from prelude + --> $SRC_DIR/core/src/prelude/mod.rs:LL:COL + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/imports/ambiguous-panic-rename-panics.rs b/tests/ui/imports/ambiguous-panic-rename-panics.rs new file mode 100644 index 000000000000..fbe23a223c93 --- /dev/null +++ b/tests/ui/imports/ambiguous-panic-rename-panics.rs @@ -0,0 +1,17 @@ +//@ edition: 2024 +#![crate_type = "lib"] + +mod m1 { + pub use core::prelude::v1::panic as p; +} + +mod m2 { + pub use std::prelude::v1::panic as p; +} + +use m2::*; +fn xx() { + use m1::*; + + p!(); //~ ERROR: `p` is ambiguous [E0659] +} diff --git a/tests/ui/imports/ambiguous-panic-rename-panics.stderr b/tests/ui/imports/ambiguous-panic-rename-panics.stderr new file mode 100644 index 000000000000..0838b6bdf2c0 --- /dev/null +++ b/tests/ui/imports/ambiguous-panic-rename-panics.stderr @@ -0,0 +1,23 @@ +error[E0659]: `p` is ambiguous + --> $DIR/ambiguous-panic-rename-panics.rs:16:5 + | +LL | p!(); + | ^ ambiguous name + | + = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution +note: `p` could refer to the macro imported here + --> $DIR/ambiguous-panic-rename-panics.rs:14:9 + | +LL | use m1::*; + | ^^^^^ + = help: consider adding an explicit import of `p` to disambiguate +note: `p` could also refer to the macro imported here + --> $DIR/ambiguous-panic-rename-panics.rs:12:5 + | +LL | use m2::*; + | ^^^^^ + = help: use `crate::p` to refer to this macro unambiguously + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/imports/ambiguous-panic.rs b/tests/ui/imports/ambiguous-panic.rs new file mode 100644 index 000000000000..5a32fe22f31b --- /dev/null +++ b/tests/ui/imports/ambiguous-panic.rs @@ -0,0 +1,12 @@ +#![deny(ambiguous_panic_imports)] +#![crate_type = "lib"] +#![no_std] + +extern crate std; +use std::prelude::v1::*; + +fn xx() { + panic!(); + //~^ ERROR `panic` is ambiguous + //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +} diff --git a/tests/ui/imports/ambiguous-panic.stderr b/tests/ui/imports/ambiguous-panic.stderr new file mode 100644 index 000000000000..781424eede48 --- /dev/null +++ b/tests/ui/imports/ambiguous-panic.stderr @@ -0,0 +1,26 @@ +error: `panic` is ambiguous + --> $DIR/ambiguous-panic.rs:9:5 + | +LL | panic!(); + | ^^^^^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #147319 + = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution +note: `panic` could refer to the macro imported here + --> $DIR/ambiguous-panic.rs:6:5 + | +LL | use std::prelude::v1::*; + | ^^^^^^^^^^^^^^^^^^^ + = help: consider adding an explicit import of `panic` to disambiguate + = help: or use `crate::panic` to refer to this macro unambiguously +note: `panic` could also refer to a macro from prelude + --> $SRC_DIR/core/src/prelude/mod.rs:LL:COL +note: the lint level is defined here + --> $DIR/ambiguous-panic.rs:1:9 + | +LL | #![deny(ambiguous_panic_imports)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/imports/glob-shadowing.stderr b/tests/ui/imports/glob-shadowing.stderr index 0ce8d4f54f8d..025147d08f01 100644 --- a/tests/ui/imports/glob-shadowing.stderr +++ b/tests/ui/imports/glob-shadowing.stderr @@ -5,14 +5,15 @@ LL | let x = env!("PATH"); | ^^^ ambiguous name | = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution - = note: `env` could refer to a macro from prelude -note: `env` could also refer to the macro imported here +note: `env` could refer to the macro imported here --> $DIR/glob-shadowing.rs:9:9 | LL | use crate::m::*; | ^^^^^^^^^^^ = help: consider adding an explicit import of `env` to disambiguate = help: or use `self::env` to refer to this macro unambiguously +note: `env` could also refer to a macro from prelude + --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL error[E0659]: `env` is ambiguous --> $DIR/glob-shadowing.rs:19:21 @@ -21,13 +22,14 @@ LL | let x = env!("PATH"); | ^^^ ambiguous name | = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution - = note: `env` could refer to a macro from prelude -note: `env` could also refer to the macro imported here +note: `env` could refer to the macro imported here --> $DIR/glob-shadowing.rs:17:13 | LL | use crate::m::*; | ^^^^^^^^^^^ = help: consider adding an explicit import of `env` to disambiguate +note: `env` could also refer to a macro from prelude + --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL error[E0659]: `fenv` is ambiguous --> $DIR/glob-shadowing.rs:29:21 diff --git a/tests/ui/imports/local-modularized-tricky-fail-1.stderr b/tests/ui/imports/local-modularized-tricky-fail-1.stderr index b5b3be5953f9..0d1a29027845 100644 --- a/tests/ui/imports/local-modularized-tricky-fail-1.stderr +++ b/tests/ui/imports/local-modularized-tricky-fail-1.stderr @@ -31,8 +31,7 @@ LL | panic!(); | ^^^^^ ambiguous name | = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution - = note: `panic` could refer to a macro from prelude -note: `panic` could also refer to the macro defined here +note: `panic` could refer to the macro defined here --> $DIR/local-modularized-tricky-fail-1.rs:12:5 | LL | / macro_rules! panic { @@ -43,6 +42,8 @@ LL | | } LL | define_panic!(); | --------------- in this macro invocation = help: use `crate::panic` to refer to this macro unambiguously +note: `panic` could also refer to a macro from prelude + --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL = note: this error originates in the macro `define_panic` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `include` is ambiguous @@ -52,8 +53,7 @@ LL | include!(); | ^^^^^^^ ambiguous name | = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution - = note: `include` could refer to a macro from prelude -note: `include` could also refer to the macro defined here +note: `include` could refer to the macro defined here --> $DIR/local-modularized-tricky-fail-1.rs:18:5 | LL | / macro_rules! include { @@ -64,6 +64,8 @@ LL | | } LL | define_include!(); | ----------------- in this macro invocation = help: use `crate::include` to refer to this macro unambiguously +note: `include` could also refer to a macro from prelude + --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL = note: this error originates in the macro `define_include` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors diff --git a/tests/ui/imports/shadow_builtin_macros.stderr b/tests/ui/imports/shadow_builtin_macros.stderr index c828b1193d81..7799fb230d43 100644 --- a/tests/ui/imports/shadow_builtin_macros.stderr +++ b/tests/ui/imports/shadow_builtin_macros.stderr @@ -5,14 +5,15 @@ LL | fn f() { panic!(); } | ^^^^^ ambiguous name | = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution - = note: `panic` could refer to a macro from prelude -note: `panic` could also refer to the macro imported here +note: `panic` could refer to the macro imported here --> $DIR/shadow_builtin_macros.rs:14:9 | LL | use crate::foo::*; | ^^^^^^^^^^^^^ = help: consider adding an explicit import of `panic` to disambiguate = help: or use `self::panic` to refer to this macro unambiguously +note: `panic` could also refer to a macro from prelude + --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL error[E0659]: `panic` is ambiguous --> $DIR/shadow_builtin_macros.rs:33:5 @@ -21,8 +22,7 @@ LL | panic!(); | ^^^^^ ambiguous name | = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution - = note: `panic` could refer to a macro from prelude -note: `panic` could also refer to the macro defined here +note: `panic` could refer to the macro defined here --> $DIR/shadow_builtin_macros.rs:30:9 | LL | macro_rules! panic { () => {} } @@ -30,6 +30,8 @@ LL | macro_rules! panic { () => {} } LL | } } LL | m!(); | ---- in this macro invocation +note: `panic` could also refer to a macro from prelude + --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `n` is ambiguous @@ -59,13 +61,14 @@ LL | fn f() { panic!(); } | ^^^^^ ambiguous name | = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution - = note: `panic` could refer to a macro from prelude -note: `panic` could also refer to the macro imported here +note: `panic` could refer to the macro imported here --> $DIR/shadow_builtin_macros.rs:19:26 | LL | ::two_macros::m!(use crate::foo::panic;); | ^^^^^^^^^^^^^^^^^ = help: use `self::panic` to refer to this macro unambiguously +note: `panic` could also refer to a macro from prelude + --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL error: aborting due to 4 previous errors diff --git a/tests/ui/lint/dead-code/with-core-crate.rs b/tests/ui/lint/dead-code/with-core-crate.rs index 0a94b528f333..9ccb6aecb75f 100644 --- a/tests/ui/lint/dead-code/with-core-crate.rs +++ b/tests/ui/lint/dead-code/with-core-crate.rs @@ -1,7 +1,6 @@ #![deny(dead_code)] #![allow(unreachable_code)] -#[macro_use] extern crate core; fn foo() { //~ ERROR function `foo` is never used diff --git a/tests/ui/lint/dead-code/with-core-crate.stderr b/tests/ui/lint/dead-code/with-core-crate.stderr index f466a616580c..9db26c956298 100644 --- a/tests/ui/lint/dead-code/with-core-crate.stderr +++ b/tests/ui/lint/dead-code/with-core-crate.stderr @@ -1,5 +1,5 @@ error: function `foo` is never used - --> $DIR/with-core-crate.rs:7:4 + --> $DIR/with-core-crate.rs:6:4 | LL | fn foo() { | ^^^ diff --git a/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.stdout b/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.stdout index 80abac44ca84..0fcfc936a59b 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.stdout +++ b/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.stdout @@ -1,6 +1,5 @@ #![feature(prelude_import)] #![no_std] -#[macro_use] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout b/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout index ba93384644d5..6e41432ad7df 100644 --- a/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout +++ b/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout @@ -1,4 +1,3 @@ -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout index e29655faabe5..d47f733d40ed 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout @@ -5,7 +5,6 @@ //@ edition: 2015 #![feature(core_intrinsics, generic_assert)] -#[macro_use] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/ui/match/issue-82392.stdout b/tests/ui/match/issue-82392.stdout index d7eef0497392..d44ffbe21671 100644 --- a/tests/ui/match/issue-82392.stdout +++ b/tests/ui/match/issue-82392.stdout @@ -1,4 +1,3 @@ -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/ui/proc-macro/meta-macro-hygiene.stdout b/tests/ui/proc-macro/meta-macro-hygiene.stdout index 452598c372c1..b5db9922b31a 100644 --- a/tests/ui/proc-macro/meta-macro-hygiene.stdout +++ b/tests/ui/proc-macro/meta-macro-hygiene.stdout @@ -16,7 +16,6 @@ Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro // in the stdout #![no_std /* 0#0 */] -#[macro_use /* 0#1 */] extern crate core /* 0#1 */; #[prelude_import /* 0#1 */] use core /* 0#1 */::prelude /* 0#1 */::rust_2018 /* 0#1 */::*; diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout index e10a5199f179..e45abab03b4c 100644 --- a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout +++ b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout @@ -36,7 +36,6 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ #![feature /* 0#0 */(decl_macro)] #![no_std /* 0#0 */] -#[macro_use /* 0#1 */] extern crate core /* 0#2 */; #[prelude_import /* 0#1 */] use ::core /* 0#1 */::prelude /* 0#1 */::rust_2015 /* 0#1 */::*; diff --git a/tests/ui/proc-macro/quote/debug.stdout b/tests/ui/proc-macro/quote/debug.stdout index 77c52f02a33c..896c809fedab 100644 --- a/tests/ui/proc-macro/quote/debug.stdout +++ b/tests/ui/proc-macro/quote/debug.stdout @@ -12,7 +12,6 @@ #![feature(proc_macro_quote)] #![crate_type = "proc-macro"] -#[macro_use] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.stdout b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.stdout index 66ba726fb9a4..9a34d6c1af7a 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.stdout +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.stdout @@ -1,6 +1,5 @@ #![feature(prelude_import)] #![no_std] -#[macro_use] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr index f2fcb98cb6a9..a91a15bc63df 100644 --- a/tests/ui/stats/input-stats.stderr +++ b/tests/ui/stats/input-stats.stderr @@ -15,7 +15,7 @@ ast-stats - Ptr 64 (NN.N%) 1 ast-stats - Ref 64 (NN.N%) 1 ast-stats - ImplicitSelf 128 (NN.N%) 2 ast-stats - Path 640 (NN.N%) 10 -ast-stats PathSegment 888 (NN.N%) 37 24 +ast-stats PathSegment 864 (NN.N%) 36 24 ast-stats Expr 648 (NN.N%) 9 72 ast-stats - InlineAsm 72 (NN.N%) 1 ast-stats - Match 72 (NN.N%) 1 @@ -41,9 +41,9 @@ ast-stats - Let 32 (NN.N%) 1 ast-stats - Semi 32 (NN.N%) 1 ast-stats - Expr 96 (NN.N%) 3 ast-stats Param 160 (NN.N%) 4 40 -ast-stats Attribute 160 (NN.N%) 5 32 +ast-stats Attribute 128 (NN.N%) 4 32 ast-stats - DocComment 32 (NN.N%) 1 -ast-stats - Normal 128 (NN.N%) 4 +ast-stats - Normal 96 (NN.N%) 3 ast-stats InlineAsm 120 (NN.N%) 1 120 ast-stats FnDecl 120 (NN.N%) 5 24 ast-stats Local 96 (NN.N%) 1 96 @@ -57,7 +57,7 @@ ast-stats GenericArgs 40 (NN.N%) 1 40 ast-stats - AngleBracketed 40 (NN.N%) 1 ast-stats Crate 40 (NN.N%) 1 40 ast-stats ---------------------------------------------------------------- -ast-stats Total 7_616 129 +ast-stats Total 7_560 127 ast-stats ================================================================ hir-stats ================================================================ hir-stats HIR STATS: input_stats @@ -93,7 +93,7 @@ hir-stats GenericParam 400 (NN.N%) 5 80 hir-stats Block 288 (NN.N%) 6 48 hir-stats GenericBound 256 (NN.N%) 4 64 hir-stats - Trait 256 (NN.N%) 4 -hir-stats Attribute 200 (NN.N%) 5 40 +hir-stats Attribute 160 (NN.N%) 4 40 hir-stats Variant 144 (NN.N%) 2 72 hir-stats GenericArgs 144 (NN.N%) 3 48 hir-stats FieldDef 128 (NN.N%) 2 64 @@ -119,5 +119,5 @@ hir-stats TraitItemId 8 (NN.N%) 2 4 hir-stats ImplItemId 8 (NN.N%) 2 4 hir-stats ForeignItemId 4 (NN.N%) 1 4 hir-stats ---------------------------------------------------------------- -hir-stats Total 8_616 173 +hir-stats Total 8_576 172 hir-stats ================================================================ diff --git a/tests/ui/type-alias-impl-trait/issue-60662.stdout b/tests/ui/type-alias-impl-trait/issue-60662.stdout index 7ad29c88bcfe..d1f337819f8b 100644 --- a/tests/ui/type-alias-impl-trait/issue-60662.stdout +++ b/tests/ui/type-alias-impl-trait/issue-60662.stdout @@ -3,7 +3,6 @@ //@ edition: 2015 #![feature(type_alias_impl_trait)] -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/ui/unpretty/bad-literal.stdout b/tests/ui/unpretty/bad-literal.stdout index 1f697aff27c9..267d59a868e4 100644 --- a/tests/ui/unpretty/bad-literal.stdout +++ b/tests/ui/unpretty/bad-literal.stdout @@ -1,4 +1,3 @@ -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/ui/unpretty/debug-fmt-hir.stdout b/tests/ui/unpretty/debug-fmt-hir.stdout index 9c79421e32ab..342dc144909c 100644 --- a/tests/ui/unpretty/debug-fmt-hir.stdout +++ b/tests/ui/unpretty/debug-fmt-hir.stdout @@ -1,4 +1,3 @@ -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/ui/unpretty/deprecated-attr.stdout b/tests/ui/unpretty/deprecated-attr.stdout index 26cc74c11604..0b0f17d55666 100644 --- a/tests/ui/unpretty/deprecated-attr.stdout +++ b/tests/ui/unpretty/deprecated-attr.stdout @@ -1,4 +1,3 @@ -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/ui/unpretty/diagnostic-attr.stdout b/tests/ui/unpretty/diagnostic-attr.stdout index 4822cf4700b9..80cd11753493 100644 --- a/tests/ui/unpretty/diagnostic-attr.stdout +++ b/tests/ui/unpretty/diagnostic-attr.stdout @@ -1,4 +1,3 @@ -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/ui/unpretty/exhaustive-asm.expanded.stdout b/tests/ui/unpretty/exhaustive-asm.expanded.stdout index 9a58e4c2877b..9b3c60b03ba7 100644 --- a/tests/ui/unpretty/exhaustive-asm.expanded.stdout +++ b/tests/ui/unpretty/exhaustive-asm.expanded.stdout @@ -1,5 +1,4 @@ #![feature(prelude_import)] -#[macro_use] extern crate std; #[prelude_import] use std::prelude::rust_2024::*; diff --git a/tests/ui/unpretty/exhaustive-asm.hir.stdout b/tests/ui/unpretty/exhaustive-asm.hir.stdout index b33b38c2caba..ed98191e1dd5 100644 --- a/tests/ui/unpretty/exhaustive-asm.hir.stdout +++ b/tests/ui/unpretty/exhaustive-asm.hir.stdout @@ -1,4 +1,3 @@ -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use std::prelude::rust_2024::*; diff --git a/tests/ui/unpretty/exhaustive.expanded.stdout b/tests/ui/unpretty/exhaustive.expanded.stdout index 1fc9e6a72693..f555904e5dd7 100644 --- a/tests/ui/unpretty/exhaustive.expanded.stdout +++ b/tests/ui/unpretty/exhaustive.expanded.stdout @@ -31,7 +31,6 @@ #![feature(try_blocks_heterogeneous)] #![feature(yeet_expr)] #![allow(incomplete_features)] -#[macro_use] extern crate std; #[prelude_import] use std::prelude::rust_2024::*; diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout index 9396e937d843..f309aa0b5fb6 100644 --- a/tests/ui/unpretty/exhaustive.hir.stdout +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -30,7 +30,6 @@ #![feature(try_blocks_heterogeneous)] #![feature(yeet_expr)] #![allow(incomplete_features)] -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use std::prelude::rust_2024::*; diff --git a/tests/ui/unpretty/flattened-format-args.stdout b/tests/ui/unpretty/flattened-format-args.stdout index 5c7866dcf39f..156dcd68a674 100644 --- a/tests/ui/unpretty/flattened-format-args.stdout +++ b/tests/ui/unpretty/flattened-format-args.stdout @@ -1,4 +1,3 @@ -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/ui/unpretty/interpolation-expanded.stdout b/tests/ui/unpretty/interpolation-expanded.stdout index 7284a89e7a9b..d385a021ed57 100644 --- a/tests/ui/unpretty/interpolation-expanded.stdout +++ b/tests/ui/unpretty/interpolation-expanded.stdout @@ -10,7 +10,6 @@ // synthesizing parentheses indiscriminately; only where necessary. #![feature(if_let_guard)] -#[macro_use] extern crate std; #[prelude_import] use std::prelude::rust_2024::*; diff --git a/tests/ui/unpretty/let-else-hir.stdout b/tests/ui/unpretty/let-else-hir.stdout index 14270a572027..cc19f392c3a4 100644 --- a/tests/ui/unpretty/let-else-hir.stdout +++ b/tests/ui/unpretty/let-else-hir.stdout @@ -1,4 +1,3 @@ -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/ui/unpretty/self-hir.stdout b/tests/ui/unpretty/self-hir.stdout index b190565dcc47..c973e143275c 100644 --- a/tests/ui/unpretty/self-hir.stdout +++ b/tests/ui/unpretty/self-hir.stdout @@ -1,4 +1,3 @@ -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout b/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout index fc0fbe8ef237..8b6ca4f672dc 100644 --- a/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout +++ b/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout @@ -4,7 +4,6 @@ #![feature(min_generic_const_args, adt_const_params)] #![expect(incomplete_features)] #![allow(dead_code)] -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; diff --git a/tests/ui/unpretty/unpretty-expr-fn-arg.stdout b/tests/ui/unpretty/unpretty-expr-fn-arg.stdout index c04909a73613..41d62d11aaa6 100644 --- a/tests/ui/unpretty/unpretty-expr-fn-arg.stdout +++ b/tests/ui/unpretty/unpretty-expr-fn-arg.stdout @@ -8,7 +8,6 @@ //@ compile-flags: -Zunpretty=hir,typed //@ edition: 2015 #![allow(dead_code)] -#[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; From ef9cbadc433ede9334ae9a9461e65fed4e90f9c2 Mon Sep 17 00:00:00 2001 From: vsriram Date: Tue, 13 Jan 2026 13:31:54 +0530 Subject: [PATCH 0647/1061] ui: add regression test for macro resolution ICE --- tests/ui/resolve/decl-macro-use-no-ice.rs | 20 ++++++++ tests/ui/resolve/decl-macro-use-no-ice.stderr | 47 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 tests/ui/resolve/decl-macro-use-no-ice.rs create mode 100644 tests/ui/resolve/decl-macro-use-no-ice.stderr diff --git a/tests/ui/resolve/decl-macro-use-no-ice.rs b/tests/ui/resolve/decl-macro-use-no-ice.rs new file mode 100644 index 000000000000..39b9cb03fea0 --- /dev/null +++ b/tests/ui/resolve/decl-macro-use-no-ice.rs @@ -0,0 +1,20 @@ +//@ edition: 2024 +#![feature(decl_macro)] + +// Regression test for issue +// The compiler previously ICE'd during identifier resolution +// involving `macro` items and `use` inside a public macro. + + +mod foo { + macro f() {} + + pub macro m() { + use f; //~ ERROR `f` is private, and cannot be re-exported + f!(); //~ ERROR macro import `f` is private + } +} + +fn main() { + foo::m!(); +} diff --git a/tests/ui/resolve/decl-macro-use-no-ice.stderr b/tests/ui/resolve/decl-macro-use-no-ice.stderr new file mode 100644 index 000000000000..9fb75b48b428 --- /dev/null +++ b/tests/ui/resolve/decl-macro-use-no-ice.stderr @@ -0,0 +1,47 @@ +error[E0364]: `f` is private, and cannot be re-exported + --> $DIR/decl-macro-use-no-ice.rs:13:13 + | +LL | use f; + | ^ +... +LL | foo::m!(); + | --------- in this macro invocation + | +note: consider marking `f` as `pub` in the imported module + --> $DIR/decl-macro-use-no-ice.rs:13:13 + | +LL | use f; + | ^ +... +LL | foo::m!(); + | --------- in this macro invocation + = note: this error originates in the macro `foo::m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0603]: macro import `f` is private + --> $DIR/decl-macro-use-no-ice.rs:14:9 + | +LL | f!(); + | ^ private macro import +... +LL | foo::m!(); + | --------- in this macro invocation + | +note: the macro import `f` is defined here... + --> $DIR/decl-macro-use-no-ice.rs:13:13 + | +LL | use f; + | ^ +... +LL | foo::m!(); + | --------- in this macro invocation +note: ...and refers to the macro `f` which is defined here + --> $DIR/decl-macro-use-no-ice.rs:10:5 + | +LL | macro f() {} + | ^^^^^^^^^ + = note: this error originates in the macro `foo::m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0364, E0603. +For more information about an error, try `rustc --explain E0364`. From 62849e64412e3dd9f7fba08881a6fab92aadadc3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 13 Jan 2026 10:22:34 +0100 Subject: [PATCH 0648/1061] Reduce flakyness for `tests/rustdoc-gui/notable-trait.goml` --- tests/rustdoc-gui/notable-trait.goml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/rustdoc-gui/notable-trait.goml b/tests/rustdoc-gui/notable-trait.goml index 839988021fce..8e4c180e0ef1 100644 --- a/tests/rustdoc-gui/notable-trait.goml +++ b/tests/rustdoc-gui/notable-trait.goml @@ -250,7 +250,7 @@ set-window-size: (1100, 600) reload: assert-count: ("//*[@class='tooltip popover']", 0) click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" -assert-count: ("//*[@class='tooltip popover']", 1) +wait-for-count: ("//*[@class='tooltip popover']", 1) call-function: ("open-settings-menu", {}) -assert-count: ("//*[@class='tooltip popover']", 0) +wait-for-count: ("//*[@class='tooltip popover']", 0) assert-false: "#method\.create_an_iterator_from_read .tooltip:focus" From e259373ce9eca5a10201d74a016a4a2e7ab42ed7 Mon Sep 17 00:00:00 2001 From: joboet Date: Tue, 6 Jan 2026 13:38:27 +0100 Subject: [PATCH 0649/1061] std: move `errno` and related functions into `sys::io` --- library/std/src/io/error.rs | 12 +- library/std/src/io/error/tests.rs | 3 +- library/std/src/sys/exit_guard.rs | 2 +- library/std/src/sys/fs/unix.rs | 4 +- library/std/src/sys/io/error/generic.rs | 15 ++ library/std/src/sys/io/error/hermit.rs | 35 ++++ library/std/src/sys/io/error/mod.rs | 55 ++++++ library/std/src/sys/io/error/motor.rs | 67 +++++++ library/std/src/sys/io/error/sgx.rs | 65 ++++++ library/std/src/sys/io/error/solid.rs | 19 ++ library/std/src/sys/io/error/teeos.rs | 64 ++++++ library/std/src/sys/io/error/uefi.rs | 104 ++++++++++ library/std/src/sys/io/error/unix.rs | 186 ++++++++++++++++++ library/std/src/sys/io/error/wasi.rs | 80 ++++++++ library/std/src/sys/io/error/windows.rs | 140 +++++++++++++ library/std/src/sys/io/error/xous.rs | 17 ++ library/std/src/sys/io/mod.rs | 20 +- .../std/src/sys/net/connection/socket/unix.rs | 2 +- library/std/src/sys/net/hostname/unix.rs | 2 +- library/std/src/sys/pal/hermit/mod.rs | 33 +--- library/std/src/sys/pal/hermit/os.rs | 8 - library/std/src/sys/pal/motor/mod.rs | 39 ---- library/std/src/sys/pal/motor/os.rs | 29 --- library/std/src/sys/pal/sgx/mod.rs | 50 ----- library/std/src/sys/pal/sgx/os.rs | 18 +- library/std/src/sys/pal/solid/mod.rs | 9 - library/std/src/sys/pal/solid/os.rs | 10 +- library/std/src/sys/pal/teeos/mod.rs | 55 ------ library/std/src/sys/pal/teeos/os.rs | 8 - library/std/src/sys/pal/uefi/mod.rs | 50 ----- library/std/src/sys/pal/uefi/os.rs | 53 ----- library/std/src/sys/pal/unix/futex.rs | 6 +- library/std/src/sys/pal/unix/mod.rs | 61 +----- library/std/src/sys/pal/unix/os.rs | 127 ------------ .../pal/unix/stack_overflow/thread_info.rs | 2 +- library/std/src/sys/pal/unsupported/common.rs | 8 - library/std/src/sys/pal/unsupported/os.rs | 8 - library/std/src/sys/pal/vexos/mod.rs | 4 +- library/std/src/sys/pal/vexos/os.rs | 4 +- library/std/src/sys/pal/wasi/helpers.rs | 56 +----- library/std/src/sys/pal/wasi/mod.rs | 2 +- library/std/src/sys/pal/wasi/os.rs | 30 +-- library/std/src/sys/pal/windows/mod.rs | 78 -------- library/std/src/sys/pal/windows/os.rs | 60 ------ library/std/src/sys/pal/xous/os.rs | 9 - library/std/src/sys/pal/zkvm/mod.rs | 8 - library/std/src/sys/pal/zkvm/os.rs | 8 - library/std/src/sys/process/uefi.rs | 2 +- library/std/src/sys/process/unix/common.rs | 2 +- library/std/src/sys/process/unix/unix.rs | 2 +- library/std/src/sys/random/linux.rs | 2 +- library/std/src/sys/sync/condvar/windows7.rs | 4 +- library/std/src/sys/thread/unix.rs | 9 +- 53 files changed, 900 insertions(+), 846 deletions(-) create mode 100644 library/std/src/sys/io/error/generic.rs create mode 100644 library/std/src/sys/io/error/hermit.rs create mode 100644 library/std/src/sys/io/error/mod.rs create mode 100644 library/std/src/sys/io/error/motor.rs create mode 100644 library/std/src/sys/io/error/sgx.rs create mode 100644 library/std/src/sys/io/error/solid.rs create mode 100644 library/std/src/sys/io/error/teeos.rs create mode 100644 library/std/src/sys/io/error/uefi.rs create mode 100644 library/std/src/sys/io/error/unix.rs create mode 100644 library/std/src/sys/io/error/wasi.rs create mode 100644 library/std/src/sys/io/error/windows.rs create mode 100644 library/std/src/sys/io/error/xous.rs diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 528eb185df08..b19087e7424a 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -653,7 +653,7 @@ impl Error { #[must_use] #[inline] pub fn last_os_error() -> Error { - Error::from_raw_os_error(sys::os::errno()) + Error::from_raw_os_error(sys::io::errno()) } /// Creates a new instance of an [`Error`] from a particular OS error code. @@ -1004,7 +1004,7 @@ impl Error { #[inline] pub fn kind(&self) -> ErrorKind { match self.repr.data() { - ErrorData::Os(code) => sys::decode_error_kind(code), + ErrorData::Os(code) => sys::io::decode_error_kind(code), ErrorData::Custom(c) => c.kind, ErrorData::Simple(kind) => kind, ErrorData::SimpleMessage(m) => m.kind, @@ -1014,7 +1014,7 @@ impl Error { #[inline] pub(crate) fn is_interrupted(&self) -> bool { match self.repr.data() { - ErrorData::Os(code) => sys::is_interrupted(code), + ErrorData::Os(code) => sys::io::is_interrupted(code), ErrorData::Custom(c) => c.kind == ErrorKind::Interrupted, ErrorData::Simple(kind) => kind == ErrorKind::Interrupted, ErrorData::SimpleMessage(m) => m.kind == ErrorKind::Interrupted, @@ -1028,8 +1028,8 @@ impl fmt::Debug for Repr { ErrorData::Os(code) => fmt .debug_struct("Os") .field("code", &code) - .field("kind", &sys::decode_error_kind(code)) - .field("message", &sys::os::error_string(code)) + .field("kind", &sys::io::decode_error_kind(code)) + .field("message", &sys::io::error_string(code)) .finish(), ErrorData::Custom(c) => fmt::Debug::fmt(&c, fmt), ErrorData::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(), @@ -1047,7 +1047,7 @@ impl fmt::Display for Error { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match self.repr.data() { ErrorData::Os(code) => { - let detail = sys::os::error_string(code); + let detail = sys::io::error_string(code); write!(fmt, "{detail} (os error {code})") } ErrorData::Custom(ref c) => c.error.fmt(fmt), diff --git a/library/std/src/io/error/tests.rs b/library/std/src/io/error/tests.rs index 3e4029768eb8..eef44c6ac3b6 100644 --- a/library/std/src/io/error/tests.rs +++ b/library/std/src/io/error/tests.rs @@ -1,7 +1,6 @@ use super::{Custom, Error, ErrorData, ErrorKind, Repr, SimpleMessage, const_error}; use crate::assert_matches::assert_matches; -use crate::sys::decode_error_kind; -use crate::sys::os::error_string; +use crate::sys::io::{decode_error_kind, error_string}; use crate::{error, fmt}; #[test] diff --git a/library/std/src/sys/exit_guard.rs b/library/std/src/sys/exit_guard.rs index 00b91842e9db..e7d7a478a5ba 100644 --- a/library/std/src/sys/exit_guard.rs +++ b/library/std/src/sys/exit_guard.rs @@ -34,7 +34,7 @@ cfg_select! { // lifetime of the thread. Additionally, accesses to `errno` are // async-signal-safe, so this function is available in all imaginable // circumstances. - let this_thread_id = crate::sys::os::errno_location(); + let this_thread_id = crate::sys::io::errno_location(); match EXITING_THREAD_ID.compare_exchange(ptr::null_mut(), this_thread_id, Acquire, Relaxed) { Ok(_) => { // This is the first thread to call `unique_thread_exit`, diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 1cc2edd0cf47..716ca9783d1f 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -726,7 +726,7 @@ impl Iterator for ReadDir { target_os = "wasi", ))] fn next(&mut self) -> Option> { - use crate::sys::os::{errno, set_errno}; + use crate::sys::io::{errno, set_errno}; if self.end_of_stream { return None; @@ -864,7 +864,7 @@ impl Iterator for ReadDir { /// The downside is that it costs an extra syscall, so we only do it for debug. #[inline] pub(crate) fn debug_assert_fd_is_open(fd: RawFd) { - use crate::sys::os::errno; + use crate::sys::io::errno; // this is similar to assert_unsafe_precondition!() but it doesn't require const if core::ub_checks::check_library_ub() { diff --git a/library/std/src/sys/io/error/generic.rs b/library/std/src/sys/io/error/generic.rs new file mode 100644 index 000000000000..fc70fbaba7e8 --- /dev/null +++ b/library/std/src/sys/io/error/generic.rs @@ -0,0 +1,15 @@ +pub fn errno() -> i32 { + 0 +} + +pub fn is_interrupted(_code: i32) -> bool { + false +} + +pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind { + crate::io::ErrorKind::Uncategorized +} + +pub fn error_string(_errno: i32) -> String { + "operation successful".to_string() +} diff --git a/library/std/src/sys/io/error/hermit.rs b/library/std/src/sys/io/error/hermit.rs new file mode 100644 index 000000000000..5f42144bb7cf --- /dev/null +++ b/library/std/src/sys/io/error/hermit.rs @@ -0,0 +1,35 @@ +use crate::io; + +pub fn errno() -> i32 { + unsafe { hermit_abi::get_errno() } +} + +#[inline] +pub fn is_interrupted(errno: i32) -> bool { + errno == hermit_abi::errno::EINTR +} + +pub fn decode_error_kind(errno: i32) -> io::ErrorKind { + match errno { + hermit_abi::errno::EACCES => io::ErrorKind::PermissionDenied, + hermit_abi::errno::EADDRINUSE => io::ErrorKind::AddrInUse, + hermit_abi::errno::EADDRNOTAVAIL => io::ErrorKind::AddrNotAvailable, + hermit_abi::errno::EAGAIN => io::ErrorKind::WouldBlock, + hermit_abi::errno::ECONNABORTED => io::ErrorKind::ConnectionAborted, + hermit_abi::errno::ECONNREFUSED => io::ErrorKind::ConnectionRefused, + hermit_abi::errno::ECONNRESET => io::ErrorKind::ConnectionReset, + hermit_abi::errno::EEXIST => io::ErrorKind::AlreadyExists, + hermit_abi::errno::EINTR => io::ErrorKind::Interrupted, + hermit_abi::errno::EINVAL => io::ErrorKind::InvalidInput, + hermit_abi::errno::ENOENT => io::ErrorKind::NotFound, + hermit_abi::errno::ENOTCONN => io::ErrorKind::NotConnected, + hermit_abi::errno::EPERM => io::ErrorKind::PermissionDenied, + hermit_abi::errno::EPIPE => io::ErrorKind::BrokenPipe, + hermit_abi::errno::ETIMEDOUT => io::ErrorKind::TimedOut, + _ => io::ErrorKind::Uncategorized, + } +} + +pub fn error_string(errno: i32) -> String { + hermit_abi::error_string(errno).to_string() +} diff --git a/library/std/src/sys/io/error/mod.rs b/library/std/src/sys/io/error/mod.rs new file mode 100644 index 000000000000..d7a0b9b4b301 --- /dev/null +++ b/library/std/src/sys/io/error/mod.rs @@ -0,0 +1,55 @@ +cfg_select! { + target_os = "hermit" => { + mod hermit; + pub use hermit::*; + } + target_os = "motor" => { + mod motor; + pub use motor::*; + } + all(target_vendor = "fortanix", target_env = "sgx") => { + mod sgx; + pub use sgx::*; + } + target_os = "solid_asp3" => { + mod solid; + pub use solid::*; + } + target_os = "teeos" => { + mod teeos; + pub use teeos::*; + } + target_os = "uefi" => { + mod uefi; + pub use uefi::*; + } + target_family = "unix" => { + mod unix; + pub use unix::*; + } + target_os = "wasi" => { + mod wasi; + pub use wasi::*; + } + target_os = "windows" => { + mod windows; + pub use windows::*; + } + target_os = "xous" => { + mod xous; + pub use xous::*; + } + any( + target_os = "vexos", + target_family = "wasm", + target_os = "zkvm", + ) => { + mod generic; + pub use generic::*; + } +} + +pub type RawOsError = cfg_select! { + target_os = "uefi" => usize, + _ => i32, +}; diff --git a/library/std/src/sys/io/error/motor.rs b/library/std/src/sys/io/error/motor.rs new file mode 100644 index 000000000000..7d612d817cdd --- /dev/null +++ b/library/std/src/sys/io/error/motor.rs @@ -0,0 +1,67 @@ +use crate::io; +use crate::sys::io::RawOsError; + +pub fn errno() -> RawOsError { + // Not used in Motor OS because it is ambiguous: Motor OS + // is micro-kernel-based, and I/O happens via a shared-memory + // ring buffer, so an I/O operation that on a unix is a syscall + // may involve no sycalls on Motor OS at all, or a syscall + // that e.g. waits for a notification from the I/O driver + // (sys-io); and the wait syscall may succeed, but the + // driver may report an I/O error; or a bunch of results + // for several I/O operations, some successful and some + // not. + // + // Also I/O operations in a Motor OS process are handled by a + // separate runtime background/I/O thread, so it is really hard + // to define what "last system error in the current thread" + // actually means. + let error_code: moto_rt::ErrorCode = moto_rt::Error::Unknown.into(); + error_code.into() +} + +pub fn is_interrupted(_code: io::RawOsError) -> bool { + false // Motor OS doesn't have signals. +} + +pub fn decode_error_kind(code: io::RawOsError) -> io::ErrorKind { + if code < 0 || code > u16::MAX.into() { + return io::ErrorKind::Uncategorized; + } + + let error = moto_rt::Error::from(code as moto_rt::ErrorCode); + + match error { + moto_rt::Error::Unspecified => io::ErrorKind::Uncategorized, + moto_rt::Error::Unknown => io::ErrorKind::Uncategorized, + moto_rt::Error::NotReady => io::ErrorKind::WouldBlock, + moto_rt::Error::NotImplemented => io::ErrorKind::Unsupported, + moto_rt::Error::VersionTooHigh => io::ErrorKind::Unsupported, + moto_rt::Error::VersionTooLow => io::ErrorKind::Unsupported, + moto_rt::Error::InvalidArgument => io::ErrorKind::InvalidInput, + moto_rt::Error::OutOfMemory => io::ErrorKind::OutOfMemory, + moto_rt::Error::NotAllowed => io::ErrorKind::PermissionDenied, + moto_rt::Error::NotFound => io::ErrorKind::NotFound, + moto_rt::Error::InternalError => io::ErrorKind::Other, + moto_rt::Error::TimedOut => io::ErrorKind::TimedOut, + moto_rt::Error::AlreadyInUse => io::ErrorKind::AlreadyExists, + moto_rt::Error::UnexpectedEof => io::ErrorKind::UnexpectedEof, + moto_rt::Error::InvalidFilename => io::ErrorKind::InvalidFilename, + moto_rt::Error::NotADirectory => io::ErrorKind::NotADirectory, + moto_rt::Error::BadHandle => io::ErrorKind::InvalidInput, + moto_rt::Error::FileTooLarge => io::ErrorKind::FileTooLarge, + moto_rt::Error::NotConnected => io::ErrorKind::NotConnected, + moto_rt::Error::StorageFull => io::ErrorKind::StorageFull, + moto_rt::Error::InvalidData => io::ErrorKind::InvalidData, + _ => io::ErrorKind::Uncategorized, + } +} + +pub fn error_string(errno: RawOsError) -> String { + let error: moto_rt::Error = match errno { + x if x < 0 => moto_rt::Error::Unknown, + x if x > u16::MAX.into() => moto_rt::Error::Unknown, + x => (x as moto_rt::ErrorCode).into(), /* u16 */ + }; + format!("{}", error) +} diff --git a/library/std/src/sys/io/error/sgx.rs b/library/std/src/sys/io/error/sgx.rs new file mode 100644 index 000000000000..8b3e08b0b661 --- /dev/null +++ b/library/std/src/sys/io/error/sgx.rs @@ -0,0 +1,65 @@ +use fortanix_sgx_abi::{Error, RESULT_SUCCESS}; + +use crate::io; + +pub fn errno() -> i32 { + RESULT_SUCCESS +} + +#[inline] +pub fn is_interrupted(code: i32) -> bool { + code == fortanix_sgx_abi::Error::Interrupted as _ +} + +pub fn decode_error_kind(code: i32) -> io::ErrorKind { + // FIXME: not sure how to make sure all variants of Error are covered + if code == Error::NotFound as _ { + io::ErrorKind::NotFound + } else if code == Error::PermissionDenied as _ { + io::ErrorKind::PermissionDenied + } else if code == Error::ConnectionRefused as _ { + io::ErrorKind::ConnectionRefused + } else if code == Error::ConnectionReset as _ { + io::ErrorKind::ConnectionReset + } else if code == Error::ConnectionAborted as _ { + io::ErrorKind::ConnectionAborted + } else if code == Error::NotConnected as _ { + io::ErrorKind::NotConnected + } else if code == Error::AddrInUse as _ { + io::ErrorKind::AddrInUse + } else if code == Error::AddrNotAvailable as _ { + io::ErrorKind::AddrNotAvailable + } else if code == Error::BrokenPipe as _ { + io::ErrorKind::BrokenPipe + } else if code == Error::AlreadyExists as _ { + io::ErrorKind::AlreadyExists + } else if code == Error::WouldBlock as _ { + io::ErrorKind::WouldBlock + } else if code == Error::InvalidInput as _ { + io::ErrorKind::InvalidInput + } else if code == Error::InvalidData as _ { + io::ErrorKind::InvalidData + } else if code == Error::TimedOut as _ { + io::ErrorKind::TimedOut + } else if code == Error::WriteZero as _ { + io::ErrorKind::WriteZero + } else if code == Error::Interrupted as _ { + io::ErrorKind::Interrupted + } else if code == Error::Other as _ { + io::ErrorKind::Uncategorized + } else if code == Error::UnexpectedEof as _ { + io::ErrorKind::UnexpectedEof + } else { + io::ErrorKind::Uncategorized + } +} + +pub fn error_string(errno: i32) -> String { + if errno == RESULT_SUCCESS { + "operation successful".into() + } else if ((Error::UserRangeStart as _)..=(Error::UserRangeEnd as _)).contains(&errno) { + format!("user-specified error {errno:08x}") + } else { + decode_error_kind(errno).as_str().into() + } +} diff --git a/library/std/src/sys/io/error/solid.rs b/library/std/src/sys/io/error/solid.rs new file mode 100644 index 000000000000..8e9503272abb --- /dev/null +++ b/library/std/src/sys/io/error/solid.rs @@ -0,0 +1,19 @@ +use crate::io; +use crate::sys::pal::error; + +pub fn errno() -> i32 { + 0 +} + +#[inline] +pub fn is_interrupted(code: i32) -> bool { + crate::sys::net::is_interrupted(code) +} + +pub fn decode_error_kind(code: i32) -> io::ErrorKind { + error::decode_error_kind(code) +} + +pub fn error_string(errno: i32) -> String { + if let Some(name) = error::error_name(errno) { name.to_owned() } else { format!("{errno}") } +} diff --git a/library/std/src/sys/io/error/teeos.rs b/library/std/src/sys/io/error/teeos.rs new file mode 100644 index 000000000000..18826ffc3894 --- /dev/null +++ b/library/std/src/sys/io/error/teeos.rs @@ -0,0 +1,64 @@ +use crate::io; + +pub fn errno() -> i32 { + unsafe { (*libc::__errno_location()) as i32 } +} + +#[inline] +pub fn is_interrupted(errno: i32) -> bool { + errno == libc::EINTR +} + +// Note: code below is 1:1 copied from unix/mod.rs +pub fn decode_error_kind(errno: i32) -> io::ErrorKind { + use io::ErrorKind::*; + match errno as libc::c_int { + libc::E2BIG => ArgumentListTooLong, + libc::EADDRINUSE => AddrInUse, + libc::EADDRNOTAVAIL => AddrNotAvailable, + libc::EBUSY => ResourceBusy, + libc::ECONNABORTED => ConnectionAborted, + libc::ECONNREFUSED => ConnectionRefused, + libc::ECONNRESET => ConnectionReset, + libc::EDEADLK => Deadlock, + libc::EDQUOT => QuotaExceeded, + libc::EEXIST => AlreadyExists, + libc::EFBIG => FileTooLarge, + libc::EHOSTUNREACH => HostUnreachable, + libc::EINTR => Interrupted, + libc::EINVAL => InvalidInput, + libc::EISDIR => IsADirectory, + libc::ELOOP => FilesystemLoop, + libc::ENOENT => NotFound, + libc::ENOMEM => OutOfMemory, + libc::ENOSPC => StorageFull, + libc::ENOSYS => Unsupported, + libc::EMLINK => TooManyLinks, + libc::ENAMETOOLONG => InvalidFilename, + libc::ENETDOWN => NetworkDown, + libc::ENETUNREACH => NetworkUnreachable, + libc::ENOTCONN => NotConnected, + libc::ENOTDIR => NotADirectory, + libc::ENOTEMPTY => DirectoryNotEmpty, + libc::EPIPE => BrokenPipe, + libc::EROFS => ReadOnlyFilesystem, + libc::ESPIPE => NotSeekable, + libc::ESTALE => StaleNetworkFileHandle, + libc::ETIMEDOUT => TimedOut, + libc::ETXTBSY => ExecutableFileBusy, + libc::EXDEV => CrossesDevices, + + libc::EACCES | libc::EPERM => PermissionDenied, + + // These two constants can have the same value on some systems, + // but different values on others, so we can't use a match + // clause + x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => WouldBlock, + + _ => Uncategorized, + } +} + +pub fn error_string(_errno: i32) -> String { + "error string unimplemented".to_string() +} diff --git a/library/std/src/sys/io/error/uefi.rs b/library/std/src/sys/io/error/uefi.rs new file mode 100644 index 000000000000..bedea240d523 --- /dev/null +++ b/library/std/src/sys/io/error/uefi.rs @@ -0,0 +1,104 @@ +use r_efi::efi::Status; + +use crate::io; + +pub fn errno() -> io::RawOsError { + 0 +} + +pub fn is_interrupted(_code: io::RawOsError) -> bool { + false +} + +pub fn decode_error_kind(code: io::RawOsError) -> io::ErrorKind { + match Status::from_usize(code) { + Status::ALREADY_STARTED + | Status::COMPROMISED_DATA + | Status::CONNECTION_FIN + | Status::CRC_ERROR + | Status::DEVICE_ERROR + | Status::END_OF_MEDIA + | Status::HTTP_ERROR + | Status::ICMP_ERROR + | Status::INCOMPATIBLE_VERSION + | Status::LOAD_ERROR + | Status::MEDIA_CHANGED + | Status::NO_MAPPING + | Status::NO_MEDIA + | Status::NOT_STARTED + | Status::PROTOCOL_ERROR + | Status::PROTOCOL_UNREACHABLE + | Status::TFTP_ERROR + | Status::VOLUME_CORRUPTED => io::ErrorKind::Other, + Status::BAD_BUFFER_SIZE | Status::INVALID_LANGUAGE => io::ErrorKind::InvalidData, + Status::ABORTED => io::ErrorKind::ConnectionAborted, + Status::ACCESS_DENIED => io::ErrorKind::PermissionDenied, + Status::BUFFER_TOO_SMALL => io::ErrorKind::FileTooLarge, + Status::CONNECTION_REFUSED => io::ErrorKind::ConnectionRefused, + Status::CONNECTION_RESET => io::ErrorKind::ConnectionReset, + Status::END_OF_FILE => io::ErrorKind::UnexpectedEof, + Status::HOST_UNREACHABLE => io::ErrorKind::HostUnreachable, + Status::INVALID_PARAMETER => io::ErrorKind::InvalidInput, + Status::IP_ADDRESS_CONFLICT => io::ErrorKind::AddrInUse, + Status::NETWORK_UNREACHABLE => io::ErrorKind::NetworkUnreachable, + Status::NO_RESPONSE => io::ErrorKind::HostUnreachable, + Status::NOT_FOUND => io::ErrorKind::NotFound, + Status::NOT_READY => io::ErrorKind::ResourceBusy, + Status::OUT_OF_RESOURCES => io::ErrorKind::OutOfMemory, + Status::SECURITY_VIOLATION => io::ErrorKind::PermissionDenied, + Status::TIMEOUT => io::ErrorKind::TimedOut, + Status::UNSUPPORTED => io::ErrorKind::Unsupported, + Status::VOLUME_FULL => io::ErrorKind::StorageFull, + Status::WRITE_PROTECTED => io::ErrorKind::ReadOnlyFilesystem, + _ => io::ErrorKind::Uncategorized, + } +} + +pub fn error_string(errno: io::RawOsError) -> String { + // Keep the List in Alphabetical Order + // The Messages are taken from UEFI Specification Appendix D - Status Codes + #[rustfmt::skip] + let msg = match Status::from_usize(errno) { + Status::ABORTED => "The operation was aborted.", + Status::ACCESS_DENIED => "Access was denied.", + Status::ALREADY_STARTED => "The protocol has already been started.", + Status::BAD_BUFFER_SIZE => "The buffer was not the proper size for the request.", + Status::BUFFER_TOO_SMALL => "The buffer is not large enough to hold the requested data. The required buffer size is returned in the appropriate parameter when this error occurs.", + Status::COMPROMISED_DATA => "The security status of the data is unknown or compromised and the data must be updated or replaced to restore a valid security status.", + Status::CONNECTION_FIN => "The receiving operation fails because the communication peer has closed the connection and there is no more data in the receive buffer of the instance.", + Status::CONNECTION_REFUSED => "The receiving or transmission operation fails because this connection is refused.", + Status::CONNECTION_RESET => "The connect fails because the connection is reset either by instance itself or the communication peer.", + Status::CRC_ERROR => "A CRC error was detected.", + Status::DEVICE_ERROR => "The physical device reported an error while attempting the operation.", + Status::END_OF_FILE => "The end of the file was reached.", + Status::END_OF_MEDIA => "Beginning or end of media was reached", + Status::HOST_UNREACHABLE => "The remote host is not reachable.", + Status::HTTP_ERROR => "A HTTP error occurred during the network operation.", + Status::ICMP_ERROR => "An ICMP error occurred during the network operation.", + Status::INCOMPATIBLE_VERSION => "The function encountered an internal version that was incompatible with a version requested by the caller.", + Status::INVALID_LANGUAGE => "The language specified was invalid.", + Status::INVALID_PARAMETER => "A parameter was incorrect.", + Status::IP_ADDRESS_CONFLICT => "There is an address conflict address allocation", + Status::LOAD_ERROR => "The image failed to load.", + Status::MEDIA_CHANGED => "The medium in the device has changed since the last access.", + Status::NETWORK_UNREACHABLE => "The network containing the remote host is not reachable.", + Status::NO_MAPPING => "A mapping to a device does not exist.", + Status::NO_MEDIA => "The device does not contain any medium to perform the operation.", + Status::NO_RESPONSE => "The server was not found or did not respond to the request.", + Status::NOT_FOUND => "The item was not found.", + Status::NOT_READY => "There is no data pending upon return.", + Status::NOT_STARTED => "The protocol has not been started.", + Status::OUT_OF_RESOURCES => "A resource has run out.", + Status::PROTOCOL_ERROR => "A protocol error occurred during the network operation.", + Status::PROTOCOL_UNREACHABLE => "An ICMP protocol unreachable error is received.", + Status::SECURITY_VIOLATION => "The function was not performed due to a security violation.", + Status::TFTP_ERROR => "A TFTP error occurred during the network operation.", + Status::TIMEOUT => "The timeout time expired.", + Status::UNSUPPORTED => "The operation is not supported.", + Status::VOLUME_FULL => "There is no more space on the file system.", + Status::VOLUME_CORRUPTED => "An inconstancy was detected on the file system causing the operating to fail.", + Status::WRITE_PROTECTED => "The device cannot be written to.", + _ => return format!("Status: {errno}"), + }; + msg.to_owned() +} diff --git a/library/std/src/sys/io/error/unix.rs b/library/std/src/sys/io/error/unix.rs new file mode 100644 index 000000000000..b10343b2752c --- /dev/null +++ b/library/std/src/sys/io/error/unix.rs @@ -0,0 +1,186 @@ +use crate::ffi::{CStr, c_char, c_int}; +use crate::io; + +unsafe extern "C" { + #[cfg(not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "rtems")))] + #[cfg_attr( + any( + target_os = "linux", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "l4re", + target_os = "hurd", + ), + link_name = "__errno_location" + )] + #[cfg_attr( + any( + target_os = "netbsd", + target_os = "openbsd", + target_os = "cygwin", + target_os = "android", + target_os = "redox", + target_os = "nuttx", + target_env = "newlib" + ), + link_name = "__errno" + )] + #[cfg_attr(any(target_os = "solaris", target_os = "illumos"), link_name = "___errno")] + #[cfg_attr(target_os = "nto", link_name = "__get_errno_ptr")] + #[cfg_attr(any(target_os = "freebsd", target_vendor = "apple"), link_name = "__error")] + #[cfg_attr(target_os = "haiku", link_name = "_errnop")] + #[cfg_attr(target_os = "aix", link_name = "_Errno")] + // SAFETY: this will always return the same pointer on a given thread. + #[unsafe(ffi_const)] + pub safe fn errno_location() -> *mut c_int; +} + +/// Returns the platform-specific value of errno +#[cfg(not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "rtems")))] +#[inline] +pub fn errno() -> i32 { + unsafe { (*errno_location()) as i32 } +} + +/// Sets the platform-specific value of errno +// needed for readdir and syscall! +#[cfg(all(not(target_os = "dragonfly"), not(target_os = "vxworks"), not(target_os = "rtems")))] +#[allow(dead_code)] // but not all target cfgs actually end up using it +#[inline] +pub fn set_errno(e: i32) { + unsafe { *errno_location() = e as c_int } +} + +#[cfg(target_os = "vxworks")] +#[inline] +pub fn errno() -> i32 { + unsafe { libc::errnoGet() } +} + +#[cfg(target_os = "rtems")] +#[inline] +pub fn errno() -> i32 { + unsafe extern "C" { + #[thread_local] + static _tls_errno: c_int; + } + + unsafe { _tls_errno as i32 } +} + +#[cfg(target_os = "dragonfly")] +#[inline] +pub fn errno() -> i32 { + unsafe extern "C" { + #[thread_local] + static errno: c_int; + } + + unsafe { errno as i32 } +} + +#[cfg(target_os = "dragonfly")] +#[allow(dead_code)] +#[inline] +pub fn set_errno(e: i32) { + unsafe extern "C" { + #[thread_local] + static mut errno: c_int; + } + + unsafe { + errno = e; + } +} + +#[inline] +pub fn is_interrupted(errno: i32) -> bool { + errno == libc::EINTR +} + +pub fn decode_error_kind(errno: i32) -> io::ErrorKind { + use io::ErrorKind::*; + match errno as libc::c_int { + libc::E2BIG => ArgumentListTooLong, + libc::EADDRINUSE => AddrInUse, + libc::EADDRNOTAVAIL => AddrNotAvailable, + libc::EBUSY => ResourceBusy, + libc::ECONNABORTED => ConnectionAborted, + libc::ECONNREFUSED => ConnectionRefused, + libc::ECONNRESET => ConnectionReset, + libc::EDEADLK => Deadlock, + libc::EDQUOT => QuotaExceeded, + libc::EEXIST => AlreadyExists, + libc::EFBIG => FileTooLarge, + libc::EHOSTUNREACH => HostUnreachable, + libc::EINTR => Interrupted, + libc::EINVAL => InvalidInput, + libc::EISDIR => IsADirectory, + libc::ELOOP => FilesystemLoop, + libc::ENOENT => NotFound, + libc::ENOMEM => OutOfMemory, + libc::ENOSPC => StorageFull, + libc::ENOSYS => Unsupported, + libc::EMLINK => TooManyLinks, + libc::ENAMETOOLONG => InvalidFilename, + libc::ENETDOWN => NetworkDown, + libc::ENETUNREACH => NetworkUnreachable, + libc::ENOTCONN => NotConnected, + libc::ENOTDIR => NotADirectory, + #[cfg(not(target_os = "aix"))] + libc::ENOTEMPTY => DirectoryNotEmpty, + libc::EPIPE => BrokenPipe, + libc::EROFS => ReadOnlyFilesystem, + libc::ESPIPE => NotSeekable, + libc::ESTALE => StaleNetworkFileHandle, + libc::ETIMEDOUT => TimedOut, + libc::ETXTBSY => ExecutableFileBusy, + libc::EXDEV => CrossesDevices, + libc::EINPROGRESS => InProgress, + libc::EOPNOTSUPP => Unsupported, + + libc::EACCES | libc::EPERM => PermissionDenied, + + // These two constants can have the same value on some systems, + // but different values on others, so we can't use a match + // clause + x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => WouldBlock, + + _ => Uncategorized, + } +} + +/// Gets a detailed string description for the given error number. +pub fn error_string(errno: i32) -> String { + const TMPBUF_SZ: usize = 128; + + unsafe extern "C" { + #[cfg_attr( + all( + any( + target_os = "linux", + target_os = "hurd", + target_env = "newlib", + target_os = "cygwin" + ), + not(target_env = "ohos") + ), + link_name = "__xpg_strerror_r" + )] + fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t) -> c_int; + } + + let mut buf = [0 as c_char; TMPBUF_SZ]; + + let p = buf.as_mut_ptr(); + unsafe { + if strerror_r(errno as c_int, p, buf.len()) < 0 { + panic!("strerror_r failure"); + } + + let p = p as *const _; + // We can't always expect a UTF-8 environment. When we don't get that luxury, + // it's better to give a low-quality error message than none at all. + String::from_utf8_lossy(CStr::from_ptr(p).to_bytes()).into() + } +} diff --git a/library/std/src/sys/io/error/wasi.rs b/library/std/src/sys/io/error/wasi.rs new file mode 100644 index 000000000000..719fc0c900ad --- /dev/null +++ b/library/std/src/sys/io/error/wasi.rs @@ -0,0 +1,80 @@ +use crate::ffi::CStr; +use crate::io as std_io; + +unsafe extern "C" { + #[thread_local] + #[link_name = "errno"] + static mut libc_errno: libc::c_int; +} + +pub fn errno() -> i32 { + unsafe { libc_errno as i32 } +} + +pub fn set_errno(val: i32) { + unsafe { + libc_errno = val; + } +} + +#[inline] +pub fn is_interrupted(errno: i32) -> bool { + errno == libc::EINTR +} + +pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind { + use std_io::ErrorKind::*; + match errno as libc::c_int { + libc::E2BIG => ArgumentListTooLong, + libc::EADDRINUSE => AddrInUse, + libc::EADDRNOTAVAIL => AddrNotAvailable, + libc::EBUSY => ResourceBusy, + libc::ECONNABORTED => ConnectionAborted, + libc::ECONNREFUSED => ConnectionRefused, + libc::ECONNRESET => ConnectionReset, + libc::EDEADLK => Deadlock, + libc::EDQUOT => QuotaExceeded, + libc::EEXIST => AlreadyExists, + libc::EFBIG => FileTooLarge, + libc::EHOSTUNREACH => HostUnreachable, + libc::EINTR => Interrupted, + libc::EINVAL => InvalidInput, + libc::EISDIR => IsADirectory, + libc::ELOOP => FilesystemLoop, + libc::ENOENT => NotFound, + libc::ENOMEM => OutOfMemory, + libc::ENOSPC => StorageFull, + libc::ENOSYS => Unsupported, + libc::EMLINK => TooManyLinks, + libc::ENAMETOOLONG => InvalidFilename, + libc::ENETDOWN => NetworkDown, + libc::ENETUNREACH => NetworkUnreachable, + libc::ENOTCONN => NotConnected, + libc::ENOTDIR => NotADirectory, + libc::EPIPE => BrokenPipe, + libc::EROFS => ReadOnlyFilesystem, + libc::ESPIPE => NotSeekable, + libc::ESTALE => StaleNetworkFileHandle, + libc::ETIMEDOUT => TimedOut, + libc::ETXTBSY => ExecutableFileBusy, + libc::EXDEV => CrossesDevices, + libc::EINPROGRESS => InProgress, + libc::EOPNOTSUPP => Unsupported, + libc::EACCES | libc::EPERM => PermissionDenied, + libc::EWOULDBLOCK => WouldBlock, + + _ => Uncategorized, + } +} + +pub fn error_string(errno: i32) -> String { + let mut buf = [0 as libc::c_char; 1024]; + + let p = buf.as_mut_ptr(); + unsafe { + if libc::strerror_r(errno as libc::c_int, p, buf.len()) < 0 { + panic!("strerror_r failure"); + } + str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned() + } +} diff --git a/library/std/src/sys/io/error/windows.rs b/library/std/src/sys/io/error/windows.rs new file mode 100644 index 000000000000..e02197ac6775 --- /dev/null +++ b/library/std/src/sys/io/error/windows.rs @@ -0,0 +1,140 @@ +use crate::sys::pal::{api, c}; +use crate::{io, ptr}; + +pub fn errno() -> i32 { + api::get_last_error().code as i32 +} + +#[inline] +pub fn is_interrupted(_errno: i32) -> bool { + false +} + +pub fn decode_error_kind(errno: i32) -> io::ErrorKind { + use io::ErrorKind::*; + + match errno as u32 { + c::ERROR_ACCESS_DENIED => return PermissionDenied, + c::ERROR_ALREADY_EXISTS => return AlreadyExists, + c::ERROR_FILE_EXISTS => return AlreadyExists, + c::ERROR_BROKEN_PIPE => return BrokenPipe, + c::ERROR_FILE_NOT_FOUND + | c::ERROR_PATH_NOT_FOUND + | c::ERROR_INVALID_DRIVE + | c::ERROR_BAD_NETPATH + | c::ERROR_BAD_NET_NAME => return NotFound, + c::ERROR_NO_DATA => return BrokenPipe, + c::ERROR_INVALID_NAME | c::ERROR_BAD_PATHNAME => return InvalidFilename, + c::ERROR_INVALID_PARAMETER => return InvalidInput, + c::ERROR_NOT_ENOUGH_MEMORY | c::ERROR_OUTOFMEMORY => return OutOfMemory, + c::ERROR_SEM_TIMEOUT + | c::WAIT_TIMEOUT + | c::ERROR_DRIVER_CANCEL_TIMEOUT + | c::ERROR_OPERATION_ABORTED + | c::ERROR_SERVICE_REQUEST_TIMEOUT + | c::ERROR_COUNTER_TIMEOUT + | c::ERROR_TIMEOUT + | c::ERROR_RESOURCE_CALL_TIMED_OUT + | c::ERROR_CTX_MODEM_RESPONSE_TIMEOUT + | c::ERROR_CTX_CLIENT_QUERY_TIMEOUT + | c::FRS_ERR_SYSVOL_POPULATE_TIMEOUT + | c::ERROR_DS_TIMELIMIT_EXCEEDED + | c::DNS_ERROR_RECORD_TIMED_OUT + | c::ERROR_IPSEC_IKE_TIMED_OUT + | c::ERROR_RUNLEVEL_SWITCH_TIMEOUT + | c::ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT => return TimedOut, + c::ERROR_CALL_NOT_IMPLEMENTED => return Unsupported, + c::ERROR_HOST_UNREACHABLE => return HostUnreachable, + c::ERROR_NETWORK_UNREACHABLE => return NetworkUnreachable, + c::ERROR_DIRECTORY => return NotADirectory, + c::ERROR_DIRECTORY_NOT_SUPPORTED => return IsADirectory, + c::ERROR_DIR_NOT_EMPTY => return DirectoryNotEmpty, + c::ERROR_WRITE_PROTECT => return ReadOnlyFilesystem, + c::ERROR_DISK_FULL | c::ERROR_HANDLE_DISK_FULL => return StorageFull, + c::ERROR_SEEK_ON_DEVICE => return NotSeekable, + c::ERROR_DISK_QUOTA_EXCEEDED => return QuotaExceeded, + c::ERROR_FILE_TOO_LARGE => return FileTooLarge, + c::ERROR_BUSY => return ResourceBusy, + c::ERROR_POSSIBLE_DEADLOCK => return Deadlock, + c::ERROR_NOT_SAME_DEVICE => return CrossesDevices, + c::ERROR_TOO_MANY_LINKS => return TooManyLinks, + c::ERROR_FILENAME_EXCED_RANGE => return InvalidFilename, + c::ERROR_CANT_RESOLVE_FILENAME => return FilesystemLoop, + _ => {} + } + + match errno { + c::WSAEACCES => PermissionDenied, + c::WSAEADDRINUSE => AddrInUse, + c::WSAEADDRNOTAVAIL => AddrNotAvailable, + c::WSAECONNABORTED => ConnectionAborted, + c::WSAECONNREFUSED => ConnectionRefused, + c::WSAECONNRESET => ConnectionReset, + c::WSAEINVAL => InvalidInput, + c::WSAENOTCONN => NotConnected, + c::WSAEWOULDBLOCK => WouldBlock, + c::WSAETIMEDOUT => TimedOut, + c::WSAEHOSTUNREACH => HostUnreachable, + c::WSAENETDOWN => NetworkDown, + c::WSAENETUNREACH => NetworkUnreachable, + c::WSAEDQUOT => QuotaExceeded, + + _ => Uncategorized, + } +} + +/// Gets a detailed string description for the given error number. +pub fn error_string(mut errnum: i32) -> String { + let mut buf = [0 as c::WCHAR; 2048]; + + unsafe { + let mut module = ptr::null_mut(); + let mut flags = 0; + + // NTSTATUS errors may be encoded as HRESULT, which may returned from + // GetLastError. For more information about Windows error codes, see + // `[MS-ERREF]`: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/0642cb2f-2075-4469-918c-4441e69c548a + if (errnum & c::FACILITY_NT_BIT as i32) != 0 { + // format according to https://support.microsoft.com/en-us/help/259693 + const NTDLL_DLL: &[u16] = &[ + 'N' as _, 'T' as _, 'D' as _, 'L' as _, 'L' as _, '.' as _, 'D' as _, 'L' as _, + 'L' as _, 0, + ]; + module = c::GetModuleHandleW(NTDLL_DLL.as_ptr()); + + if !module.is_null() { + errnum ^= c::FACILITY_NT_BIT as i32; + flags = c::FORMAT_MESSAGE_FROM_HMODULE; + } + } + + let res = c::FormatMessageW( + flags | c::FORMAT_MESSAGE_FROM_SYSTEM | c::FORMAT_MESSAGE_IGNORE_INSERTS, + module, + errnum as u32, + 0, + buf.as_mut_ptr(), + buf.len() as u32, + ptr::null(), + ) as usize; + if res == 0 { + // Sometimes FormatMessageW can fail e.g., system doesn't like 0 as langId, + let fm_err = errno(); + return format!("OS Error {errnum} (FormatMessageW() returned error {fm_err})"); + } + + match String::from_utf16(&buf[..res]) { + Ok(mut msg) => { + // Trim trailing CRLF inserted by FormatMessageW + let len = msg.trim_end().len(); + msg.truncate(len); + msg + } + Err(..) => format!( + "OS Error {} (FormatMessageW() returned \ + invalid UTF-16)", + errnum + ), + } + } +} diff --git a/library/std/src/sys/io/error/xous.rs b/library/std/src/sys/io/error/xous.rs new file mode 100644 index 000000000000..2e9ea8e4f092 --- /dev/null +++ b/library/std/src/sys/io/error/xous.rs @@ -0,0 +1,17 @@ +use crate::os::xous::ffi::Error as XousError; + +pub fn errno() -> i32 { + 0 +} + +pub fn is_interrupted(_code: i32) -> bool { + false +} + +pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind { + crate::io::ErrorKind::Uncategorized +} + +pub fn error_string(errno: i32) -> String { + Into::::into(errno).to_string() +} diff --git a/library/std/src/sys/io/mod.rs b/library/std/src/sys/io/mod.rs index 4a5d6f8e27f2..b3587ab63696 100644 --- a/library/std/src/sys/io/mod.rs +++ b/library/std/src/sys/io/mod.rs @@ -1,5 +1,7 @@ #![forbid(unsafe_op_in_unsafe_fn)] +mod error; + mod io_slice { cfg_select! { any(target_family = "unix", target_os = "hermit", target_os = "solid_asp3", target_os = "trusty", target_os = "wasi") => { @@ -48,6 +50,19 @@ mod is_terminal { mod kernel_copy; +#[cfg_attr(not(target_os = "linux"), allow(unused_imports))] +#[cfg(all( + target_family = "unix", + not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "rtems")) +))] +pub use error::errno_location; +#[cfg_attr(not(target_os = "linux"), allow(unused_imports))] +#[cfg(any( + all(target_family = "unix", not(any(target_os = "vxworks", target_os = "rtems"))), + target_os = "wasi", +))] +pub use error::set_errno; +pub use error::{RawOsError, decode_error_kind, errno, error_string, is_interrupted}; pub use io_slice::{IoSlice, IoSliceMut}; pub use is_terminal::is_terminal; pub use kernel_copy::{CopyState, kernel_copy}; @@ -55,8 +70,3 @@ pub use kernel_copy::{CopyState, kernel_copy}; // Bare metal platforms usually have very small amounts of RAM // (in the order of hundreds of KB) pub const DEFAULT_BUF_SIZE: usize = if cfg!(target_os = "espidf") { 512 } else { 8 * 1024 }; - -pub type RawOsError = cfg_select! { - target_os = "uefi" => usize, - _ => i32, -}; diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs index d09ba97cfe01..5e20c0ffdfa6 100644 --- a/library/std/src/sys/net/connection/socket/unix.rs +++ b/library/std/src/sys/net/connection/socket/unix.rs @@ -151,7 +151,7 @@ impl Socket { loop { let result = unsafe { libc::connect(self.as_raw_fd(), addr.as_ptr(), len) }; if result.is_minus_one() { - let err = crate::sys::os::errno(); + let err = crate::sys::io::errno(); match err { libc::EINTR => continue, libc::EISCONN => return Ok(()), diff --git a/library/std/src/sys/net/hostname/unix.rs b/library/std/src/sys/net/hostname/unix.rs index bc6fa82a38f0..d444182f3fde 100644 --- a/library/std/src/sys/net/hostname/unix.rs +++ b/library/std/src/sys/net/hostname/unix.rs @@ -1,7 +1,7 @@ use crate::ffi::OsString; use crate::io; use crate::os::unix::ffi::OsStringExt; -use crate::sys::pal::os::errno; +use crate::sys::io::errno; pub fn hostname() -> io::Result { // Query the system for the maximum host name length. diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs index 0e1328a7972f..db64f8d882e2 100644 --- a/library/std/src/sys/pal/hermit/mod.rs +++ b/library/std/src/sys/pal/hermit/mod.rs @@ -75,32 +75,6 @@ pub unsafe extern "C" fn runtime_entry( } } -#[inline] -pub(crate) fn is_interrupted(errno: i32) -> bool { - errno == hermit_abi::errno::EINTR -} - -pub fn decode_error_kind(errno: i32) -> io::ErrorKind { - match errno { - hermit_abi::errno::EACCES => io::ErrorKind::PermissionDenied, - hermit_abi::errno::EADDRINUSE => io::ErrorKind::AddrInUse, - hermit_abi::errno::EADDRNOTAVAIL => io::ErrorKind::AddrNotAvailable, - hermit_abi::errno::EAGAIN => io::ErrorKind::WouldBlock, - hermit_abi::errno::ECONNABORTED => io::ErrorKind::ConnectionAborted, - hermit_abi::errno::ECONNREFUSED => io::ErrorKind::ConnectionRefused, - hermit_abi::errno::ECONNRESET => io::ErrorKind::ConnectionReset, - hermit_abi::errno::EEXIST => io::ErrorKind::AlreadyExists, - hermit_abi::errno::EINTR => io::ErrorKind::Interrupted, - hermit_abi::errno::EINVAL => io::ErrorKind::InvalidInput, - hermit_abi::errno::ENOENT => io::ErrorKind::NotFound, - hermit_abi::errno::ENOTCONN => io::ErrorKind::NotConnected, - hermit_abi::errno::EPERM => io::ErrorKind::PermissionDenied, - hermit_abi::errno::EPIPE => io::ErrorKind::BrokenPipe, - hermit_abi::errno::ETIMEDOUT => io::ErrorKind::TimedOut, - _ => io::ErrorKind::Uncategorized, - } -} - #[doc(hidden)] pub trait IsNegative { fn is_negative(&self) -> bool; @@ -131,12 +105,7 @@ impl IsNegative for i32 { impl_is_negative! { i8 i16 i64 isize } pub fn cvt(t: T) -> io::Result { - if t.is_negative() { - let e = decode_error_kind(t.negate()); - Err(io::Error::from(e)) - } else { - Ok(t) - } + if t.is_negative() { Err(io::Error::from_raw_os_error(t.negate())) } else { Ok(t) } } pub fn cvt_r(mut f: F) -> io::Result diff --git a/library/std/src/sys/pal/hermit/os.rs b/library/std/src/sys/pal/hermit/os.rs index 9681964ed9b2..48a7cdcd2f76 100644 --- a/library/std/src/sys/pal/hermit/os.rs +++ b/library/std/src/sys/pal/hermit/os.rs @@ -5,14 +5,6 @@ use crate::path::{self, PathBuf}; use crate::sys::unsupported; use crate::{fmt, io}; -pub fn errno() -> i32 { - unsafe { hermit_abi::get_errno() } -} - -pub fn error_string(errno: i32) -> String { - hermit_abi::error_string(errno).to_string() -} - pub fn getcwd() -> io::Result { Ok(PathBuf::from("/")) } diff --git a/library/std/src/sys/pal/motor/mod.rs b/library/std/src/sys/pal/motor/mod.rs index 016fbe5c154c..e5b99cea01d5 100644 --- a/library/std/src/sys/pal/motor/mod.rs +++ b/library/std/src/sys/pal/motor/mod.rs @@ -44,45 +44,6 @@ pub fn unsupported_err() -> io::Error { io::Error::UNSUPPORTED_PLATFORM } -pub fn is_interrupted(_code: io::RawOsError) -> bool { - false // Motor OS doesn't have signals. -} - -pub fn decode_error_kind(code: io::RawOsError) -> io::ErrorKind { - use moto_rt::error::*; - - if code < 0 || code > u16::MAX.into() { - return io::ErrorKind::Uncategorized; - } - - let error = moto_rt::Error::from(code as moto_rt::ErrorCode); - - match error { - moto_rt::Error::Unspecified => io::ErrorKind::Uncategorized, - moto_rt::Error::Unknown => io::ErrorKind::Uncategorized, - moto_rt::Error::NotReady => io::ErrorKind::WouldBlock, - moto_rt::Error::NotImplemented => io::ErrorKind::Unsupported, - moto_rt::Error::VersionTooHigh => io::ErrorKind::Unsupported, - moto_rt::Error::VersionTooLow => io::ErrorKind::Unsupported, - moto_rt::Error::InvalidArgument => io::ErrorKind::InvalidInput, - moto_rt::Error::OutOfMemory => io::ErrorKind::OutOfMemory, - moto_rt::Error::NotAllowed => io::ErrorKind::PermissionDenied, - moto_rt::Error::NotFound => io::ErrorKind::NotFound, - moto_rt::Error::InternalError => io::ErrorKind::Other, - moto_rt::Error::TimedOut => io::ErrorKind::TimedOut, - moto_rt::Error::AlreadyInUse => io::ErrorKind::AlreadyExists, - moto_rt::Error::UnexpectedEof => io::ErrorKind::UnexpectedEof, - moto_rt::Error::InvalidFilename => io::ErrorKind::InvalidFilename, - moto_rt::Error::NotADirectory => io::ErrorKind::NotADirectory, - moto_rt::Error::BadHandle => io::ErrorKind::InvalidInput, - moto_rt::Error::FileTooLarge => io::ErrorKind::FileTooLarge, - moto_rt::Error::NotConnected => io::ErrorKind::NotConnected, - moto_rt::Error::StorageFull => io::ErrorKind::StorageFull, - moto_rt::Error::InvalidData => io::ErrorKind::InvalidData, - _ => io::ErrorKind::Uncategorized, - } -} - pub fn abort_internal() -> ! { core::intrinsics::abort(); } diff --git a/library/std/src/sys/pal/motor/os.rs b/library/std/src/sys/pal/motor/os.rs index 0367c905b453..cdf66e3958db 100644 --- a/library/std/src/sys/pal/motor/os.rs +++ b/library/std/src/sys/pal/motor/os.rs @@ -4,37 +4,8 @@ use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; use crate::os::motor::ffi::OsStrExt; use crate::path::{self, PathBuf}; -use crate::sys::io::RawOsError; use crate::{fmt, io}; -pub fn errno() -> RawOsError { - // Not used in Motor OS because it is ambiguous: Motor OS - // is micro-kernel-based, and I/O happens via a shared-memory - // ring buffer, so an I/O operation that on a unix is a syscall - // may involve no sycalls on Motor OS at all, or a syscall - // that e.g. waits for a notification from the I/O driver - // (sys-io); and the wait syscall may succeed, but the - // driver may report an I/O error; or a bunch of results - // for several I/O operations, some successful and some - // not. - // - // Also I/O operations in a Motor OS process are handled by a - // separate runtime background/I/O thread, so it is really hard - // to define what "last system error in the current thread" - // actually means. - let error_code: moto_rt::ErrorCode = moto_rt::Error::Unknown.into(); - error_code.into() -} - -pub fn error_string(errno: RawOsError) -> String { - let error: moto_rt::Error = match errno { - x if x < 0 => moto_rt::Error::Unknown, - x if x > u16::MAX.into() => moto_rt::Error::Unknown, - x => (x as moto_rt::ErrorCode).into(), /* u16 */ - }; - format!("{}", error) -} - pub fn getcwd() -> io::Result { moto_rt::fs::getcwd().map(PathBuf::from).map_err(map_motor_error) } diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs index a067480508c7..7f1c81a0ff7b 100644 --- a/library/std/src/sys/pal/sgx/mod.rs +++ b/library/std/src/sys/pal/sgx/mod.rs @@ -54,56 +54,6 @@ pub fn sgx_ineffective(v: T) -> io::Result { } } -#[inline] -pub fn is_interrupted(code: i32) -> bool { - code == fortanix_sgx_abi::Error::Interrupted as _ -} - -pub fn decode_error_kind(code: i32) -> io::ErrorKind { - use fortanix_sgx_abi::Error; - - // FIXME: not sure how to make sure all variants of Error are covered - if code == Error::NotFound as _ { - io::ErrorKind::NotFound - } else if code == Error::PermissionDenied as _ { - io::ErrorKind::PermissionDenied - } else if code == Error::ConnectionRefused as _ { - io::ErrorKind::ConnectionRefused - } else if code == Error::ConnectionReset as _ { - io::ErrorKind::ConnectionReset - } else if code == Error::ConnectionAborted as _ { - io::ErrorKind::ConnectionAborted - } else if code == Error::NotConnected as _ { - io::ErrorKind::NotConnected - } else if code == Error::AddrInUse as _ { - io::ErrorKind::AddrInUse - } else if code == Error::AddrNotAvailable as _ { - io::ErrorKind::AddrNotAvailable - } else if code == Error::BrokenPipe as _ { - io::ErrorKind::BrokenPipe - } else if code == Error::AlreadyExists as _ { - io::ErrorKind::AlreadyExists - } else if code == Error::WouldBlock as _ { - io::ErrorKind::WouldBlock - } else if code == Error::InvalidInput as _ { - io::ErrorKind::InvalidInput - } else if code == Error::InvalidData as _ { - io::ErrorKind::InvalidData - } else if code == Error::TimedOut as _ { - io::ErrorKind::TimedOut - } else if code == Error::WriteZero as _ { - io::ErrorKind::WriteZero - } else if code == Error::Interrupted as _ { - io::ErrorKind::Interrupted - } else if code == Error::Other as _ { - io::ErrorKind::Uncategorized - } else if code == Error::UnexpectedEof as _ { - io::ErrorKind::UnexpectedEof - } else { - io::ErrorKind::Uncategorized - } -} - pub fn abort_internal() -> ! { abi::usercalls::exit(true) } diff --git a/library/std/src/sys/pal/sgx/os.rs b/library/std/src/sys/pal/sgx/os.rs index 28d79963ac87..ba47af7ff88d 100644 --- a/library/std/src/sys/pal/sgx/os.rs +++ b/library/std/src/sys/pal/sgx/os.rs @@ -1,25 +1,9 @@ -use fortanix_sgx_abi::{Error, RESULT_SUCCESS}; - use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; use crate::path::{self, PathBuf}; -use crate::sys::{decode_error_kind, sgx_ineffective, unsupported}; +use crate::sys::{sgx_ineffective, unsupported}; use crate::{fmt, io}; -pub fn errno() -> i32 { - RESULT_SUCCESS -} - -pub fn error_string(errno: i32) -> String { - if errno == RESULT_SUCCESS { - "operation successful".into() - } else if ((Error::UserRangeStart as _)..=(Error::UserRangeEnd as _)).contains(&errno) { - format!("user-specified error {errno:08x}") - } else { - decode_error_kind(errno).as_str().into() - } -} - pub fn getcwd() -> io::Result { unsupported() } diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs index 01477c7dc5e9..4eec12dacd7c 100644 --- a/library/std/src/sys/pal/solid/mod.rs +++ b/library/std/src/sys/pal/solid/mod.rs @@ -38,15 +38,6 @@ pub fn unsupported_err() -> io::Error { io::Error::UNSUPPORTED_PLATFORM } -#[inline] -pub fn is_interrupted(code: i32) -> bool { - crate::sys::net::is_interrupted(code) -} - -pub fn decode_error_kind(code: i32) -> io::ErrorKind { - error::decode_error_kind(code) -} - #[inline] pub fn abort_internal() -> ! { unsafe { libc::abort() } diff --git a/library/std/src/sys/pal/solid/os.rs b/library/std/src/sys/pal/solid/os.rs index cb6e2cbceae6..c336a1042da4 100644 --- a/library/std/src/sys/pal/solid/os.rs +++ b/library/std/src/sys/pal/solid/os.rs @@ -1,4 +1,4 @@ -use super::{error, itron, unsupported}; +use super::{itron, unsupported}; use crate::ffi::{OsStr, OsString}; use crate::path::{self, PathBuf}; use crate::{fmt, io}; @@ -11,14 +11,6 @@ impl itron::error::ItronError { } } -pub fn errno() -> i32 { - 0 -} - -pub fn error_string(errno: i32) -> String { - if let Some(name) = error::error_name(errno) { name.to_owned() } else { format!("{errno}") } -} - pub fn getcwd() -> io::Result { unsupported() } diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs index 627096b11c38..d40c10663fd1 100644 --- a/library/std/src/sys/pal/teeos/mod.rs +++ b/library/std/src/sys/pal/teeos/mod.rs @@ -38,61 +38,6 @@ pub unsafe fn cleanup() { // stack_overflow::cleanup(); } -#[inline] -pub(crate) fn is_interrupted(errno: i32) -> bool { - errno == libc::EINTR -} - -// Note: code below is 1:1 copied from unix/mod.rs -pub fn decode_error_kind(errno: i32) -> io::ErrorKind { - use io::ErrorKind::*; - match errno as libc::c_int { - libc::E2BIG => ArgumentListTooLong, - libc::EADDRINUSE => AddrInUse, - libc::EADDRNOTAVAIL => AddrNotAvailable, - libc::EBUSY => ResourceBusy, - libc::ECONNABORTED => ConnectionAborted, - libc::ECONNREFUSED => ConnectionRefused, - libc::ECONNRESET => ConnectionReset, - libc::EDEADLK => Deadlock, - libc::EDQUOT => QuotaExceeded, - libc::EEXIST => AlreadyExists, - libc::EFBIG => FileTooLarge, - libc::EHOSTUNREACH => HostUnreachable, - libc::EINTR => Interrupted, - libc::EINVAL => InvalidInput, - libc::EISDIR => IsADirectory, - libc::ELOOP => FilesystemLoop, - libc::ENOENT => NotFound, - libc::ENOMEM => OutOfMemory, - libc::ENOSPC => StorageFull, - libc::ENOSYS => Unsupported, - libc::EMLINK => TooManyLinks, - libc::ENAMETOOLONG => InvalidFilename, - libc::ENETDOWN => NetworkDown, - libc::ENETUNREACH => NetworkUnreachable, - libc::ENOTCONN => NotConnected, - libc::ENOTDIR => NotADirectory, - libc::ENOTEMPTY => DirectoryNotEmpty, - libc::EPIPE => BrokenPipe, - libc::EROFS => ReadOnlyFilesystem, - libc::ESPIPE => NotSeekable, - libc::ESTALE => StaleNetworkFileHandle, - libc::ETIMEDOUT => TimedOut, - libc::ETXTBSY => ExecutableFileBusy, - libc::EXDEV => CrossesDevices, - - libc::EACCES | libc::EPERM => PermissionDenied, - - // These two constants can have the same value on some systems, - // but different values on others, so we can't use a match - // clause - x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => WouldBlock, - - _ => Uncategorized, - } -} - #[doc(hidden)] pub trait IsMinusOne { fn is_minus_one(&self) -> bool; diff --git a/library/std/src/sys/pal/teeos/os.rs b/library/std/src/sys/pal/teeos/os.rs index 512b3e2885bf..a4b1d3c6ae67 100644 --- a/library/std/src/sys/pal/teeos/os.rs +++ b/library/std/src/sys/pal/teeos/os.rs @@ -7,10 +7,6 @@ use crate::ffi::{OsStr, OsString}; use crate::path::PathBuf; use crate::{fmt, io, path}; -pub fn errno() -> i32 { - unsafe { (*libc::__errno_location()) as i32 } -} - // Hardcoded to return 4096, since `sysconf` is only implemented as a stub. pub fn page_size() -> usize { // unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }; @@ -19,10 +15,6 @@ pub fn page_size() -> usize { // Everything below are stubs and copied from unsupported.rs -pub fn error_string(_errno: i32) -> String { - "error string unimplemented".to_string() -} - pub fn getcwd() -> io::Result { unsupported() } diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs index e2f99d6751f5..b181d78c2345 100644 --- a/library/std/src/sys/pal/uefi/mod.rs +++ b/library/std/src/sys/pal/uefi/mod.rs @@ -83,52 +83,6 @@ pub const fn unsupported_err() -> io::Error { io::const_error!(io::ErrorKind::Unsupported, "operation not supported on UEFI") } -pub fn decode_error_kind(code: io::RawOsError) -> io::ErrorKind { - use r_efi::efi::Status; - - match r_efi::efi::Status::from_usize(code) { - Status::ALREADY_STARTED - | Status::COMPROMISED_DATA - | Status::CONNECTION_FIN - | Status::CRC_ERROR - | Status::DEVICE_ERROR - | Status::END_OF_MEDIA - | Status::HTTP_ERROR - | Status::ICMP_ERROR - | Status::INCOMPATIBLE_VERSION - | Status::LOAD_ERROR - | Status::MEDIA_CHANGED - | Status::NO_MAPPING - | Status::NO_MEDIA - | Status::NOT_STARTED - | Status::PROTOCOL_ERROR - | Status::PROTOCOL_UNREACHABLE - | Status::TFTP_ERROR - | Status::VOLUME_CORRUPTED => io::ErrorKind::Other, - Status::BAD_BUFFER_SIZE | Status::INVALID_LANGUAGE => io::ErrorKind::InvalidData, - Status::ABORTED => io::ErrorKind::ConnectionAborted, - Status::ACCESS_DENIED => io::ErrorKind::PermissionDenied, - Status::BUFFER_TOO_SMALL => io::ErrorKind::FileTooLarge, - Status::CONNECTION_REFUSED => io::ErrorKind::ConnectionRefused, - Status::CONNECTION_RESET => io::ErrorKind::ConnectionReset, - Status::END_OF_FILE => io::ErrorKind::UnexpectedEof, - Status::HOST_UNREACHABLE => io::ErrorKind::HostUnreachable, - Status::INVALID_PARAMETER => io::ErrorKind::InvalidInput, - Status::IP_ADDRESS_CONFLICT => io::ErrorKind::AddrInUse, - Status::NETWORK_UNREACHABLE => io::ErrorKind::NetworkUnreachable, - Status::NO_RESPONSE => io::ErrorKind::HostUnreachable, - Status::NOT_FOUND => io::ErrorKind::NotFound, - Status::NOT_READY => io::ErrorKind::ResourceBusy, - Status::OUT_OF_RESOURCES => io::ErrorKind::OutOfMemory, - Status::SECURITY_VIOLATION => io::ErrorKind::PermissionDenied, - Status::TIMEOUT => io::ErrorKind::TimedOut, - Status::UNSUPPORTED => io::ErrorKind::Unsupported, - Status::VOLUME_FULL => io::ErrorKind::StorageFull, - Status::WRITE_PROTECTED => io::ErrorKind::ReadOnlyFilesystem, - _ => io::ErrorKind::Uncategorized, - } -} - pub fn abort_internal() -> ! { if let Some(exit_boot_service_event) = NonNull::new(EXIT_BOOT_SERVICE_EVENT.load(Ordering::Acquire)) @@ -158,7 +112,3 @@ pub fn abort_internal() -> ! { extern "efiapi" fn exit_boot_service_handler(_e: r_efi::efi::Event, _ctx: *mut crate::ffi::c_void) { uefi::env::disable_boot_services(); } - -pub fn is_interrupted(_code: io::RawOsError) -> bool { - false -} diff --git a/library/std/src/sys/pal/uefi/os.rs b/library/std/src/sys/pal/uefi/os.rs index 5593e195178d..178f7f506341 100644 --- a/library/std/src/sys/pal/uefi/os.rs +++ b/library/std/src/sys/pal/uefi/os.rs @@ -9,59 +9,6 @@ use crate::path::{self, PathBuf}; use crate::ptr::NonNull; use crate::{fmt, io}; -pub fn errno() -> io::RawOsError { - 0 -} - -pub fn error_string(errno: io::RawOsError) -> String { - // Keep the List in Alphabetical Order - // The Messages are taken from UEFI Specification Appendix D - Status Codes - #[rustfmt::skip] - let msg = match r_efi::efi::Status::from_usize(errno) { - Status::ABORTED => "The operation was aborted.", - Status::ACCESS_DENIED => "Access was denied.", - Status::ALREADY_STARTED => "The protocol has already been started.", - Status::BAD_BUFFER_SIZE => "The buffer was not the proper size for the request.", - Status::BUFFER_TOO_SMALL => "The buffer is not large enough to hold the requested data. The required buffer size is returned in the appropriate parameter when this error occurs.", - Status::COMPROMISED_DATA => "The security status of the data is unknown or compromised and the data must be updated or replaced to restore a valid security status.", - Status::CONNECTION_FIN => "The receiving operation fails because the communication peer has closed the connection and there is no more data in the receive buffer of the instance.", - Status::CONNECTION_REFUSED => "The receiving or transmission operation fails because this connection is refused.", - Status::CONNECTION_RESET => "The connect fails because the connection is reset either by instance itself or the communication peer.", - Status::CRC_ERROR => "A CRC error was detected.", - Status::DEVICE_ERROR => "The physical device reported an error while attempting the operation.", - Status::END_OF_FILE => "The end of the file was reached.", - Status::END_OF_MEDIA => "Beginning or end of media was reached", - Status::HOST_UNREACHABLE => "The remote host is not reachable.", - Status::HTTP_ERROR => "A HTTP error occurred during the network operation.", - Status::ICMP_ERROR => "An ICMP error occurred during the network operation.", - Status::INCOMPATIBLE_VERSION => "The function encountered an internal version that was incompatible with a version requested by the caller.", - Status::INVALID_LANGUAGE => "The language specified was invalid.", - Status::INVALID_PARAMETER => "A parameter was incorrect.", - Status::IP_ADDRESS_CONFLICT => "There is an address conflict address allocation", - Status::LOAD_ERROR => "The image failed to load.", - Status::MEDIA_CHANGED => "The medium in the device has changed since the last access.", - Status::NETWORK_UNREACHABLE => "The network containing the remote host is not reachable.", - Status::NO_MAPPING => "A mapping to a device does not exist.", - Status::NO_MEDIA => "The device does not contain any medium to perform the operation.", - Status::NO_RESPONSE => "The server was not found or did not respond to the request.", - Status::NOT_FOUND => "The item was not found.", - Status::NOT_READY => "There is no data pending upon return.", - Status::NOT_STARTED => "The protocol has not been started.", - Status::OUT_OF_RESOURCES => "A resource has run out.", - Status::PROTOCOL_ERROR => "A protocol error occurred during the network operation.", - Status::PROTOCOL_UNREACHABLE => "An ICMP protocol unreachable error is received.", - Status::SECURITY_VIOLATION => "The function was not performed due to a security violation.", - Status::TFTP_ERROR => "A TFTP error occurred during the network operation.", - Status::TIMEOUT => "The timeout time expired.", - Status::UNSUPPORTED => "The operation is not supported.", - Status::VOLUME_FULL => "There is no more space on the file system.", - Status::VOLUME_CORRUPTED => "An inconstancy was detected on the file system causing the operating to fail.", - Status::WRITE_PROTECTED => "The device cannot be written to.", - _ => return format!("Status: {errno}"), - }; - msg.to_owned() -} - pub fn getcwd() -> io::Result { match helpers::open_shell() { Some(shell) => { diff --git a/library/std/src/sys/pal/unix/futex.rs b/library/std/src/sys/pal/unix/futex.rs index 265067d84d50..2948d3d594ea 100644 --- a/library/std/src/sys/pal/unix/futex.rs +++ b/library/std/src/sys/pal/unix/futex.rs @@ -86,7 +86,7 @@ pub fn futex_wait(futex: &Atomic, expected: u32, timeout: Option) } }; - match (r < 0).then(super::os::errno) { + match (r < 0).then(crate::sys::io::errno) { Some(libc::ETIMEDOUT) => return false, Some(libc::EINTR) => continue, _ => return true, @@ -167,7 +167,7 @@ pub fn futex_wait(futex: &Atomic, expected: u32, timeout: Option) ) }; - r == 0 || super::os::errno() != libc::ETIMEDOUT + r == 0 || crate::sys::io::errno() != libc::ETIMEDOUT } #[cfg(target_os = "openbsd")] @@ -210,7 +210,7 @@ pub fn futex_wait(futex: &Atomic, expected: u32, timeout: Option) libc::umtx_sleep(futex as *const Atomic as *const i32, expected as i32, timeout_ms) }; - r == 0 || super::os::errno() != libc::ETIMEDOUT + r == 0 || crate::sys::io::errno() != libc::ETIMEDOUT } // DragonflyBSD doesn't tell us how many threads are woken up, so this always returns false. diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index f24898671af8..6127bb98f80e 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -91,7 +91,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { target_vendor = "apple", )))] 'poll: { - use crate::sys::os::errno; + use crate::sys::io::errno; let pfds: &mut [_] = &mut [ libc::pollfd { fd: 0, events: 0, revents: 0 }, libc::pollfd { fd: 1, events: 0, revents: 0 }, @@ -135,7 +135,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { target_os = "vita", )))] { - use crate::sys::os::errno; + use crate::sys::io::errno; for fd in 0..3 { if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF { open_devnull(); @@ -224,63 +224,6 @@ pub unsafe fn cleanup() { #[allow(unused_imports)] pub use libc::signal; -#[inline] -pub(crate) fn is_interrupted(errno: i32) -> bool { - errno == libc::EINTR -} - -pub fn decode_error_kind(errno: i32) -> io::ErrorKind { - use io::ErrorKind::*; - match errno as libc::c_int { - libc::E2BIG => ArgumentListTooLong, - libc::EADDRINUSE => AddrInUse, - libc::EADDRNOTAVAIL => AddrNotAvailable, - libc::EBUSY => ResourceBusy, - libc::ECONNABORTED => ConnectionAborted, - libc::ECONNREFUSED => ConnectionRefused, - libc::ECONNRESET => ConnectionReset, - libc::EDEADLK => Deadlock, - libc::EDQUOT => QuotaExceeded, - libc::EEXIST => AlreadyExists, - libc::EFBIG => FileTooLarge, - libc::EHOSTUNREACH => HostUnreachable, - libc::EINTR => Interrupted, - libc::EINVAL => InvalidInput, - libc::EISDIR => IsADirectory, - libc::ELOOP => FilesystemLoop, - libc::ENOENT => NotFound, - libc::ENOMEM => OutOfMemory, - libc::ENOSPC => StorageFull, - libc::ENOSYS => Unsupported, - libc::EMLINK => TooManyLinks, - libc::ENAMETOOLONG => InvalidFilename, - libc::ENETDOWN => NetworkDown, - libc::ENETUNREACH => NetworkUnreachable, - libc::ENOTCONN => NotConnected, - libc::ENOTDIR => NotADirectory, - #[cfg(not(target_os = "aix"))] - libc::ENOTEMPTY => DirectoryNotEmpty, - libc::EPIPE => BrokenPipe, - libc::EROFS => ReadOnlyFilesystem, - libc::ESPIPE => NotSeekable, - libc::ESTALE => StaleNetworkFileHandle, - libc::ETIMEDOUT => TimedOut, - libc::ETXTBSY => ExecutableFileBusy, - libc::EXDEV => CrossesDevices, - libc::EINPROGRESS => InProgress, - libc::EOPNOTSUPP => Unsupported, - - libc::EACCES | libc::EPERM => PermissionDenied, - - // These two constants can have the same value on some systems, - // but different values on others, so we can't use a match - // clause - x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => WouldBlock, - - _ => Uncategorized, - } -} - #[doc(hidden)] pub trait IsMinusOne { fn is_minus_one(&self) -> bool; diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index ef3b4a02f8ae..b8280a8f29a0 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -14,135 +14,8 @@ use crate::sys::cvt; use crate::sys::helpers::run_path_with_cstr; use crate::{fmt, io, iter, mem, ptr, slice, str}; -const TMPBUF_SZ: usize = 128; - const PATH_SEPARATOR: u8 = b':'; -unsafe extern "C" { - #[cfg(not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "rtems")))] - #[cfg_attr( - any( - target_os = "linux", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "l4re", - target_os = "hurd", - ), - link_name = "__errno_location" - )] - #[cfg_attr( - any( - target_os = "netbsd", - target_os = "openbsd", - target_os = "cygwin", - target_os = "android", - target_os = "redox", - target_os = "nuttx", - target_env = "newlib" - ), - link_name = "__errno" - )] - #[cfg_attr(any(target_os = "solaris", target_os = "illumos"), link_name = "___errno")] - #[cfg_attr(target_os = "nto", link_name = "__get_errno_ptr")] - #[cfg_attr(any(target_os = "freebsd", target_vendor = "apple"), link_name = "__error")] - #[cfg_attr(target_os = "haiku", link_name = "_errnop")] - #[cfg_attr(target_os = "aix", link_name = "_Errno")] - // SAFETY: this will always return the same pointer on a given thread. - #[unsafe(ffi_const)] - pub safe fn errno_location() -> *mut c_int; -} - -/// Returns the platform-specific value of errno -#[cfg(not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "rtems")))] -#[inline] -pub fn errno() -> i32 { - unsafe { (*errno_location()) as i32 } -} - -/// Sets the platform-specific value of errno -// needed for readdir and syscall! -#[cfg(all(not(target_os = "dragonfly"), not(target_os = "vxworks"), not(target_os = "rtems")))] -#[allow(dead_code)] // but not all target cfgs actually end up using it -#[inline] -pub fn set_errno(e: i32) { - unsafe { *errno_location() = e as c_int } -} - -#[cfg(target_os = "vxworks")] -#[inline] -pub fn errno() -> i32 { - unsafe { libc::errnoGet() } -} - -#[cfg(target_os = "rtems")] -#[inline] -pub fn errno() -> i32 { - unsafe extern "C" { - #[thread_local] - static _tls_errno: c_int; - } - - unsafe { _tls_errno as i32 } -} - -#[cfg(target_os = "dragonfly")] -#[inline] -pub fn errno() -> i32 { - unsafe extern "C" { - #[thread_local] - static errno: c_int; - } - - unsafe { errno as i32 } -} - -#[cfg(target_os = "dragonfly")] -#[allow(dead_code)] -#[inline] -pub fn set_errno(e: i32) { - unsafe extern "C" { - #[thread_local] - static mut errno: c_int; - } - - unsafe { - errno = e; - } -} - -/// Gets a detailed string description for the given error number. -pub fn error_string(errno: i32) -> String { - unsafe extern "C" { - #[cfg_attr( - all( - any( - target_os = "linux", - target_os = "hurd", - target_env = "newlib", - target_os = "cygwin" - ), - not(target_env = "ohos") - ), - link_name = "__xpg_strerror_r" - )] - fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t) -> c_int; - } - - let mut buf = [0 as c_char; TMPBUF_SZ]; - - let p = buf.as_mut_ptr(); - unsafe { - if strerror_r(errno as c_int, p, buf.len()) < 0 { - panic!("strerror_r failure"); - } - - let p = p as *const _; - // We can't always expect a UTF-8 environment. When we don't get that luxury, - // it's better to give a low-quality error message than none at all. - String::from_utf8_lossy(CStr::from_ptr(p).to_bytes()).into() - } -} - #[cfg(target_os = "espidf")] pub fn getcwd() -> io::Result { Ok(PathBuf::from("/")) diff --git a/library/std/src/sys/pal/unix/stack_overflow/thread_info.rs b/library/std/src/sys/pal/unix/stack_overflow/thread_info.rs index 42eb0cd9a61a..45e2f09f303c 100644 --- a/library/std/src/sys/pal/unix/stack_overflow/thread_info.rs +++ b/library/std/src/sys/pal/unix/stack_overflow/thread_info.rs @@ -29,7 +29,7 @@ use crate::hint::spin_loop; use crate::ops::Range; use crate::sync::Mutex; use crate::sync::atomic::{AtomicUsize, Ordering}; -use crate::sys::os::errno_location; +use crate::sys::io::errno_location; pub struct ThreadInfo { pub tid: u64, diff --git a/library/std/src/sys/pal/unsupported/common.rs b/library/std/src/sys/pal/unsupported/common.rs index 34a766683830..d94b9015d0f5 100644 --- a/library/std/src/sys/pal/unsupported/common.rs +++ b/library/std/src/sys/pal/unsupported/common.rs @@ -16,14 +16,6 @@ pub fn unsupported_err() -> std_io::Error { std_io::Error::UNSUPPORTED_PLATFORM } -pub fn is_interrupted(_code: i32) -> bool { - false -} - -pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind { - crate::io::ErrorKind::Uncategorized -} - pub fn abort_internal() -> ! { core::intrinsics::abort(); } diff --git a/library/std/src/sys/pal/unsupported/os.rs b/library/std/src/sys/pal/unsupported/os.rs index 13d2a2044f48..cb925ef4348d 100644 --- a/library/std/src/sys/pal/unsupported/os.rs +++ b/library/std/src/sys/pal/unsupported/os.rs @@ -4,14 +4,6 @@ use crate::marker::PhantomData; use crate::path::{self, PathBuf}; use crate::{fmt, io}; -pub fn errno() -> i32 { - 0 -} - -pub fn error_string(_errno: i32) -> String { - "operation successful".to_string() -} - pub fn getcwd() -> io::Result { unsupported() } diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs index 049b435905d4..0abfc2fd7986 100644 --- a/library/std/src/sys/pal/vexos/mod.rs +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -5,9 +5,7 @@ pub mod time; #[path = "../unsupported/common.rs"] mod unsupported_common; -pub use unsupported_common::{ - decode_error_kind, init, is_interrupted, unsupported, unsupported_err, -}; +pub use unsupported_common::{init, unsupported, unsupported_err}; use crate::arch::global_asm; use crate::ptr; diff --git a/library/std/src/sys/pal/vexos/os.rs b/library/std/src/sys/pal/vexos/os.rs index 405f7c918f4a..303b452a078f 100644 --- a/library/std/src/sys/pal/vexos/os.rs +++ b/library/std/src/sys/pal/vexos/os.rs @@ -2,8 +2,8 @@ #[path = "../unsupported/os.rs"] mod unsupported_os; pub use unsupported_os::{ - JoinPathsError, SplitPaths, chdir, current_exe, errno, error_string, getcwd, getpid, home_dir, - join_paths, split_paths, temp_dir, + JoinPathsError, SplitPaths, chdir, current_exe, getcwd, getpid, home_dir, join_paths, + split_paths, temp_dir, }; pub use super::unsupported; diff --git a/library/std/src/sys/pal/wasi/helpers.rs b/library/std/src/sys/pal/wasi/helpers.rs index 6bc41d469584..4f2eb1148f0b 100644 --- a/library/std/src/sys/pal/wasi/helpers.rs +++ b/library/std/src/sys/pal/wasi/helpers.rs @@ -1,63 +1,11 @@ #![forbid(unsafe_op_in_unsafe_fn)] -use crate::io as std_io; - -#[inline] -pub fn is_interrupted(errno: i32) -> bool { - errno == libc::EINTR -} - -pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind { - use std_io::ErrorKind::*; - match errno as libc::c_int { - libc::E2BIG => ArgumentListTooLong, - libc::EADDRINUSE => AddrInUse, - libc::EADDRNOTAVAIL => AddrNotAvailable, - libc::EBUSY => ResourceBusy, - libc::ECONNABORTED => ConnectionAborted, - libc::ECONNREFUSED => ConnectionRefused, - libc::ECONNRESET => ConnectionReset, - libc::EDEADLK => Deadlock, - libc::EDQUOT => QuotaExceeded, - libc::EEXIST => AlreadyExists, - libc::EFBIG => FileTooLarge, - libc::EHOSTUNREACH => HostUnreachable, - libc::EINTR => Interrupted, - libc::EINVAL => InvalidInput, - libc::EISDIR => IsADirectory, - libc::ELOOP => FilesystemLoop, - libc::ENOENT => NotFound, - libc::ENOMEM => OutOfMemory, - libc::ENOSPC => StorageFull, - libc::ENOSYS => Unsupported, - libc::EMLINK => TooManyLinks, - libc::ENAMETOOLONG => InvalidFilename, - libc::ENETDOWN => NetworkDown, - libc::ENETUNREACH => NetworkUnreachable, - libc::ENOTCONN => NotConnected, - libc::ENOTDIR => NotADirectory, - libc::EPIPE => BrokenPipe, - libc::EROFS => ReadOnlyFilesystem, - libc::ESPIPE => NotSeekable, - libc::ESTALE => StaleNetworkFileHandle, - libc::ETIMEDOUT => TimedOut, - libc::ETXTBSY => ExecutableFileBusy, - libc::EXDEV => CrossesDevices, - libc::EINPROGRESS => InProgress, - libc::EOPNOTSUPP => Unsupported, - libc::EACCES | libc::EPERM => PermissionDenied, - libc::EWOULDBLOCK => WouldBlock, - - _ => Uncategorized, - } -} - pub fn abort_internal() -> ! { unsafe { libc::abort() } } #[inline] #[cfg(target_env = "p1")] -pub(crate) fn err2io(err: wasi::Errno) -> std_io::Error { - std_io::Error::from_raw_os_error(err.raw().into()) +pub(crate) fn err2io(err: wasi::Errno) -> crate::io::Error { + crate::io::Error::from_raw_os_error(err.raw().into()) } diff --git a/library/std/src/sys/pal/wasi/mod.rs b/library/std/src/sys/pal/wasi/mod.rs index 5d36687df097..9b49db9af6b0 100644 --- a/library/std/src/sys/pal/wasi/mod.rs +++ b/library/std/src/sys/pal/wasi/mod.rs @@ -26,9 +26,9 @@ mod helpers; // import conflict rules. If we glob export `helpers` and `common` together, // then the compiler complains about conflicts. +pub(crate) use helpers::abort_internal; #[cfg(target_env = "p1")] pub(crate) use helpers::err2io; -pub(crate) use helpers::{abort_internal, decode_error_kind, is_interrupted}; #[cfg(not(target_env = "p1"))] pub use os::IsMinusOne; pub use os::{cvt, cvt_r}; diff --git a/library/std/src/sys/pal/wasi/os.rs b/library/std/src/sys/pal/wasi/os.rs index fee187a8adf3..285be3ca9fda 100644 --- a/library/std/src/sys/pal/wasi/os.rs +++ b/library/std/src/sys/pal/wasi/os.rs @@ -6,7 +6,7 @@ use crate::os::wasi::prelude::*; use crate::path::{self, PathBuf}; use crate::sys::helpers::run_path_with_cstr; use crate::sys::unsupported; -use crate::{fmt, io, str}; +use crate::{fmt, io}; // Add a few symbols not in upstream `libc` just yet. pub mod libc { @@ -19,34 +19,6 @@ pub mod libc { } } -unsafe extern "C" { - #[thread_local] - #[link_name = "errno"] - static mut libc_errno: libc::c_int; -} - -pub fn errno() -> i32 { - unsafe { libc_errno as i32 } -} - -pub fn set_errno(val: i32) { - unsafe { - libc_errno = val; - } -} - -pub fn error_string(errno: i32) -> String { - let mut buf = [0 as libc::c_char; 1024]; - - let p = buf.as_mut_ptr(); - unsafe { - if libc::strerror_r(errno as libc::c_int, p, buf.len()) < 0 { - panic!("strerror_r failure"); - } - str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned() - } -} - pub fn getcwd() -> io::Result { let mut buf = Vec::with_capacity(512); loop { diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index 19f0259b1bf0..17e3cdbecd5c 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -60,84 +60,6 @@ pub unsafe fn cleanup() { winsock::cleanup(); } -#[inline] -pub fn is_interrupted(_errno: i32) -> bool { - false -} - -pub fn decode_error_kind(errno: i32) -> io::ErrorKind { - use io::ErrorKind::*; - - match errno as u32 { - c::ERROR_ACCESS_DENIED => return PermissionDenied, - c::ERROR_ALREADY_EXISTS => return AlreadyExists, - c::ERROR_FILE_EXISTS => return AlreadyExists, - c::ERROR_BROKEN_PIPE => return BrokenPipe, - c::ERROR_FILE_NOT_FOUND - | c::ERROR_PATH_NOT_FOUND - | c::ERROR_INVALID_DRIVE - | c::ERROR_BAD_NETPATH - | c::ERROR_BAD_NET_NAME => return NotFound, - c::ERROR_NO_DATA => return BrokenPipe, - c::ERROR_INVALID_NAME | c::ERROR_BAD_PATHNAME => return InvalidFilename, - c::ERROR_INVALID_PARAMETER => return InvalidInput, - c::ERROR_NOT_ENOUGH_MEMORY | c::ERROR_OUTOFMEMORY => return OutOfMemory, - c::ERROR_SEM_TIMEOUT - | c::WAIT_TIMEOUT - | c::ERROR_DRIVER_CANCEL_TIMEOUT - | c::ERROR_OPERATION_ABORTED - | c::ERROR_SERVICE_REQUEST_TIMEOUT - | c::ERROR_COUNTER_TIMEOUT - | c::ERROR_TIMEOUT - | c::ERROR_RESOURCE_CALL_TIMED_OUT - | c::ERROR_CTX_MODEM_RESPONSE_TIMEOUT - | c::ERROR_CTX_CLIENT_QUERY_TIMEOUT - | c::FRS_ERR_SYSVOL_POPULATE_TIMEOUT - | c::ERROR_DS_TIMELIMIT_EXCEEDED - | c::DNS_ERROR_RECORD_TIMED_OUT - | c::ERROR_IPSEC_IKE_TIMED_OUT - | c::ERROR_RUNLEVEL_SWITCH_TIMEOUT - | c::ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT => return TimedOut, - c::ERROR_CALL_NOT_IMPLEMENTED => return Unsupported, - c::ERROR_HOST_UNREACHABLE => return HostUnreachable, - c::ERROR_NETWORK_UNREACHABLE => return NetworkUnreachable, - c::ERROR_DIRECTORY => return NotADirectory, - c::ERROR_DIRECTORY_NOT_SUPPORTED => return IsADirectory, - c::ERROR_DIR_NOT_EMPTY => return DirectoryNotEmpty, - c::ERROR_WRITE_PROTECT => return ReadOnlyFilesystem, - c::ERROR_DISK_FULL | c::ERROR_HANDLE_DISK_FULL => return StorageFull, - c::ERROR_SEEK_ON_DEVICE => return NotSeekable, - c::ERROR_DISK_QUOTA_EXCEEDED => return QuotaExceeded, - c::ERROR_FILE_TOO_LARGE => return FileTooLarge, - c::ERROR_BUSY => return ResourceBusy, - c::ERROR_POSSIBLE_DEADLOCK => return Deadlock, - c::ERROR_NOT_SAME_DEVICE => return CrossesDevices, - c::ERROR_TOO_MANY_LINKS => return TooManyLinks, - c::ERROR_FILENAME_EXCED_RANGE => return InvalidFilename, - c::ERROR_CANT_RESOLVE_FILENAME => return FilesystemLoop, - _ => {} - } - - match errno { - c::WSAEACCES => PermissionDenied, - c::WSAEADDRINUSE => AddrInUse, - c::WSAEADDRNOTAVAIL => AddrNotAvailable, - c::WSAECONNABORTED => ConnectionAborted, - c::WSAECONNREFUSED => ConnectionRefused, - c::WSAECONNRESET => ConnectionReset, - c::WSAEINVAL => InvalidInput, - c::WSAENOTCONN => NotConnected, - c::WSAEWOULDBLOCK => WouldBlock, - c::WSAETIMEDOUT => TimedOut, - c::WSAEHOSTUNREACH => HostUnreachable, - c::WSAENETDOWN => NetworkDown, - c::WSAENETUNREACH => NetworkUnreachable, - c::WSAEDQUOT => QuotaExceeded, - - _ => Uncategorized, - } -} - pub fn unrolled_find_u16s(needle: u16, haystack: &[u16]) -> Option { let ptr = haystack.as_ptr(); let mut start = haystack; diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs index 1b3c80c079be..3eb6ec827840 100644 --- a/library/std/src/sys/pal/windows/os.rs +++ b/library/std/src/sys/pal/windows/os.rs @@ -15,66 +15,6 @@ use crate::path::{self, PathBuf}; use crate::sys::pal::{c, cvt}; use crate::{fmt, io, ptr}; -pub fn errno() -> i32 { - api::get_last_error().code as i32 -} - -/// Gets a detailed string description for the given error number. -pub fn error_string(mut errnum: i32) -> String { - let mut buf = [0 as c::WCHAR; 2048]; - - unsafe { - let mut module = ptr::null_mut(); - let mut flags = 0; - - // NTSTATUS errors may be encoded as HRESULT, which may returned from - // GetLastError. For more information about Windows error codes, see - // `[MS-ERREF]`: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/0642cb2f-2075-4469-918c-4441e69c548a - if (errnum & c::FACILITY_NT_BIT as i32) != 0 { - // format according to https://support.microsoft.com/en-us/help/259693 - const NTDLL_DLL: &[u16] = &[ - 'N' as _, 'T' as _, 'D' as _, 'L' as _, 'L' as _, '.' as _, 'D' as _, 'L' as _, - 'L' as _, 0, - ]; - module = c::GetModuleHandleW(NTDLL_DLL.as_ptr()); - - if !module.is_null() { - errnum ^= c::FACILITY_NT_BIT as i32; - flags = c::FORMAT_MESSAGE_FROM_HMODULE; - } - } - - let res = c::FormatMessageW( - flags | c::FORMAT_MESSAGE_FROM_SYSTEM | c::FORMAT_MESSAGE_IGNORE_INSERTS, - module, - errnum as u32, - 0, - buf.as_mut_ptr(), - buf.len() as u32, - ptr::null(), - ) as usize; - if res == 0 { - // Sometimes FormatMessageW can fail e.g., system doesn't like 0 as langId, - let fm_err = errno(); - return format!("OS Error {errnum} (FormatMessageW() returned error {fm_err})"); - } - - match String::from_utf16(&buf[..res]) { - Ok(mut msg) => { - // Trim trailing CRLF inserted by FormatMessageW - let len = msg.trim_end().len(); - msg.truncate(len); - msg - } - Err(..) => format!( - "OS Error {} (FormatMessageW() returned \ - invalid UTF-16)", - errnum - ), - } - } -} - pub struct SplitPaths<'a> { data: EncodeWide<'a>, must_yield: bool, diff --git a/library/std/src/sys/pal/xous/os.rs b/library/std/src/sys/pal/xous/os.rs index 2da711f89dfa..cd7b7b59d112 100644 --- a/library/std/src/sys/pal/xous/os.rs +++ b/library/std/src/sys/pal/xous/os.rs @@ -1,7 +1,6 @@ use super::unsupported; use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; -use crate::os::xous::ffi::Error as XousError; use crate::path::{self, PathBuf}; use crate::sync::atomic::{Atomic, AtomicPtr, Ordering}; use crate::{fmt, io}; @@ -63,14 +62,6 @@ mod c_compat { } } -pub fn errno() -> i32 { - 0 -} - -pub fn error_string(errno: i32) -> String { - Into::::into(errno).to_string() -} - pub fn getcwd() -> io::Result { unsupported() } diff --git a/library/std/src/sys/pal/zkvm/mod.rs b/library/std/src/sys/pal/zkvm/mod.rs index 6dece1055a08..f09020820a03 100644 --- a/library/std/src/sys/pal/zkvm/mod.rs +++ b/library/std/src/sys/pal/zkvm/mod.rs @@ -33,14 +33,6 @@ pub fn unsupported_err() -> std_io::Error { std_io::Error::UNSUPPORTED_PLATFORM } -pub fn is_interrupted(_code: i32) -> bool { - false -} - -pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind { - crate::io::ErrorKind::Uncategorized -} - pub fn abort_internal() -> ! { core::intrinsics::abort(); } diff --git a/library/std/src/sys/pal/zkvm/os.rs b/library/std/src/sys/pal/zkvm/os.rs index 13d2a2044f48..cb925ef4348d 100644 --- a/library/std/src/sys/pal/zkvm/os.rs +++ b/library/std/src/sys/pal/zkvm/os.rs @@ -4,14 +4,6 @@ use crate::marker::PhantomData; use crate::path::{self, PathBuf}; use crate::{fmt, io}; -pub fn errno() -> i32 { - 0 -} - -pub fn error_string(_errno: i32) -> String { - "operation successful".to_string() -} - pub fn getcwd() -> io::Result { unsupported() } diff --git a/library/std/src/sys/process/uefi.rs b/library/std/src/sys/process/uefi.rs index d627a477dc1a..31914aeb67c5 100644 --- a/library/std/src/sys/process/uefi.rs +++ b/library/std/src/sys/process/uefi.rs @@ -8,8 +8,8 @@ use crate::num::{NonZero, NonZeroI32}; use crate::path::Path; use crate::process::StdioPipes; use crate::sys::fs::File; +use crate::sys::io::error_string; use crate::sys::pal::helpers; -use crate::sys::pal::os::error_string; use crate::sys::unsupported; use crate::{fmt, io}; diff --git a/library/std/src/sys/process/unix/common.rs b/library/std/src/sys/process/unix/common.rs index 2e1cd7068d7f..f6bbfed61ef3 100644 --- a/library/std/src/sys/process/unix/common.rs +++ b/library/std/src/sys/process/unix/common.rs @@ -61,7 +61,7 @@ cfg_select! { let bit = (signum - 1) as usize; if set.is_null() || bit >= (8 * size_of::()) { - crate::sys::pal::os::set_errno(libc::EINVAL); + crate::sys::io::set_errno(libc::EINVAL); return -1; } let raw = slice::from_raw_parts_mut( diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs index 5ba57e11679c..53fe69805de3 100644 --- a/library/std/src/sys/process/unix/unix.rs +++ b/library/std/src/sys/process/unix/unix.rs @@ -194,7 +194,7 @@ impl Command { // See also https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/f/fork.html #[cfg(target_os = "nto")] unsafe fn do_fork(&mut self) -> Result { - use crate::sys::os::errno; + use crate::sys::io::errno; let mut delay = MIN_FORKSPAWN_SLEEP; diff --git a/library/std/src/sys/random/linux.rs b/library/std/src/sys/random/linux.rs index 53e2f1da6753..a5b790a1db42 100644 --- a/library/std/src/sys/random/linux.rs +++ b/library/std/src/sys/random/linux.rs @@ -66,7 +66,7 @@ use crate::os::fd::AsRawFd; use crate::sync::OnceLock; use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; use crate::sync::atomic::{Atomic, AtomicBool}; -use crate::sys::pal::os::errno; +use crate::sys::io::errno; use crate::sys::pal::weak::syscall; fn getrandom(mut bytes: &mut [u8], insecure: bool) { diff --git a/library/std/src/sys/sync/condvar/windows7.rs b/library/std/src/sys/sync/condvar/windows7.rs index f03feef22212..c3f680be4bb5 100644 --- a/library/std/src/sys/sync/condvar/windows7.rs +++ b/library/std/src/sys/sync/condvar/windows7.rs @@ -1,6 +1,6 @@ use crate::cell::UnsafeCell; +use crate::sys::c; use crate::sys::sync::{Mutex, mutex}; -use crate::sys::{c, os}; use crate::time::Duration; pub struct Condvar { @@ -30,7 +30,7 @@ impl Condvar { 0, ); if r == 0 { - debug_assert_eq!(os::errno() as usize, c::ERROR_TIMEOUT as usize); + debug_assert_eq!(crate::sys::io::errno() as usize, c::ERROR_TIMEOUT as usize); false } else { true diff --git a/library/std/src/sys/thread/unix.rs b/library/std/src/sys/thread/unix.rs index d0396ed71300..82e2e0456e64 100644 --- a/library/std/src/sys/thread/unix.rs +++ b/library/std/src/sys/thread/unix.rs @@ -14,10 +14,9 @@ use crate::num::NonZero; use crate::sys::weak::dlsym; #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto",))] use crate::sys::weak::weak; -use crate::sys::{os, stack_overflow}; use crate::thread::ThreadInit; use crate::time::Duration; -use crate::{cmp, io, ptr}; +use crate::{cmp, io, ptr, sys}; #[cfg(not(any( target_os = "l4re", target_os = "vxworks", @@ -77,7 +76,7 @@ impl Thread { // multiple of the system page size. Because it's definitely // >= PTHREAD_STACK_MIN, it must be an alignment issue. // Round up to the nearest page and try again. - let page_size = os::page_size(); + let page_size = sys::os::page_size(); let stack_size = (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1); @@ -114,7 +113,7 @@ impl Thread { // Now that the thread information is set, set up our stack // overflow handler. - let _handler = stack_overflow::Handler::new(); + let _handler = sys::stack_overflow::Handler::new(); rust_start(); } @@ -536,7 +535,7 @@ pub fn sleep(dur: Duration) { secs -= ts.tv_sec as u64; let ts_ptr = &raw mut ts; if libc::nanosleep(ts_ptr, ts_ptr) == -1 { - assert_eq!(os::errno(), libc::EINTR); + assert_eq!(sys::io::errno(), libc::EINTR); secs += ts.tv_sec as u64; nsecs = ts.tv_nsec; } else { From 0f25fca1a1f36ae93c76333a11132d8f54350b7c Mon Sep 17 00:00:00 2001 From: joboet Date: Tue, 6 Jan 2026 13:38:57 +0100 Subject: [PATCH 0650/1061] update import in UI test --- tests/ui/stability-attribute/stability-in-private-module.rs | 2 +- tests/ui/stability-attribute/stability-in-private-module.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui/stability-attribute/stability-in-private-module.rs b/tests/ui/stability-attribute/stability-in-private-module.rs index df94931690b7..000de46ab45e 100644 --- a/tests/ui/stability-attribute/stability-in-private-module.rs +++ b/tests/ui/stability-attribute/stability-in-private-module.rs @@ -1,4 +1,4 @@ fn main() { - let _ = std::sys::os::errno(); + let _ = std::sys::io::errno(); //~^ERROR module `sys` is private } diff --git a/tests/ui/stability-attribute/stability-in-private-module.stderr b/tests/ui/stability-attribute/stability-in-private-module.stderr index e65f8aa9b1fc..ab27f703ab6b 100644 --- a/tests/ui/stability-attribute/stability-in-private-module.stderr +++ b/tests/ui/stability-attribute/stability-in-private-module.stderr @@ -1,7 +1,7 @@ error[E0603]: module `sys` is private --> $DIR/stability-in-private-module.rs:2:18 | -LL | let _ = std::sys::os::errno(); +LL | let _ = std::sys::io::errno(); | ^^^ ----- function `errno` is not publicly re-exported | | | private module From 959be82effe087543befbd1aeb0920171ae2fc3f Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 12 Jan 2026 13:58:29 +0100 Subject: [PATCH 0651/1061] std: implement `sleep_until` on Apple platforms --- library/std/src/lib.rs | 1 + library/std/src/sys/pal/unix/time.rs | 52 ++++++++++++++++++++++------ library/std/src/sys/thread/mod.rs | 2 ++ library/std/src/sys/thread/unix.rs | 41 ++++++++++++++++++++++ library/std/src/thread/functions.rs | 1 + 5 files changed, 87 insertions(+), 10 deletions(-) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index f5b9f69a5f9f..93f2c519dd1b 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -326,6 +326,7 @@ #![feature(const_convert)] #![feature(core_intrinsics)] #![feature(core_io_borrowed_buf)] +#![feature(cstr_display)] #![feature(drop_guard)] #![feature(duration_constants)] #![feature(error_generic_member_access)] diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index 50b690256a20..a56034f3778c 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -270,22 +270,25 @@ pub struct Instant { } impl Instant { + // CLOCK_UPTIME_RAW clock that increments monotonically, in the same man- + // ner as CLOCK_MONOTONIC_RAW, but that does not incre- + // ment while the system is asleep. The returned value + // is identical to the result of mach_absolute_time() + // after the appropriate mach_timebase conversion is + // applied. + // + // We use `CLOCK_UPTIME_RAW` instead of `CLOCK_MONOTONIC` since + // `CLOCK_UPTIME_RAW` is based on `mach_absolute_time`, which is the + // clock that all timeouts and deadlines are measured against inside + // the kernel. #[cfg(target_vendor = "apple")] pub(crate) const CLOCK_ID: libc::clockid_t = libc::CLOCK_UPTIME_RAW; + #[cfg(not(target_vendor = "apple"))] pub(crate) const CLOCK_ID: libc::clockid_t = libc::CLOCK_MONOTONIC; + pub fn now() -> Instant { // https://pubs.opengroup.org/onlinepubs/9799919799/functions/clock_getres.html - // - // CLOCK_UPTIME_RAW clock that increments monotonically, in the same man- - // ner as CLOCK_MONOTONIC_RAW, but that does not incre- - // ment while the system is asleep. The returned value - // is identical to the result of mach_absolute_time() - // after the appropriate mach_timebase conversion is - // applied. - // - // Instant on macos was historically implemented using mach_absolute_time; - // we preserve this value domain out of an abundance of caution. Instant { t: Timespec::now(Self::CLOCK_ID) } } @@ -308,6 +311,35 @@ impl Instant { pub(crate) fn into_timespec(self) -> Timespec { self.t } + + /// Returns `self` converted into units of `mach_absolute_time`, or `None` + /// if `self` is before the system boot time. + #[cfg(target_vendor = "apple")] + pub fn into_mach_absolute_time(self) -> Option { + #[repr(C)] + struct mach_timebase_info { + numer: u32, + denom: u32, + } + + unsafe extern "C" { + unsafe fn mach_timebase_info(info: *mut mach_timebase_info) -> libc::kern_return_t; + } + + let secs = u64::try_from(self.t.tv_sec).ok()?; + + let mut timebase = mach_timebase_info { numer: 0, denom: 0 }; + assert_eq!(unsafe { mach_timebase_info(&mut timebase) }, libc::KERN_SUCCESS); + + // Since `tv_sec` is 64-bit and `tv_nsec` is smaller than 1 billion, + // this cannot overflow. The resulting number needs at most 94 bits. + let nanos = + u128::from(secs) * u128::from(NSEC_PER_SEC) + u128::from(self.t.tv_nsec.as_inner()); + // This multiplication cannot overflow since multiplying a 94-bit + // number by a 32-bit number yields a number that needs at most + // 126 bits. + Some(nanos * u128::from(timebase.denom) / u128::from(timebase.numer)) + } } impl AsInner for Instant { diff --git a/library/std/src/sys/thread/mod.rs b/library/std/src/sys/thread/mod.rs index cb6bf6518f81..3460270b15fc 100644 --- a/library/std/src/sys/thread/mod.rs +++ b/library/std/src/sys/thread/mod.rs @@ -73,6 +73,7 @@ cfg_select! { target_os = "fuchsia", target_os = "vxworks", target_os = "wasi", + target_vendor = "apple", ))] pub use unix::sleep_until; #[expect(dead_code)] @@ -133,6 +134,7 @@ cfg_select! { target_os = "fuchsia", target_os = "vxworks", target_os = "wasi", + target_vendor = "apple", )))] pub fn sleep_until(deadline: crate::time::Instant) { use crate::time::Instant; diff --git a/library/std/src/sys/thread/unix.rs b/library/std/src/sys/thread/unix.rs index d0396ed71300..e52bc63ea5b1 100644 --- a/library/std/src/sys/thread/unix.rs +++ b/library/std/src/sys/thread/unix.rs @@ -636,6 +636,47 @@ pub fn sleep_until(deadline: crate::time::Instant) { } } +#[cfg(target_vendor = "apple")] +pub fn sleep_until(deadline: crate::time::Instant) { + unsafe extern "C" { + // This is defined in the public header mach/mach_time.h alongside + // `mach_absolute_time`, and like it has been available since the very + // beginning. + // + // There isn't really any documentation on this function, except for a + // short reference in technical note 2169: + // https://developer.apple.com/library/archive/technotes/tn2169/_index.html + safe fn mach_wait_until(deadline: u64) -> libc::kern_return_t; + } + + let Some(deadline) = deadline.into_inner().into_mach_absolute_time() else { + // Since the deadline is before the system boot time, it has already + // passed, so we can return immediately. + return; + }; + + // If the deadline is not representable, then sleep for the maximum duration + // possible and worry about the potential clock issues later (in ca. 600 years). + let deadline = deadline.try_into().unwrap_or(u64::MAX); + loop { + match mach_wait_until(deadline) { + // Success! The deadline has passed. + libc::KERN_SUCCESS => break, + // If the sleep gets interrupted by a signal, `mach_wait_until` + // returns KERN_ABORTED, so we need to restart the syscall. + // Also see Apple's implementation of the POSIX `nanosleep`, which + // converts this error to the POSIX equivalent EINTR: + // https://github.com/apple-oss-distributions/Libc/blob/55b54c0a0c37b3b24393b42b90a4c561d6c606b1/gen/nanosleep.c#L281-L306 + libc::KERN_ABORTED => continue, + // All other errors indicate that something has gone wrong... + error => { + let description = unsafe { CStr::from_ptr(libc::mach_error_string(error)) }; + panic!("mach_wait_until failed: {} (code {error})", description.display()) + } + } + } +} + pub fn yield_now() { let ret = unsafe { libc::sched_yield() }; debug_assert_eq!(ret, 0); diff --git a/library/std/src/thread/functions.rs b/library/std/src/thread/functions.rs index a25bae1aae31..73d727878570 100644 --- a/library/std/src/thread/functions.rs +++ b/library/std/src/thread/functions.rs @@ -318,6 +318,7 @@ pub fn sleep(dur: Duration) { /// | Hurd | [clock_nanosleep] (Monotonic Clock)] | /// | Fuchsia | [clock_nanosleep] (Monotonic Clock)] | /// | Vxworks | [clock_nanosleep] (Monotonic Clock)] | +/// | Apple | `mach_wait_until` | /// | Other | `sleep_until` uses [`sleep`] and does not issue a syscall itself | /// /// [currently]: crate::io#platform-specific-behavior From 1d968067881c968c3e79558472988ab117eaf8b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sat, 10 Jan 2026 10:54:31 +0100 Subject: [PATCH 0652/1061] type params on eii --- tests/ui/eii/type_checking/type_params_149983.rs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/ui/eii/type_checking/type_params_149983.rs diff --git a/tests/ui/eii/type_checking/type_params_149983.rs b/tests/ui/eii/type_checking/type_params_149983.rs new file mode 100644 index 000000000000..a0314657bb1d --- /dev/null +++ b/tests/ui/eii/type_checking/type_params_149983.rs @@ -0,0 +1,7 @@ +//@ check-fail +// Check that type parameters on EIIs are properly rejected. +// Specifically a regression test for https://github.com/rust-lang/rust/issues/149983. +#![feature(extern_item_impls)] + +#[eii] +fn foo() {} From d25f4718adf1f2358c63299af16c1c4c0519bb03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sat, 10 Jan 2026 16:00:46 +0100 Subject: [PATCH 0653/1061] deduplicate error message when EII has generics --- compiler/rustc_hir_analysis/messages.ftl | 4 ---- .../rustc_hir_analysis/src/check/check.rs | 9 +++++++- .../src/check/compare_eii.rs | 23 +------------------ compiler/rustc_hir_analysis/src/errors.rs | 10 -------- 4 files changed, 9 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 416a6b19edfc..9ead1225d5f5 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -165,10 +165,6 @@ hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported hir_analysis_duplicate_precise_capture = cannot capture parameter `{$name}` twice .label = parameter captured again here -hir_analysis_eii_with_generics = - #[{$eii_name}] cannot have generic parameters other than lifetimes - .label = required by this attribute - hir_analysis_empty_specialization = specialization impl does not specialize any associated items .note = impl is a specialization of this impl diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 4664bfcce853..c37611ab2ee7 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -974,12 +974,19 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), (0, _) => ("const", "consts", None), _ => ("type or const", "types or consts", None), }; + let name = + if find_attr!(tcx.get_all_attrs(def_id), AttributeKind::EiiForeignItem) { + "externally implementable items" + } else { + "foreign items" + }; + let span = tcx.def_span(def_id); struct_span_code_err!( tcx.dcx(), span, E0044, - "foreign items may not have {kinds} parameters", + "{name} may not have {kinds} parameters", ) .with_span_label(span, format!("can't have {kinds} parameters")) .with_help( diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index d8afee9aafc9..c2a9b1fbdee0 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -24,7 +24,7 @@ use super::potentially_plural_count; use crate::check::compare_impl_item::{ CheckNumberOfEarlyBoundRegionsError, check_number_of_early_bound_regions, }; -use crate::errors::{EiiWithGenerics, LifetimesOrBoundsMismatchOnEii}; +use crate::errors::LifetimesOrBoundsMismatchOnEii; /// Checks whether the signature of some `external_impl`, matches /// the signature of `declaration`, which it is supposed to be compatible @@ -154,32 +154,11 @@ fn check_is_structurally_compatible<'tcx>( eii_name: Symbol, eii_attr_span: Span, ) -> Result<(), ErrorGuaranteed> { - check_no_generics(tcx, external_impl, declaration, eii_name, eii_attr_span)?; check_number_of_arguments(tcx, external_impl, declaration, eii_name, eii_attr_span)?; check_early_region_bounds(tcx, external_impl, declaration, eii_attr_span)?; Ok(()) } -/// externally implementable items can't have generics -fn check_no_generics<'tcx>( - tcx: TyCtxt<'tcx>, - external_impl: LocalDefId, - _declaration: DefId, - eii_name: Symbol, - eii_attr_span: Span, -) -> Result<(), ErrorGuaranteed> { - let generics = tcx.generics_of(external_impl); - if generics.own_requires_monomorphization() { - tcx.dcx().emit_err(EiiWithGenerics { - span: tcx.def_span(external_impl), - attr: eii_attr_span, - eii_name, - }); - } - - Ok(()) -} - fn check_early_region_bounds<'tcx>( tcx: TyCtxt<'tcx>, external_impl: LocalDefId, diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index b388396ac4fc..7d4f65434dc4 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1652,13 +1652,3 @@ pub(crate) struct LifetimesOrBoundsMismatchOnEii { pub bounds_span: Vec, pub ident: Symbol, } - -#[derive(Diagnostic)] -#[diag(hir_analysis_eii_with_generics)] -pub(crate) struct EiiWithGenerics { - #[primary_span] - pub span: Span, - #[label] - pub attr: Span, - pub eii_name: Symbol, -} From b64a9be97ebe4195e55768e98f6eb4dcdd9220a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sun, 11 Jan 2026 16:52:46 +0100 Subject: [PATCH 0654/1061] bless the tests --- tests/ui/eii/type_checking/type_params_149983.rs | 3 +++ tests/ui/eii/type_checking/type_params_149983.stderr | 11 +++++++++++ 2 files changed, 14 insertions(+) create mode 100644 tests/ui/eii/type_checking/type_params_149983.stderr diff --git a/tests/ui/eii/type_checking/type_params_149983.rs b/tests/ui/eii/type_checking/type_params_149983.rs index a0314657bb1d..6dc9b309712e 100644 --- a/tests/ui/eii/type_checking/type_params_149983.rs +++ b/tests/ui/eii/type_checking/type_params_149983.rs @@ -5,3 +5,6 @@ #[eii] fn foo() {} +//~^ ERROR externally implementable items may not have type parameters + +fn main() {} diff --git a/tests/ui/eii/type_checking/type_params_149983.stderr b/tests/ui/eii/type_checking/type_params_149983.stderr new file mode 100644 index 000000000000..11f06e6c88e2 --- /dev/null +++ b/tests/ui/eii/type_checking/type_params_149983.stderr @@ -0,0 +1,11 @@ +error[E0044]: externally implementable items may not have type parameters + --> $DIR/type_params_149983.rs:7:1 + | +LL | fn foo() {} + | ^^^^^^^^^^^ can't have type parameters + | + = help: replace the type parameters with concrete types like `u32` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0044`. From 467a2d2a1a8654524be29dbadd34c89d9616d8dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sun, 11 Jan 2026 16:09:18 +0100 Subject: [PATCH 0655/1061] use self instead of super --- compiler/rustc_builtin_macros/src/eii.rs | 54 ++++-------------------- 1 file changed, 9 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index cec7599d68e9..f72b78fe7f99 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -105,10 +105,10 @@ fn eii_( let item_span = func.sig.span; let foreign_item_name = func.ident; - let mut return_items = Vec::new(); + let mut module_items = Vec::new(); if func.body.is_some() { - return_items.push(generate_default_impl( + module_items.push(generate_default_impl( ecx, &func, impl_unsafe, @@ -119,7 +119,7 @@ fn eii_( )) } - return_items.push(generate_foreign_item( + module_items.push(generate_foreign_item( ecx, eii_attr_span, item_span, @@ -127,7 +127,7 @@ fn eii_( vis, &attrs_from_decl, )); - return_items.push(generate_attribute_macro_to_implement( + module_items.push(generate_attribute_macro_to_implement( ecx, eii_attr_span, macro_name, @@ -136,7 +136,7 @@ fn eii_( &attrs_from_decl, )); - return_items.into_iter().map(wrap_item).collect() + module_items.into_iter().map(wrap_item).collect() } /// Decide on the name of the macro that can be used to implement the EII. @@ -213,29 +213,13 @@ fn generate_default_impl( known_eii_macro_resolution: Some(ast::EiiDecl { foreign_item: ecx.path( foreign_item_name.span, - // prefix super to escape the `dflt` module generated below - vec![Ident::from_str_and_span("super", foreign_item_name.span), foreign_item_name], + // prefix super to explicitly escape the const block generated below + vec![Ident::from_str_and_span("self", foreign_item_name.span), foreign_item_name], ), impl_unsafe, }), }); - let item_mod = |span: Span, name: Ident, items: ThinVec>| { - ecx.item( - item_span, - ThinVec::new(), - ItemKind::Mod( - ast::Safety::Default, - name, - ast::ModKind::Loaded( - items, - ast::Inline::Yes, - ast::ModSpans { inner_span: span, inject_use_span: span }, - ), - ), - ) - }; - let anon_mod = |span: Span, stmts: ThinVec| { let unit = ecx.ty(item_span, ast::TyKind::Tup(ThinVec::new())); let underscore = Ident::new(kw::Underscore, item_span); @@ -248,33 +232,13 @@ fn generate_default_impl( }; // const _: () = { - // mod dflt { - // use super::*; - // - // } + // // } anon_mod( item_span, thin_vec![ecx.stmt_item( item_span, - item_mod( - item_span, - Ident::from_str_and_span("dflt", item_span), - thin_vec![ - ecx.item( - item_span, - thin_vec![ecx.attr_nested_word(sym::allow, sym::unused_imports, item_span)], - ItemKind::Use(ast::UseTree { - prefix: ast::Path::from_ident(Ident::from_str_and_span( - "super", item_span, - )), - kind: ast::UseTreeKind::Glob, - span: item_span, - }) - ), - ecx.item(item_span, attrs, ItemKind::Fn(Box::new(default_func))) - ] - ) + ecx.item(item_span, attrs, ItemKind::Fn(Box::new(default_func))) ),], ) } From b454f76bd1ddf5c7459238f295647561a7895cbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sun, 11 Jan 2026 17:45:50 +0100 Subject: [PATCH 0656/1061] ensure generics are still properly reported on EII *implementations*, and test this --- compiler/rustc_hir_analysis/messages.ftl | 5 +++ .../src/check/compare_eii.rs | 38 ++++++++++++++++++- compiler/rustc_hir_analysis/src/errors.rs | 12 ++++++ .../type_checking/generic_implementation.rs | 13 +++++++ .../generic_implementation.stderr | 12 ++++++ 5 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 tests/ui/eii/type_checking/generic_implementation.rs create mode 100644 tests/ui/eii/type_checking/generic_implementation.stderr diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 9ead1225d5f5..fa3c4cb05f96 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -165,6 +165,11 @@ hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported hir_analysis_duplicate_precise_capture = cannot capture parameter `{$name}` twice .label = parameter captured again here +hir_analysis_eii_with_generics = + `{$impl_name}` cannot have generic parameters other than lifetimes + .label = required by this attribute + .help = `#[{$eii_name}]` marks the implementation of an "externally implementable item" + hir_analysis_empty_specialization = specialization impl does not specialize any associated items .note = impl is a specialization of this impl diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index c2a9b1fbdee0..2beb7eb09c11 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -8,8 +8,9 @@ use std::iter; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{Applicability, E0806, struct_span_code_err}; +use rustc_hir::attrs::{AttributeKind, EiiImplResolution}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{self as hir, FnSig, HirId, ItemKind}; +use rustc_hir::{self as hir, FnSig, HirId, ItemKind, find_attr}; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; @@ -24,7 +25,7 @@ use super::potentially_plural_count; use crate::check::compare_impl_item::{ CheckNumberOfEarlyBoundRegionsError, check_number_of_early_bound_regions, }; -use crate::errors::LifetimesOrBoundsMismatchOnEii; +use crate::errors::{EiiWithGenerics, LifetimesOrBoundsMismatchOnEii}; /// Checks whether the signature of some `external_impl`, matches /// the signature of `declaration`, which it is supposed to be compatible @@ -154,11 +155,44 @@ fn check_is_structurally_compatible<'tcx>( eii_name: Symbol, eii_attr_span: Span, ) -> Result<(), ErrorGuaranteed> { + check_no_generics(tcx, external_impl, declaration, eii_name, eii_attr_span)?; check_number_of_arguments(tcx, external_impl, declaration, eii_name, eii_attr_span)?; check_early_region_bounds(tcx, external_impl, declaration, eii_attr_span)?; Ok(()) } +/// externally implementable items can't have generics +fn check_no_generics<'tcx>( + tcx: TyCtxt<'tcx>, + external_impl: LocalDefId, + _declaration: DefId, + eii_name: Symbol, + eii_attr_span: Span, +) -> Result<(), ErrorGuaranteed> { + let generics = tcx.generics_of(external_impl); + if generics.own_requires_monomorphization() + // When an EII implementation is automatically generated by the `#[eii]` macro, + // it will directly refer to the foreign item, not through a macro. + // We don't want to emit this error if it's an implementation that's generated by the `#[eii]` macro, + // since in that case it looks like a duplicate error: the declaration of the EII already can't contain generics. + // So, we check here if at least one of the eii impls has ImplResolution::Macro, which indicates it's + // not generated as part of the declaration. + && find_attr!( + tcx.get_all_attrs(external_impl), + AttributeKind::EiiImpls(impls) if impls.iter().any(|i| matches!(i.resolution, EiiImplResolution::Macro(_))) + ) + { + tcx.dcx().emit_err(EiiWithGenerics { + span: tcx.def_span(external_impl), + attr: eii_attr_span, + eii_name, + impl_name: tcx.item_name(external_impl), + }); + } + + Ok(()) +} + fn check_early_region_bounds<'tcx>( tcx: TyCtxt<'tcx>, external_impl: LocalDefId, diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 7d4f65434dc4..185a822bdfa6 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1652,3 +1652,15 @@ pub(crate) struct LifetimesOrBoundsMismatchOnEii { pub bounds_span: Vec, pub ident: Symbol, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_eii_with_generics)] +#[help] +pub(crate) struct EiiWithGenerics { + #[primary_span] + pub span: Span, + #[label] + pub attr: Span, + pub eii_name: Symbol, + pub impl_name: Symbol, +} diff --git a/tests/ui/eii/type_checking/generic_implementation.rs b/tests/ui/eii/type_checking/generic_implementation.rs new file mode 100644 index 000000000000..489fd2e645d8 --- /dev/null +++ b/tests/ui/eii/type_checking/generic_implementation.rs @@ -0,0 +1,13 @@ +//@ check-fail +// Check that type parameters on EIIs are properly rejected. +// Specifically a regression test for https://github.com/rust-lang/rust/issues/149983. +#![feature(extern_item_impls)] + +#[eii] +fn foo(); + +#[foo] +fn foo_impl() {} +//~^ ERROR `foo_impl` cannot have generic parameters other than lifetimes + +fn main() {} diff --git a/tests/ui/eii/type_checking/generic_implementation.stderr b/tests/ui/eii/type_checking/generic_implementation.stderr new file mode 100644 index 000000000000..17a71998423d --- /dev/null +++ b/tests/ui/eii/type_checking/generic_implementation.stderr @@ -0,0 +1,12 @@ +error: `foo_impl` cannot have generic parameters other than lifetimes + --> $DIR/generic_implementation.rs:10:1 + | +LL | #[foo] + | ------ required by this attribute +LL | fn foo_impl() {} + | ^^^^^^^^^^^^^^^^ + | + = help: `#[foo]` marks the implementation of an "externally implementable item" + +error: aborting due to 1 previous error + From df55233c6d290bf23f499d846a51897982b7bee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sun, 11 Jan 2026 16:18:49 +0100 Subject: [PATCH 0657/1061] disallow in statement position --- compiler/rustc_builtin_macros/messages.ftl | 2 + compiler/rustc_builtin_macros/src/eii.rs | 41 ++++++++++++--------- compiler/rustc_builtin_macros/src/errors.rs | 10 +++++ 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 1501bd6c73e2..f9ffddf79084 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -161,6 +161,8 @@ builtin_macros_eii_only_once = `#[{$name}]` can only be specified once builtin_macros_eii_shared_macro_expected_function = `#[{$name}]` is only valid on functions builtin_macros_eii_shared_macro_expected_max_one_argument = `#[{$name}]` expected no arguments or a single argument: `#[{$name}(default)]` +builtin_macros_eii_shared_macro_in_statement_position = `#[{$name}]` can only be used on functions inside a module + .label = `#[{$name}]` is used on this item, which is part of another item's local scope builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time .cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index f72b78fe7f99..43e9dfe0092e 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -1,8 +1,7 @@ use rustc_ast::token::{Delimiter, TokenKind}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_ast::{ - Attribute, DUMMY_NODE_ID, EiiDecl, EiiImpl, ItemKind, MetaItem, Path, Stmt, StmtKind, - Visibility, ast, + Attribute, DUMMY_NODE_ID, EiiDecl, EiiImpl, ItemKind, MetaItem, Path, StmtKind, Visibility, ast, }; use rustc_ast_pretty::pprust::path_to_string; use rustc_expand::base::{Annotatable, ExtCtxt}; @@ -12,6 +11,7 @@ use thin_vec::{ThinVec, thin_vec}; use crate::errors::{ EiiExternTargetExpectedList, EiiExternTargetExpectedMacro, EiiExternTargetExpectedUnsafe, EiiMacroExpectedMaxOneArgument, EiiOnlyOnce, EiiSharedMacroExpectedFunction, + EiiSharedMacroInStatementPosition, }; /// ```rust @@ -55,29 +55,29 @@ fn eii_( ecx: &mut ExtCtxt<'_>, eii_attr_span: Span, meta_item: &ast::MetaItem, - item: Annotatable, + orig_item: Annotatable, impl_unsafe: bool, ) -> Vec { let eii_attr_span = ecx.with_def_site_ctxt(eii_attr_span); - let (item, wrap_item): (_, &dyn Fn(_) -> _) = if let Annotatable::Item(item) = item { - (item, &Annotatable::Item) - } else if let Annotatable::Stmt(ref stmt) = item + let item = if let Annotatable::Item(item) = orig_item { + item + } else if let Annotatable::Stmt(ref stmt) = orig_item && let StmtKind::Item(ref item) = stmt.kind + && let ItemKind::Fn(ref f) = item.kind { - (item.clone(), &|item| { - Annotatable::Stmt(Box::new(Stmt { - id: DUMMY_NODE_ID, - kind: StmtKind::Item(item), - span: eii_attr_span, - })) - }) + ecx.dcx().emit_err(EiiSharedMacroInStatementPosition { + span: eii_attr_span.to(item.span), + name: path_to_string(&meta_item.path), + item_span: f.ident.span, + }); + return vec![orig_item]; } else { ecx.dcx().emit_err(EiiSharedMacroExpectedFunction { span: eii_attr_span, name: path_to_string(&meta_item.path), }); - return vec![item]; + return vec![orig_item]; }; let ast::Item { attrs, id: _, span: _, vis, kind: ItemKind::Fn(func), tokens: _ } = @@ -87,7 +87,7 @@ fn eii_( span: eii_attr_span, name: path_to_string(&meta_item.path), }); - return vec![wrap_item(item)]; + return vec![Annotatable::Item(item)]; }; // only clone what we need let attrs = attrs.clone(); @@ -98,7 +98,9 @@ fn eii_( filter_attrs_for_multiple_eii_attr(ecx, attrs, eii_attr_span, &meta_item.path); let Ok(macro_name) = name_for_impl_macro(ecx, &func, &meta_item) else { - return vec![wrap_item(item)]; + // we don't need to wrap in Annotatable::Stmt conditionally since + // EII can't be used on items in statement position + return vec![Annotatable::Item(item)]; }; // span of the declaring item without attributes @@ -136,7 +138,9 @@ fn eii_( &attrs_from_decl, )); - module_items.into_iter().map(wrap_item).collect() + // we don't need to wrap in Annotatable::Stmt conditionally since + // EII can't be used on items in statement position + module_items.into_iter().map(Annotatable::Item).collect() } /// Decide on the name of the macro that can be used to implement the EII. @@ -213,7 +217,8 @@ fn generate_default_impl( known_eii_macro_resolution: Some(ast::EiiDecl { foreign_item: ecx.path( foreign_item_name.span, - // prefix super to explicitly escape the const block generated below + // prefix self to explicitly escape the const block generated below + // NOTE: this is why EIIs can't be used on statements vec![Ident::from_str_and_span("self", foreign_item_name.span), foreign_item_name], ), impl_unsafe, diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 5d4c4e340fa1..a9ce41c9be76 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1039,6 +1039,16 @@ pub(crate) struct EiiSharedMacroExpectedFunction { pub name: String, } +#[derive(Diagnostic)] +#[diag(builtin_macros_eii_shared_macro_in_statement_position)] +pub(crate) struct EiiSharedMacroInStatementPosition { + #[primary_span] + pub span: Span, + pub name: String, + #[label] + pub item_span: Span, +} + #[derive(Diagnostic)] #[diag(builtin_macros_eii_only_once)] pub(crate) struct EiiOnlyOnce { From 8dd701cec77fec63902e78c575dd34e2f715dfa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sun, 11 Jan 2026 16:25:10 +0100 Subject: [PATCH 0658/1061] add test for rejecting EIIs in statement position --- tests/ui/eii/error_statement_position.rs | 15 ++++++++------- tests/ui/eii/error_statement_position.stderr | 13 +++++++++++-- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/tests/ui/eii/error_statement_position.rs b/tests/ui/eii/error_statement_position.rs index cf81e7e6a8b2..75d87595b9e3 100644 --- a/tests/ui/eii/error_statement_position.rs +++ b/tests/ui/eii/error_statement_position.rs @@ -1,11 +1,6 @@ #![feature(extern_item_impls)] -// EIIs can, despite not being super useful, be declared in statement position -// nested inside items. Items in statement position, when expanded as part of a macro, -// need to be wrapped slightly differently (in an `ast::Statement`). -// We did this on the happy path (no errors), but when there was an error, we'd -// replace it with *just* an `ast::Item` not wrapped in an `ast::Statement`. -// This caused an ICE (https://github.com/rust-lang/rust/issues/149980). -// this test fails to build, but demonstrates that no ICE is produced. +// EIIs cannot be used in statement position. +// This is also a regression test for an ICE (https://github.com/rust-lang/rust/issues/149980). fn main() { struct Bar; @@ -13,4 +8,10 @@ fn main() { #[eii] //~^ ERROR `#[eii]` is only valid on functions impl Bar {} + + + // Even on functions, eiis in statement position are rejected + #[eii] + //~^ ERROR `#[eii]` can only be used on functions inside a module + fn foo() {} } diff --git a/tests/ui/eii/error_statement_position.stderr b/tests/ui/eii/error_statement_position.stderr index 01b7394ef00f..f14e6c33e64f 100644 --- a/tests/ui/eii/error_statement_position.stderr +++ b/tests/ui/eii/error_statement_position.stderr @@ -1,8 +1,17 @@ error: `#[eii]` is only valid on functions - --> $DIR/error_statement_position.rs:13:5 + --> $DIR/error_statement_position.rs:8:5 | LL | #[eii] | ^^^^^^ -error: aborting due to 1 previous error +error: `#[eii]` can only be used on functions inside a module + --> $DIR/error_statement_position.rs:14:5 + | +LL | #[eii] + | ^^^^^^ +LL | +LL | fn foo() {} + | --- `#[eii]` is used on this item, which is part of another item's local scope + +error: aborting due to 2 previous errors From d616e6cb189c762789a8179cb00e065fcc7f9992 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Tue, 13 Jan 2026 21:36:53 +0900 Subject: [PATCH 0659/1061] Emit error instead of delayed bug when meeting mismatch type for const array --- .../src/hir_ty_lowering/mod.rs | 9 ++++---- ...array-expr-type-mismatch-in-where-bound.rs | 21 +++++++++++++++++++ ...y-expr-type-mismatch-in-where-bound.stderr | 15 +++++++++++++ 3 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 tests/ui/const-generics/mgca/array-expr-type-mismatch-in-where-bound.rs create mode 100644 tests/ui/const-generics/mgca/array-expr-type-mismatch-in-where-bound.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index d2cbf89336d8..a66a521975c5 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2415,11 +2415,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; let ty::Array(elem_ty, _) = ty.kind() else { - return Const::new_error_with_message( - tcx, - array_expr.span, - "const array must have an array type", - ); + let e = tcx + .dcx() + .span_err(array_expr.span, format!("expected `{}`, found const array", ty)); + return Const::new_error(tcx, e); }; let elems = array_expr diff --git a/tests/ui/const-generics/mgca/array-expr-type-mismatch-in-where-bound.rs b/tests/ui/const-generics/mgca/array-expr-type-mismatch-in-where-bound.rs new file mode 100644 index 000000000000..cda519b96d4d --- /dev/null +++ b/tests/ui/const-generics/mgca/array-expr-type-mismatch-in-where-bound.rs @@ -0,0 +1,21 @@ +//! regression test for +#![feature(min_generic_const_args)] +#![feature(adt_const_params)] +#![expect(incomplete_features)] + +trait Trait1 {} +trait Trait2 {} + +fn foo() +where + T: Trait1<{ [] }>, //~ ERROR: expected `usize`, found const array +{ +} + +fn bar() +where + T: Trait2<3>, //~ ERROR: mismatched types +{ +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/array-expr-type-mismatch-in-where-bound.stderr b/tests/ui/const-generics/mgca/array-expr-type-mismatch-in-where-bound.stderr new file mode 100644 index 000000000000..be40e4474226 --- /dev/null +++ b/tests/ui/const-generics/mgca/array-expr-type-mismatch-in-where-bound.stderr @@ -0,0 +1,15 @@ +error: expected `usize`, found const array + --> $DIR/array-expr-type-mismatch-in-where-bound.rs:11:17 + | +LL | T: Trait1<{ [] }>, + | ^^ + +error[E0308]: mismatched types + --> $DIR/array-expr-type-mismatch-in-where-bound.rs:17:15 + | +LL | T: Trait2<3>, + | ^ expected `[u8; 3]`, found integer + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. From 84d59d073170aecbb15de9c1cdcf542bf7443673 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 12 Jan 2026 19:39:34 +0100 Subject: [PATCH 0660/1061] Port `#[rustc_dump_user_args]` --- .../rustc_attr_parsing/src/attributes/mod.rs | 1 + .../src/attributes/rustc_dump.rs | 17 +++++++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 2 ++ compiler/rustc_hir/src/attrs/data_structures.rs | 3 +++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_hir_typeck/src/writeback.rs | 9 +++++---- compiler/rustc_passes/src/check_attr.rs | 2 +- 7 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index e02d71a26158..26db2992d8af 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -57,6 +57,7 @@ pub(crate) mod pin_v2; pub(crate) mod proc_macro_attrs; pub(crate) mod prototype; pub(crate) mod repr; +pub(crate) mod rustc_dump; pub(crate) mod rustc_internal; pub(crate) mod semantics; pub(crate) mod stability; diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs new file mode 100644 index 000000000000..d5593a7e02f3 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs @@ -0,0 +1,17 @@ +use rustc_hir::Target; +use rustc_hir::attrs::AttributeKind; +use rustc_span::{Span, Symbol, sym}; + +use crate::attributes::prelude::Allow; +use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; +use crate::context::Stage; +use crate::target_checking::AllowedTargets; + +pub(crate) struct RustcDumpUserArgs; + +impl NoArgsAttributeParser for RustcDumpUserArgs { + const PATH: &[Symbol] = &[sym::rustc_dump_user_args]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpUserArgs; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 6b1b1d484283..4ba1936086a2 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -63,6 +63,7 @@ use crate::attributes::proc_macro_attrs::{ }; use crate::attributes::prototype::CustomMirParser; use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; +use crate::attributes::rustc_dump::RustcDumpUserArgs; use crate::attributes::rustc_internal::{ RustcHasIncoherentInherentImplsParser, RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser, RustcLegacyConstGenericsParser, @@ -267,6 +268,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 8d18d335b355..42575f712d4a 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -906,6 +906,9 @@ pub enum AttributeKind { /// Represents `#[rustc_coherence_is_core]` RustcCoherenceIsCore(Span), + /// Represents `#[rustc_dump_user_args]` + RustcDumpUserArgs, + /// Represents `#[rustc_has_incoherent_inherent_impls]` RustcHasIncoherentInherentImpls, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 33655f4f0063..07dd9f8e3e06 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -97,6 +97,7 @@ impl AttributeKind { Repr { .. } => No, RustcBuiltinMacro { .. } => Yes, RustcCoherenceIsCore(..) => No, + RustcDumpUserArgs => No, RustcHasIncoherentInherentImpls => Yes, RustcLayoutScalarValidRangeEnd(..) => Yes, RustcLayoutScalarValidRangeStart(..) => Yes, diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 960a8497a266..0078cd9d0683 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -14,9 +14,10 @@ use std::ops::ControlFlow; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::unord::ExtendUnord; use rustc_errors::{E0720, ErrorGuaranteed}; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, InferKind, Visitor}; -use rustc_hir::{self as hir, AmbigArg, HirId}; +use rustc_hir::{self as hir, AmbigArg, HirId, find_attr}; use rustc_infer::traits::solve::Goal; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion}; @@ -25,7 +26,7 @@ use rustc_middle::ty::{ TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, fold_regions, }; -use rustc_span::{Span, sym}; +use rustc_span::Span; use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; use rustc_trait_selection::opaque_types::opaque_type_has_defining_use_args; use rustc_trait_selection::solve; @@ -45,8 +46,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This attribute causes us to dump some writeback information // in the form of errors, which is used for unit tests. - let rustc_dump_user_args = - self.has_rustc_attrs && self.tcx.has_attr(item_def_id, sym::rustc_dump_user_args); + let rustc_dump_user_args = self.has_rustc_attrs + && find_attr!(self.tcx.get_all_attrs(item_def_id), AttributeKind::RustcDumpUserArgs); let mut wbcx = WritebackCx::new(self, body, rustc_dump_user_args); for param in body.params { diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 8f80822a81ab..f088bd5b5119 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -309,6 +309,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::CfiEncoding { .. } | AttributeKind::RustcHasIncoherentInherentImpls | AttributeKind::MustNotSupend { .. } + | AttributeKind::RustcDumpUserArgs ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); @@ -379,7 +380,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::rustc_variance_of_opaques | sym::rustc_hidden_type_of_opaques | sym::rustc_mir - | sym::rustc_dump_user_args | sym::rustc_effective_visibility | sym::rustc_outlives | sym::rustc_symbol_name From cf4d480eff238667a779c56938ebc51956f586d4 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 12 Jan 2026 19:43:31 +0100 Subject: [PATCH 0661/1061] Port `#[rustc_dump_def_parents]` --- compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs | 9 +++++++++ compiler/rustc_attr_parsing/src/context.rs | 3 ++- compiler/rustc_hir/src/attrs/data_structures.rs | 3 +++ compiler/rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_hir_analysis/src/collect/dump.rs | 5 +++-- compiler/rustc_passes/src/check_attr.rs | 2 +- 6 files changed, 19 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs index d5593a7e02f3..86cc88fe26e6 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs @@ -15,3 +15,12 @@ impl NoArgsAttributeParser for RustcDumpUserArgs { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpUserArgs; } + +pub(crate) struct RustcDumpDefParents; + +impl NoArgsAttributeParser for RustcDumpDefParents { + const PATH: &[Symbol] = &[sym::rustc_dump_def_parents]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpDefParents; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 4ba1936086a2..adcdbf7752a3 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -63,7 +63,7 @@ use crate::attributes::proc_macro_attrs::{ }; use crate::attributes::prototype::CustomMirParser; use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; -use crate::attributes::rustc_dump::RustcDumpUserArgs; +use crate::attributes::rustc_dump::{RustcDumpUserArgs, RustcDumpDefParents}; use crate::attributes::rustc_internal::{ RustcHasIncoherentInherentImplsParser, RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser, RustcLegacyConstGenericsParser, @@ -268,6 +268,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 42575f712d4a..63a89c84ed4a 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -906,6 +906,9 @@ pub enum AttributeKind { /// Represents `#[rustc_coherence_is_core]` RustcCoherenceIsCore(Span), + /// Represents `#[rustc_dump_def_parents]` + RustcDumpDefParents, + /// Represents `#[rustc_dump_user_args]` RustcDumpUserArgs, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 07dd9f8e3e06..aa2a7cb6d4b4 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -97,6 +97,7 @@ impl AttributeKind { Repr { .. } => No, RustcBuiltinMacro { .. } => Yes, RustcCoherenceIsCore(..) => No, + RustcDumpDefParents => No, RustcDumpUserArgs => No, RustcHasIncoherentInherentImpls => Yes, RustcLayoutScalarValidRangeEnd(..) => Yes, diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs index b167f31a246c..1ace60721eae 100644 --- a/compiler/rustc_hir_analysis/src/collect/dump.rs +++ b/compiler/rustc_hir_analysis/src/collect/dump.rs @@ -1,6 +1,7 @@ use rustc_hir as hir; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; -use rustc_hir::intravisit; +use rustc_hir::{find_attr, intravisit}; +use rustc_hir::attrs::AttributeKind; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_span::sym; @@ -54,7 +55,7 @@ pub(crate) fn predicates_and_item_bounds(tcx: TyCtxt<'_>) { pub(crate) fn def_parents(tcx: TyCtxt<'_>) { for iid in tcx.hir_free_items() { let did = iid.owner_id.def_id; - if tcx.has_attr(did, sym::rustc_dump_def_parents) { + if find_attr!(tcx.get_all_attrs(did), AttributeKind::RustcDumpDefParents) { struct AnonConstFinder<'tcx> { tcx: TyCtxt<'tcx>, anon_consts: Vec, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index f088bd5b5119..dfa407964fc4 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -310,6 +310,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcHasIncoherentInherentImpls | AttributeKind::MustNotSupend { .. } | AttributeKind::RustcDumpUserArgs + | AttributeKind::RustcDumpDefParents ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); @@ -369,7 +370,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::rustc_abi | sym::rustc_layout | sym::rustc_proc_macro_decls - | sym::rustc_dump_def_parents | sym::rustc_never_type_options | sym::rustc_autodiff | sym::rustc_capture_analysis From 2a455409e302df2d1db755edec775f5100641365 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 12 Jan 2026 19:47:18 +0100 Subject: [PATCH 0662/1061] Port `#[rustc_dump_item_bounds]` --- compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs | 9 +++++++++ compiler/rustc_attr_parsing/src/context.rs | 5 +++-- compiler/rustc_hir/src/attrs/data_structures.rs | 5 ++++- compiler/rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_hir_analysis/src/collect/dump.rs | 4 ++-- compiler/rustc_passes/src/check_attr.rs | 2 +- 6 files changed, 20 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs index 86cc88fe26e6..cc866f9297d2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs @@ -24,3 +24,12 @@ impl NoArgsAttributeParser for RustcDumpDefParents { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpDefParents; } + +pub(crate) struct RustcDumpItemBounds; + +impl NoArgsAttributeParser for RustcDumpItemBounds { + const PATH: &[Symbol] = &[sym::rustc_dump_item_bounds]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::AssocTy)]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpItemBounds; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index adcdbf7752a3..5b959e553482 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -63,7 +63,7 @@ use crate::attributes::proc_macro_attrs::{ }; use crate::attributes::prototype::CustomMirParser; use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; -use crate::attributes::rustc_dump::{RustcDumpUserArgs, RustcDumpDefParents}; +use crate::attributes::rustc_dump::{RustcDumpDefParents, RustcDumpItemBounds, RustcDumpUserArgs}; use crate::attributes::rustc_internal::{ RustcHasIncoherentInherentImplsParser, RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser, RustcLegacyConstGenericsParser, @@ -268,7 +268,8 @@ attribute_parsers!( Single>, Single>, Single>, - Single>, + Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 63a89c84ed4a..051bd76e6eb7 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -908,7 +908,10 @@ pub enum AttributeKind { /// Represents `#[rustc_dump_def_parents]` RustcDumpDefParents, - + + /// Represents `#[rustc_dump_item_bounds]` + RustcDumpItemBounds, + /// Represents `#[rustc_dump_user_args]` RustcDumpUserArgs, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index aa2a7cb6d4b4..f3da08bae5db 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -98,6 +98,7 @@ impl AttributeKind { RustcBuiltinMacro { .. } => Yes, RustcCoherenceIsCore(..) => No, RustcDumpDefParents => No, + RustcDumpItemBounds => No, RustcDumpUserArgs => No, RustcHasIncoherentInherentImpls => Yes, RustcLayoutScalarValidRangeEnd(..) => Yes, diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs index 1ace60721eae..f87fb3a66095 100644 --- a/compiler/rustc_hir_analysis/src/collect/dump.rs +++ b/compiler/rustc_hir_analysis/src/collect/dump.rs @@ -1,7 +1,7 @@ use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_hir::{find_attr, intravisit}; -use rustc_hir::attrs::AttributeKind; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_span::sym; @@ -39,7 +39,7 @@ pub(crate) fn predicates_and_item_bounds(tcx: TyCtxt<'_>) { } diag.emit(); } - if tcx.has_attr(id, sym::rustc_dump_item_bounds) { + if find_attr!(tcx.get_all_attrs(id), AttributeKind::RustcDumpItemBounds) { let bounds = tcx.item_bounds(id).instantiate_identity(); let span = tcx.def_span(id); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index dfa407964fc4..4f9f584a3a61 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -310,6 +310,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcHasIncoherentInherentImpls | AttributeKind::MustNotSupend { .. } | AttributeKind::RustcDumpUserArgs + | AttributeKind::RustcDumpItemBounds | AttributeKind::RustcDumpDefParents ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { @@ -386,7 +387,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::rustc_evaluate_where_clauses | sym::rustc_dump_vtable | sym::rustc_delayed_bug_from_inside_query - | sym::rustc_dump_item_bounds | sym::rustc_def_path | sym::rustc_partition_reused | sym::rustc_partition_codegened From a4c34b421cf20e187f07c5254adedcee612aaad4 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 12 Jan 2026 19:51:50 +0100 Subject: [PATCH 0663/1061] Port `#[rustc_dump_vtable]` --- .../src/attributes/rustc_dump.rs | 12 ++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 5 ++++- .../rustc_hir/src/attrs/data_structures.rs | 3 +++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + .../rustc_hir_analysis/src/collect/dump.rs | 19 ++++++++++--------- compiler/rustc_passes/src/check_attr.rs | 2 +- 6 files changed, 31 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs index cc866f9297d2..25e60d899422 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs @@ -33,3 +33,15 @@ impl NoArgsAttributeParser for RustcDumpItemBounds { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::AssocTy)]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpItemBounds; } + +pub(crate) struct RustcDumpVtable; + +impl NoArgsAttributeParser for RustcDumpVtable { + const PATH: &[Symbol] = &[sym::rustc_dump_vtable]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Impl { of_trait: true }), + Allow(Target::TyAlias), + ]); + const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcDumpVtable; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 5b959e553482..8cc09117e710 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -63,7 +63,9 @@ use crate::attributes::proc_macro_attrs::{ }; use crate::attributes::prototype::CustomMirParser; use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; -use crate::attributes::rustc_dump::{RustcDumpDefParents, RustcDumpItemBounds, RustcDumpUserArgs}; +use crate::attributes::rustc_dump::{ + RustcDumpDefParents, RustcDumpItemBounds, RustcDumpUserArgs, RustcDumpVtable, +}; use crate::attributes::rustc_internal::{ RustcHasIncoherentInherentImplsParser, RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser, RustcLegacyConstGenericsParser, @@ -271,6 +273,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 051bd76e6eb7..941c12c7d6fa 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -915,6 +915,9 @@ pub enum AttributeKind { /// Represents `#[rustc_dump_user_args]` RustcDumpUserArgs, + /// Represents `#[rustc_dump_vtable]` + RustcDumpVtable(Span), + /// Represents `#[rustc_has_incoherent_inherent_impls]` RustcHasIncoherentInherentImpls, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index f3da08bae5db..df386a00dd11 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -100,6 +100,7 @@ impl AttributeKind { RustcDumpDefParents => No, RustcDumpItemBounds => No, RustcDumpUserArgs => No, + RustcDumpVtable(..) => No, RustcHasIncoherentInherentImpls => Yes, RustcLayoutScalarValidRangeEnd(..) => Yes, RustcLayoutScalarValidRangeStart(..) => Yes, diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs index f87fb3a66095..a61ea29a1a71 100644 --- a/compiler/rustc_hir_analysis/src/collect/dump.rs +++ b/compiler/rustc_hir_analysis/src/collect/dump.rs @@ -103,7 +103,9 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) { for id in tcx.hir_free_items() { let def_id = id.owner_id.def_id; - let Some(attr) = tcx.get_attr(def_id, sym::rustc_dump_vtable) else { + let Some(&attr_span) = + find_attr!(tcx.get_all_attrs(def_id), AttributeKind::RustcDumpVtable(span) => span) + else { continue; }; @@ -112,14 +114,14 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) { let trait_ref = tcx.impl_trait_ref(def_id).instantiate_identity(); if trait_ref.has_non_region_param() { tcx.dcx().span_err( - attr.span(), + attr_span, "`rustc_dump_vtable` must be applied to non-generic impl", ); continue; } if !tcx.is_dyn_compatible(trait_ref.def_id) { tcx.dcx().span_err( - attr.span(), + attr_span, "`rustc_dump_vtable` must be applied to dyn-compatible trait", ); continue; @@ -128,7 +130,7 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) { .try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), trait_ref) else { tcx.dcx().span_err( - attr.span(), + attr_span, "`rustc_dump_vtable` applied to impl header that cannot be normalized", ); continue; @@ -139,7 +141,7 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) { let ty = tcx.type_of(def_id).instantiate_identity(); if ty.has_non_region_param() { tcx.dcx().span_err( - attr.span(), + attr_span, "`rustc_dump_vtable` must be applied to non-generic type", ); continue; @@ -148,14 +150,13 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) { tcx.try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), ty) else { tcx.dcx().span_err( - attr.span(), + attr_span, "`rustc_dump_vtable` applied to type alias that cannot be normalized", ); continue; }; let ty::Dynamic(data, _) = *ty.kind() else { - tcx.dcx() - .span_err(attr.span(), "`rustc_dump_vtable` to type alias of dyn type"); + tcx.dcx().span_err(attr_span, "`rustc_dump_vtable` to type alias of dyn type"); continue; }; if let Some(principal) = data.principal() { @@ -168,7 +169,7 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) { } _ => { tcx.dcx().span_err( - attr.span(), + attr_span, "`rustc_dump_vtable` only applies to impl, or type alias of dyn type", ); continue; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 4f9f584a3a61..3d51429f20d7 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -312,6 +312,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcDumpUserArgs | AttributeKind::RustcDumpItemBounds | AttributeKind::RustcDumpDefParents + | AttributeKind::RustcDumpVtable(..) ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); @@ -385,7 +386,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::rustc_outlives | sym::rustc_symbol_name | sym::rustc_evaluate_where_clauses - | sym::rustc_dump_vtable | sym::rustc_delayed_bug_from_inside_query | sym::rustc_def_path | sym::rustc_partition_reused From abcbf72bab56c56ab395b8c7cd44a87364ac43df Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 12 Jan 2026 19:54:54 +0100 Subject: [PATCH 0664/1061] Port `#[rustc_dump_predicates]` --- .../src/attributes/rustc_dump.rs | 15 +++++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 4 +++- compiler/rustc_hir/src/attrs/data_structures.rs | 3 +++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_hir_analysis/src/collect/dump.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 2 +- 6 files changed, 24 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs index 25e60d899422..53120dece916 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs @@ -34,6 +34,21 @@ impl NoArgsAttributeParser for RustcDumpItemBounds { const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpItemBounds; } +pub(crate) struct RustcDumpPredicates; + +impl NoArgsAttributeParser for RustcDumpPredicates { + const PATH: &[Symbol] = &[sym::rustc_dump_predicates]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Struct), + Allow(Target::Enum), + Allow(Target::Union), + Allow(Target::Trait), + Allow(Target::AssocTy), + ]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpPredicates; +} + pub(crate) struct RustcDumpVtable; impl NoArgsAttributeParser for RustcDumpVtable { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 8cc09117e710..8305d027d13c 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -64,7 +64,8 @@ use crate::attributes::proc_macro_attrs::{ use crate::attributes::prototype::CustomMirParser; use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; use crate::attributes::rustc_dump::{ - RustcDumpDefParents, RustcDumpItemBounds, RustcDumpUserArgs, RustcDumpVtable, + RustcDumpDefParents, RustcDumpItemBounds, RustcDumpPredicates, RustcDumpUserArgs, + RustcDumpVtable, }; use crate::attributes::rustc_internal::{ RustcHasIncoherentInherentImplsParser, RustcLayoutScalarValidRangeEndParser, @@ -272,6 +273,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 941c12c7d6fa..3d9362d2d923 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -912,6 +912,9 @@ pub enum AttributeKind { /// Represents `#[rustc_dump_item_bounds]` RustcDumpItemBounds, + /// Represents `#[rustc_dump_predicates]` + RustcDumpPredicates, + /// Represents `#[rustc_dump_user_args]` RustcDumpUserArgs, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index df386a00dd11..48f3ceba9c39 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -99,6 +99,7 @@ impl AttributeKind { RustcCoherenceIsCore(..) => No, RustcDumpDefParents => No, RustcDumpItemBounds => No, + RustcDumpPredicates => No, RustcDumpUserArgs => No, RustcDumpVtable(..) => No, RustcHasIncoherentInherentImpls => Yes, diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs index a61ea29a1a71..2dfd4ab6111f 100644 --- a/compiler/rustc_hir_analysis/src/collect/dump.rs +++ b/compiler/rustc_hir_analysis/src/collect/dump.rs @@ -29,7 +29,7 @@ pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) { pub(crate) fn predicates_and_item_bounds(tcx: TyCtxt<'_>) { for id in tcx.hir_crate_items(()).owners() { - if tcx.has_attr(id, sym::rustc_dump_predicates) { + if find_attr!(tcx.get_all_attrs(id), AttributeKind::RustcDumpPredicates) { let preds = tcx.predicates_of(id).instantiate_identity(tcx).predicates; let span = tcx.def_span(id); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 3d51429f20d7..f047d66a8254 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -311,6 +311,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::MustNotSupend { .. } | AttributeKind::RustcDumpUserArgs | AttributeKind::RustcDumpItemBounds + | AttributeKind::RustcDumpPredicates | AttributeKind::RustcDumpDefParents | AttributeKind::RustcDumpVtable(..) ) => { /* do nothing */ } @@ -377,7 +378,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::rustc_capture_analysis | sym::rustc_regions | sym::rustc_strict_coherence - | sym::rustc_dump_predicates | sym::rustc_variance | sym::rustc_variance_of_opaques | sym::rustc_hidden_type_of_opaques From 8afa95d28f70a98d5b32b78f03a918ff5578e263 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 13 Jan 2026 15:16:06 +0000 Subject: [PATCH 0665/1061] Avoid should-fail in two ui tests should-fail is only meant for testing the compiletest framework itself. It checks that the test runner itself panicked. --- tests/ui/borrowck/two-phase-reservation-sharing-interference.rs | 2 +- tests/ui/type-inference/box_has_sigdrop.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui/borrowck/two-phase-reservation-sharing-interference.rs b/tests/ui/borrowck/two-phase-reservation-sharing-interference.rs index 61446577db29..342b8cce7b01 100644 --- a/tests/ui/borrowck/two-phase-reservation-sharing-interference.rs +++ b/tests/ui/borrowck/two-phase-reservation-sharing-interference.rs @@ -3,7 +3,7 @@ // The nll_beyond revision is disabled due to missing support from two-phase beyond autorefs //@ unused-revision-names: nll_beyond //@[nll_beyond]compile-flags: -Z two-phase-beyond-autoref -//@[nll_beyond]should-fail +//@[nll_beyond]check-fail // This is a corner case that the current implementation is (probably) // treating more conservatively than is necessary. But it also does diff --git a/tests/ui/type-inference/box_has_sigdrop.rs b/tests/ui/type-inference/box_has_sigdrop.rs index 3e801197a78e..2d1b1cd0249e 100644 --- a/tests/ui/type-inference/box_has_sigdrop.rs +++ b/tests/ui/type-inference/box_has_sigdrop.rs @@ -1,4 +1,4 @@ -//@ should-fail +//@ known-bug: unknown //@ compile-flags: -Wrust-2021-incompatible-closure-captures // Inference, canonicalization, and significant drops should work nicely together. // Related issue: #86868 From 15112eee6764c08f83d8c444dce7440d68adf9da Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 13 Jan 2026 15:21:20 +0000 Subject: [PATCH 0666/1061] Avoid should-fail in a codegen-llvm test --- .../codegen-llvm/option-niche-unfixed/option-nonzero-eq.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/codegen-llvm/option-niche-unfixed/option-nonzero-eq.rs b/tests/codegen-llvm/option-niche-unfixed/option-nonzero-eq.rs index 308856cfb7e9..1eb4542323c1 100644 --- a/tests/codegen-llvm/option-niche-unfixed/option-nonzero-eq.rs +++ b/tests/codegen-llvm/option-niche-unfixed/option-nonzero-eq.rs @@ -1,6 +1,5 @@ -//@ should-fail +//@ known-bug: #49892 //@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled -//! FIXME(#49892) //! Test that the derived implementation of `PartialEq` for `Option` is not fully //! optimized by LLVM. If this starts passing, the test and manual impl should //! be removed. @@ -18,7 +17,7 @@ pub enum Option { #[no_mangle] pub fn non_zero_eq(l: Option>, r: Option>) -> bool { // CHECK: start: - // CHECK-NEXT: icmp eq i32 - // CHECK-NEXT: ret i1 + // COMMENTEDCHECK-NEXT: icmp eq i32 + // COMMENTEDCHECK-NEXT: ret i1 l == r } From 513b6ad231859f0b3c7953c454f9b209d58c25a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 13 Jan 2026 17:41:55 +0100 Subject: [PATCH 0667/1061] Remove references to homu and fix bors delegation command --- src/doc/rustc-dev-guide/src/about-this-guide.md | 4 ++-- src/doc/rustc-dev-guide/src/compiler-team.md | 4 ++-- src/doc/rustc-dev-guide/src/contributing.md | 2 +- src/doc/rustc-dev-guide/src/tests/ci.md | 11 +++-------- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/about-this-guide.md b/src/doc/rustc-dev-guide/src/about-this-guide.md index 2082481a200e..9d493e0cb065 100644 --- a/src/doc/rustc-dev-guide/src/about-this-guide.md +++ b/src/doc/rustc-dev-guide/src/about-this-guide.md @@ -103,9 +103,9 @@ You might also find the following sites useful: [tlgba]: https://tomlee.co/2014/04/a-more-detailed-tour-of-the-rust-compiler/ [ro]: https://www.rustaceans.org/ [rctd]: tests/intro.md -[cheatsheet]: https://bors.rust-lang.org/ +[cheatsheet]: https://bors.rust-lang.org/help [Miri]: https://github.com/rust-lang/miri -[@bors]: https://github.com/bors +[@bors]: https://github.com/rust-lang/bors [a GitHub repository]: https://github.com/rust-lang/rustc-dev-guide/ [rustc API docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle [Forge]: https://forge.rust-lang.org/ diff --git a/src/doc/rustc-dev-guide/src/compiler-team.md b/src/doc/rustc-dev-guide/src/compiler-team.md index dfc1e7eedf62..495bd22da4d8 100644 --- a/src/doc/rustc-dev-guide/src/compiler-team.md +++ b/src/doc/rustc-dev-guide/src/compiler-team.md @@ -96,9 +96,9 @@ Once you have made a number of individual PRs to rustc, we will often offer r+ privileges. This means that you have the right to instruct "bors" (the robot that manages which PRs get landed into rustc) to merge a PR -([here are some instructions for how to talk to bors][homu-guide]). +([here are some instructions for how to talk to bors][bors-guide]). -[homu-guide]: https://bors.rust-lang.org/ +[bors-guide]: https://bors.rust-lang.org/ The guidelines for reviewers are as follows: diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index 40ad58e025c1..46d0dc23394a 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -283,7 +283,7 @@ this can take a while and the queue can sometimes be long. Also, note that PRs are never merged by hand. [@rustbot]: https://github.com/rustbot -[@bors]: https://github.com/bors +[@bors]: https://github.com/rust-lang/bors ### Opening a PR diff --git a/src/doc/rustc-dev-guide/src/tests/ci.md b/src/doc/rustc-dev-guide/src/tests/ci.md index e132946ae83e..ce80b07fe08d 100644 --- a/src/doc/rustc-dev-guide/src/tests/ci.md +++ b/src/doc/rustc-dev-guide/src/tests/ci.md @@ -198,7 +198,7 @@ to help make the perf comparison as fair as possible. > > 3. Run the prescribed try jobs with `@bors try`. As aforementioned, this > requires the user to either (1) have `try` permissions or (2) be delegated -> with `try` permissions by `@bors delegate` by someone who has `try` +> with `try` permissions by `@bors delegate=try` by someone who has `try` > permissions. > > Note that this is usually easier to do than manually edit [`jobs.yml`]. @@ -213,10 +213,7 @@ the corresponding PR. Multiple try builds can execute concurrently across different PRs, but there can be at most a single try build running on a single PR at any given time. -Note that try builds are handled using the [new bors] implementation. - [rustc-perf]: https://github.com/rust-lang/rustc-perf -[new bors]: https://github.com/rust-lang/bors ### Modifying CI jobs @@ -281,8 +278,7 @@ Breakages like these usually happen when another, incompatible PR is merged after the build happened. To ensure a `main` branch that works all the time, we forbid manual merges. -Instead, all PRs have to be approved through our bot, [bors] (the software -behind it is called [homu]). +Instead, all PRs have to be approved through our bot, [bors]. All the approved PRs are put in a [merge queue] (sorted by priority and creation date) and are automatically tested one at the time. If all the builders are green, the PR is merged, otherwise the failure is @@ -465,8 +461,7 @@ To do this: [`jobs.yml`]: https://github.com/rust-lang/rust/blob/HEAD/src/ci/github-actions/jobs.yml [`.github/workflows/ci.yml`]: https://github.com/rust-lang/rust/blob/HEAD/.github/workflows/ci.yml [`src/ci/citool`]: https://github.com/rust-lang/rust/blob/HEAD/src/ci/citool -[bors]: https://github.com/bors -[homu]: https://github.com/rust-lang/homu +[bors]: https://github.com/rust-lang/bors [merge queue]: https://bors.rust-lang.org/queue/rust [dist-x86_64-linux]: https://github.com/rust-lang/rust/blob/HEAD/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile [the GitHub Actions workflows page]: https://github.com/rust-lang/rust/actions From 27e09ce0be5693cd4767576bf97098ddb994d59e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 13 Jan 2026 16:53:21 +0000 Subject: [PATCH 0668/1061] Update ui-fulldeps --stage 2 tests --- tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr | 2 +- tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr | 2 +- .../diagnostic-derive-doc-comment-field.stderr | 4 ++-- tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr b/tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr index d2303ef4bbb5..4a6ca56bf329 100644 --- a/tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr +++ b/tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `NotAValidResultType: VisitorResult` is not satisf LL | type Result = NotAValidResultType; | ^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound | -help: the trait `VisitorResult` is not implemented for `NotAValidResultType` +help: the nightly-only, unstable trait `VisitorResult` is not implemented for `NotAValidResultType` --> $DIR/rustc-dev-remap.rs:LL:COL | LL | struct NotAValidResultType; diff --git a/tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr b/tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr index 50bb60e78d68..18dffdb2cf79 100644 --- a/tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr +++ b/tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `NotAValidResultType: VisitorResult` is not satisf LL | type Result = NotAValidResultType; | ^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound | -help: the trait `VisitorResult` is not implemented for `NotAValidResultType` +help: the nightly-only, unstable trait `VisitorResult` is not implemented for `NotAValidResultType` --> $DIR/rustc-dev-remap.rs:LL:COL | LL | struct NotAValidResultType; diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr index 72e150dd5178..316f23888bc1 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr @@ -7,7 +7,7 @@ LL | #[derive(Diagnostic)] LL | arg: NotIntoDiagArg, | ^^^^^^^^^^^^^^ unsatisfied trait bound | -help: the trait `IntoDiagArg` is not implemented for `NotIntoDiagArg` +help: the nightly-only, unstable trait `IntoDiagArg` is not implemented for `NotIntoDiagArg` --> $DIR/diagnostic-derive-doc-comment-field.rs:28:1 | LL | struct NotIntoDiagArg; @@ -29,7 +29,7 @@ LL | #[derive(Subdiagnostic)] LL | arg: NotIntoDiagArg, | ^^^^^^^^^^^^^^ unsatisfied trait bound | -help: the trait `IntoDiagArg` is not implemented for `NotIntoDiagArg` +help: the nightly-only, unstable trait `IntoDiagArg` is not implemented for `NotIntoDiagArg` --> $DIR/diagnostic-derive-doc-comment-field.rs:28:1 | LL | struct NotIntoDiagArg; diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index f2244a968769..90ad21ef08f9 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -657,7 +657,7 @@ LL | #[derive(Diagnostic)] LL | other: Hello, | ^^^^^ unsatisfied trait bound | -help: the trait `IntoDiagArg` is not implemented for `Hello` +help: the nightly-only, unstable trait `IntoDiagArg` is not implemented for `Hello` --> $DIR/diagnostic-derive.rs:40:1 | LL | struct Hello {} From 814647f047e277399b6185b9e94f6096edb16a07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 26 Dec 2025 20:23:50 +0000 Subject: [PATCH 0669/1061] Change some `matches!(.., .. if ..)` with let-chains --- compiler/rustc_const_eval/src/check_consts/check.rs | 13 +++++++------ .../rustc_lint/src/early/diagnostics/check_cfg.rs | 2 +- compiler/rustc_lint/src/transmute.rs | 4 +++- compiler/rustc_middle/src/mir/pretty.rs | 7 +++++-- compiler/rustc_parse/src/parser/diagnostics.rs | 4 +++- compiler/rustc_parse/src/parser/mod.rs | 7 +++---- .../src/error_reporting/traits/suggestions.rs | 3 ++- 7 files changed, 24 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index b06b407a6085..3a85ca3760d2 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -833,12 +833,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // const-eval of `panic_display` assumes the argument is `&&str` if tcx.is_lang_item(callee, LangItem::PanicDisplay) { - match args[0].node.ty(&self.ccx.body.local_decls, tcx).kind() { - ty::Ref(_, ty, _) if matches!(ty.kind(), ty::Ref(_, ty, _) if ty.is_str()) => - {} - _ => { - self.check_op(ops::PanicNonStr); - } + if let ty::Ref(_, ty, _) = + args[0].node.ty(&self.ccx.body.local_decls, tcx).kind() + && let ty::Ref(_, ty, _) = ty.kind() + && ty.is_str() + { + } else { + self.check_op(ops::PanicNonStr); } // Allow this call, skip all the checks below. return; diff --git a/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs b/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs index 0c8d7523a9dc..fab0e9e863dc 100644 --- a/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs +++ b/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs @@ -70,7 +70,7 @@ fn cargo_help_sub( // `build_script_build`) to try to figure out if we are building a Cargo build script let unescaped = &inst(EscapeQuotes::No); - if matches!(&sess.opts.crate_name, Some(crate_name) if crate_name == "build_script_build") { + if let Some("build_script_build") = sess.opts.crate_name.as_deref() { lints::UnexpectedCfgCargoHelp::lint_cfg(unescaped) } else { lints::UnexpectedCfgCargoHelp::lint_cfg_and_build_rs(unescaped, &inst(EscapeQuotes::Yes)) diff --git a/compiler/rustc_lint/src/transmute.rs b/compiler/rustc_lint/src/transmute.rs index 98510eea73b8..6bc4617eb2dc 100644 --- a/compiler/rustc_lint/src/transmute.rs +++ b/compiler/rustc_lint/src/transmute.rs @@ -152,7 +152,9 @@ fn check_int_to_ptr_transmute<'tcx>( return; }; // bail-out if the argument is literal 0 as we have other lints for those cases - if matches!(arg.kind, hir::ExprKind::Lit(hir::Lit { node: LitKind::Int(v, _), .. }) if v == 0) { + if let hir::ExprKind::Lit(hir::Lit { node: LitKind::Int(v, _), .. }) = arg.kind + && v == 0 + { return; } // bail-out if the inner type is a ZST diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index a31f03362a3d..ded02595563c 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1871,13 +1871,16 @@ fn pretty_print_const_value_tcx<'tcx>( let u8_type = tcx.types.u8; match (ct, ty.kind()) { // Byte/string slices, printed as (byte) string literals. - (_, ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Str) => { + (_, ty::Ref(_, inner_ty, _)) if let ty::Str = inner_ty.kind() => { if let Some(data) = ct.try_get_slice_bytes_for_diagnostics(tcx) { fmt.write_str(&format!("{:?}", String::from_utf8_lossy(data)))?; return Ok(()); } } - (_, ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Slice(t) if *t == u8_type) => { + (_, ty::Ref(_, inner_ty, _)) + if let ty::Slice(t) = inner_ty.kind() + && *t == u8_type => + { if let Some(data) = ct.try_get_slice_bytes_for_diagnostics(tcx) { pretty_print_byte_str(fmt, data)?; return Ok(()); diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 70ec80a50812..2fd1d146b1f6 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -761,7 +761,9 @@ impl<'a> Parser<'a> { } // Check for misspelled keywords if there are no suggestions added to the diagnostic. - if matches!(&err.suggestions, Suggestions::Enabled(list) if list.is_empty()) { + if let Suggestions::Enabled(list) = &err.suggestions + && list.is_empty() + { self.check_for_misspelled_kw(&mut err, &expected); } Err(err) diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 4dade1d01282..d6e99bc540f7 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1203,10 +1203,9 @@ impl<'a> Parser<'a> { let mut token = Token::dummy(); while i < dist { token = cursor.next().0; - if matches!( - token.kind, - token::OpenInvisible(origin) | token::CloseInvisible(origin) if origin.skip() - ) { + if let token::OpenInvisible(origin) | token::CloseInvisible(origin) = token.kind + && origin.skip() + { continue; } i += 1; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 511e9e85b5f6..507371425e4f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -4722,7 +4722,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // slices of `element_ty` with `mutability`. let mut is_slice = |candidate: Ty<'tcx>| match *candidate.kind() { ty::RawPtr(t, m) | ty::Ref(_, t, m) => { - if matches!(*t.kind(), ty::Slice(e) if e == element_ty) + if let ty::Slice(e) = *t.kind() + && e == element_ty && m == mutability.unwrap_or(m) { // Use the candidate's mutability going forward. From e027ecdbb57822527ed69e3cc81ca9ce36735678 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 12 Jan 2026 16:24:49 -0500 Subject: [PATCH 0670/1061] feat: support arrays in type reflection --- .../src/const_eval/type_info.rs | 35 +++++++++++++++++-- compiler/rustc_span/src/symbol.rs | 2 ++ library/core/src/mem/type_info.rs | 13 +++++++ library/coretests/tests/lib.rs | 1 + library/coretests/tests/mem.rs | 2 ++ library/coretests/tests/mem/type_info.rs | 23 ++++++++++++ tests/ui/reflection/dump.rs | 1 + tests/ui/reflection/dump.run.stdout | 6 ++++ 8 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 library/coretests/tests/mem/type_info.rs diff --git a/compiler/rustc_const_eval/src/const_eval/type_info.rs b/compiler/rustc_const_eval/src/const_eval/type_info.rs index f932b198b426..814c81278a10 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -3,7 +3,7 @@ use rustc_hir::LangItem; use rustc_middle::mir::interpret::CtfeProvenance; use rustc_middle::span_bug; use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::{self, ScalarInt, Ty}; +use rustc_middle::ty::{self, Const, ScalarInt, Ty}; use rustc_span::{Symbol, sym}; use crate::const_eval::CompileTimeMachine; @@ -56,6 +56,14 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { self.write_tuple_fields(tuple_place, fields, ty)?; variant } + ty::Array(ty, len) => { + let (variant, variant_place) = downcast(sym::Array)?; + let array_place = self.project_field(&variant_place, FieldIdx::ZERO)?; + + self.write_array_type_info(array_place, *ty, *len)?; + + variant + } // For now just merge all primitives into one `Leaf` variant with no data ty::Uint(_) | ty::Int(_) | ty::Float(_) | ty::Char | ty::Bool => { downcast(sym::Leaf)?.0 @@ -63,7 +71,6 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { ty::Adt(_, _) | ty::Foreign(_) | ty::Str - | ty::Array(_, _) | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(..) @@ -172,4 +179,28 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { } interp_ok(()) } + + pub(crate) fn write_array_type_info( + &mut self, + place: impl Writeable<'tcx, CtfeProvenance>, + ty: Ty<'tcx>, + len: Const<'tcx>, + ) -> InterpResult<'tcx> { + // Iterate over all fields of `type_info::Array`. + for (field_idx, field) in + place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated() + { + let field_place = self.project_field(&place, field_idx)?; + + match field.name { + // Write the `TypeId` of the array's elements to the `element_ty` field. + sym::element_ty => self.write_type_id(ty, &field_place)?, + // Write the length of the array to the `len` field. + sym::len => self.write_scalar(len.to_leaf(), &field_place)?, + other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"), + } + } + + interp_ok(()) + } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index f56c3421ce0f..34804160ed39 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -162,6 +162,7 @@ symbols! { Arc, ArcWeak, Argument, + Array, ArrayIntoIter, AsMut, AsRef, @@ -939,6 +940,7 @@ symbols! { eii_impl, eii_internals, eii_shared_macro, + element_ty, emit, emit_enum, emit_enum_variant, diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index 7938e2b52ed0..208cbc299aae 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -43,6 +43,8 @@ impl Type { pub enum TypeKind { /// Tuples. Tuple(Tuple), + /// Arrays. + Array(Array), /// Primitives /// FIXME(#146922): disambiguate further Leaf, @@ -69,3 +71,14 @@ pub struct Field { /// Offset in bytes from the parent type pub offset: usize, } + +/// Compile-time type information about arrays. +#[derive(Debug)] +#[non_exhaustive] +#[unstable(feature = "type_info", issue = "146922")] +pub struct Array { + /// The type of each element in the array. + pub element_ty: TypeId, + /// The length of the array. + pub len: usize, +} diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index ff4fc4c892af..caa130be1483 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -115,6 +115,7 @@ #![feature(try_blocks)] #![feature(try_find)] #![feature(try_trait_v2)] +#![feature(type_info)] #![feature(uint_bit_width)] #![feature(uint_gather_scatter_bits)] #![feature(unsize)] diff --git a/library/coretests/tests/mem.rs b/library/coretests/tests/mem.rs index 5247e01fba01..193d5416b06a 100644 --- a/library/coretests/tests/mem.rs +++ b/library/coretests/tests/mem.rs @@ -1,3 +1,5 @@ +mod type_info; + use core::mem::*; use core::{array, ptr}; use std::cell::Cell; diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs new file mode 100644 index 000000000000..5cd690363a01 --- /dev/null +++ b/library/coretests/tests/mem/type_info.rs @@ -0,0 +1,23 @@ +use std::any::TypeId; +use std::mem::type_info::{Type, TypeKind}; + +#[test] +fn test_arrays() { + // Normal array. + match const { Type::of::<[u16; 4]>() }.kind { + TypeKind::Array(array) => { + assert_eq!(array.element_ty, TypeId::of::()); + assert_eq!(array.len, 4); + } + _ => unreachable!(), + } + + // Zero-length array. + match const { Type::of::<[bool; 0]>() }.kind { + TypeKind::Array(array) => { + assert_eq!(array.element_ty, TypeId::of::()); + assert_eq!(array.len, 0); + } + _ => unreachable!(), + } +} diff --git a/tests/ui/reflection/dump.rs b/tests/ui/reflection/dump.rs index 3bf4f32b6641..cc3bcb8b9faf 100644 --- a/tests/ui/reflection/dump.rs +++ b/tests/ui/reflection/dump.rs @@ -22,6 +22,7 @@ struct Unsized { fn main() { println!("{:#?}", const { Type::of::<(u8, u8, ())>() }.kind); + println!("{:#?}", const { Type::of::<[u8; 2]>() }.kind); println!("{:#?}", const { Type::of::() }.kind); println!("{:#?}", const { Type::of::() }.kind); println!("{:#?}", const { Type::of::<&Unsized>() }.kind); diff --git a/tests/ui/reflection/dump.run.stdout b/tests/ui/reflection/dump.run.stdout index 71fd80b46658..7a0bb9592a3c 100644 --- a/tests/ui/reflection/dump.run.stdout +++ b/tests/ui/reflection/dump.run.stdout @@ -16,6 +16,12 @@ Tuple( ], }, ) +Array( + Array { + element_ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), + len: 2, + }, +) Other Other Other From 71f8ea99fe5cfbca752ddcfb1c0b13453941a9e6 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Tue, 13 Jan 2026 12:19:37 -0500 Subject: [PATCH 0671/1061] refactor: move tuples type info ui test to coretest --- library/coretests/tests/mem/type_info.rs | 33 ++++++++++++++++++++++ tests/ui/reflection/tuples.rs | 36 ------------------------ 2 files changed, 33 insertions(+), 36 deletions(-) delete mode 100644 tests/ui/reflection/tuples.rs diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs index 5cd690363a01..b3b8d96d49b0 100644 --- a/library/coretests/tests/mem/type_info.rs +++ b/library/coretests/tests/mem/type_info.rs @@ -21,3 +21,36 @@ fn test_arrays() { _ => unreachable!(), } } + +#[test] +fn test_tuples() { + fn assert_tuple_arity() { + match const { Type::of::() }.kind { + TypeKind::Tuple(tup) => { + assert_eq!(tup.fields.len(), N); + } + _ => unreachable!(), + } + } + + assert_tuple_arity::<(), 0>(); + assert_tuple_arity::<(u8,), 1>(); + assert_tuple_arity::<(u8, u8), 2>(); + + const { + match Type::of::<(u8, u8)>().kind { + TypeKind::Tuple(tup) => { + let [a, b] = tup.fields else { unreachable!() }; + + assert!(a.offset == 0); + assert!(b.offset == 1); + + match (a.ty.info().kind, b.ty.info().kind) { + (TypeKind::Leaf, TypeKind::Leaf) => {} + _ => unreachable!(), + } + } + _ => unreachable!(), + } + } +} diff --git a/tests/ui/reflection/tuples.rs b/tests/ui/reflection/tuples.rs deleted file mode 100644 index eab25a691efe..000000000000 --- a/tests/ui/reflection/tuples.rs +++ /dev/null @@ -1,36 +0,0 @@ -#![feature(type_info)] - -//@ run-pass - -use std::mem::type_info::{Type, TypeKind}; - -fn assert_tuple_arity() { - const { - match &Type::of::().kind { - TypeKind::Tuple(tup) => { - assert!(tup.fields.len() == N); - } - _ => unreachable!(), - } - } -} - -fn main() { - assert_tuple_arity::<(), 0>(); - assert_tuple_arity::<(u8,), 1>(); - assert_tuple_arity::<(u8, u8), 2>(); - const { - match &Type::of::<(u8, u8)>().kind { - TypeKind::Tuple(tup) => { - let [a, b] = tup.fields else { unreachable!() }; - assert!(a.offset == 0); - assert!(b.offset == 1); - match (&a.ty.info().kind, &b.ty.info().kind) { - (TypeKind::Leaf, TypeKind::Leaf) => {} - _ => unreachable!(), - } - } - _ => unreachable!(), - } - } -} From c4820e6cb45407c8d34ebf7fe7a8bdd683f2003f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 9 Jan 2026 14:40:20 +0300 Subject: [PATCH 0672/1061] resolve: Refactor away the side table `decl_parent_modules` Instead keep parent modules in `DeclData` itself --- .../rustc_resolve/src/build_reduced_graph.rs | 33 ++++++++++--------- compiler/rustc_resolve/src/diagnostics.rs | 27 +++++++-------- compiler/rustc_resolve/src/imports.rs | 9 ++--- compiler/rustc_resolve/src/lib.rs | 31 +++++++---------- 4 files changed, 46 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 752d8c46beb4..736648c125b6 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -48,14 +48,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// and report an error in case of a collision. pub(crate) fn plant_decl_into_local_module( &mut self, - parent: Module<'ra>, ident: Macros20NormalizedIdent, ns: Namespace, decl: Decl<'ra>, ) { - if let Err(old_decl) = self.try_plant_decl_into_local_module(parent, ident, ns, decl, false) - { - self.report_conflict(parent, ident.0, ns, old_decl, decl); + if let Err(old_decl) = self.try_plant_decl_into_local_module(ident, ns, decl, false) { + self.report_conflict(ident.0, ns, old_decl, decl); } } @@ -70,9 +68,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { span: Span, expn_id: LocalExpnId, ) { - let decl = self.arenas.new_def_decl(res, vis.to_def_id(), span, expn_id); + let decl = self.arenas.new_def_decl(res, vis.to_def_id(), span, expn_id, Some(parent)); let ident = Macros20NormalizedIdent::new(ident); - self.plant_decl_into_local_module(parent, ident, ns, decl); + self.plant_decl_into_local_module(ident, ns, decl); } /// Create a name definitinon from the given components, and put it into the extern module. @@ -96,6 +94,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { vis: CmCell::new(vis), span, expansion, + parent_module: Some(parent), }); // Even if underscore names cannot be looked up, we still need to add them to modules, // because they can be fetched by glob imports from those modules, and bring traits @@ -289,7 +288,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let ModChild { ident: _, res, vis, ref reexport_chain } = *ambig_child; let span = child_span(self, reexport_chain, res); let res = res.expect_non_local(); - self.arenas.new_def_decl(res, vis, span, expansion) + self.arenas.new_def_decl(res, vis, span, expansion, Some(parent)) }); // Record primary definitions. @@ -844,7 +843,6 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { ident, local_def_id, vis, - parent, ); } @@ -976,10 +974,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { ident: Ident, local_def_id: LocalDefId, vis: Visibility, - parent: Module<'ra>, ) { let sp = item.span; let parent_scope = self.parent_scope; + let parent = parent_scope.module; let expansion = parent_scope.expansion; let (used, module, decl) = if orig_name.is_none() && ident.name == kw::SelfLower { @@ -1009,7 +1007,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let import = self.r.arenas.alloc_import(ImportData { kind: ImportKind::ExternCrate { source: orig_name, target: ident, id: item.id }, root_id: item.id, - parent_scope: self.parent_scope, + parent_scope, imported_module: CmCell::new(module), has_attributes: !item.attrs.is_empty(), use_span_with_attributes: item.span_with_attributes(), @@ -1057,7 +1055,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { }), }; } - self.r.plant_decl_into_local_module(parent, ident, TypeNS, import_decl); + self.r.plant_decl_into_local_module(ident, TypeNS, import_decl); } /// Constructs the reduced graph for one foreign item. @@ -1300,14 +1298,19 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } else { Visibility::Restricted(CRATE_DEF_ID) }; - let decl = self.r.arenas.new_def_decl(res, vis.to_def_id(), span, expansion); - self.r.set_decl_parent_module(decl, parent_scope.module); + let decl = self.r.arenas.new_def_decl( + res, + vis.to_def_id(), + span, + expansion, + Some(parent_scope.module), + ); self.r.all_macro_rules.insert(ident.name); if is_macro_export { let import = self.r.arenas.alloc_import(ImportData { kind: ImportKind::MacroExport, root_id: item.id, - parent_scope: self.parent_scope, + parent_scope: ParentScope { module: self.r.graph_root, ..parent_scope }, imported_module: CmCell::new(None), has_attributes: false, use_span_with_attributes: span, @@ -1320,7 +1323,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { }); self.r.import_use_map.insert(import, Used::Other); let import_decl = self.r.new_import_decl(decl, import); - self.r.plant_decl_into_local_module(self.r.graph_root, ident, MacroNS, import_decl); + self.r.plant_decl_into_local_module(ident, MacroNS, import_decl); } else { self.r.check_reserved_macro_name(ident.0, res); self.insert_unused_macro(ident.0, def_id, item.id); diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 7bc08f1de546..b80011e8c0cb 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -210,7 +210,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn report_conflict( &mut self, - parent: Module<'_>, ident: Ident, ns: Namespace, new_binding: Decl<'ra>, @@ -218,13 +217,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) { // Error on the second of two conflicting names if old_binding.span.lo() > new_binding.span.lo() { - return self.report_conflict(parent, ident, ns, old_binding, new_binding); + return self.report_conflict(ident, ns, old_binding, new_binding); } - let container = match parent.kind { + let container = match old_binding.parent_module.unwrap().kind { // Avoid using TyCtxt::def_kind_descr in the resolver, because it // indirectly *calls* the resolver, and would cause a query cycle. - ModuleKind::Def(kind, _, _) => kind.descr(parent.def_id()), + ModuleKind::Def(kind, def_id, _) => kind.descr(def_id), ModuleKind::Block => "block", }; @@ -2034,15 +2033,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { help_msgs.push(format!("use `::{ident}` to refer to this {thing} unambiguously")) } - if let Scope::ModuleNonGlobs(module, _) | Scope::ModuleGlobs(module, _) = scope { - if module == self.graph_root { - help_msgs.push(format!( - "use `crate::{ident}` to refer to this {thing} unambiguously" - )); - } else if module != self.empty_module && module.is_normal() { - help_msgs.push(format!( - "use `self::{ident}` to refer to this {thing} unambiguously" - )); + if kind != AmbiguityKind::GlobVsGlob { + if let Scope::ModuleNonGlobs(module, _) | Scope::ModuleGlobs(module, _) = scope { + if module == self.graph_root { + help_msgs.push(format!( + "use `crate::{ident}` to refer to this {thing} unambiguously" + )); + } else if module.is_normal() { + help_msgs.push(format!( + "use `self::{ident}` to refer to this {thing} unambiguously" + )); + } } } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 4447374b8b06..e525abd00f99 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -340,6 +340,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { span: import.span, vis: CmCell::new(vis), expansion: import.parent_scope.expansion, + parent_module: Some(import.parent_scope.module), }) } @@ -409,15 +410,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// and return existing declaration if there is a collision. pub(crate) fn try_plant_decl_into_local_module( &mut self, - module: Module<'ra>, ident: Macros20NormalizedIdent, ns: Namespace, decl: Decl<'ra>, warn_ambiguity: bool, ) -> Result<(), Decl<'ra>> { + let module = decl.parent_module.unwrap(); let res = decl.res(); self.check_reserved_macro_name(ident.0, res); - self.set_decl_parent_module(decl, module); // Even if underscore names cannot be looked up, we still need to add them to modules, // because they can be fetched by glob imports from those modules, and bring traits // into scope both directly and through glob imports. @@ -511,7 +511,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if self.is_accessible_from(binding.vis(), scope) { let import_decl = self.new_import_decl(binding, *import); let _ = self.try_plant_decl_into_local_module( - import.parent_scope.module, ident, key.ns, import_decl, @@ -535,7 +534,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.per_ns(|this, ns| { let module = import.parent_scope.module; let ident = Macros20NormalizedIdent::new(target); - let _ = this.try_plant_decl_into_local_module(module, ident, ns, dummy_decl, false); + let _ = this.try_plant_decl_into_local_module(ident, ns, dummy_decl, false); // Don't remove underscores from `single_imports`, they were never added. if target.name != kw::Underscore { let key = BindingKey::new(ident, ns); @@ -916,7 +915,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // We need the `target`, `source` can be extracted. let import_decl = this.new_import_decl(binding, import); this.get_mut_unchecked().plant_decl_into_local_module( - parent, Macros20NormalizedIdent::new(target), ns, import_decl, @@ -1542,7 +1540,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .and_then(|r| r.binding()) .is_some_and(|binding| binding.warn_ambiguity_recursive()); let _ = self.try_plant_decl_into_local_module( - import.parent_scope.module, key.ident, key.ns, import_decl, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index c4c1e06f94ae..2c22aacb3241 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -67,7 +67,6 @@ use rustc_metadata::creader::CStore; use rustc_middle::metadata::{AmbigModChild, ModChild, Reexport}; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::query::Providers; -use rustc_middle::span_bug; use rustc_middle::ty::{ self, DelegationFnSig, DelegationInfo, Feed, MainDefinition, RegisteredTools, ResolverAstLowering, ResolverGlobalCtxt, TyCtxt, TyCtxtFeed, Visibility, @@ -812,6 +811,7 @@ struct DeclData<'ra> { expansion: LocalExpnId, span: Span, vis: CmCell>, + parent_module: Option>, } /// All name declarations are unique and allocated on a same arena, @@ -922,7 +922,6 @@ struct AmbiguityError<'ra> { ident: Ident, b1: Decl<'ra>, b2: Decl<'ra>, - // `empty_module` in module scope serves as an unknown module here. scope1: Scope<'ra>, scope2: Scope<'ra>, warning: Option, @@ -1186,7 +1185,6 @@ pub struct Resolver<'ra, 'tcx> { local_module_map: FxIndexMap>, /// Lazily populated cache of modules loaded from external crates. extern_module_map: CacheRefCell>>, - decl_parent_modules: FxHashMap, Module<'ra>>, /// Maps glob imports to the names of items actually imported. glob_map: FxIndexMap>, @@ -1349,6 +1347,7 @@ impl<'ra> ResolverArenas<'ra> { vis: Visibility, span: Span, expansion: LocalExpnId, + parent_module: Option>, ) -> Decl<'ra> { self.alloc_decl(DeclData { kind: DeclKind::Def(res), @@ -1357,11 +1356,12 @@ impl<'ra> ResolverArenas<'ra> { vis: CmCell::new(vis), span, expansion, + parent_module, }) } fn new_pub_def_decl(&'ra self, res: Res, span: Span, expn_id: LocalExpnId) -> Decl<'ra> { - self.new_def_decl(res, Visibility::Public, span, expn_id) + self.new_def_decl(res, Visibility::Public, span, expn_id, None) } fn new_module( @@ -1616,7 +1616,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { local_module_map, extern_module_map: Default::default(), block_map: Default::default(), - decl_parent_modules: FxHashMap::default(), ast_transform_scopes: FxHashMap::default(), glob_map: Default::default(), @@ -2071,8 +2070,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, b1: used_decl, b2, - scope1: Scope::ModuleGlobs(self.empty_module, None), - scope2: Scope::ModuleGlobs(self.empty_module, None), + scope1: Scope::ModuleGlobs(used_decl.parent_module.unwrap(), None), + scope2: Scope::ModuleGlobs(b2.parent_module.unwrap(), None), warning: if warn_ambiguity { Some(AmbiguityWarning::GlobImport) } else { None }, }; if !self.matches_previous_ambiguity_error(&ambiguity_error) { @@ -2237,14 +2236,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { vis.is_accessible_from(module.nearest_parent_mod(), self.tcx) } - fn set_decl_parent_module(&mut self, decl: Decl<'ra>, module: Module<'ra>) { - if let Some(old_module) = self.decl_parent_modules.insert(decl, module) { - if module != old_module { - span_bug!(decl.span, "parent module is reset for a name declaration"); - } - } - } - fn disambiguate_macro_rules_vs_modularized( &self, macro_rules: Decl<'ra>, @@ -2254,13 +2245,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // is disambiguated to mitigate regressions from macro modularization. // Scoping for `macro_rules` behaves like scoping for `let` at module level, in general. // - // panic on index should be impossible, the only name_bindings passed in should be from + // Panic on unwrap should be impossible, the only name_bindings passed in should be from // `resolve_ident_in_scope_set` which will always refer to a local binding from an - // import or macro definition - let macro_rules = &self.decl_parent_modules[¯o_rules]; - let modularized = &self.decl_parent_modules[&modularized]; + // import or macro definition. + let macro_rules = macro_rules.parent_module.unwrap(); + let modularized = modularized.parent_module.unwrap(); macro_rules.nearest_parent_mod() == modularized.nearest_parent_mod() - && modularized.is_ancestor_of(*macro_rules) + && modularized.is_ancestor_of(macro_rules) } fn extern_prelude_get_item<'r>( From 5435e8188ce1bf0912b3a98a54e316e391d3ca27 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Tue, 13 Jan 2026 18:52:04 +0100 Subject: [PATCH 0673/1061] also handle ENOTTY ioctl errors when checking pidfd -> pid support Otherwise the std testsuite fails on older kernels. --- library/std/src/sys/pal/unix/linux/pidfd.rs | 2 +- library/std/src/sys/pal/unix/linux/pidfd/tests.rs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/pal/unix/linux/pidfd.rs b/library/std/src/sys/pal/unix/linux/pidfd.rs index e9e4831fcc02..671046949aa1 100644 --- a/library/std/src/sys/pal/unix/linux/pidfd.rs +++ b/library/std/src/sys/pal/unix/linux/pidfd.rs @@ -33,7 +33,7 @@ impl PidFd { match cvt(unsafe { libc::ioctl(self.0.as_raw_fd(), libc::PIDFD_GET_INFO, &mut pidfd_info) }) { Ok(_) => {} - Err(e) if e.raw_os_error() == Some(libc::EINVAL) => { + Err(e) if matches!(e.raw_os_error(), Some(libc::EINVAL | libc::ENOTTY)) => { // kernel doesn't support that ioctl, try the glibc helper that looks at procfs weak!( fn pidfd_getpid(pidfd: RawFd) -> libc::pid_t; diff --git a/library/std/src/sys/pal/unix/linux/pidfd/tests.rs b/library/std/src/sys/pal/unix/linux/pidfd/tests.rs index a3bb5d5d64ba..0330f28e647d 100644 --- a/library/std/src/sys/pal/unix/linux/pidfd/tests.rs +++ b/library/std/src/sys/pal/unix/linux/pidfd/tests.rs @@ -1,6 +1,5 @@ use super::PidFd as InternalPidFd; use crate::assert_matches::assert_matches; -use crate::io::ErrorKind; use crate::os::fd::AsRawFd; use crate::os::linux::process::{ChildExt, CommandExt as _}; use crate::os::unix::process::{CommandExt as _, ExitStatusExt}; @@ -62,7 +61,9 @@ fn test_command_pidfd() { if let Ok(pidfd) = child.pidfd() { match pidfd.as_inner().pid() { Ok(pid) => assert_eq!(pid, id), - Err(e) if e.kind() == ErrorKind::InvalidInput => { /* older kernel */ } + Err(e) if matches!(e.raw_os_error(), Some(libc::EINVAL | libc::ENOTTY)) => { + /* older kernel */ + } Err(e) => panic!("unexpected error getting pid from pidfd: {}", e), } } From 348bfe3e355a4479287d3940ca6b87f9be967040 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 13 Jan 2026 10:54:33 -0800 Subject: [PATCH 0674/1061] compiler: upgrade to hashbrown 0.16.1 See also #135634, #149159, and rust-lang/hashbrown#662. This includes an in-tree upgrade of `indexmap` as well, which uses the new `HashTable` buckets API internally, hopefully impacting performance for the better! --- Cargo.lock | 19 +++++++++++-------- compiler/rustc_data_structures/Cargo.toml | 4 ++-- compiler/rustc_mir_transform/Cargo.toml | 2 +- compiler/rustc_query_system/Cargo.toml | 2 +- src/bootstrap/src/utils/proc_macro_deps.rs | 1 + 5 files changed, 16 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bf28939ac87b..45d01c486faf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1670,9 +1670,12 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "foldhash 0.2.0", +] [[package]] name = "heck" @@ -1950,12 +1953,12 @@ checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5" [[package]] name = "indexmap" -version = "2.12.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" dependencies = [ "equivalent", - "hashbrown 0.16.0", + "hashbrown 0.16.1", "serde", "serde_core", ] @@ -3730,7 +3733,7 @@ dependencies = [ "either", "elsa", "ena", - "hashbrown 0.15.5", + "hashbrown 0.16.1", "indexmap", "jobserver", "libc", @@ -4346,7 +4349,7 @@ name = "rustc_mir_transform" version = "0.0.0" dependencies = [ "either", - "hashbrown 0.15.5", + "hashbrown 0.16.1", "itertools", "rustc_abi", "rustc_arena", @@ -4557,7 +4560,7 @@ dependencies = [ name = "rustc_query_system" version = "0.0.0" dependencies = [ - "hashbrown 0.15.5", + "hashbrown 0.16.1", "parking_lot", "rustc_abi", "rustc_ast", diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index c8296e05f6bd..f358ffffb47d 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -10,7 +10,7 @@ bitflags = "2.4.1" either = "1.0" elsa = "1.11.0" ena = "0.14.3" -indexmap = "2.4.0" +indexmap = "2.12.1" jobserver_crate = { version = "0.1.28", package = "jobserver" } measureme = "12.0.1" parking_lot = "0.12" @@ -31,7 +31,7 @@ tracing = "0.1" # tidy-alphabetical-end [dependencies.hashbrown] -version = "0.15.2" +version = "0.16.1" default-features = false features = ["nightly"] # for may_dangle diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml index 6df7a869ca28..22de197d374a 100644 --- a/compiler/rustc_mir_transform/Cargo.toml +++ b/compiler/rustc_mir_transform/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start either = "1" -hashbrown = "0.15" +hashbrown = { version = "0.16.1", default-features = false } itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml index 7480ba03474f..73ab03576dec 100644 --- a/compiler/rustc_query_system/Cargo.toml +++ b/compiler/rustc_query_system/Cargo.toml @@ -25,6 +25,6 @@ tracing = "0.1" # tidy-alphabetical-end [dependencies.hashbrown] -version = "0.15.2" +version = "0.16.1" default-features = false features = ["nightly"] # for may_dangle diff --git a/src/bootstrap/src/utils/proc_macro_deps.rs b/src/bootstrap/src/utils/proc_macro_deps.rs index 71b6aacdebed..f1bf6e399fb1 100644 --- a/src/bootstrap/src/utils/proc_macro_deps.rs +++ b/src/bootstrap/src/utils/proc_macro_deps.rs @@ -22,6 +22,7 @@ pub static CRATES: &[&str] = &[ "fluent-langneg", "fluent-syntax", "fnv", + "foldhash", "generic-array", "hashbrown", "heck", From afa2260a9cea4592606353895e0f8eee88356198 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 13 Jan 2026 10:54:39 -0800 Subject: [PATCH 0675/1061] library: finish unspecializing `Copy` --- library/core/src/marker.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 68f5649210de..da7ba167ef74 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -455,9 +455,6 @@ marker_impls! { /// [impls]: #implementors #[stable(feature = "rust1", since = "1.0.0")] #[lang = "copy"] -// This is unsound, but required by `hashbrown` -// FIXME(joboet): change `hashbrown` to use `TrivialClone` -#[rustc_unsafe_specialization_marker] #[rustc_diagnostic_item = "Copy"] pub trait Copy: Clone { // Empty. From a1e2cea685fca526ad36667cb9f188127c6438eb Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Tue, 13 Jan 2026 16:29:02 +0100 Subject: [PATCH 0676/1061] Port `do_not_recommend` to new attr parsing --- .../src/attributes/do_not_recommend.rs | 31 +++++++++++++++++ .../rustc_attr_parsing/src/attributes/mod.rs | 1 + compiler/rustc_attr_parsing/src/context.rs | 2 ++ .../rustc_hir/src/attrs/data_structures.rs | 3 ++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_lint/messages.ftl | 3 ++ compiler/rustc_lint/src/early/diagnostics.rs | 4 +++ compiler/rustc_lint/src/lints.rs | 4 +++ compiler/rustc_lint_defs/src/lib.rs | 1 + compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 33 +------------------ compiler/rustc_passes/messages.ftl | 3 -- compiler/rustc_passes/src/check_attr.rs | 20 +++-------- compiler/rustc_passes/src/errors.rs | 4 --- .../src/solve/fulfill/derive_errors.rs | 2 +- tests/ui/attributes/malformed-attrs.stderr | 15 ++++----- tests/ui/unpretty/diagnostic-attr.stdout | 2 +- 17 files changed, 65 insertions(+), 66 deletions(-) create mode 100644 compiler/rustc_attr_parsing/src/attributes/do_not_recommend.rs diff --git a/compiler/rustc_attr_parsing/src/attributes/do_not_recommend.rs b/compiler/rustc_attr_parsing/src/attributes/do_not_recommend.rs new file mode 100644 index 000000000000..4a89cf6515ce --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/do_not_recommend.rs @@ -0,0 +1,31 @@ +use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::lints::AttributeLintKind; +use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES; +use rustc_span::{Symbol, sym}; + +use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; +use crate::context::{AcceptContext, Stage}; +use crate::parser::ArgParser; +use crate::target_checking::{ALL_TARGETS, AllowedTargets}; + +pub(crate) struct DoNotRecommendParser; +impl SingleAttributeParser for DoNotRecommendParser { + const PATH: &[Symbol] = &[sym::diagnostic, sym::do_not_recommend]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Checked in check_attr. + const TEMPLATE: AttributeTemplate = template!(Word /*doesn't matter */); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { + let attr_span = cx.attr_span; + if !matches!(args, ArgParser::NoArgs) { + cx.emit_lint( + MALFORMED_DIAGNOSTIC_ATTRIBUTES, + AttributeLintKind::DoNotRecommendDoesNotExpectArgs, + attr_span, + ); + } + Some(AttributeKind::DoNotRecommend { attr_span }) + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index e02d71a26158..3da27f077a61 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -39,6 +39,7 @@ pub(crate) mod confusables; pub(crate) mod crate_level; pub(crate) mod debugger; pub(crate) mod deprecation; +pub(crate) mod do_not_recommend; pub(crate) mod doc; pub(crate) mod dummy; pub(crate) mod inline; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 6b1b1d484283..a207af57ccca 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -34,6 +34,7 @@ use crate::attributes::crate_level::{ }; use crate::attributes::debugger::DebuggerViualizerParser; use crate::attributes::deprecation::DeprecationParser; +use crate::attributes::do_not_recommend::DoNotRecommendParser; use crate::attributes::doc::DocParser; use crate::attributes::dummy::DummyParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; @@ -197,6 +198,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, Single, Single, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 8d18d335b355..16bee3d53297 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -731,6 +731,9 @@ pub enum AttributeKind { /// Represents `#[rustc_do_not_implement_via_object]`. DoNotImplementViaObject(Span), + /// Represents `#[diagnostic::do_not_recommend]`. + DoNotRecommend { attr_span: Span }, + /// Represents [`#[doc]`](https://doc.rust-lang.org/stable/rustdoc/write-documentation/the-doc-attribute.html). /// Represents all other uses of the [`#[doc]`](https://doc.rust-lang.org/stable/rustdoc/write-documentation/the-doc-attribute.html) /// attribute. diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 33655f4f0063..7cdcdc3a5e94 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -44,6 +44,7 @@ impl AttributeKind { DenyExplicitImpl(..) => No, Deprecation { .. } => Yes, DoNotImplementViaObject(..) => No, + DoNotRecommend { .. } => Yes, Doc(_) => Yes, DocComment { .. } => Yes, Dummy => No, diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 9b0b1abc91df..f5b882494863 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -480,6 +480,9 @@ lint_improper_ctypes_unsafe_binder = unsafe binders are incompatible with foreig lint_improper_gpu_kernel_arg = passing type `{$ty}` to a function with "gpu-kernel" ABI may have unexpected behavior .help = use primitive types and raw pointers to get reliable behavior +lint_incorrect_do_not_recommend_args = + `#[diagnostic::do_not_recommend]` does not expect any arguments + lint_int_to_ptr_transmutes = transmuting an integer to a pointer creates a pointer without provenance .note = this is dangerous because dereferencing the resulting pointer is undefined behavior .note_exposed_provenance = exposed provenance semantics can be used to create a pointer based on some previously exposed provenance diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 5745f0d4edde..037a31c162d2 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -419,5 +419,9 @@ pub fn decorate_attribute_lint( &AttributeLintKind::DocTestLiteral => lints::DocTestLiteral.decorate_lint(diag), &AttributeLintKind::AttrCrateLevelOnly => lints::AttrCrateLevelOnly.decorate_lint(diag), + + &AttributeLintKind::DoNotRecommendDoesNotExpectArgs => { + lints::DoNotRecommendDoesNotExpectArgs.decorate_lint(diag) + } } } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 33e9375ec71b..c85e4ffe91fc 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3317,3 +3317,7 @@ pub(crate) struct DocTestLiteral; #[diag(lint_attr_crate_level)] #[note] pub(crate) struct AttrCrateLevelOnly; + +#[derive(LintDiagnostic)] +#[diag(lint_incorrect_do_not_recommend_args)] +pub(crate) struct DoNotRecommendDoesNotExpectArgs; diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index c8713b23633f..4d0c44f16760 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -821,6 +821,7 @@ pub enum AttributeLintKind { }, DocTestLiteral, AttrCrateLevelOnly, + DoNotRecommendDoesNotExpectArgs, } pub type RegisteredTools = FxIndexSet; diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index a3eec72214c0..e9fa3f14358e 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -3540,7 +3540,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Whether this is a trait implementation that has `#[diagnostic::do_not_recommend]` pub fn do_not_recommend_impl(self, def_id: DefId) -> bool { - self.get_diagnostic_attr(def_id, sym::do_not_recommend).is_some() + find_attr!(self.get_all_attrs(def_id), AttributeKind::DoNotRecommend { .. }) } pub fn is_trivial_const

(self, def_id: P) -> bool diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index e2a94b607de1..8eee114ead02 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -51,7 +51,7 @@ use rustc_query_system::ich::StableHashingContext; use rustc_serialize::{Decodable, Encodable}; pub use rustc_session::lint::RegisteredTools; use rustc_span::hygiene::MacroKind; -use rustc_span::{DUMMY_SP, ExpnId, ExpnKind, Ident, Span, Symbol, sym}; +use rustc_span::{DUMMY_SP, ExpnId, ExpnKind, Ident, Span, Symbol}; pub use rustc_type_ir::data_structures::{DelayedMap, DelayedSet}; pub use rustc_type_ir::fast_reject::DeepRejectCtxt; #[allow( @@ -1819,37 +1819,6 @@ impl<'tcx> TyCtxt<'tcx> { } } - /// Get an attribute from the diagnostic attribute namespace - /// - /// This function requests an attribute with the following structure: - /// - /// `#[diagnostic::$attr]` - /// - /// This function performs feature checking, so if an attribute is returned - /// it can be used by the consumer - pub fn get_diagnostic_attr( - self, - did: impl Into, - attr: Symbol, - ) -> Option<&'tcx hir::Attribute> { - let did: DefId = did.into(); - if did.as_local().is_some() { - // it's a crate local item, we need to check feature flags - if rustc_feature::is_stable_diagnostic_attribute(attr, self.features()) { - self.get_attrs_by_path(did, &[sym::diagnostic, sym::do_not_recommend]).next() - } else { - None - } - } else { - // we filter out unstable diagnostic attributes before - // encoding attributes - debug_assert!(rustc_feature::encode_cross_crate(attr)); - self.attrs_for_def(did) - .iter() - .find(|a| matches!(a.path().as_ref(), [sym::diagnostic, a] if *a == attr)) - } - } - pub fn get_attrs_by_path( self, did: DefId, diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 11e4b8b20222..51c439b4243c 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -246,9 +246,6 @@ passes_implied_feature_not_exist = passes_incorrect_crate_type = lang items are not allowed in stable dylibs -passes_incorrect_do_not_recommend_args = - `#[diagnostic::do_not_recommend]` does not expect any arguments - passes_incorrect_do_not_recommend_location = `#[diagnostic::do_not_recommend]` can only be placed on trait implementations diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 8f80822a81ab..3402b9744b3c 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -43,8 +43,8 @@ use rustc_middle::{bug, span_bug}; use rustc_session::config::CrateType; use rustc_session::lint; use rustc_session::lint::builtin::{ - CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, MALFORMED_DIAGNOSTIC_ATTRIBUTES, - MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES, + CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, MISPLACED_DIAGNOSTIC_ATTRIBUTES, + UNUSED_ATTRIBUTES, }; use rustc_session::parse::feature_err; use rustc_span::edition::Edition; @@ -223,6 +223,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::RustcMustImplementOneOf { attr_span, fn_names }) => { self.check_rustc_must_implement_one_of(*attr_span, fn_names, hir_id,target) }, + Attribute::Parsed(AttributeKind::DoNotRecommend{attr_span}) => {self.check_do_not_recommend(*attr_span, hir_id, target, item)}, Attribute::Parsed( AttributeKind::EiiDeclaration { .. } | AttributeKind::EiiForeignItem @@ -313,9 +314,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); match attr.path().as_slice() { - [sym::diagnostic, sym::do_not_recommend, ..] => { - self.check_do_not_recommend(attr.span(), hir_id, target, attr, item) - } [sym::diagnostic, sym::on_unimplemented, ..] => { self.check_diagnostic_on_unimplemented(attr.span(), hir_id, target) } @@ -568,14 +566,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks if `#[diagnostic::do_not_recommend]` is applied on a trait impl and that it has no - /// arguments. + /// Checks if `#[diagnostic::do_not_recommend]` is applied on a trait impl fn check_do_not_recommend( &self, attr_span: Span, hir_id: HirId, target: Target, - attr: &Attribute, item: Option>, ) { if !matches!(target, Target::Impl { .. }) @@ -592,14 +588,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { errors::IncorrectDoNotRecommendLocation, ); } - if !attr.is_word() { - self.tcx.emit_node_span_lint( - MALFORMED_DIAGNOSTIC_ATTRIBUTES, - hir_id, - attr_span, - errors::DoNotRecommendDoesNotExpectArgs, - ); - } } /// Checks if `#[diagnostic::on_unimplemented]` is applied to a trait definition diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 1f3f0d7f8884..bf9b615546d8 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -20,10 +20,6 @@ use crate::lang_items::Duplicate; #[diag(passes_incorrect_do_not_recommend_location)] pub(crate) struct IncorrectDoNotRecommendLocation; -#[derive(LintDiagnostic)] -#[diag(passes_incorrect_do_not_recommend_args)] -pub(crate) struct DoNotRecommendDoesNotExpectArgs; - #[derive(Diagnostic)] #[diag(passes_autodiff_attr)] pub(crate) struct AutoDiffAttr { diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index eef8b870a5b8..77834320dbc6 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -434,7 +434,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { } = candidate.kind() && tcx.do_not_recommend_impl(impl_def_id) { - trace!("#[do_not_recommend] -> exit"); + trace!("#[diagnostic::do_not_recommend] -> exit"); return ControlFlow::Break(self.obligation.clone()); } diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index fc644668735e..04f51f54b2cd 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -729,14 +729,6 @@ help: use `#[rustc_align(...)]` instead LL | #[repr] | ^^^^^^^ -warning: `#[diagnostic::do_not_recommend]` does not expect any arguments - --> $DIR/malformed-attrs.rs:155:1 - | -LL | #[diagnostic::do_not_recommend()] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default - warning: missing options for `on_unimplemented` attribute --> $DIR/malformed-attrs.rs:144:1 | @@ -744,6 +736,7 @@ LL | #[diagnostic::on_unimplemented] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: at least one of the `message`, `note` and `label` options are expected + = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default warning: malformed `on_unimplemented` attribute --> $DIR/malformed-attrs.rs:146:1 @@ -823,6 +816,12 @@ LL | #[no_implicit_prelude = 23] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = help: `#[no_implicit_prelude]` can be applied to crates and modules +warning: `#[diagnostic::do_not_recommend]` does not expect any arguments + --> $DIR/malformed-attrs.rs:155:1 + | +LL | #[diagnostic::do_not_recommend()] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + warning: `#[automatically_derived]` attribute cannot be used on modules --> $DIR/malformed-attrs.rs:196:1 | diff --git a/tests/ui/unpretty/diagnostic-attr.stdout b/tests/ui/unpretty/diagnostic-attr.stdout index 4822cf4700b9..f74637fa7efe 100644 --- a/tests/ui/unpretty/diagnostic-attr.stdout +++ b/tests/ui/unpretty/diagnostic-attr.stdout @@ -11,5 +11,5 @@ use ::std::prelude::rust_2015::*; "My Label", note = "Note 1", note = "Note 2")] trait ImportantTrait { } -#[diagnostic::do_not_recommend] +#[attr = DoNotRecommend] impl ImportantTrait for T where T: Clone { } From ed6e63092c4f1303b127e10f5d5e300e59e9dbfa Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Tue, 13 Jan 2026 16:29:12 +0100 Subject: [PATCH 0677/1061] Keep allowing invalid metaitem syntax in diagnostic attributes --- compiler/rustc_attr_parsing/src/parser.rs | 5 +++-- .../does_not_acccept_args.current.stderr | 14 ++++++++++---- .../does_not_acccept_args.next.stderr | 14 ++++++++++---- .../do_not_recommend/does_not_acccept_args.rs | 5 +++++ 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 68265649d182..72b0fc63cc15 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -113,8 +113,9 @@ impl ArgParser { Some(match value { AttrArgs::Empty => Self::NoArgs, AttrArgs::Delimited(args) => { - // The arguments of rustc_dummy are not validated if the arguments are delimited - if parts == &[sym::rustc_dummy] { + // The arguments of rustc_dummy and diagnostic attributes are not validated + // if the arguments are delimited + if parts == &[sym::rustc_dummy] || parts[0] == sym::diagnostic { return Some(ArgParser::List(MetaItemListParser { sub_parsers: ThinVec::new(), span: args.dspan.entire(), diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.current.stderr index 2af24130a1e5..43205bd395fc 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.current.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.current.stderr @@ -1,5 +1,5 @@ warning: `#[diagnostic::do_not_recommend]` does not expect any arguments - --> $DIR/does_not_acccept_args.rs:11:1 + --> $DIR/does_not_acccept_args.rs:12:1 | LL | #[diagnostic::do_not_recommend(not_accepted)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,16 +7,22 @@ LL | #[diagnostic::do_not_recommend(not_accepted)] = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default warning: `#[diagnostic::do_not_recommend]` does not expect any arguments - --> $DIR/does_not_acccept_args.rs:15:1 + --> $DIR/does_not_acccept_args.rs:16:1 | LL | #[diagnostic::do_not_recommend(not_accepted = "foo")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[diagnostic::do_not_recommend]` does not expect any arguments - --> $DIR/does_not_acccept_args.rs:19:1 + --> $DIR/does_not_acccept_args.rs:20:1 | LL | #[diagnostic::do_not_recommend(not_accepted(42))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: 3 warnings emitted +warning: `#[diagnostic::do_not_recommend]` does not expect any arguments + --> $DIR/does_not_acccept_args.rs:24:1 + | +LL | #[diagnostic::do_not_recommend(x = y + z)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 4 warnings emitted diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.next.stderr index 2af24130a1e5..43205bd395fc 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.next.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.next.stderr @@ -1,5 +1,5 @@ warning: `#[diagnostic::do_not_recommend]` does not expect any arguments - --> $DIR/does_not_acccept_args.rs:11:1 + --> $DIR/does_not_acccept_args.rs:12:1 | LL | #[diagnostic::do_not_recommend(not_accepted)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,16 +7,22 @@ LL | #[diagnostic::do_not_recommend(not_accepted)] = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default warning: `#[diagnostic::do_not_recommend]` does not expect any arguments - --> $DIR/does_not_acccept_args.rs:15:1 + --> $DIR/does_not_acccept_args.rs:16:1 | LL | #[diagnostic::do_not_recommend(not_accepted = "foo")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[diagnostic::do_not_recommend]` does not expect any arguments - --> $DIR/does_not_acccept_args.rs:19:1 + --> $DIR/does_not_acccept_args.rs:20:1 | LL | #[diagnostic::do_not_recommend(not_accepted(42))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: 3 warnings emitted +warning: `#[diagnostic::do_not_recommend]` does not expect any arguments + --> $DIR/does_not_acccept_args.rs:24:1 + | +LL | #[diagnostic::do_not_recommend(x = y + z)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 4 warnings emitted diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.rs b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.rs index 5c21c045e10a..918bf5a0113e 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.rs +++ b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.rs @@ -7,6 +7,7 @@ trait Foo {} trait Bar {} trait Baz {} +trait Boo {} #[diagnostic::do_not_recommend(not_accepted)] //~^ WARNING `#[diagnostic::do_not_recommend]` does not expect any arguments @@ -20,4 +21,8 @@ impl Bar for T where T: Send {} //~^ WARNING `#[diagnostic::do_not_recommend]` does not expect any arguments impl Baz for T where T: Send {} +#[diagnostic::do_not_recommend(x = y + z)] +//~^ WARNING `#[diagnostic::do_not_recommend]` does not expect any arguments +impl Boo for T where T: Send {} + fn main() {} From 1fe705ca709cd81d3ce8735e992cd4333c1404fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 13 Jan 2026 16:59:03 +0000 Subject: [PATCH 0678/1061] Mention the type in the label, to avoid confusion at the cost of redundancy --- library/core/src/iter/range.rs | 2 +- .../run-make/missing-unstable-trait-bound/missing-bound.stderr | 2 +- tests/ui/range/range-1.stderr | 2 +- tests/ui/trait-bounds/unstable-trait-suggestion.stderr | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 7880e18d7d31..a6ab2e4d8b7d 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -23,7 +23,7 @@ unsafe_impl_trusted_step![AsciiChar char i8 i16 i32 i64 i128 isize u8 u16 u32 u6 #[rustc_diagnostic_item = "range_step"] #[rustc_on_unimplemented( message = "`std::ops::Range<{Self}>` is not an iterator", - label = "not an iterator", + label = "`Range<{Self}>` is not an iterator", note = "`Range` only implements `Iterator` for select types in the standard library, \ particularly integers; to see the full list of types, see the documentation for the \ unstable `Step` trait" diff --git a/tests/run-make/missing-unstable-trait-bound/missing-bound.stderr b/tests/run-make/missing-unstable-trait-bound/missing-bound.stderr index d503751a2e93..d680ae1aca1d 100644 --- a/tests/run-make/missing-unstable-trait-bound/missing-bound.stderr +++ b/tests/run-make/missing-unstable-trait-bound/missing-bound.stderr @@ -2,7 +2,7 @@ error[E0277]: `std::ops::Range` is not an iterator --> missing-bound.rs:2:14 | 2 | for _ in t {} - | ^ not an iterator + | ^ `Range` is not an iterator | = note: `Range` only implements `Iterator` for select types in the standard library, particularly integers; to see the full list of types, see the documentation for the unstable `Step` trait = note: required for `std::ops::Range` to implement `Iterator` diff --git a/tests/ui/range/range-1.stderr b/tests/ui/range/range-1.stderr index 9682122539c5..d7d0f87ac991 100644 --- a/tests/ui/range/range-1.stderr +++ b/tests/ui/range/range-1.stderr @@ -8,7 +8,7 @@ error[E0277]: `std::ops::Range` is not an iterator --> $DIR/range-1.rs:9:14 | LL | for i in false..true {} - | ^^^^^^^^^^^ not an iterator + | ^^^^^^^^^^^ `Range` is not an iterator | = help: the nightly-only, unstable trait `Step` is not implemented for `bool` = note: `Range` only implements `Iterator` for select types in the standard library, particularly integers; to see the full list of types, see the documentation for the unstable `Step` trait diff --git a/tests/ui/trait-bounds/unstable-trait-suggestion.stderr b/tests/ui/trait-bounds/unstable-trait-suggestion.stderr index 5edaed0f4dfe..9ae209d5aa96 100644 --- a/tests/ui/trait-bounds/unstable-trait-suggestion.stderr +++ b/tests/ui/trait-bounds/unstable-trait-suggestion.stderr @@ -20,7 +20,7 @@ error[E0277]: `std::ops::Range` is not an iterator --> $DIR/unstable-trait-suggestion.rs:17:14 | LL | for _ in t {} - | ^ not an iterator + | ^ `Range` is not an iterator | = note: `Range` only implements `Iterator` for select types in the standard library, particularly integers; to see the full list of types, see the documentation for the unstable `Step` trait = note: required for `std::ops::Range` to implement `Iterator` From 596ea17eae592b68a16a7661bf26c10a5155da89 Mon Sep 17 00:00:00 2001 From: rami3l Date: Tue, 13 Jan 2026 21:05:44 +0100 Subject: [PATCH 0679/1061] fix(build-manifest): enable docs target fallback for `rustc-docs` --- src/tools/build-manifest/src/main.rs | 12 ++++++------ src/tools/build-manifest/src/versions.rs | 5 +---- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 4cec1b1f164b..58f7487a0fda 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -14,11 +14,11 @@ use crate::versions::{PkgType, Versions}; include!(concat!(env!("OUT_DIR"), "/targets.rs")); -/// This allows the manifest to contain rust-docs for hosts that don't build -/// docs. +/// This allows the manifest to contain rust-docs and rustc-docs for hosts +/// that don't build certain docs. /// /// Tuples of `(host_partial, host_instead)`. If the host does not have the -/// rust-docs component available, then if the host name contains +/// corresponding docs component available, then if the host name contains /// `host_partial`, it will use the docs from `host_instead` instead. /// /// The order here matters, more specific entries should be first. @@ -392,9 +392,9 @@ impl Builder { let t = Target::from_compressed_tar(self, &tarball_name!(fallback_target)); // Fallbacks should typically be available on 'production' builds // but may not be available for try builds, which only build one target by - // default. Ideally we'd gate this being a hard error on whether we're in a - // production build or not, but it's not information that's readily available - // here. + // default. It is also possible that `rust-docs` and `rustc-docs` differ in + // availability per target. Thus, we take the first available fallback we can + // find. if !t.available { eprintln!( "{:?} not available for fallback", diff --git a/src/tools/build-manifest/src/versions.rs b/src/tools/build-manifest/src/versions.rs index 6ef8a0e83de3..da887a66d98e 100644 --- a/src/tools/build-manifest/src/versions.rs +++ b/src/tools/build-manifest/src/versions.rs @@ -133,10 +133,7 @@ impl PkgType { /// Whether to package these target-specific docs for another similar target. pub(crate) fn use_docs_fallback(&self) -> bool { - match self { - PkgType::JsonDocs | PkgType::HtmlDocs => true, - _ => false, - } + matches!(self, PkgType::JsonDocs | PkgType::HtmlDocs | PkgType::RustcDocs) } } From 6166b619794ba095919deaad239628ad2ddce3b3 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Mon, 12 Jan 2026 00:45:50 +0900 Subject: [PATCH 0680/1061] Add crashes mGCA tests --- tests/crashes/138226-2.rs | 13 ++++++++ tests/crashes/138226.rs | 13 ++++++++ tests/crashes/149809.rs | 13 ++++++++ tests/crashes/150960.rs | 11 +++++++ .../mgca/cast-with-type-mismatched.rs | 14 -------- .../mgca/cast-with-type-mismatched.stderr | 20 ------------ .../mgca/const-eval-with-invalid-args.rs | 26 --------------- .../mgca/const-eval-with-invalid-args.stderr | 32 ------------------- .../recursive-self-referencing-const-param.rs | 11 ------- ...ursive-self-referencing-const-param.stderr | 23 ------------- .../mgca/size-of-generic-ptr-in-array-len.rs | 2 ++ .../size-of-generic-ptr-in-array-len.stderr | 8 ++++- 12 files changed, 59 insertions(+), 127 deletions(-) create mode 100644 tests/crashes/138226-2.rs create mode 100644 tests/crashes/138226.rs create mode 100644 tests/crashes/149809.rs create mode 100644 tests/crashes/150960.rs delete mode 100644 tests/ui/const-generics/mgca/cast-with-type-mismatched.rs delete mode 100644 tests/ui/const-generics/mgca/cast-with-type-mismatched.stderr delete mode 100644 tests/ui/const-generics/mgca/const-eval-with-invalid-args.rs delete mode 100644 tests/ui/const-generics/mgca/const-eval-with-invalid-args.stderr delete mode 100644 tests/ui/const-generics/mgca/recursive-self-referencing-const-param.rs delete mode 100644 tests/ui/const-generics/mgca/recursive-self-referencing-const-param.stderr diff --git a/tests/crashes/138226-2.rs b/tests/crashes/138226-2.rs new file mode 100644 index 000000000000..a2ebbdefdf3f --- /dev/null +++ b/tests/crashes/138226-2.rs @@ -0,0 +1,13 @@ +//@ known-bug: #138226 +//@ needs-rustc-debug-assertions +#![feature(min_generic_const_args)] +#![feature(inherent_associated_types)] +struct Bar; +impl Bar { + #[type_const] + const LEN: usize = 4; + + fn bar() { + let _ = [0; Self::LEN]; + } +} diff --git a/tests/crashes/138226.rs b/tests/crashes/138226.rs new file mode 100644 index 000000000000..7d13461a56b3 --- /dev/null +++ b/tests/crashes/138226.rs @@ -0,0 +1,13 @@ +//@ known-bug: #138226 +//@ needs-rustc-debug-assertions +#![feature(min_generic_const_args)] +#![feature(inherent_associated_types)] +struct Foo(A, B); +impl Foo { + #[type_const] + const LEN: usize = 4; + + fn foo() { + let _ = [5; Self::LEN]; + } +} diff --git a/tests/crashes/149809.rs b/tests/crashes/149809.rs new file mode 100644 index 000000000000..2b948e9079c3 --- /dev/null +++ b/tests/crashes/149809.rs @@ -0,0 +1,13 @@ +//@ known-bug: #149809 +#![feature(min_generic_const_args)] +#![feature(inherent_associated_types)] +struct Qux<'a> { + x: &'a (), +} +impl<'a> Qux<'a> { + #[type_const] + const LEN: usize = 4; + fn foo(_: [u8; Qux::LEN]) {} +} + +fn main() {} diff --git a/tests/crashes/150960.rs b/tests/crashes/150960.rs new file mode 100644 index 000000000000..2d46eea67989 --- /dev/null +++ b/tests/crashes/150960.rs @@ -0,0 +1,11 @@ +//@ known-bug: #150960 +#![feature(min_generic_const_args)] +struct Baz; +impl Baz { + #[type_const] + const LEN: usize = 4; + + fn baz() { + let _ = [0; const { Self::LEN }]; + } +} diff --git a/tests/ui/const-generics/mgca/cast-with-type-mismatched.rs b/tests/ui/const-generics/mgca/cast-with-type-mismatched.rs deleted file mode 100644 index 1f499c222e7f..000000000000 --- a/tests/ui/const-generics/mgca/cast-with-type-mismatched.rs +++ /dev/null @@ -1,14 +0,0 @@ -//! regression test for -#![expect(incomplete_features)] -#![feature(generic_const_exprs)] -#![feature(min_generic_const_args)] - -fn foo(a: [(); N as usize]) {} -//~^ ERROR: complex const arguments must be placed inside of a `const` block - -const C: f32 = 1.0; - -fn main() { - foo::([]); - //~^ ERROR: the constant `C` is not of type `u32` -} diff --git a/tests/ui/const-generics/mgca/cast-with-type-mismatched.stderr b/tests/ui/const-generics/mgca/cast-with-type-mismatched.stderr deleted file mode 100644 index 7e1b21138ec8..000000000000 --- a/tests/ui/const-generics/mgca/cast-with-type-mismatched.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: complex const arguments must be placed inside of a `const` block - --> $DIR/cast-with-type-mismatched.rs:6:30 - | -LL | fn foo(a: [(); N as usize]) {} - | ^^^^^^^^^^ - -error: the constant `C` is not of type `u32` - --> $DIR/cast-with-type-mismatched.rs:12:11 - | -LL | foo::([]); - | ^ expected `u32`, found `f32` - | -note: required by a const generic parameter in `foo` - --> $DIR/cast-with-type-mismatched.rs:6:8 - | -LL | fn foo(a: [(); N as usize]) {} - | ^^^^^^^^^^^^ required by this const generic parameter in `foo` - -error: aborting due to 2 previous errors - diff --git a/tests/ui/const-generics/mgca/const-eval-with-invalid-args.rs b/tests/ui/const-generics/mgca/const-eval-with-invalid-args.rs deleted file mode 100644 index 3bf951e0c212..000000000000 --- a/tests/ui/const-generics/mgca/const-eval-with-invalid-args.rs +++ /dev/null @@ -1,26 +0,0 @@ -//! regression test for -#![expect(incomplete_features)] -#![feature(generic_const_exprs)] -#![feature(min_generic_const_args)] - -// The previous ICE was an "invalid field access on immediate". -// If we remove `val: i32` from the field, another ICE occurs. -// "assertion `left == right` failed: invalid field type in -// Immediate::offset: scalar value has wrong size" -struct A { - arr: usize, - val: i32, -} - -struct B { - //~^ ERROR: `A` is forbidden as the type of a const generic parameter - arr: [u8; N.arr], - //~^ ERROR: complex const arguments must be placed inside of a `const` block -} - -const C: u32 = 1; -fn main() { - let b = B:: {arr: [1]}; - //~^ ERROR: the constant `C` is not of type `A` - let _ = b.arr.len(); -} diff --git a/tests/ui/const-generics/mgca/const-eval-with-invalid-args.stderr b/tests/ui/const-generics/mgca/const-eval-with-invalid-args.stderr deleted file mode 100644 index a226718ccf1b..000000000000 --- a/tests/ui/const-generics/mgca/const-eval-with-invalid-args.stderr +++ /dev/null @@ -1,32 +0,0 @@ -error: complex const arguments must be placed inside of a `const` block - --> $DIR/const-eval-with-invalid-args.rs:17:15 - | -LL | arr: [u8; N.arr], - | ^^^^^ - -error: `A` is forbidden as the type of a const generic parameter - --> $DIR/const-eval-with-invalid-args.rs:15:19 - | -LL | struct B { - | ^ - | - = note: the only supported types are integers, `bool`, and `char` -help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types - | -LL + #![feature(adt_const_params)] - | - -error: the constant `C` is not of type `A` - --> $DIR/const-eval-with-invalid-args.rs:23:17 - | -LL | let b = B:: {arr: [1]}; - | ^ expected `A`, found `u32` - | -note: required by a const generic parameter in `B` - --> $DIR/const-eval-with-invalid-args.rs:15:10 - | -LL | struct B { - | ^^^^^^^^^^ required by this const generic parameter in `B` - -error: aborting due to 3 previous errors - diff --git a/tests/ui/const-generics/mgca/recursive-self-referencing-const-param.rs b/tests/ui/const-generics/mgca/recursive-self-referencing-const-param.rs deleted file mode 100644 index 37dcc58ff468..000000000000 --- a/tests/ui/const-generics/mgca/recursive-self-referencing-const-param.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! regression test for -#![expect(incomplete_features)] -#![feature(generic_const_exprs)] -#![feature(min_generic_const_args)] - -fn identity }>() }>>(); -//~^ ERROR: free function without a body -//~| ERROR: expected type, found function `identity` -//~| ERROR: complex const arguments must be placed inside of a `const` block - -fn main() {} diff --git a/tests/ui/const-generics/mgca/recursive-self-referencing-const-param.stderr b/tests/ui/const-generics/mgca/recursive-self-referencing-const-param.stderr deleted file mode 100644 index d1899c476ec6..000000000000 --- a/tests/ui/const-generics/mgca/recursive-self-referencing-const-param.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error: free function without a body - --> $DIR/recursive-self-referencing-const-param.rs:6:1 - | -LL | fn identity }>() }>>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- - | | - | help: provide a definition for the function: `{ }` - -error[E0573]: expected type, found function `identity` - --> $DIR/recursive-self-referencing-const-param.rs:6:22 - | -LL | fn identity }>() }>>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a type - -error: complex const arguments must be placed inside of a `const` block - --> $DIR/recursive-self-referencing-const-param.rs:6:57 - | -LL | fn identity }>() }>>(); - | ^^ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0573`. diff --git a/tests/ui/const-generics/mgca/size-of-generic-ptr-in-array-len.rs b/tests/ui/const-generics/mgca/size-of-generic-ptr-in-array-len.rs index 2a7c23929845..22963b6438c0 100644 --- a/tests/ui/const-generics/mgca/size-of-generic-ptr-in-array-len.rs +++ b/tests/ui/const-generics/mgca/size-of-generic-ptr-in-array-len.rs @@ -5,6 +5,8 @@ fn foo() { [0; size_of::<*mut T>()]; //~^ ERROR: tuple constructor with invalid base path + [0; const { size_of::<*mut T>() }]; + //~^ ERROR: generic parameters may not be used in const operations } fn main() {} diff --git a/tests/ui/const-generics/mgca/size-of-generic-ptr-in-array-len.stderr b/tests/ui/const-generics/mgca/size-of-generic-ptr-in-array-len.stderr index dcdc56a1cf47..913d8195fe21 100644 --- a/tests/ui/const-generics/mgca/size-of-generic-ptr-in-array-len.stderr +++ b/tests/ui/const-generics/mgca/size-of-generic-ptr-in-array-len.stderr @@ -4,5 +4,11 @@ error: tuple constructor with invalid base path LL | [0; size_of::<*mut T>()]; | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error: generic parameters may not be used in const operations + --> $DIR/size-of-generic-ptr-in-array-len.rs:8:32 + | +LL | [0; const { size_of::<*mut T>() }]; + | ^ + +error: aborting due to 2 previous errors From 6c4cdfaf42bef13a33935835e09bedd353791af6 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Tue, 13 Jan 2026 23:11:42 +0100 Subject: [PATCH 0681/1061] =?UTF-8?q?Replace=20complex=20`matches!(?= =?UTF-8?q?=E2=80=A6,=20=E2=80=A6=20if=20=E2=80=A6)`=20by=20`if=20let`=20c?= =?UTF-8?q?hain?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- clippy_lints/src/slow_vector_initialization.rs | 4 +++- clippy_lints/src/unnested_or_patterns.rs | 7 ++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index b25fa0905feb..8524497c387c 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -150,7 +150,9 @@ impl SlowVectorInit { && func.ty_rel_def(cx).is_diag_item(cx, sym::vec_with_capacity) { Some(InitializedSize::Initialized(len_expr)) - } else if matches!(expr.kind, ExprKind::Call(func, []) if func.ty_rel_def(cx).is_diag_item(cx, sym::vec_new)) { + } else if let ExprKind::Call(func, []) = expr.kind + && func.ty_rel_def(cx).is_diag_item(cx, sym::vec_new) + { Some(InitializedSize::Uninitialized) } else { None diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index 975dd332ad06..12f8bd50e144 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -152,7 +152,12 @@ fn insert_necessary_parens(pat: &mut Pat) { walk_pat(self, pat); let target = match &mut pat.kind { // `i @ a | b`, `box a | b`, and `& mut? a | b`. - Ident(.., Some(p)) | Box(p) | Ref(p, _, _) if matches!(&p.kind, Or(ps) if ps.len() > 1) => p, + Ident(.., Some(p)) | Box(p) | Ref(p, _, _) + if let Or(ps) = &p.kind + && ps.len() > 1 => + { + p + }, // `&(mut x)` Ref(p, Pinnedness::Not, Mutability::Not) if matches!(p.kind, Ident(BindingMode::MUT, ..)) => p, _ => return, From 0ee43b16b6aa77096246e42c294de72affa60f40 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Tue, 13 Jan 2026 23:57:34 +0100 Subject: [PATCH 0682/1061] Do not validate `diagnostic::do_not_recommend` args --- compiler/rustc_attr_parsing/src/parser.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 72b0fc63cc15..63c82ccbc7df 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -113,9 +113,12 @@ impl ArgParser { Some(match value { AttrArgs::Empty => Self::NoArgs, AttrArgs::Delimited(args) => { - // The arguments of rustc_dummy and diagnostic attributes are not validated - // if the arguments are delimited - if parts == &[sym::rustc_dummy] || parts[0] == sym::diagnostic { + // The arguments of rustc_dummy and diagnostic::do_not_recommend are not validated + // if the arguments are delimited. + // See https://doc.rust-lang.org/reference/attributes/diagnostics.html#r-attributes.diagnostic.namespace.unknown-invalid-syntax + if parts == &[sym::rustc_dummy] + || parts == &[sym::diagnostic, sym::do_not_recommend] + { return Some(ArgParser::List(MetaItemListParser { sub_parsers: ThinVec::new(), span: args.dspan.entire(), From 03cc50fc57424001285b72c02af2e19f36aabfd5 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 13 Jan 2026 15:23:59 -0800 Subject: [PATCH 0683/1061] update to indexmap v2.13.0 --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 45d01c486faf..4297c1b32e35 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1953,9 +1953,9 @@ checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5" [[package]] name = "indexmap" -version = "2.12.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", "hashbrown 0.16.1", From 15d8e9ea66442a7ee8c642245aaa77f6a78f2cf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 13 Jan 2026 19:33:40 +0000 Subject: [PATCH 0684/1061] Recognize potential `impl` to `impl` mistake When encountering code like `impl Bar for [u8; N]`, suggest `impl Bar for [u8; N]` as a possibility. ``` error[E0423]: expected value, found type parameter `T` --> $DIR/issue-69654.rs:5:25 | LL | impl Bar for [u8; T] {} | - ^ not a value | | | found this type parameter | help: you might have meant to write a const parameter here | LL | impl Bar for [u8; T] {} | +++++ ++++++++++++ ``` --- compiler/rustc_resolve/src/errors.rs | 13 +++++++ .../rustc_resolve/src/late/diagnostics.rs | 35 ++++++++++++++++++- .../generic_const_exprs/issue-69654.stderr | 5 +++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index af58d88ec35f..8880c2ba2666 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -867,6 +867,19 @@ pub(crate) struct UnexpectedResChangeTyToConstParamSugg { pub applicability: Applicability, } +#[derive(Subdiagnostic)] +#[multipart_suggestion( + resolve_unexpected_res_change_ty_to_const_param_sugg, + applicability = "has-placeholders", + style = "verbose" +)] +pub(crate) struct UnexpectedResChangeTyParamToConstParamSugg { + #[suggestion_part(code = "const ")] + pub before: Span, + #[suggestion_part(code = ": /* Type */")] + pub after: Span, +} + #[derive(Subdiagnostic)] #[suggestion( resolve_unexpected_res_use_at_op_in_slice_pat_with_range_sugg, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index a2805497e796..c5d15dcc91af 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -414,6 +414,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { /// Handles error reporting for `smart_resolve_path_fragment` function. /// Creates base error and amends it with one short label and possibly some longer helps/notes. + #[tracing::instrument(skip(self), level = "debug")] pub(crate) fn smart_resolve_report_errors( &mut self, path: &[Segment], @@ -451,7 +452,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { err.span_suggestion_verbose(sugg.0, sugg.1, &sugg.2, Applicability::MaybeIncorrect); } - self.suggest_changing_type_to_const_param(&mut err, res, source, span); + self.suggest_changing_type_to_const_param(&mut err, res, source, path, following_seg, span); self.explain_functions_in_pattern(&mut err, res, source); if self.suggest_pattern_match_with_let(&mut err, source, span) { @@ -1505,8 +1506,40 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { err: &mut Diag<'_>, res: Option, source: PathSource<'_, '_, '_>, + path: &[Segment], + following_seg: Option<&Segment>, span: Span, ) { + if let PathSource::Expr(None) = source + && let Some(Res::Def(DefKind::TyParam, _)) = res + && following_seg.is_none() + && let [segment] = path + { + // We have something like + // impl From<[T; N]> for VecWrapper { + // fn from(slice: [T; N]) -> Self { + // VecWrapper(slice.to_vec()) + // } + // } + // where `N` is a type param but should likely have been a const param. + let Some(item) = self.diag_metadata.current_item else { return }; + let Some(generics) = item.kind.generics() else { return }; + let Some(span) = generics.params.iter().find_map(|param| { + // Only consider type params with no bounds. + if param.bounds.is_empty() && param.ident.name == segment.ident.name { + Some(param.ident.span) + } else { + None + } + }) else { + return; + }; + err.subdiagnostic(errors::UnexpectedResChangeTyParamToConstParamSugg { + before: span.shrink_to_lo(), + after: span.shrink_to_hi(), + }); + return; + } let PathSource::Trait(_) = source else { return }; // We don't include `DefKind::Str` and `DefKind::AssocTy` as they can't be reached here anyway. diff --git a/tests/ui/const-generics/generic_const_exprs/issue-69654.stderr b/tests/ui/const-generics/generic_const_exprs/issue-69654.stderr index eb4ff8305dac..7fa0d8c7dbaa 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-69654.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-69654.stderr @@ -5,6 +5,11 @@ LL | impl Bar for [u8; T] {} | - ^ not a value | | | found this type parameter + | +help: you might have meant to write a const parameter here + | +LL | impl Bar for [u8; T] {} + | +++++ ++++++++++++ error[E0599]: the function or associated item `foo` exists for struct `Foo<_>`, but its trait bounds were not satisfied --> $DIR/issue-69654.rs:17:10 From c8c7b5b449d243a4ee5474e49e9bb112d56264aa Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 14 Jan 2026 00:58:35 +0100 Subject: [PATCH 0685/1061] Generate macro expansion for rust compiler crates docs --- src/bootstrap/src/core/build_steps/doc.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index b86582807f72..fa36a6471cae 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -932,6 +932,7 @@ impl Step for Rustc { // see https://github.com/rust-lang/rust/pull/122066#issuecomment-1983049222 // If there is any bug, please comment out the next line. cargo.rustdocflag("--generate-link-to-definition"); + cargo.rustdocflag("--generate-macro-expansion"); compile::rustc_cargo(builder, &mut cargo, target, &build_compiler, &self.crates); cargo.arg("-Zskip-rustdoc-fingerprint"); From b202eee0816938126195e95488ce6df8e9602214 Mon Sep 17 00:00:00 2001 From: Taeyoon Kim Date: Wed, 14 Jan 2026 10:06:39 +0900 Subject: [PATCH 0686/1061] Add Korean translation to Rust By Example Add korean translation. Thanks in advanced --- src/bootstrap/src/core/build_steps/doc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index b86582807f72..9bb16fe33fd5 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -75,7 +75,7 @@ book!( EditionGuide, "src/doc/edition-guide", "edition-guide", &[]; EmbeddedBook, "src/doc/embedded-book", "embedded-book", &[]; Nomicon, "src/doc/nomicon", "nomicon", &[]; - RustByExample, "src/doc/rust-by-example", "rust-by-example", &["es", "ja", "zh"]; + RustByExample, "src/doc/rust-by-example", "rust-by-example", &["es", "ja", "zh", "ko"]; RustdocBook, "src/doc/rustdoc", "rustdoc", &[]; StyleGuide, "src/doc/style-guide", "style-guide", &[]; ); From 795745ccf1f7af296334204931ae1d0e467d62c2 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Tue, 13 Jan 2026 19:48:38 -0500 Subject: [PATCH 0687/1061] remote-test-server: Fix compilation on UEFI targets Tested with: ./x build src/tools/remote-test-server --target x86_64-unknown-uefi --- src/tools/remote-test-server/src/main.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tools/remote-test-server/src/main.rs b/src/tools/remote-test-server/src/main.rs index bfe8f54937f6..a15f30d4659e 100644 --- a/src/tools/remote-test-server/src/main.rs +++ b/src/tools/remote-test-server/src/main.rs @@ -10,13 +10,13 @@ //! themselves having support libraries. All data over the TCP sockets is in a //! basically custom format suiting our needs. -#[cfg(all(not(windows), not(target_os = "motor")))] +#[cfg(not(any(windows, target_os = "motor", target_os = "uefi")))] use std::fs::Permissions; use std::fs::{self, File}; use std::io::prelude::*; use std::io::{self, BufReader}; use std::net::{SocketAddr, TcpListener, TcpStream}; -#[cfg(all(not(windows), not(target_os = "motor")))] +#[cfg(not(any(windows, target_os = "motor", target_os = "uefi")))] use std::os::unix::prelude::*; use std::path::{Path, PathBuf}; use std::process::{Command, ExitStatus, Stdio}; @@ -325,7 +325,7 @@ fn handle_run(socket: TcpStream, work: &Path, tmp: &Path, lock: &Mutex<()>, conf ])); } -#[cfg(all(not(windows), not(target_os = "motor")))] +#[cfg(not(any(windows, target_os = "motor", target_os = "uefi")))] fn get_status_code(status: &ExitStatus) -> (u8, i32) { match status.code() { Some(n) => (0, n), @@ -333,7 +333,7 @@ fn get_status_code(status: &ExitStatus) -> (u8, i32) { } } -#[cfg(any(windows, target_os = "motor"))] +#[cfg(any(windows, target_os = "motor", target_os = "uefi"))] fn get_status_code(status: &ExitStatus) -> (u8, i32) { (0, status.code().unwrap()) } @@ -359,11 +359,11 @@ fn recv(dir: &Path, io: &mut B) -> PathBuf { dst } -#[cfg(all(not(windows), not(target_os = "motor")))] +#[cfg(not(any(windows, target_os = "motor", target_os = "uefi")))] fn set_permissions(path: &Path) { t!(fs::set_permissions(&path, Permissions::from_mode(0o755))); } -#[cfg(any(windows, target_os = "motor"))] +#[cfg(any(windows, target_os = "motor", target_os = "uefi"))] fn set_permissions(_path: &Path) {} fn my_copy(src: &mut dyn Read, which: u8, dst: &Mutex) { From 3aa31788b57da7a5eeee8184dccb00178b40121b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 14 Jan 2026 10:30:08 +1100 Subject: [PATCH 0688/1061] Remove `Deref`/`DerefMut` impl for `Providers`. It's described as a "backwards compatibility hack to keep the diff small". Removing it requires only a modest amount of churn, and the resulting code is clearer without the invisible derefs. --- compiler/rustc_codegen_gcc/src/lib.rs | 3 +- compiler/rustc_codegen_llvm/src/lib.rs | 2 +- .../src/back/symbol_export.rs | 18 ++++---- compiler/rustc_codegen_ssa/src/lib.rs | 6 +-- compiler/rustc_const_eval/src/lib.rs | 16 +++---- compiler/rustc_interface/src/passes.rs | 46 +++++++++---------- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- compiler/rustc_middle/src/util/mod.rs | 17 ------- compiler/rustc_mir_build/src/lib.rs | 12 ++--- compiler/rustc_mir_transform/src/lib.rs | 6 +-- compiler/rustc_monomorphize/src/collector.rs | 2 +- compiler/rustc_monomorphize/src/lib.rs | 2 +- .../rustc_monomorphize/src/partitioning.rs | 8 ++-- compiler/rustc_passes/src/lib.rs | 2 +- src/librustdoc/core.rs | 9 ++-- src/tools/miri/src/bin/miri.rs | 2 +- tests/ui-fulldeps/obtain-borrowck.rs | 6 +-- 17 files changed, 72 insertions(+), 87 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 96d3a0024f41..cf1be1806235 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -286,7 +286,8 @@ impl CodegenBackend for GccCodegenBackend { } fn provide(&self, providers: &mut Providers) { - providers.global_backend_features = |tcx, ()| gcc_util::global_gcc_features(tcx.sess) + providers.queries.global_backend_features = + |tcx, ()| gcc_util::global_gcc_features(tcx.sess) } fn codegen_crate(&self, tcx: TyCtxt<'_>) -> Box { diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 438a74e0a091..e0007f69828d 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -264,7 +264,7 @@ impl CodegenBackend for LlvmCodegenBackend { } fn provide(&self, providers: &mut Providers) { - providers.global_backend_features = + providers.queries.global_backend_features = |tcx, ()| llvm_util::global_llvm_features(tcx.sess, false) } diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 27989f6f5ea2..59d0f5ee9d54 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -474,15 +474,15 @@ fn is_unreachable_local_definition_provider(tcx: TyCtxt<'_>, def_id: LocalDefId) } pub(crate) fn provide(providers: &mut Providers) { - providers.reachable_non_generics = reachable_non_generics_provider; - providers.is_reachable_non_generic = is_reachable_non_generic_provider_local; - providers.exported_non_generic_symbols = exported_non_generic_symbols_provider_local; - providers.exported_generic_symbols = exported_generic_symbols_provider_local; - providers.upstream_monomorphizations = upstream_monomorphizations_provider; - providers.is_unreachable_local_definition = is_unreachable_local_definition_provider; - providers.upstream_drop_glue_for = upstream_drop_glue_for_provider; - providers.upstream_async_drop_glue_for = upstream_async_drop_glue_for_provider; - providers.wasm_import_module_map = wasm_import_module_map; + providers.queries.reachable_non_generics = reachable_non_generics_provider; + providers.queries.is_reachable_non_generic = is_reachable_non_generic_provider_local; + providers.queries.exported_non_generic_symbols = exported_non_generic_symbols_provider_local; + providers.queries.exported_generic_symbols = exported_generic_symbols_provider_local; + providers.queries.upstream_monomorphizations = upstream_monomorphizations_provider; + providers.queries.is_unreachable_local_definition = is_unreachable_local_definition_provider; + providers.queries.upstream_drop_glue_for = upstream_drop_glue_for_provider; + providers.queries.upstream_async_drop_glue_for = upstream_async_drop_glue_for_provider; + providers.queries.wasm_import_module_map = wasm_import_module_map; providers.extern_queries.is_reachable_non_generic = is_reachable_non_generic_provider_extern; providers.extern_queries.upstream_monomorphizations_for = upstream_monomorphizations_for_provider; diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index d7461c76ff03..8c39d04ef21d 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -266,9 +266,9 @@ pub enum CodegenErrors { pub fn provide(providers: &mut Providers) { crate::back::symbol_export::provide(providers); - crate::base::provide(providers); - crate::target_features::provide(providers); - crate::codegen_attrs::provide(providers); + crate::base::provide(&mut providers.queries); + crate::target_features::provide(&mut providers.queries); + crate::codegen_attrs::provide(&mut providers.queries); providers.queries.global_backend_features = |_tcx: TyCtxt<'_>, ()| vec![]; } diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 2fce4b8c0566..9b1d4652212b 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -30,20 +30,20 @@ pub use self::errors::ReportErrorExt; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } pub fn provide(providers: &mut Providers) { - const_eval::provide(providers); - providers.tag_for_variant = const_eval::tag_for_variant_provider; - providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider; - providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider; - providers.eval_static_initializer = const_eval::eval_static_initializer_provider; + const_eval::provide(&mut providers.queries); + providers.queries.tag_for_variant = const_eval::tag_for_variant_provider; + providers.queries.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider; + providers.queries.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider; + providers.queries.eval_static_initializer = const_eval::eval_static_initializer_provider; providers.hooks.const_caller_location = util::caller_location::const_caller_location_provider; - providers.eval_to_valtree = |tcx, ty::PseudoCanonicalInput { typing_env, value }| { + providers.queries.eval_to_valtree = |tcx, ty::PseudoCanonicalInput { typing_env, value }| { const_eval::eval_to_valtree(tcx, typing_env, value) }; providers.hooks.try_destructure_mir_constant_for_user_output = const_eval::try_destructure_mir_constant_for_user_output; - providers.valtree_to_const_val = + providers.queries.valtree_to_const_val = |tcx, cv| const_eval::valtree_to_const_value(tcx, ty::TypingEnv::fully_monomorphized(), cv); - providers.check_validity_requirement = |tcx, (init_kind, param_env_and_ty)| { + providers.queries.check_validity_requirement = |tcx, (init_kind, param_env_and_ty)| { util::check_validity_requirement(tcx, init_kind, param_env_and_ty) }; providers.hooks.validate_scalar_in_layout = diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index a0383b187de5..35ab202d4c27 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -880,36 +880,36 @@ pub fn write_interface<'tcx>(tcx: TyCtxt<'tcx>) { pub static DEFAULT_QUERY_PROVIDERS: LazyLock = LazyLock::new(|| { let providers = &mut Providers::default(); - providers.analysis = analysis; - providers.hir_crate = rustc_ast_lowering::lower_to_hir; - providers.resolver_for_lowering_raw = resolver_for_lowering_raw; - providers.stripped_cfg_items = |tcx, _| &tcx.resolutions(()).stripped_cfg_items[..]; - providers.resolutions = |tcx, ()| tcx.resolver_for_lowering_raw(()).1; - providers.early_lint_checks = early_lint_checks; - providers.env_var_os = env_var_os; - limits::provide(providers); - proc_macro_decls::provide(providers); + providers.queries.analysis = analysis; + providers.queries.hir_crate = rustc_ast_lowering::lower_to_hir; + providers.queries.resolver_for_lowering_raw = resolver_for_lowering_raw; + providers.queries.stripped_cfg_items = |tcx, _| &tcx.resolutions(()).stripped_cfg_items[..]; + providers.queries.resolutions = |tcx, ()| tcx.resolver_for_lowering_raw(()).1; + providers.queries.early_lint_checks = early_lint_checks; + providers.queries.env_var_os = env_var_os; + limits::provide(&mut providers.queries); + proc_macro_decls::provide(&mut providers.queries); rustc_const_eval::provide(providers); - rustc_middle::hir::provide(providers); - rustc_borrowck::provide(providers); + rustc_middle::hir::provide(&mut providers.queries); + rustc_borrowck::provide(&mut providers.queries); rustc_incremental::provide(providers); rustc_mir_build::provide(providers); rustc_mir_transform::provide(providers); rustc_monomorphize::provide(providers); - rustc_privacy::provide(providers); + rustc_privacy::provide(&mut providers.queries); rustc_query_impl::provide(providers); - rustc_resolve::provide(providers); - rustc_hir_analysis::provide(providers); - rustc_hir_typeck::provide(providers); - ty::provide(providers); - traits::provide(providers); - solve::provide(providers); - rustc_passes::provide(providers); - rustc_traits::provide(providers); - rustc_ty_utils::provide(providers); + rustc_resolve::provide(&mut providers.queries); + rustc_hir_analysis::provide(&mut providers.queries); + rustc_hir_typeck::provide(&mut providers.queries); + ty::provide(&mut providers.queries); + traits::provide(&mut providers.queries); + solve::provide(&mut providers.queries); + rustc_passes::provide(&mut providers.queries); + rustc_traits::provide(&mut providers.queries); + rustc_ty_utils::provide(&mut providers.queries); rustc_metadata::provide(providers); - rustc_lint::provide(providers); - rustc_symbol_mangling::provide(providers); + rustc_lint::provide(&mut providers.queries); + rustc_symbol_mangling::provide(&mut providers.queries); rustc_codegen_ssa::provide(providers); *providers }); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 0de54cf87433..af6df0cd6eb6 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -585,6 +585,6 @@ const SYMBOL_OFFSET: u8 = 1; const SYMBOL_PREDEFINED: u8 = 2; pub fn provide(providers: &mut Providers) { - encoder::provide(providers); + encoder::provide(&mut providers.queries); decoder::provide(providers); } diff --git a/compiler/rustc_middle/src/util/mod.rs b/compiler/rustc_middle/src/util/mod.rs index 85519fb0a7d2..d5076a278eab 100644 --- a/compiler/rustc_middle/src/util/mod.rs +++ b/compiler/rustc_middle/src/util/mod.rs @@ -6,20 +6,3 @@ pub struct Providers { pub extern_queries: crate::query::ExternProviders, pub hooks: crate::hooks::Providers, } - -/// Backwards compatibility hack to keep the diff small. This -/// gives direct access to the `queries` field's fields, which -/// are what almost everything wants access to. -impl std::ops::DerefMut for Providers { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.queries - } -} - -impl std::ops::Deref for Providers { - type Target = crate::query::Providers; - - fn deref(&self) -> &Self::Target { - &self.queries - } -} diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 410ea791ac5c..91cc4dfa665f 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -23,12 +23,12 @@ use rustc_middle::util::Providers; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } pub fn provide(providers: &mut Providers) { - providers.check_match = thir::pattern::check_match; - providers.lit_to_const = thir::constant::lit_to_const; - providers.closure_saved_names_of_captured_variables = + providers.queries.check_match = thir::pattern::check_match; + providers.queries.lit_to_const = thir::constant::lit_to_const; + providers.queries.closure_saved_names_of_captured_variables = builder::closure_saved_names_of_captured_variables; - providers.check_unsafety = check_unsafety::check_unsafety; - providers.check_tail_calls = check_tail_calls::check_tail_calls; - providers.thir_body = thir::cx::thir_body; + providers.queries.check_unsafety = check_unsafety::check_unsafety; + providers.queries.check_tail_calls = check_tail_calls::check_tail_calls; + providers.queries.thir_body = thir::cx::thir_body; providers.hooks.build_mir_inner_impl = builder::build_mir_inner_impl; } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index c78b0adaf6f1..328a4b23c175 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -206,9 +206,9 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" } pub fn provide(providers: &mut Providers) { coverage::query::provide(providers); - ffi_unwind_calls::provide(providers); - shim::provide(providers); - cross_crate_inline::provide(providers); + ffi_unwind_calls::provide(&mut providers.queries); + shim::provide(&mut providers.queries); + cross_crate_inline::provide(&mut providers.queries); providers.queries = query::Providers { mir_keys, mir_built, diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 070db1ae6b5e..ce1704696918 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1825,5 +1825,5 @@ pub(crate) fn collect_crate_mono_items<'tcx>( pub(crate) fn provide(providers: &mut Providers) { providers.hooks.should_codegen_locally = should_codegen_locally; - providers.items_of_instance = items_of_instance; + providers.queries.items_of_instance = items_of_instance; } diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 5b4f74ca6a70..56c74b693fb7 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -52,5 +52,5 @@ fn custom_coerce_unsize_info<'tcx>( pub fn provide(providers: &mut Providers) { partitioning::provide(providers); - mono_checks::provide(providers); + mono_checks::provide(&mut providers.queries); } diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 13d7f6a25f76..a86230e9ab22 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -1313,12 +1313,12 @@ fn dump_mono_items_stats<'tcx>( } pub(crate) fn provide(providers: &mut Providers) { - providers.collect_and_partition_mono_items = collect_and_partition_mono_items; + providers.queries.collect_and_partition_mono_items = collect_and_partition_mono_items; - providers.is_codegened_item = + providers.queries.is_codegened_item = |tcx, def_id| tcx.collect_and_partition_mono_items(()).all_mono_items.contains(&def_id); - providers.codegen_unit = |tcx, name| { + providers.queries.codegen_unit = |tcx, name| { tcx.collect_and_partition_mono_items(()) .codegen_units .iter() @@ -1326,7 +1326,7 @@ pub(crate) fn provide(providers: &mut Providers) { .unwrap_or_else(|| panic!("failed to find cgu with name {name:?}")) }; - providers.size_estimate = |tcx, instance| { + providers.queries.size_estimate = |tcx, instance| { match instance.def { // "Normal" functions size estimate: the number of // statements, plus one for the terminator. diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 865f2a9c3b8b..d371589cba6c 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -9,7 +9,7 @@ #![feature(map_try_insert)] // tidy-alphabetical-end -use rustc_middle::util::Providers; +use rustc_middle::query::Providers; pub mod abi_test; mod check_attr; diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index fb2088963284..413163290ee3 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -297,14 +297,15 @@ pub(crate) fn create_config( override_queries: Some(|_sess, providers| { // We do not register late module lints, so this only runs `MissingDoc`. // Most lints will require typechecking, so just don't run them. - providers.lint_mod = |tcx, module_def_id| late_lint_mod(tcx, module_def_id, MissingDoc); + providers.queries.lint_mod = + |tcx, module_def_id| late_lint_mod(tcx, module_def_id, MissingDoc); // hack so that `used_trait_imports` won't try to call typeck - providers.used_trait_imports = |_, _| { + providers.queries.used_trait_imports = |_, _| { static EMPTY_SET: LazyLock> = LazyLock::new(UnordSet::default); &EMPTY_SET }; // In case typeck does end up being called, don't ICE in case there were name resolution errors - providers.typeck = move |tcx, def_id| { + providers.queries.typeck = move |tcx, def_id| { // Closures' tables come from their outermost function, // as they are part of the same "inference environment". // This avoids emitting errors for the parent twice (see similar code in `typeck_with_fallback`) @@ -316,7 +317,7 @@ pub(crate) fn create_config( let body = tcx.hir_body_owned_by(def_id); debug!("visiting body for {def_id:?}"); EmitIgnoredResolutionErrors::new(tcx).visit_body(body); - (rustc_interface::DEFAULT_QUERY_PROVIDERS.typeck)(tcx, def_id) + (rustc_interface::DEFAULT_QUERY_PROVIDERS.queries.typeck)(tcx, def_id) }; }), extra_symbols: Vec::new(), diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 19fbf90246c9..9816061a8eca 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -305,7 +305,7 @@ impl rustc_driver::Callbacks for MiriDepCompilerCalls { config.override_queries = Some(|_, local_providers| { // We need to add #[used] symbols to exported_symbols for `lookup_link_section`. // FIXME handle this somehow in rustc itself to avoid this hack. - local_providers.exported_non_generic_symbols = |tcx, LocalCrate| { + local_providers.queries.exported_non_generic_symbols = |tcx, LocalCrate| { let reachable_set = tcx .with_stable_hashing_context(|hcx| tcx.reachable_set(()).to_sorted(&hcx, true)); tcx.arena.alloc_from_iter( diff --git a/tests/ui-fulldeps/obtain-borrowck.rs b/tests/ui-fulldeps/obtain-borrowck.rs index 08213fd75880..a562d0ccd3df 100644 --- a/tests/ui-fulldeps/obtain-borrowck.rs +++ b/tests/ui-fulldeps/obtain-borrowck.rs @@ -114,7 +114,7 @@ impl rustc_driver::Callbacks for CompilerCalls { } fn override_queries(_session: &Session, local: &mut Providers) { - local.mir_borrowck = mir_borrowck; + local.queries.mir_borrowck = mir_borrowck; } // Since mir_borrowck does not have access to any other state, we need to use a @@ -142,8 +142,8 @@ fn mir_borrowck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ProvidedValue<'t } }); let mut providers = Providers::default(); - rustc_borrowck::provide(&mut providers); - let original_mir_borrowck = providers.mir_borrowck; + rustc_borrowck::provide(&mut providers.queries); + let original_mir_borrowck = providers.queries.mir_borrowck; original_mir_borrowck(tcx, def_id) } From 0c57e8c83266603eb2ef4e899fe76c783073ce7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 7 Jan 2026 16:57:33 +0100 Subject: [PATCH 0689/1061] Change `bors build finished` job to `publish toolstate` --- .github/workflows/ci.yml | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0fe906cb8622..e6a00bb42785 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -305,30 +305,22 @@ jobs: DD_GITHUB_JOB_NAME: ${{ matrix.full_name }} run: ./build/citool/debug/citool upload-build-metrics build/cpu-usage.csv - # This job isused to tell bors the final status of the build, as there is no practical way to detect - # when a workflow is successful listening to webhooks only in our current bors implementation (homu). + # This job is used to publish toolstate for successful auto builds. outcome: - name: bors build finished + name: publish toolstate runs-on: ubuntu-24.04 needs: [ calculate_matrix, job ] - # !cancelled() executes the job regardless of whether the previous jobs passed or failed - if: ${{ !cancelled() && contains(fromJSON('["auto", "try"]'), needs.calculate_matrix.outputs.run_type) }} - environment: ${{ ((github.repository == 'rust-lang/rust' && (github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try' || github.ref == 'refs/heads/automation/bors/auto')) && 'bors') || '' }} + if: ${{ needs.calculate_matrix.outputs.run_type == 'auto' }} + environment: ${{ (github.repository == 'rust-lang/rust' && 'bors') || '' }} steps: - name: checkout the source code uses: actions/checkout@v5 with: fetch-depth: 2 - # Calculate the exit status of the whole CI workflow. - # If all dependent jobs were successful, this exits with 0 (and the outcome job continues successfully). - # If a some dependent job has failed, this exits with 1. - - name: calculate the correct exit status - run: jq --exit-status 'all(.result == "success" or .result == "skipped")' <<< '${{ toJson(needs) }}' # Publish the toolstate if an auto build succeeds (just before push to the default branch) - name: publish toolstate run: src/ci/publish_toolstate.sh shell: bash - if: needs.calculate_matrix.outputs.run_type == 'auto' env: TOOLSTATE_ISSUES_API_URL: https://api.github.com/repos/rust-lang/rust/issues TOOLSTATE_PUBLISH: 1 From 414e00d3509a4cfedaab0d9c712a5f41861ea0c6 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 14 Jan 2026 15:55:49 +1100 Subject: [PATCH 0690/1061] Clarify the docs/examples for `ProjectionElem::ConstantIndex` --- compiler/rustc_middle/src/mir/syntax.rs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 83e9a1f1784b..6ec874fb15f7 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1221,25 +1221,32 @@ pub enum ProjectionElem { /// thing is true of the `ConstantIndex` and `Subslice` projections below. Index(V), - /// These indices are generated by slice patterns. Easiest to explain - /// by example: + /// These endpoint-relative indices are generated by slice/array patterns. + /// + /// For array types, `offset` is always relative to the start of the array. + /// For slice types, `from_end` determines whether `offset` is relative to + /// the start or the end of the slice being inspected. + /// + /// Slice-pattern indices are easiest to explain by the position of `X` in + /// these examples: /// /// ```ignore (illustrative) - /// [X, _, .._, _, _] => { offset: 0, min_length: 4, from_end: false }, - /// [_, X, .._, _, _] => { offset: 1, min_length: 4, from_end: false }, - /// [_, _, .._, X, _] => { offset: 2, min_length: 4, from_end: true }, - /// [_, _, .._, _, X] => { offset: 1, min_length: 4, from_end: true }, + /// [X, _, .., _, _] => { offset: 0, min_length: 4, from_end: false }, + /// [_, X, .., _, _] => { offset: 1, min_length: 4, from_end: false }, + /// [_, _, .., X, _] => { offset: 2, min_length: 4, from_end: true }, + /// [_, _, .., _, X] => { offset: 1, min_length: 4, from_end: true }, /// ``` ConstantIndex { - /// index or -index (in Python terms), depending on from_end + /// - If `from_end == false`, this is a 0-based offset from the start of the array/slice. + /// - If `from_end == true`, this is a 1-based offset from the end of the slice. offset: u64, /// The thing being indexed must be at least this long -- otherwise, the /// projection is UB. /// /// For arrays this is always the exact length. min_length: u64, - /// Counting backwards from end? This is always false when indexing an - /// array. + /// If `true`, `offset` is a 1-based offset from the end of the slice. + /// Always false when indexing an array. from_end: bool, }, From a9ce7503d51b2be5a71a25315b4b4cb63eebf8b6 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 14 Jan 2026 14:53:57 +1100 Subject: [PATCH 0691/1061] Pull array length determination out of `prefix_slice_suffix` --- .../src/builder/matches/match_pair.rs | 85 +++++++++++-------- 1 file changed, 48 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index 8cee3ff27e8f..19b4cd70c0b9 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -40,33 +40,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match_pairs: &mut Vec>, extra_data: &mut PatternExtraData<'tcx>, place: &PlaceBuilder<'tcx>, + array_len: Option, prefix: &[Pat<'tcx>], opt_slice: &Option>>, suffix: &[Pat<'tcx>], ) { - let tcx = self.tcx; - let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) { - let place_ty = place_resolved.ty(&self.local_decls, tcx).ty; - match place_ty.kind() { - ty::Array(_, length) => { - if let Some(length) = length.try_to_target_usize(tcx) { - (length, true) - } else { - // This can happen when the array length is a generic const - // expression that couldn't be evaluated (e.g., due to an error). - // Since there's already a compilation error, we use a fallback - // to avoid an ICE. - tcx.dcx().span_delayed_bug( - tcx.def_span(self.def_id), - "array length in pattern couldn't be evaluated", - ); - ((prefix.len() + suffix.len()).try_into().unwrap(), false) - } - } - _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false), - } - } else { - ((prefix.len() + suffix.len()).try_into().unwrap(), false) + let prefix_len = u64::try_from(prefix.len()).unwrap(); + let suffix_len = u64::try_from(suffix.len()).unwrap(); + + // For slice patterns with a `..` followed by 0 or more suffix subpatterns, + // the actual slice index of those subpatterns isn't statically known, so + // we have to index them relative to the end of the slice. + // + // For array patterns, all subpatterns are indexed relative to the start. + let (min_length, is_array) = match array_len { + Some(len) => (len, true), + None => (prefix_len + suffix_len, false), }; for (idx, subpattern) in prefix.iter().enumerate() { @@ -77,11 +66,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } if let Some(subslice_pat) = opt_slice { - let suffix_len = suffix.len() as u64; let subslice = place.clone_project(PlaceElem::Subslice { - from: prefix.len() as u64, - to: if exact_size { min_length - suffix_len } else { suffix_len }, - from_end: !exact_size, + from: prefix_len, + to: if is_array { min_length - suffix_len } else { suffix_len }, + from_end: !is_array, }); MatchPairTree::for_pattern(subslice, subslice_pat, self, match_pairs, extra_data); } @@ -89,9 +77,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { for (idx, subpattern) in suffix.iter().rev().enumerate() { let end_offset = (idx + 1) as u64; let elem = ProjectionElem::ConstantIndex { - offset: if exact_size { min_length - end_offset } else { end_offset }, + offset: if is_array { min_length - end_offset } else { end_offset }, min_length, - from_end: !exact_size, + from_end: !is_array, }; let place = place.clone_project(elem); MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data) @@ -256,14 +244,36 @@ impl<'tcx> MatchPairTree<'tcx> { } PatKind::Array { ref prefix, ref slice, ref suffix } => { - cx.prefix_slice_suffix( - &mut subpairs, - extra_data, - &place_builder, - prefix, - slice, - suffix, - ); + // Determine the statically-known length of the array type being matched. + // This should always succeed for legal programs, but could fail for + // erroneous programs (e.g. the type is `[u8; const { panic!() }]`), + // so take care not to ICE if this fails. + let array_len = match pattern.ty.kind() { + ty::Array(_, len) => len.try_to_target_usize(cx.tcx), + _ => None, + }; + if let Some(array_len) = array_len { + cx.prefix_slice_suffix( + &mut subpairs, + extra_data, + &place_builder, + Some(array_len), + prefix, + slice, + suffix, + ); + } else { + // If the array length couldn't be determined, ignore the + // subpatterns and delayed-assert that compilation will fail. + cx.tcx.dcx().span_delayed_bug( + pattern.span, + format!( + "array length in pattern couldn't be determined for ty={:?}", + pattern.ty + ), + ); + } + None } PatKind::Slice { ref prefix, ref slice, ref suffix } => { @@ -271,6 +281,7 @@ impl<'tcx> MatchPairTree<'tcx> { &mut subpairs, extra_data, &place_builder, + None, prefix, slice, suffix, From a72083f739c369cd1ce675a1d278505656674af6 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 14 Jan 2026 16:13:49 +1100 Subject: [PATCH 0692/1061] Avoid some more usize-to-u64 casts in `prefix_slice_suffix` --- .../rustc_mir_build/src/builder/matches/match_pair.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index 19b4cd70c0b9..3edd0234b0ad 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -58,9 +58,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None => (prefix_len + suffix_len, false), }; - for (idx, subpattern) in prefix.iter().enumerate() { - let elem = - ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false }; + for (offset, subpattern) in (0u64..).zip(prefix) { + let elem = ProjectionElem::ConstantIndex { offset, min_length, from_end: false }; let place = place.clone_project(elem); MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data) } @@ -74,8 +73,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { MatchPairTree::for_pattern(subslice, subslice_pat, self, match_pairs, extra_data); } - for (idx, subpattern) in suffix.iter().rev().enumerate() { - let end_offset = (idx + 1) as u64; + for (end_offset, subpattern) in (1u64..).zip(suffix.iter().rev()) { let elem = ProjectionElem::ConstantIndex { offset: if is_array { min_length - end_offset } else { end_offset }, min_length, From bc751adcdb7cd5cce59a6aec36e74b959132e0af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Dom=C3=ADnguez?= Date: Sun, 4 Jan 2026 17:26:21 +0100 Subject: [PATCH 0693/1061] Minor doc and ty fixes --- compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs index b8eb4f038216..7817755dafe4 100644 --- a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs +++ b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs @@ -445,9 +445,8 @@ fn declare_offload_fn<'ll>( // the gpu. For now, we only handle the data transfer part of it. // If two consecutive kernels use the same memory, we still move it to the host and back to the gpu. // Since in our frontend users (by default) don't have to specify data transfer, this is something -// we should optimize in the future! We also assume that everything should be copied back and forth, -// but sometimes we can directly zero-allocate on the device and only move back, or if something is -// immutable, we might only copy it to the device, but not back. +// we should optimize in the future! In some cases we can directly zero-allocate ont he device and +// only move data back, or if something is immutable, we might only copy it to the device. // // Current steps: // 0. Alloca some variables for the following steps From 2c9c5d14a210767f83358c6cb17c7a81ec7ae41c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Dom=C3=ADnguez?= Date: Tue, 6 Jan 2026 19:14:14 +0100 Subject: [PATCH 0694/1061] Allow bounded types --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 481f75f337d6..59cbcd78dd0f 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1388,7 +1388,8 @@ fn codegen_offload<'ll, 'tcx>( let args = get_args_from_tuple(bx, args[3], fn_target); let target_symbol = symbol_name_for_instance_in_crate(tcx, fn_target, LOCAL_CRATE); - let sig = tcx.fn_sig(fn_target.def_id()).skip_binder().skip_binder(); + let sig = tcx.fn_sig(fn_target.def_id()).instantiate_identity(); + let sig = tcx.instantiate_bound_regions_with_erased(sig); let inputs = sig.inputs(); let metadata = inputs.iter().map(|ty| OffloadMetadata::from_ty(tcx, *ty)).collect::>(); From 5769006794df86e3a27fedbc5317f695c0f153e6 Mon Sep 17 00:00:00 2001 From: dianqk Date: Wed, 14 Jan 2026 18:57:17 +0800 Subject: [PATCH 0695/1061] Run dummy_span.rs test with SimplifyComparisonIntegral --- tests/debuginfo/dummy_span.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/debuginfo/dummy_span.rs b/tests/debuginfo/dummy_span.rs index fec4f33e3d56..6cf79c46d9a9 100644 --- a/tests/debuginfo/dummy_span.rs +++ b/tests/debuginfo/dummy_span.rs @@ -1,6 +1,8 @@ //@ min-lldb-version: 310 //@ compile-flags:-g +// FIXME: Investigate why test fails without SimplifyComparisonIntegral pass. +//@ compile-flags: -Zmir-enable-passes=+SimplifyComparisonIntegral //@ ignore-backends: gcc // === GDB TESTS =================================================================================== From d0b760369f46eeb8ded4d7420d67d7bdc9f02dd1 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Sat, 10 Jan 2026 17:06:21 +0800 Subject: [PATCH 0696/1061] Remove all usage of FeedConstTy::No --- .../src/hir_ty_lowering/bounds.rs | 34 ++++----- .../src/hir_ty_lowering/mod.rs | 53 +++++++++++--- compiler/rustc_hir_typeck/src/expr.rs | 5 +- src/librustdoc/clean/mod.rs | 70 ++++++++++++++++--- 4 files changed, 126 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 72d21371f66c..0a874b881801 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -510,7 +510,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Create the generic arguments for the associated type or constant by joining the // parent arguments (the arguments of the trait) and the own arguments (the ones of // the associated item itself) and construct an alias type using them. - let alias_term = candidate.map_bound(|trait_ref| { + candidate.map_bound(|trait_ref| { let item_segment = hir::PathSegment { ident: constraint.ident, hir_id: constraint.hir_id, @@ -528,20 +528,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { debug!(?alias_args); ty::AliasTerm::new_from_args(tcx, assoc_item.def_id, alias_args) - }); - - // Provide the resolved type of the associated constant to `type_of(AnonConst)`. - if let Some(const_arg) = constraint.ct() - && let hir::ConstArgKind::Anon(anon_const) = const_arg.kind - { - let ty = alias_term - .map_bound(|alias| tcx.type_of(alias.def_id).instantiate(tcx, alias.args)); - let ty = - check_assoc_const_binding_type(self, constraint.ident, ty, constraint.hir_id); - tcx.feed_anon_const_type(anon_const.def_id, ty::EarlyBinder::bind(ty)); - } - - alias_term + }) }; match constraint.kind { @@ -555,7 +542,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::AssocItemConstraintKind::Equality { term } => { let term = match term { hir::Term::Ty(ty) => self.lower_ty(ty).into(), - hir::Term::Const(ct) => self.lower_const_arg(ct, FeedConstTy::No).into(), + hir::Term::Const(ct) => { + // Provide the resolved type of the associated constant + let ty = projection_term.map_bound(|alias| { + tcx.type_of(alias.def_id).instantiate(tcx, alias.args) + }); + let ty = check_assoc_const_binding_type( + self, + constraint.ident, + ty, + constraint.hir_id, + ); + + self.lower_const_arg(ct, FeedConstTy::WithTy(ty)).into() + } }; // Find any late-bound regions declared in `ty` that are not @@ -871,7 +871,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// probably gate this behind another feature flag. /// /// [^1]: . -fn check_assoc_const_binding_type<'tcx>( +pub(crate) fn check_assoc_const_binding_type<'tcx>( cx: &dyn HirTyLowerer<'tcx>, assoc_const: Ident, ty: ty::Binder<'tcx, Ty<'tcx>>, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index d2cbf89336d8..be5ac21e2ca8 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1269,10 +1269,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut where_bounds = vec![]; for bound in [bound, bound2].into_iter().chain(matching_candidates) { let bound_id = bound.def_id(); - let bound_span = tcx - .associated_items(bound_id) - .find_by_ident_and_kind(tcx, assoc_ident, assoc_tag, bound_id) - .and_then(|item| tcx.hir_span_if_local(item.def_id)); + let assoc_item = tcx.associated_items(bound_id).find_by_ident_and_kind( + tcx, + assoc_ident, + assoc_tag, + bound_id, + ); + let bound_span = assoc_item.and_then(|item| tcx.hir_span_if_local(item.def_id)); if let Some(bound_span) = bound_span { err.span_label( @@ -1285,7 +1288,41 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let term: ty::Term<'_> = match term { hir::Term::Ty(ty) => self.lower_ty(ty).into(), hir::Term::Const(ct) => { - self.lower_const_arg(ct, FeedConstTy::No).into() + let assoc_item = + assoc_item.expect("assoc_item should be present"); + let projection_term = bound.map_bound(|trait_ref| { + let item_segment = hir::PathSegment { + ident: constraint.ident, + hir_id: constraint.hir_id, + res: Res::Err, + args: Some(constraint.gen_args), + infer_args: false, + }; + + let alias_args = self.lower_generic_args_of_assoc_item( + constraint.ident.span, + assoc_item.def_id, + &item_segment, + trait_ref.args, + ); + ty::AliasTerm::new_from_args( + tcx, + assoc_item.def_id, + alias_args, + ) + }); + + let ty = projection_term.map_bound(|alias| { + tcx.type_of(alias.def_id).instantiate(tcx, alias.args) + }); + let ty = bounds::check_assoc_const_binding_type( + self, + constraint.ident, + ty, + constraint.hir_id, + ); + + self.lower_const_arg(ct, FeedConstTy::WithTy(ty)).into() } }; if term.references_error() { @@ -2993,7 +3030,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .unwrap_or_else(|guar| Ty::new_error(tcx, guar)) } hir::TyKind::Array(ty, length) => { - let length = self.lower_const_arg(length, FeedConstTy::No); + let length = self.lower_const_arg(length, FeedConstTy::WithTy(tcx.types.usize)); Ty::new_array_with_const_len(tcx, self.lower_ty(ty), length) } hir::TyKind::Infer(()) => { @@ -3033,8 +3070,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Keep this list of types in sync with the list of types that // the `RangePattern` trait is implemented for. ty::Int(_) | ty::Uint(_) | ty::Char => { - let start = self.lower_const_arg(start, FeedConstTy::No); - let end = self.lower_const_arg(end, FeedConstTy::No); + let start = self.lower_const_arg(start, FeedConstTy::WithTy(ty)); + let end = self.lower_const_arg(end, FeedConstTy::WithTy(ty)); Ok(ty::PatternKind::Range { start, end }) } _ => Err(self diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 9d7e09b020a7..d7366887d85c 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1749,7 +1749,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let count_span = count.span; let count = self.try_structurally_resolve_const( count_span, - self.normalize(count_span, self.lower_const_arg(count, FeedConstTy::No)), + self.normalize( + count_span, + self.lower_const_arg(count, FeedConstTy::WithTy(tcx.types.usize)), + ), ); if let Some(count) = count.try_to_target_usize(tcx) { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 597a85f39769..ac17014ebfde 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -469,11 +469,23 @@ fn clean_middle_term<'tcx>( } } -fn clean_hir_term<'tcx>(term: &hir::Term<'tcx>, cx: &mut DocContext<'tcx>) -> Term { +fn clean_hir_term<'tcx>( + assoc_item: Option, + term: &hir::Term<'tcx>, + span: rustc_span::Span, + cx: &mut DocContext<'tcx>, +) -> Term { match term { hir::Term::Ty(ty) => Term::Type(clean_ty(ty, cx)), hir::Term::Const(c) => { - let ct = lower_const_arg_for_rustdoc(cx.tcx, c, FeedConstTy::No); + let ty = if let Some(assoc_item) = assoc_item { + // FIXME(generic_const_items): this should instantiate with the alias item's args + cx.tcx.type_of(assoc_item).instantiate_identity() + } else { + Ty::new_error_with_message(cx.tcx, span, "cannot find the associated constant") + }; + + let ct = lower_const_arg_for_rustdoc(cx.tcx, c, FeedConstTy::WithTy(ty)); Term::Constant(clean_middle_const(ty::Binder::dummy(ct), cx)) } } @@ -650,7 +662,14 @@ fn clean_generic_param<'tcx>( GenericParamDefKind::Const { ty: Box::new(clean_ty(ty, cx)), default: default.map(|ct| { - Box::new(lower_const_arg_for_rustdoc(cx.tcx, ct, FeedConstTy::No).to_string()) + Box::new( + lower_const_arg_for_rustdoc( + cx.tcx, + ct, + FeedConstTy::WithTy(lower_ty(cx.tcx, ty)), + ) + .to_string(), + ) }), }, ), @@ -1531,7 +1550,7 @@ fn first_non_private_clean_path<'tcx>( && path_last.args.is_some() { assert!(new_path_last.args.is_empty()); - new_path_last.args = clean_generic_args(path_last_args, cx); + new_path_last.args = clean_generic_args(None, path_last_args, cx); } new_clean_path } @@ -1812,7 +1831,11 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T let length = match const_arg.kind { hir::ConstArgKind::Infer(..) | hir::ConstArgKind::Error(..) => "_".to_string(), hir::ConstArgKind::Anon(hir::AnonConst { def_id, .. }) => { - let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, FeedConstTy::No); + let ct = lower_const_arg_for_rustdoc( + cx.tcx, + const_arg, + FeedConstTy::WithTy(cx.tcx.types.usize), + ); let typing_env = ty::TypingEnv::post_analysis(cx.tcx, *def_id); let ct = cx.tcx.normalize_erasing_regions(typing_env, ct); print_const(cx, ct) @@ -1823,7 +1846,11 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T | hir::ConstArgKind::Tup(..) | hir::ConstArgKind::Array(..) | hir::ConstArgKind::Literal(..) => { - let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, FeedConstTy::No); + let ct = lower_const_arg_for_rustdoc( + cx.tcx, + const_arg, + FeedConstTy::WithTy(cx.tcx.types.usize), + ); print_const(cx, ct) } }; @@ -2516,6 +2543,7 @@ fn clean_path<'tcx>(path: &hir::Path<'tcx>, cx: &mut DocContext<'tcx>) -> Path { } fn clean_generic_args<'tcx>( + trait_did: Option, generic_args: &hir::GenericArgs<'tcx>, cx: &mut DocContext<'tcx>, ) -> GenericArgs { @@ -2539,7 +2567,13 @@ fn clean_generic_args<'tcx>( let constraints = generic_args .constraints .iter() - .map(|c| clean_assoc_item_constraint(c, cx)) + .map(|c| { + clean_assoc_item_constraint( + trait_did.expect("only trait ref has constraints"), + c, + cx, + ) + }) .collect::>(); GenericArgs::AngleBracketed { args, constraints } } @@ -2562,7 +2596,11 @@ fn clean_path_segment<'tcx>( path: &hir::PathSegment<'tcx>, cx: &mut DocContext<'tcx>, ) -> PathSegment { - PathSegment { name: path.ident.name, args: clean_generic_args(path.args(), cx) } + let trait_did = match path.res { + hir::def::Res::Def(DefKind::Trait | DefKind::TraitAlias, did) => Some(did), + _ => None, + }; + PathSegment { name: path.ident.name, args: clean_generic_args(trait_did, path.args(), cx) } } fn clean_bare_fn_ty<'tcx>( @@ -3126,17 +3164,29 @@ fn clean_maybe_renamed_foreign_item<'tcx>( } fn clean_assoc_item_constraint<'tcx>( + trait_did: DefId, constraint: &hir::AssocItemConstraint<'tcx>, cx: &mut DocContext<'tcx>, ) -> AssocItemConstraint { AssocItemConstraint { assoc: PathSegment { name: constraint.ident.name, - args: clean_generic_args(constraint.gen_args, cx), + args: clean_generic_args(None, constraint.gen_args, cx), }, kind: match constraint.kind { hir::AssocItemConstraintKind::Equality { ref term } => { - AssocItemConstraintKind::Equality { term: clean_hir_term(term, cx) } + let assoc_tag = match term { + hir::Term::Ty(_) => ty::AssocTag::Type, + hir::Term::Const(_) => ty::AssocTag::Const, + }; + let assoc_item = cx + .tcx + .associated_items(trait_did) + .find_by_ident_and_kind(cx.tcx, constraint.ident, assoc_tag, trait_did) + .map(|item| item.def_id); + AssocItemConstraintKind::Equality { + term: clean_hir_term(assoc_item, term, constraint.span, cx), + } } hir::AssocItemConstraintKind::Bound { bounds } => AssocItemConstraintKind::Bound { bounds: bounds.iter().filter_map(|b| clean_generic_bound(b, cx)).collect(), From e27fcfd28eb6b185894e38d1f9fbde216f026f3e Mon Sep 17 00:00:00 2001 From: mu001999 Date: Sun, 11 Jan 2026 18:43:25 +0800 Subject: [PATCH 0697/1061] Remove FeedConstTy --- compiler/rustc_hir_analysis/src/collect.rs | 8 +- .../src/hir_ty_lowering/bounds.rs | 5 +- .../src/hir_ty_lowering/mod.rs | 89 +++++-------------- compiler/rustc_hir_analysis/src/lib.rs | 6 +- compiler/rustc_hir_typeck/src/expr.rs | 7 +- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 13 +-- .../rustc_hir_typeck/src/method/confirm.rs | 7 +- src/librustdoc/clean/mod.rs | 22 +---- 8 files changed, 48 insertions(+), 109 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index bacdf0049806..2c0253409387 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -47,9 +47,7 @@ use rustc_trait_selection::traits::{ use tracing::{debug, instrument}; use crate::errors; -use crate::hir_ty_lowering::{ - FeedConstTy, HirTyLowerer, InherentAssocCandidate, RegionInferReason, -}; +use crate::hir_ty_lowering::{HirTyLowerer, InherentAssocCandidate, RegionInferReason}; pub(crate) mod dump; mod generics_of; @@ -1499,7 +1497,7 @@ fn const_param_default<'tcx>( let ct = icx .lowerer() - .lower_const_arg(default_ct, FeedConstTy::with_type_of(tcx, def_id, identity_args)); + .lower_const_arg(default_ct, tcx.type_of(def_id).instantiate(tcx, identity_args)); ty::EarlyBinder::bind(ct) } @@ -1557,7 +1555,7 @@ fn const_of_item<'tcx>( let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id); let ct = icx .lowerer() - .lower_const_arg(ct_arg, FeedConstTy::with_type_of(tcx, def_id.to_def_id(), identity_args)); + .lower_const_arg(ct_arg, tcx.type_of(def_id.to_def_id()).instantiate(tcx, identity_args)); if let Err(e) = icx.check_tainted_by_errors() && !ct.references_error() { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 0a874b881801..d6441702b268 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -20,7 +20,7 @@ use tracing::{debug, instrument}; use crate::errors; use crate::hir_ty_lowering::{ - AssocItemQSelf, FeedConstTy, GenericsArgsErrExtend, HirTyLowerer, ImpliedBoundsContext, + AssocItemQSelf, GenericsArgsErrExtend, HirTyLowerer, ImpliedBoundsContext, OverlappingAsssocItemConstraints, PredicateFilter, RegionInferReason, }; @@ -543,7 +543,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let term = match term { hir::Term::Ty(ty) => self.lower_ty(ty).into(), hir::Term::Const(ct) => { - // Provide the resolved type of the associated constant let ty = projection_term.map_bound(|alias| { tcx.type_of(alias.def_id).instantiate(tcx, alias.args) }); @@ -554,7 +553,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { constraint.hir_id, ); - self.lower_const_arg(ct, FeedConstTy::WithTy(ty)).into() + self.lower_const_arg(ct, ty).into() } }; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index be5ac21e2ca8..3dcc0232b301 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -253,35 +253,6 @@ impl AssocItemQSelf { } } -/// In some cases, [`hir::ConstArg`]s that are being used in the type system -/// through const generics need to have their type "fed" to them -/// using the query system. -/// -/// Use this enum with `::lower_const_arg` to instruct it with the -/// desired behavior. -#[derive(Debug, Clone, Copy)] -pub enum FeedConstTy<'tcx> { - /// Feed the type to the (anno) const arg. - WithTy(Ty<'tcx>), - /// Don't feed the type. - No, -} - -impl<'tcx> FeedConstTy<'tcx> { - /// The `DefId` belongs to the const param that we are supplying - /// this (anon) const arg to. - /// - /// The list of generic args is used to instantiate the parameters - /// used by the type of the const param specified by `DefId`. - pub fn with_type_of( - tcx: TyCtxt<'tcx>, - def_id: DefId, - generic_args: &[ty::GenericArg<'tcx>], - ) -> Self { - Self::WithTy(tcx.type_of(def_id).instantiate(tcx, generic_args)) - } -} - #[derive(Debug, Clone, Copy)] enum LowerTypeRelativePathMode { Type(PermitVariants), @@ -733,7 +704,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Ambig portions of `ConstArg` are handled in the match arm below .lower_const_arg( ct.as_unambig_ct(), - FeedConstTy::with_type_of(tcx, param.def_id, preceding_args), + tcx.type_of(param.def_id).instantiate(tcx, preceding_args), ) .into(), (&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { @@ -1322,7 +1293,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { constraint.hir_id, ); - self.lower_const_arg(ct, FeedConstTy::WithTy(ty)).into() + self.lower_const_arg(ct, ty).into() } }; if term.references_error() { @@ -2347,16 +2318,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Lower a [`hir::ConstArg`] to a (type-level) [`ty::Const`](Const). #[instrument(skip(self), level = "debug")] - pub fn lower_const_arg( - &self, - const_arg: &hir::ConstArg<'tcx>, - feed: FeedConstTy<'tcx>, - ) -> Const<'tcx> { + pub fn lower_const_arg(&self, const_arg: &hir::ConstArg<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { let tcx = self.tcx(); - if let FeedConstTy::WithTy(anon_const_type) = feed - && let hir::ConstArgKind::Anon(anon) = &const_arg.kind - { + if let hir::ConstArgKind::Anon(anon) = &const_arg.kind { // FIXME(generic_const_parameter_types): Ideally we remove these errors below when // we have the ability to intermix typeck of anon const const args with the parent // bodies typeck. @@ -2366,7 +2331,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // hir typeck was using equality but mir borrowck wound up using subtyping as that could // result in a non-infer in hir typeck but a region variable in borrowck. if tcx.features().generic_const_parameter_types() - && (anon_const_type.has_free_regions() || anon_const_type.has_erased_regions()) + && (ty.has_free_regions() || ty.has_erased_regions()) { let e = self.dcx().span_err( const_arg.span, @@ -2378,7 +2343,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // We must error if the instantiated type has any inference variables as we will // use this type to feed the `type_of` and query results must not contain inference // variables otherwise we will ICE. - if anon_const_type.has_non_region_infer() { + if ty.has_non_region_infer() { let e = self.dcx().span_err( const_arg.span, "anonymous constants with inferred types are not yet supported", @@ -2388,7 +2353,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } // We error when the type contains unsubstituted generics since we do not currently // give the anon const any of the generics from the parent. - if anon_const_type.has_non_region_param() { + if ty.has_non_region_param() { let e = self.dcx().span_err( const_arg.span, "anonymous constants referencing generics are not yet supported", @@ -2397,12 +2362,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { return ty::Const::new_error(tcx, e); } - tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(anon_const_type)); + tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(ty)); } let hir_id = const_arg.hir_id; match const_arg.kind { - hir::ConstArgKind::Tup(exprs) => self.lower_const_arg_tup(exprs, feed, const_arg.span), + hir::ConstArgKind::Tup(exprs) => self.lower_const_arg_tup(exprs, ty, const_arg.span), hir::ConstArgKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { debug!(?maybe_qself, ?path); let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); @@ -2426,16 +2391,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::ConstArgKind::TupleCall(qpath, args) => { self.lower_const_arg_tuple_call(hir_id, qpath, args, const_arg.span) } - hir::ConstArgKind::Array(array_expr) => self.lower_const_arg_array(array_expr, feed), + hir::ConstArgKind::Array(array_expr) => self.lower_const_arg_array(array_expr, ty), hir::ConstArgKind::Anon(anon) => self.lower_const_arg_anon(anon), hir::ConstArgKind::Infer(()) => self.ct_infer(None, const_arg.span), hir::ConstArgKind::Error(e) => ty::Const::new_error(tcx, e), - hir::ConstArgKind::Literal(kind) if let FeedConstTy::WithTy(anon_const_type) = feed => { - self.lower_const_arg_literal(&kind, anon_const_type, const_arg.span) - } - hir::ConstArgKind::Literal(..) => { - let e = self.dcx().span_err(const_arg.span, "literal of unknown type"); - ty::Const::new_error(tcx, e) + hir::ConstArgKind::Literal(kind) => { + self.lower_const_arg_literal(&kind, ty, const_arg.span) } } } @@ -2443,14 +2404,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn lower_const_arg_array( &self, array_expr: &'tcx hir::ConstArgArrayExpr<'tcx>, - feed: FeedConstTy<'tcx>, + ty: Ty<'tcx>, ) -> Const<'tcx> { let tcx = self.tcx(); - let FeedConstTy::WithTy(ty) = feed else { - return Const::new_error_with_message(tcx, array_expr.span, "unsupported const array"); - }; - let ty::Array(elem_ty, _) = ty.kind() else { return Const::new_error_with_message( tcx, @@ -2462,7 +2419,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let elems = array_expr .elems .iter() - .map(|elem| self.lower_const_arg(elem, FeedConstTy::WithTy(*elem_ty))) + .map(|elem| self.lower_const_arg(elem, *elem_ty)) .collect::>(); let valtree = ty::ValTree::from_branches(tcx, elems); @@ -2545,7 +2502,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .iter() .zip(args) .map(|(field_def, arg)| { - self.lower_const_arg(arg, FeedConstTy::with_type_of(tcx, field_def.did, adt_args)) + self.lower_const_arg(arg, tcx.type_of(field_def.did).instantiate(tcx, adt_args)) }) .collect::>(); @@ -2564,15 +2521,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn lower_const_arg_tup( &self, exprs: &'tcx [&'tcx hir::ConstArg<'tcx>], - feed: FeedConstTy<'tcx>, + ty: Ty<'tcx>, span: Span, ) -> Const<'tcx> { let tcx = self.tcx(); - let FeedConstTy::WithTy(ty) = feed else { - return Const::new_error_with_message(tcx, span, "const tuple lack type information"); - }; - let ty::Tuple(tys) = ty.kind() else { let e = tcx.dcx().span_err(span, format!("expected `{}`, found const tuple", ty)); return Const::new_error(tcx, e); @@ -2581,7 +2534,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let exprs = exprs .iter() .zip(tys.iter()) - .map(|(expr, ty)| self.lower_const_arg(expr, FeedConstTy::WithTy(ty))) + .map(|(expr, ty)| self.lower_const_arg(expr, ty)) .collect::>(); let valtree = ty::ValTree::from_branches(tcx, exprs); @@ -2668,7 +2621,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.lower_const_arg( expr.expr, - FeedConstTy::with_type_of(tcx, field_def.did, adt_args), + tcx.type_of(field_def.did).instantiate(tcx, adt_args), ) } None => { @@ -3030,7 +2983,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .unwrap_or_else(|guar| Ty::new_error(tcx, guar)) } hir::TyKind::Array(ty, length) => { - let length = self.lower_const_arg(length, FeedConstTy::WithTy(tcx.types.usize)); + let length = self.lower_const_arg(length, tcx.types.usize); Ty::new_array_with_const_len(tcx, self.lower_ty(ty), length) } hir::TyKind::Infer(()) => { @@ -3070,8 +3023,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Keep this list of types in sync with the list of types that // the `RangePattern` trait is implemented for. ty::Int(_) | ty::Uint(_) | ty::Char => { - let start = self.lower_const_arg(start, FeedConstTy::WithTy(ty)); - let end = self.lower_const_arg(end, FeedConstTy::WithTy(ty)); + let start = self.lower_const_arg(start, ty); + let end = self.lower_const_arg(end, ty); Ok(ty::PatternKind::Range { start, end }) } _ => Err(self diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 7296ba6f964a..a51355adf72f 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -101,7 +101,7 @@ use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::traits; pub use crate::collect::suggest_impl_trait; -use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer}; +use crate::hir_ty_lowering::HirTyLowerer; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } @@ -301,8 +301,8 @@ pub fn lower_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { pub fn lower_const_arg_for_rustdoc<'tcx>( tcx: TyCtxt<'tcx>, hir_ct: &hir::ConstArg<'tcx>, - feed: FeedConstTy<'tcx>, + ty: Ty<'tcx>, ) -> Const<'tcx> { let env_def_id = tcx.hir_get_parent_item(hir_ct.hir_id); - collect::ItemCtxt::new(tcx, env_def_id.def_id).lowerer().lower_const_arg(hir_ct, feed) + collect::ItemCtxt::new(tcx, env_def_id.def_id).lowerer().lower_const_arg(hir_ct, ty) } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index d7366887d85c..9f3ff0b2d03c 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -21,7 +21,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, HirId, QPath, find_attr, is_range_literal}; use rustc_hir_analysis::NoVariantNamed; -use rustc_hir_analysis::hir_ty_lowering::{FeedConstTy, HirTyLowerer as _}; +use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer as _; use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk, RegionVariableOrigin}; use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; @@ -1749,10 +1749,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let count_span = count.span; let count = self.try_structurally_resolve_const( count_span, - self.normalize( - count_span, - self.lower_const_arg(count, FeedConstTy::WithTy(tcx.types.usize)), - ), + self.normalize(count_span, self.lower_const_arg(count, tcx.types.usize)), ); if let Some(count) = count.try_to_target_usize(tcx) { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index a66ff2a23c25..91f91d911444 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -14,8 +14,8 @@ use rustc_hir_analysis::hir_ty_lowering::generics::{ check_generic_arg_count_for_call, lower_generic_args, }; use rustc_hir_analysis::hir_ty_lowering::{ - ExplicitLateBound, FeedConstTy, GenericArgCountMismatch, GenericArgCountResult, - GenericArgsLowerer, GenericPathSegment, HirTyLowerer, IsMethodCall, RegionInferReason, + ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgsLowerer, + GenericPathSegment, HirTyLowerer, IsMethodCall, RegionInferReason, }; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::{DefineOpaqueTypes, InferResult}; @@ -525,9 +525,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn lower_const_arg( &self, const_arg: &'tcx hir::ConstArg<'tcx>, - feed: FeedConstTy<'tcx>, + ty: Ty<'tcx>, ) -> ty::Const<'tcx> { - let ct = self.lowerer().lower_const_arg(const_arg, feed); + let ct = self.lowerer().lower_const_arg(const_arg, ty); self.register_wf_obligation( ct.into(), self.tcx.hir_span(const_arg.hir_id), @@ -1228,7 +1228,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Ambiguous parts of `ConstArg` are handled in the match arms below .lower_const_arg( ct.as_unambig_ct(), - FeedConstTy::with_type_of(self.fcx.tcx, param.def_id, preceding_args), + self.fcx + .tcx + .type_of(param.def_id) + .instantiate(self.fcx.tcx, preceding_args), ) .into(), (&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index aab4e3985555..270f011b2b15 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -7,7 +7,7 @@ use rustc_hir_analysis::hir_ty_lowering::generics::{ check_generic_arg_count_for_call, lower_generic_args, }; use rustc_hir_analysis::hir_ty_lowering::{ - FeedConstTy, GenericArgsLowerer, HirTyLowerer, IsMethodCall, RegionInferReason, + GenericArgsLowerer, HirTyLowerer, IsMethodCall, RegionInferReason, }; use rustc_infer::infer::{ BoundRegionConversionTime, DefineOpaqueTypes, InferOk, RegionVariableOrigin, @@ -447,7 +447,10 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // We handle the ambig portions of `ConstArg` in the match arms below .lower_const_arg( ct.as_unambig_ct(), - FeedConstTy::with_type_of(self.cfcx.tcx, param.def_id, preceding_args), + self.cfcx + .tcx + .type_of(param.def_id) + .instantiate(self.cfcx.tcx, preceding_args), ) .into(), (GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ac17014ebfde..c7c23f75d694 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -43,7 +43,6 @@ use rustc_hir::attrs::{AttributeKind, DocAttribute, DocInline}; use rustc_hir::def::{CtorKind, DefKind, MacroKinds, Res}; use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE, LocalDefId}; use rustc_hir::{LangItem, PredicateOrigin, find_attr}; -use rustc_hir_analysis::hir_ty_lowering::FeedConstTy; use rustc_hir_analysis::{lower_const_arg_for_rustdoc, lower_ty}; use rustc_middle::metadata::Reexport; use rustc_middle::middle::resolve_bound_vars as rbv; @@ -485,7 +484,7 @@ fn clean_hir_term<'tcx>( Ty::new_error_with_message(cx.tcx, span, "cannot find the associated constant") }; - let ct = lower_const_arg_for_rustdoc(cx.tcx, c, FeedConstTy::WithTy(ty)); + let ct = lower_const_arg_for_rustdoc(cx.tcx, c, ty); Term::Constant(clean_middle_const(ty::Binder::dummy(ct), cx)) } } @@ -663,12 +662,7 @@ fn clean_generic_param<'tcx>( ty: Box::new(clean_ty(ty, cx)), default: default.map(|ct| { Box::new( - lower_const_arg_for_rustdoc( - cx.tcx, - ct, - FeedConstTy::WithTy(lower_ty(cx.tcx, ty)), - ) - .to_string(), + lower_const_arg_for_rustdoc(cx.tcx, ct, lower_ty(cx.tcx, ty)).to_string(), ) }), }, @@ -1831,11 +1825,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T let length = match const_arg.kind { hir::ConstArgKind::Infer(..) | hir::ConstArgKind::Error(..) => "_".to_string(), hir::ConstArgKind::Anon(hir::AnonConst { def_id, .. }) => { - let ct = lower_const_arg_for_rustdoc( - cx.tcx, - const_arg, - FeedConstTy::WithTy(cx.tcx.types.usize), - ); + let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, cx.tcx.types.usize); let typing_env = ty::TypingEnv::post_analysis(cx.tcx, *def_id); let ct = cx.tcx.normalize_erasing_regions(typing_env, ct); print_const(cx, ct) @@ -1846,11 +1836,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T | hir::ConstArgKind::Tup(..) | hir::ConstArgKind::Array(..) | hir::ConstArgKind::Literal(..) => { - let ct = lower_const_arg_for_rustdoc( - cx.tcx, - const_arg, - FeedConstTy::WithTy(cx.tcx.types.usize), - ); + let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, cx.tcx.types.usize); print_const(cx, ct) } }; From 37f20b7631c6a6c712f0c19a91531623282d6507 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Sun, 11 Jan 2026 21:02:00 +0800 Subject: [PATCH 0698/1061] Bless tests --- .../associated-const-bindings/ambiguity.stderr | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/ui/const-generics/associated-const-bindings/ambiguity.stderr b/tests/ui/const-generics/associated-const-bindings/ambiguity.stderr index a14afe9d6923..806708f18d65 100644 --- a/tests/ui/const-generics/associated-const-bindings/ambiguity.stderr +++ b/tests/ui/const-generics/associated-const-bindings/ambiguity.stderr @@ -27,6 +27,12 @@ LL | const C: &'static str; ... LL | fn take1(_: impl Trait1) {} | ^^^^^^^ ambiguous associated constant `C` + | + = help: consider introducing a new type parameter `T` and adding `where` constraints: + where + T: Trait1, + T: Parent2::C = "?", + T: Parent1::C = "?" error: aborting due to 2 previous errors From 80bd069138feba6452059852785bb913a7dba66c Mon Sep 17 00:00:00 2001 From: mu001999 Date: Mon, 12 Jan 2026 23:50:32 +0800 Subject: [PATCH 0699/1061] Fix review comments --- .../rustc_hir_analysis/src/hir_ty_lowering/mod.rs | 2 ++ src/librustdoc/clean/mod.rs | 14 +++----------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 3dcc0232b301..65d2d61e6fc4 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1283,6 +1283,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) }); + // FIXME(mgca): code duplication with other places we lower + // the rhs' of associated const bindings let ty = projection_term.map_bound(|alias| { tcx.type_of(alias.def_id).instantiate(tcx, alias.args) }); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c7c23f75d694..0ad9d2fdbe80 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -471,19 +471,13 @@ fn clean_middle_term<'tcx>( fn clean_hir_term<'tcx>( assoc_item: Option, term: &hir::Term<'tcx>, - span: rustc_span::Span, cx: &mut DocContext<'tcx>, ) -> Term { match term { hir::Term::Ty(ty) => Term::Type(clean_ty(ty, cx)), hir::Term::Const(c) => { - let ty = if let Some(assoc_item) = assoc_item { - // FIXME(generic_const_items): this should instantiate with the alias item's args - cx.tcx.type_of(assoc_item).instantiate_identity() - } else { - Ty::new_error_with_message(cx.tcx, span, "cannot find the associated constant") - }; - + // FIXME(generic_const_items): this should instantiate with the alias item's args + let ty = cx.tcx.type_of(assoc_item.unwrap()).instantiate_identity(); let ct = lower_const_arg_for_rustdoc(cx.tcx, c, ty); Term::Constant(clean_middle_const(ty::Binder::dummy(ct), cx)) } @@ -3170,9 +3164,7 @@ fn clean_assoc_item_constraint<'tcx>( .associated_items(trait_did) .find_by_ident_and_kind(cx.tcx, constraint.ident, assoc_tag, trait_did) .map(|item| item.def_id); - AssocItemConstraintKind::Equality { - term: clean_hir_term(assoc_item, term, constraint.span, cx), - } + AssocItemConstraintKind::Equality { term: clean_hir_term(assoc_item, term, cx) } } hir::AssocItemConstraintKind::Bound { bounds } => AssocItemConstraintKind::Bound { bounds: bounds.iter().filter_map(|b| clean_generic_bound(b, cx)).collect(), From 12b4b72715b5814ab48fc4c78169fd6cef0ccc25 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Tue, 13 Jan 2026 20:53:48 +0800 Subject: [PATCH 0700/1061] Add test for issue 151048 --- .../mgca/tuple_expr_arg_bad-issue-151048.rs | 8 ++++++++ .../mgca/tuple_expr_arg_bad-issue-151048.stderr | 8 ++++++++ 2 files changed, 16 insertions(+) create mode 100644 tests/ui/const-generics/mgca/tuple_expr_arg_bad-issue-151048.rs create mode 100644 tests/ui/const-generics/mgca/tuple_expr_arg_bad-issue-151048.stderr diff --git a/tests/ui/const-generics/mgca/tuple_expr_arg_bad-issue-151048.rs b/tests/ui/const-generics/mgca/tuple_expr_arg_bad-issue-151048.rs new file mode 100644 index 000000000000..4aecd30e86bb --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_expr_arg_bad-issue-151048.rs @@ -0,0 +1,8 @@ +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +struct Y { + stuff: [u8; { ([1, 2], 3, [4, 5]) }], //~ ERROR expected `usize`, found const tuple +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/tuple_expr_arg_bad-issue-151048.stderr b/tests/ui/const-generics/mgca/tuple_expr_arg_bad-issue-151048.stderr new file mode 100644 index 000000000000..468bf703d90d --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_expr_arg_bad-issue-151048.stderr @@ -0,0 +1,8 @@ +error: expected `usize`, found const tuple + --> $DIR/tuple_expr_arg_bad-issue-151048.rs:5:19 + | +LL | stuff: [u8; { ([1, 2], 3, [4, 5]) }], + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + From 2b209a69cf97c18ecef9043abf3ec8b6fe9867b9 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 14 Jan 2026 13:21:16 +0000 Subject: [PATCH 0701/1061] Avoid serde dependency in build_helper when not necessary --- src/bootstrap/Cargo.toml | 2 +- src/build_helper/Cargo.toml | 7 +++++-- src/build_helper/src/lib.rs | 1 + src/ci/citool/Cargo.toml | 2 +- src/tools/opt-dist/Cargo.toml | 2 +- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index e1725db60cfc..e66c0576e9ee 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -6,7 +6,7 @@ build = "build.rs" default-run = "bootstrap" [features] -build-metrics = ["sysinfo"] +build-metrics = ["dep:sysinfo", "build_helper/metrics"] tracing = ["dep:tracing", "dep:tracing-chrome", "dep:tracing-subscriber", "dep:chrono", "dep:tempfile"] [lib] diff --git a/src/build_helper/Cargo.toml b/src/build_helper/Cargo.toml index 66894e1abc40..2ec44fe2730b 100644 --- a/src/build_helper/Cargo.toml +++ b/src/build_helper/Cargo.toml @@ -6,5 +6,8 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -serde = "1" -serde_derive = "1" +serde = { version = "1", optional = true } +serde_derive = { version = "1", optional = true } + +[features] +metrics = ["dep:serde", "dep:serde_derive"] diff --git a/src/build_helper/src/lib.rs b/src/build_helper/src/lib.rs index 266eedc62458..e23a158ac059 100644 --- a/src/build_helper/src/lib.rs +++ b/src/build_helper/src/lib.rs @@ -4,6 +4,7 @@ pub mod ci; pub mod drop_bomb; pub mod fs; pub mod git; +#[cfg(feature = "metrics")] pub mod metrics; pub mod npm; pub mod stage0_parser; diff --git a/src/ci/citool/Cargo.toml b/src/ci/citool/Cargo.toml index 468d8c8a02aa..539edf60033a 100644 --- a/src/ci/citool/Cargo.toml +++ b/src/ci/citool/Cargo.toml @@ -15,7 +15,7 @@ serde_yaml = "0.9" serde_json = "1" ureq = { version = "3", features = ["json"] } -build_helper = { path = "../../build_helper" } +build_helper = { path = "../../build_helper", features = ["metrics"] } [dev-dependencies] insta = "1" diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml index f4051ae67d7c..66c19183f343 100644 --- a/src/tools/opt-dist/Cargo.toml +++ b/src/tools/opt-dist/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] -build_helper = { path = "../../build_helper" } +build_helper = { path = "../../build_helper", features = ["metrics"] } env_logger = "0.11" log = "0.4" anyhow = "1" From 7d80e7d720162fed8223407e91912683631c93f2 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Wed, 14 Jan 2026 23:12:57 +0900 Subject: [PATCH 0702/1061] rustc_target: Remove unused Arch::PowerPC64LE target_arch for powerpc64le- targets is "powerpc64". --- compiler/rustc_codegen_llvm/src/mono_item.rs | 2 +- compiler/rustc_codegen_llvm/src/va_arg.rs | 9 --------- compiler/rustc_span/src/symbol.rs | 1 - compiler/rustc_target/src/asm/mod.rs | 2 +- compiler/rustc_target/src/callconv/mod.rs | 2 +- compiler/rustc_target/src/spec/mod.rs | 7 ++----- compiler/rustc_target/src/target_features.rs | 8 +------- src/tools/miri/src/shims/alloc.rs | 1 - 8 files changed, 6 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 1878f4043ee8..838db689e729 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -144,7 +144,7 @@ impl CodegenCx<'_, '_> { } // PowerPC64 prefers TOC indirection to avoid copy relocations. - if matches!(self.tcx.sess.target.arch, Arch::PowerPC64 | Arch::PowerPC64LE) { + if self.tcx.sess.target.arch == Arch::PowerPC64 { return false; } diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index 688f461e7478..c7da2457ada5 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -1064,15 +1064,6 @@ pub(super) fn emit_va_arg<'ll, 'tcx>( AllowHigherAlign::Yes, ForceRightAdjust::Yes, ), - Arch::PowerPC64LE => emit_ptr_va_arg( - bx, - addr, - target_ty, - PassMode::Direct, - SlotSize::Bytes8, - AllowHigherAlign::Yes, - ForceRightAdjust::No, - ), Arch::LoongArch32 => emit_ptr_va_arg( bx, addr, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index b473d36a45fc..c4f77cedbe09 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1723,7 +1723,6 @@ symbols! { postfix_match, powerpc, powerpc64, - powerpc64le, powerpc_target_feature, powf16, powf32, diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 0078866ab950..a10699bbce88 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -261,7 +261,7 @@ impl InlineAsmArch { Arch::Mips | Arch::Mips32r6 => Some(Self::Mips), Arch::Mips64 | Arch::Mips64r6 => Some(Self::Mips64), Arch::PowerPC => Some(Self::PowerPC), - Arch::PowerPC64 | Arch::PowerPC64LE => Some(Self::PowerPC64), + Arch::PowerPC64 => Some(Self::PowerPC64), Arch::S390x => Some(Self::S390x), Arch::Sparc => Some(Self::Sparc), Arch::Sparc64 => Some(Self::Sparc64), diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 6faa57252ca2..6c8e0e181c4a 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -702,7 +702,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { Arch::RiscV32 | Arch::RiscV64 => riscv::compute_abi_info(cx, self), Arch::Wasm32 | Arch::Wasm64 => wasm::compute_abi_info(cx, self), Arch::Bpf => bpf::compute_abi_info(cx, self), - arch @ (Arch::PowerPC64LE | Arch::SpirV | Arch::Other(_)) => { + arch @ (Arch::SpirV | Arch::Other(_)) => { panic!("no lowering implemented for {arch}") } } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 89c9fdc935cc..57effe3a8668 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1873,7 +1873,6 @@ crate::target_spec_enum! { Nvptx64 = "nvptx64", PowerPC = "powerpc", PowerPC64 = "powerpc64", - PowerPC64LE = "powerpc64le", RiscV32 = "riscv32", RiscV64 = "riscv64", S390x = "s390x", @@ -1911,7 +1910,6 @@ impl Arch { Self::Nvptx64 => sym::nvptx64, Self::PowerPC => sym::powerpc, Self::PowerPC64 => sym::powerpc64, - Self::PowerPC64LE => sym::powerpc64le, Self::RiscV32 => sym::riscv32, Self::RiscV64 => sym::riscv64, Self::S390x => sym::s390x, @@ -1940,8 +1938,8 @@ impl Arch { AArch64 | AmdGpu | Arm | Arm64EC | Avr | CSky | Hexagon | LoongArch32 | LoongArch64 | M68k | Mips | Mips32r6 | Mips64 | Mips64r6 | Msp430 | Nvptx64 | PowerPC - | PowerPC64 | PowerPC64LE | RiscV32 | RiscV64 | S390x | Sparc | Sparc64 | Wasm32 - | Wasm64 | X86 | X86_64 | Xtensa => true, + | PowerPC64 | RiscV32 | RiscV64 | S390x | Sparc | Sparc64 | Wasm32 | Wasm64 | X86 + | X86_64 | Xtensa => true, } } } @@ -3436,7 +3434,6 @@ impl Target { Arch::Arm64EC => (Architecture::Aarch64, Some(object::SubArchitecture::Arm64EC)), Arch::AmdGpu | Arch::Nvptx64 - | Arch::PowerPC64LE | Arch::SpirV | Arch::Wasm32 | Arch::Wasm64 diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 40cc4f40a333..4eba426dda59 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -986,7 +986,6 @@ impl Target { Arch::AmdGpu | Arch::Avr | Arch::Msp430 - | Arch::PowerPC64LE | Arch::SpirV | Arch::Xtensa | Arch::Other(_) => &[], @@ -1015,12 +1014,7 @@ impl Target { Arch::CSky => CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, // FIXME: for some tier3 targets, we are overly cautious and always give warnings // when passing args in vector registers. - Arch::Avr - | Arch::Msp430 - | Arch::PowerPC64LE - | Arch::SpirV - | Arch::Xtensa - | Arch::Other(_) => &[], + Arch::Avr | Arch::Msp430 | Arch::SpirV | Arch::Xtensa | Arch::Other(_) => &[], } } diff --git a/src/tools/miri/src/shims/alloc.rs b/src/tools/miri/src/shims/alloc.rs index 94649dde4736..b4d53c36d19b 100644 --- a/src/tools/miri/src/shims/alloc.rs +++ b/src/tools/miri/src/shims/alloc.rs @@ -52,7 +52,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | Arch::Bpf | Arch::Msp430 | Arch::Nvptx64 - | Arch::PowerPC64LE | Arch::SpirV | Arch::Other(_)) => bug!("unsupported target architecture for malloc: `{arch}`"), }; From c1bcae06384b1e6e0c1ddb25970df5eb77024084 Mon Sep 17 00:00:00 2001 From: Colin Murphy Date: Mon, 12 Jan 2026 10:45:24 -0500 Subject: [PATCH 0703/1061] Fix WASI threading regression with minimal invasive change Recent changes made WASI targets use the Unix threading implementation, but WASI does not support threading. When the Unix code tries to call pthread_create, it fails with EAGAIN, causing libraries like rayon to panic when trying to initialize their global thread pool. This fix adds an early return in Thread::new() that checks for WASI and returns UNSUPPORTED_PLATFORM. This approach: - Continues using most of the unix.rs code path (less invasive) - Only requires a small cfg check at the start of Thread::new() - Can be easily removed once wasi-sdk is updated with the proper fix The real fix is being tracked in `WebAssembly/wasi-libc#716` which will change the error code returned by pthread_create to properly indicate unsupported operations. Once that propagates to wasi-sdk, this workaround can be removed. Fixes the regression where rayon-based code (e.g., lopdf in PDF handling) panicked on WASI after nightly-2025-12-10. Before fix: pthread_create returns EAGAIN (error code 6) ThreadPoolBuildError { kind: IOError(Os { code: 6, kind: WouldBlock, message: "Resource temporarily unavailable" }) } After fix: Thread::new returns Err(io::Error::UNSUPPORTED_PLATFORM) Libraries can gracefully handle the lack of threading support --- library/std/src/sys/thread/unix.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/library/std/src/sys/thread/unix.rs b/library/std/src/sys/thread/unix.rs index d0396ed71300..f0cfdb956392 100644 --- a/library/std/src/sys/thread/unix.rs +++ b/library/std/src/sys/thread/unix.rs @@ -45,6 +45,15 @@ impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub unsafe fn new(stack: usize, init: Box) -> io::Result { + // FIXME: remove this block once wasi-sdk is updated with the fix from + // https://github.com/WebAssembly/wasi-libc/pull/716 + // WASI does not support threading via pthreads. While wasi-libc provides + // pthread stubs, pthread_create returns EAGAIN, which causes confusing + // errors. We return UNSUPPORTED_PLATFORM directly instead. + if cfg!(target_os = "wasi") { + return Err(io::Error::UNSUPPORTED_PLATFORM); + } + let data = init; let mut attr: mem::MaybeUninit = mem::MaybeUninit::uninit(); assert_eq!(libc::pthread_attr_init(attr.as_mut_ptr()), 0); From 0361bd004a5074e7fddc8479bca9414e03178e04 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 12 Jan 2026 02:10:41 +0300 Subject: [PATCH 0704/1061] resolve: In `visit_scopes` do not extract ctxt out of span unless necessary --- compiler/rustc_resolve/src/diagnostics.rs | 5 ++++- compiler/rustc_resolve/src/ident.rs | 19 +++++++++++-------- compiler/rustc_resolve/src/late.rs | 8 +++----- compiler/rustc_resolve/src/lib.rs | 2 +- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 7bc08f1de546..899f81525529 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -32,7 +32,9 @@ use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::{SourceMap, Spanned}; -use rustc_span::{BytePos, Ident, Macros20NormalizedIdent, Span, Symbol, SyntaxContext, kw, sym}; +use rustc_span::{ + BytePos, DUMMY_SP, Ident, Macros20NormalizedIdent, Span, Symbol, SyntaxContext, kw, sym, +}; use thin_vec::{ThinVec, thin_vec}; use tracing::{debug, instrument}; @@ -1179,6 +1181,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ctxt: SyntaxContext, filter_fn: &impl Fn(Res) -> bool, ) { + let ctxt = DUMMY_SP.with_ctxt(ctxt); self.cm().visit_scopes(scope_set, ps, ctxt, None, |this, scope, use_prelude, _| { match scope { Scope::DeriveHelpers(expn_id) => { diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 7f04216c5553..f7e628048ccd 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -53,13 +53,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { mut self: CmResolver<'r, 'ra, 'tcx>, scope_set: ScopeSet<'ra>, parent_scope: &ParentScope<'ra>, - orig_ctxt: SyntaxContext, + // Location of the span is not significant, but pass a `Span` instead of `SyntaxContext` + // to avoid extracting and re-packaging the syntax context unnecessarily. + orig_ctxt: Span, derive_fallback_lint_id: Option, mut visitor: impl FnMut( &mut CmResolver<'r, 'ra, 'tcx>, Scope<'ra>, UsePrelude, - SyntaxContext, + Span, ) -> ControlFlow, ) -> Option { // General principles: @@ -238,11 +240,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn hygienic_lexical_parent( &self, module: Module<'ra>, - ctxt: &mut SyntaxContext, + span: &mut Span, derive_fallback_lint_id: Option, ) -> Option<(Module<'ra>, Option)> { - if !module.expansion.outer_expn_is_descendant_of(*ctxt) { - return Some((self.expn_def_scope(ctxt.remove_mark()), None)); + let ctxt = span.ctxt(); + if !module.expansion.outer_expn_is_descendant_of(ctxt) { + return Some((self.expn_def_scope(span.remove_mark()), None)); } if let ModuleKind::Block = module.kind { @@ -272,7 +275,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let ext = &self.get_macro_by_def_id(def_id).ext; if ext.builtin_name.is_none() && ext.macro_kinds() == MacroKinds::DERIVE - && parent.expansion.outer_expn_is_descendant_of(*ctxt) + && parent.expansion.outer_expn_is_descendant_of(ctxt) { return Some((parent, derive_fallback_lint_id)); } @@ -433,10 +436,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let break_result = self.visit_scopes( scope_set, parent_scope, - orig_ident.span.ctxt(), + orig_ident.span, derive_fallback_lint_id, |this, scope, use_prelude, ctxt| { - let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt)); + let ident = Ident::new(orig_ident.name, ctxt); // The passed `ctxt` is already normalized, so avoid expensive double normalization. let ident = Macros20NormalizedIdent(ident); let res = match this.reborrow().resolve_ident_in_scope( diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 6d0097631772..6557e1dea1a1 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -37,9 +37,7 @@ use rustc_session::config::{CrateType, ResolveDocLinks}; use rustc_session::lint; use rustc_session::parse::feature_err; use rustc_span::source_map::{Spanned, respan}; -use rustc_span::{ - BytePos, DUMMY_SP, Ident, Macros20NormalizedIdent, Span, Symbol, SyntaxContext, kw, sym, -}; +use rustc_span::{BytePos, DUMMY_SP, Ident, Macros20NormalizedIdent, Span, Symbol, kw, sym}; use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; use tracing::{debug, instrument, trace}; @@ -5224,7 +5222,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.r.traits_in_scope( self.current_trait_ref.as_ref().map(|(module, _)| *module), &self.parent_scope, - ident.span.ctxt(), + ident.span, Some((ident.name, ns)), ) } @@ -5323,7 +5321,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { .entry(self.parent_scope.module.nearest_parent_mod().expect_local()) .or_insert_with(|| { self.r - .traits_in_scope(None, &self.parent_scope, SyntaxContext::root(), None) + .traits_in_scope(None, &self.parent_scope, DUMMY_SP, None) .into_iter() .filter_map(|tr| { if self.is_invalid_proc_macro_item_for_doc(tr.def_id) { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index c4c1e06f94ae..0939f8cddbe5 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1918,7 +1918,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { &mut self, current_trait: Option>, parent_scope: &ParentScope<'ra>, - ctxt: SyntaxContext, + ctxt: Span, assoc_item: Option<(Symbol, Namespace)>, ) -> Vec { let mut found_traits = Vec::new(); From 00384df08069939166b91813bca8b3c67d47d850 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Wed, 14 Jan 2026 17:47:11 +0100 Subject: [PATCH 0705/1061] Delete `MetaItemOrLitParser::Err` --- compiler/rustc_attr_parsing/src/attributes/cfg.rs | 1 - compiler/rustc_attr_parsing/src/attributes/doc.rs | 6 ------ compiler/rustc_attr_parsing/src/parser.rs | 8 +++----- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index ccf0a394afd0..dcb74dda81af 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -94,7 +94,6 @@ pub fn parse_cfg_entry( LitKind::Bool(b) => CfgEntry::Bool(b, lit.span), _ => return Err(cx.expected_identifier(lit.span)), }, - MetaItemOrLitParser::Err(_, err) => return Err(*err), }) } diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 6cc4ac35eadb..409102a79c06 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -514,9 +514,6 @@ impl DocParser { MetaItemOrLitParser::Lit(lit) => { cx.unexpected_literal(lit.span); } - MetaItemOrLitParser::Err(..) => { - // already had an error here, move on. - } } } } @@ -600,9 +597,6 @@ impl DocParser { MetaItemOrLitParser::Lit(lit) => { cx.expected_name_value(lit.span, None); } - MetaItemOrLitParser::Err(..) => { - // already had an error here, move on. - } } } } diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 68265649d182..ebf12dd1dfde 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -18,7 +18,7 @@ use rustc_parse::exp; use rustc_parse::parser::{ForceCollect, Parser, PathStyle, token_descr}; use rustc_session::errors::{create_lit_error, report_lit_error}; use rustc_session::parse::ParseSess; -use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, sym}; +use rustc_span::{Ident, Span, Symbol, sym}; use thin_vec::ThinVec; use crate::ShouldEmit; @@ -192,7 +192,6 @@ impl ArgParser { pub enum MetaItemOrLitParser { MetaItemParser(MetaItemParser), Lit(MetaItemLit), - Err(Span, ErrorGuaranteed), } impl MetaItemOrLitParser { @@ -210,21 +209,20 @@ impl MetaItemOrLitParser { generic_meta_item_parser.span() } MetaItemOrLitParser::Lit(meta_item_lit) => meta_item_lit.span, - MetaItemOrLitParser::Err(span, _) => *span, } } pub fn lit(&self) -> Option<&MetaItemLit> { match self { MetaItemOrLitParser::Lit(meta_item_lit) => Some(meta_item_lit), - _ => None, + MetaItemOrLitParser::MetaItemParser(_) => None, } } pub fn meta_item(&self) -> Option<&MetaItemParser> { match self { MetaItemOrLitParser::MetaItemParser(parser) => Some(parser), - _ => None, + MetaItemOrLitParser::Lit(_) => None, } } } From 8b52c73b3ec29dadf5df8dc02aeea5aeea778fd7 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 10 Jan 2026 19:21:38 +0300 Subject: [PATCH 0706/1061] resolve: Relax some asserts in glob overwriting and add tests --- compiler/rustc_resolve/src/imports.rs | 6 ++--- tests/ui/imports/overwrite-deep-glob.rs | 22 ++++++++++++++++ tests/ui/imports/overwrite-deep-glob.stderr | 12 +++++++++ tests/ui/imports/overwrite-different-ambig.rs | 25 +++++++++++++++++++ tests/ui/imports/overwrite-different-vis.rs | 21 ++++++++++++++++ 5 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 tests/ui/imports/overwrite-deep-glob.rs create mode 100644 tests/ui/imports/overwrite-deep-glob.stderr create mode 100644 tests/ui/imports/overwrite-different-ambig.rs create mode 100644 tests/ui/imports/overwrite-different-vis.rs diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index e525abd00f99..7c0cbcf1d522 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -300,13 +300,13 @@ fn remove_same_import<'ra>(d1: Decl<'ra>, d2: Decl<'ra>) -> (Decl<'ra>, Decl<'ra if let DeclKind::Import { import: import1, source_decl: d1_next } = d1.kind && let DeclKind::Import { import: import2, source_decl: d2_next } = d2.kind && import1 == import2 - && d1.warn_ambiguity.get() == d2.warn_ambiguity.get() { assert_eq!(d1.ambiguity.get(), d2.ambiguity.get()); - assert!(!d1.warn_ambiguity.get()); assert_eq!(d1.expansion, d2.expansion); assert_eq!(d1.span, d2.span); - assert_eq!(d1.vis(), d2.vis()); + // Visibility of the new import declaration may be different, + // because it already incorporates the visibility of the source binding. + // `warn_ambiguity` of a re-fetched glob can also change in both directions. remove_same_import(d1_next, d2_next) } else { (d1, d2) diff --git a/tests/ui/imports/overwrite-deep-glob.rs b/tests/ui/imports/overwrite-deep-glob.rs new file mode 100644 index 000000000000..261b22f6e0a0 --- /dev/null +++ b/tests/ui/imports/overwrite-deep-glob.rs @@ -0,0 +1,22 @@ +//@ check-pass + +mod openssl { + pub use self::handwritten::*; + + mod handwritten { + mod m1 { + pub struct S {} + } + mod m2 { + #[derive(Default)] + pub struct S {} + } + + pub use self::m1::*; //~ WARN ambiguous glob re-exports + pub use self::m2::*; + } +} + +pub use openssl::*; + +fn main() {} diff --git a/tests/ui/imports/overwrite-deep-glob.stderr b/tests/ui/imports/overwrite-deep-glob.stderr new file mode 100644 index 000000000000..093478c57c93 --- /dev/null +++ b/tests/ui/imports/overwrite-deep-glob.stderr @@ -0,0 +1,12 @@ +warning: ambiguous glob re-exports + --> $DIR/overwrite-deep-glob.rs:15:17 + | +LL | pub use self::m1::*; + | ^^^^^^^^^^^ the name `S` in the type namespace is first re-exported here +LL | pub use self::m2::*; + | ----------- but the name `S` in the type namespace is also re-exported here + | + = note: `#[warn(ambiguous_glob_reexports)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/imports/overwrite-different-ambig.rs b/tests/ui/imports/overwrite-different-ambig.rs new file mode 100644 index 000000000000..9aee63e18973 --- /dev/null +++ b/tests/ui/imports/overwrite-different-ambig.rs @@ -0,0 +1,25 @@ +//@ check-pass +//@ edition:2024 + +mod a { + mod b { + mod c { + pub struct E; + } + mod d { + mod c { + pub struct E; + } + mod d { + #[derive(Debug)] + pub struct E; + } + pub use c::*; + use d::*; + } + use c::*; + use d::*; + } +} + +fn main() {} diff --git a/tests/ui/imports/overwrite-different-vis.rs b/tests/ui/imports/overwrite-different-vis.rs new file mode 100644 index 000000000000..edcc441bcb77 --- /dev/null +++ b/tests/ui/imports/overwrite-different-vis.rs @@ -0,0 +1,21 @@ +//@ check-pass + +mod b { + pub mod http { + pub struct HeaderMap; + } + + pub(crate) use self::http::*; + #[derive(Debug)] + pub struct HeaderMap; +} + +mod a { + pub use crate::b::*; + + fn check_type() { + let _: HeaderMap = crate::b::HeaderMap; + } +} + +fn main() {} From 81ef42d5b7c4de7e8fa621fff4dc8f4627a581dc Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 11 Jan 2026 01:31:10 +0300 Subject: [PATCH 0707/1061] resolve: Consistently use old decls before new decls in interfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The opposite ordering was a consistent source of confusion during debuggingю `report_conflict` actually used an incorrect order due to similar confusion. --- compiler/rustc_resolve/src/diagnostics.rs | 4 ++-- compiler/rustc_resolve/src/imports.rs | 8 ++++---- tests/ui/hygiene/cross-crate-redefine.rs | 2 +- tests/ui/hygiene/cross-crate-redefine.stderr | 7 +++---- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index b80011e8c0cb..9f13ba1201f7 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -212,12 +212,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { &mut self, ident: Ident, ns: Namespace, - new_binding: Decl<'ra>, old_binding: Decl<'ra>, + new_binding: Decl<'ra>, ) { // Error on the second of two conflicting names if old_binding.span.lo() > new_binding.span.lo() { - return self.report_conflict(ident, ns, old_binding, new_binding); + return self.report_conflict(ident, ns, new_binding, old_binding); } let container = match old_binding.parent_module.unwrap().kind { diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 7c0cbcf1d522..c3ea408deb89 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -348,8 +348,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// decide which one to keep. fn select_glob_decl( &self, - glob_decl: Decl<'ra>, old_glob_decl: Decl<'ra>, + glob_decl: Decl<'ra>, warn_ambiguity: bool, ) -> Decl<'ra> { assert!(glob_decl.is_glob_import()); @@ -369,7 +369,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // with the re-fetched decls. // This is probably incorrect in corner cases, and the outdated decls still get // propagated to other places and get stuck there, but that's what we have at the moment. - let (deep_decl, old_deep_decl) = remove_same_import(glob_decl, old_glob_decl); + let (old_deep_decl, deep_decl) = remove_same_import(old_glob_decl, glob_decl); if deep_decl != glob_decl { // Some import layers have been removed, need to overwrite. assert_ne!(old_deep_decl, old_glob_decl); @@ -436,7 +436,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { match (old_decl.is_glob_import(), decl.is_glob_import()) { (true, true) => { resolution.glob_decl = - Some(this.select_glob_decl(decl, old_decl, warn_ambiguity)); + Some(this.select_glob_decl(old_decl, decl, warn_ambiguity)); } (old_glob @ true, false) | (old_glob @ false, true) => { let (glob_decl, non_glob_decl) = @@ -446,7 +446,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && old_glob_decl != glob_decl { resolution.glob_decl = - Some(this.select_glob_decl(glob_decl, old_glob_decl, false)); + Some(this.select_glob_decl(old_glob_decl, glob_decl, false)); } else { resolution.glob_decl = Some(glob_decl); } diff --git a/tests/ui/hygiene/cross-crate-redefine.rs b/tests/ui/hygiene/cross-crate-redefine.rs index e42c5e3de064..a87c933391d4 100644 --- a/tests/ui/hygiene/cross-crate-redefine.rs +++ b/tests/ui/hygiene/cross-crate-redefine.rs @@ -8,7 +8,7 @@ extern crate use_by_macro; use use_by_macro::*; my_struct!(define); -//~^ ERROR the name `MyStruct` is defined multiple times my_struct!(define); +//~^ ERROR the name `MyStruct` is defined multiple times fn main() {} diff --git a/tests/ui/hygiene/cross-crate-redefine.stderr b/tests/ui/hygiene/cross-crate-redefine.stderr index c0fd3f4b7ebf..8ad7d6d7b089 100644 --- a/tests/ui/hygiene/cross-crate-redefine.stderr +++ b/tests/ui/hygiene/cross-crate-redefine.stderr @@ -1,11 +1,10 @@ error[E0428]: the name `MyStruct` is defined multiple times - --> $DIR/cross-crate-redefine.rs:10:1 + --> $DIR/cross-crate-redefine.rs:11:1 | -LL | my_struct!(define); - | ^^^^^^^^^^^^^^^^^^ `MyStruct` redefined here -LL | LL | my_struct!(define); | ------------------ previous definition of the type `MyStruct` here +LL | my_struct!(define); + | ^^^^^^^^^^^^^^^^^^ `MyStruct` redefined here | = note: `MyStruct` must be defined only once in the type namespace of this module = note: this error originates in the macro `my_struct` (in Nightly builds, run with -Z macro-backtrace for more info) From 1c3841b372a248c0e8c405b051050dbef68f1527 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 11 Jan 2026 22:44:37 +0300 Subject: [PATCH 0708/1061] Add a test for issue 150977 --- .../overwrite-different-warn-ambiguity.rs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/ui/imports/overwrite-different-warn-ambiguity.rs diff --git a/tests/ui/imports/overwrite-different-warn-ambiguity.rs b/tests/ui/imports/overwrite-different-warn-ambiguity.rs new file mode 100644 index 000000000000..f843208b37d6 --- /dev/null +++ b/tests/ui/imports/overwrite-different-warn-ambiguity.rs @@ -0,0 +1,28 @@ +//@ check-pass +//@ edition:2024 + +mod framing { + mod public_message_in { + mod public_message { + mod public_message { + pub struct ConfirmedTranscriptHashInput; + } + mod public_message_in { + use super::*; + #[derive(Debug)] + pub struct ConfirmedTranscriptHashInput; + } + pub use public_message::*; + use public_message_in::*; + } + mod public_message_in { + #[derive(Debug)] + pub struct ConfirmedTranscriptHashInput; + } + pub use public_message::*; + use public_message_in::*; + } + use public_message_in::*; +} + +fn main() {} From 83c5f2c19409deb44778bc6ad36a33f3b9ce0f57 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 11 Jan 2026 23:16:42 +0300 Subject: [PATCH 0709/1061] resolve: Relax one more assert in glob overwriting and add a test Also avoid losing some glob ambiguities when re-fetching globs --- compiler/rustc_resolve/src/imports.rs | 9 +++- .../ui/imports/overwrite-different-ambig-2.rs | 24 +++++++++ .../overwrite-different-ambig-2.stderr | 49 +++++++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 tests/ui/imports/overwrite-different-ambig-2.rs create mode 100644 tests/ui/imports/overwrite-different-ambig-2.stderr diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index c3ea408deb89..451779ae32c6 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -301,9 +301,12 @@ fn remove_same_import<'ra>(d1: Decl<'ra>, d2: Decl<'ra>) -> (Decl<'ra>, Decl<'ra && let DeclKind::Import { import: import2, source_decl: d2_next } = d2.kind && import1 == import2 { - assert_eq!(d1.ambiguity.get(), d2.ambiguity.get()); assert_eq!(d1.expansion, d2.expansion); assert_eq!(d1.span, d2.span); + if d1.ambiguity.get() != d2.ambiguity.get() { + assert!(d1.ambiguity.get().is_some()); + assert!(d2.ambiguity.get().is_none()); + } // Visibility of the new import declaration may be different, // because it already incorporates the visibility of the source binding. // `warn_ambiguity` of a re-fetched glob can also change in both directions. @@ -377,6 +380,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // assert_ne!(old_deep_decl, deep_decl); // assert!(old_deep_decl.is_glob_import()); assert!(!deep_decl.is_glob_import()); + if old_glob_decl.ambiguity.get().is_some() && glob_decl.ambiguity.get().is_none() { + // Do not lose glob ambiguities when re-fetching the glob. + glob_decl.ambiguity.set_unchecked(old_glob_decl.ambiguity.get()); + } if glob_decl.is_ambiguity_recursive() { glob_decl.warn_ambiguity.set_unchecked(true); } diff --git a/tests/ui/imports/overwrite-different-ambig-2.rs b/tests/ui/imports/overwrite-different-ambig-2.rs new file mode 100644 index 000000000000..1b6d20e24d30 --- /dev/null +++ b/tests/ui/imports/overwrite-different-ambig-2.rs @@ -0,0 +1,24 @@ +mod m1 { + mod inner { + pub struct S {} + } + pub use self::inner::*; + + #[derive(Debug)] + pub struct S {} +} + +mod m2 { + pub struct S {} +} + +// First we have a glob ambiguity in this glob (with `m2::*`). +// Then we re-fetch `m1::*` because non-glob `m1::S` materializes from derive, +// and we need to make sure that the glob ambiguity is not lost during re-fetching. +use m1::*; +use m2::*; + +fn main() { + let _: m1::S = S {}; //~ ERROR `S` is ambiguous + //~| WARN this was previously accepted +} diff --git a/tests/ui/imports/overwrite-different-ambig-2.stderr b/tests/ui/imports/overwrite-different-ambig-2.stderr new file mode 100644 index 000000000000..e75f552d119c --- /dev/null +++ b/tests/ui/imports/overwrite-different-ambig-2.stderr @@ -0,0 +1,49 @@ +error: `S` is ambiguous + --> $DIR/overwrite-different-ambig-2.rs:22:20 + | +LL | let _: m1::S = S {}; + | ^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `S` could refer to the struct imported here + --> $DIR/overwrite-different-ambig-2.rs:18:5 + | +LL | use m1::*; + | ^^^^^ + = help: consider adding an explicit import of `S` to disambiguate +note: `S` could also refer to the struct imported here + --> $DIR/overwrite-different-ambig-2.rs:19:5 + | +LL | use m2::*; + | ^^^^^ + = help: consider adding an explicit import of `S` to disambiguate + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + +error: aborting due to 1 previous error + +Future incompatibility report: Future breakage diagnostic: +error: `S` is ambiguous + --> $DIR/overwrite-different-ambig-2.rs:22:20 + | +LL | let _: m1::S = S {}; + | ^ ambiguous name + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114095 + = note: ambiguous because of multiple glob imports of a name in the same module +note: `S` could refer to the struct imported here + --> $DIR/overwrite-different-ambig-2.rs:18:5 + | +LL | use m1::*; + | ^^^^^ + = help: consider adding an explicit import of `S` to disambiguate +note: `S` could also refer to the struct imported here + --> $DIR/overwrite-different-ambig-2.rs:19:5 + | +LL | use m2::*; + | ^^^^^ + = help: consider adding an explicit import of `S` to disambiguate + = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + From 9f1cf9efe0eaa25e76243e23a695b9a042c16c06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 14 Jan 2026 18:01:50 +0100 Subject: [PATCH 0710/1061] Add temporary new bors e-mail address to the mailmap To match it to bors in thanks. --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index 4c254b396b53..948f1ab14fde 100644 --- a/.mailmap +++ b/.mailmap @@ -96,6 +96,7 @@ boolean_coercion Boris Egorov bors bors[bot] <26634292+bors[bot]@users.noreply.github.com> bors bors[bot] +bors <122020455+rust-bors[bot]@users.noreply.github.com> BoxyUwU BoxyUwU Braden Nelson From 92db7b2b5ab89a37a2d7bdd9c8a25fd8be31e303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 14 Jan 2026 02:22:54 +0000 Subject: [PATCH 0711/1061] Recover parse gracefully from `` When a const param doesn't have a `: Type`, recover the parser state and provide a structured suggestion. This not only provides guidance on what was missing, but it also makes subsuequent errors to be emitted that would otherwise be silenced. ``` error: expected `:`, found `>` --> $DIR/incorrect-const-param.rs:26:16 | LL | impl From<[T; N]> for VecWrapper | ^ expected `:` | help: you might have meant to write the type of the const parameter here | LL | impl From<[T; N]> for VecWrapper | ++++++++++++ ``` --- compiler/rustc_parse/src/parser/generics.rs | 26 ++++++- .../const-generics/incorrect-const-param.rs | 45 ++++++++++++ .../incorrect-const-param.stderr | 70 +++++++++++++++++++ 3 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 tests/ui/const-generics/incorrect-const-param.rs create mode 100644 tests/ui/const-generics/incorrect-const-param.stderr diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 2c76c0fe3583..ef6c9cc344ce 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -109,7 +109,31 @@ impl<'a> Parser<'a> { self.expect_keyword(exp!(Const))?; let ident = self.parse_ident()?; - self.expect(exp!(Colon))?; + if let Err(mut err) = self.expect(exp!(Colon)) { + return if self.token.kind == token::Comma || self.token.kind == token::Gt { + // Recover parse from `` where the type is missing. + let span = const_span.to(ident.span); + err.span_suggestion_verbose( + ident.span.shrink_to_hi(), + "you likely meant to write the type of the const parameter here", + ": /* Type */".to_string(), + Applicability::HasPlaceholders, + ); + let kind = TyKind::Err(err.emit()); + let ty = self.mk_ty(span, kind); + Ok(GenericParam { + ident, + id: ast::DUMMY_NODE_ID, + attrs: preceding_attrs, + bounds: Vec::new(), + kind: GenericParamKind::Const { ty, span, default: None }, + is_placeholder: false, + colon_span: None, + }) + } else { + Err(err) + }; + } let ty = self.parse_ty()?; // Parse optional const generics default value. diff --git a/tests/ui/const-generics/incorrect-const-param.rs b/tests/ui/const-generics/incorrect-const-param.rs new file mode 100644 index 000000000000..5f1d8ca2ae99 --- /dev/null +++ b/tests/ui/const-generics/incorrect-const-param.rs @@ -0,0 +1,45 @@ +// #84327 + +struct VecWrapper(Vec); + +// Correct +impl From<[T; N]> for VecWrapper +where + T: Clone, +{ + fn from(slice: [T; N]) -> Self { + VecWrapper(slice.to_vec()) + } +} + +// Forgot const +impl From<[T; N]> for VecWrapper //~ ERROR expected value, found type parameter `N` +where //~^ ERROR expected trait, found builtin type `usize` + T: Clone, +{ + fn from(slice: [T; N]) -> Self { //~ ERROR expected value, found type parameter `N` + VecWrapper(slice.to_vec()) + } +} + +// Forgot type +impl From<[T; N]> for VecWrapper //~ ERROR expected `:`, found `>` +where + T: Clone, +{ + fn from(slice: [T; N]) -> Self { + VecWrapper(slice.to_vec()) + } +} + +// Forgot const and type +impl From<[T; N]> for VecWrapper //~ ERROR expected value, found type parameter `N` +where + T: Clone, +{ + fn from(slice: [T; N]) -> Self { //~ ERROR expected value, found type parameter `N` + VecWrapper(slice.to_vec()) + } +} + +fn main() {} diff --git a/tests/ui/const-generics/incorrect-const-param.stderr b/tests/ui/const-generics/incorrect-const-param.stderr new file mode 100644 index 000000000000..c5cf54500ee0 --- /dev/null +++ b/tests/ui/const-generics/incorrect-const-param.stderr @@ -0,0 +1,70 @@ +error: expected `:`, found `>` + --> $DIR/incorrect-const-param.rs:26:16 + | +LL | impl From<[T; N]> for VecWrapper + | ^ expected `:` + | +help: you likely meant to write the type of the const parameter here + | +LL | impl From<[T; N]> for VecWrapper + | ++++++++++++ + +error[E0423]: expected value, found type parameter `N` + --> $DIR/incorrect-const-param.rs:16:28 + | +LL | impl From<[T; N]> for VecWrapper + | - ^ not a value + | | + | found this type parameter + +error[E0404]: expected trait, found builtin type `usize` + --> $DIR/incorrect-const-param.rs:16:12 + | +LL | impl From<[T; N]> for VecWrapper + | ^^^^^ not a trait + | +help: you might have meant to write a const parameter here + | +LL | impl From<[T; N]> for VecWrapper + | +++++ + +error[E0423]: expected value, found type parameter `N` + --> $DIR/incorrect-const-param.rs:20:24 + | +LL | impl From<[T; N]> for VecWrapper + | - found this type parameter +... +LL | fn from(slice: [T; N]) -> Self { + | ^ not a value + +error[E0423]: expected value, found type parameter `N` + --> $DIR/incorrect-const-param.rs:36:21 + | +LL | impl From<[T; N]> for VecWrapper + | - ^ not a value + | | + | found this type parameter + | +help: you might have meant to write a const parameter here + | +LL | impl From<[T; N]> for VecWrapper + | +++++ ++++++++++++ + +error[E0423]: expected value, found type parameter `N` + --> $DIR/incorrect-const-param.rs:40:24 + | +LL | impl From<[T; N]> for VecWrapper + | - found this type parameter +... +LL | fn from(slice: [T; N]) -> Self { + | ^ not a value + | +help: you might have meant to write a const parameter here + | +LL | impl From<[T; N]> for VecWrapper + | +++++ ++++++++++++ + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0404, E0423. +For more information about an error, try `rustc --explain E0404`. From 79ec275e2d513d5f1b8a685a20476b9b700674fe Mon Sep 17 00:00:00 2001 From: Asuna Date: Wed, 14 Jan 2026 17:00:22 +0100 Subject: [PATCH 0712/1061] Support primitives in type info reflection Support {bool,char,int,uint,float,str} primitive types for feature `type_info` reflection. --- .../src/const_eval/type_info.rs | 84 +++++++- compiler/rustc_span/src/symbol.rs | 8 +- library/core/src/mem/type_info.rs | 75 ++++++- library/coretests/tests/mem/type_info.rs | 39 +++- .../const_prop/invalid_constant.main.GVN.diff | 2 +- .../invalid_constant.main.RemoveZsts.diff | 2 +- tests/ui/lint/recommend-literal.rs | 2 + tests/ui/lint/recommend-literal.stderr | 22 ++- tests/ui/reflection/dump.bit32.run.stdout | 186 ++++++++++++++++++ tests/ui/reflection/dump.bit64.run.stdout | 186 ++++++++++++++++++ tests/ui/reflection/dump.rs | 33 ++-- tests/ui/reflection/dump.run.stdout | 31 --- ...stion-when-stmt-and-expr-span-equal.stderr | 4 +- tests/ui/traits/issue-77982.stderr | 2 +- tests/ui/try-trait/bad-interconversion.stderr | 2 +- 15 files changed, 612 insertions(+), 66 deletions(-) create mode 100644 tests/ui/reflection/dump.bit32.run.stdout create mode 100644 tests/ui/reflection/dump.bit64.run.stdout delete mode 100644 tests/ui/reflection/dump.run.stdout diff --git a/compiler/rustc_const_eval/src/const_eval/type_info.rs b/compiler/rustc_const_eval/src/const_eval/type_info.rs index 814c81278a10..fc3378275be2 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -35,6 +35,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { interp_ok((variant_id, self.project_downcast(&field_dest, variant_id)?)) }; + let ptr_bit_width = || self.tcx.data_layout.pointer_size().bits(); match field.name { sym::kind => { let variant_index = match ty.kind() { @@ -64,13 +65,60 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { variant } - // For now just merge all primitives into one `Leaf` variant with no data - ty::Uint(_) | ty::Int(_) | ty::Float(_) | ty::Char | ty::Bool => { - downcast(sym::Leaf)?.0 + ty::Bool => { + let (variant, variant_place) = downcast(sym::Bool)?; + let place = self.project_field(&variant_place, FieldIdx::ZERO)?; + self.write_primitive_type_info(place, ty, None)?; + variant + } + ty::Char => { + let (variant, variant_place) = downcast(sym::Char)?; + let place = self.project_field(&variant_place, FieldIdx::ZERO)?; + self.write_primitive_type_info(place, ty, None)?; + variant + } + ty::Int(int_ty) => { + let (variant, variant_place) = downcast(sym::Int)?; + let place = self.project_field(&variant_place, FieldIdx::ZERO)?; + self.write_primitive_type_info( + place, + ty, + Some( + int_ty + .bit_width() + .unwrap_or_else(/* isize */ ptr_bit_width), + ), + )?; + variant + } + ty::Uint(uint_ty) => { + let (variant, variant_place) = downcast(sym::Uint)?; + let place = self.project_field(&variant_place, FieldIdx::ZERO)?; + self.write_primitive_type_info( + place, + ty, + Some( + uint_ty + .bit_width() + .unwrap_or_else(/* usize */ ptr_bit_width), + ), + )?; + variant + } + ty::Float(float_ty) => { + let (variant, variant_place) = downcast(sym::Float)?; + let place = self.project_field(&variant_place, FieldIdx::ZERO)?; + self.write_primitive_type_info(place, ty, Some(float_ty.bit_width()))?; + variant + } + ty::Str => { + let (variant, variant_place) = downcast(sym::Str)?; + let place = self.project_field(&variant_place, FieldIdx::ZERO)?; + self.write_primitive_type_info(place, ty, None)?; + variant } ty::Adt(_, _) | ty::Foreign(_) - | ty::Str | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(..) @@ -203,4 +251,32 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { interp_ok(()) } + + // This method always writes to field `ty`. + // If field `bit_width` is present, it also writes to it (in which case parameter `write_bit_width` must be `Some`). + fn write_primitive_type_info( + &mut self, + place: impl Writeable<'tcx, CtfeProvenance>, + ty: Ty<'tcx>, + write_bit_width: Option, + ) -> InterpResult<'tcx> { + for (field_idx, field) in + place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated() + { + let field_place = self.project_field(&place, field_idx)?; + match field.name { + sym::ty => self.write_type_id(ty, &field_place)?, + sym::bit_width => { + let bit_width = write_bit_width + .expect("type info struct needs a `bit_width` but none was provided"); + self.write_scalar( + ScalarInt::try_from_target_usize(bit_width, self.tcx.tcx).unwrap(), + &field_place, + )? + } + other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"), + } + } + interp_ok(()) + } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 34804160ed39..4c19fa83fd3a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -190,6 +190,7 @@ symbols! { BTreeMap, BTreeSet, BinaryHeap, + Bool, Borrow, BorrowMut, Break, @@ -202,6 +203,7 @@ symbols! { Capture, Cell, Center, + Char, Child, Cleanup, Clone, @@ -238,6 +240,7 @@ symbols! { Error, File, FileType, + Float, FmtArgumentsNew, FmtWrite, Fn, @@ -263,6 +266,7 @@ symbols! { IndexOutput, Input, Instant, + Int, Into, IntoFuture, IntoIterator, @@ -285,7 +289,6 @@ symbols! { IteratorItem, IteratorMap, Layout, - Leaf, Left, LinkedList, LintDiagnostic, @@ -363,6 +366,7 @@ symbols! { Some, SpanCtxt, Stdin, + Str, String, StructuralPartialEq, SubdiagMessage, @@ -387,6 +391,7 @@ symbols! { Ty, TyCtxt, TyKind, + Uint, Unknown, Unsize, UnsizedConstParamTy, @@ -584,6 +589,7 @@ symbols! { binaryheap_iter, bind_by_move_pattern_guards, bindings_after_at, + bit_width, bitand, bitand_assign, bitor, diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index e4ccc408f1c6..7db4f3b00123 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -45,9 +45,18 @@ pub enum TypeKind { Tuple(Tuple), /// Arrays. Array(Array), - /// Primitives - /// FIXME(#146922): disambiguate further - Leaf, + /// Primitive boolean type. + Bool(Bool), + /// Primitive character type. + Char(Char), + /// Primitive signed integer type. + Int(Int), + /// Primitive unsigned integer type. + Uint(Uint), + /// Primitive floating-point type. + Float(Float), + /// String slice type. + Str(Str), /// FIXME(#146922): add all the common types Other, } @@ -82,3 +91,63 @@ pub struct Array { /// The length of the array. pub len: usize, } + +/// Compile-time type information about `bool`. +#[derive(Debug)] +#[non_exhaustive] +#[unstable(feature = "type_info", issue = "146922")] +pub struct Bool { + /// The type id of `bool`. + pub ty: TypeId, +} + +/// Compile-time type information about `char`. +#[derive(Debug)] +#[non_exhaustive] +#[unstable(feature = "type_info", issue = "146922")] +pub struct Char { + /// The type id of `char`. + pub ty: TypeId, +} + +/// Compile-time type information about signed integer types. +#[derive(Debug)] +#[non_exhaustive] +#[unstable(feature = "type_info", issue = "146922")] +pub struct Int { + /// The type id of signed integer type. + pub ty: TypeId, + /// The bit width of the signed integer type. + pub bit_width: usize, +} + +/// Compile-time type information about unsigned integer types. +#[derive(Debug)] +#[non_exhaustive] +#[unstable(feature = "type_info", issue = "146922")] +pub struct Uint { + /// The type id of unsigned integer type. + pub ty: TypeId, + /// The bit width of the unsigned integer type. + pub bit_width: usize, +} + +/// Compile-time type information about floating-point types. +#[derive(Debug)] +#[non_exhaustive] +#[unstable(feature = "type_info", issue = "146922")] +pub struct Float { + /// The type id of floating-point type. + pub ty: TypeId, + /// The bit width of the floating-point type. + pub bit_width: usize, +} + +/// Compile-time type information about string slice types. +#[derive(Debug)] +#[non_exhaustive] +#[unstable(feature = "type_info", issue = "146922")] +pub struct Str { + /// The type id of `str`. + pub ty: TypeId, +} diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs index b3b8d96d49b0..5dd8f4034d11 100644 --- a/library/coretests/tests/mem/type_info.rs +++ b/library/coretests/tests/mem/type_info.rs @@ -46,7 +46,10 @@ fn test_tuples() { assert!(b.offset == 1); match (a.ty.info().kind, b.ty.info().kind) { - (TypeKind::Leaf, TypeKind::Leaf) => {} + (TypeKind::Uint(a), TypeKind::Uint(b)) => { + assert!(a.bit_width == 8); + assert!(b.bit_width == 8); + } _ => unreachable!(), } } @@ -54,3 +57,37 @@ fn test_tuples() { } } } + +#[test] +fn test_primitives() { + use TypeKind::*; + + let Type { kind: Bool(_ty), size, .. } = (const { Type::of::() }) else { panic!() }; + assert_eq!(size, Some(1)); + + let Type { kind: Char(_ty), size, .. } = (const { Type::of::() }) else { panic!() }; + assert_eq!(size, Some(4)); + + let Type { kind: Int(ty), size, .. } = (const { Type::of::() }) else { panic!() }; + assert_eq!(size, Some(4)); + assert_eq!(ty.bit_width, 32); + + let Type { kind: Int(ty), size, .. } = (const { Type::of::() }) else { panic!() }; + assert_eq!(size, Some(size_of::())); + assert_eq!(ty.bit_width, size_of::() * 8); + + let Type { kind: Uint(ty), size, .. } = (const { Type::of::() }) else { panic!() }; + assert_eq!(size, Some(4)); + assert_eq!(ty.bit_width, 32); + + let Type { kind: Uint(ty), size, .. } = (const { Type::of::() }) else { panic!() }; + assert_eq!(size, Some(size_of::())); + assert_eq!(ty.bit_width, size_of::() * 8); + + let Type { kind: Float(ty), size, .. } = (const { Type::of::() }) else { panic!() }; + assert_eq!(size, Some(4)); + assert_eq!(ty.bit_width, 32); + + let Type { kind: Str(_ty), size, .. } = (const { Type::of::() }) else { panic!() }; + assert_eq!(size, None); +} diff --git a/tests/mir-opt/const_prop/invalid_constant.main.GVN.diff b/tests/mir-opt/const_prop/invalid_constant.main.GVN.diff index 20923d0352cd..3dc6fc9e3f65 100644 --- a/tests/mir-opt/const_prop/invalid_constant.main.GVN.diff +++ b/tests/mir-opt/const_prop/invalid_constant.main.GVN.diff @@ -19,7 +19,7 @@ debug _enum_without_variants => const [ZeroSized: Empty]; let _9: main::Str<"���">; scope 4 { - debug _non_utf8_str => const Str::<"���">; + debug _non_utf8_str => const main::Str::<"���">; } } } diff --git a/tests/mir-opt/const_prop/invalid_constant.main.RemoveZsts.diff b/tests/mir-opt/const_prop/invalid_constant.main.RemoveZsts.diff index 6593b329756c..c16cbaf4c0f2 100644 --- a/tests/mir-opt/const_prop/invalid_constant.main.RemoveZsts.diff +++ b/tests/mir-opt/const_prop/invalid_constant.main.RemoveZsts.diff @@ -21,7 +21,7 @@ let _9: main::Str<"���">; scope 4 { - debug _non_utf8_str => _9; -+ debug _non_utf8_str => const Str::<"���">; ++ debug _non_utf8_str => const main::Str::<"���">; } } } diff --git a/tests/ui/lint/recommend-literal.rs b/tests/ui/lint/recommend-literal.rs index 45f9ae0a7bdf..be074c111453 100644 --- a/tests/ui/lint/recommend-literal.rs +++ b/tests/ui/lint/recommend-literal.rs @@ -1,3 +1,5 @@ +//~vv HELP consider importing this struct + type Real = double; //~^ ERROR cannot find type `double` in this scope //~| HELP perhaps you intended to use this type diff --git a/tests/ui/lint/recommend-literal.stderr b/tests/ui/lint/recommend-literal.stderr index 6b6dd134e1d2..01e993df17a9 100644 --- a/tests/ui/lint/recommend-literal.stderr +++ b/tests/ui/lint/recommend-literal.stderr @@ -1,5 +1,5 @@ error[E0425]: cannot find type `double` in this scope - --> $DIR/recommend-literal.rs:1:13 + --> $DIR/recommend-literal.rs:3:13 | LL | type Real = double; | ^^^^^^ @@ -8,7 +8,7 @@ LL | type Real = double; | help: perhaps you intended to use this type: `f64` error[E0425]: cannot find type `long` in this scope - --> $DIR/recommend-literal.rs:7:12 + --> $DIR/recommend-literal.rs:9:12 | LL | let y: long = 74802374902374923; | ^^^^ @@ -17,7 +17,7 @@ LL | let y: long = 74802374902374923; | help: perhaps you intended to use this type: `i64` error[E0425]: cannot find type `Boolean` in this scope - --> $DIR/recommend-literal.rs:10:13 + --> $DIR/recommend-literal.rs:12:13 | LL | let v1: Boolean = true; | ^^^^^^^ @@ -26,7 +26,7 @@ LL | let v1: Boolean = true; | help: perhaps you intended to use this type: `bool` error[E0425]: cannot find type `Bool` in this scope - --> $DIR/recommend-literal.rs:13:13 + --> $DIR/recommend-literal.rs:15:13 | LL | let v2: Bool = true; | ^^^^ @@ -41,9 +41,13 @@ help: perhaps you intended to use this type LL - let v2: Bool = true; LL + let v2: bool = true; | +help: consider importing this struct + | +LL + use std::mem::type_info::Bool; + | error[E0425]: cannot find type `boolean` in this scope - --> $DIR/recommend-literal.rs:19:9 + --> $DIR/recommend-literal.rs:21:9 | LL | fn z(a: boolean) { | ^^^^^^^ @@ -52,7 +56,7 @@ LL | fn z(a: boolean) { | help: perhaps you intended to use this type: `bool` error[E0425]: cannot find type `byte` in this scope - --> $DIR/recommend-literal.rs:24:11 + --> $DIR/recommend-literal.rs:26:11 | LL | fn a() -> byte { | ^^^^ @@ -61,7 +65,7 @@ LL | fn a() -> byte { | help: perhaps you intended to use this type: `u8` error[E0425]: cannot find type `float` in this scope - --> $DIR/recommend-literal.rs:31:12 + --> $DIR/recommend-literal.rs:33:12 | LL | width: float, | ^^^^^ @@ -70,7 +74,7 @@ LL | width: float, | help: perhaps you intended to use this type: `f32` error[E0425]: cannot find type `int` in this scope - --> $DIR/recommend-literal.rs:34:19 + --> $DIR/recommend-literal.rs:36:19 | LL | depth: Option, | ^^^ not found in this scope @@ -86,7 +90,7 @@ LL | struct Data { | +++++ error[E0425]: cannot find type `short` in this scope - --> $DIR/recommend-literal.rs:40:16 + --> $DIR/recommend-literal.rs:42:16 | LL | impl Stuff for short {} | ^^^^^ diff --git a/tests/ui/reflection/dump.bit32.run.stdout b/tests/ui/reflection/dump.bit32.run.stdout new file mode 100644 index 000000000000..d747ee210204 --- /dev/null +++ b/tests/ui/reflection/dump.bit32.run.stdout @@ -0,0 +1,186 @@ +Type { + kind: Tuple( + Tuple { + fields: [ + Field { + ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), + offset: 0, + }, + Field { + ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), + offset: 1, + }, + Field { + ty: TypeId(0x41223169ff28813ba79b7268a2a968d9), + offset: 2, + }, + ], + }, + ), + size: Some( + 2, + ), +} +Type { + kind: Array( + Array { + element_ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), + len: 2, + }, + ), + size: Some( + 2, + ), +} +Type { + kind: Int( + Int { + ty: TypeId(0x12427c993eca190c841e0d92c5b7a45d), + bit_width: 8, + }, + ), + size: Some( + 1, + ), +} +Type { + kind: Int( + Int { + ty: TypeId(0x56ced5e4a15bd89050bb9674fa2df013), + bit_width: 32, + }, + ), + size: Some( + 4, + ), +} +Type { + kind: Int( + Int { + ty: TypeId(0xae6c4318bb07632e00428affbea41961), + bit_width: 64, + }, + ), + size: Some( + 8, + ), +} +Type { + kind: Int( + Int { + ty: TypeId(0xc7164498f3902dde0d8194a7b9733e79), + bit_width: 128, + }, + ), + size: Some( + 16, + ), +} +Type { + kind: Int( + Int { + ty: TypeId(0x1e5f92831c560aac8658b980a22e60b0), + bit_width: 32, + }, + ), + size: Some( + 4, + ), +} +Type { + kind: Uint( + Uint { + ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), + bit_width: 8, + }, + ), + size: Some( + 1, + ), +} +Type { + kind: Uint( + Uint { + ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), + bit_width: 32, + }, + ), + size: Some( + 4, + ), +} +Type { + kind: Uint( + Uint { + ty: TypeId(0x9ed91be891e304132cb86891e578f4a5), + bit_width: 64, + }, + ), + size: Some( + 8, + ), +} +Type { + kind: Uint( + Uint { + ty: TypeId(0x7bf7411d57d603e9fb393892a9c3f362), + bit_width: 128, + }, + ), + size: Some( + 16, + ), +} +Type { + kind: Uint( + Uint { + ty: TypeId(0x763d199bccd319899208909ed1a860c6), + bit_width: 32, + }, + ), + size: Some( + 4, + ), +} +Type { + kind: Other, + size: Some( + 4, + ), +} +Type { + kind: Other, + size: Some( + 12, + ), +} +Type { + kind: Other, + size: Some( + 8, + ), +} +Type { + kind: Other, + size: Some( + 8, + ), +} +Type { + kind: Other, + size: Some( + 8, + ), +} +Type { + kind: Str( + Str { + ty: TypeId(0x474ccf3b5db264ef53916706f7d7bb2c), + }, + ), + size: None, +} +Type { + kind: Other, + size: None, +} diff --git a/tests/ui/reflection/dump.bit64.run.stdout b/tests/ui/reflection/dump.bit64.run.stdout new file mode 100644 index 000000000000..180a6e2882d7 --- /dev/null +++ b/tests/ui/reflection/dump.bit64.run.stdout @@ -0,0 +1,186 @@ +Type { + kind: Tuple( + Tuple { + fields: [ + Field { + ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), + offset: 0, + }, + Field { + ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), + offset: 1, + }, + Field { + ty: TypeId(0x41223169ff28813ba79b7268a2a968d9), + offset: 2, + }, + ], + }, + ), + size: Some( + 2, + ), +} +Type { + kind: Array( + Array { + element_ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), + len: 2, + }, + ), + size: Some( + 2, + ), +} +Type { + kind: Int( + Int { + ty: TypeId(0x12427c993eca190c841e0d92c5b7a45d), + bit_width: 8, + }, + ), + size: Some( + 1, + ), +} +Type { + kind: Int( + Int { + ty: TypeId(0x56ced5e4a15bd89050bb9674fa2df013), + bit_width: 32, + }, + ), + size: Some( + 4, + ), +} +Type { + kind: Int( + Int { + ty: TypeId(0xae6c4318bb07632e00428affbea41961), + bit_width: 64, + }, + ), + size: Some( + 8, + ), +} +Type { + kind: Int( + Int { + ty: TypeId(0xc7164498f3902dde0d8194a7b9733e79), + bit_width: 128, + }, + ), + size: Some( + 16, + ), +} +Type { + kind: Int( + Int { + ty: TypeId(0x1e5f92831c560aac8658b980a22e60b0), + bit_width: 64, + }, + ), + size: Some( + 8, + ), +} +Type { + kind: Uint( + Uint { + ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), + bit_width: 8, + }, + ), + size: Some( + 1, + ), +} +Type { + kind: Uint( + Uint { + ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), + bit_width: 32, + }, + ), + size: Some( + 4, + ), +} +Type { + kind: Uint( + Uint { + ty: TypeId(0x9ed91be891e304132cb86891e578f4a5), + bit_width: 64, + }, + ), + size: Some( + 8, + ), +} +Type { + kind: Uint( + Uint { + ty: TypeId(0x7bf7411d57d603e9fb393892a9c3f362), + bit_width: 128, + }, + ), + size: Some( + 16, + ), +} +Type { + kind: Uint( + Uint { + ty: TypeId(0x763d199bccd319899208909ed1a860c6), + bit_width: 64, + }, + ), + size: Some( + 8, + ), +} +Type { + kind: Other, + size: Some( + 4, + ), +} +Type { + kind: Other, + size: Some( + 24, + ), +} +Type { + kind: Other, + size: Some( + 16, + ), +} +Type { + kind: Other, + size: Some( + 16, + ), +} +Type { + kind: Other, + size: Some( + 16, + ), +} +Type { + kind: Str( + Str { + ty: TypeId(0x474ccf3b5db264ef53916706f7d7bb2c), + }, + ), + size: None, +} +Type { + kind: Other, + size: None, +} diff --git a/tests/ui/reflection/dump.rs b/tests/ui/reflection/dump.rs index 0adcda481b5a..584b7c8ed4ae 100644 --- a/tests/ui/reflection/dump.rs +++ b/tests/ui/reflection/dump.rs @@ -1,6 +1,11 @@ -#![feature(type_info)] +// Some types whose length depends on the target pointer length will be dumped. +//@ revisions: bit32 bit64 +//@[bit32] only-32bit +//@[bit64] only-64bit //@ run-pass //@ check-run-results + +#![feature(type_info)] #![allow(dead_code)] use std::mem::type_info::Type; @@ -20,14 +25,20 @@ struct Unsized { s: str, } -fn main() { - println!("{:#?}", const { Type::of::<(u8, u8, ())>() }.kind); - println!("{:#?}", const { Type::of::<[u8; 2]>() }.kind); - println!("{:#?}", const { Type::of::() }.kind); - println!("{:#?}", const { Type::of::() }.kind); - println!("{:#?}", const { Type::of::<&Unsized>() }.kind); - println!("{:#?}", const { Type::of::<&str>() }.kind); - println!("{:#?}", const { Type::of::<&[u8]>() }.kind); - println!("{:#?}", const { Type::of::() }.kind); - println!("{:#?}", const { Type::of::<[u8]>() }.kind); +macro_rules! dump_types { + ($($ty:ty),+ $(,)?) => { + $(println!("{:#?}", const { Type::of::<$ty>() });)+ + }; +} + +fn main() { + dump_types! { + (u8, u8, ()), + [u8; 2], + i8, i32, i64, i128, isize, + u8, u32, u64, u128, usize, + Foo, Bar, + &Unsized, &str, &[u8], + str, [u8], + } } diff --git a/tests/ui/reflection/dump.run.stdout b/tests/ui/reflection/dump.run.stdout deleted file mode 100644 index dfd128664e2d..000000000000 --- a/tests/ui/reflection/dump.run.stdout +++ /dev/null @@ -1,31 +0,0 @@ -Tuple( - Tuple { - fields: [ - Field { - ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), - offset: 0, - }, - Field { - ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), - offset: 1, - }, - Field { - ty: TypeId(0x41223169ff28813ba79b7268a2a968d9), - offset: 2, - }, - ], - }, -) -Array( - Array { - element_ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), - len: 2, - }, -) -Other -Other -Other -Other -Other -Other -Other diff --git a/tests/ui/suggestions/semi-suggestion-when-stmt-and-expr-span-equal.stderr b/tests/ui/suggestions/semi-suggestion-when-stmt-and-expr-span-equal.stderr index aa96159aacf5..9f34d2747881 100644 --- a/tests/ui/suggestions/semi-suggestion-when-stmt-and-expr-span-equal.stderr +++ b/tests/ui/suggestions/semi-suggestion-when-stmt-and-expr-span-equal.stderr @@ -21,14 +21,14 @@ LL | .collect::(); | = help: the trait `FromIterator<()>` is not implemented for `String` = help: the following other types implement trait `FromIterator`: - `String` implements `FromIterator<&Char>` `String` implements `FromIterator<&char>` + `String` implements `FromIterator<&std::ascii::Char>` `String` implements `FromIterator<&str>` `String` implements `FromIterator>` - `String` implements `FromIterator` `String` implements `FromIterator>` `String` implements `FromIterator` `String` implements `FromIterator` + `String` implements `FromIterator` note: the method call chain might not have had the expected associated types --> $DIR/semi-suggestion-when-stmt-and-expr-span-equal.rs:20:10 | diff --git a/tests/ui/traits/issue-77982.stderr b/tests/ui/traits/issue-77982.stderr index 4bc24e81215a..b1baabc4394b 100644 --- a/tests/ui/traits/issue-77982.stderr +++ b/tests/ui/traits/issue-77982.stderr @@ -44,10 +44,10 @@ LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(0u32.into())).collect( | type must be known at this point | = note: multiple `impl`s satisfying `u32: From<_>` found in the `core` crate: - - impl From for u32; - impl From for u32; - impl From for u32; - impl From for u32; + - impl From for u32; - impl From for u32; - impl From for u32; help: try using a fully qualified path to specify the expected types diff --git a/tests/ui/try-trait/bad-interconversion.stderr b/tests/ui/try-trait/bad-interconversion.stderr index 61fecaf89917..f8c0deba99ba 100644 --- a/tests/ui/try-trait/bad-interconversion.stderr +++ b/tests/ui/try-trait/bad-interconversion.stderr @@ -18,7 +18,7 @@ help: the following other types implement trait `From` = note: in this macro invocation --> $SRC_DIR/core/src/ascii/ascii_char.rs:LL:COL | - = note: `u8` implements `From` + = note: `u8` implements `From` ::: $SRC_DIR/core/src/ascii/ascii_char.rs:LL:COL | = note: in this macro invocation From 1028c7a66a718a6421241b3a46268681f79fd597 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maja=20K=C4=85dzio=C5=82ka?= Date: Sun, 11 Jan 2026 20:10:22 +0100 Subject: [PATCH 0713/1061] Avoid ICEs after bad patterns, for the other syntactic variants --- compiler/rustc_hir_typeck/src/pat.rs | 13 +++--- tests/ui/pattern/type_mismatch.rs | 63 ++++++++++++++++++++++++++- tests/ui/pattern/type_mismatch.stderr | 61 +++++++++++++++++++++++++- 3 files changed, 128 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 90e22b2cd381..b56ab6dcb4ab 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1512,11 +1512,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat_info: PatInfo<'tcx>, ) -> Ty<'tcx> { // Type-check the path. - let _ = self.demand_eqtype_pat(pat.span, expected, pat_ty, &pat_info.top_info); + let had_err = self.demand_eqtype_pat(pat.span, expected, pat_ty, &pat_info.top_info); // Type-check subpatterns. match self.check_struct_pat_fields(pat_ty, pat, variant, fields, has_rest_pat, pat_info) { - Ok(()) => pat_ty, + Ok(()) => match had_err { + Ok(()) => pat_ty, + Err(guar) => Ty::new_error(self.tcx, guar), + }, Err(guar) => Ty::new_error(self.tcx, guar), } } @@ -1764,8 +1767,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Type-check the tuple struct pattern against the expected type. - let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, &pat_info.top_info); - let had_err = diag.map_err(|diag| diag.emit()); + let had_err = self.demand_eqtype_pat(pat.span, expected, pat_ty, &pat_info.top_info); // Type-check subpatterns. if subpats.len() == variant.fields.len() @@ -1989,11 +1991,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Err(reported) = self.demand_eqtype_pat(span, expected, pat_ty, &pat_info.top_info) { // Walk subpatterns with an expected type of `err` in this case to silence // further errors being emitted when using the bindings. #50333 - let element_tys_iter = (0..max_len).map(|_| Ty::new_error(tcx, reported)); for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { self.check_pat(elem, Ty::new_error(tcx, reported), pat_info); } - Ty::new_tup_from_iter(tcx, element_tys_iter) + Ty::new_error(tcx, reported) } else { for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { self.check_pat(elem, element_tys[i], pat_info); diff --git a/tests/ui/pattern/type_mismatch.rs b/tests/ui/pattern/type_mismatch.rs index 408ff7588471..39d57301e98f 100644 --- a/tests/ui/pattern/type_mismatch.rs +++ b/tests/ui/pattern/type_mismatch.rs @@ -1,4 +1,4 @@ -//! This test used to ICE: rust-lang/rust#109812 +//! These tests used to ICE: rust-lang/rust#109812, rust-lang/rust#150507 //! Instead of actually analyzing the erroneous patterns, //! we instead stop after typeck where errors are already //! reported. @@ -8,12 +8,21 @@ enum Either { One(X), Two(X), + Three { a: X }, } struct X(Y); struct Y; +struct Z(*const i32); +unsafe impl Send for Z {} + +enum Meow { + A { a: Z }, + B(Z), +} + fn consume_fnmut(_: impl FnMut()) {} fn move_into_fnmut() { @@ -25,6 +34,58 @@ fn move_into_fnmut() { let X(mut _t) = x; }); + + consume_fnmut(|| { + let Either::Three { a: ref mut _t } = x; + //~^ ERROR: mismatched types + + let X(mut _t) = x; + }); +} + +fn tuple_against_array() { + let variant: [();1] = [()]; + + || match variant { + (2,) => (), + //~^ ERROR: mismatched types + _ => {} + }; + + || { + let ((2,) | _) = variant; + //~^ ERROR: mismatched types + }; +} + +// Reproducer that triggers the compatibility lint more reliably, instead of relying on the fact +// that at the time of writing, an unresolved integer type variable does not implement any +// auto-traits. +// +// The @_ makes this example also reproduce ICE #150507 before PR #138961 +fn arcane() { + let variant: [();1] = [()]; + + || { + match variant { + (Z(y@_),) => {} + //~^ ERROR: mismatched types + } + }; + + || { + match variant { + Meow::A { a: Z(y@_) } => {} + //~^ ERROR: mismatched types + } + }; + + || { + match variant { + Meow::B(Z(y@_)) => {} + //~^ ERROR: mismatched types + } + }; } fn main() {} diff --git a/tests/ui/pattern/type_mismatch.stderr b/tests/ui/pattern/type_mismatch.stderr index b0441b1fadcf..3f24b2e70694 100644 --- a/tests/ui/pattern/type_mismatch.stderr +++ b/tests/ui/pattern/type_mismatch.stderr @@ -1,11 +1,68 @@ error[E0308]: mismatched types - --> $DIR/type_mismatch.rs:23:13 + --> $DIR/type_mismatch.rs:32:13 | LL | let Either::Two(ref mut _t) = x; | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `X` | | | expected `X`, found `Either` -error: aborting due to 1 previous error +error[E0308]: mismatched types + --> $DIR/type_mismatch.rs:39:13 + | +LL | let Either::Three { a: ref mut _t } = x; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `X` + | | + | expected `X`, found `Either` + +error[E0308]: mismatched types + --> $DIR/type_mismatch.rs:50:9 + | +LL | || match variant { + | ------- this expression has type `[(); 1]` +LL | (2,) => (), + | ^^^^ expected `[(); 1]`, found `(_,)` + | + = note: expected array `[(); 1]` + found tuple `(_,)` + +error[E0308]: mismatched types + --> $DIR/type_mismatch.rs:56:14 + | +LL | let ((2,) | _) = variant; + | ^^^^ ------- this expression has type `[(); 1]` + | | + | expected `[(); 1]`, found `(_,)` + | + = note: expected array `[(); 1]` + found tuple `(_,)` + +error[E0308]: mismatched types + --> $DIR/type_mismatch.rs:71:13 + | +LL | match variant { + | ------- this expression has type `[(); 1]` +LL | (Z(y@_),) => {} + | ^^^^^^^^^ expected `[(); 1]`, found `(_,)` + | + = note: expected array `[(); 1]` + found tuple `(_,)` + +error[E0308]: mismatched types + --> $DIR/type_mismatch.rs:78:13 + | +LL | match variant { + | ------- this expression has type `[(); 1]` +LL | Meow::A { a: Z(y@_) } => {} + | ^^^^^^^^^^^^^^^^^^^^^ expected `[(); 1]`, found `Meow` + +error[E0308]: mismatched types + --> $DIR/type_mismatch.rs:85:13 + | +LL | match variant { + | ------- this expression has type `[(); 1]` +LL | Meow::B(Z(y@_)) => {} + | ^^^^^^^^^^^^^^^ expected `[(); 1]`, found `Meow` + +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0308`. From 436fb87eeb833f8986ca520311e91f32ed0c32e2 Mon Sep 17 00:00:00 2001 From: Zijie Zhao Date: Wed, 14 Jan 2026 14:20:45 -0600 Subject: [PATCH 0714/1061] Rename `rust.use-lld` to `rust.bootstrap-override-lld` in INSTALL.md --- INSTALL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/INSTALL.md b/INSTALL.md index 98eb825cd10f..dd6c64b3df5f 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -97,7 +97,7 @@ See [the rustc-dev-guide for more info][sysllvm]. --set llvm.ninja=false \ --set rust.debug-assertions=false \ --set rust.jemalloc \ - --set rust.use-lld=true \ + --set rust.bootstrap-override-lld=true \ --set rust.lto=thin \ --set rust.codegen-units=1 ``` From ed7479c658484647858e08342a9aa00aa0fb5b30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 14 Jan 2026 21:47:24 +0100 Subject: [PATCH 0715/1061] Add the GCC codegen backend to build-manifest --- src/tools/build-manifest/src/main.rs | 3 ++- src/tools/build-manifest/src/versions.rs | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 4cec1b1f164b..7c0c528bcc04 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -32,7 +32,7 @@ static DOCS_FALLBACK: &[(&str, &str)] = &[ static PKG_INSTALLERS: &[&str] = &["x86_64-apple-darwin", "aarch64-apple-darwin"]; static NIGHTLY_ONLY_COMPONENTS: &[PkgType] = - &[PkgType::Miri, PkgType::JsonDocs, PkgType::RustcCodegenCranelift]; + &[PkgType::Miri, PkgType::JsonDocs, PkgType::RustcCodegenCranelift, PkgType::RustcCodegenGcc]; macro_rules! t { ($e:expr) => { @@ -302,6 +302,7 @@ impl Builder { | PkgType::RustAnalysis | PkgType::JsonDocs | PkgType::RustcCodegenCranelift + | PkgType::RustcCodegenGcc | PkgType::LlvmBitcodeLinker => { extensions.push(host_component(pkg)); } diff --git a/src/tools/build-manifest/src/versions.rs b/src/tools/build-manifest/src/versions.rs index 6ef8a0e83de3..1e55d1d467e6 100644 --- a/src/tools/build-manifest/src/versions.rs +++ b/src/tools/build-manifest/src/versions.rs @@ -59,6 +59,7 @@ pkg_type! { JsonDocs = "rust-docs-json"; preview = true, RustcCodegenCranelift = "rustc-codegen-cranelift"; preview = true, LlvmBitcodeLinker = "llvm-bitcode-linker"; preview = true, + RustcCodegenGcc = "rustc-codegen-gcc"; preview = true, } impl PkgType { @@ -82,6 +83,7 @@ impl PkgType { PkgType::LlvmTools => false, PkgType::Miri => false, PkgType::RustcCodegenCranelift => false, + PkgType::RustcCodegenGcc => false, PkgType::Rust => true, PkgType::RustStd => true, @@ -111,6 +113,7 @@ impl PkgType { RustcDocs => HOSTS, Cargo => HOSTS, RustcCodegenCranelift => HOSTS, + RustcCodegenGcc => HOSTS, RustMingw => MINGW, RustStd => TARGETS, HtmlDocs => HOSTS, From 4ceb13807e8062d5a4a3e9adecbd1d42a61eecf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 14 Jan 2026 21:49:44 +0100 Subject: [PATCH 0716/1061] Forbid distributing GCC on CI if `gcc.download-ci-gcc` is enabled --- src/bootstrap/src/core/build_steps/dist.rs | 10 +++++++++- src/bootstrap/src/core/config/mod.rs | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index cfcb144e0993..bfffc958f858 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -30,7 +30,7 @@ use crate::core::build_steps::tool::{ use crate::core::build_steps::vendor::{VENDOR_DIR, Vendor}; use crate::core::build_steps::{compile, llvm}; use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step, StepMetadata}; -use crate::core::config::TargetSelection; +use crate::core::config::{GccCiMode, TargetSelection}; use crate::utils::build_stamp::{self, BuildStamp}; use crate::utils::channel::{self, Info}; use crate::utils::exec::{BootstrapCommand, command}; @@ -3035,6 +3035,14 @@ impl Step for Gcc { return None; } + if builder.config.is_running_on_ci { + assert_eq!( + builder.config.gcc_ci_mode, + GccCiMode::BuildLocally, + "Cannot use gcc.download-ci-gcc when distributing GCC on CI" + ); + } + // We need the GCC sources to build GCC and also to add its license and README // files to the tarball builder.require_submodule( diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs index 007ed4aaba13..7651def62672 100644 --- a/src/bootstrap/src/core/config/mod.rs +++ b/src/bootstrap/src/core/config/mod.rs @@ -425,7 +425,7 @@ impl std::str::FromStr for RustcLto { } /// Determines how will GCC be provided. -#[derive(Default, Clone)] +#[derive(Default, Debug, Clone, PartialEq)] pub enum GccCiMode { /// Build GCC from the local `src/gcc` submodule. BuildLocally, From e4e2e8bd6f607e16c35c966f16a616daced632e7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 14 Jan 2026 16:37:01 +0100 Subject: [PATCH 0717/1061] Fix `deprecated` attribute intra-doc link not resolved in the right location on reexported item --- .../passes/collect_intra_doc_links.rs | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 07d6efaa97e1..8a37f46b9a96 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -7,7 +7,6 @@ use std::fmt::Display; use std::mem; use std::ops::Range; -use rustc_ast::attr::AttributeExt; use rustc_ast::util::comments::may_have_doc_links; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; @@ -1038,10 +1037,11 @@ fn preprocessed_markdown_links(s: &str) -> Vec { impl LinkCollector<'_, '_> { #[instrument(level = "debug", skip_all)] fn resolve_links(&mut self, item: &Item) { + let tcx = self.cx.tcx; if !self.cx.document_private() && let Some(def_id) = item.item_id.as_def_id() && let Some(def_id) = def_id.as_local() - && !self.cx.tcx.effective_visibilities(()).is_exported(def_id) + && !tcx.effective_visibilities(()).is_exported(def_id) && !has_primitive_or_keyword_or_attribute_docs(&item.attrs.other_attrs) { // Skip link resolution for non-exported items. @@ -1049,9 +1049,9 @@ impl LinkCollector<'_, '_> { } let mut insert_links = |item_id, doc: &str| { - let module_id = match self.cx.tcx.def_kind(item_id) { - DefKind::Mod if item.inner_docs(self.cx.tcx) => item_id, - _ => find_nearest_parent_module(self.cx.tcx, item_id).unwrap(), + let module_id = match tcx.def_kind(item_id) { + DefKind::Mod if item.inner_docs(tcx) => item_id, + _ => find_nearest_parent_module(tcx, item_id).unwrap(), }; for md_link in preprocessed_markdown_links(&doc) { let link = self.resolve_link(&doc, item, item_id, module_id, &md_link); @@ -1084,7 +1084,14 @@ impl LinkCollector<'_, '_> { // Also resolve links in the note text of `#[deprecated]`. for attr in &item.attrs.other_attrs { - let Some(note_sym) = attr.deprecation_note() else { continue }; + let rustc_hir::Attribute::Parsed(rustc_hir::attrs::AttributeKind::Deprecation { + span, + deprecation, + }) = attr + else { + continue; + }; + let Some(note_sym) = deprecation.note else { continue }; let note = note_sym.as_str(); if !may_have_doc_links(note) { @@ -1092,7 +1099,18 @@ impl LinkCollector<'_, '_> { } debug!("deprecated_note={note}"); - insert_links(item.item_id.expect_def_id(), note) + // When resolving an intra-doc link inside a deprecation note that is on an inlined + // `use` statement, we need to use the `def_id` of the `use` statement, not the + // inlined item. + // + let item_id = if let Some(inline_stmt_id) = item.inline_stmt_id + && item.span(tcx).is_none_or(|item_span| !item_span.inner().contains(*span)) + { + inline_stmt_id.to_def_id() + } else { + item.item_id.expect_def_id() + }; + insert_links(item_id, note) } } From c341745970fa9f18e5f87166bba95574231edebf Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 14 Jan 2026 16:37:24 +0100 Subject: [PATCH 0718/1061] Add regression test for #151028 --- .../intra-doc/ice-deprecated-note-on-reexport.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/rustdoc-html/intra-doc/ice-deprecated-note-on-reexport.rs diff --git a/tests/rustdoc-html/intra-doc/ice-deprecated-note-on-reexport.rs b/tests/rustdoc-html/intra-doc/ice-deprecated-note-on-reexport.rs new file mode 100644 index 000000000000..99415a9a2fd4 --- /dev/null +++ b/tests/rustdoc-html/intra-doc/ice-deprecated-note-on-reexport.rs @@ -0,0 +1,11 @@ +// This test ensures that the intra-doc link in `deprecated` note is resolved at the correct +// location (ie in the current crate and not in the reexported item's location/crate) and +// therefore doesn't crash. +// +// This is a regression test for . + +#![crate_name = "foo"] + +#[deprecated(note = "use [`std::mem::forget`]")] +#[doc(inline)] +pub use std::mem::drop; From 4ded6397b376b0a005c26381ed92c944e3702019 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 14 Jan 2026 00:45:16 +0100 Subject: [PATCH 0719/1061] Add new "hide deprecated items" setting in rustdoc --- src/librustdoc/clean/auto_trait.rs | 1 + src/librustdoc/clean/blanket_impl.rs | 3 ++ src/librustdoc/clean/inline.rs | 3 ++ src/librustdoc/clean/mod.rs | 4 ++ src/librustdoc/clean/types.rs | 8 ++++ src/librustdoc/html/render/mod.rs | 33 +++++++++++---- src/librustdoc/html/render/print_item.rs | 49 +++++++++++++++------- src/librustdoc/html/static/css/rustdoc.css | 9 ++++ src/librustdoc/html/static/js/search.js | 3 ++ src/librustdoc/html/static/js/settings.js | 11 +++++ src/librustdoc/html/static/js/storage.js | 3 ++ src/librustdoc/json/conversions.rs | 3 +- 12 files changed, 107 insertions(+), 23 deletions(-) diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 6c67916571a4..847e688d03d0 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -126,6 +126,7 @@ fn synthesize_auto_trait_impl<'tcx>( items: Vec::new(), polarity, kind: clean::ImplKind::Auto, + is_deprecated: false, })), item_id: clean::ItemId::Auto { trait_: trait_def_id, for_: item_def_id }, cfg: None, diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index ddfce7aeb92d..de45922e856f 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -117,6 +117,9 @@ pub(crate) fn synthesize_blanket_impls( None, None, ))), + is_deprecated: tcx + .lookup_deprecation(impl_def_id) + .is_some_and(|deprecation| deprecation.is_in_effect()), })), cfg: None, inline_stmt_id: None, diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index c86a655c083a..19974f4847d4 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -645,6 +645,9 @@ pub(crate) fn build_impl( } else { ImplKind::Normal }, + is_deprecated: tcx + .lookup_deprecation(did) + .is_some_and(|deprecation| deprecation.is_in_effect()), })), merged_attrs, cfg, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 817eda4c52ec..0e970a042ff0 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2882,6 +2882,9 @@ fn clean_impl<'tcx>( )), _ => None, }); + let is_deprecated = tcx + .lookup_deprecation(def_id.to_def_id()) + .is_some_and(|deprecation| deprecation.is_in_effect()); let mut make_item = |trait_: Option, for_: Type, items: Vec| { let kind = ImplItem(Box::new(Impl { safety: match impl_.of_trait { @@ -2902,6 +2905,7 @@ fn clean_impl<'tcx>( } else { ImplKind::Normal }, + is_deprecated, })); Item::from_def_id_and_parts(def_id.to_def_id(), None, kind, cx) }; diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index c3bafd3db13a..93863ea41396 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -427,6 +427,10 @@ impl Item { }) } + pub(crate) fn is_deprecated(&self, tcx: TyCtxt<'_>) -> bool { + self.deprecation(tcx).is_some_and(|deprecation| deprecation.is_in_effect()) + } + pub(crate) fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool { self.item_id.as_def_id().map(|did| inner_docs(tcx.get_all_attrs(did))).unwrap_or(false) } @@ -1270,6 +1274,9 @@ impl Trait { pub(crate) fn is_dyn_compatible(&self, tcx: TyCtxt<'_>) -> bool { tcx.is_dyn_compatible(self.def_id) } + pub(crate) fn is_deprecated(&self, tcx: TyCtxt<'_>) -> bool { + tcx.lookup_deprecation(self.def_id).is_some_and(|deprecation| deprecation.is_in_effect()) + } } #[derive(Clone, Debug)] @@ -2254,6 +2261,7 @@ pub(crate) struct Impl { pub(crate) items: Vec, pub(crate) polarity: ty::ImplPolarity, pub(crate) kind: ImplKind, + pub(crate) is_deprecated: bool, } impl Impl { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 63de870f07f4..106aefa4626b 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1794,12 +1794,14 @@ fn render_impl( let mut info_buffer = String::new(); let mut short_documented = true; + let mut trait_item_deprecated = false; if render_method_item { if !is_default_item { if let Some(t) = trait_ { // The trait item may have been stripped so we might not // find any documentation or stability for it. if let Some(it) = t.items.iter().find(|i| i.name == item.name) { + trait_item_deprecated = it.is_deprecated(cx.tcx()); // We need the stability of the item from the trait // because impls can't have a stability. if !item.doc_value().is_empty() { @@ -1839,10 +1841,20 @@ fn render_impl( Either::Right(boring) }; + let mut deprecation_class = if trait_item_deprecated || item.is_deprecated(cx.tcx()) { + " deprecated" + } else { + "" + }; + let toggled = !doc_buffer.is_empty(); if toggled { let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" }; - write!(w, "

")?; + write!( + w, + "
" + )?; + deprecation_class = ""; } match &item.kind { clean::MethodItem(..) | clean::RequiredMethodItem(_) => { @@ -1859,7 +1871,7 @@ fn render_impl( .map(|item| format!("{}.{name}", item.type_())); write!( w, - "
\ + "
\ {}", render_rightside(cx, item, render_mode) )?; @@ -1885,7 +1897,7 @@ fn render_impl( let id = cx.derive_id(&source_id); write!( w, - "
\ + "
\ {}", render_rightside(cx, item, render_mode) )?; @@ -1912,7 +1924,7 @@ fn render_impl( let id = cx.derive_id(&source_id); write!( w, - "
\ + "
\ {}", render_rightside(cx, item, render_mode), )?; @@ -1944,7 +1956,7 @@ fn render_impl( let id = cx.derive_id(&source_id); write!( w, - "
\ + "
\ {}", render_rightside(cx, item, render_mode), )?; @@ -1971,7 +1983,7 @@ fn render_impl( let id = cx.derive_id(&source_id); write!( w, - "
\ + "
\ {}", render_rightside(cx, item, render_mode), )?; @@ -2143,11 +2155,18 @@ fn render_impl( } if render_mode == RenderMode::Normal { let toggled = !(impl_items.is_empty() && default_impl_items.is_empty()); + let deprecation_attr = if impl_.is_deprecated + || trait_.is_some_and(|trait_| trait_.is_deprecated(cx.tcx())) + { + " deprecated" + } else { + "" + }; if toggled { close_tags.push("
"); write!( w, - "
\ + "
\ ", if rendering_params.toggle_open_by_default { " open" } else { "" } )?; diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 84e93a479b5b..55e36c462f96 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -217,6 +217,10 @@ fn toggle_close(mut w: impl fmt::Write) { } fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> impl fmt::Display { + fn deprecation_class_attr(is_deprecated: bool) -> &'static str { + if is_deprecated { " class=\"deprecated\"" } else { "" } + } + fmt::from_fn(|w| { write!(w, "{}", document(cx, item, None, HeadingOffset::H2))?; @@ -370,11 +374,18 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i write!(w, "")? } clean::ImportItem(ref import) => { - let stab_tags = - import.source.did.map_or_else(String::new, |import_def_id| { - print_extra_info_tags(tcx, myitem, item, Some(import_def_id)) - .to_string() - }); + let (stab_tags, deprecation) = match import.source.did { + Some(import_def_id) => { + let stab_tags = + print_extra_info_tags(tcx, myitem, item, Some(import_def_id)) + .to_string(); + let deprecation = tcx + .lookup_deprecation(import_def_id) + .is_some_and(|deprecation| deprecation.is_in_effect()); + (stab_tags, deprecation) + } + None => (String::new(), item.is_deprecated(tcx)), + }; let id = match import.kind { clean::ImportKind::Simple(s) => { format!(" id=\"{}\"", cx.derive_id(format!("reexport.{s}"))) @@ -383,8 +394,8 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i }; write!( w, - "\ - " + "", + deprecation_attr = deprecation_class_attr(deprecation) )?; render_attributes_in_code(w, myitem, "", cx)?; write!( @@ -396,9 +407,7 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i )?; } _ => { - if myitem.name.is_none() { - continue; - } + let Some(item_name) = myitem.name else { continue }; let unsafety_flag = match myitem.kind { clean::FunctionItem(_) | clean::ForeignFunctionItem(..) @@ -431,9 +440,10 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i .into_string(); let (docs_before, docs_after) = if docs.is_empty() { ("", "") } else { ("
", "
") }; + let deprecation_attr = deprecation_class_attr(myitem.is_deprecated(tcx)); write!( w, - "
\ + "\ \ {name}\ \ @@ -442,12 +452,12 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i {stab_tags}\
\ {docs_before}{docs}{docs_after}", - name = EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()), + name = EscapeBodyTextWithWbr(item_name.as_str()), visibility_and_hidden = visibility_and_hidden, stab_tags = print_extra_info_tags(tcx, myitem, item, None), class = type_, unsafety_flag = unsafety_flag, - href = print_item_path(type_, myitem.name.unwrap().as_str()), + href = print_item_path(type_, item_name.as_str()), title1 = myitem.type_(), title2 = full_path(cx, myitem), )?; @@ -778,15 +788,24 @@ fn item_trait(cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) -> impl fmt: let content = document_full(m, cx, HeadingOffset::H5).to_string(); + let mut deprecation_class = + if m.is_deprecated(cx.tcx()) { " deprecated" } else { "" }; + let toggled = !content.is_empty(); if toggled { let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" }; - write!(w, "
")?; + write!( + w, + "
" + )?; + deprecation_class = ""; } write!( w, - "
\ + "
\ {}\

{}

", render_rightside(cx, m, RenderMode::Normal), diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index b770a0e2a0e4..73eb260a2b8e 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -2642,6 +2642,15 @@ However, it's not needed with smaller screen width because the doc/code block is } } +/* Items on module pages */ +.hide-deprecated-items dt.deprecated, +.hide-deprecated-items dt.deprecated + dd, +/* Items on item pages */ +.hide-deprecated-items .deprecated, +.hide-deprecated-items .deprecated + .item-info { + display: none; +} + /* WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY If you update this line, then you also need to update the line with the same warning diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index b2880a2f4c2b..9961c1447ec2 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -4920,6 +4920,9 @@ async function addTab(results, query, display, finishedCallback, isTypeSearch) { const link = document.createElement("a"); link.className = "result-" + type; + if (obj.item.deprecated) { + link.className += " deprecated"; + } link.href = obj.href; const resultName = document.createElement("span"); diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index 347d3d0750ec..b28b76b0d2e7 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -78,6 +78,12 @@ removeClass(document.documentElement, "word-wrap-source-code"); } break; + case "hide-deprecated-items": + if (value === true) { + addClass(document.documentElement, "hide-deprecated-items"); + } else { + removeClass(document.documentElement, "hide-deprecated-items"); + } } } @@ -274,6 +280,11 @@ "js_name": "word-wrap-source-code", "default": false, }, + { + "name": "Hide deprecated items", + "js_name": "hide-deprecated-items", + "default": false, + }, ]; // Then we build the DOM. diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index 40ab8be03c93..7cc70374378b 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -334,6 +334,9 @@ if (getSettingValue("sans-serif-fonts") === "true") { if (getSettingValue("word-wrap-source-code") === "true") { addClass(document.documentElement, "word-wrap-source-code"); } +if (getSettingValue("hide-deprecated-items") === "true") { + addClass(document.documentElement, "hide-deprecated-items"); +} function updateSidebarWidth() { const desktopSidebarWidth = getSettingValue("desktop-sidebar-width"); if (desktopSidebarWidth && desktopSidebarWidth !== "null") { diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 892cc483dbd6..2edf7891be40 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -711,7 +711,8 @@ impl FromClean for PolyTrait { impl FromClean for Impl { fn from_clean(impl_: &clean::Impl, renderer: &JsonRenderer<'_>) -> Self { let provided_trait_methods = impl_.provided_trait_methods(renderer.tcx); - let clean::Impl { safety, generics, trait_, for_, items, polarity, kind } = impl_; + let clean::Impl { safety, generics, trait_, for_, items, polarity, kind, is_deprecated: _ } = + impl_; // FIXME: use something like ImplKind in JSON? let (is_synthetic, blanket_impl) = match kind { clean::ImplKind::Normal | clean::ImplKind::FakeVariadic => (false, None), From 4bacdf7b8b9046507ef5ae3bcb349d54fb827b0d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 14 Jan 2026 22:47:53 +0100 Subject: [PATCH 0720/1061] Reduce rustdoc GUI flakyness, take 2 --- tests/rustdoc-gui/utils.goml | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/tests/rustdoc-gui/utils.goml b/tests/rustdoc-gui/utils.goml index c0625ead2f1a..c5c8ab3b1af8 100644 --- a/tests/rustdoc-gui/utils.goml +++ b/tests/rustdoc-gui/utils.goml @@ -29,9 +29,18 @@ define-function: ( "open-settings-menu", [], block { - call-function: ("click-settings-button", {}) - // Wait for the popover to appear... - wait-for-css: ("#settings", {"display": "block"}) + store-count: ("#settings", nb_settings_menu) + if: (|nb_settings_menu| != 0, block { + store-css: ("#settings", {"display": settings_display}) + }) + else: block { + store-value: (settings_display, "none") + } + if: (|settings_display| != "block", block { + call-function: ("click-settings-button", {}) + // Wait for the popover to appear... + wait-for-css: ("#settings", {"display": "block"}) + }) } ) @@ -39,9 +48,18 @@ define-function: ( "close-settings-menu", [], block { - call-function: ("click-settings-button", {}) - // Wait for the popover to disappear... - wait-for-css-false: ("#settings", {"display": "block"}) + store-count: ("#settings", nb_settings_menu) + if: (|nb_settings_menu| != 0, block { + store-css: ("#settings", {"display": settings_display}) + }) + else: block { + store-value: (settings_display, "block") + } + if: (|settings_display| == "block", block { + call-function: ("click-settings-button", {}) + // Wait for the popover to disappear... + wait-for-css-false: ("#settings", {"display": "block"}) + }) } ) From 36d37fd11b43e4cce1a2d993497937c40db9a7a2 Mon Sep 17 00:00:00 2001 From: dianne Date: Thu, 8 Jan 2026 15:44:41 -0800 Subject: [PATCH 0721/1061] THIR: directly contain `HirId`s, not `LintLevel`s --- compiler/rustc_middle/src/thir.rs | 8 +- compiler/rustc_middle/src/thir/visit.rs | 8 +- compiler/rustc_mir_build/src/builder/block.rs | 12 +-- .../src/builder/expr/as_constant.rs | 2 +- .../src/builder/expr/as_operand.rs | 8 +- .../src/builder/expr/as_place.rs | 4 +- .../src/builder/expr/as_rvalue.rs | 8 +- .../src/builder/expr/as_temp.rs | 10 ++- .../rustc_mir_build/src/builder/expr/into.rs | 4 +- .../rustc_mir_build/src/builder/expr/stmt.rs | 8 +- .../src/builder/matches/mod.rs | 6 +- .../rustc_mir_build/src/check_unsafety.rs | 2 +- compiler/rustc_mir_build/src/thir/cx/block.rs | 2 +- compiler/rustc_mir_build/src/thir/cx/expr.rs | 4 +- .../src/thir/pattern/check_match.rs | 66 +++++++--------- compiler/rustc_mir_build/src/thir/print.rs | 12 +-- tests/ui/thir-print/c-variadic.stdout | 2 +- tests/ui/thir-print/offset_of.stdout | 76 +++++++++---------- .../thir-print/thir-flat-const-variant.stdout | 36 +++------ tests/ui/thir-print/thir-flat.stdout | 4 +- .../ui/thir-print/thir-tree-loop-match.stdout | 24 +++--- tests/ui/thir-print/thir-tree-match.stdout | 20 ++--- tests/ui/thir-print/thir-tree.stdout | 2 +- tests/ui/unpretty/box.stdout | 8 +- 24 files changed, 155 insertions(+), 181 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 3683c1cfb7dd..86bd6fb803b7 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -236,8 +236,8 @@ pub enum StmtKind<'tcx> { /// `let pat: ty = else { }` else_block: Option, - /// The lint level for this `let` statement. - lint_level: LintLevel, + /// The [`HirId`] for this `let` statement. + hir_id: HirId, /// Span of the `let = ` part. span: Span, @@ -271,7 +271,7 @@ pub enum ExprKind<'tcx> { /// and to track the `HirId` of the expressions within the scope. Scope { region_scope: region::Scope, - lint_level: LintLevel, + hir_id: HirId, value: ExprId, }, /// A `box ` expression. @@ -579,7 +579,7 @@ pub struct Arm<'tcx> { pub pattern: Box>, pub guard: Option, pub body: ExprId, - pub lint_level: LintLevel, + pub hir_id: HirId, pub scope: region::Scope, pub span: Span, } diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index d792bbe60c88..4e30c450c89b 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -47,9 +47,7 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( use ExprKind::*; let Expr { kind, ty: _, temp_scope_id: _, span: _ } = expr; match *kind { - Scope { value, region_scope: _, lint_level: _ } => { - visitor.visit_expr(&visitor.thir()[value]) - } + Scope { value, region_scope: _, hir_id: _ } => visitor.visit_expr(&visitor.thir()[value]), Box { value } => visitor.visit_expr(&visitor.thir()[value]), If { cond, then, else_opt, if_then_scope: _ } => { visitor.visit_expr(&visitor.thir()[cond]); @@ -205,7 +203,7 @@ pub fn walk_stmt<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( remainder_scope: _, init_scope: _, pattern, - lint_level: _, + hir_id: _, else_block, span: _, } => { @@ -238,7 +236,7 @@ pub fn walk_arm<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( visitor: &mut V, arm: &'thir Arm<'tcx>, ) { - let Arm { guard, pattern, body, lint_level: _, span: _, scope: _ } = arm; + let Arm { guard, pattern, body, hir_id: _, span: _, scope: _ } = arm; if let Some(expr) = guard { visitor.visit_expr(&visitor.thir()[*expr]) } diff --git a/compiler/rustc_mir_build/src/builder/block.rs b/compiler/rustc_mir_build/src/builder/block.rs index 88533ad22648..d8837d2b195a 100644 --- a/compiler/rustc_mir_build/src/builder/block.rs +++ b/compiler/rustc_mir_build/src/builder/block.rs @@ -83,7 +83,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { init_scope, pattern, initializer: Some(initializer), - lint_level, + hir_id, else_block: Some(else_block), span: _, } => { @@ -191,7 +191,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let initializer_span = this.thir[*initializer].span; let scope = (*init_scope, source_info); - let failure_and_block = this.in_scope(scope, *lint_level, |this| { + let lint_level = LintLevel::Explicit(*hir_id); + let failure_and_block = this.in_scope(scope, lint_level, |this| { this.declare_bindings( visibility_scope, remainder_span, @@ -232,7 +233,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { init_scope, pattern, initializer, - lint_level, + hir_id, else_block: None, span: _, } => { @@ -250,12 +251,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Some(this.new_source_scope(remainder_span, LintLevel::Inherited)); // Evaluate the initializer, if present. + let lint_level = LintLevel::Explicit(*hir_id); if let Some(init) = *initializer { let initializer_span = this.thir[init].span; let scope = (*init_scope, source_info); block = this - .in_scope(scope, *lint_level, |this| { + .in_scope(scope, lint_level, |this| { this.declare_bindings( visibility_scope, remainder_span, @@ -269,7 +271,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .into_block(); } else { let scope = (*init_scope, source_info); - let _: BlockAnd<()> = this.in_scope(scope, *lint_level, |this| { + let _: BlockAnd<()> = this.in_scope(scope, lint_level, |this| { this.declare_bindings( visibility_scope, remainder_span, diff --git a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs index 186fde4883df..39b4390f7749 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs @@ -23,7 +23,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let tcx = this.tcx; let Expr { ty, temp_scope_id: _, span, ref kind } = *expr; match kind { - ExprKind::Scope { region_scope: _, lint_level: _, value } => { + ExprKind::Scope { region_scope: _, hir_id: _, value } => { this.as_constant(&this.thir[*value]) } _ => as_constant_inner( diff --git a/compiler/rustc_mir_build/src/builder/expr/as_operand.rs b/compiler/rustc_mir_build/src/builder/expr/as_operand.rs index 5989a15b9346..c9c166b7f018 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_operand.rs @@ -122,10 +122,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let this = self; // See "LET_THIS_SELF". let expr = &this.thir[expr_id]; - if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind { + if let ExprKind::Scope { region_scope, hir_id, value } = expr.kind { let source_info = this.source_info(expr.span); let region_scope = (region_scope, source_info); - return this.in_scope(region_scope, lint_level, |this| { + return this.in_scope(region_scope, LintLevel::Explicit(hir_id), |this| { this.as_operand(block, scope, value, local_info, needs_temporary) }); } @@ -165,10 +165,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let expr = &this.thir[expr_id]; debug!("as_call_operand(block={:?}, expr={:?})", block, expr); - if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind { + if let ExprKind::Scope { region_scope, hir_id, value } = expr.kind { let source_info = this.source_info(expr.span); let region_scope = (region_scope, source_info); - return this.in_scope(region_scope, lint_level, |this| { + return this.in_scope(region_scope, LintLevel::Explicit(hir_id), |this| { this.as_call_operand(block, scope, value) }); } diff --git a/compiler/rustc_mir_build/src/builder/expr/as_place.rs b/compiler/rustc_mir_build/src/builder/expr/as_place.rs index cb81b42128a8..db9aa3cd8704 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs @@ -427,8 +427,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let expr_span = expr.span; let source_info = this.source_info(expr_span); match expr.kind { - ExprKind::Scope { region_scope, lint_level, value } => { - this.in_scope((region_scope, source_info), lint_level, |this| { + ExprKind::Scope { region_scope, hir_id, value } => { + this.in_scope((region_scope, source_info), LintLevel::Explicit(hir_id), |this| { this.expr_as_place(block, value, mutability, fake_borrow_temps) }) } diff --git a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs index bb1095ced47a..3d1774bd1d68 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs @@ -56,9 +56,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match expr.kind { ExprKind::ThreadLocalRef(did) => block.and(Rvalue::ThreadLocalRef(did)), - ExprKind::Scope { region_scope, lint_level, value } => { + ExprKind::Scope { region_scope, hir_id, value } => { let region_scope = (region_scope, source_info); - this.in_scope(region_scope, lint_level, |this| this.as_rvalue(block, scope, value)) + this.in_scope(region_scope, LintLevel::Explicit(hir_id), |this| { + this.as_rvalue(block, scope, value) + }) } ExprKind::Repeat { value, count } => { if Some(0) == count.try_to_target_usize(this.tcx) { @@ -657,7 +659,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source: eid, is_from_as_cast: _, } - | &ExprKind::Scope { region_scope: _, lint_level: _, value: eid } => { + | &ExprKind::Scope { region_scope: _, hir_id: _, value: eid } => { kind = &self.thir[eid].kind } _ => return matches!(Category::of(&kind), Some(Category::Constant)), diff --git a/compiler/rustc_mir_build/src/builder/expr/as_temp.rs b/compiler/rustc_mir_build/src/builder/expr/as_temp.rs index d8ac19e34aae..2aace64062cd 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_temp.rs @@ -39,10 +39,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let expr = &this.thir[expr_id]; let expr_span = expr.span; let source_info = this.source_info(expr_span); - if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind { - return this.in_scope((region_scope, source_info), lint_level, |this| { - this.as_temp(block, temp_lifetime, value, mutability) - }); + if let ExprKind::Scope { region_scope, hir_id, value } = expr.kind { + return this.in_scope( + (region_scope, source_info), + LintLevel::Explicit(hir_id), + |this| this.as_temp(block, temp_lifetime, value, mutability), + ); } let expr_ty = expr.ty; diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index f595cfc77e9d..9731f0de135f 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -45,10 +45,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } let block_and = match expr.kind { - ExprKind::Scope { region_scope, lint_level, value } => { + ExprKind::Scope { region_scope, hir_id, value } => { let region_scope = (region_scope, source_info); ensure_sufficient_stack(|| { - this.in_scope(region_scope, lint_level, |this| { + this.in_scope(region_scope, LintLevel::Explicit(hir_id), |this| { this.expr_into_dest(destination, block, value) }) }) diff --git a/compiler/rustc_mir_build/src/builder/expr/stmt.rs b/compiler/rustc_mir_build/src/builder/expr/stmt.rs index 66ee13939849..f28e483b6a5d 100644 --- a/compiler/rustc_mir_build/src/builder/expr/stmt.rs +++ b/compiler/rustc_mir_build/src/builder/expr/stmt.rs @@ -25,8 +25,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Handle a number of expressions that don't need a destination at all. This // avoids needing a mountain of temporary `()` variables. match expr.kind { - ExprKind::Scope { region_scope, lint_level, value } => { - this.in_scope((region_scope, source_info), lint_level, |this| { + ExprKind::Scope { region_scope, hir_id, value } => { + this.in_scope((region_scope, source_info), LintLevel::Explicit(hir_id), |this| { this.stmt_expr(block, value, statement_scope) }) } @@ -106,7 +106,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ExprKind::Become { value } => { let v = &this.thir[value]; - let ExprKind::Scope { value, lint_level, region_scope } = v.kind else { + let ExprKind::Scope { value, hir_id, region_scope } = v.kind else { span_bug!(v.span, "`thir_check_tail_calls` should have disallowed this {v:?}") }; @@ -115,7 +115,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span_bug!(v.span, "`thir_check_tail_calls` should have disallowed this {v:?}") }; - this.in_scope((region_scope, source_info), lint_level, |this| { + this.in_scope((region_scope, source_info), LintLevel::Explicit(hir_id), |this| { let fun = unpack!(block = this.as_local_operand(block, fun)); let args: Box<[_]> = args .into_iter() diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 9080e2ba801b..49caee4a1896 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -182,9 +182,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.break_for_else(success_block, args.variable_source_info); failure_block.unit() } - ExprKind::Scope { region_scope, lint_level, value } => { + ExprKind::Scope { region_scope, hir_id, value } => { let region_scope = (region_scope, this.source_info(expr_span)); - this.in_scope(region_scope, lint_level, |this| { + this.in_scope(region_scope, LintLevel::Explicit(hir_id), |this| { this.then_else_break_inner(block, value, args) }) } @@ -434,7 +434,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let guard_scope = arm .guard .map(|_| region::Scope { data: region::ScopeData::MatchGuard, ..arm.scope }); - self.in_scope(arm_scope, arm.lint_level, |this| { + self.in_scope(arm_scope, LintLevel::Explicit(arm.hir_id), |this| { this.opt_in_scope(guard_scope.map(|scope| (scope, arm_source_info)), |this| { // `if let` guard temps needing deduplicating will be in the guard scope. let old_dedup_scope = diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 4f03e3d965c6..e330242c8a1f 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -478,7 +478,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { } }; match expr.kind { - ExprKind::Scope { value, lint_level: LintLevel::Explicit(hir_id), region_scope: _ } => { + ExprKind::Scope { value, hir_id, region_scope: _ } => { let prev_id = self.hir_context; self.hir_context = hir_id; ensure_sufficient_stack(|| { diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs index 7cdd70a7fc27..fad73a7115b0 100644 --- a/compiler/rustc_mir_build/src/thir/cx/block.rs +++ b/compiler/rustc_mir_build/src/thir/cx/block.rs @@ -88,7 +88,7 @@ impl<'tcx> ThirBuildCx<'tcx> { pattern, initializer: local.init.map(|init| self.mirror_expr(init)), else_block, - lint_level: LintLevel::Explicit(local.hir_id), + hir_id: local.hir_id, span, }, }; diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 50ccbd50d971..8e02424706ee 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -77,7 +77,7 @@ impl<'tcx> ThirBuildCx<'tcx> { kind: ExprKind::Scope { region_scope: expr_scope, value: self.thir.exprs.push(expr), - lint_level: LintLevel::Explicit(hir_expr.hir_id), + hir_id: hir_expr.hir_id, }, }; @@ -1192,7 +1192,7 @@ impl<'tcx> ThirBuildCx<'tcx> { pattern: self.pattern_from_hir(&arm.pat), guard: arm.guard.as_ref().map(|g| self.mirror_expr(g)), body: self.mirror_expr(arm.body), - lint_level: LintLevel::Explicit(arm.hir_id), + hir_id: arm.hir_id, scope: region::Scope { local_id: arm.hir_id.local_id, data: region::ScopeData::Node }, span: arm.span, }; diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index bf480cf601ee..b8c64d98881b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -43,7 +43,7 @@ pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), Err typeck_results, // FIXME(#132279): We're in a body, should handle opaques. typing_env: ty::TypingEnv::non_body_analysis(tcx, def_id), - lint_level: tcx.local_def_id_to_hir_id(def_id), + hir_source: tcx.local_def_id_to_hir_id(def_id), let_source: LetSource::None, pattern_arena: &pattern_arena, dropless_arena: &dropless_arena, @@ -92,7 +92,7 @@ struct MatchVisitor<'p, 'tcx> { typing_env: ty::TypingEnv<'tcx>, typeck_results: &'tcx ty::TypeckResults<'tcx>, thir: &'p Thir<'tcx>, - lint_level: HirId, + hir_source: HirId, let_source: LetSource, pattern_arena: &'p TypedArena>, dropless_arena: &'p DroplessArena, @@ -111,7 +111,7 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> { #[instrument(level = "trace", skip(self))] fn visit_arm(&mut self, arm: &'p Arm<'tcx>) { - self.with_lint_level(arm.lint_level, |this| { + self.with_hir_source(arm.hir_id, |this| { if let Some(expr) = arm.guard { this.with_let_source(LetSource::IfLetGuard, |this| { this.visit_expr(&this.thir[expr]) @@ -125,8 +125,8 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> { #[instrument(level = "trace", skip(self))] fn visit_expr(&mut self, ex: &'p Expr<'tcx>) { match ex.kind { - ExprKind::Scope { value, lint_level, .. } => { - self.with_lint_level(lint_level, |this| { + ExprKind::Scope { value, hir_id, .. } => { + self.with_hir_source(hir_id, |this| { this.visit_expr(&this.thir[value]); }); return; @@ -181,10 +181,8 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> { fn visit_stmt(&mut self, stmt: &'p Stmt<'tcx>) { match stmt.kind { - StmtKind::Let { - box ref pattern, initializer, else_block, lint_level, span, .. - } => { - self.with_lint_level(lint_level, |this| { + StmtKind::Let { box ref pattern, initializer, else_block, hir_id, span, .. } => { + self.with_hir_source(hir_id, |this| { let let_source = if else_block.is_some() { LetSource::LetElse } else { LetSource::PlainLet }; this.with_let_source(let_source, |this| { @@ -209,20 +207,12 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { self.let_source = old_let_source; } - fn with_lint_level( - &mut self, - new_lint_level: LintLevel, - f: impl FnOnce(&mut Self) -> T, - ) -> T { - if let LintLevel::Explicit(hir_id) = new_lint_level { - let old_lint_level = self.lint_level; - self.lint_level = hir_id; - let ret = f(self); - self.lint_level = old_lint_level; - ret - } else { - f(self) - } + fn with_hir_source(&mut self, new_hir_source: HirId, f: impl FnOnce(&mut Self) -> T) -> T { + let old_hir_source = self.hir_source; + self.hir_source = new_hir_source; + let ret = f(self); + self.hir_source = old_hir_source; + ret } /// Visit a nested chain of `&&`. Used for if-let chains. This must call `visit_expr` on the @@ -233,9 +223,9 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { accumulator: &mut Vec>, ) -> Result<(), ErrorGuaranteed> { match ex.kind { - ExprKind::Scope { value, lint_level, .. } => self.with_lint_level(lint_level, |this| { - this.visit_land(&this.thir[value], accumulator) - }), + ExprKind::Scope { value, hir_id, .. } => { + self.with_hir_source(hir_id, |this| this.visit_land(&this.thir[value], accumulator)) + } ExprKind::LogicalOp { op: LogicalOp::And, lhs, rhs } => { // We recurse into the lhs only, because `&&` chains associate to the left. let res_lhs = self.visit_land(&self.thir[lhs], accumulator); @@ -259,8 +249,8 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { ex: &'p Expr<'tcx>, ) -> Result, ErrorGuaranteed> { match ex.kind { - ExprKind::Scope { value, lint_level, .. } => { - self.with_lint_level(lint_level, |this| this.visit_land_rhs(&this.thir[value])) + ExprKind::Scope { value, hir_id, .. } => { + self.with_hir_source(hir_id, |this| this.visit_land_rhs(&this.thir[value])) } ExprKind::Let { box ref pat, expr } => { let expr = &self.thir()[expr]; @@ -398,9 +388,9 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { tcx: self.tcx, typeck_results: self.typeck_results, typing_env: self.typing_env, - module: self.tcx.parent_module(self.lint_level).to_def_id(), + module: self.tcx.parent_module(self.hir_source).to_def_id(), dropless_arena: self.dropless_arena, - match_lint_level: self.lint_level, + match_lint_level: self.hir_source, whole_match_span, scrut_span, refutable, @@ -448,7 +438,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { if matches!(refutability, Irrefutable) { report_irrefutable_let_patterns( self.tcx, - self.lint_level, + self.hir_source, self.let_source, 1, span, @@ -470,10 +460,10 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { let mut tarms = Vec::with_capacity(arms.len()); for &arm in arms { let arm = &self.thir.arms[arm]; - let got_error = self.with_lint_level(arm.lint_level, |this| { + let got_error = self.with_hir_source(arm.hir_id, |this| { let Ok(pat) = this.lower_pattern(&cx, &arm.pattern) else { return true }; let arm = - MatchArm { pat, arm_data: this.lint_level, has_guard: arm.guard.is_some() }; + MatchArm { pat, arm_data: this.hir_source, has_guard: arm.guard.is_some() }; tarms.push(arm); false }); @@ -572,7 +562,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { // The entire chain is made up of irrefutable `let` statements report_irrefutable_let_patterns( self.tcx, - self.lint_level, + self.hir_source, self.let_source, chain_refutabilities.len(), whole_chain_span, @@ -605,7 +595,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { let count = prefix.len(); self.tcx.emit_node_span_lint( IRREFUTABLE_LET_PATTERNS, - self.lint_level, + self.hir_source, span, LeadingIrrefutableLetPatterns { count }, ); @@ -624,7 +614,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { let count = suffix.len(); self.tcx.emit_node_span_lint( IRREFUTABLE_LET_PATTERNS, - self.lint_level, + self.hir_source, span, TrailingIrrefutableLetPatterns { count }, ); @@ -639,7 +629,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { ) -> Result<(PatCtxt<'p, 'tcx>, UsefulnessReport<'p, 'tcx>), ErrorGuaranteed> { let cx = self.new_cx(refutability, None, scrut, pat.span); let pat = self.lower_pattern(&cx, pat)?; - let arms = [MatchArm { pat, arm_data: self.lint_level, has_guard: false }]; + let arms = [MatchArm { pat, arm_data: self.hir_source, has_guard: false }]; let report = self.analyze_patterns(&cx, &arms, pat.ty().inner())?; Ok((cx, report)) } @@ -893,7 +883,7 @@ fn check_for_bindings_named_same_as_variants( let ty_path = with_no_trimmed_paths!(cx.tcx.def_path_str(edef.did())); cx.tcx.emit_node_span_lint( BINDINGS_WITH_VARIANT_NAME, - cx.lint_level, + cx.hir_source, pat.span, BindingsWithVariantName { // If this is an irrefutable pattern, and there's > 1 variant, diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 5a2d6cfef1cc..d837aa3d70ca 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -142,7 +142,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { pattern, initializer, else_block, - lint_level, + hir_id, span, } => { print_indented!(self, "kind: Let {", depth_lvl + 1); @@ -173,7 +173,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, "else_block: None", depth_lvl + 2); } - print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 2); + print_indented!(self, format!("hir_id: {:?}", hir_id), depth_lvl + 2); print_indented!(self, format!("span: {:?}", span), depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } @@ -197,10 +197,10 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { use rustc_middle::thir::ExprKind::*; match expr_kind { - Scope { region_scope, value, lint_level } => { + Scope { region_scope, value, hir_id } => { print_indented!(self, "Scope {", depth_lvl); print_indented!(self, format!("region_scope: {:?}", region_scope), depth_lvl + 1); - print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 1); + print_indented!(self, format!("hir_id: {:?}", hir_id), depth_lvl + 1); print_indented!(self, "value:", depth_lvl + 1); self.print_expr(*value, depth_lvl + 2); print_indented!(self, "}", depth_lvl); @@ -642,7 +642,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, "Arm {", depth_lvl); let arm = &self.thir.arms[arm_id]; - let Arm { pattern, guard, body, lint_level, scope, span } = arm; + let Arm { pattern, guard, body, hir_id, scope, span } = arm; print_indented!(self, "pattern: ", depth_lvl + 1); self.print_pat(pattern, depth_lvl + 2); @@ -656,7 +656,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, "body: ", depth_lvl + 1); self.print_expr(*body, depth_lvl + 2); - print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 1); + print_indented!(self, format!("hir_id: {:?}", hir_id), depth_lvl + 1); print_indented!(self, format!("scope: {:?}", scope), depth_lvl + 1); print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); print_indented!(self, "}", depth_lvl); diff --git a/tests/ui/thir-print/c-variadic.stdout b/tests/ui/thir-print/c-variadic.stdout index f1905e04f72b..a3e3fa5e0008 100644 --- a/tests/ui/thir-print/c-variadic.stdout +++ b/tests/ui/thir-print/c-variadic.stdout @@ -39,7 +39,7 @@ body: kind: Scope { region_scope: Node(6) - lint_level: Explicit(HirId(DefId(0:3 ~ c_variadic[a5de]::foo).6)) + hir_id: HirId(DefId(0:3 ~ c_variadic[a5de]::foo).6) value: Expr { ty: () diff --git a/tests/ui/thir-print/offset_of.stdout b/tests/ui/thir-print/offset_of.stdout index dcf60a86af9b..29399bb98e32 100644 --- a/tests/ui/thir-print/offset_of.stdout +++ b/tests/ui/thir-print/offset_of.stdout @@ -9,7 +9,7 @@ body: kind: Scope { region_scope: Node(52) - lint_level: Explicit(HirId(DefId(offset_of::concrete).52)) + hir_id: HirId(DefId(offset_of::concrete).52) value: Expr { ty: () @@ -51,7 +51,7 @@ body: kind: Scope { region_scope: Node(3) - lint_level: Explicit(HirId(DefId(offset_of::concrete).3)) + hir_id: HirId(DefId(offset_of::concrete).3) value: Expr { ty: usize @@ -67,7 +67,7 @@ body: } ) else_block: None - lint_level: Explicit(HirId(DefId(offset_of::concrete).10)) + hir_id: HirId(DefId(offset_of::concrete).10) span: $DIR/offset_of.rs:37:5: 1440:57 (#0) } } @@ -100,7 +100,7 @@ body: kind: Scope { region_scope: Node(13) - lint_level: Explicit(HirId(DefId(offset_of::concrete).13)) + hir_id: HirId(DefId(offset_of::concrete).13) value: Expr { ty: usize @@ -116,7 +116,7 @@ body: } ) else_block: None - lint_level: Explicit(HirId(DefId(offset_of::concrete).20)) + hir_id: HirId(DefId(offset_of::concrete).20) span: $DIR/offset_of.rs:38:5: 1440:57 (#0) } } @@ -149,7 +149,7 @@ body: kind: Scope { region_scope: Node(23) - lint_level: Explicit(HirId(DefId(offset_of::concrete).23)) + hir_id: HirId(DefId(offset_of::concrete).23) value: Expr { ty: usize @@ -165,7 +165,7 @@ body: } ) else_block: None - lint_level: Explicit(HirId(DefId(offset_of::concrete).30)) + hir_id: HirId(DefId(offset_of::concrete).30) span: $DIR/offset_of.rs:39:5: 1440:57 (#0) } } @@ -198,7 +198,7 @@ body: kind: Scope { region_scope: Node(33) - lint_level: Explicit(HirId(DefId(offset_of::concrete).33)) + hir_id: HirId(DefId(offset_of::concrete).33) value: Expr { ty: usize @@ -214,7 +214,7 @@ body: } ) else_block: None - lint_level: Explicit(HirId(DefId(offset_of::concrete).40)) + hir_id: HirId(DefId(offset_of::concrete).40) span: $DIR/offset_of.rs:40:5: 1440:57 (#0) } } @@ -247,7 +247,7 @@ body: kind: Scope { region_scope: Node(43) - lint_level: Explicit(HirId(DefId(offset_of::concrete).43)) + hir_id: HirId(DefId(offset_of::concrete).43) value: Expr { ty: usize @@ -263,7 +263,7 @@ body: } ) else_block: None - lint_level: Explicit(HirId(DefId(offset_of::concrete).50)) + hir_id: HirId(DefId(offset_of::concrete).50) span: $DIR/offset_of.rs:41:5: 1440:57 (#0) } } @@ -286,7 +286,7 @@ body: kind: Scope { region_scope: Node(5) - lint_level: Explicit(HirId(DefId(offset_of::concrete).5)) + hir_id: HirId(DefId(offset_of::concrete).5) value: Expr { ty: usize @@ -307,7 +307,7 @@ body: kind: Scope { region_scope: Node(7) - lint_level: Explicit(HirId(DefId(offset_of::concrete).7)) + hir_id: HirId(DefId(offset_of::concrete).7) value: Expr { ty: usize @@ -369,7 +369,7 @@ body: kind: Scope { region_scope: Node(15) - lint_level: Explicit(HirId(DefId(offset_of::concrete).15)) + hir_id: HirId(DefId(offset_of::concrete).15) value: Expr { ty: usize @@ -390,7 +390,7 @@ body: kind: Scope { region_scope: Node(17) - lint_level: Explicit(HirId(DefId(offset_of::concrete).17)) + hir_id: HirId(DefId(offset_of::concrete).17) value: Expr { ty: usize @@ -452,7 +452,7 @@ body: kind: Scope { region_scope: Node(25) - lint_level: Explicit(HirId(DefId(offset_of::concrete).25)) + hir_id: HirId(DefId(offset_of::concrete).25) value: Expr { ty: usize @@ -473,7 +473,7 @@ body: kind: Scope { region_scope: Node(27) - lint_level: Explicit(HirId(DefId(offset_of::concrete).27)) + hir_id: HirId(DefId(offset_of::concrete).27) value: Expr { ty: usize @@ -535,7 +535,7 @@ body: kind: Scope { region_scope: Node(35) - lint_level: Explicit(HirId(DefId(offset_of::concrete).35)) + hir_id: HirId(DefId(offset_of::concrete).35) value: Expr { ty: usize @@ -556,7 +556,7 @@ body: kind: Scope { region_scope: Node(37) - lint_level: Explicit(HirId(DefId(offset_of::concrete).37)) + hir_id: HirId(DefId(offset_of::concrete).37) value: Expr { ty: usize @@ -670,7 +670,7 @@ body: kind: Scope { region_scope: Node(45) - lint_level: Explicit(HirId(DefId(offset_of::concrete).45)) + hir_id: HirId(DefId(offset_of::concrete).45) value: Expr { ty: usize @@ -691,7 +691,7 @@ body: kind: Scope { region_scope: Node(47) - lint_level: Explicit(HirId(DefId(offset_of::concrete).47)) + hir_id: HirId(DefId(offset_of::concrete).47) value: Expr { ty: usize @@ -805,7 +805,7 @@ body: kind: Scope { region_scope: Node(50) - lint_level: Explicit(HirId(DefId(offset_of::generic).50)) + hir_id: HirId(DefId(offset_of::generic).50) value: Expr { ty: () @@ -847,7 +847,7 @@ body: kind: Scope { region_scope: Node(3) - lint_level: Explicit(HirId(DefId(offset_of::generic).3)) + hir_id: HirId(DefId(offset_of::generic).3) value: Expr { ty: usize @@ -863,7 +863,7 @@ body: } ) else_block: None - lint_level: Explicit(HirId(DefId(offset_of::generic).12)) + hir_id: HirId(DefId(offset_of::generic).12) span: $DIR/offset_of.rs:45:5: 1440:57 (#0) } } @@ -896,7 +896,7 @@ body: kind: Scope { region_scope: Node(15) - lint_level: Explicit(HirId(DefId(offset_of::generic).15)) + hir_id: HirId(DefId(offset_of::generic).15) value: Expr { ty: usize @@ -912,7 +912,7 @@ body: } ) else_block: None - lint_level: Explicit(HirId(DefId(offset_of::generic).24)) + hir_id: HirId(DefId(offset_of::generic).24) span: $DIR/offset_of.rs:46:5: 1440:57 (#0) } } @@ -945,7 +945,7 @@ body: kind: Scope { region_scope: Node(27) - lint_level: Explicit(HirId(DefId(offset_of::generic).27)) + hir_id: HirId(DefId(offset_of::generic).27) value: Expr { ty: usize @@ -961,7 +961,7 @@ body: } ) else_block: None - lint_level: Explicit(HirId(DefId(offset_of::generic).36)) + hir_id: HirId(DefId(offset_of::generic).36) span: $DIR/offset_of.rs:47:5: 1440:57 (#0) } } @@ -994,7 +994,7 @@ body: kind: Scope { region_scope: Node(39) - lint_level: Explicit(HirId(DefId(offset_of::generic).39)) + hir_id: HirId(DefId(offset_of::generic).39) value: Expr { ty: usize @@ -1010,7 +1010,7 @@ body: } ) else_block: None - lint_level: Explicit(HirId(DefId(offset_of::generic).48)) + hir_id: HirId(DefId(offset_of::generic).48) span: $DIR/offset_of.rs:48:5: 1440:57 (#0) } } @@ -1033,7 +1033,7 @@ body: kind: Scope { region_scope: Node(5) - lint_level: Explicit(HirId(DefId(offset_of::generic).5)) + hir_id: HirId(DefId(offset_of::generic).5) value: Expr { ty: usize @@ -1054,7 +1054,7 @@ body: kind: Scope { region_scope: Node(7) - lint_level: Explicit(HirId(DefId(offset_of::generic).7)) + hir_id: HirId(DefId(offset_of::generic).7) value: Expr { ty: usize @@ -1116,7 +1116,7 @@ body: kind: Scope { region_scope: Node(17) - lint_level: Explicit(HirId(DefId(offset_of::generic).17)) + hir_id: HirId(DefId(offset_of::generic).17) value: Expr { ty: usize @@ -1137,7 +1137,7 @@ body: kind: Scope { region_scope: Node(19) - lint_level: Explicit(HirId(DefId(offset_of::generic).19)) + hir_id: HirId(DefId(offset_of::generic).19) value: Expr { ty: usize @@ -1199,7 +1199,7 @@ body: kind: Scope { region_scope: Node(29) - lint_level: Explicit(HirId(DefId(offset_of::generic).29)) + hir_id: HirId(DefId(offset_of::generic).29) value: Expr { ty: usize @@ -1220,7 +1220,7 @@ body: kind: Scope { region_scope: Node(31) - lint_level: Explicit(HirId(DefId(offset_of::generic).31)) + hir_id: HirId(DefId(offset_of::generic).31) value: Expr { ty: usize @@ -1282,7 +1282,7 @@ body: kind: Scope { region_scope: Node(41) - lint_level: Explicit(HirId(DefId(offset_of::generic).41)) + hir_id: HirId(DefId(offset_of::generic).41) value: Expr { ty: usize @@ -1303,7 +1303,7 @@ body: kind: Scope { region_scope: Node(43) - lint_level: Explicit(HirId(DefId(offset_of::generic).43)) + hir_id: HirId(DefId(offset_of::generic).43) value: Expr { ty: usize diff --git a/tests/ui/thir-print/thir-flat-const-variant.stdout b/tests/ui/thir-print/thir-flat-const-variant.stdout index 750a47a7141c..908684094ec3 100644 --- a/tests/ui/thir-print/thir-flat-const-variant.stdout +++ b/tests/ui/thir-print/thir-flat-const-variant.stdout @@ -17,9 +17,7 @@ Thir { Expr { kind: Scope { region_scope: Node(7), - lint_level: Explicit( - HirId(DefId(0:8 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR1).7), - ), + hir_id: HirId(DefId(0:8 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR1).7), value: e0, }, ty: (), @@ -49,9 +47,7 @@ Thir { Expr { kind: Scope { region_scope: Node(3), - lint_level: Explicit( - HirId(DefId(0:8 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR1).3), - ), + hir_id: HirId(DefId(0:8 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR1).3), value: e2, }, ty: Foo, @@ -82,9 +78,7 @@ Thir { Expr { kind: Scope { region_scope: Node(8), - lint_level: Explicit( - HirId(DefId(0:9 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR2).8), - ), + hir_id: HirId(DefId(0:9 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR2).8), value: e0, }, ty: (), @@ -114,9 +108,7 @@ Thir { Expr { kind: Scope { region_scope: Node(3), - lint_level: Explicit( - HirId(DefId(0:9 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR2).3), - ), + hir_id: HirId(DefId(0:9 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR2).3), value: e2, }, ty: Foo, @@ -147,9 +139,7 @@ Thir { Expr { kind: Scope { region_scope: Node(7), - lint_level: Explicit( - HirId(DefId(0:10 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR3).7), - ), + hir_id: HirId(DefId(0:10 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR3).7), value: e0, }, ty: (), @@ -179,9 +169,7 @@ Thir { Expr { kind: Scope { region_scope: Node(3), - lint_level: Explicit( - HirId(DefId(0:10 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR3).3), - ), + hir_id: HirId(DefId(0:10 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR3).3), value: e2, }, ty: Foo, @@ -212,9 +200,7 @@ Thir { Expr { kind: Scope { region_scope: Node(8), - lint_level: Explicit( - HirId(DefId(0:11 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR4).8), - ), + hir_id: HirId(DefId(0:11 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR4).8), value: e0, }, ty: (), @@ -244,9 +230,7 @@ Thir { Expr { kind: Scope { region_scope: Node(3), - lint_level: Explicit( - HirId(DefId(0:11 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR4).3), - ), + hir_id: HirId(DefId(0:11 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR4).3), value: e2, }, ty: Foo, @@ -286,9 +270,7 @@ Thir { Expr { kind: Scope { region_scope: Node(2), - lint_level: Explicit( - HirId(DefId(0:12 ~ thir_flat_const_variant[1f54]::main).2), - ), + hir_id: HirId(DefId(0:12 ~ thir_flat_const_variant[1f54]::main).2), value: e0, }, ty: (), diff --git a/tests/ui/thir-print/thir-flat.stdout b/tests/ui/thir-print/thir-flat.stdout index f01d64e60b3d..37106427745e 100644 --- a/tests/ui/thir-print/thir-flat.stdout +++ b/tests/ui/thir-print/thir-flat.stdout @@ -26,9 +26,7 @@ Thir { Expr { kind: Scope { region_scope: Node(2), - lint_level: Explicit( - HirId(DefId(0:3 ~ thir_flat[7b97]::main).2), - ), + hir_id: HirId(DefId(0:3 ~ thir_flat[7b97]::main).2), value: e0, }, ty: (), diff --git a/tests/ui/thir-print/thir-tree-loop-match.stdout b/tests/ui/thir-print/thir-tree-loop-match.stdout index 5f6b130c3905..4a1b2aaf67f5 100644 --- a/tests/ui/thir-print/thir-tree-loop-match.stdout +++ b/tests/ui/thir-print/thir-tree-loop-match.stdout @@ -32,7 +32,7 @@ body: kind: Scope { region_scope: Node(28) - lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).28)) + hir_id: HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).28) value: Expr { ty: bool @@ -53,7 +53,7 @@ body: kind: Scope { region_scope: Node(4) - lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).4)) + hir_id: HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).4) value: Expr { ty: bool @@ -76,7 +76,7 @@ body: kind: Scope { region_scope: Node(7) - lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).7)) + hir_id: HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).7) value: Expr { ty: bool @@ -101,7 +101,7 @@ body: kind: Scope { region_scope: Node(12) - lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).12)) + hir_id: HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).12) value: Expr { ty: bool @@ -135,7 +135,7 @@ body: kind: Scope { region_scope: Node(17) - lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).17)) + hir_id: HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).17) value: Expr { ty: bool @@ -166,7 +166,7 @@ body: kind: Scope { region_scope: Node(19) - lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).19)) + hir_id: HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).19) value: Expr { ty: ! @@ -183,7 +183,7 @@ body: kind: Scope { region_scope: Node(20) - lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).20)) + hir_id: HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).20) value: Expr { ty: bool @@ -209,7 +209,7 @@ body: } } } - lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).16)) + hir_id: HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).16) scope: Node(16) span: $DIR/thir-tree-loop-match.rs:12:17: 15:18 (#0) } @@ -233,7 +233,7 @@ body: kind: Scope { region_scope: Node(25) - lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).25)) + hir_id: HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).25) value: Expr { ty: bool @@ -256,7 +256,7 @@ body: kind: Scope { region_scope: Node(26) - lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).26)) + hir_id: HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).26) value: Expr { ty: bool @@ -275,7 +275,7 @@ body: } } } - lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).24)) + hir_id: HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).24) scope: Node(24) span: $DIR/thir-tree-loop-match.rs:16:17: 16:38 (#0) } @@ -304,7 +304,7 @@ body: kind: Scope { region_scope: Node(2) - lint_level: Explicit(HirId(DefId(0:4 ~ thir_tree_loop_match[3c53]::main).2)) + hir_id: HirId(DefId(0:4 ~ thir_tree_loop_match[3c53]::main).2) value: Expr { ty: () diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout index ecc5fb21435f..a6d23ee204cb 100644 --- a/tests/ui/thir-print/thir-tree-match.stdout +++ b/tests/ui/thir-print/thir-tree-match.stdout @@ -32,7 +32,7 @@ body: kind: Scope { region_scope: Node(28) - lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).28)) + hir_id: HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).28) value: Expr { ty: bool @@ -53,7 +53,7 @@ body: kind: Scope { region_scope: Node(4) - lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).4)) + hir_id: HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).4) value: Expr { ty: bool @@ -69,7 +69,7 @@ body: kind: Scope { region_scope: Node(5) - lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).5)) + hir_id: HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).5) value: Expr { ty: Foo @@ -129,7 +129,7 @@ body: kind: Scope { region_scope: Node(15) - lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).15)) + hir_id: HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).15) value: Expr { ty: bool @@ -141,7 +141,7 @@ body: } } } - lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).14)) + hir_id: HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).14) scope: Node(14) span: $DIR/thir-tree-match.rs:17:9: 17:40 (#0) } @@ -181,7 +181,7 @@ body: kind: Scope { region_scope: Node(21) - lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).21)) + hir_id: HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).21) value: Expr { ty: bool @@ -193,7 +193,7 @@ body: } } } - lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).20)) + hir_id: HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).20) scope: Node(20) span: $DIR/thir-tree-match.rs:18:9: 18:32 (#0) } @@ -225,7 +225,7 @@ body: kind: Scope { region_scope: Node(27) - lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).27)) + hir_id: HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).27) value: Expr { ty: bool @@ -237,7 +237,7 @@ body: } } } - lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).26)) + hir_id: HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).26) scope: Node(26) span: $DIR/thir-tree-match.rs:19:9: 19:28 (#0) } @@ -263,7 +263,7 @@ body: kind: Scope { region_scope: Node(2) - lint_level: Explicit(HirId(DefId(0:17 ~ thir_tree_match[fcf8]::main).2)) + hir_id: HirId(DefId(0:17 ~ thir_tree_match[fcf8]::main).2) value: Expr { ty: () diff --git a/tests/ui/thir-print/thir-tree.stdout b/tests/ui/thir-print/thir-tree.stdout index d61176d6480f..25d0ccfa7a05 100644 --- a/tests/ui/thir-print/thir-tree.stdout +++ b/tests/ui/thir-print/thir-tree.stdout @@ -9,7 +9,7 @@ body: kind: Scope { region_scope: Node(2) - lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree[7aaa]::main).2)) + hir_id: HirId(DefId(0:3 ~ thir_tree[7aaa]::main).2) value: Expr { ty: () diff --git a/tests/ui/unpretty/box.stdout b/tests/ui/unpretty/box.stdout index 54bd98c7a683..123273be4efe 100644 --- a/tests/ui/unpretty/box.stdout +++ b/tests/ui/unpretty/box.stdout @@ -9,7 +9,7 @@ body: kind: Scope { region_scope: Node(11) - lint_level: Explicit(HirId(DefId(0:3 ~ box[efb9]::main).11)) + hir_id: HirId(DefId(0:3 ~ box[efb9]::main).11) value: Expr { ty: () @@ -43,7 +43,7 @@ body: kind: Scope { region_scope: Node(3) - lint_level: Explicit(HirId(DefId(0:3 ~ box[efb9]::main).3)) + hir_id: HirId(DefId(0:3 ~ box[efb9]::main).3) value: Expr { ty: std::boxed::Box @@ -58,7 +58,7 @@ body: kind: Scope { region_scope: Node(8) - lint_level: Explicit(HirId(DefId(0:3 ~ box[efb9]::main).8)) + hir_id: HirId(DefId(0:3 ~ box[efb9]::main).8) value: Expr { ty: i32 @@ -76,7 +76,7 @@ body: } ) else_block: None - lint_level: Explicit(HirId(DefId(0:3 ~ box[efb9]::main).9)) + hir_id: HirId(DefId(0:3 ~ box[efb9]::main).9) span: $DIR/box.rs:7:5: 7:35 (#0) } } From 8868b479a81cdf27e7493c2ac41d2b7efa2dbe89 Mon Sep 17 00:00:00 2001 From: dianne Date: Thu, 8 Jan 2026 16:04:02 -0800 Subject: [PATCH 0722/1061] move `LintLevel` to `rustc_mir_build` --- compiler/rustc_middle/src/thir.rs | 6 ------ compiler/rustc_mir_build/src/builder/block.rs | 1 + .../rustc_mir_build/src/builder/expr/as_operand.rs | 1 + compiler/rustc_mir_build/src/builder/expr/as_place.rs | 1 + compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs | 1 + compiler/rustc_mir_build/src/builder/expr/as_temp.rs | 2 +- compiler/rustc_mir_build/src/builder/expr/into.rs | 1 + compiler/rustc_mir_build/src/builder/expr/stmt.rs | 2 +- compiler/rustc_mir_build/src/builder/matches/mod.rs | 2 +- compiler/rustc_mir_build/src/builder/mod.rs | 4 ++-- compiler/rustc_mir_build/src/builder/scope.rs | 10 +++++++++- 11 files changed, 19 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 86bd6fb803b7..86c19520e072 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -116,12 +116,6 @@ pub struct Param<'tcx> { pub hir_id: Option, } -#[derive(Copy, Clone, Debug, HashStable)] -pub enum LintLevel { - Inherited, - Explicit(HirId), -} - #[derive(Clone, Debug, HashStable)] pub struct Block { /// Whether the block itself has a label. Used by `label: {}` diff --git a/compiler/rustc_mir_build/src/builder/block.rs b/compiler/rustc_mir_build/src/builder/block.rs index d8837d2b195a..bfbb6fa7d169 100644 --- a/compiler/rustc_mir_build/src/builder/block.rs +++ b/compiler/rustc_mir_build/src/builder/block.rs @@ -7,6 +7,7 @@ use tracing::debug; use crate::builder::ForGuard::OutsideGuard; use crate::builder::matches::{DeclareLetBindings, ScheduleDrops}; +use crate::builder::scope::LintLevel; use crate::builder::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; impl<'a, 'tcx> Builder<'a, 'tcx> { diff --git a/compiler/rustc_mir_build/src/builder/expr/as_operand.rs b/compiler/rustc_mir_build/src/builder/expr/as_operand.rs index c9c166b7f018..d2f06cc9d57b 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_operand.rs @@ -6,6 +6,7 @@ use rustc_middle::thir::*; use tracing::{debug, instrument}; use crate::builder::expr::category::Category; +use crate::builder::scope::LintLevel; use crate::builder::{BlockAnd, BlockAndExtension, Builder, NeedsTemporary}; impl<'a, 'tcx> Builder<'a, 'tcx> { diff --git a/compiler/rustc_mir_build/src/builder/expr/as_place.rs b/compiler/rustc_mir_build/src/builder/expr/as_place.rs index db9aa3cd8704..139c6da29d44 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs @@ -16,6 +16,7 @@ use tracing::{debug, instrument, trace}; use crate::builder::ForGuard::{OutsideGuard, RefWithinGuard}; use crate::builder::expr::category::Category; +use crate::builder::scope::LintLevel; use crate::builder::{BlockAnd, BlockAndExtension, Builder, Capture, CaptureMap}; /// The "outermost" place that holds this value. diff --git a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs index 3d1774bd1d68..8de79ab2531f 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs @@ -18,6 +18,7 @@ use tracing::debug; use crate::builder::expr::as_place::PlaceBase; use crate::builder::expr::category::{Category, RvalueFunc}; +use crate::builder::scope::LintLevel; use crate::builder::{BlockAnd, BlockAndExtension, Builder, NeedsTemporary}; impl<'a, 'tcx> Builder<'a, 'tcx> { diff --git a/compiler/rustc_mir_build/src/builder/expr/as_temp.rs b/compiler/rustc_mir_build/src/builder/expr/as_temp.rs index 2aace64062cd..55296c647c81 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_temp.rs @@ -7,7 +7,7 @@ use rustc_middle::mir::*; use rustc_middle::thir::*; use tracing::{debug, instrument}; -use crate::builder::scope::DropKind; +use crate::builder::scope::{DropKind, LintLevel}; use crate::builder::{BlockAnd, BlockAndExtension, Builder}; impl<'a, 'tcx> Builder<'a, 'tcx> { diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index 9731f0de135f..60e05b691a83 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -16,6 +16,7 @@ use tracing::{debug, instrument}; use crate::builder::expr::category::{Category, RvalueFunc}; use crate::builder::matches::{DeclareLetBindings, HasMatchGuard}; +use crate::builder::scope::LintLevel; use crate::builder::{BlockAnd, BlockAndExtension, BlockFrame, Builder, NeedsTemporary}; use crate::errors::{LoopMatchArmWithGuard, LoopMatchUnsupportedType}; diff --git a/compiler/rustc_mir_build/src/builder/expr/stmt.rs b/compiler/rustc_mir_build/src/builder/expr/stmt.rs index f28e483b6a5d..3d603afbaa4a 100644 --- a/compiler/rustc_mir_build/src/builder/expr/stmt.rs +++ b/compiler/rustc_mir_build/src/builder/expr/stmt.rs @@ -5,7 +5,7 @@ use rustc_middle::thir::*; use rustc_span::source_map::Spanned; use tracing::debug; -use crate::builder::scope::BreakableTarget; +use crate::builder::scope::{BreakableTarget, LintLevel}; use crate::builder::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; impl<'a, 'tcx> Builder<'a, 'tcx> { diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 49caee4a1896..565d97fa68b8 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -29,7 +29,7 @@ use crate::builder::ForGuard::{self, OutsideGuard, RefWithinGuard}; use crate::builder::expr::as_place::PlaceBuilder; use crate::builder::matches::buckets::PartitionedCandidates; use crate::builder::matches::user_ty::ProjectedUserTypesNode; -use crate::builder::scope::DropKind; +use crate::builder::scope::{DropKind, LintLevel}; use crate::builder::{ BlockAnd, BlockAndExtension, Builder, GuardFrame, GuardFrameLocal, LocalsForNode, }; diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 40f1fe0d5d11..132062961da6 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -38,14 +38,14 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_middle::hir::place::PlaceBase as HirPlaceBase; use rustc_middle::middle::region; use rustc_middle::mir::*; -use rustc_middle::thir::{self, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir}; +use rustc_middle::thir::{self, ExprId, LocalVarId, Param, ParamId, PatKind, Thir}; use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt, TypeVisitableExt, TypingMode}; use rustc_middle::{bug, span_bug}; use rustc_session::lint; use rustc_span::{Span, Symbol, sym}; use crate::builder::expr::as_place::PlaceBuilder; -use crate::builder::scope::DropKind; +use crate::builder::scope::{DropKind, LintLevel}; use crate::errors; pub(crate) fn closure_saved_names_of_captured_variables<'tcx>( diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index 981704052536..b10df60e0f75 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -89,7 +89,7 @@ use rustc_hir::HirId; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::middle::region; use rustc_middle::mir::{self, *}; -use rustc_middle::thir::{AdtExpr, AdtExprBase, ArmId, ExprId, ExprKind, LintLevel}; +use rustc_middle::thir::{AdtExpr, AdtExprBase, ArmId, ExprId, ExprKind}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, ValTree}; use rustc_middle::{bug, span_bug}; use rustc_pattern_analysis::rustc::RustcPatCtxt; @@ -522,6 +522,14 @@ impl<'tcx> Scopes<'tcx> { } } +/// Used by [`Builder::in_scope`] to create source scopes mapping from MIR back to HIR at points +/// where lint levels change. +#[derive(Copy, Clone, Debug)] +pub(crate) enum LintLevel { + Inherited, + Explicit(HirId), +} + impl<'a, 'tcx> Builder<'a, 'tcx> { // Adding and removing scopes // ========================== From cd79ff2e2c804c626c5ab0dce701077afc35db83 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Thu, 15 Jan 2026 09:37:16 +0800 Subject: [PATCH 0723/1061] Revert "avoid phi node for pointers flowing into Vec appends #130998" This reverts PR because the added test seems to be flaky / non-deterministic, and has been failing in unrelated PRs during merge CI. --- compiler/rustc_codegen_llvm/src/attributes.rs | 11 +------ library/alloc/src/slice.rs | 8 ++--- library/alloc/src/vec/mod.rs | 6 +--- .../lib-optimizations/append-elements.rs | 30 ------------------- 4 files changed, 5 insertions(+), 50 deletions(-) delete mode 100644 tests/codegen-llvm/lib-optimizations/append-elements.rs diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index bf6bb81b53b0..a25ce9e5a90a 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -517,16 +517,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( to_add.push(llvm::CreateAllocKindAttr(cx.llcx, AllocKindFlags::Free)); // applies to argument place instead of function place let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx); - let attrs: &[_] = if llvm_util::get_version() >= (21, 0, 0) { - // "Does not capture provenance" means "if the function call stashes the pointer somewhere, - // accessing that pointer after the function returns is UB". That is definitely the case here since - // freeing will destroy the provenance. - let captures_addr = AttributeKind::CapturesAddress.create_attr(cx.llcx); - &[allocated_pointer, captures_addr] - } else { - &[allocated_pointer] - }; - attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), attrs); + attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]); } if let Some(align) = codegen_fn_attrs.alignment { llvm::set_alignment(llfn, align); diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 58abf4bd6571..e7d0fc3454ee 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -448,11 +448,9 @@ impl [T] { // SAFETY: // allocated above with the capacity of `s`, and initialize to `s.len()` in // ptr::copy_to_non_overlapping below. - if s.len() > 0 { - unsafe { - s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len()); - v.set_len(s.len()); - } + unsafe { + s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len()); + v.set_len(s.len()); } v } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index ac86399df7ab..379e964f0a0c 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2818,11 +2818,7 @@ impl Vec { let count = other.len(); self.reserve(count); let len = self.len(); - if count > 0 { - unsafe { - ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count) - }; - } + unsafe { ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count) }; self.len += count; } diff --git a/tests/codegen-llvm/lib-optimizations/append-elements.rs b/tests/codegen-llvm/lib-optimizations/append-elements.rs deleted file mode 100644 index 8ee520a131f0..000000000000 --- a/tests/codegen-llvm/lib-optimizations/append-elements.rs +++ /dev/null @@ -1,30 +0,0 @@ -//@ compile-flags: -O -Zmerge-functions=disabled -//@ min-llvm-version: 21 -#![crate_type = "lib"] - -//! Check that a temporary intermediate allocations can eliminated and replaced -//! with memcpy forwarding. -//! This requires Vec code to be structured in a way that avoids phi nodes from the -//! zero-capacity length flowing into the memcpy arguments. - -// CHECK-LABEL: @vec_append_with_temp_alloc -#[no_mangle] -pub fn vec_append_with_temp_alloc(dst: &mut Vec, src: &[u8]) { - // CHECK-NOT: call void @llvm.memcpy - // CHECK: call void @llvm.memcpy.{{.*}}%dst.i{{.*}}%src.0 - // CHECK-NOT: call void @llvm.memcpy - let temp = src.to_vec(); - dst.extend(&temp); - // CHECK: ret -} - -// CHECK-LABEL: @string_append_with_temp_alloc -#[no_mangle] -pub fn string_append_with_temp_alloc(dst: &mut String, src: &str) { - // CHECK-NOT: call void @llvm.memcpy - // CHECK: call void @llvm.memcpy.{{.*}}%dst.i{{.*}}%src.0 - // CHECK-NOT: call void @llvm.memcpy - let temp = src.to_string(); - dst.push_str(&temp); - // CHECK: ret -} From df386c5b48e2b3a3dabae22f2b018501f5abcbe8 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 30 Dec 2025 16:57:56 -0500 Subject: [PATCH 0724/1061] Test that -Zbuild-std=core works on a variety of profiles --- Cargo.lock | 1 + .../src/spec/targets/i586_unknown_redox.rs | 2 +- .../spec/targets/x86_64_unknown_linux_none.rs | 2 +- .../src/spec/targets/xtensa_esp32_espidf.rs | 2 +- .../src/spec/targets/xtensa_esp32s2_espidf.rs | 2 +- .../src/spec/targets/xtensa_esp32s3_espidf.rs | 2 +- src/bootstrap/mk/Makefile.in | 5 + src/bootstrap/src/core/build_steps/test.rs | 8 +- src/bootstrap/src/core/builder/cli_paths.rs | 1 + .../cli_paths/snapshots/x_test_tests.snap | 3 + .../snapshots/x_test_tests_skip_coverage.snap | 3 + src/bootstrap/src/core/builder/mod.rs | 1 + src/bootstrap/src/core/builder/tests.rs | 4 +- .../rustc-dev-guide/src/tests/compiletest.md | 10 ++ src/tools/compiletest/src/common.rs | 1 + src/tools/compiletest/src/runtest/run_make.rs | 4 +- src/tools/run-make-support/Cargo.toml | 1 + src/tools/run-make-support/src/command.rs | 13 ++ src/tools/run-make-support/src/lib.rs | 4 +- src/tools/run-make-support/src/util.rs | 3 + tests/build-std/configurations/rmake.rs | 131 ++++++++++++++++++ 21 files changed, 192 insertions(+), 11 deletions(-) create mode 100644 tests/build-std/configurations/rmake.rs diff --git a/Cargo.lock b/Cargo.lock index bf28939ac87b..bf0bc9234d39 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3334,6 +3334,7 @@ dependencies = [ "rustdoc-json-types", "serde_json", "similar", + "tempfile", "wasmparser 0.236.1", ] diff --git a/compiler/rustc_target/src/spec/targets/i586_unknown_redox.rs b/compiler/rustc_target/src/spec/targets/i586_unknown_redox.rs index 935666630dae..56e1c8a9705d 100644 --- a/compiler/rustc_target/src/spec/targets/i586_unknown_redox.rs +++ b/compiler/rustc_target/src/spec/targets/i586_unknown_redox.rs @@ -11,7 +11,7 @@ pub(crate) fn target() -> Target { Target { llvm_target: "i586-unknown-redox".into(), - metadata: TargetMetadata { description: None, tier: None, host_tools: None, std: None }, + metadata: TargetMetadata { description: None, tier: Some(3), host_tools: None, std: None }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128" diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_none.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_none.rs index ecf232f1ab2f..768b1a1ba112 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_none.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_none.rs @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { llvm_target: "x86_64-unknown-linux-none".into(), metadata: TargetMetadata { description: None, - tier: None, + tier: Some(3), host_tools: None, std: Some(false), }, diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32_espidf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32_espidf.rs index 83835705f3da..0fb4d186087b 100644 --- a/compiler/rustc_target/src/spec/targets/xtensa_esp32_espidf.rs +++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32_espidf.rs @@ -9,7 +9,7 @@ pub(crate) fn target() -> Target { pointer_width: 32, data_layout: "e-m:e-p:32:32-v1:8:8-i64:64-i128:128-n32".into(), arch: Arch::Xtensa, - metadata: TargetMetadata { description: None, tier: None, host_tools: None, std: None }, + metadata: TargetMetadata { description: None, tier: Some(3), host_tools: None, std: None }, options: TargetOptions { endian: Endian::Little, diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs index 42e4c7bf8bec..81eab657db71 100644 --- a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs +++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs @@ -9,7 +9,7 @@ pub(crate) fn target() -> Target { pointer_width: 32, data_layout: "e-m:e-p:32:32-v1:8:8-i64:64-i128:128-n32".into(), arch: Arch::Xtensa, - metadata: TargetMetadata { description: None, tier: None, host_tools: None, std: None }, + metadata: TargetMetadata { description: None, tier: Some(3), host_tools: None, std: None }, options: TargetOptions { endian: Endian::Little, diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs index 498daf4e6063..fb1f4f471979 100644 --- a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs +++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs @@ -9,7 +9,7 @@ pub(crate) fn target() -> Target { pointer_width: 32, data_layout: "e-m:e-p:32:32-v1:8:8-i64:64-i128:128-n32".into(), arch: Arch::Xtensa, - metadata: TargetMetadata { description: None, tier: None, host_tools: None, std: None }, + metadata: TargetMetadata { description: None, tier: Some(3), host_tools: None, std: None }, options: TargetOptions { endian: Endian::Little, diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 6bef58a0ac20..5f956f03ecb1 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -53,6 +53,11 @@ check-aux: src/tools/cargotest \ src/tools/test-float-parse \ $(BOOTSTRAP_ARGS) + # The build-std suite is off by default because it is uncommonly slow + # and memory-hungry. + $(Q)$(BOOTSTRAP) test --stage 2 \ + build-std \ + $(BOOTSTRAP_ARGS) # Run standard library tests in Miri. $(Q)MIRIFLAGS="-Zmiri-strict-provenance" \ $(BOOTSTRAP) miri --stage 2 \ diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index f3a1c6b0e3dd..080931fc0a93 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1625,6 +1625,12 @@ test!(RunMakeCargo { suite: "run-make-cargo", default: true }); +test!(BuildStd { + path: "tests/build-std", + mode: CompiletestMode::RunMake, + suite: "build-std", + default: false +}); test!(AssemblyLlvm { path: "tests/assembly-llvm", @@ -1948,7 +1954,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the let stage0_rustc_path = builder.compiler(0, test_compiler.host); cmd.arg("--stage0-rustc-path").arg(builder.rustc(stage0_rustc_path)); - if suite == "run-make-cargo" { + if matches!(suite, "run-make-cargo" | "build-std") { let cargo_path = if test_compiler.stage == 0 { // If we're using `--stage 0`, we should provide the bootstrap cargo. builder.initial_cargo.clone() diff --git a/src/bootstrap/src/core/builder/cli_paths.rs b/src/bootstrap/src/core/builder/cli_paths.rs index 5ff2b380e4b9..1b0caa980e1d 100644 --- a/src/bootstrap/src/core/builder/cli_paths.rs +++ b/src/bootstrap/src/core/builder/cli_paths.rs @@ -20,6 +20,7 @@ pub(crate) const PATH_REMAP: &[(&str, &[&str])] = &[ &[ // tidy-alphabetical-start "tests/assembly-llvm", + "tests/build-std", "tests/codegen-llvm", "tests/codegen-units", "tests/coverage", diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_tests.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_tests.snap index ad9660ef5c91..65349a59a1e8 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_tests.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_tests.snap @@ -5,6 +5,9 @@ expression: test tests [Test] test::AssemblyLlvm targets: [aarch64-unknown-linux-gnu] - Suite(test::tests/assembly-llvm) +[Test] test::BuildStd + targets: [aarch64-unknown-linux-gnu] + - Suite(test::tests/build-std) [Test] test::CodegenLlvm targets: [aarch64-unknown-linux-gnu] - Suite(test::tests/codegen-llvm) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_tests_skip_coverage.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_tests_skip_coverage.snap index 4572f089b0ae..694bb0672ee4 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_tests_skip_coverage.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_tests_skip_coverage.snap @@ -5,6 +5,9 @@ expression: test tests --skip=coverage [Test] test::AssemblyLlvm targets: [aarch64-unknown-linux-gnu] - Suite(test::tests/assembly-llvm) +[Test] test::BuildStd + targets: [aarch64-unknown-linux-gnu] + - Suite(test::tests/build-std) [Test] test::CodegenLlvm targets: [aarch64-unknown-linux-gnu] - Suite(test::tests/codegen-llvm) diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 4a04b97c549a..7f98e42227af 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -927,6 +927,7 @@ impl<'a> Builder<'a> { test::CollectLicenseMetadata, test::RunMake, test::RunMakeCargo, + test::BuildStd, ), Kind::Miri => describe!(test::Crate), Kind::Bench => describe!(test::Crate, test::CrateLibrustc, test::CrateRustdoc), diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 66614cc6cced..af26c2f87d02 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2077,7 +2077,7 @@ mod snapshot { let ctx = TestCtx::new(); insta::assert_snapshot!( prepare_test_config(&ctx) - .render_steps(), @r" + .render_steps(), @" [build] rustc 0 -> Tidy 1 [test] tidy <> [build] rustdoc 0 @@ -2255,7 +2255,7 @@ mod snapshot { insta::assert_snapshot!( prepare_test_config(&ctx) .stage(2) - .render_steps(), @r" + .render_steps(), @" [build] rustc 0 -> Tidy 1 [test] tidy <> [build] rustdoc 0 diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md index d69e0a5ce988..7f22bc27600c 100644 --- a/src/doc/rustc-dev-guide/src/tests/compiletest.md +++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md @@ -78,6 +78,10 @@ The following test suites are available, with links for more information: [`run-make`](#run-make-tests) are general purpose tests using Rust programs. +### The build-std test suite + +[`build-std`](#build-std-tests) test that -Zbuild-std works. + ### Rustdoc test suites | Test suite | Purpose | @@ -429,6 +433,12 @@ use cases that require testing in-tree `cargo` in conjunction with in-tree `rust The `run-make` test suite does not have access to in-tree `cargo` (so it can be the faster-to-iterate test suite). +### `build-std` tests + +The tests in [`tests/build-std`] check that `-Zbuild-std` works. This is currently +just a run-make test suite with a single recipe. The recipe generates test cases +and runs them in parallel. + #### Using Rust recipes Each test should be in a separate directory with a `rmake.rs` Rust program, diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index a2f3a8f00dac..843b4ad2975d 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -77,6 +77,7 @@ string_enum! { RustdocUi => "rustdoc-ui", Ui => "ui", UiFullDeps => "ui-fulldeps", + BuildStd => "build-std", } } diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs index 4eb8f91fe894..ac8846a263c0 100644 --- a/src/tools/compiletest/src/runtest/run_make.rs +++ b/src/tools/compiletest/src/runtest/run_make.rs @@ -190,8 +190,8 @@ impl TestCx<'_> { // through a specific CI runner). .env("LLVM_COMPONENTS", &self.config.llvm_components); - // Only `run-make-cargo` test suite gets an in-tree `cargo`, not `run-make`. - if self.config.suite == TestSuite::RunMakeCargo { + // The `run-make-cargo` and `build-std` suites need an in-tree `cargo`, `run-make` does not. + if matches!(self.config.suite, TestSuite::RunMakeCargo | TestSuite::BuildStd) { cmd.env( "CARGO", self.config.cargo_path.as_ref().expect("cargo must be built and made available"), diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index 9d9cd656f570..918f5ef0d506 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -17,6 +17,7 @@ object = "0.37" regex = "1.11" serde_json = "1.0" similar = "2.7" +tempfile = "3" wasmparser = { version = "0.236", default-features = false, features = ["std", "features", "validate"] } # tidy-alphabetical-end diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs index 0aeb189bb6a5..f4a09f9faae8 100644 --- a/src/tools/run-make-support/src/command.rs +++ b/src/tools/run-make-support/src/command.rs @@ -46,6 +46,8 @@ pub struct Command { // Emulate linear type semantics. drop_bomb: DropBomb, already_executed: bool, + + context: String, } impl Command { @@ -60,6 +62,7 @@ impl Command { stdout: None, stderr: None, already_executed: false, + context: String::new(), } } @@ -69,6 +72,16 @@ impl Command { self.cmd } + pub(crate) fn get_context(&self) -> &str { + &self.context + } + + /// Appends context to the command, to provide a better error message if the command fails. + pub fn context(&mut self, ctx: &str) -> &mut Self { + self.context.push_str(&format!("{ctx}\n")); + self + } + /// Specify a stdin input buffer. This is a convenience helper, pub fn stdin_buf>(&mut self, input: I) -> &mut Self { self.stdin_buf = Some(input.as_ref().to_vec().into_boxed_slice()); diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 5253dc04a93e..b19d73b78a94 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -34,7 +34,9 @@ pub mod rfs { } // Re-exports of third-party library crates. -pub use {bstr, gimli, libc, object, regex, rustdoc_json_types, serde_json, similar, wasmparser}; +pub use { + bstr, gimli, libc, object, regex, rustdoc_json_types, serde_json, similar, tempfile, wasmparser, +}; // Helpers for building names of output artifacts that are potentially target-specific. pub use crate::artifact_names::{ diff --git a/src/tools/run-make-support/src/util.rs b/src/tools/run-make-support/src/util.rs index af01758447b9..7908dc1f7b3d 100644 --- a/src/tools/run-make-support/src/util.rs +++ b/src/tools/run-make-support/src/util.rs @@ -21,6 +21,9 @@ pub(crate) fn handle_failed_output( eprintln!("output status: `{}`", output.status()); eprintln!("=== STDOUT ===\n{}\n\n", output.stdout_utf8()); eprintln!("=== STDERR ===\n{}\n\n", output.stderr_utf8()); + if !cmd.get_context().is_empty() { + eprintln!("Context:\n{}", cmd.get_context()); + } std::process::exit(1) } diff --git a/tests/build-std/configurations/rmake.rs b/tests/build-std/configurations/rmake.rs new file mode 100644 index 000000000000..99cb9f9b0f4d --- /dev/null +++ b/tests/build-std/configurations/rmake.rs @@ -0,0 +1,131 @@ +// This test ensures we are able to compile -Zbuild-std=core under a variety of profiles. +// Currently, it tests that we can compile to all Tier 1 targets, and it does this by checking what +// the tier metadata in target-spec JSON. This means that all in-tree targets must have a tier set. + +#![deny(warnings)] + +use std::collections::HashMap; +use std::sync::{Arc, Mutex}; +use std::thread; + +use run_make_support::serde_json::{self, Value}; +use run_make_support::tempfile::TempDir; +use run_make_support::{cargo, rfs, rustc}; + +#[derive(Clone)] +struct Task { + target: String, + opt_level: u8, + debug: u8, + panic: &'static str, +} + +fn manifest(task: &Task) -> String { + let Task { opt_level, debug, panic, target: _ } = task; + format!( + r#"[package] +name = "scratch" +version = "0.1.0" +edition = "2024" + +[lib] +path = "lib.rs" + +[profile.release] +opt-level = {opt_level} +debug = {debug} +panic = "{panic}" +"# + ) +} + +fn main() { + let mut targets = Vec::new(); + let all_targets = + rustc().args(&["--print=all-target-specs-json", "-Zunstable-options"]).run().stdout_utf8(); + let all_targets: HashMap = serde_json::from_str(&all_targets).unwrap(); + for (target, spec) in all_targets { + let metadata = spec.as_object().unwrap()["metadata"].as_object().unwrap(); + let tier = metadata["tier"] + .as_u64() + .expect(&format!("Target {} is missing tier metadata", target)); + if tier == 1 { + targets.push(target); + } + } + + let mut tasks = Vec::new(); + + // Testing every combination of compiler flags is infeasible. So we are making some attempt to + // choose combinations that will tend to run into problems. + // + // The particular combination of settings below is tuned to look for problems generating the + // code for compiler-builtins. + // We only exercise opt-level 0 and 3 to exercise mir-opt-level 1 and 2. + // We only exercise debug 0 and 2 because level 2 turns off some MIR optimizations. + // We only test abort and immediate-abort because abort vs unwind doesn't change MIR much at + // all. but immediate-abort does. + // + // Currently this only tests that we can compile the tier 1 targets. But since we are using + // -Zbuild-std=core, we could have any list of targets. + + for opt_level in [0, 3] { + for debug in [0, 2] { + for panic in ["abort", "immediate-abort"] { + for target in &targets { + tasks.push(Task { target: target.clone(), opt_level, debug, panic }); + } + } + } + } + + let tasks = Arc::new(Mutex::new(tasks)); + let mut threads = Vec::new(); + + // Try to obey the -j argument passed to bootstrap, otherwise fall back to using all the system + // resouces. This test can be rather memory-hungry (~1 GB/thread); if it causes trouble in + // practice do not hesitate to limit its parallelism. + for _ in 0..run_make_support::env::jobs() { + let tasks = Arc::clone(&tasks); + let handle = thread::spawn(move || { + loop { + let maybe_task = tasks.lock().unwrap().pop(); + if let Some(task) = maybe_task { + test(task); + } else { + break; + } + } + }); + threads.push(handle); + } + + for t in threads { + t.join().unwrap(); + } +} + +fn test(task: Task) { + let dir = TempDir::new().unwrap(); + + let manifest = manifest(&task); + rfs::write(dir.path().join("Cargo.toml"), &manifest); + rfs::write(dir.path().join("lib.rs"), "#![no_std]"); + + let mut args = vec!["build", "--release", "-Zbuild-std=core", "--target", &task.target, "-j1"]; + if task.panic == "immediate-abort" { + args.push("-Zpanic-immediate-abort"); + } + cargo() + .current_dir(dir.path()) + .args(&args) + .env("RUSTC_BOOTSTRAP", "1") + // Visual Studio 2022 requires that the LIB env var be set so it can + // find the Windows SDK. + .env("LIB", std::env::var("LIB").unwrap_or_default()) + .context(&format!( + "build-std for target `{}` failed with the following Cargo.toml:\n\n{manifest}", + task.target + )) + .run(); +} From d59c47c2bc933f46e63ea5f23618f9618c0b9f51 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Thu, 15 Jan 2026 05:01:05 +0000 Subject: [PATCH 0725/1061] Prepare for merging from rust-lang/rust This updates the rust-version file to b6fdaf2a15736cbccf248b532f48e33179614d40. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index b53a66c66751..a6ccd9bab393 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -44a5b55557c26353f388400d7da95527256fe260 +b6fdaf2a15736cbccf248b532f48e33179614d40 From d7e5996e4f55158af402fc77322812bea46eb8c2 Mon Sep 17 00:00:00 2001 From: Hugh Date: Wed, 14 Jan 2026 23:12:46 -0800 Subject: [PATCH 0726/1061] Skip elidable_lifetime_names lint for proc-macro generated code When linting code generated by proc macros (like `derivative`), the `elidable_lifetime_names` lint can produce fix suggestions with overlapping spans. This causes `cargo clippy --fix` to fail with "cannot replace slice of data that was already replaced". This change adds `is_from_proc_macro` checks to the three lint entry points (`check_item`, `check_impl_item`, `check_trait_item`) to skip linting proc-macro generated code entirely. Fixes #16316 --- clippy_lints/src/lifetimes.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 727e9b172a87..8917c90262a4 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::trait_ref_of_method; +use clippy_utils::{is_from_proc_macro, trait_ref_of_method}; use itertools::Itertools; use rustc_ast::visit::{try_visit, walk_list}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; @@ -149,16 +149,22 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { .. } = item.kind { + if is_from_proc_macro(cx, item) { + return; + } check_fn_inner(cx, sig, Some(id), None, generics, item.span, true, self.msrv); } else if let ItemKind::Impl(impl_) = &item.kind && !item.span.from_expansion() + && !is_from_proc_macro(cx, item) { report_extra_impl_lifetimes(cx, impl_); } } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { - if let ImplItemKind::Fn(ref sig, id) = item.kind { + if let ImplItemKind::Fn(ref sig, id) = item.kind + && !is_from_proc_macro(cx, item) + { let report_extra_lifetimes = trait_ref_of_method(cx, item.owner_id).is_none(); check_fn_inner( cx, @@ -174,7 +180,9 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { - if let TraitItemKind::Fn(ref sig, ref body) = item.kind { + if let TraitItemKind::Fn(ref sig, ref body) = item.kind + && !is_from_proc_macro(cx, item) + { let (body, trait_sig) = match *body { TraitFn::Required(sig) => (None, Some(sig)), TraitFn::Provided(id) => (Some(id), None), From cd05071ec4a4b62d469603fb7b89d0a35857cbe1 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 14 Jan 2026 20:18:09 +0300 Subject: [PATCH 0727/1061] resolve: Downgrade `ambiguous_glob_imports` to warn-by-default But still keep it report-in-deps. To revert after ~February 27 2026, when Rust 1.95 branches out from the main branch. --- compiler/rustc_lint_defs/src/builtin.rs | 2 +- tests/ui/imports/ambiguous-10.rs | 4 ++-- tests/ui/imports/ambiguous-10.stderr | 10 ++++----- tests/ui/imports/ambiguous-12.rs | 4 ++-- tests/ui/imports/ambiguous-12.stderr | 10 ++++----- tests/ui/imports/ambiguous-13.rs | 4 ++-- tests/ui/imports/ambiguous-13.stderr | 10 ++++----- tests/ui/imports/ambiguous-14.rs | 4 ++-- tests/ui/imports/ambiguous-14.stderr | 10 ++++----- tests/ui/imports/ambiguous-15.rs | 4 ++-- tests/ui/imports/ambiguous-15.stderr | 10 ++++----- tests/ui/imports/ambiguous-16.rs | 4 ++-- tests/ui/imports/ambiguous-16.stderr | 10 ++++----- tests/ui/imports/ambiguous-17.rs | 4 ++-- tests/ui/imports/ambiguous-17.stderr | 10 ++++----- tests/ui/imports/ambiguous-2.rs | 4 ++-- tests/ui/imports/ambiguous-2.stderr | 10 ++++----- tests/ui/imports/ambiguous-3.rs | 4 ++-- tests/ui/imports/ambiguous-3.stderr | 10 ++++----- tests/ui/imports/ambiguous-4.rs | 4 ++-- tests/ui/imports/ambiguous-4.stderr | 10 ++++----- tests/ui/imports/ambiguous-5.rs | 4 ++-- tests/ui/imports/ambiguous-5.stderr | 10 ++++----- tests/ui/imports/ambiguous-6.rs | 4 ++-- tests/ui/imports/ambiguous-6.stderr | 10 ++++----- tests/ui/imports/ambiguous-9.rs | 6 ++--- tests/ui/imports/ambiguous-9.stderr | 16 +++++++------- .../ui/imports/ambiguous-panic-globvsglob.rs | 4 ++-- .../imports/ambiguous-panic-globvsglob.stderr | 10 ++++----- tests/ui/imports/duplicate.rs | 2 +- tests/ui/imports/duplicate.stderr | 10 ++++----- .../ui/imports/glob-conflict-cross-crate-1.rs | 6 ++--- .../glob-conflict-cross-crate-1.stderr | 16 +++++++------- .../ui/imports/glob-conflict-cross-crate-2.rs | 4 ++-- .../glob-conflict-cross-crate-2.stderr | 10 ++++----- .../ui/imports/glob-conflict-cross-crate-3.rs | 6 ++--- .../glob-conflict-cross-crate-3.stderr | 16 +++++++------- tests/ui/imports/issue-114682-2.rs | 6 ++--- tests/ui/imports/issue-114682-2.stderr | 16 +++++++------- tests/ui/imports/issue-114682-4.rs | 2 +- tests/ui/imports/issue-114682-4.stderr | 10 ++++----- tests/ui/imports/issue-114682-5.rs | 2 +- tests/ui/imports/issue-114682-5.stderr | 10 ++++----- tests/ui/imports/issue-114682-6.rs | 4 ++-- tests/ui/imports/issue-114682-6.stderr | 10 ++++----- .../ui/imports/overwrite-different-ambig-2.rs | 4 +++- .../overwrite-different-ambig-2.stderr | 22 +++++++++---------- .../imports/unresolved-seg-after-ambiguous.rs | 2 +- .../unresolved-seg-after-ambiguous.stderr | 10 ++++----- 49 files changed, 188 insertions(+), 186 deletions(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 4230aa7568e2..c165b91cc916 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -4465,7 +4465,7 @@ declare_lint! { /// /// [future-incompatible]: ../index.md#future-incompatible-lints pub AMBIGUOUS_GLOB_IMPORTS, - Deny, + Warn, "detects certain glob imports that require reporting an ambiguity error", @future_incompatible = FutureIncompatibleInfo { reason: fcw!(FutureReleaseError #114095), diff --git a/tests/ui/imports/ambiguous-10.rs b/tests/ui/imports/ambiguous-10.rs index 166b01ede12d..61069cb75124 100644 --- a/tests/ui/imports/ambiguous-10.rs +++ b/tests/ui/imports/ambiguous-10.rs @@ -1,5 +1,5 @@ // https://github.com/rust-lang/rust/pull/113099#issuecomment-1637022296 - +//@ check-pass mod a { pub enum Token {} } @@ -13,6 +13,6 @@ mod b { use crate::a::*; use crate::b::*; fn c(_: Token) {} -//~^ ERROR `Token` is ambiguous +//~^ WARN `Token` is ambiguous //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! fn main() { } diff --git a/tests/ui/imports/ambiguous-10.stderr b/tests/ui/imports/ambiguous-10.stderr index f175d27c99e9..4ae3e4203fab 100644 --- a/tests/ui/imports/ambiguous-10.stderr +++ b/tests/ui/imports/ambiguous-10.stderr @@ -1,4 +1,4 @@ -error: `Token` is ambiguous +warning: `Token` is ambiguous --> $DIR/ambiguous-10.rs:15:9 | LL | fn c(_: Token) {} @@ -19,12 +19,12 @@ note: `Token` could also refer to the enum imported here LL | use crate::b::*; | ^^^^^^^^^^^ = help: consider adding an explicit import of `Token` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default -error: aborting due to 1 previous error +warning: 1 warning emitted Future incompatibility report: Future breakage diagnostic: -error: `Token` is ambiguous +warning: `Token` is ambiguous --> $DIR/ambiguous-10.rs:15:9 | LL | fn c(_: Token) {} @@ -45,5 +45,5 @@ note: `Token` could also refer to the enum imported here LL | use crate::b::*; | ^^^^^^^^^^^ = help: consider adding an explicit import of `Token` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default diff --git a/tests/ui/imports/ambiguous-12.rs b/tests/ui/imports/ambiguous-12.rs index 543396b8dfe5..93cd3ca6f347 100644 --- a/tests/ui/imports/ambiguous-12.rs +++ b/tests/ui/imports/ambiguous-12.rs @@ -1,5 +1,5 @@ // https://github.com/rust-lang/rust/pull/113099#issuecomment-1637022296 - +//@ check-pass macro_rules! m { () => { pub fn b() {} @@ -19,6 +19,6 @@ use crate::public::*; fn main() { b(); - //~^ ERROR `b` is ambiguous + //~^ WARN `b` is ambiguous //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! } diff --git a/tests/ui/imports/ambiguous-12.stderr b/tests/ui/imports/ambiguous-12.stderr index 5f92eae0dbcb..1a1777dedac4 100644 --- a/tests/ui/imports/ambiguous-12.stderr +++ b/tests/ui/imports/ambiguous-12.stderr @@ -1,4 +1,4 @@ -error: `b` is ambiguous +warning: `b` is ambiguous --> $DIR/ambiguous-12.rs:21:5 | LL | b(); @@ -19,12 +19,12 @@ note: `b` could also refer to the function imported here LL | use crate::public::*; | ^^^^^^^^^^^^^^^^ = help: consider adding an explicit import of `b` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default -error: aborting due to 1 previous error +warning: 1 warning emitted Future incompatibility report: Future breakage diagnostic: -error: `b` is ambiguous +warning: `b` is ambiguous --> $DIR/ambiguous-12.rs:21:5 | LL | b(); @@ -45,5 +45,5 @@ note: `b` could also refer to the function imported here LL | use crate::public::*; | ^^^^^^^^^^^^^^^^ = help: consider adding an explicit import of `b` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default diff --git a/tests/ui/imports/ambiguous-13.rs b/tests/ui/imports/ambiguous-13.rs index 3569dd5d9adc..5fbb71d8545a 100644 --- a/tests/ui/imports/ambiguous-13.rs +++ b/tests/ui/imports/ambiguous-13.rs @@ -1,5 +1,5 @@ // https://github.com/rust-lang/rust/pull/113099#issuecomment-1637022296 - +//@ check-pass pub mod object { #[derive(Debug)] pub struct Rect; @@ -16,6 +16,6 @@ use crate::object::*; use crate::content::*; fn a(_: Rect) {} -//~^ ERROR `Rect` is ambiguous +//~^ WARN `Rect` is ambiguous //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! fn main() { } diff --git a/tests/ui/imports/ambiguous-13.stderr b/tests/ui/imports/ambiguous-13.stderr index 279b4e8f1420..ca83cf63c12c 100644 --- a/tests/ui/imports/ambiguous-13.stderr +++ b/tests/ui/imports/ambiguous-13.stderr @@ -1,4 +1,4 @@ -error: `Rect` is ambiguous +warning: `Rect` is ambiguous --> $DIR/ambiguous-13.rs:18:9 | LL | fn a(_: Rect) {} @@ -19,12 +19,12 @@ note: `Rect` could also refer to the struct imported here LL | use crate::content::*; | ^^^^^^^^^^^^^^^^^ = help: consider adding an explicit import of `Rect` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default -error: aborting due to 1 previous error +warning: 1 warning emitted Future incompatibility report: Future breakage diagnostic: -error: `Rect` is ambiguous +warning: `Rect` is ambiguous --> $DIR/ambiguous-13.rs:18:9 | LL | fn a(_: Rect) {} @@ -45,5 +45,5 @@ note: `Rect` could also refer to the struct imported here LL | use crate::content::*; | ^^^^^^^^^^^^^^^^^ = help: consider adding an explicit import of `Rect` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default diff --git a/tests/ui/imports/ambiguous-14.rs b/tests/ui/imports/ambiguous-14.rs index ba2d7dc4e016..325b29f3b481 100644 --- a/tests/ui/imports/ambiguous-14.rs +++ b/tests/ui/imports/ambiguous-14.rs @@ -1,6 +1,6 @@ //@ edition:2015 // https://github.com/rust-lang/rust/issues/98467 - +//@ check-pass mod a { pub fn foo() {} } @@ -21,6 +21,6 @@ mod g { fn main() { g::foo(); - //~^ ERROR `foo` is ambiguous + //~^ WARN `foo` is ambiguous //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! } diff --git a/tests/ui/imports/ambiguous-14.stderr b/tests/ui/imports/ambiguous-14.stderr index 2a3557c31f12..6823d728c368 100644 --- a/tests/ui/imports/ambiguous-14.stderr +++ b/tests/ui/imports/ambiguous-14.stderr @@ -1,4 +1,4 @@ -error: `foo` is ambiguous +warning: `foo` is ambiguous --> $DIR/ambiguous-14.rs:23:8 | LL | g::foo(); @@ -19,12 +19,12 @@ note: `foo` could also refer to the function imported here LL | pub use f::*; | ^^^^ = help: consider adding an explicit import of `foo` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default -error: aborting due to 1 previous error +warning: 1 warning emitted Future incompatibility report: Future breakage diagnostic: -error: `foo` is ambiguous +warning: `foo` is ambiguous --> $DIR/ambiguous-14.rs:23:8 | LL | g::foo(); @@ -45,5 +45,5 @@ note: `foo` could also refer to the function imported here LL | pub use f::*; | ^^^^ = help: consider adding an explicit import of `foo` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default diff --git a/tests/ui/imports/ambiguous-15.rs b/tests/ui/imports/ambiguous-15.rs index 07d8893b2dea..f90d9696e8ef 100644 --- a/tests/ui/imports/ambiguous-15.rs +++ b/tests/ui/imports/ambiguous-15.rs @@ -1,5 +1,5 @@ // https://github.com/rust-lang/rust/pull/113099#issuecomment-1638206152 - +//@ check-pass mod t2 { #[derive(Debug)] pub enum Error {} @@ -20,7 +20,7 @@ mod t3 { use self::t3::*; fn a(_: E) {} -//~^ ERROR `Error` is ambiguous +//~^ WARN `Error` is ambiguous //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! fn main() {} diff --git a/tests/ui/imports/ambiguous-15.stderr b/tests/ui/imports/ambiguous-15.stderr index 15f83546532e..59f9cb0526fc 100644 --- a/tests/ui/imports/ambiguous-15.stderr +++ b/tests/ui/imports/ambiguous-15.stderr @@ -1,4 +1,4 @@ -error: `Error` is ambiguous +warning: `Error` is ambiguous --> $DIR/ambiguous-15.rs:22:9 | LL | fn a(_: E) {} @@ -19,12 +19,12 @@ note: `Error` could also refer to the enum imported here LL | pub use t2::*; | ^^^^^ = help: consider adding an explicit import of `Error` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default -error: aborting due to 1 previous error +warning: 1 warning emitted Future incompatibility report: Future breakage diagnostic: -error: `Error` is ambiguous +warning: `Error` is ambiguous --> $DIR/ambiguous-15.rs:22:9 | LL | fn a(_: E) {} @@ -45,5 +45,5 @@ note: `Error` could also refer to the enum imported here LL | pub use t2::*; | ^^^^^ = help: consider adding an explicit import of `Error` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default diff --git a/tests/ui/imports/ambiguous-16.rs b/tests/ui/imports/ambiguous-16.rs index f31c78d18a38..2cd1e2aca9d3 100644 --- a/tests/ui/imports/ambiguous-16.rs +++ b/tests/ui/imports/ambiguous-16.rs @@ -1,5 +1,5 @@ // https://github.com/rust-lang/rust/pull/113099 - +//@ check-pass mod framing { mod public_message { use super::*; @@ -20,7 +20,7 @@ mod framing { } use crate::framing::ConfirmedTranscriptHashInput; -//~^ ERROR `ConfirmedTranscriptHashInput` is ambiguous +//~^ WARN `ConfirmedTranscriptHashInput` is ambiguous //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! fn main() { } diff --git a/tests/ui/imports/ambiguous-16.stderr b/tests/ui/imports/ambiguous-16.stderr index 7c80dee17f04..bb76111ebe89 100644 --- a/tests/ui/imports/ambiguous-16.stderr +++ b/tests/ui/imports/ambiguous-16.stderr @@ -1,4 +1,4 @@ -error: `ConfirmedTranscriptHashInput` is ambiguous +warning: `ConfirmedTranscriptHashInput` is ambiguous --> $DIR/ambiguous-16.rs:22:21 | LL | use crate::framing::ConfirmedTranscriptHashInput; @@ -19,12 +19,12 @@ note: `ConfirmedTranscriptHashInput` could also refer to the struct imported her LL | pub use self::public_message_in::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: consider adding an explicit import of `ConfirmedTranscriptHashInput` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default -error: aborting due to 1 previous error +warning: 1 warning emitted Future incompatibility report: Future breakage diagnostic: -error: `ConfirmedTranscriptHashInput` is ambiguous +warning: `ConfirmedTranscriptHashInput` is ambiguous --> $DIR/ambiguous-16.rs:22:21 | LL | use crate::framing::ConfirmedTranscriptHashInput; @@ -45,5 +45,5 @@ note: `ConfirmedTranscriptHashInput` could also refer to the struct imported her LL | pub use self::public_message_in::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: consider adding an explicit import of `ConfirmedTranscriptHashInput` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default diff --git a/tests/ui/imports/ambiguous-17.rs b/tests/ui/imports/ambiguous-17.rs index 3a51c156d34c..8ef0318fa046 100644 --- a/tests/ui/imports/ambiguous-17.rs +++ b/tests/ui/imports/ambiguous-17.rs @@ -1,6 +1,6 @@ //@ edition:2015 // https://github.com/rust-lang/rust/pull/113099#issuecomment-1638206152 - +//@ check-pass pub use evp::*; //~ WARNING ambiguous glob re-exports pub use handwritten::*; @@ -24,6 +24,6 @@ mod handwritten { fn main() { id(); - //~^ ERROR `id` is ambiguous + //~^ WARN `id` is ambiguous //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! } diff --git a/tests/ui/imports/ambiguous-17.stderr b/tests/ui/imports/ambiguous-17.stderr index 1849b83d76a3..ef4a835a0b3c 100644 --- a/tests/ui/imports/ambiguous-17.stderr +++ b/tests/ui/imports/ambiguous-17.stderr @@ -8,7 +8,7 @@ LL | pub use handwritten::*; | = note: `#[warn(ambiguous_glob_reexports)]` on by default -error: `id` is ambiguous +warning: `id` is ambiguous --> $DIR/ambiguous-17.rs:26:5 | LL | id(); @@ -29,12 +29,12 @@ note: `id` could also refer to the function imported here LL | pub use handwritten::*; | ^^^^^^^^^^^^^^ = help: consider adding an explicit import of `id` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default -error: aborting due to 1 previous error; 1 warning emitted +warning: 2 warnings emitted Future incompatibility report: Future breakage diagnostic: -error: `id` is ambiguous +warning: `id` is ambiguous --> $DIR/ambiguous-17.rs:26:5 | LL | id(); @@ -55,5 +55,5 @@ note: `id` could also refer to the function imported here LL | pub use handwritten::*; | ^^^^^^^^^^^^^^ = help: consider adding an explicit import of `id` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default diff --git a/tests/ui/imports/ambiguous-2.rs b/tests/ui/imports/ambiguous-2.rs index 65c971c00b9a..978655bc0177 100644 --- a/tests/ui/imports/ambiguous-2.rs +++ b/tests/ui/imports/ambiguous-2.rs @@ -1,9 +1,9 @@ //@ aux-build: ../ambiguous-1.rs // https://github.com/rust-lang/rust/pull/113099#issuecomment-1633574396 - +//@ check-pass extern crate ambiguous_1; fn main() { - ambiguous_1::id(); //~ ERROR `id` is ambiguous + ambiguous_1::id(); //~ WARN `id` is ambiguous //~| WARN this was previously accepted } diff --git a/tests/ui/imports/ambiguous-2.stderr b/tests/ui/imports/ambiguous-2.stderr index d428e58a78fd..a0222099239a 100644 --- a/tests/ui/imports/ambiguous-2.stderr +++ b/tests/ui/imports/ambiguous-2.stderr @@ -1,4 +1,4 @@ -error: `id` is ambiguous +warning: `id` is ambiguous --> $DIR/ambiguous-2.rs:7:18 | LL | ambiguous_1::id(); @@ -17,12 +17,12 @@ note: `id` could also refer to the function defined here | LL | pub use self::handwritten::*; | ^^^^^^^^^^^^^^^^^ - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default -error: aborting due to 1 previous error +warning: 1 warning emitted Future incompatibility report: Future breakage diagnostic: -error: `id` is ambiguous +warning: `id` is ambiguous --> $DIR/ambiguous-2.rs:7:18 | LL | ambiguous_1::id(); @@ -41,5 +41,5 @@ note: `id` could also refer to the function defined here | LL | pub use self::handwritten::*; | ^^^^^^^^^^^^^^^^^ - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default diff --git a/tests/ui/imports/ambiguous-3.rs b/tests/ui/imports/ambiguous-3.rs index ff0dcc221ec0..717c1eb8597a 100644 --- a/tests/ui/imports/ambiguous-3.rs +++ b/tests/ui/imports/ambiguous-3.rs @@ -1,9 +1,9 @@ // https://github.com/rust-lang/rust/issues/47525 - +//@ check-pass fn main() { use a::*; x(); - //~^ ERROR `x` is ambiguous + //~^ WARN `x` is ambiguous //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! } diff --git a/tests/ui/imports/ambiguous-3.stderr b/tests/ui/imports/ambiguous-3.stderr index 27fa05a195b9..7addf9bc797c 100644 --- a/tests/ui/imports/ambiguous-3.stderr +++ b/tests/ui/imports/ambiguous-3.stderr @@ -1,4 +1,4 @@ -error: `x` is ambiguous +warning: `x` is ambiguous --> $DIR/ambiguous-3.rs:5:5 | LL | x(); @@ -19,12 +19,12 @@ note: `x` could also refer to the function imported here LL | pub use self::c::*; | ^^^^^^^^^^ = help: consider adding an explicit import of `x` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default -error: aborting due to 1 previous error +warning: 1 warning emitted Future incompatibility report: Future breakage diagnostic: -error: `x` is ambiguous +warning: `x` is ambiguous --> $DIR/ambiguous-3.rs:5:5 | LL | x(); @@ -45,5 +45,5 @@ note: `x` could also refer to the function imported here LL | pub use self::c::*; | ^^^^^^^^^^ = help: consider adding an explicit import of `x` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default diff --git a/tests/ui/imports/ambiguous-4.rs b/tests/ui/imports/ambiguous-4.rs index e66d231f93cc..1a2bfeaf53dc 100644 --- a/tests/ui/imports/ambiguous-4.rs +++ b/tests/ui/imports/ambiguous-4.rs @@ -1,9 +1,9 @@ //@ edition:2015 //@ aux-build: ../ambiguous-4-extern.rs - +//@ check-pass extern crate ambiguous_4_extern; fn main() { - ambiguous_4_extern::id(); //~ ERROR `id` is ambiguous + ambiguous_4_extern::id(); //~ WARN `id` is ambiguous //~| WARN this was previously accepted } diff --git a/tests/ui/imports/ambiguous-4.stderr b/tests/ui/imports/ambiguous-4.stderr index cf4127cbbb1c..6c1a2679fcae 100644 --- a/tests/ui/imports/ambiguous-4.stderr +++ b/tests/ui/imports/ambiguous-4.stderr @@ -1,4 +1,4 @@ -error: `id` is ambiguous +warning: `id` is ambiguous --> $DIR/ambiguous-4.rs:7:25 | LL | ambiguous_4_extern::id(); @@ -17,12 +17,12 @@ note: `id` could also refer to the function defined here | LL | pub use handwritten::*; | ^^^^^^^^^^^ - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default -error: aborting due to 1 previous error +warning: 1 warning emitted Future incompatibility report: Future breakage diagnostic: -error: `id` is ambiguous +warning: `id` is ambiguous --> $DIR/ambiguous-4.rs:7:25 | LL | ambiguous_4_extern::id(); @@ -41,5 +41,5 @@ note: `id` could also refer to the function defined here | LL | pub use handwritten::*; | ^^^^^^^^^^^ - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default diff --git a/tests/ui/imports/ambiguous-5.rs b/tests/ui/imports/ambiguous-5.rs index 8f89c966d4a5..9879216280a2 100644 --- a/tests/ui/imports/ambiguous-5.rs +++ b/tests/ui/imports/ambiguous-5.rs @@ -1,5 +1,5 @@ // https://github.com/rust-lang/rust/pull/113099#issuecomment-1637022296 - +//@ check-pass mod a { pub struct Class(u16); } @@ -10,7 +10,7 @@ mod gpos { use super::gsubgpos::*; use super::*; struct MarkRecord(Class); - //~^ ERROR`Class` is ambiguous + //~^ WARN`Class` is ambiguous //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! } diff --git a/tests/ui/imports/ambiguous-5.stderr b/tests/ui/imports/ambiguous-5.stderr index 1fc5f4543f35..a4f3151c9e85 100644 --- a/tests/ui/imports/ambiguous-5.stderr +++ b/tests/ui/imports/ambiguous-5.stderr @@ -1,4 +1,4 @@ -error: `Class` is ambiguous +warning: `Class` is ambiguous --> $DIR/ambiguous-5.rs:12:23 | LL | struct MarkRecord(Class); @@ -19,12 +19,12 @@ note: `Class` could also refer to the struct imported here LL | use super::gsubgpos::*; | ^^^^^^^^^^^^^^^^^^ = help: consider adding an explicit import of `Class` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default -error: aborting due to 1 previous error +warning: 1 warning emitted Future incompatibility report: Future breakage diagnostic: -error: `Class` is ambiguous +warning: `Class` is ambiguous --> $DIR/ambiguous-5.rs:12:23 | LL | struct MarkRecord(Class); @@ -45,5 +45,5 @@ note: `Class` could also refer to the struct imported here LL | use super::gsubgpos::*; | ^^^^^^^^^^^^^^^^^^ = help: consider adding an explicit import of `Class` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default diff --git a/tests/ui/imports/ambiguous-6.rs b/tests/ui/imports/ambiguous-6.rs index 1c6e34377165..9a3a138bda4c 100644 --- a/tests/ui/imports/ambiguous-6.rs +++ b/tests/ui/imports/ambiguous-6.rs @@ -1,10 +1,10 @@ //@ edition: 2021 // https://github.com/rust-lang/rust/issues/112713 - +//@ check-pass pub fn foo() -> u32 { use sub::*; C - //~^ ERROR `C` is ambiguous + //~^ WARN `C` is ambiguous //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! } diff --git a/tests/ui/imports/ambiguous-6.stderr b/tests/ui/imports/ambiguous-6.stderr index 681bc40931f5..d811cfa4236a 100644 --- a/tests/ui/imports/ambiguous-6.stderr +++ b/tests/ui/imports/ambiguous-6.stderr @@ -1,4 +1,4 @@ -error: `C` is ambiguous +warning: `C` is ambiguous --> $DIR/ambiguous-6.rs:6:5 | LL | C @@ -19,12 +19,12 @@ note: `C` could also refer to the constant imported here LL | pub use mod2::*; | ^^^^^^^ = help: consider adding an explicit import of `C` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default -error: aborting due to 1 previous error +warning: 1 warning emitted Future incompatibility report: Future breakage diagnostic: -error: `C` is ambiguous +warning: `C` is ambiguous --> $DIR/ambiguous-6.rs:6:5 | LL | C @@ -45,5 +45,5 @@ note: `C` could also refer to the constant imported here LL | pub use mod2::*; | ^^^^^^^ = help: consider adding an explicit import of `C` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default diff --git a/tests/ui/imports/ambiguous-9.rs b/tests/ui/imports/ambiguous-9.rs index c10b1268060c..e6329b8d46ac 100644 --- a/tests/ui/imports/ambiguous-9.rs +++ b/tests/ui/imports/ambiguous-9.rs @@ -1,5 +1,5 @@ // https://github.com/rust-lang/rust/pull/113099#issuecomment-1638206152 - +//@ check-pass pub mod dsl { mod range { pub fn date_range() {} @@ -21,8 +21,8 @@ use prelude::*; fn main() { date_range(); - //~^ ERROR `date_range` is ambiguous + //~^ WARN `date_range` is ambiguous //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //~| ERROR `date_range` is ambiguous + //~| WARN `date_range` is ambiguous //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! } diff --git a/tests/ui/imports/ambiguous-9.stderr b/tests/ui/imports/ambiguous-9.stderr index 800a2e10c9d7..da7d2d970fdd 100644 --- a/tests/ui/imports/ambiguous-9.stderr +++ b/tests/ui/imports/ambiguous-9.stderr @@ -8,7 +8,7 @@ LL | use super::prelude::*; | = note: `#[warn(ambiguous_glob_reexports)]` on by default -error: `date_range` is ambiguous +warning: `date_range` is ambiguous --> $DIR/ambiguous-9.rs:23:5 | LL | date_range(); @@ -29,7 +29,7 @@ note: `date_range` could also refer to the function imported here LL | use super::prelude::*; | ^^^^^^^^^^^^^^^^^ = help: consider adding an explicit import of `date_range` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default warning: ambiguous glob re-exports --> $DIR/ambiguous-9.rs:15:13 @@ -39,7 +39,7 @@ LL | pub use self::t::*; LL | pub use super::dsl::*; | ------------- but the name `date_range` in the value namespace is also re-exported here -error: `date_range` is ambiguous +warning: `date_range` is ambiguous --> $DIR/ambiguous-9.rs:23:5 | LL | date_range(); @@ -61,10 +61,10 @@ LL | use prelude::*; | ^^^^^^^^^^ = help: consider adding an explicit import of `date_range` to disambiguate -error: aborting due to 2 previous errors; 2 warnings emitted +warning: 4 warnings emitted Future incompatibility report: Future breakage diagnostic: -error: `date_range` is ambiguous +warning: `date_range` is ambiguous --> $DIR/ambiguous-9.rs:23:5 | LL | date_range(); @@ -85,10 +85,10 @@ note: `date_range` could also refer to the function imported here LL | use super::prelude::*; | ^^^^^^^^^^^^^^^^^ = help: consider adding an explicit import of `date_range` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default Future breakage diagnostic: -error: `date_range` is ambiguous +warning: `date_range` is ambiguous --> $DIR/ambiguous-9.rs:23:5 | LL | date_range(); @@ -109,5 +109,5 @@ note: `date_range` could also refer to the function imported here LL | use prelude::*; | ^^^^^^^^^^ = help: consider adding an explicit import of `date_range` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default diff --git a/tests/ui/imports/ambiguous-panic-globvsglob.rs b/tests/ui/imports/ambiguous-panic-globvsglob.rs index 4ff3cc822535..335fba74b208 100644 --- a/tests/ui/imports/ambiguous-panic-globvsglob.rs +++ b/tests/ui/imports/ambiguous-panic-globvsglob.rs @@ -3,7 +3,7 @@ mod m1 { pub use core::prelude::v1::*; } - +//@ check-pass mod m2 { pub use std::prelude::v1::*; } @@ -18,6 +18,6 @@ fn foo() { panic!(); //~^ WARN: `panic` is ambiguous [ambiguous_panic_imports] //~| WARN: this was previously accepted by the compiler - //~| ERROR: `panic` is ambiguous [ambiguous_glob_imports] + //~| WARN: `panic` is ambiguous [ambiguous_glob_imports] //~| WARN: this was previously accepted by the compiler } diff --git a/tests/ui/imports/ambiguous-panic-globvsglob.stderr b/tests/ui/imports/ambiguous-panic-globvsglob.stderr index 455c58bb6c02..8e216b21734f 100644 --- a/tests/ui/imports/ambiguous-panic-globvsglob.stderr +++ b/tests/ui/imports/ambiguous-panic-globvsglob.stderr @@ -1,4 +1,4 @@ -error: `panic` is ambiguous +warning: `panic` is ambiguous --> $DIR/ambiguous-panic-globvsglob.rs:18:5 | LL | panic!(); @@ -19,7 +19,7 @@ note: `panic` could also refer to the macro imported here LL | use m2::*; | ^^^^^ = help: consider adding an explicit import of `panic` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default warning: `panic` is ambiguous --> $DIR/ambiguous-panic-globvsglob.rs:18:5 @@ -40,10 +40,10 @@ note: `panic` could also refer to a macro from prelude --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL = note: `#[warn(ambiguous_panic_imports)]` (part of `#[warn(future_incompatible)]`) on by default -error: aborting due to 1 previous error; 1 warning emitted +warning: 2 warnings emitted Future incompatibility report: Future breakage diagnostic: -error: `panic` is ambiguous +warning: `panic` is ambiguous --> $DIR/ambiguous-panic-globvsglob.rs:18:5 | LL | panic!(); @@ -64,5 +64,5 @@ note: `panic` could also refer to the macro imported here LL | use m2::*; | ^^^^^ = help: consider adding an explicit import of `panic` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default diff --git a/tests/ui/imports/duplicate.rs b/tests/ui/imports/duplicate.rs index 0a652889ca8a..ef54726c9a93 100644 --- a/tests/ui/imports/duplicate.rs +++ b/tests/ui/imports/duplicate.rs @@ -34,7 +34,7 @@ fn main() { e::foo(); f::foo(); //~ ERROR `foo` is ambiguous g::foo(); - //~^ ERROR `foo` is ambiguous + //~^ WARN `foo` is ambiguous //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! } diff --git a/tests/ui/imports/duplicate.stderr b/tests/ui/imports/duplicate.stderr index 74829fc21e22..9252a041749d 100644 --- a/tests/ui/imports/duplicate.stderr +++ b/tests/ui/imports/duplicate.stderr @@ -68,7 +68,7 @@ LL | use self::m2::*; | ^^^^^^^^^^^ = help: consider adding an explicit import of `foo` to disambiguate -error: `foo` is ambiguous +warning: `foo` is ambiguous --> $DIR/duplicate.rs:36:8 | LL | g::foo(); @@ -89,14 +89,14 @@ note: `foo` could also refer to the function imported here LL | pub use crate::f::*; | ^^^^^^^^^^^ = help: consider adding an explicit import of `foo` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors; 1 warning emitted Some errors have detailed explanations: E0252, E0659. For more information about an error, try `rustc --explain E0252`. Future incompatibility report: Future breakage diagnostic: -error: `foo` is ambiguous +warning: `foo` is ambiguous --> $DIR/duplicate.rs:36:8 | LL | g::foo(); @@ -117,5 +117,5 @@ note: `foo` could also refer to the function imported here LL | pub use crate::f::*; | ^^^^^^^^^^^ = help: consider adding an explicit import of `foo` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default diff --git a/tests/ui/imports/glob-conflict-cross-crate-1.rs b/tests/ui/imports/glob-conflict-cross-crate-1.rs index 08ce6166b5c1..787fa36db2d9 100644 --- a/tests/ui/imports/glob-conflict-cross-crate-1.rs +++ b/tests/ui/imports/glob-conflict-cross-crate-1.rs @@ -1,11 +1,11 @@ //@ edition:2015 //@ aux-build:glob-conflict.rs - +//@ check-pass extern crate glob_conflict; fn main() { - glob_conflict::f(); //~ ERROR `f` is ambiguous + glob_conflict::f(); //~ WARN `f` is ambiguous //~| WARN this was previously accepted - glob_conflict::glob::f(); //~ ERROR `f` is ambiguous + glob_conflict::glob::f(); //~ WARN `f` is ambiguous //~| WARN this was previously accepted } diff --git a/tests/ui/imports/glob-conflict-cross-crate-1.stderr b/tests/ui/imports/glob-conflict-cross-crate-1.stderr index 54b7976b057e..440113653675 100644 --- a/tests/ui/imports/glob-conflict-cross-crate-1.stderr +++ b/tests/ui/imports/glob-conflict-cross-crate-1.stderr @@ -1,4 +1,4 @@ -error: `f` is ambiguous +warning: `f` is ambiguous --> $DIR/glob-conflict-cross-crate-1.rs:7:20 | LL | glob_conflict::f(); @@ -17,9 +17,9 @@ note: `f` could also refer to the function defined here | LL | pub use m2::*; | ^^ - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default -error: `f` is ambiguous +warning: `f` is ambiguous --> $DIR/glob-conflict-cross-crate-1.rs:9:26 | LL | glob_conflict::glob::f(); @@ -39,10 +39,10 @@ note: `f` could also refer to the function defined here LL | pub use m2::*; | ^^ -error: aborting due to 2 previous errors +warning: 2 warnings emitted Future incompatibility report: Future breakage diagnostic: -error: `f` is ambiguous +warning: `f` is ambiguous --> $DIR/glob-conflict-cross-crate-1.rs:7:20 | LL | glob_conflict::f(); @@ -61,10 +61,10 @@ note: `f` could also refer to the function defined here | LL | pub use m2::*; | ^^ - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default Future breakage diagnostic: -error: `f` is ambiguous +warning: `f` is ambiguous --> $DIR/glob-conflict-cross-crate-1.rs:9:26 | LL | glob_conflict::glob::f(); @@ -83,5 +83,5 @@ note: `f` could also refer to the function defined here | LL | pub use m2::*; | ^^ - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default diff --git a/tests/ui/imports/glob-conflict-cross-crate-2.rs b/tests/ui/imports/glob-conflict-cross-crate-2.rs index b4dd3d8eeb44..018a74d35d7f 100644 --- a/tests/ui/imports/glob-conflict-cross-crate-2.rs +++ b/tests/ui/imports/glob-conflict-cross-crate-2.rs @@ -1,10 +1,10 @@ //@ aux-build:glob-conflict-cross-crate-2-extern.rs - +//@ check-pass extern crate glob_conflict_cross_crate_2_extern; use glob_conflict_cross_crate_2_extern::*; fn main() { - let _a: C = 1; //~ ERROR `C` is ambiguous + let _a: C = 1; //~ WARN `C` is ambiguous //~| WARN this was previously accepted } diff --git a/tests/ui/imports/glob-conflict-cross-crate-2.stderr b/tests/ui/imports/glob-conflict-cross-crate-2.stderr index cbc2180c14f4..2ee519a364b3 100644 --- a/tests/ui/imports/glob-conflict-cross-crate-2.stderr +++ b/tests/ui/imports/glob-conflict-cross-crate-2.stderr @@ -1,4 +1,4 @@ -error: `C` is ambiguous +warning: `C` is ambiguous --> $DIR/glob-conflict-cross-crate-2.rs:8:13 | LL | let _a: C = 1; @@ -17,12 +17,12 @@ note: `C` could also refer to the type alias defined here | LL | pub use b::*; | ^ - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default -error: aborting due to 1 previous error +warning: 1 warning emitted Future incompatibility report: Future breakage diagnostic: -error: `C` is ambiguous +warning: `C` is ambiguous --> $DIR/glob-conflict-cross-crate-2.rs:8:13 | LL | let _a: C = 1; @@ -41,5 +41,5 @@ note: `C` could also refer to the type alias defined here | LL | pub use b::*; | ^ - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default diff --git a/tests/ui/imports/glob-conflict-cross-crate-3.rs b/tests/ui/imports/glob-conflict-cross-crate-3.rs index 31c234b9250f..a7b215359090 100644 --- a/tests/ui/imports/glob-conflict-cross-crate-3.rs +++ b/tests/ui/imports/glob-conflict-cross-crate-3.rs @@ -1,5 +1,5 @@ //@ aux-build:glob-conflict-cross-crate-2-extern.rs - +//@ check-pass extern crate glob_conflict_cross_crate_2_extern; mod a { @@ -11,8 +11,8 @@ use a::*; fn main() { let _a: C = 1; - //~^ ERROR `C` is ambiguous - //~| ERROR `C` is ambiguous + //~^ WARN `C` is ambiguous + //~| WARN `C` is ambiguous //~| WARN this was previously accepted //~| WARN this was previously accepted } diff --git a/tests/ui/imports/glob-conflict-cross-crate-3.stderr b/tests/ui/imports/glob-conflict-cross-crate-3.stderr index 213eafda20b7..c7457efe866e 100644 --- a/tests/ui/imports/glob-conflict-cross-crate-3.stderr +++ b/tests/ui/imports/glob-conflict-cross-crate-3.stderr @@ -1,4 +1,4 @@ -error: `C` is ambiguous +warning: `C` is ambiguous --> $DIR/glob-conflict-cross-crate-3.rs:13:13 | LL | let _a: C = 1; @@ -17,9 +17,9 @@ note: `C` could also refer to the type alias defined here | LL | pub use b::*; | ^ - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default -error: `C` is ambiguous +warning: `C` is ambiguous --> $DIR/glob-conflict-cross-crate-3.rs:13:13 | LL | let _a: C = 1; @@ -41,10 +41,10 @@ LL | use a::*; | ^^^^ = help: consider adding an explicit import of `C` to disambiguate -error: aborting due to 2 previous errors +warning: 2 warnings emitted Future incompatibility report: Future breakage diagnostic: -error: `C` is ambiguous +warning: `C` is ambiguous --> $DIR/glob-conflict-cross-crate-3.rs:13:13 | LL | let _a: C = 1; @@ -63,10 +63,10 @@ note: `C` could also refer to the type alias defined here | LL | pub use b::*; | ^ - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default Future breakage diagnostic: -error: `C` is ambiguous +warning: `C` is ambiguous --> $DIR/glob-conflict-cross-crate-3.rs:13:13 | LL | let _a: C = 1; @@ -87,5 +87,5 @@ note: `C` could also refer to the type alias imported here LL | use a::*; | ^^^^ = help: consider adding an explicit import of `C` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default diff --git a/tests/ui/imports/issue-114682-2.rs b/tests/ui/imports/issue-114682-2.rs index a9459c5b02ef..da145f3addc0 100644 --- a/tests/ui/imports/issue-114682-2.rs +++ b/tests/ui/imports/issue-114682-2.rs @@ -1,12 +1,12 @@ //@ aux-build: issue-114682-2-extern.rs // https://github.com/rust-lang/rust/pull/114682#issuecomment-1879998900 - +//@ check-pass extern crate issue_114682_2_extern; -use issue_114682_2_extern::max; //~ ERROR `max` is ambiguous +use issue_114682_2_extern::max; //~ WARN `max` is ambiguous //~| WARN this was previously accepted -type A = issue_114682_2_extern::max; //~ ERROR `max` is ambiguous +type A = issue_114682_2_extern::max; //~ WARN `max` is ambiguous //~| WARN this was previously accepted fn main() {} diff --git a/tests/ui/imports/issue-114682-2.stderr b/tests/ui/imports/issue-114682-2.stderr index 07c696651c38..f93e4409f0c4 100644 --- a/tests/ui/imports/issue-114682-2.stderr +++ b/tests/ui/imports/issue-114682-2.stderr @@ -1,4 +1,4 @@ -error: `max` is ambiguous +warning: `max` is ambiguous --> $DIR/issue-114682-2.rs:6:28 | LL | use issue_114682_2_extern::max; @@ -17,9 +17,9 @@ note: `max` could also refer to the module defined here | LL | pub use self::d::*; | ^^^^^^^ - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default -error: `max` is ambiguous +warning: `max` is ambiguous --> $DIR/issue-114682-2.rs:9:33 | LL | type A = issue_114682_2_extern::max; @@ -39,10 +39,10 @@ note: `max` could also refer to the module defined here LL | pub use self::d::*; | ^^^^^^^ -error: aborting due to 2 previous errors +warning: 2 warnings emitted Future incompatibility report: Future breakage diagnostic: -error: `max` is ambiguous +warning: `max` is ambiguous --> $DIR/issue-114682-2.rs:6:28 | LL | use issue_114682_2_extern::max; @@ -61,10 +61,10 @@ note: `max` could also refer to the module defined here | LL | pub use self::d::*; | ^^^^^^^ - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default Future breakage diagnostic: -error: `max` is ambiguous +warning: `max` is ambiguous --> $DIR/issue-114682-2.rs:9:33 | LL | type A = issue_114682_2_extern::max; @@ -83,5 +83,5 @@ note: `max` could also refer to the module defined here | LL | pub use self::d::*; | ^^^^^^^ - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default diff --git a/tests/ui/imports/issue-114682-4.rs b/tests/ui/imports/issue-114682-4.rs index 01921928a007..29e175b5ed54 100644 --- a/tests/ui/imports/issue-114682-4.rs +++ b/tests/ui/imports/issue-114682-4.rs @@ -6,7 +6,7 @@ extern crate issue_114682_4_extern; use issue_114682_4_extern::*; //~v ERROR type alias takes 1 generic argument but 2 generic arguments were supplied -fn a() -> Result { //~ ERROR `Result` is ambiguous +fn a() -> Result { //~ WARN `Result` is ambiguous //~| WARN this was previously accepted Ok(1) } diff --git a/tests/ui/imports/issue-114682-4.stderr b/tests/ui/imports/issue-114682-4.stderr index 5e677cd7ae72..12cb9ae95a42 100644 --- a/tests/ui/imports/issue-114682-4.stderr +++ b/tests/ui/imports/issue-114682-4.stderr @@ -1,4 +1,4 @@ -error: `Result` is ambiguous +warning: `Result` is ambiguous --> $DIR/issue-114682-4.rs:9:11 | LL | fn a() -> Result { @@ -17,7 +17,7 @@ note: `Result` could also refer to the type alias defined here | LL | pub use b::*; | ^ - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default error[E0107]: type alias takes 1 generic argument but 2 generic arguments were supplied --> $DIR/issue-114682-4.rs:9:11 @@ -33,11 +33,11 @@ note: type alias defined here, with 1 generic parameter: `T` LL | pub type Result = std::result::Result; | ^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error; 1 warning emitted For more information about this error, try `rustc --explain E0107`. Future incompatibility report: Future breakage diagnostic: -error: `Result` is ambiguous +warning: `Result` is ambiguous --> $DIR/issue-114682-4.rs:9:11 | LL | fn a() -> Result { @@ -56,5 +56,5 @@ note: `Result` could also refer to the type alias defined here | LL | pub use b::*; | ^ - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default diff --git a/tests/ui/imports/issue-114682-5.rs b/tests/ui/imports/issue-114682-5.rs index be33960e40b8..1408a8105d75 100644 --- a/tests/ui/imports/issue-114682-5.rs +++ b/tests/ui/imports/issue-114682-5.rs @@ -9,7 +9,7 @@ extern crate issue_114682_5_extern_2; use issue_114682_5_extern_2::p::*; use issue_114682_5_extern_1::Url; //~^ ERROR `issue_114682_5_extern_1` is ambiguous -//~| ERROR `issue_114682_5_extern_1` is ambiguous +//~| WARN `issue_114682_5_extern_1` is ambiguous //~| ERROR unresolved import `issue_114682_5_extern_1::Url` //~| WARN this was previously accepted diff --git a/tests/ui/imports/issue-114682-5.stderr b/tests/ui/imports/issue-114682-5.stderr index 427a5b16765b..74b42e0990b7 100644 --- a/tests/ui/imports/issue-114682-5.stderr +++ b/tests/ui/imports/issue-114682-5.stderr @@ -26,7 +26,7 @@ LL | use issue_114682_5_extern_2::p::*; = help: consider adding an explicit import of `issue_114682_5_extern_1` to disambiguate = help: or use `crate::issue_114682_5_extern_1` to refer to this module unambiguously -error: `issue_114682_5_extern_1` is ambiguous +warning: `issue_114682_5_extern_1` is ambiguous --> $DIR/issue-114682-5.rs:10:5 | LL | use issue_114682_5_extern_1::Url; @@ -46,14 +46,14 @@ note: `issue_114682_5_extern_1` could also refer to the crate defined here LL | pub use crate::*; | ^^^^^ = help: use `::issue_114682_5_extern_1` to refer to this crate unambiguously - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors; 1 warning emitted Some errors have detailed explanations: E0432, E0659. For more information about an error, try `rustc --explain E0432`. Future incompatibility report: Future breakage diagnostic: -error: `issue_114682_5_extern_1` is ambiguous +warning: `issue_114682_5_extern_1` is ambiguous --> $DIR/issue-114682-5.rs:10:5 | LL | use issue_114682_5_extern_1::Url; @@ -73,5 +73,5 @@ note: `issue_114682_5_extern_1` could also refer to the crate defined here LL | pub use crate::*; | ^^^^^ = help: use `::issue_114682_5_extern_1` to refer to this crate unambiguously - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default diff --git a/tests/ui/imports/issue-114682-6.rs b/tests/ui/imports/issue-114682-6.rs index 92173f4b8464..480caedb70a1 100644 --- a/tests/ui/imports/issue-114682-6.rs +++ b/tests/ui/imports/issue-114682-6.rs @@ -1,12 +1,12 @@ //@ aux-build: issue-114682-6-extern.rs // https://github.com/rust-lang/rust/pull/114682#issuecomment-1880755441 - +//@ check-pass extern crate issue_114682_6_extern; use issue_114682_6_extern::*; fn main() { - let log = 2; //~ ERROR `log` is ambiguous + let log = 2; //~ WARN `log` is ambiguous //~| WARN this was previously accepted let _ = log; } diff --git a/tests/ui/imports/issue-114682-6.stderr b/tests/ui/imports/issue-114682-6.stderr index 67ad25798c19..37f8f6c16ff2 100644 --- a/tests/ui/imports/issue-114682-6.stderr +++ b/tests/ui/imports/issue-114682-6.stderr @@ -1,4 +1,4 @@ -error: `log` is ambiguous +warning: `log` is ambiguous --> $DIR/issue-114682-6.rs:9:9 | LL | let log = 2; @@ -17,12 +17,12 @@ note: `log` could also refer to the function defined here | LL | pub use self::b::*; | ^^^^^^^ - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default -error: aborting due to 1 previous error +warning: 1 warning emitted Future incompatibility report: Future breakage diagnostic: -error: `log` is ambiguous +warning: `log` is ambiguous --> $DIR/issue-114682-6.rs:9:9 | LL | let log = 2; @@ -41,5 +41,5 @@ note: `log` could also refer to the function defined here | LL | pub use self::b::*; | ^^^^^^^ - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default diff --git a/tests/ui/imports/overwrite-different-ambig-2.rs b/tests/ui/imports/overwrite-different-ambig-2.rs index 1b6d20e24d30..1d6416c00fdc 100644 --- a/tests/ui/imports/overwrite-different-ambig-2.rs +++ b/tests/ui/imports/overwrite-different-ambig-2.rs @@ -1,3 +1,5 @@ +//@ check-pass + mod m1 { mod inner { pub struct S {} @@ -19,6 +21,6 @@ use m1::*; use m2::*; fn main() { - let _: m1::S = S {}; //~ ERROR `S` is ambiguous + let _: m1::S = S {}; //~ WARN `S` is ambiguous //~| WARN this was previously accepted } diff --git a/tests/ui/imports/overwrite-different-ambig-2.stderr b/tests/ui/imports/overwrite-different-ambig-2.stderr index e75f552d119c..2d8446585717 100644 --- a/tests/ui/imports/overwrite-different-ambig-2.stderr +++ b/tests/ui/imports/overwrite-different-ambig-2.stderr @@ -1,5 +1,5 @@ -error: `S` is ambiguous - --> $DIR/overwrite-different-ambig-2.rs:22:20 +warning: `S` is ambiguous + --> $DIR/overwrite-different-ambig-2.rs:24:20 | LL | let _: m1::S = S {}; | ^ ambiguous name @@ -8,24 +8,24 @@ LL | let _: m1::S = S {}; = note: for more information, see issue #114095 = note: ambiguous because of multiple glob imports of a name in the same module note: `S` could refer to the struct imported here - --> $DIR/overwrite-different-ambig-2.rs:18:5 + --> $DIR/overwrite-different-ambig-2.rs:20:5 | LL | use m1::*; | ^^^^^ = help: consider adding an explicit import of `S` to disambiguate note: `S` could also refer to the struct imported here - --> $DIR/overwrite-different-ambig-2.rs:19:5 + --> $DIR/overwrite-different-ambig-2.rs:21:5 | LL | use m2::*; | ^^^^^ = help: consider adding an explicit import of `S` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default -error: aborting due to 1 previous error +warning: 1 warning emitted Future incompatibility report: Future breakage diagnostic: -error: `S` is ambiguous - --> $DIR/overwrite-different-ambig-2.rs:22:20 +warning: `S` is ambiguous + --> $DIR/overwrite-different-ambig-2.rs:24:20 | LL | let _: m1::S = S {}; | ^ ambiguous name @@ -34,16 +34,16 @@ LL | let _: m1::S = S {}; = note: for more information, see issue #114095 = note: ambiguous because of multiple glob imports of a name in the same module note: `S` could refer to the struct imported here - --> $DIR/overwrite-different-ambig-2.rs:18:5 + --> $DIR/overwrite-different-ambig-2.rs:20:5 | LL | use m1::*; | ^^^^^ = help: consider adding an explicit import of `S` to disambiguate note: `S` could also refer to the struct imported here - --> $DIR/overwrite-different-ambig-2.rs:19:5 + --> $DIR/overwrite-different-ambig-2.rs:21:5 | LL | use m2::*; | ^^^^^ = help: consider adding an explicit import of `S` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default diff --git a/tests/ui/imports/unresolved-seg-after-ambiguous.rs b/tests/ui/imports/unresolved-seg-after-ambiguous.rs index 67366deabaaf..820f579ae3bb 100644 --- a/tests/ui/imports/unresolved-seg-after-ambiguous.rs +++ b/tests/ui/imports/unresolved-seg-after-ambiguous.rs @@ -18,7 +18,7 @@ mod a { use self::a::E::in_exist; //~^ ERROR: unresolved import `self::a::E` -//~| ERROR: `E` is ambiguous +//~| WARN: `E` is ambiguous //~| WARNING: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! fn main() {} diff --git a/tests/ui/imports/unresolved-seg-after-ambiguous.stderr b/tests/ui/imports/unresolved-seg-after-ambiguous.stderr index 67316462a27e..411cd1dbe5ef 100644 --- a/tests/ui/imports/unresolved-seg-after-ambiguous.stderr +++ b/tests/ui/imports/unresolved-seg-after-ambiguous.stderr @@ -4,7 +4,7 @@ error[E0432]: unresolved import `self::a::E` LL | use self::a::E::in_exist; | ^ `E` is a struct, not a module -error: `E` is ambiguous +warning: `E` is ambiguous --> $DIR/unresolved-seg-after-ambiguous.rs:19:14 | LL | use self::a::E::in_exist; @@ -25,13 +25,13 @@ note: `E` could also refer to the struct imported here LL | pub use self::d::*; | ^^^^^^^^^^ = help: consider adding an explicit import of `E` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default -error: aborting due to 2 previous errors +error: aborting due to 1 previous error; 1 warning emitted For more information about this error, try `rustc --explain E0432`. Future incompatibility report: Future breakage diagnostic: -error: `E` is ambiguous +warning: `E` is ambiguous --> $DIR/unresolved-seg-after-ambiguous.rs:19:14 | LL | use self::a::E::in_exist; @@ -52,5 +52,5 @@ note: `E` could also refer to the struct imported here LL | pub use self::d::*; | ^^^^^^^^^^ = help: consider adding an explicit import of `E` to disambiguate - = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default + = note: `#[warn(ambiguous_glob_imports)]` (part of `#[warn(future_incompatible)]`) on by default From ea9b062a8a71d16f8327ddf7d9ceac405a9a3bdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 15 Jan 2026 11:15:26 +0100 Subject: [PATCH 0728/1061] Add GCC to build-manifest --- src/tools/build-manifest/src/main.rs | 7 +-- src/tools/build-manifest/src/versions.rs | 56 +++++++++++++++++++----- 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 7c0c528bcc04..cd6efad01141 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -158,7 +158,7 @@ impl Builder { } fn add_packages_to(&mut self, manifest: &mut Manifest) { - for pkg in PkgType::all() { + for pkg in &PkgType::all() { self.package(pkg, &mut manifest.pkg); } } @@ -227,7 +227,7 @@ impl Builder { }; for pkg in PkgType::all() { if pkg.is_preview() { - rename(pkg.tarball_component_name(), &pkg.manifest_component_name()); + rename(&pkg.tarball_component_name(), &pkg.manifest_component_name()); } } } @@ -263,7 +263,7 @@ impl Builder { let host_component = |pkg: &_| Component::from_pkg(pkg, host); - for pkg in PkgType::all() { + for pkg in &PkgType::all() { match pkg { // rustc/rust-std/cargo/docs are all required PkgType::Rustc | PkgType::Cargo | PkgType::HtmlDocs => { @@ -303,6 +303,7 @@ impl Builder { | PkgType::JsonDocs | PkgType::RustcCodegenCranelift | PkgType::RustcCodegenGcc + | PkgType::Gcc { .. } | PkgType::LlvmBitcodeLinker => { extensions.push(host_component(pkg)); } diff --git a/src/tools/build-manifest/src/versions.rs b/src/tools/build-manifest/src/versions.rs index 1e55d1d467e6..b53f6c5edc5d 100644 --- a/src/tools/build-manifest/src/versions.rs +++ b/src/tools/build-manifest/src/versions.rs @@ -11,29 +11,54 @@ use xz2::read::XzDecoder; const DEFAULT_TARGET: &str = "x86_64-unknown-linux-gnu"; macro_rules! pkg_type { - ( $($variant:ident = $component:literal $(; preview = true $(@$is_preview:tt)? )? ),+ $(,)? ) => { + ( $($variant:ident = $component:literal $(; preview = true $(@$is_preview:tt)? )? $(; suffixes = [$($suffixes:literal),+] $(@$is_suffixed:tt)? )? ),+ $(,)? ) => { #[derive(Debug, Hash, Eq, PartialEq, Clone)] pub(crate) enum PkgType { - $($variant,)+ + $($variant $( $($is_suffixed)? { suffix: &'static str })?,)+ } impl PkgType { pub(crate) fn is_preview(&self) -> bool { match self { - $( $( $($is_preview)? PkgType::$variant => true, )? )+ - _ => false, + $( PkgType::$variant $($($is_suffixed)? { .. })? => false $( $($is_preview)? || true)?, )+ } } - /// First part of the tarball name. - pub(crate) fn tarball_component_name(&self) -> &str { + /// First part of the tarball name. May include a suffix, if the package has one. + pub(crate) fn tarball_component_name(&self) -> String { match self { - $( PkgType::$variant => $component,)+ + $( PkgType::$variant $($($is_suffixed)? { suffix })? => { + #[allow(unused_mut)] + let mut name = $component.to_owned(); + $($($is_suffixed)? + name.push('-'); + name.push_str(suffix); + )? + name + },)+ } } - pub(crate) fn all() -> &'static [PkgType] { - &[ $(PkgType::$variant),+ ] + pub(crate) fn all() -> Vec { + let mut packages = vec![]; + $( + // Push the single variant + packages.push(PkgType::$variant $($($is_suffixed)? { suffix: "" })?); + // Macro hell, we have to remove the fake empty suffix if we actually have + // suffixes + $( + $($is_suffixed)? + packages.pop(); + )? + // And now add the suffixes, if any + $( + $($is_suffixed)? + $( + packages.push(PkgType::$variant { suffix: $suffixes }); + )+ + )? + )+ + packages } } } @@ -60,6 +85,9 @@ pkg_type! { RustcCodegenCranelift = "rustc-codegen-cranelift"; preview = true, LlvmBitcodeLinker = "llvm-bitcode-linker"; preview = true, RustcCodegenGcc = "rustc-codegen-gcc"; preview = true, + Gcc = "gcc"; preview = true; suffixes = [ + "x86_64-unknown-linux-gnu" + ], } impl PkgType { @@ -68,7 +96,7 @@ impl PkgType { if self.is_preview() { format!("{}-preview", self.tarball_component_name()) } else { - self.tarball_component_name().to_string() + self.tarball_component_name() } } @@ -84,6 +112,7 @@ impl PkgType { PkgType::Miri => false, PkgType::RustcCodegenCranelift => false, PkgType::RustcCodegenGcc => false, + PkgType::Gcc { suffix: _ } => false, PkgType::Rust => true, PkgType::RustStd => true, @@ -114,6 +143,13 @@ impl PkgType { Cargo => HOSTS, RustcCodegenCranelift => HOSTS, RustcCodegenGcc => HOSTS, + // Gcc is "special", because we need a separate libgccjit.so for each + // (host, target) compilation pair. So it's even more special than stdlib, which has a + // separate component per target. This component thus hardcodes its compilation + // target in its name, and we thus ship it for HOSTS only. So we essentially have + // gcc-T1, gcc-T2, a separate *component/package* per each compilation target. + // So on host T1, if you want to compile for T2, you would install gcc-T2. + Gcc { suffix: _ } => HOSTS, RustMingw => MINGW, RustStd => TARGETS, HtmlDocs => HOSTS, From 55abc484d7243eea77fd40247b531bcb0796e697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 15 Jan 2026 11:29:07 +0100 Subject: [PATCH 0729/1061] Extend build-manifest local test guide Fill in more blanks about how to test build-manifest changes with Rustup. --- src/tools/build-manifest/README.md | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/tools/build-manifest/README.md b/src/tools/build-manifest/README.md index bc1992ef80cc..f88949f48d8b 100644 --- a/src/tools/build-manifest/README.md +++ b/src/tools/build-manifest/README.md @@ -18,7 +18,7 @@ This gets called by `promote-release` build/dist/channel-rust-nightly.toml.sha256 +``` + +And start a HTTP server from the `build` directory: +```sh +cd build +python3 -m http.server 8000 +``` + +After you do all that, you can then install the locally generated components with rustup: +``` +rustup uninstall nightly +RUSTUP_DIST_SERVER=http://localhost:8000 rustup toolchain install nightly --profile minimal +RUSTUP_DIST_SERVER=http://localhost:8000 rustup +nightly component add +``` + +Note that generally it will not work to combine components built locally and those built from CI (nightly). Ideally, if you want to ship new rustup components, first dist them in nightly, and then test everything from nightly here after it's available on CI. From 316627ee24c2214037631c227dc073bde46001e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 16 Dec 2025 21:19:20 +0100 Subject: [PATCH 0730/1061] Refactor `Enzyme` step --- src/bootstrap/src/core/build_steps/compile.rs | 22 +++------ src/bootstrap/src/core/build_steps/llvm.rs | 49 +++++++++++++++---- 2 files changed, 46 insertions(+), 25 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 11f2a28bb935..651ff03a8690 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -2292,23 +2292,13 @@ impl Step for Assemble { builder.compiler(target_compiler.stage - 1, builder.config.host_target); // Build enzyme - if builder.config.llvm_enzyme && !builder.config.dry_run() { + if builder.config.llvm_enzyme { debug!("`llvm_enzyme` requested"); - let enzyme_install = builder.ensure(llvm::Enzyme { target: build_compiler.host }); - if let Some(llvm_config) = builder.llvm_config(builder.config.host_target) { - let llvm_version_major = llvm::get_llvm_version_major(builder, &llvm_config); - let lib_ext = std::env::consts::DLL_EXTENSION; - let libenzyme = format!("libEnzyme-{llvm_version_major}"); - let src_lib = - enzyme_install.join("build/Enzyme").join(&libenzyme).with_extension(lib_ext); - let libdir = builder.sysroot_target_libdir(build_compiler, build_compiler.host); - let target_libdir = - builder.sysroot_target_libdir(target_compiler, target_compiler.host); - let dst_lib = libdir.join(&libenzyme).with_extension(lib_ext); - let target_dst_lib = target_libdir.join(&libenzyme).with_extension(lib_ext); - builder.copy_link(&src_lib, &dst_lib, FileType::NativeLibrary); - builder.copy_link(&src_lib, &target_dst_lib, FileType::NativeLibrary); - } + let enzyme = builder.ensure(llvm::Enzyme { target: build_compiler.host }); + let target_libdir = + builder.sysroot_target_libdir(target_compiler, target_compiler.host); + let target_dst_lib = target_libdir.join(enzyme.enzyme_filename()); + builder.copy_link(&enzyme.enzyme_path(), &target_dst_lib, FileType::NativeLibrary); } if builder.config.llvm_offload && !builder.config.dry_run() { diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index c3935d9810e9..f6a763b94075 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -17,6 +17,7 @@ use std::{env, fs}; use build_helper::exit; use build_helper::git::PathFreshness; +use crate::core::build_steps::llvm; use crate::core::builder::{Builder, RunConfig, ShouldRun, Step, StepMetadata}; use crate::core::config::{Config, TargetSelection}; use crate::utils::build_stamp::{BuildStamp, generate_smart_stamp_hash}; @@ -1077,13 +1078,28 @@ impl Step for OmpOffload { } } +#[derive(Clone)] +pub struct BuiltEnzyme { + /// Path to the libEnzyme dylib. + enzyme: PathBuf, +} + +impl BuiltEnzyme { + pub fn enzyme_path(&self) -> PathBuf { + self.enzyme.clone() + } + pub fn enzyme_filename(&self) -> String { + self.enzyme.file_name().unwrap().to_str().unwrap().to_owned() + } +} + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Enzyme { pub target: TargetSelection, } impl Step for Enzyme { - type Output = PathBuf; + type Output = BuiltEnzyme; const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -1095,17 +1111,17 @@ impl Step for Enzyme { } /// Compile Enzyme for `target`. - fn run(self, builder: &Builder<'_>) -> PathBuf { + fn run(self, builder: &Builder<'_>) -> Self::Output { builder.require_submodule( "src/tools/enzyme", Some("The Enzyme sources are required for autodiff."), ); - if builder.config.dry_run() { - let out_dir = builder.enzyme_out(self.target); - return out_dir; - } let target = self.target; + if builder.config.dry_run() { + return BuiltEnzyme { enzyme: builder.config.tempdir().join("enzyme-dryrun") }; + } + let LlvmResult { host_llvm_config, llvm_cmake_dir } = builder.ensure(Llvm { target }); static STAMP_HASH_MEMO: OnceLock = OnceLock::new(); @@ -1120,6 +1136,12 @@ impl Step for Enzyme { let out_dir = builder.enzyme_out(target); let stamp = BuildStamp::new(&out_dir).with_prefix("enzyme").add_stamp(smart_stamp_hash); + let llvm_version_major = llvm::get_llvm_version_major(builder, &host_llvm_config); + let lib_ext = std::env::consts::DLL_EXTENSION; + let libenzyme = format!("libEnzyme-{llvm_version_major}"); + let build_dir = out_dir.join("lib"); + let dylib = build_dir.join(&libenzyme).with_extension(lib_ext); + trace!("checking build stamp to see if we need to rebuild enzyme artifacts"); if stamp.is_up_to_date() { trace!(?out_dir, "enzyme build artifacts are up to date"); @@ -1133,7 +1155,7 @@ impl Step for Enzyme { stamp.path().display() )); } - return out_dir; + return BuiltEnzyme { enzyme: dylib }; } if !builder.config.dry_run() && !llvm_cmake_dir.is_dir() { @@ -1149,7 +1171,6 @@ impl Step for Enzyme { let _time = helpers::timeit(builder); t!(fs::create_dir_all(&out_dir)); - builder.config.update_submodule("src/tools/enzyme"); let mut cfg = cmake::Config::new(builder.src.join("src/tools/enzyme/enzyme/")); // Enzyme devs maintain upstream compatibility, but only fix deprecations when they are about // to turn into a hard error. As such, Enzyme generates various warnings which could make it @@ -1178,8 +1199,18 @@ impl Step for Enzyme { cfg.build(); + // At this point, `out_dir` should contain the built libEnzyme-. + // file. + if !dylib.exists() { + eprintln!( + "`{libenzyme}` not found in `{}`. Either the build has failed or Enzyme was built with a wrong version of LLVM", + build_dir.display() + ); + exit!(1); + } + t!(stamp.write()); - out_dir + BuiltEnzyme { enzyme: dylib } } } From 85e01e3c4e328a63b39ea1189de03b79cc02b0cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 16 Dec 2025 21:55:56 +0100 Subject: [PATCH 0731/1061] Add dist step for `Enzyme` --- src/bootstrap/src/core/build_steps/dist.rs | 49 ++++++++++++++++++++++ src/bootstrap/src/core/builder/mod.rs | 1 + src/bootstrap/src/utils/tarball.rs | 3 ++ 3 files changed, 53 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index cfcb144e0993..8ba05a7fa3a7 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -2717,6 +2717,55 @@ impl Step for LlvmBitcodeLinker { } } +/// Distributes the `enzyme` library so that it can be used by a compiler whose host +/// is `target`. +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct Enzyme { + /// Enzyme will by usable by rustc on this host. + pub target: TargetSelection, +} + +impl Step for Enzyme { + type Output = Option; + const IS_HOST: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.alias("enzyme") + } + + fn is_default_step(builder: &Builder<'_>) -> bool { + builder.config.llvm_enzyme + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(Enzyme { target: run.target }); + } + + fn run(self, builder: &Builder<'_>) -> Option { + // This prevents Enzyme from being built for "dist" + // or "install" on the stable/beta channels. It is not yet stable and + // should not be included. + if !builder.build.unstable_features() { + return None; + } + + let target = self.target; + + let enzyme = builder.ensure(llvm::Enzyme { target }); + + let target_libdir = format!("lib/rustlib/{}/lib", target.triple); + + // Prepare the image directory + let mut tarball = Tarball::new(builder, "enzyme", &target.triple); + tarball.set_overlay(OverlayKind::Enzyme); + tarball.is_preview(true); + + tarball.add_file(enzyme.enzyme_path(), target_libdir, FileType::NativeLibrary); + + Some(tarball.generate()) + } +} + /// Tarball intended for internal consumption to ease rustc/std development. /// /// Should not be considered stable by end users. diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index f63b8e044550..14cae2d0efc4 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -980,6 +980,7 @@ impl<'a> Builder<'a> { dist::LlvmTools, dist::LlvmBitcodeLinker, dist::RustDev, + dist::Enzyme, dist::Bootstrap, dist::Extended, // It seems that PlainSourceTarball somehow changes how some of the tools diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index cd6a03c84870..17d75e83daea 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -28,6 +28,7 @@ pub(crate) enum OverlayKind { RustcCodegenGcc, Gcc, LlvmBitcodeLinker, + Enzyme, } impl OverlayKind { @@ -37,6 +38,7 @@ impl OverlayKind { OverlayKind::Llvm => { &["src/llvm-project/llvm/LICENSE.TXT", "src/llvm-project/llvm/README.txt"] } + OverlayKind::Enzyme => &["src/tools/enzyme/LICENSE", "src/tools/enzyme/Readme.md"], OverlayKind::Cargo => &[ "src/tools/cargo/README.md", "src/tools/cargo/LICENSE-MIT", @@ -111,6 +113,7 @@ impl OverlayKind { OverlayKind::RustcCodegenGcc => builder.rust_version(), OverlayKind::LlvmBitcodeLinker => builder.rust_version(), OverlayKind::Gcc => builder.rust_version(), + OverlayKind::Enzyme => builder.rust_version(), } } } From cd7d40d97507d75b4d0341e19a24edfaf654c6c5 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 15 Jan 2026 15:06:29 +0100 Subject: [PATCH 0732/1061] Update `rustc_attr_parsing::SharedContext::target` type from `Option` to `Target` --- compiler/rustc_attr_parsing/src/attributes/cfg.rs | 3 ++- compiler/rustc_attr_parsing/src/attributes/cfg_select.rs | 4 +++- compiler/rustc_attr_parsing/src/attributes/doc.rs | 4 ++-- compiler/rustc_attr_parsing/src/context.rs | 2 +- compiler/rustc_attr_parsing/src/interface.rs | 9 ++++++--- compiler/rustc_builtin_macros/src/cfg.rs | 4 +++- compiler/rustc_expand/src/config.rs | 3 +++ compiler/rustc_expand/src/expand.rs | 2 ++ 8 files changed, 22 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index ccf0a394afd0..3e430cf59485 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -9,7 +9,7 @@ use rustc_feature::{ }; use rustc_hir::attrs::CfgEntry; use rustc_hir::lints::AttributeLintKind; -use rustc_hir::{AttrPath, RustcVersion}; +use rustc_hir::{AttrPath, RustcVersion, Target}; use rustc_parse::parser::{ForceCollect, Parser}; use rustc_parse::{exp, parse_in}; use rustc_session::Session; @@ -374,6 +374,7 @@ fn parse_cfg_attr_internal<'a>( ParsedDescription::Attribute, pred_span, CRATE_NODE_ID, + Target::Crate, features, ShouldEmit::ErrorsAndLints, &meta, diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs index 24b989e22a2b..e80084021a84 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs @@ -2,8 +2,8 @@ use rustc_ast::token::Token; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{AttrStyle, NodeId, token}; use rustc_feature::{AttributeTemplate, Features}; -use rustc_hir::AttrPath; use rustc_hir::attrs::CfgEntry; +use rustc_hir::{AttrPath, Target}; use rustc_parse::exp; use rustc_parse::parser::Parser; use rustc_session::Session; @@ -91,6 +91,8 @@ pub fn parse_cfg_select( ParsedDescription::Macro, cfg_span, lint_node_id, + // Doesn't matter what the target actually is here. + Target::Crate, features, ShouldEmit::ErrorsAndLints, &meta, diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 6cc4ac35eadb..99825d93216f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -50,7 +50,7 @@ fn check_attr_not_crate_level( span: Span, attr_name: Symbol, ) -> bool { - if cx.shared.target.is_some_and(|target| target == Target::Crate) { + if cx.shared.target == Target::Crate { cx.emit_err(DocAttrNotCrateLevel { span, attr_name }); return false; } @@ -59,7 +59,7 @@ fn check_attr_not_crate_level( /// Checks that an attribute is used at the crate level. Returns `true` if valid. fn check_attr_crate_level(cx: &mut AcceptContext<'_, '_, S>, span: Span) -> bool { - if cx.shared.target.is_some_and(|target| target != Target::Crate) { + if cx.shared.target != Target::Crate { cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, AttributeLintKind::AttrCrateLevelOnly, diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 8305d027d13c..f885151330a3 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -665,7 +665,7 @@ pub struct SharedContext<'p, 'sess, S: Stage> { pub(crate) target_span: Span, /// The id ([`NodeId`] if `S` is `Early`, [`HirId`] if `S` is `Late`) of the syntactical component this attribute was applied to pub(crate) target_id: S::Id, - pub(crate) target: Option, + pub(crate) target: rustc_hir::Target, pub(crate) emit_lint: &'p mut dyn FnMut(AttributeLint), } diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index b7137c60e63a..8f2c36fa8c9e 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -135,6 +135,7 @@ impl<'sess> AttributeParser<'sess, Early> { attr: &ast::Attribute, target_span: Span, target_node_id: NodeId, + target: Target, features: Option<&'sess Features>, emit_errors: ShouldEmit, parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser) -> Option, @@ -163,6 +164,7 @@ impl<'sess> AttributeParser<'sess, Early> { ParsedDescription::Attribute, target_span, target_node_id, + target, features, emit_errors, &args, @@ -183,6 +185,7 @@ impl<'sess> AttributeParser<'sess, Early> { parsed_description: ParsedDescription, target_span: Span, target_node_id: NodeId, + target: Target, features: Option<&'sess Features>, emit_errors: ShouldEmit, args: &I, @@ -218,7 +221,7 @@ impl<'sess> AttributeParser<'sess, Early> { cx: &mut parser, target_span, target_id: target_node_id, - target: None, + target, emit_lint: &mut emit_lint, }, attr_span, @@ -379,7 +382,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { cx: self, target_span, target_id, - target: Some(target), + target, emit_lint: &mut emit_lint, }, attr_span, @@ -431,7 +434,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { cx: self, target_span, target_id, - target: Some(target), + target, emit_lint: &mut emit_lint, }, all_attrs: &attr_paths, diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 557daa94b98e..be1ce5a06d5e 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -10,8 +10,8 @@ use rustc_attr_parsing::{ AttributeParser, CFG_TEMPLATE, ParsedDescription, ShouldEmit, parse_cfg_entry, }; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; -use rustc_hir::AttrPath; use rustc_hir::attrs::CfgEntry; +use rustc_hir::{AttrPath, Target}; use rustc_parse::exp; use rustc_span::{ErrorGuaranteed, Span, sym}; @@ -52,6 +52,8 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result StripUnconfigured<'a> { attr, attr.span, self.lint_node_id, + // Doesn't matter what the target actually is here. + Target::Crate, self.features, emit_errors, parse_cfg, diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index c130d9f59940..fabe1f5a8c5d 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -2218,6 +2218,8 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { &attr, attr.span, self.cfg().lint_node_id, + // Target doesn't matter for `cfg` parsing. + Target::Crate, self.cfg().features, ShouldEmit::ErrorsAndLints, parse_cfg, From 820579243f5cd9a27c3831d6c335f138a4567c41 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 15 Jan 2026 15:39:00 +0100 Subject: [PATCH 0733/1061] Remove `rustc_attr_parsing::SharedContext::target_id` field --- compiler/rustc_ast_lowering/src/lib.rs | 12 +++-- compiler/rustc_attr_parsing/src/context.rs | 11 +++-- compiler/rustc_attr_parsing/src/interface.rs | 47 +++++++------------- compiler/rustc_attr_parsing/src/safety.rs | 16 +++---- compiler/rustc_resolve/src/def_collector.rs | 3 +- 5 files changed, 36 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 350fa04ab3bd..51d1fd20cec6 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -51,7 +51,7 @@ use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId}; use rustc_hir::definitions::{DefPathData, DisambiguatorState}; -use rustc_hir::lints::DelayedLint; +use rustc_hir::lints::{AttributeLint, DelayedLint}; use rustc_hir::{ self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LifetimeSource, LifetimeSyntax, ParamName, Target, TraitCandidate, find_attr, @@ -1022,12 +1022,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.attribute_parser.parse_attribute_list( attrs, target_span, - target_hir_id, target, OmitDoc::Lower, |s| l.lower(s), - |l| { - self.delayed_lints.push(DelayedLint::AttributeParsing(l)); + |lint_id, span, kind| { + self.delayed_lints.push(DelayedLint::AttributeParsing(AttributeLint { + lint_id, + id: target_hir_id, + span, + kind, + })); }, ) } diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index f885151330a3..d6a3ddf4d300 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -8,7 +8,7 @@ use rustc_ast::{AttrStyle, MetaItemLit, NodeId}; use rustc_errors::{Diag, Diagnostic, Level}; use rustc_feature::{AttrSuggestionStyle, AttributeTemplate}; use rustc_hir::attrs::AttributeKind; -use rustc_hir::lints::{AttributeLint, AttributeLintKind}; +use rustc_hir::lints::AttributeLintKind; use rustc_hir::{AttrPath, HirId}; use rustc_session::Session; use rustc_session::lint::{Lint, LintId}; @@ -417,8 +417,7 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> { ) { return; } - let id = self.target_id; - (self.emit_lint)(AttributeLint { lint_id: LintId::of(lint), id, span, kind }); + (self.emit_lint)(LintId::of(lint), span, kind); } pub(crate) fn warn_unused_duplicate(&mut self, used_span: Span, unused_span: Span) { @@ -663,11 +662,11 @@ pub struct SharedContext<'p, 'sess, S: Stage> { pub(crate) cx: &'p mut AttributeParser<'sess, S>, /// The span of the syntactical component this attribute was applied to pub(crate) target_span: Span, - /// The id ([`NodeId`] if `S` is `Early`, [`HirId`] if `S` is `Late`) of the syntactical component this attribute was applied to - pub(crate) target_id: S::Id, pub(crate) target: rustc_hir::Target, - pub(crate) emit_lint: &'p mut dyn FnMut(AttributeLint), + /// The second argument of the closure is a [`NodeId`] if `S` is `Early` and a [`HirId`] if `S` + /// is `Late` and is the ID of the syntactical component this attribute was applied to. + pub(crate) emit_lint: &'p mut dyn FnMut(LintId, Span, AttributeLintKind), } /// Context given to every attribute parser during finalization. diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 8f2c36fa8c9e..c6be18321b5e 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -6,10 +6,10 @@ use rustc_ast::{AttrItemKind, AttrStyle, NodeId, Safety}; use rustc_errors::DiagCtxtHandle; use rustc_feature::{AttributeTemplate, Features}; use rustc_hir::attrs::AttributeKind; -use rustc_hir::lints::AttributeLint; +use rustc_hir::lints::AttributeLintKind; use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, Target}; use rustc_session::Session; -use rustc_session::lint::BuiltinLintDiag; +use rustc_session::lint::{BuiltinLintDiag, LintId}; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use crate::context::{AcceptContext, FinalizeContext, SharedContext, Stage}; @@ -113,16 +113,15 @@ impl<'sess> AttributeParser<'sess, Early> { p.parse_attribute_list( attrs, target_span, - target_node_id, target, OmitDoc::Skip, std::convert::identity, - |lint| { + |lint_id, span, kind| { sess.psess.buffer_lint( - lint.lint_id.lint, - lint.span, - lint.id, - BuiltinLintDiag::AttributeLint(lint.kind), + lint_id.lint, + span, + target_node_id, + BuiltinLintDiag::AttributeLint(kind), ) }, ) @@ -199,28 +198,21 @@ impl<'sess> AttributeParser<'sess, Early> { sess, stage: Early { emit_errors }, }; - let mut emit_lint = |lint: AttributeLint| { + let mut emit_lint = |lint_id: LintId, span: Span, kind: AttributeLintKind| { sess.psess.buffer_lint( - lint.lint_id.lint, - lint.span, - lint.id, - BuiltinLintDiag::AttributeLint(lint.kind), + lint_id.lint, + span, + target_node_id, + BuiltinLintDiag::AttributeLint(kind), ) }; if let Some(safety) = attr_safety { - parser.check_attribute_safety( - &attr_path, - inner_span, - safety, - &mut emit_lint, - target_node_id, - ) + parser.check_attribute_safety(&attr_path, inner_span, safety, &mut emit_lint) } let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext { shared: SharedContext { cx: &mut parser, target_span, - target_id: target_node_id, target, emit_lint: &mut emit_lint, }, @@ -269,11 +261,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { &mut self, attrs: &[ast::Attribute], target_span: Span, - target_id: S::Id, target: Target, omit_doc: OmitDoc, lower_span: impl Copy + Fn(Span) -> Span, - mut emit_lint: impl FnMut(AttributeLint), + mut emit_lint: impl FnMut(LintId, Span, AttributeLintKind), ) -> Vec { let mut attributes = Vec::new(); let mut attr_paths: Vec> = Vec::new(); @@ -329,7 +320,6 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { lower_span(n.item.span()), n.item.unsafety, &mut emit_lint, - target_id, ); let parts = @@ -381,7 +371,6 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { shared: SharedContext { cx: self, target_span, - target_id, target, emit_lint: &mut emit_lint, }, @@ -430,13 +419,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { early_parsed_state.finalize_early_parsed_attributes(&mut attributes); for f in &S::parsers().finalizers { if let Some(attr) = f(&mut FinalizeContext { - shared: SharedContext { - cx: self, - target_span, - target_id, - target, - emit_lint: &mut emit_lint, - }, + shared: SharedContext { cx: self, target_span, target, emit_lint: &mut emit_lint }, all_attrs: &attr_paths, }) { attributes.push(Attribute::Parsed(attr)); diff --git a/compiler/rustc_attr_parsing/src/safety.rs b/compiler/rustc_attr_parsing/src/safety.rs index 9fca57f88025..4cc703c5d0cc 100644 --- a/compiler/rustc_attr_parsing/src/safety.rs +++ b/compiler/rustc_attr_parsing/src/safety.rs @@ -1,7 +1,7 @@ use rustc_ast::Safety; use rustc_feature::{AttributeSafety, BUILTIN_ATTRIBUTE_MAP}; use rustc_hir::AttrPath; -use rustc_hir::lints::{AttributeLint, AttributeLintKind}; +use rustc_hir::lints::AttributeLintKind; use rustc_session::lint::LintId; use rustc_session::lint::builtin::UNSAFE_ATTR_OUTSIDE_UNSAFE; use rustc_span::Span; @@ -15,8 +15,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { attr_path: &AttrPath, attr_span: Span, attr_safety: Safety, - emit_lint: &mut impl FnMut(AttributeLint), - target_id: S::Id, + emit_lint: &mut impl FnMut(LintId, Span, AttributeLintKind), ) { if matches!(self.stage.should_emit(), ShouldEmit::Nothing) { return; @@ -82,16 +81,15 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { }, ); } else { - emit_lint(AttributeLint { - lint_id: LintId::of(UNSAFE_ATTR_OUTSIDE_UNSAFE), - id: target_id, - span: path_span, - kind: AttributeLintKind::UnsafeAttrOutsideUnsafe { + emit_lint( + LintId::of(UNSAFE_ATTR_OUTSIDE_UNSAFE), + path_span, + AttributeLintKind::UnsafeAttrOutsideUnsafe { attribute_name_span: path_span, sugg_spans: not_from_proc_macro .then(|| (diag_span.shrink_to_lo(), diag_span.shrink_to_hi())), }, - }) + ) } } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index ea5640ecc1fa..8f1a43c090b1 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -148,11 +148,10 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { let attrs = parser.parse_attribute_list( &i.attrs, i.span, - i.id, Target::MacroDef, OmitDoc::Skip, std::convert::identity, - |_l| { + |_lint_id, _span, _kind| { // FIXME(jdonszelmann): emit lints here properly // NOTE that before new attribute parsing, they didn't happen either // but it would be nice if we could change that. From 6cd43592a8dbbe8f4c888eca3a4994710b57d978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Bj=C3=B8rnager=20Jensen?= Date: Thu, 15 Jan 2026 15:46:39 +0100 Subject: [PATCH 0734/1061] Stabilise 'EULER_GAMMA' and 'GOLDEN_RATIO' constants; --- library/core/src/num/f128.rs | 8 ++++---- library/core/src/num/f16.rs | 6 ++---- library/core/src/num/f32.rs | 8 ++++---- library/core/src/num/f64.rs | 8 ++++---- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index bf99fee4fc78..65afdd2969b8 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -34,13 +34,13 @@ pub mod consts { /// The golden ratio (φ) #[unstable(feature = "f128", issue = "116909")] - // Also, #[unstable(feature = "more_float_constants", issue = "146939")] - pub const PHI: f128 = 1.61803398874989484820458683436563811772030917980576286213545_f128; + pub const GOLDEN_RATIO: f128 = + 1.61803398874989484820458683436563811772030917980576286213545_f128; /// The Euler-Mascheroni constant (γ) #[unstable(feature = "f128", issue = "116909")] - // Also, #[unstable(feature = "more_float_constants", issue = "146939")] - pub const EGAMMA: f128 = 0.577215664901532860606512090082402431042159335939923598805767_f128; + pub const EULER_GAMMA: f128 = + 0.577215664901532860606512090082402431042159335939923598805767_f128; /// π/2 #[unstable(feature = "f128", issue = "116909")] diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index f39ee22871d5..bcf0f3fc45c2 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -36,13 +36,11 @@ pub mod consts { /// The golden ratio (φ) #[unstable(feature = "f16", issue = "116909")] - // Also, #[unstable(feature = "more_float_constants", issue = "146939")] - pub const PHI: f16 = 1.618033988749894848204586834365638118_f16; + pub const GOLDEN_RATIO: f16 = 1.618033988749894848204586834365638118_f16; /// The Euler-Mascheroni constant (γ) #[unstable(feature = "f16", issue = "116909")] - // Also, #[unstable(feature = "more_float_constants", issue = "146939")] - pub const EGAMMA: f16 = 0.577215664901532860606512090082402431_f16; + pub const EULER_GAMMA: f16 = 0.577215664901532860606512090082402431_f16; /// π/2 #[unstable(feature = "f16", issue = "116909")] diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 6fe4285374b2..f7f16b57a526 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -292,12 +292,12 @@ pub mod consts { pub const TAU: f32 = 6.28318530717958647692528676655900577_f32; /// The golden ratio (φ) - #[unstable(feature = "more_float_constants", issue = "146939")] - pub const PHI: f32 = 1.618033988749894848204586834365638118_f32; + #[stable(feature = "euler_gamma_golden_ratio", since = "CURRENT_RUSTC_VERSION")] + pub const GOLDEN_RATIO: f32 = 1.618033988749894848204586834365638118_f32; /// The Euler-Mascheroni constant (γ) - #[unstable(feature = "more_float_constants", issue = "146939")] - pub const EGAMMA: f32 = 0.577215664901532860606512090082402431_f32; + #[stable(feature = "euler_gamma_golden_ratio", since = "CURRENT_RUSTC_VERSION")] + pub const EULER_GAMMA: f32 = 0.577215664901532860606512090082402431_f32; /// π/2 #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index d0aca152415e..f021c88f2235 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -292,12 +292,12 @@ pub mod consts { pub const TAU: f64 = 6.28318530717958647692528676655900577_f64; /// The golden ratio (φ) - #[unstable(feature = "more_float_constants", issue = "146939")] - pub const PHI: f64 = 1.618033988749894848204586834365638118_f64; + #[stable(feature = "euler_gamma_golden_ratio", since = "CURRENT_RUSTC_VERSION")] + pub const GOLDEN_RATIO: f64 = 1.618033988749894848204586834365638118_f64; /// The Euler-Mascheroni constant (γ) - #[unstable(feature = "more_float_constants", issue = "146939")] - pub const EGAMMA: f64 = 0.577215664901532860606512090082402431_f64; + #[stable(feature = "euler_gamma_golden_ratio", since = "CURRENT_RUSTC_VERSION")] + pub const EULER_GAMMA: f64 = 0.577215664901532860606512090082402431_f64; /// π/2 #[stable(feature = "rust1", since = "1.0.0")] From 08362d3e51a2da3eb10fa7a918c5739249873cd8 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Fri, 16 Jan 2026 00:35:10 +0900 Subject: [PATCH 0735/1061] fix: Do not delay E0107 when there exists an assoc ty with the same name --- .../src/hir_ty_lowering/generics.rs | 22 ++++++++++-- ...me-name-with-lacking-generic-arg-148121.rs | 17 +++++++++ ...ame-with-lacking-generic-arg-148121.stderr | 35 +++++++++++++++++++ 3 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 tests/ui/traits/associated_type_bound/assoc-type-bounds-with-the-same-name-with-lacking-generic-arg-148121.rs create mode 100644 tests/ui/traits/associated_type_bound/assoc-type-bounds-with-the-same-name-with-lacking-generic-arg-148121.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index f5a64ede398e..0a2946323c7b 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -9,6 +9,7 @@ use rustc_middle::ty::{ }; use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS; use rustc_span::kw; +use rustc_trait_selection::traits; use smallvec::SmallVec; use tracing::{debug, instrument}; @@ -535,9 +536,26 @@ pub(crate) fn check_generic_arg_count( .map(|param| param.name) .collect(); if constraint_names == param_names { + let has_assoc_ty_with_same_name = + if let DefKind::Trait = cx.tcx().def_kind(def_id) { + gen_args.constraints.iter().any(|constraint| { + traits::supertrait_def_ids(cx.tcx(), def_id).any(|trait_did| { + cx.probe_trait_that_defines_assoc_item( + trait_did, + ty::AssocTag::Type, + constraint.ident, + ) + }) + }) + } else { + false + }; // We set this to true and delay emitting `WrongNumberOfGenericArgs` - // to provide a succinct error for cases like issue #113073 - all_params_are_binded = true; + // to provide a succinct error for cases like issue #113073, + // but only if when we don't have any assoc type with the same name with a + // generic arg. Otherwise it will cause an ICE due to a delayed error because we + // don't have any error other than `WrongNumberOfGenericArgs`. + all_params_are_binded = !has_assoc_ty_with_same_name; }; } diff --git a/tests/ui/traits/associated_type_bound/assoc-type-bounds-with-the-same-name-with-lacking-generic-arg-148121.rs b/tests/ui/traits/associated_type_bound/assoc-type-bounds-with-the-same-name-with-lacking-generic-arg-148121.rs new file mode 100644 index 000000000000..f1dffc0ff6b4 --- /dev/null +++ b/tests/ui/traits/associated_type_bound/assoc-type-bounds-with-the-same-name-with-lacking-generic-arg-148121.rs @@ -0,0 +1,17 @@ +// A regression test for https://github.com/rust-lang/rust/issues/148121 + +pub trait Super { + type X; +} + +pub trait Zelf: Super {} + +pub trait A {} + +impl A for dyn Super {} +//~^ ERROR: trait takes 1 generic argument but 0 generic arguments were supplied + +impl A for dyn Zelf {} +//~^ ERROR: trait takes 1 generic argument but 0 generic arguments were supplied + +fn main() {} diff --git a/tests/ui/traits/associated_type_bound/assoc-type-bounds-with-the-same-name-with-lacking-generic-arg-148121.stderr b/tests/ui/traits/associated_type_bound/assoc-type-bounds-with-the-same-name-with-lacking-generic-arg-148121.stderr new file mode 100644 index 000000000000..5a7969193b55 --- /dev/null +++ b/tests/ui/traits/associated_type_bound/assoc-type-bounds-with-the-same-name-with-lacking-generic-arg-148121.stderr @@ -0,0 +1,35 @@ +error[E0107]: trait takes 1 generic argument but 0 generic arguments were supplied + --> $DIR/assoc-type-bounds-with-the-same-name-with-lacking-generic-arg-148121.rs:11:16 + | +LL | impl A for dyn Super {} + | ^^^^^ expected 1 generic argument + | +note: trait defined here, with 1 generic parameter: `X` + --> $DIR/assoc-type-bounds-with-the-same-name-with-lacking-generic-arg-148121.rs:3:11 + | +LL | pub trait Super { + | ^^^^^ - +help: add missing generic argument + | +LL | impl A for dyn Super {} + | ++ + +error[E0107]: trait takes 1 generic argument but 0 generic arguments were supplied + --> $DIR/assoc-type-bounds-with-the-same-name-with-lacking-generic-arg-148121.rs:14:16 + | +LL | impl A for dyn Zelf {} + | ^^^^ expected 1 generic argument + | +note: trait defined here, with 1 generic parameter: `X` + --> $DIR/assoc-type-bounds-with-the-same-name-with-lacking-generic-arg-148121.rs:7:11 + | +LL | pub trait Zelf: Super {} + | ^^^^ - +help: add missing generic argument + | +LL | impl A for dyn Zelf {} + | ++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0107`. From 8536979cdb67143bc09398150cf7d2f023992488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maja=20K=C4=85dzio=C5=82ka?= Date: Thu, 15 Jan 2026 16:50:20 +0100 Subject: [PATCH 0736/1061] Move some match edge case tests While these test cases were inspired by issue 137467, they aren't directly related, and better fit into match-edge-cases_2.rs --- .../match/match-edge-cases_2.rs | 78 +++++++++++++++++++ tests/ui/closures/or-patterns-issue-137467.rs | 64 --------------- 2 files changed, 78 insertions(+), 64 deletions(-) diff --git a/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_2.rs b/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_2.rs index a3b19708899a..81013e5b2cd1 100644 --- a/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_2.rs +++ b/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_2.rs @@ -34,4 +34,82 @@ fn edge_case_if() { _b(); } +struct Unit; + +enum TSingle { + A(u32, u32), +} + +enum SSingle { + A { a: u32, b: u32 }, +} + +struct TStruct(u32, u32); +struct SStruct { a: u32, b: u32 } + + +// Destructuring a unit struct should not capture it +fn match_unit_struct(mut x: (Unit, u32)) { + let r = &mut x.0; + let _ = || { + let (Unit, a) = x; + a + }; + + let _ = *r; +} + +// The same is true for an equivalent enum +fn match_unit_enum(mut x: (SingleVariant, u32)) { + let r = &mut x.0; + let _ = || { + let (SingleVariant::A, a) = x; + a + }; + + let _ = *r; +} + +// More generally, destructuring a struct should only capture the fields being touched +fn match_struct(mut x: SStruct) { + let r = &mut x.a; + let _ = || { + let SStruct { b, .. } = x; + b + }; + + let _ = *r; +} + +fn match_tuple_struct(mut x: TStruct) { + let r = &mut x.0; + let _ = || { + let TStruct(_, a) = x; + a + }; + + let _ = *r; +} + +// The same is true for an equivalent enum as well +fn match_singleton(mut x: SSingle) { + let SSingle::A { a: ref mut r, .. } = x; + let _ = || { + let SSingle::A { b, .. } = x; + b + }; + + let _ = *r; +} + +fn match_tuple_singleton(mut x: TSingle) { + let TSingle::A(ref mut r, _) = x; + let _ = || { + let TSingle::A(_, a) = x; + a + }; + + let _ = *r; +} + fn main() {} diff --git a/tests/ui/closures/or-patterns-issue-137467.rs b/tests/ui/closures/or-patterns-issue-137467.rs index 5a1e84e1c9a0..de2a4beeaf9d 100644 --- a/tests/ui/closures/or-patterns-issue-137467.rs +++ b/tests/ui/closures/or-patterns-issue-137467.rs @@ -40,30 +40,6 @@ fn match_unit_variant(x: (Choice, u32, u32)) { }; } -struct Unit; - -fn match_unit_struct(mut x: (Unit, u32)) { - let r = &mut x.0; - let _ = || { - let (Unit, a) = x; - a - }; - - let _ = *r; -} - -enum Also { Unit } - -fn match_unit_enum(mut x: (Also, u32)) { - let r = &mut x.0; - let _ = || { - let (Also::Unit, a) = x; - a - }; - - let _ = *r; -} - enum TEnum { A(u32), B(u32), @@ -99,46 +75,6 @@ enum SSingle { struct TStruct(u32, u32); struct SStruct { a: u32, b: u32 } -fn match_struct(mut x: SStruct) { - let r = &mut x.a; - let _ = || { - let SStruct { b, .. } = x; - b - }; - - let _ = *r; -} - -fn match_tuple_struct(mut x: TStruct) { - let r = &mut x.0; - let _ = || { - let TStruct(_, a) = x; - a - }; - - let _ = *r; -} - -fn match_singleton(mut x: SSingle) { - let SSingle::A { a: ref mut r, .. } = x; - let _ = || { - let SSingle::A { b, .. } = x; - b - }; - - let _ = *r; -} - -fn match_tuple_singleton(mut x: TSingle) { - let TSingle::A(ref mut r, _) = x; - let _ = || { - let TSingle::A(_, a) = x; - a - }; - - let _ = *r; -} - fn match_slice(x: (&[u32], u32, u32)) { let _ = || { let (([], a, _) | ([_, ..], _, a)) = x; From 4e090078b46833b2b71179b7e4382ddbddafc4f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maja=20K=C4=85dzio=C5=82ka?= Date: Thu, 15 Jan 2026 17:24:27 +0100 Subject: [PATCH 0737/1061] capture-enums.rs: get rid of feature gate noise --- .../2229_closure_analysis/capture-enums.rs | 7 +-- .../capture-enums.stderr | 51 ++++++------------- 2 files changed, 16 insertions(+), 42 deletions(-) diff --git a/tests/ui/closures/2229_closure_analysis/capture-enums.rs b/tests/ui/closures/2229_closure_analysis/capture-enums.rs index 4c600ccdaa43..36b98351854b 100644 --- a/tests/ui/closures/2229_closure_analysis/capture-enums.rs +++ b/tests/ui/closures/2229_closure_analysis/capture-enums.rs @@ -1,6 +1,7 @@ //@ edition:2021 #![feature(rustc_attrs)] +#![feature(stmt_expr_attributes)] enum Info { Point(i32, i32, String), @@ -14,9 +15,6 @@ fn multi_variant_enum() { let meta = Info::Meta("meta".into(), vec); let c = #[rustc_capture_analysis] - //~^ ERROR: attributes on expressions are experimental - //~| NOTE: see issue #15701 - //~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date || { //~^ ERROR First Pass analysis includes: //~| ERROR Min Capture analysis includes: @@ -48,9 +46,6 @@ fn single_variant_enum() { let point = SingleVariant::Point(10, -10, "1".into()); let c = #[rustc_capture_analysis] - //~^ ERROR: attributes on expressions are experimental - //~| NOTE: see issue #15701 - //~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date || { //~^ ERROR First Pass analysis includes: //~| ERROR Min Capture analysis includes: diff --git a/tests/ui/closures/2229_closure_analysis/capture-enums.stderr b/tests/ui/closures/2229_closure_analysis/capture-enums.stderr index b62384ffe12e..2f49c8668f85 100644 --- a/tests/ui/closures/2229_closure_analysis/capture-enums.stderr +++ b/tests/ui/closures/2229_closure_analysis/capture-enums.stderr @@ -1,25 +1,5 @@ -error[E0658]: attributes on expressions are experimental - --> $DIR/capture-enums.rs:16:13 - | -LL | let c = #[rustc_capture_analysis] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #15701 for more information - = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: attributes on expressions are experimental - --> $DIR/capture-enums.rs:50:13 - | -LL | let c = #[rustc_capture_analysis] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #15701 for more information - = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error: First Pass analysis includes: - --> $DIR/capture-enums.rs:20:5 + --> $DIR/capture-enums.rs:18:5 | LL | / || { LL | | @@ -30,38 +10,38 @@ LL | | }; | |_____^ | note: Capturing point[] -> Immutable - --> $DIR/capture-enums.rs:23:41 + --> $DIR/capture-enums.rs:21:41 | LL | if let Info::Point(_, _, str) = point { | ^^^^^ note: Capturing point[] -> Immutable - --> $DIR/capture-enums.rs:23:41 + --> $DIR/capture-enums.rs:21:41 | LL | if let Info::Point(_, _, str) = point { | ^^^^^ note: Capturing point[(2, 0)] -> ByValue - --> $DIR/capture-enums.rs:23:41 + --> $DIR/capture-enums.rs:21:41 | LL | if let Info::Point(_, _, str) = point { | ^^^^^ note: Capturing meta[] -> Immutable - --> $DIR/capture-enums.rs:31:35 + --> $DIR/capture-enums.rs:29:35 | LL | if let Info::Meta(_, v) = meta { | ^^^^ note: Capturing meta[] -> Immutable - --> $DIR/capture-enums.rs:31:35 + --> $DIR/capture-enums.rs:29:35 | LL | if let Info::Meta(_, v) = meta { | ^^^^ note: Capturing meta[(1, 1)] -> ByValue - --> $DIR/capture-enums.rs:31:35 + --> $DIR/capture-enums.rs:29:35 | LL | if let Info::Meta(_, v) = meta { | ^^^^ error: Min Capture analysis includes: - --> $DIR/capture-enums.rs:20:5 + --> $DIR/capture-enums.rs:18:5 | LL | / || { LL | | @@ -72,18 +52,18 @@ LL | | }; | |_____^ | note: Min Capture point[] -> ByValue - --> $DIR/capture-enums.rs:23:41 + --> $DIR/capture-enums.rs:21:41 | LL | if let Info::Point(_, _, str) = point { | ^^^^^ note: Min Capture meta[] -> ByValue - --> $DIR/capture-enums.rs:31:35 + --> $DIR/capture-enums.rs:29:35 | LL | if let Info::Meta(_, v) = meta { | ^^^^ error: First Pass analysis includes: - --> $DIR/capture-enums.rs:54:5 + --> $DIR/capture-enums.rs:49:5 | LL | / || { LL | | @@ -95,13 +75,13 @@ LL | | }; | |_____^ | note: Capturing point[(2, 0)] -> ByValue - --> $DIR/capture-enums.rs:57:47 + --> $DIR/capture-enums.rs:52:47 | LL | let SingleVariant::Point(_, _, str) = point; | ^^^^^ error: Min Capture analysis includes: - --> $DIR/capture-enums.rs:54:5 + --> $DIR/capture-enums.rs:49:5 | LL | / || { LL | | @@ -113,11 +93,10 @@ LL | | }; | |_____^ | note: Min Capture point[(2, 0)] -> ByValue - --> $DIR/capture-enums.rs:57:47 + --> $DIR/capture-enums.rs:52:47 | LL | let SingleVariant::Point(_, _, str) = point; | ^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0658`. From 940a48966fd1c4cf8809abcac8d501cf47e4576c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maja=20K=C4=85dzio=C5=82ka?= Date: Thu, 15 Jan 2026 17:30:51 +0100 Subject: [PATCH 0738/1061] non-exhaustive-match.rs: actually test what the comments say --- .../2229_closure_analysis/match/non-exhaustive-match.rs | 2 ++ .../match/non-exhaustive-match.stderr | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.rs b/tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.rs index 322555827181..5b7259c6c2cc 100644 --- a/tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.rs +++ b/tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.rs @@ -10,6 +10,8 @@ // Ignore non_exhaustive in the same crate #[non_exhaustive] enum L1 { A, B } + +#[non_exhaustive] enum L2 { C } extern crate match_non_exhaustive_lib; diff --git a/tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr b/tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr index 85426dd9a5ea..99d33b05429e 100644 --- a/tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr +++ b/tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: `L1::B` not covered - --> $DIR/non-exhaustive-match.rs:26:25 + --> $DIR/non-exhaustive-match.rs:28:25 | LL | let _b = || { match l1 { L1::A => () } }; | ^^ pattern `L1::B` not covered @@ -16,7 +16,7 @@ LL | let _b = || { match l1 { L1::A => (), L1::B => todo!() } }; | ++++++++++++++++++ error[E0004]: non-exhaustive patterns: type `E1` is non-empty - --> $DIR/non-exhaustive-match.rs:37:25 + --> $DIR/non-exhaustive-match.rs:39:25 | LL | let _d = || { match e1 {} }; | ^^ @@ -35,7 +35,7 @@ LL ~ } }; | error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/non-exhaustive-match.rs:39:25 + --> $DIR/non-exhaustive-match.rs:41:25 | LL | let _e = || { match e2 { E2::A => (), E2::B => () } }; | ^^ pattern `_` not covered @@ -53,7 +53,7 @@ LL | let _e = || { match e2 { E2::A => (), E2::B => (), _ => todo!() } }; | ++++++++++++++ error[E0505]: cannot move out of `e3` because it is borrowed - --> $DIR/non-exhaustive-match.rs:46:22 + --> $DIR/non-exhaustive-match.rs:48:22 | LL | let _g = || { match e3 { E3::C => (), _ => () } }; | -- -- borrow occurs due to use in closure From a28b279357283aacb9cfb0ecb8321a798738df46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maja=20K=C4=85dzio=C5=82ka?= Date: Wed, 14 Jan 2026 23:47:33 +0100 Subject: [PATCH 0739/1061] Make some mir-opt tests more resilient --- tests/mir-opt/unreachable.rs | 7 ++++--- tests/mir-opt/unreachable_enum_branching.rs | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/tests/mir-opt/unreachable.rs b/tests/mir-opt/unreachable.rs index f7f4815ae7ce..afab1291fc3d 100644 --- a/tests/mir-opt/unreachable.rs +++ b/tests/mir-opt/unreachable.rs @@ -47,10 +47,11 @@ fn as_match() { // CHECK: bb1: { // CHECK: [[eq:_.*]] = Ne({{.*}}, const 1_isize); // CHECK-NEXT: assume(move [[eq]]); - // CHECK-NEXT: goto -> bb2; - // CHECK: bb2: { + // CHECK-NEXT: goto -> [[return:bb.*]]; + // CHECK: [[return]]: { + // CHECK-NOT: {{bb.*}}: { // CHECK: return; - // CHECK: bb3: { + // CHECK: {{bb.*}}: { // CHECK-NEXT: unreachable; match empty() { Some(_x) => match _x {}, diff --git a/tests/mir-opt/unreachable_enum_branching.rs b/tests/mir-opt/unreachable_enum_branching.rs index 7647f9bf0779..0f6656f4168e 100644 --- a/tests/mir-opt/unreachable_enum_branching.rs +++ b/tests/mir-opt/unreachable_enum_branching.rs @@ -49,7 +49,7 @@ struct Plop { fn simple() { // CHECK-LABEL: fn simple( // CHECK: [[discr:_.*]] = discriminant( - // CHECK: switchInt(move [[discr]]) -> [0: [[unreachable:bb.*]], 1: [[unreachable]], 2: bb1, otherwise: [[unreachable]]]; + // CHECK: switchInt(move [[discr]]) -> [0: [[unreachable:bb.*]], 1: [[unreachable]], 2: {{bb.*}}, otherwise: [[unreachable]]]; // CHECK: [[unreachable]]: { // CHECK-NEXT: unreachable; match Test1::C { @@ -63,7 +63,7 @@ fn simple() { fn custom_discriminant() { // CHECK-LABEL: fn custom_discriminant( // CHECK: [[discr:_.*]] = discriminant( - // CHECK: switchInt(move [[discr]]) -> [4: bb3, 5: bb2, otherwise: [[unreachable:bb.*]]]; + // CHECK: switchInt(move [[discr]]) -> [4: {{bb.*}}, 5: {{bb.*}}, otherwise: [[unreachable:bb.*]]]; // CHECK: [[unreachable]]: { // CHECK-NEXT: unreachable; match Test2::D { @@ -76,7 +76,7 @@ fn custom_discriminant() { fn otherwise_t1() { // CHECK-LABEL: fn otherwise_t1( // CHECK: [[discr:_.*]] = discriminant( - // CHECK: switchInt(move [[discr]]) -> [0: bb5, 1: bb5, 2: bb1, otherwise: [[unreachable:bb.*]]]; + // CHECK: switchInt(move [[discr]]) -> [0: {{bb.*}}, 1: {{bb.*}}, 2: {{bb.*}}, otherwise: [[unreachable:bb.*]]]; // CHECK: [[unreachable]]: { // CHECK-NEXT: unreachable; match Test1::C { @@ -90,7 +90,7 @@ fn otherwise_t1() { fn otherwise_t2() { // CHECK-LABEL: fn otherwise_t2( // CHECK: [[discr:_.*]] = discriminant( - // CHECK: switchInt(move [[discr]]) -> [4: bb2, 5: bb1, otherwise: [[unreachable:bb.*]]]; + // CHECK: switchInt(move [[discr]]) -> [4: {{bb.*}}, 5: {{bb.*}}, otherwise: [[unreachable:bb.*]]]; // CHECK: [[unreachable]]: { // CHECK-NEXT: unreachable; match Test2::D { From d194795f142639a7155ce82422f47fc56c53ed4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 15 Jan 2026 19:32:39 +0000 Subject: [PATCH 0740/1061] Do not recover from `Trait()` if generic list is unterminated If we encounter `fn foo`), we bail from the recovery as more likely there could have been a missing closing `>` and the `(` corresponds to the start of the fn parameter list. --- compiler/rustc_parse/src/parser/generics.rs | 13 ++++- compiler/rustc_parse/src/parser/mod.rs | 3 ++ compiler/rustc_parse/src/parser/ty.rs | 47 +++++++++++++++++-- .../missing-closing-generics-bracket.fixed | 10 ++++ .../missing-closing-generics-bracket.rs | 10 ++++ .../missing-closing-generics-bracket.stderr | 13 +++++ 6 files changed, 91 insertions(+), 5 deletions(-) create mode 100644 tests/ui/parser/missing-closing-generics-bracket.fixed create mode 100644 tests/ui/parser/missing-closing-generics-bracket.rs create mode 100644 tests/ui/parser/missing-closing-generics-bracket.stderr diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index ef6c9cc344ce..8c02092fd678 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -204,9 +204,11 @@ impl<'a> Parser<'a> { pub(super) fn parse_generic_params(&mut self) -> PResult<'a, ThinVec> { let mut params = ThinVec::new(); let mut done = false; + let prev = self.parsing_generics; + self.parsing_generics = true; while !done { let attrs = self.parse_outer_attributes()?; - let param = self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| { + let param = match self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| { if this.eat_keyword_noexpect(kw::SelfUpper) { // `Self` as a generic param is invalid. Here we emit the diagnostic and continue parsing // as if `Self` never existed. @@ -288,7 +290,13 @@ impl<'a> Parser<'a> { } // We just ate the comma, so no need to capture the trailing token. Ok((param, Trailing::No, UsePreAttrPos::No)) - })?; + }) { + Ok(param) => param, + Err(err) => { + self.parsing_generics = prev; + return Err(err); + } + }; if let Some(param) = param { params.push(param); @@ -296,6 +304,7 @@ impl<'a> Parser<'a> { break; } } + self.parsing_generics = prev; Ok(params) } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index d6e99bc540f7..ca2048d07147 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -212,6 +212,8 @@ pub struct Parser<'a> { /// See the comments in the `parse_path_segment` function for more details. unmatched_angle_bracket_count: u16, angle_bracket_nesting: u16, + /// Keep track of when we're within `<...>` for proper error recovery. + parsing_generics: bool = false, last_unexpected_token_span: Option, /// If present, this `Parser` is not parsing Rust code but rather a macro call. @@ -372,6 +374,7 @@ impl<'a> Parser<'a> { }, current_closure: None, recovery: Recovery::Allowed, + .. }; // Make parser point to the first token. diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 0185c51c5c56..380b6a214846 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -1488,14 +1488,44 @@ impl<'a> Parser<'a> { return Ok(()); } + let snapshot = if self.parsing_generics { + // The snapshot is only relevant if we're parsing the generics of an `fn` to avoid + // incorrect recovery. + Some(self.create_snapshot_for_diagnostic()) + } else { + None + }; // Parse `(T, U) -> R`. let inputs_lo = self.token.span; let mode = FnParseMode { req_name: |_, _| false, context: FnContext::Free, req_body: false }; - let inputs: ThinVec<_> = - self.parse_fn_params(&mode)?.into_iter().map(|input| input.ty).collect(); + let params = match self.parse_fn_params(&mode) { + Ok(params) => params, + Err(err) => { + if let Some(snapshot) = snapshot { + self.restore_snapshot(snapshot); + err.cancel(); + return Ok(()); + } else { + return Err(err); + } + } + }; + let inputs: ThinVec<_> = params.into_iter().map(|input| input.ty).collect(); let inputs_span = inputs_lo.to(self.prev_token.span); - let output = self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverReturnSign::No)?; + let output = match self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverReturnSign::No) + { + Ok(output) => output, + Err(err) => { + if let Some(snapshot) = snapshot { + self.restore_snapshot(snapshot); + err.cancel(); + return Ok(()); + } else { + return Err(err); + } + } + }; let args = ast::ParenthesizedArgs { span: fn_path_segment.span().to(self.prev_token.span), inputs, @@ -1503,6 +1533,17 @@ impl<'a> Parser<'a> { output, } .into(); + + if let Some(snapshot) = snapshot + && ![token::Comma, token::Gt, token::Plus].contains(&self.token.kind) + { + // We would expect another bound or the end of type params by now. Most likely we've + // encountered a `(` *not* representing `Trait()`, but rather the start of the `fn`'s + // argument list where the generic param list wasn't properly closed. + self.restore_snapshot(snapshot); + return Ok(()); + } + *fn_path_segment = ast::PathSegment { ident: fn_path_segment.ident, args: Some(args), diff --git a/tests/ui/parser/missing-closing-generics-bracket.fixed b/tests/ui/parser/missing-closing-generics-bracket.fixed new file mode 100644 index 000000000000..3166887fa8c3 --- /dev/null +++ b/tests/ui/parser/missing-closing-generics-bracket.fixed @@ -0,0 +1,10 @@ +// Issue #141436 +//@ run-rustfix +#![allow(dead_code)] + +trait Trait<'a> {} + +fn foo>() {} +//~^ ERROR expected one of + +fn main() {} diff --git a/tests/ui/parser/missing-closing-generics-bracket.rs b/tests/ui/parser/missing-closing-generics-bracket.rs new file mode 100644 index 000000000000..9424e3467246 --- /dev/null +++ b/tests/ui/parser/missing-closing-generics-bracket.rs @@ -0,0 +1,10 @@ +// Issue #141436 +//@ run-rustfix +#![allow(dead_code)] + +trait Trait<'a> {} + +fn foo() {} +//~^ ERROR expected one of + +fn main() {} diff --git a/tests/ui/parser/missing-closing-generics-bracket.stderr b/tests/ui/parser/missing-closing-generics-bracket.stderr new file mode 100644 index 000000000000..c4287301c595 --- /dev/null +++ b/tests/ui/parser/missing-closing-generics-bracket.stderr @@ -0,0 +1,13 @@ +error: expected one of `+`, `,`, `::`, `=`, or `>`, found `(` + --> $DIR/missing-closing-generics-bracket.rs:7:25 + | +LL | fn foo() {} + | ^ expected one of `+`, `,`, `::`, `=`, or `>` + | +help: you might have meant to end the type parameters here + | +LL | fn foo>() {} + | + + +error: aborting due to 1 previous error + From 3df0dc880376ef16076851046c40f2ad7374b63c Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sat, 10 Jan 2026 14:21:33 +0100 Subject: [PATCH 0741/1061] mark rust_dealloc as captures(address) Co-authored-by: Ralf Jung --- compiler/rustc_codegen_llvm/src/attributes.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index a25ce9e5a90a..bf6bb81b53b0 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -517,7 +517,16 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( to_add.push(llvm::CreateAllocKindAttr(cx.llcx, AllocKindFlags::Free)); // applies to argument place instead of function place let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx); - attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]); + let attrs: &[_] = if llvm_util::get_version() >= (21, 0, 0) { + // "Does not capture provenance" means "if the function call stashes the pointer somewhere, + // accessing that pointer after the function returns is UB". That is definitely the case here since + // freeing will destroy the provenance. + let captures_addr = AttributeKind::CapturesAddress.create_attr(cx.llcx); + &[allocated_pointer, captures_addr] + } else { + &[allocated_pointer] + }; + attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), attrs); } if let Some(align) = codegen_fn_attrs.alignment { llvm::set_alignment(llfn, align); From c6c4372f8231bab89007267c23a42e35b177578b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 15 Jan 2026 19:46:54 +0000 Subject: [PATCH 0742/1061] Use default field values in `Parser` --- compiler/rustc_ast/src/token.rs | 4 +- compiler/rustc_parse/src/parser/mod.rs | 39 +++++++------------ compiler/rustc_parse/src/parser/token_type.rs | 2 +- 3 files changed, 16 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index accf4d181632..e0807dbceee4 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -625,12 +625,12 @@ impl TokenKind { } impl Token { - pub fn new(kind: TokenKind, span: Span) -> Self { + pub const fn new(kind: TokenKind, span: Span) -> Self { Token { kind, span } } /// Some token that will be thrown away later. - pub fn dummy() -> Self { + pub const fn dummy() -> Self { Token::new(TokenKind::Question, DUMMY_SP) } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index ca2048d07147..4145cd5727dc 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -175,17 +175,17 @@ pub enum Recovery { pub struct Parser<'a> { pub psess: &'a ParseSess, /// The current token. - pub token: Token, + pub token: Token = Token::dummy(), /// The spacing for the current token. - token_spacing: Spacing, + token_spacing: Spacing = Spacing::Alone, /// The previous token. - pub prev_token: Token, - pub capture_cfg: bool, - restrictions: Restrictions, - expected_token_types: TokenTypeSet, + pub prev_token: Token = Token::dummy(), + pub capture_cfg: bool = false, + restrictions: Restrictions = Restrictions::empty(), + expected_token_types: TokenTypeSet = TokenTypeSet::new(), token_cursor: TokenCursor, // The number of calls to `bump`, i.e. the position in the token stream. - num_bump_calls: u32, + num_bump_calls: u32 = 0, // During parsing we may sometimes need to "unglue" a glued token into two // or three component tokens (e.g. `>>` into `>` and `>`, or `>>=` into `>` // and `>` and `=`), so the parser can consume them one at a time. This @@ -204,27 +204,27 @@ pub struct Parser<'a> { // // This value is always 0, 1, or 2. It can only reach 2 when splitting // `>>=` or `<<=`. - break_last_token: u32, + break_last_token: u32 = 0, /// This field is used to keep track of how many left angle brackets we have seen. This is /// required in order to detect extra leading left angle brackets (`<` characters) and error /// appropriately. /// /// See the comments in the `parse_path_segment` function for more details. - unmatched_angle_bracket_count: u16, - angle_bracket_nesting: u16, + unmatched_angle_bracket_count: u16 = 0, + angle_bracket_nesting: u16 = 0, /// Keep track of when we're within `<...>` for proper error recovery. parsing_generics: bool = false, - last_unexpected_token_span: Option, + last_unexpected_token_span: Option = None, /// If present, this `Parser` is not parsing Rust code but rather a macro call. subparser_name: Option<&'static str>, capture_state: CaptureState, /// This allows us to recover when the user forget to add braces around /// multiple statements in the closure body. - current_closure: Option, + current_closure: Option = None, /// Whether the parser is allowed to do recovery. /// This is disabled when parsing macro arguments, see #103534 - recovery: Recovery, + recovery: Recovery = Recovery::Allowed, } // This type is used a lot, e.g. it's cloned when matching many declarative macro rules with @@ -353,18 +353,7 @@ impl<'a> Parser<'a> { ) -> Self { let mut parser = Parser { psess, - token: Token::dummy(), - token_spacing: Spacing::Alone, - prev_token: Token::dummy(), - capture_cfg: false, - restrictions: Restrictions::empty(), - expected_token_types: TokenTypeSet::new(), token_cursor: TokenCursor { curr: TokenTreeCursor::new(stream), stack: Vec::new() }, - num_bump_calls: 0, - break_last_token: 0, - unmatched_angle_bracket_count: 0, - angle_bracket_nesting: 0, - last_unexpected_token_span: None, subparser_name, capture_state: CaptureState { capturing: Capturing::No, @@ -372,8 +361,6 @@ impl<'a> Parser<'a> { inner_attr_parser_ranges: Default::default(), seen_attrs: IntervalSet::new(u32::MAX as usize), }, - current_closure: None, - recovery: Recovery::Allowed, .. }; diff --git a/compiler/rustc_parse/src/parser/token_type.rs b/compiler/rustc_parse/src/parser/token_type.rs index e5dda7cf9104..567b1be5e5d9 100644 --- a/compiler/rustc_parse/src/parser/token_type.rs +++ b/compiler/rustc_parse/src/parser/token_type.rs @@ -585,7 +585,7 @@ macro_rules! exp { pub(super) struct TokenTypeSet(u128); impl TokenTypeSet { - pub(super) fn new() -> TokenTypeSet { + pub(super) const fn new() -> TokenTypeSet { TokenTypeSet(0) } From 9750d22c17092fa747e088ae24bb749077edefa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 13 Jan 2026 21:13:48 +0000 Subject: [PATCH 0743/1061] Silence unused type param and inference errors on struct parse error --- compiler/rustc_hir/src/hir.rs | 20 +++++++++++++++ .../rustc_hir_analysis/src/check/wfcheck.rs | 7 +++++- .../error_reporting/infer/need_type_info.rs | 25 ++++++++++++++++++- .../structs/parse-error-with-type-param.fixed | 14 +++++++++++ .../ui/structs/parse-error-with-type-param.rs | 14 +++++++++++ .../parse-error-with-type-param.stderr | 18 +++++++++++++ 6 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 tests/ui/structs/parse-error-with-type-param.fixed create mode 100644 tests/ui/structs/parse-error-with-type-param.rs create mode 100644 tests/ui/structs/parse-error-with-type-param.stderr diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index dac4c7e3965a..b296522749f0 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4525,6 +4525,26 @@ impl ItemKind<'_> { _ => return None, }) } + + pub fn recovered(&self) -> bool { + match self { + ItemKind::Struct( + _, + _, + VariantData::Struct { recovered: ast::Recovered::Yes(_), .. }, + ) => true, + ItemKind::Union( + _, + _, + VariantData::Struct { recovered: ast::Recovered::Yes(_), .. }, + ) => true, + ItemKind::Enum(_, _, def) => def.variants.iter().any(|v| match v.data { + VariantData::Struct { recovered: ast::Recovered::Yes(_), .. } => true, + _ => false, + }), + _ => false, + } + } } // The bodies for items are stored "out of line", in a separate diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index cfc7e57cc14e..8b50eceb26e4 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -2160,7 +2160,12 @@ fn report_bivariance<'tcx>( const_param_help, }); diag.code(E0392); - diag.emit() + if item.kind.recovered() { + // Silence potentially redundant error, as the item had a parse error. + diag.delay_as_bug() + } else { + diag.emit() + } } /// Detects cases where an ADT/LTA is trivially cyclical -- we want to detect this so diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index 0a2442b71e78..e3c8bfe4a452 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -488,7 +488,30 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } let Some(InferSource { span, kind }) = local_visitor.infer_source else { - return self.bad_inference_failure_err(failure_span, arg_data, error_code); + let silence = if let DefKind::AssocFn = self.tcx.def_kind(body_def_id) + && let parent = self.tcx.parent(body_def_id.into()) + && self.tcx.is_automatically_derived(parent) + && let Some(parent) = parent.as_local() + && let hir::Node::Item(item) = self.tcx.hir_node_by_def_id(parent) + && let hir::ItemKind::Impl(imp) = item.kind + && let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = imp.self_ty.kind + && let Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, def_id) = path.res + && let Some(def_id) = def_id.as_local() + && let hir::Node::Item(item) = self.tcx.hir_node_by_def_id(def_id) + { + // We have encountered an inference error within an automatically derived `impl`, + // from a `#[derive(..)]` on an item that had a parse error. Because the parse + // error might have caused the expanded code to be malformed, we silence the + // inference error. + item.kind.recovered() + } else { + false + }; + let mut err = self.bad_inference_failure_err(failure_span, arg_data, error_code); + if silence { + err.downgrade_to_delayed_bug(); + } + return err; }; let (source_kind, name, long_ty_path) = kind.ty_localized_msg(self); diff --git a/tests/ui/structs/parse-error-with-type-param.fixed b/tests/ui/structs/parse-error-with-type-param.fixed new file mode 100644 index 000000000000..46d1c2722843 --- /dev/null +++ b/tests/ui/structs/parse-error-with-type-param.fixed @@ -0,0 +1,14 @@ +//@ run-rustfix +// #141403 +#![allow(dead_code)] + +#[derive(Clone)] +struct B { + a: A<(T, u32)>, // <- note, comma is missing here + /// asdf + //~^ ERROR found a documentation comment that doesn't document anything + b: u32, +} +#[derive(Clone)] +struct A(T); +fn main() {} diff --git a/tests/ui/structs/parse-error-with-type-param.rs b/tests/ui/structs/parse-error-with-type-param.rs new file mode 100644 index 000000000000..27a9fc854f57 --- /dev/null +++ b/tests/ui/structs/parse-error-with-type-param.rs @@ -0,0 +1,14 @@ +//@ run-rustfix +// #141403 +#![allow(dead_code)] + +#[derive(Clone)] +struct B { + a: A<(T, u32)> // <- note, comma is missing here + /// asdf + //~^ ERROR found a documentation comment that doesn't document anything + b: u32, +} +#[derive(Clone)] +struct A(T); +fn main() {} diff --git a/tests/ui/structs/parse-error-with-type-param.stderr b/tests/ui/structs/parse-error-with-type-param.stderr new file mode 100644 index 000000000000..d01eae193b14 --- /dev/null +++ b/tests/ui/structs/parse-error-with-type-param.stderr @@ -0,0 +1,18 @@ +error[E0585]: found a documentation comment that doesn't document anything + --> $DIR/parse-error-with-type-param.rs:8:5 + | +LL | struct B { + | - while parsing this struct +LL | a: A<(T, u32)> // <- note, comma is missing here +LL | /// asdf + | ^^^^^^^^ + | + = help: doc comments must come before what they document, if a comment was intended use `//` +help: missing comma here + | +LL | a: A<(T, u32)>, // <- note, comma is missing here + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0585`. From 559e67248921197206f009792560fa2861dd1750 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 15 Jan 2026 15:41:27 +0900 Subject: [PATCH 0744/1061] move some tests --- .../issue-50600.rs => array-slice-vec/closure-in-array-len.rs} | 0 .../closure-in-array-len.stderr} | 0 .../issue-51714.rs => array-slice-vec/return-in-array-len.rs} | 0 .../return-in-array-len.stderr} | 0 .../issue-17503.rs => array-slice-vec/slice-of-multi-ref.rs} | 0 .../issue-42453.rs => derives/derive-hygiene-struct-builder.rs} | 0 tests/ui/{issues/issue-17361.rs => dst/unsized-str-mutability.rs} | 0 .../issue-28105.rs => for-loop-while/break-outside-loop-2.rs} | 0 .../break-outside-loop-2.stderr} | 0 .../issue-22706.rs => generics/type-args-on-module-in-bound.rs} | 0 .../type-args-on-module-in-bound.stderr} | 0 .../ui/{issues/issue-28109.rs => label/undeclared-label-span.rs} | 0 .../issue-28109.stderr => label/undeclared-label-span.stderr} | 0 .../{issues/issue-43057.rs => macros/column-macro-collision.rs} | 0 .../array-repeat-unit-struct.rs} | 0 .../array-repeat-unit-struct.stderr} | 0 .../vec-hashset-type-mismatch.rs} | 0 .../vec-hashset-type-mismatch.stderr} | 0 .../issue-16725.rs => privacy/auxiliary/private-extern-fn.rs} | 0 tests/ui/{issues/issue-28433.rs => privacy/privacy-sanity-2.rs} | 0 .../issue-28433.stderr => privacy/privacy-sanity-2.stderr} | 0 .../issue-16725.rs => privacy/private-extern-fn-visibility.rs} | 0 .../private-extern-fn-visibility.stderr} | 0 .../ui/{issues/issue-22894.rs => static/static-str-deref-ref.rs} | 0 .../std-sync-right-kind-impls-2.rs} | 0 25 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{issues/issue-50600.rs => array-slice-vec/closure-in-array-len.rs} (100%) rename tests/ui/{issues/issue-50600.stderr => array-slice-vec/closure-in-array-len.stderr} (100%) rename tests/ui/{issues/issue-51714.rs => array-slice-vec/return-in-array-len.rs} (100%) rename tests/ui/{issues/issue-51714.stderr => array-slice-vec/return-in-array-len.stderr} (100%) rename tests/ui/{issues/issue-17503.rs => array-slice-vec/slice-of-multi-ref.rs} (100%) rename tests/ui/{issues/issue-42453.rs => derives/derive-hygiene-struct-builder.rs} (100%) rename tests/ui/{issues/issue-17361.rs => dst/unsized-str-mutability.rs} (100%) rename tests/ui/{issues/issue-28105.rs => for-loop-while/break-outside-loop-2.rs} (100%) rename tests/ui/{issues/issue-28105.stderr => for-loop-while/break-outside-loop-2.stderr} (100%) rename tests/ui/{issues/issue-22706.rs => generics/type-args-on-module-in-bound.rs} (100%) rename tests/ui/{issues/issue-22706.stderr => generics/type-args-on-module-in-bound.stderr} (100%) rename tests/ui/{issues/issue-28109.rs => label/undeclared-label-span.rs} (100%) rename tests/ui/{issues/issue-28109.stderr => label/undeclared-label-span.stderr} (100%) rename tests/ui/{issues/issue-43057.rs => macros/column-macro-collision.rs} (100%) rename tests/ui/{issues/issue-27008.rs => mismatched_types/array-repeat-unit-struct.rs} (100%) rename tests/ui/{issues/issue-27008.stderr => mismatched_types/array-repeat-unit-struct.stderr} (100%) rename tests/ui/{issues/issue-24819.rs => mismatched_types/vec-hashset-type-mismatch.rs} (100%) rename tests/ui/{issues/issue-24819.stderr => mismatched_types/vec-hashset-type-mismatch.stderr} (100%) rename tests/ui/{issues/auxiliary/issue-16725.rs => privacy/auxiliary/private-extern-fn.rs} (100%) rename tests/ui/{issues/issue-28433.rs => privacy/privacy-sanity-2.rs} (100%) rename tests/ui/{issues/issue-28433.stderr => privacy/privacy-sanity-2.stderr} (100%) rename tests/ui/{issues/issue-16725.rs => privacy/private-extern-fn-visibility.rs} (100%) rename tests/ui/{issues/issue-16725.stderr => privacy/private-extern-fn-visibility.stderr} (100%) rename tests/ui/{issues/issue-22894.rs => static/static-str-deref-ref.rs} (100%) rename tests/ui/{issues/issue-22577.rs => threads-sendsync/std-sync-right-kind-impls-2.rs} (100%) diff --git a/tests/ui/issues/issue-50600.rs b/tests/ui/array-slice-vec/closure-in-array-len.rs similarity index 100% rename from tests/ui/issues/issue-50600.rs rename to tests/ui/array-slice-vec/closure-in-array-len.rs diff --git a/tests/ui/issues/issue-50600.stderr b/tests/ui/array-slice-vec/closure-in-array-len.stderr similarity index 100% rename from tests/ui/issues/issue-50600.stderr rename to tests/ui/array-slice-vec/closure-in-array-len.stderr diff --git a/tests/ui/issues/issue-51714.rs b/tests/ui/array-slice-vec/return-in-array-len.rs similarity index 100% rename from tests/ui/issues/issue-51714.rs rename to tests/ui/array-slice-vec/return-in-array-len.rs diff --git a/tests/ui/issues/issue-51714.stderr b/tests/ui/array-slice-vec/return-in-array-len.stderr similarity index 100% rename from tests/ui/issues/issue-51714.stderr rename to tests/ui/array-slice-vec/return-in-array-len.stderr diff --git a/tests/ui/issues/issue-17503.rs b/tests/ui/array-slice-vec/slice-of-multi-ref.rs similarity index 100% rename from tests/ui/issues/issue-17503.rs rename to tests/ui/array-slice-vec/slice-of-multi-ref.rs diff --git a/tests/ui/issues/issue-42453.rs b/tests/ui/derives/derive-hygiene-struct-builder.rs similarity index 100% rename from tests/ui/issues/issue-42453.rs rename to tests/ui/derives/derive-hygiene-struct-builder.rs diff --git a/tests/ui/issues/issue-17361.rs b/tests/ui/dst/unsized-str-mutability.rs similarity index 100% rename from tests/ui/issues/issue-17361.rs rename to tests/ui/dst/unsized-str-mutability.rs diff --git a/tests/ui/issues/issue-28105.rs b/tests/ui/for-loop-while/break-outside-loop-2.rs similarity index 100% rename from tests/ui/issues/issue-28105.rs rename to tests/ui/for-loop-while/break-outside-loop-2.rs diff --git a/tests/ui/issues/issue-28105.stderr b/tests/ui/for-loop-while/break-outside-loop-2.stderr similarity index 100% rename from tests/ui/issues/issue-28105.stderr rename to tests/ui/for-loop-while/break-outside-loop-2.stderr diff --git a/tests/ui/issues/issue-22706.rs b/tests/ui/generics/type-args-on-module-in-bound.rs similarity index 100% rename from tests/ui/issues/issue-22706.rs rename to tests/ui/generics/type-args-on-module-in-bound.rs diff --git a/tests/ui/issues/issue-22706.stderr b/tests/ui/generics/type-args-on-module-in-bound.stderr similarity index 100% rename from tests/ui/issues/issue-22706.stderr rename to tests/ui/generics/type-args-on-module-in-bound.stderr diff --git a/tests/ui/issues/issue-28109.rs b/tests/ui/label/undeclared-label-span.rs similarity index 100% rename from tests/ui/issues/issue-28109.rs rename to tests/ui/label/undeclared-label-span.rs diff --git a/tests/ui/issues/issue-28109.stderr b/tests/ui/label/undeclared-label-span.stderr similarity index 100% rename from tests/ui/issues/issue-28109.stderr rename to tests/ui/label/undeclared-label-span.stderr diff --git a/tests/ui/issues/issue-43057.rs b/tests/ui/macros/column-macro-collision.rs similarity index 100% rename from tests/ui/issues/issue-43057.rs rename to tests/ui/macros/column-macro-collision.rs diff --git a/tests/ui/issues/issue-27008.rs b/tests/ui/mismatched_types/array-repeat-unit-struct.rs similarity index 100% rename from tests/ui/issues/issue-27008.rs rename to tests/ui/mismatched_types/array-repeat-unit-struct.rs diff --git a/tests/ui/issues/issue-27008.stderr b/tests/ui/mismatched_types/array-repeat-unit-struct.stderr similarity index 100% rename from tests/ui/issues/issue-27008.stderr rename to tests/ui/mismatched_types/array-repeat-unit-struct.stderr diff --git a/tests/ui/issues/issue-24819.rs b/tests/ui/mismatched_types/vec-hashset-type-mismatch.rs similarity index 100% rename from tests/ui/issues/issue-24819.rs rename to tests/ui/mismatched_types/vec-hashset-type-mismatch.rs diff --git a/tests/ui/issues/issue-24819.stderr b/tests/ui/mismatched_types/vec-hashset-type-mismatch.stderr similarity index 100% rename from tests/ui/issues/issue-24819.stderr rename to tests/ui/mismatched_types/vec-hashset-type-mismatch.stderr diff --git a/tests/ui/issues/auxiliary/issue-16725.rs b/tests/ui/privacy/auxiliary/private-extern-fn.rs similarity index 100% rename from tests/ui/issues/auxiliary/issue-16725.rs rename to tests/ui/privacy/auxiliary/private-extern-fn.rs diff --git a/tests/ui/issues/issue-28433.rs b/tests/ui/privacy/privacy-sanity-2.rs similarity index 100% rename from tests/ui/issues/issue-28433.rs rename to tests/ui/privacy/privacy-sanity-2.rs diff --git a/tests/ui/issues/issue-28433.stderr b/tests/ui/privacy/privacy-sanity-2.stderr similarity index 100% rename from tests/ui/issues/issue-28433.stderr rename to tests/ui/privacy/privacy-sanity-2.stderr diff --git a/tests/ui/issues/issue-16725.rs b/tests/ui/privacy/private-extern-fn-visibility.rs similarity index 100% rename from tests/ui/issues/issue-16725.rs rename to tests/ui/privacy/private-extern-fn-visibility.rs diff --git a/tests/ui/issues/issue-16725.stderr b/tests/ui/privacy/private-extern-fn-visibility.stderr similarity index 100% rename from tests/ui/issues/issue-16725.stderr rename to tests/ui/privacy/private-extern-fn-visibility.stderr diff --git a/tests/ui/issues/issue-22894.rs b/tests/ui/static/static-str-deref-ref.rs similarity index 100% rename from tests/ui/issues/issue-22894.rs rename to tests/ui/static/static-str-deref-ref.rs diff --git a/tests/ui/issues/issue-22577.rs b/tests/ui/threads-sendsync/std-sync-right-kind-impls-2.rs similarity index 100% rename from tests/ui/issues/issue-22577.rs rename to tests/ui/threads-sendsync/std-sync-right-kind-impls-2.rs From 77b2a196fb13a1b4c6751c9361dad7d55a0e7d9d Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 15 Jan 2026 18:34:54 +0900 Subject: [PATCH 0745/1061] cleaned up some tests merge privacy/privacy-sanity-2 with privacy/privacy-sanity.rs Add comment to generics/type-args-on-module-in-bound.rs Add comment to array-slice-vec/closure-in-array-eln.rs Add comment to array-slice-vec/return-in-array-len.rs Merge for-loop-while/break-outside-loop-2.rs with for-loop-while/break-outside-loop.rs Add comment to macros/column-macro-collision.rs Add comment to privacy/private-extern-fn-visibility.rs Add comment to mismatched_types/vec-hashset-type-mismatch.rs Merge std-sync-right-kind-impls-2.rs with std-sync-right-kind-impls.rs Add comment to array-slice-vec/slice-of-multi-ref.rs Add comment to mismatched_types\vec-hashset-type-mismatch.rs Add comment to derives/derive-hygiene-struct-builder.rs Add comment to label/undeclared-label-span.rs Add comment to label\undeclared-label-span.rs Add comment to mismatched_types/array-repeat-unit-struct.rs --- .../array-slice-vec/closure-in-array-len.rs | 3 +- .../closure-in-array-len.stderr | 4 +- .../ui/array-slice-vec/return-in-array-len.rs | 1 + .../return-in-array-len.stderr | 8 +-- .../ui/array-slice-vec/slice-of-multi-ref.rs | 1 + .../derives/derive-hygiene-struct-builder.rs | 6 +- tests/ui/dst/unsized-str-mutability.rs | 4 +- .../ui/for-loop-while/break-outside-loop-2.rs | 8 --- .../break-outside-loop-2.stderr | 15 ----- tests/ui/for-loop-while/break-outside-loop.rs | 40 ++++++++++--- .../for-loop-while/break-outside-loop.stderr | 43 +++++++++----- .../generics/type-args-on-module-in-bound.rs | 1 + .../type-args-on-module-in-bound.stderr | 2 +- tests/ui/label/undeclared-label-span.rs | 3 +- tests/ui/label/undeclared-label-span.stderr | 4 +- tests/ui/macros/column-macro-collision.rs | 3 + .../array-repeat-unit-struct.rs | 2 + .../array-repeat-unit-struct.stderr | 2 +- .../vec-hashset-type-mismatch.rs | 4 +- .../vec-hashset-type-mismatch.stderr | 6 +- tests/ui/privacy/privacy-sanity-2.rs | 12 ---- tests/ui/privacy/privacy-sanity-2.stderr | 19 ------ tests/ui/privacy/privacy-sanity.rs | 15 +++++ tests/ui/privacy/privacy-sanity.stderr | 58 ++++++++++++++----- .../privacy/private-extern-fn-visibility.rs | 11 ++-- .../private-extern-fn-visibility.stderr | 8 +-- tests/ui/static/static-str-deref-ref.rs | 1 + .../std-sync-right-kind-impls-2.rs | 25 -------- .../std-sync-right-kind-impls.rs | 18 +++++- 29 files changed, 180 insertions(+), 147 deletions(-) delete mode 100644 tests/ui/for-loop-while/break-outside-loop-2.rs delete mode 100644 tests/ui/for-loop-while/break-outside-loop-2.stderr delete mode 100644 tests/ui/privacy/privacy-sanity-2.rs delete mode 100644 tests/ui/privacy/privacy-sanity-2.stderr delete mode 100644 tests/ui/threads-sendsync/std-sync-right-kind-impls-2.rs diff --git a/tests/ui/array-slice-vec/closure-in-array-len.rs b/tests/ui/array-slice-vec/closure-in-array-len.rs index 963e607afcfd..ce13e0f16081 100644 --- a/tests/ui/array-slice-vec/closure-in-array-len.rs +++ b/tests/ui/array-slice-vec/closure-in-array-len.rs @@ -1,4 +1,5 @@ -struct Foo ( +//! regression test for +struct Foo( fn([u8; |x: u8| {}]), //~ ERROR mismatched types ); diff --git a/tests/ui/array-slice-vec/closure-in-array-len.stderr b/tests/ui/array-slice-vec/closure-in-array-len.stderr index e3ae7f144c35..decdde042c6f 100644 --- a/tests/ui/array-slice-vec/closure-in-array-len.stderr +++ b/tests/ui/array-slice-vec/closure-in-array-len.stderr @@ -1,11 +1,11 @@ error[E0308]: mismatched types - --> $DIR/issue-50600.rs:2:13 + --> $DIR/closure-in-array-len.rs:3:13 | LL | fn([u8; |x: u8| {}]), | ^^^^^^^^^^ expected `usize`, found closure | = note: expected type `usize` - found closure `{closure@$DIR/issue-50600.rs:2:13: 2:20}` + found closure `{closure@$DIR/closure-in-array-len.rs:3:13: 3:20}` error: aborting due to 1 previous error diff --git a/tests/ui/array-slice-vec/return-in-array-len.rs b/tests/ui/array-slice-vec/return-in-array-len.rs index 03b50b7963ea..dea1bb2818bb 100644 --- a/tests/ui/array-slice-vec/return-in-array-len.rs +++ b/tests/ui/array-slice-vec/return-in-array-len.rs @@ -1,3 +1,4 @@ +//! regression test for fn main() { //~^ NOTE: not the enclosing function body //~| NOTE: not the enclosing function body diff --git a/tests/ui/array-slice-vec/return-in-array-len.stderr b/tests/ui/array-slice-vec/return-in-array-len.stderr index da3e3caea29a..974a748edc93 100644 --- a/tests/ui/array-slice-vec/return-in-array-len.stderr +++ b/tests/ui/array-slice-vec/return-in-array-len.stderr @@ -1,5 +1,5 @@ error[E0572]: return statement outside of function body - --> $DIR/issue-51714.rs:6:13 + --> $DIR/return-in-array-len.rs:7:13 | LL | / fn main() { ... | @@ -10,7 +10,7 @@ LL | | } | |_- ...not the enclosing function body error[E0572]: return statement outside of function body - --> $DIR/issue-51714.rs:10:10 + --> $DIR/return-in-array-len.rs:11:10 | LL | / fn main() { ... | @@ -21,7 +21,7 @@ LL | | } | |_- ...not the enclosing function body error[E0572]: return statement outside of function body - --> $DIR/issue-51714.rs:14:10 + --> $DIR/return-in-array-len.rs:15:10 | LL | / fn main() { ... | @@ -32,7 +32,7 @@ LL | | } | |_- ...not the enclosing function body error[E0572]: return statement outside of function body - --> $DIR/issue-51714.rs:18:10 + --> $DIR/return-in-array-len.rs:19:10 | LL | / fn main() { ... | diff --git a/tests/ui/array-slice-vec/slice-of-multi-ref.rs b/tests/ui/array-slice-vec/slice-of-multi-ref.rs index 6c966b5319cd..b4917f594d83 100644 --- a/tests/ui/array-slice-vec/slice-of-multi-ref.rs +++ b/tests/ui/array-slice-vec/slice-of-multi-ref.rs @@ -1,3 +1,4 @@ +//! regression test for //@ run-pass fn main() { let s: &[isize] = &[0, 1, 2, 3, 4]; diff --git a/tests/ui/derives/derive-hygiene-struct-builder.rs b/tests/ui/derives/derive-hygiene-struct-builder.rs index 9ed9080e8a92..95245a3b3f5a 100644 --- a/tests/ui/derives/derive-hygiene-struct-builder.rs +++ b/tests/ui/derives/derive-hygiene-struct-builder.rs @@ -1,3 +1,5 @@ +//! regression test for +//! struct named "builder" conflicted with derive macro internals. //@ run-pass #![allow(dead_code)] #![allow(non_camel_case_types)] @@ -5,6 +7,4 @@ #[derive(Debug)] struct builder; -fn main() { - -} +fn main() {} diff --git a/tests/ui/dst/unsized-str-mutability.rs b/tests/ui/dst/unsized-str-mutability.rs index 6f6fc42db383..d84fa001fd67 100644 --- a/tests/ui/dst/unsized-str-mutability.rs +++ b/tests/ui/dst/unsized-str-mutability.rs @@ -1,6 +1,6 @@ +//! regression test for +//! Test that HIR ty lowering doesn't forget about mutability of `&mut str`. //@ run-pass -// Test that HIR ty lowering doesn't forget about mutability of `&mut str`. - fn main() { fn foo(_: &mut T) {} diff --git a/tests/ui/for-loop-while/break-outside-loop-2.rs b/tests/ui/for-loop-while/break-outside-loop-2.rs deleted file mode 100644 index 1e8d2d6ccf13..000000000000 --- a/tests/ui/for-loop-while/break-outside-loop-2.rs +++ /dev/null @@ -1,8 +0,0 @@ -// Make sure that a continue span actually contains the keyword. - -fn main() { - continue //~ ERROR `continue` outside of a loop - ; - break //~ ERROR `break` outside of a loop - ; -} diff --git a/tests/ui/for-loop-while/break-outside-loop-2.stderr b/tests/ui/for-loop-while/break-outside-loop-2.stderr deleted file mode 100644 index f450256f3ecf..000000000000 --- a/tests/ui/for-loop-while/break-outside-loop-2.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0268]: `continue` outside of a loop - --> $DIR/issue-28105.rs:4:5 - | -LL | continue - | ^^^^^^^^ cannot `continue` outside of a loop - -error[E0268]: `break` outside of a loop or labeled block - --> $DIR/issue-28105.rs:6:5 - | -LL | break - | ^^^^^ cannot `break` outside of a loop or labeled block - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0268`. diff --git a/tests/ui/for-loop-while/break-outside-loop.rs b/tests/ui/for-loop-while/break-outside-loop.rs index 26769b30dd5f..06c513aa8457 100644 --- a/tests/ui/for-loop-while/break-outside-loop.rs +++ b/tests/ui/for-loop-while/break-outside-loop.rs @@ -1,25 +1,41 @@ struct Foo { - t: String + t: String, } -fn cond() -> bool { true } +fn cond() -> bool { + true +} -fn foo(_: F) where F: FnOnce() {} +fn foo(_: F) +where + F: FnOnce(), +{ +} fn main() { let pth = break; //~ ERROR: `break` outside of a loop - if cond() { continue } //~ ERROR: `continue` outside of a loop + if cond() { + continue; //~ ERROR: `continue` outside of a loop + } while cond() { - if cond() { break } - if cond() { continue } + if cond() { + break; + } + if cond() { + continue; + } foo(|| { - if cond() { break } //~ ERROR: `break` inside of a closure - if cond() { continue } //~ ERROR: `continue` inside of a closure + if cond() { + break; //~ ERROR: `break` inside of a closure + } + if cond() { + continue; //~ ERROR: `continue` inside of a closure + } }) } - let rs: Foo = Foo{t: pth}; + let rs: Foo = Foo { t: pth }; let unconstrained = break; //~ ERROR: `break` outside of a loop @@ -32,4 +48,10 @@ fn main() { //~| ERROR `break` inside of a closure }; } + + // Make sure that a continue span actually contains the keyword. (#28105) + continue //~ ERROR `continue` outside of a loop + ; + break //~ ERROR `break` outside of a loop + ; } diff --git a/tests/ui/for-loop-while/break-outside-loop.stderr b/tests/ui/for-loop-while/break-outside-loop.stderr index 9092f34df354..7dbff2d41245 100644 --- a/tests/ui/for-loop-while/break-outside-loop.stderr +++ b/tests/ui/for-loop-while/break-outside-loop.stderr @@ -1,5 +1,5 @@ error[E0767]: use of unreachable label `'lab` - --> $DIR/break-outside-loop.rs:30:19 + --> $DIR/break-outside-loop.rs:46:19 | LL | 'lab: loop { | ---- unreachable label defined here @@ -10,49 +10,62 @@ LL | break 'lab; = note: labels are unreachable through functions, closures, async blocks and modules error[E0268]: `break` outside of a loop or labeled block - --> $DIR/break-outside-loop.rs:10:15 + --> $DIR/break-outside-loop.rs:16:15 | LL | let pth = break; | ^^^^^ cannot `break` outside of a loop or labeled block error[E0268]: `continue` outside of a loop - --> $DIR/break-outside-loop.rs:11:17 + --> $DIR/break-outside-loop.rs:18:9 | -LL | if cond() { continue } - | ^^^^^^^^ cannot `continue` outside of a loop +LL | continue; + | ^^^^^^^^ cannot `continue` outside of a loop error[E0267]: `break` inside of a closure - --> $DIR/break-outside-loop.rs:17:25 + --> $DIR/break-outside-loop.rs:30:17 | LL | foo(|| { | -- enclosing closure -LL | if cond() { break } - | ^^^^^ cannot `break` inside of a closure +LL | if cond() { +LL | break; + | ^^^^^ cannot `break` inside of a closure error[E0267]: `continue` inside of a closure - --> $DIR/break-outside-loop.rs:18:25 + --> $DIR/break-outside-loop.rs:33:17 | LL | foo(|| { | -- enclosing closure -LL | if cond() { break } -LL | if cond() { continue } - | ^^^^^^^^ cannot `continue` inside of a closure +... +LL | continue; + | ^^^^^^^^ cannot `continue` inside of a closure error[E0268]: `break` outside of a loop or labeled block - --> $DIR/break-outside-loop.rs:24:25 + --> $DIR/break-outside-loop.rs:40:25 | LL | let unconstrained = break; | ^^^^^ cannot `break` outside of a loop or labeled block error[E0267]: `break` inside of a closure - --> $DIR/break-outside-loop.rs:30:13 + --> $DIR/break-outside-loop.rs:46:13 | LL | || { | -- enclosing closure LL | break 'lab; | ^^^^^^^^^^ cannot `break` inside of a closure -error: aborting due to 7 previous errors +error[E0268]: `continue` outside of a loop + --> $DIR/break-outside-loop.rs:53:5 + | +LL | continue + | ^^^^^^^^ cannot `continue` outside of a loop + +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-outside-loop.rs:55:5 + | +LL | break + | ^^^^^ cannot `break` outside of a loop or labeled block + +error: aborting due to 9 previous errors Some errors have detailed explanations: E0267, E0268, E0767. For more information about an error, try `rustc --explain E0267`. diff --git a/tests/ui/generics/type-args-on-module-in-bound.rs b/tests/ui/generics/type-args-on-module-in-bound.rs index bb8a58d3d2ec..96ca37407cfc 100644 --- a/tests/ui/generics/type-args-on-module-in-bound.rs +++ b/tests/ui/generics/type-args-on-module-in-bound.rs @@ -1,3 +1,4 @@ +//! regression test for fn is_copy::Copy>() {} //~^ ERROR type arguments are not allowed on module `marker` [E0109] fn main() {} diff --git a/tests/ui/generics/type-args-on-module-in-bound.stderr b/tests/ui/generics/type-args-on-module-in-bound.stderr index 309e11a25f1a..ac70ae63e90b 100644 --- a/tests/ui/generics/type-args-on-module-in-bound.stderr +++ b/tests/ui/generics/type-args-on-module-in-bound.stderr @@ -1,5 +1,5 @@ error[E0109]: type arguments are not allowed on module `marker` - --> $DIR/issue-22706.rs:1:29 + --> $DIR/type-args-on-module-in-bound.rs:2:29 | LL | fn is_copy::Copy>() {} | ------ ^^^ type argument not allowed diff --git a/tests/ui/label/undeclared-label-span.rs b/tests/ui/label/undeclared-label-span.rs index 755a539b5003..c6f38c067192 100644 --- a/tests/ui/label/undeclared-label-span.rs +++ b/tests/ui/label/undeclared-label-span.rs @@ -1,4 +1,5 @@ -// Make sure that label for continue and break is spanned correctly +//! regression test for +//! Make sure that label for continue and break is spanned correctly. fn main() { loop { diff --git a/tests/ui/label/undeclared-label-span.stderr b/tests/ui/label/undeclared-label-span.stderr index 0f918d3b6f70..e5451b4655d8 100644 --- a/tests/ui/label/undeclared-label-span.stderr +++ b/tests/ui/label/undeclared-label-span.stderr @@ -1,11 +1,11 @@ error[E0426]: use of undeclared label `'b` - --> $DIR/issue-28109.rs:6:9 + --> $DIR/undeclared-label-span.rs:7:9 | LL | 'b | ^^ undeclared label `'b` error[E0426]: use of undeclared label `'c` - --> $DIR/issue-28109.rs:9:9 + --> $DIR/undeclared-label-span.rs:10:9 | LL | 'c | ^^ undeclared label `'c` diff --git a/tests/ui/macros/column-macro-collision.rs b/tests/ui/macros/column-macro-collision.rs index 4dd1fe461f1b..7acf491888af 100644 --- a/tests/ui/macros/column-macro-collision.rs +++ b/tests/ui/macros/column-macro-collision.rs @@ -1,3 +1,6 @@ +//! regression test for +//! user-defined `column!` macro must not shadow +//! the built-in `column!()` used internally by `panic!()`. //@ check-pass #![allow(unused)] diff --git a/tests/ui/mismatched_types/array-repeat-unit-struct.rs b/tests/ui/mismatched_types/array-repeat-unit-struct.rs index 20aa4f282c7e..db05e1daedbd 100644 --- a/tests/ui/mismatched_types/array-repeat-unit-struct.rs +++ b/tests/ui/mismatched_types/array-repeat-unit-struct.rs @@ -1,3 +1,5 @@ +//! regression test for + struct S; fn main() { diff --git a/tests/ui/mismatched_types/array-repeat-unit-struct.stderr b/tests/ui/mismatched_types/array-repeat-unit-struct.stderr index b4bfaa278633..9a9cc946f82a 100644 --- a/tests/ui/mismatched_types/array-repeat-unit-struct.stderr +++ b/tests/ui/mismatched_types/array-repeat-unit-struct.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-27008.rs:4:17 + --> $DIR/array-repeat-unit-struct.rs:6:17 | LL | let b = [0; S]; | ^ expected `usize`, found `S` diff --git a/tests/ui/mismatched_types/vec-hashset-type-mismatch.rs b/tests/ui/mismatched_types/vec-hashset-type-mismatch.rs index 97d288e5cb14..3724a423d0dd 100644 --- a/tests/ui/mismatched_types/vec-hashset-type-mismatch.rs +++ b/tests/ui/mismatched_types/vec-hashset-type-mismatch.rs @@ -1,3 +1,4 @@ +//! regression test for //@ dont-require-annotations: NOTE use std::collections::HashSet; @@ -9,5 +10,4 @@ fn main() { //~| NOTE expected `&mut HashSet`, found `&mut Vec<_>` } -fn foo(h: &mut HashSet) { -} +fn foo(h: &mut HashSet) {} diff --git a/tests/ui/mismatched_types/vec-hashset-type-mismatch.stderr b/tests/ui/mismatched_types/vec-hashset-type-mismatch.stderr index e144f37d6e48..e778422d0064 100644 --- a/tests/ui/mismatched_types/vec-hashset-type-mismatch.stderr +++ b/tests/ui/mismatched_types/vec-hashset-type-mismatch.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-24819.rs:7:9 + --> $DIR/vec-hashset-type-mismatch.rs:8:9 | LL | foo(&mut v); | --- ^^^^^^ expected `&mut HashSet`, found `&mut Vec<_>` @@ -9,9 +9,9 @@ LL | foo(&mut v); = note: expected mutable reference `&mut HashSet` found mutable reference `&mut Vec<_>` note: function defined here - --> $DIR/issue-24819.rs:12:4 + --> $DIR/vec-hashset-type-mismatch.rs:13:4 | -LL | fn foo(h: &mut HashSet) { +LL | fn foo(h: &mut HashSet) {} | ^^^ -------------------- error: aborting due to 1 previous error diff --git a/tests/ui/privacy/privacy-sanity-2.rs b/tests/ui/privacy/privacy-sanity-2.rs deleted file mode 100644 index 2298ad240d56..000000000000 --- a/tests/ui/privacy/privacy-sanity-2.rs +++ /dev/null @@ -1,12 +0,0 @@ -enum Bird { - pub Duck, - //~^ ERROR visibility qualifiers are not permitted here - Goose, - pub(crate) Dove - //~^ ERROR visibility qualifiers are not permitted here -} - - -fn main() { - let y = Bird::Goose; -} diff --git a/tests/ui/privacy/privacy-sanity-2.stderr b/tests/ui/privacy/privacy-sanity-2.stderr deleted file mode 100644 index 0fa67e35f1d4..000000000000 --- a/tests/ui/privacy/privacy-sanity-2.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0449]: visibility qualifiers are not permitted here - --> $DIR/issue-28433.rs:2:5 - | -LL | pub Duck, - | ^^^ help: remove the qualifier - | - = note: enum variants and their fields always share the visibility of the enum they are in - -error[E0449]: visibility qualifiers are not permitted here - --> $DIR/issue-28433.rs:5:5 - | -LL | pub(crate) Dove - | ^^^^^^^^^^ help: remove the qualifier - | - = note: enum variants and their fields always share the visibility of the enum they are in - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0449`. diff --git a/tests/ui/privacy/privacy-sanity.rs b/tests/ui/privacy/privacy-sanity.rs index 6622089dda6d..fcd03394d631 100644 --- a/tests/ui/privacy/privacy-sanity.rs +++ b/tests/ui/privacy/privacy-sanity.rs @@ -25,6 +25,14 @@ pub extern "C" { //~ ERROR visibility qualifiers are not permitted here pub static St: u8; } +enum Bird { + pub Duck, + //~^ ERROR visibility qualifiers are not permitted here + pub(crate) Dove, + //~^ ERROR visibility qualifiers are not permitted here + Goose, +} + const MAIN: u8 = { pub trait Tr { fn f(); @@ -79,4 +87,11 @@ fn main() { pub fn f(); pub static St: u8; } + enum Bird { + pub Duck, + //~^ ERROR visibility qualifiers are not permitted here + pub(crate) Dove, + //~^ ERROR visibility qualifiers are not permitted here + Goose, + } } diff --git a/tests/ui/privacy/privacy-sanity.stderr b/tests/ui/privacy/privacy-sanity.stderr index 0acb05cbabaa..fd643357335a 100644 --- a/tests/ui/privacy/privacy-sanity.stderr +++ b/tests/ui/privacy/privacy-sanity.stderr @@ -47,7 +47,23 @@ LL | pub extern "C" { = note: place qualifiers on individual foreign items instead error[E0449]: visibility qualifiers are not permitted here - --> $DIR/privacy-sanity.rs:39:5 + --> $DIR/privacy-sanity.rs:29:5 + | +LL | pub Duck, + | ^^^ help: remove the qualifier + | + = note: enum variants and their fields always share the visibility of the enum they are in + +error[E0449]: visibility qualifiers are not permitted here + --> $DIR/privacy-sanity.rs:31:5 + | +LL | pub(crate) Dove, + | ^^^^^^^^^^ help: remove the qualifier + | + = note: enum variants and their fields always share the visibility of the enum they are in + +error[E0449]: visibility qualifiers are not permitted here + --> $DIR/privacy-sanity.rs:47:5 | LL | pub impl Tr for S { | ^^^ help: remove the qualifier @@ -55,7 +71,7 @@ LL | pub impl Tr for S { = note: trait items always share the visibility of their trait error[E0449]: visibility qualifiers are not permitted here - --> $DIR/privacy-sanity.rs:40:9 + --> $DIR/privacy-sanity.rs:48:9 | LL | pub fn f() {} | ^^^ help: remove the qualifier @@ -63,7 +79,7 @@ LL | pub fn f() {} = note: trait items always share the visibility of their trait error[E0449]: visibility qualifiers are not permitted here - --> $DIR/privacy-sanity.rs:41:9 + --> $DIR/privacy-sanity.rs:49:9 | LL | pub const C: u8 = 0; | ^^^ help: remove the qualifier @@ -71,7 +87,7 @@ LL | pub const C: u8 = 0; = note: trait items always share the visibility of their trait error[E0449]: visibility qualifiers are not permitted here - --> $DIR/privacy-sanity.rs:42:9 + --> $DIR/privacy-sanity.rs:50:9 | LL | pub type T = u8; | ^^^ help: remove the qualifier @@ -79,7 +95,7 @@ LL | pub type T = u8; = note: trait items always share the visibility of their trait error[E0449]: visibility qualifiers are not permitted here - --> $DIR/privacy-sanity.rs:44:5 + --> $DIR/privacy-sanity.rs:52:5 | LL | pub impl S { | ^^^ help: remove the qualifier @@ -87,7 +103,7 @@ LL | pub impl S { = note: place qualifiers on individual impl items instead error[E0449]: visibility qualifiers are not permitted here - --> $DIR/privacy-sanity.rs:49:5 + --> $DIR/privacy-sanity.rs:57:5 | LL | pub extern "C" { | ^^^ help: remove the qualifier @@ -95,7 +111,7 @@ LL | pub extern "C" { = note: place qualifiers on individual foreign items instead error[E0449]: visibility qualifiers are not permitted here - --> $DIR/privacy-sanity.rs:68:5 + --> $DIR/privacy-sanity.rs:76:5 | LL | pub impl Tr for S { | ^^^ help: remove the qualifier @@ -103,7 +119,7 @@ LL | pub impl Tr for S { = note: trait items always share the visibility of their trait error[E0449]: visibility qualifiers are not permitted here - --> $DIR/privacy-sanity.rs:69:9 + --> $DIR/privacy-sanity.rs:77:9 | LL | pub fn f() {} | ^^^ help: remove the qualifier @@ -111,7 +127,7 @@ LL | pub fn f() {} = note: trait items always share the visibility of their trait error[E0449]: visibility qualifiers are not permitted here - --> $DIR/privacy-sanity.rs:70:9 + --> $DIR/privacy-sanity.rs:78:9 | LL | pub const C: u8 = 0; | ^^^ help: remove the qualifier @@ -119,7 +135,7 @@ LL | pub const C: u8 = 0; = note: trait items always share the visibility of their trait error[E0449]: visibility qualifiers are not permitted here - --> $DIR/privacy-sanity.rs:71:9 + --> $DIR/privacy-sanity.rs:79:9 | LL | pub type T = u8; | ^^^ help: remove the qualifier @@ -127,7 +143,7 @@ LL | pub type T = u8; = note: trait items always share the visibility of their trait error[E0449]: visibility qualifiers are not permitted here - --> $DIR/privacy-sanity.rs:73:5 + --> $DIR/privacy-sanity.rs:81:5 | LL | pub impl S { | ^^^ help: remove the qualifier @@ -135,13 +151,29 @@ LL | pub impl S { = note: place qualifiers on individual impl items instead error[E0449]: visibility qualifiers are not permitted here - --> $DIR/privacy-sanity.rs:78:5 + --> $DIR/privacy-sanity.rs:86:5 | LL | pub extern "C" { | ^^^ help: remove the qualifier | = note: place qualifiers on individual foreign items instead -error: aborting due to 18 previous errors +error[E0449]: visibility qualifiers are not permitted here + --> $DIR/privacy-sanity.rs:91:9 + | +LL | pub Duck, + | ^^^ help: remove the qualifier + | + = note: enum variants and their fields always share the visibility of the enum they are in + +error[E0449]: visibility qualifiers are not permitted here + --> $DIR/privacy-sanity.rs:93:9 + | +LL | pub(crate) Dove, + | ^^^^^^^^^^ help: remove the qualifier + | + = note: enum variants and their fields always share the visibility of the enum they are in + +error: aborting due to 22 previous errors For more information about this error, try `rustc --explain E0449`. diff --git a/tests/ui/privacy/private-extern-fn-visibility.rs b/tests/ui/privacy/private-extern-fn-visibility.rs index 7741f828c474..39f2c3c003d5 100644 --- a/tests/ui/privacy/private-extern-fn-visibility.rs +++ b/tests/ui/privacy/private-extern-fn-visibility.rs @@ -1,8 +1,11 @@ -//@ aux-build:issue-16725.rs +//! regression test for +//@ aux-build:private-extern-fn.rs -extern crate issue_16725 as foo; +extern crate private_extern_fn as foo; fn main() { - unsafe { foo::bar(); } - //~^ ERROR: function `bar` is private + unsafe { + foo::bar(); + //~^ ERROR: function `bar` is private + } } diff --git a/tests/ui/privacy/private-extern-fn-visibility.stderr b/tests/ui/privacy/private-extern-fn-visibility.stderr index dcb7d58b0f96..8b1fa512b5de 100644 --- a/tests/ui/privacy/private-extern-fn-visibility.stderr +++ b/tests/ui/privacy/private-extern-fn-visibility.stderr @@ -1,11 +1,11 @@ error[E0603]: function `bar` is private - --> $DIR/issue-16725.rs:6:19 + --> $DIR/private-extern-fn-visibility.rs:8:14 | -LL | unsafe { foo::bar(); } - | ^^^ private function +LL | foo::bar(); + | ^^^ private function | note: the function `bar` is defined here - --> $DIR/auxiliary/issue-16725.rs:2:5 + --> $DIR/auxiliary/private-extern-fn.rs:2:5 | LL | fn bar(); | ^^^^^^^^^ diff --git a/tests/ui/static/static-str-deref-ref.rs b/tests/ui/static/static-str-deref-ref.rs index e8fc680f0422..86c37e527657 100644 --- a/tests/ui/static/static-str-deref-ref.rs +++ b/tests/ui/static/static-str-deref-ref.rs @@ -1,3 +1,4 @@ +//! regression test for //@ build-pass #[allow(dead_code)] static X: &'static str = &*""; diff --git a/tests/ui/threads-sendsync/std-sync-right-kind-impls-2.rs b/tests/ui/threads-sendsync/std-sync-right-kind-impls-2.rs deleted file mode 100644 index 0fa284cc7c0c..000000000000 --- a/tests/ui/threads-sendsync/std-sync-right-kind-impls-2.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - -use std::{fs, net}; - -fn assert_both() {} -fn assert_send() {} - -fn main() { - assert_both::(); - assert_both::(); - assert_both::(); - assert_both::(); - assert_both::(); - assert_both::(); - - assert_both::(); - assert_both::(); - assert_both::(); - assert_both::(); - assert_both::(); - assert_both::(); - assert_both::(); - assert_both::(); -} diff --git a/tests/ui/threads-sendsync/std-sync-right-kind-impls.rs b/tests/ui/threads-sendsync/std-sync-right-kind-impls.rs index b2d22631c1a5..42135fe1c45b 100644 --- a/tests/ui/threads-sendsync/std-sync-right-kind-impls.rs +++ b/tests/ui/threads-sendsync/std-sync-right-kind-impls.rs @@ -1,6 +1,6 @@ //@ run-pass -use std::sync; +use std::{fs, net, sync}; fn assert_both() {} @@ -12,4 +12,20 @@ fn main() { assert_both::>(); assert_both::>(); assert_both::(); + + assert_both::(); + assert_both::(); + assert_both::(); + assert_both::(); + assert_both::(); + assert_both::(); + + assert_both::(); + assert_both::(); + assert_both::(); + assert_both::(); + assert_both::(); + assert_both::(); + assert_both::(); + assert_both::(); } From 5c057ad89617b3872de836f6658f53db2a6c6e3a Mon Sep 17 00:00:00 2001 From: Asuna Date: Thu, 15 Jan 2026 21:12:04 +0100 Subject: [PATCH 0746/1061] Remove their own `TypeId` from type info for primitives --- .../src/const_eval/type_info.rs | 52 +++++-------------- library/core/src/mem/type_info.rs | 15 ++---- tests/ui/reflection/dump.bit32.run.stdout | 14 +---- tests/ui/reflection/dump.bit64.run.stdout | 14 +---- 4 files changed, 19 insertions(+), 76 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/type_info.rs b/compiler/rustc_const_eval/src/const_eval/type_info.rs index fc3378275be2..1e4b72d0ddac 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -66,55 +66,39 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { variant } ty::Bool => { - let (variant, variant_place) = downcast(sym::Bool)?; - let place = self.project_field(&variant_place, FieldIdx::ZERO)?; - self.write_primitive_type_info(place, ty, None)?; + let (variant, _variant_place) = downcast(sym::Bool)?; variant } ty::Char => { - let (variant, variant_place) = downcast(sym::Char)?; - let place = self.project_field(&variant_place, FieldIdx::ZERO)?; - self.write_primitive_type_info(place, ty, None)?; + let (variant, _variant_place) = downcast(sym::Char)?; variant } ty::Int(int_ty) => { let (variant, variant_place) = downcast(sym::Int)?; let place = self.project_field(&variant_place, FieldIdx::ZERO)?; - self.write_primitive_type_info( + self.write_int_float_type_info( place, - ty, - Some( - int_ty - .bit_width() - .unwrap_or_else(/* isize */ ptr_bit_width), - ), + int_ty.bit_width().unwrap_or_else(/* isize */ ptr_bit_width), )?; variant } ty::Uint(uint_ty) => { let (variant, variant_place) = downcast(sym::Uint)?; let place = self.project_field(&variant_place, FieldIdx::ZERO)?; - self.write_primitive_type_info( + self.write_int_float_type_info( place, - ty, - Some( - uint_ty - .bit_width() - .unwrap_or_else(/* usize */ ptr_bit_width), - ), + uint_ty.bit_width().unwrap_or_else(/* usize */ ptr_bit_width), )?; variant } ty::Float(float_ty) => { let (variant, variant_place) = downcast(sym::Float)?; let place = self.project_field(&variant_place, FieldIdx::ZERO)?; - self.write_primitive_type_info(place, ty, Some(float_ty.bit_width()))?; + self.write_int_float_type_info(place, float_ty.bit_width())?; variant } ty::Str => { - let (variant, variant_place) = downcast(sym::Str)?; - let place = self.project_field(&variant_place, FieldIdx::ZERO)?; - self.write_primitive_type_info(place, ty, None)?; + let (variant, _variant_place) = downcast(sym::Str)?; variant } ty::Adt(_, _) @@ -252,28 +236,20 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { interp_ok(()) } - // This method always writes to field `ty`. - // If field `bit_width` is present, it also writes to it (in which case parameter `write_bit_width` must be `Some`). - fn write_primitive_type_info( + fn write_int_float_type_info( &mut self, place: impl Writeable<'tcx, CtfeProvenance>, - ty: Ty<'tcx>, - write_bit_width: Option, + bit_width: u64, ) -> InterpResult<'tcx> { for (field_idx, field) in place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated() { let field_place = self.project_field(&place, field_idx)?; match field.name { - sym::ty => self.write_type_id(ty, &field_place)?, - sym::bit_width => { - let bit_width = write_bit_width - .expect("type info struct needs a `bit_width` but none was provided"); - self.write_scalar( - ScalarInt::try_from_target_usize(bit_width, self.tcx.tcx).unwrap(), - &field_place, - )? - } + sym::bit_width => self.write_scalar( + ScalarInt::try_from_target_usize(bit_width, self.tcx.tcx).unwrap(), + &field_place, + )?, other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"), } } diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index 7db4f3b00123..e02e07ae3b4a 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -97,8 +97,7 @@ pub struct Array { #[non_exhaustive] #[unstable(feature = "type_info", issue = "146922")] pub struct Bool { - /// The type id of `bool`. - pub ty: TypeId, + // No additional information to provide for now. } /// Compile-time type information about `char`. @@ -106,8 +105,7 @@ pub struct Bool { #[non_exhaustive] #[unstable(feature = "type_info", issue = "146922")] pub struct Char { - /// The type id of `char`. - pub ty: TypeId, + // No additional information to provide for now. } /// Compile-time type information about signed integer types. @@ -115,8 +113,6 @@ pub struct Char { #[non_exhaustive] #[unstable(feature = "type_info", issue = "146922")] pub struct Int { - /// The type id of signed integer type. - pub ty: TypeId, /// The bit width of the signed integer type. pub bit_width: usize, } @@ -126,8 +122,6 @@ pub struct Int { #[non_exhaustive] #[unstable(feature = "type_info", issue = "146922")] pub struct Uint { - /// The type id of unsigned integer type. - pub ty: TypeId, /// The bit width of the unsigned integer type. pub bit_width: usize, } @@ -137,8 +131,6 @@ pub struct Uint { #[non_exhaustive] #[unstable(feature = "type_info", issue = "146922")] pub struct Float { - /// The type id of floating-point type. - pub ty: TypeId, /// The bit width of the floating-point type. pub bit_width: usize, } @@ -148,6 +140,5 @@ pub struct Float { #[non_exhaustive] #[unstable(feature = "type_info", issue = "146922")] pub struct Str { - /// The type id of `str`. - pub ty: TypeId, + // No additional information to provide for now. } diff --git a/tests/ui/reflection/dump.bit32.run.stdout b/tests/ui/reflection/dump.bit32.run.stdout index d747ee210204..c6df7b00bf4a 100644 --- a/tests/ui/reflection/dump.bit32.run.stdout +++ b/tests/ui/reflection/dump.bit32.run.stdout @@ -35,7 +35,6 @@ Type { Type { kind: Int( Int { - ty: TypeId(0x12427c993eca190c841e0d92c5b7a45d), bit_width: 8, }, ), @@ -46,7 +45,6 @@ Type { Type { kind: Int( Int { - ty: TypeId(0x56ced5e4a15bd89050bb9674fa2df013), bit_width: 32, }, ), @@ -57,7 +55,6 @@ Type { Type { kind: Int( Int { - ty: TypeId(0xae6c4318bb07632e00428affbea41961), bit_width: 64, }, ), @@ -68,7 +65,6 @@ Type { Type { kind: Int( Int { - ty: TypeId(0xc7164498f3902dde0d8194a7b9733e79), bit_width: 128, }, ), @@ -79,7 +75,6 @@ Type { Type { kind: Int( Int { - ty: TypeId(0x1e5f92831c560aac8658b980a22e60b0), bit_width: 32, }, ), @@ -90,7 +85,6 @@ Type { Type { kind: Uint( Uint { - ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), bit_width: 8, }, ), @@ -101,7 +95,6 @@ Type { Type { kind: Uint( Uint { - ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), bit_width: 32, }, ), @@ -112,7 +105,6 @@ Type { Type { kind: Uint( Uint { - ty: TypeId(0x9ed91be891e304132cb86891e578f4a5), bit_width: 64, }, ), @@ -123,7 +115,6 @@ Type { Type { kind: Uint( Uint { - ty: TypeId(0x7bf7411d57d603e9fb393892a9c3f362), bit_width: 128, }, ), @@ -134,7 +125,6 @@ Type { Type { kind: Uint( Uint { - ty: TypeId(0x763d199bccd319899208909ed1a860c6), bit_width: 32, }, ), @@ -174,9 +164,7 @@ Type { } Type { kind: Str( - Str { - ty: TypeId(0x474ccf3b5db264ef53916706f7d7bb2c), - }, + Str, ), size: None, } diff --git a/tests/ui/reflection/dump.bit64.run.stdout b/tests/ui/reflection/dump.bit64.run.stdout index 180a6e2882d7..0f39e3e4c6b0 100644 --- a/tests/ui/reflection/dump.bit64.run.stdout +++ b/tests/ui/reflection/dump.bit64.run.stdout @@ -35,7 +35,6 @@ Type { Type { kind: Int( Int { - ty: TypeId(0x12427c993eca190c841e0d92c5b7a45d), bit_width: 8, }, ), @@ -46,7 +45,6 @@ Type { Type { kind: Int( Int { - ty: TypeId(0x56ced5e4a15bd89050bb9674fa2df013), bit_width: 32, }, ), @@ -57,7 +55,6 @@ Type { Type { kind: Int( Int { - ty: TypeId(0xae6c4318bb07632e00428affbea41961), bit_width: 64, }, ), @@ -68,7 +65,6 @@ Type { Type { kind: Int( Int { - ty: TypeId(0xc7164498f3902dde0d8194a7b9733e79), bit_width: 128, }, ), @@ -79,7 +75,6 @@ Type { Type { kind: Int( Int { - ty: TypeId(0x1e5f92831c560aac8658b980a22e60b0), bit_width: 64, }, ), @@ -90,7 +85,6 @@ Type { Type { kind: Uint( Uint { - ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), bit_width: 8, }, ), @@ -101,7 +95,6 @@ Type { Type { kind: Uint( Uint { - ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), bit_width: 32, }, ), @@ -112,7 +105,6 @@ Type { Type { kind: Uint( Uint { - ty: TypeId(0x9ed91be891e304132cb86891e578f4a5), bit_width: 64, }, ), @@ -123,7 +115,6 @@ Type { Type { kind: Uint( Uint { - ty: TypeId(0x7bf7411d57d603e9fb393892a9c3f362), bit_width: 128, }, ), @@ -134,7 +125,6 @@ Type { Type { kind: Uint( Uint { - ty: TypeId(0x763d199bccd319899208909ed1a860c6), bit_width: 64, }, ), @@ -174,9 +164,7 @@ Type { } Type { kind: Str( - Str { - ty: TypeId(0x474ccf3b5db264ef53916706f7d7bb2c), - }, + Str, ), size: None, } From b2a7b18ec4c93ef11eb51cb2dccbe5f257993bd1 Mon Sep 17 00:00:00 2001 From: Asuna Date: Thu, 15 Jan 2026 22:17:43 +0100 Subject: [PATCH 0747/1061] Merge type info variant `Uint` into `Int` --- .../src/const_eval/type_info.rs | 36 +++++++++++++++---- compiler/rustc_span/src/symbol.rs | 2 +- library/core/src/mem/type_info.rs | 17 +++------ library/coretests/tests/mem/type_info.rs | 16 +++++---- tests/ui/reflection/dump.bit32.run.stdout | 30 ++++++++++------ tests/ui/reflection/dump.bit64.run.stdout | 30 ++++++++++------ 6 files changed, 85 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/type_info.rs b/compiler/rustc_const_eval/src/const_eval/type_info.rs index 1e4b72d0ddac..5d37db06d76a 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -1,6 +1,6 @@ use rustc_abi::FieldIdx; use rustc_hir::LangItem; -use rustc_middle::mir::interpret::CtfeProvenance; +use rustc_middle::mir::interpret::{CtfeProvenance, Scalar}; use rustc_middle::span_bug; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{self, Const, ScalarInt, Ty}; @@ -76,25 +76,27 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { ty::Int(int_ty) => { let (variant, variant_place) = downcast(sym::Int)?; let place = self.project_field(&variant_place, FieldIdx::ZERO)?; - self.write_int_float_type_info( + self.write_int_type_info( place, int_ty.bit_width().unwrap_or_else(/* isize */ ptr_bit_width), + true, )?; variant } ty::Uint(uint_ty) => { - let (variant, variant_place) = downcast(sym::Uint)?; + let (variant, variant_place) = downcast(sym::Int)?; let place = self.project_field(&variant_place, FieldIdx::ZERO)?; - self.write_int_float_type_info( + self.write_int_type_info( place, uint_ty.bit_width().unwrap_or_else(/* usize */ ptr_bit_width), + false, )?; variant } ty::Float(float_ty) => { let (variant, variant_place) = downcast(sym::Float)?; let place = self.project_field(&variant_place, FieldIdx::ZERO)?; - self.write_int_float_type_info(place, float_ty.bit_width())?; + self.write_float_type_info(place, float_ty.bit_width())?; variant } ty::Str => { @@ -236,7 +238,29 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { interp_ok(()) } - fn write_int_float_type_info( + fn write_int_type_info( + &mut self, + place: impl Writeable<'tcx, CtfeProvenance>, + bit_width: u64, + signed: bool, + ) -> InterpResult<'tcx> { + for (field_idx, field) in + place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated() + { + let field_place = self.project_field(&place, field_idx)?; + match field.name { + sym::bit_width => self.write_scalar( + ScalarInt::try_from_target_usize(bit_width, self.tcx.tcx).unwrap(), + &field_place, + )?, + sym::signed => self.write_scalar(Scalar::from_bool(signed), &field_place)?, + other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"), + } + } + interp_ok(()) + } + + fn write_float_type_info( &mut self, place: impl Writeable<'tcx, CtfeProvenance>, bit_width: u64, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4c19fa83fd3a..6aa6ce269517 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -391,7 +391,6 @@ symbols! { Ty, TyCtxt, TyKind, - Uint, Unknown, Unsize, UnsizedConstParamTy, @@ -2066,6 +2065,7 @@ symbols! { shr_assign, sig_dfl, sig_ign, + signed, simd, simd_add, simd_and, diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index e02e07ae3b4a..2e3bdb45ce05 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -49,10 +49,8 @@ pub enum TypeKind { Bool(Bool), /// Primitive character type. Char(Char), - /// Primitive signed integer type. + /// Primitive signed and unsigned integer type. Int(Int), - /// Primitive unsigned integer type. - Uint(Uint), /// Primitive floating-point type. Float(Float), /// String slice type. @@ -108,22 +106,15 @@ pub struct Char { // No additional information to provide for now. } -/// Compile-time type information about signed integer types. +/// Compile-time type information about signed and unsigned integer types. #[derive(Debug)] #[non_exhaustive] #[unstable(feature = "type_info", issue = "146922")] pub struct Int { /// The bit width of the signed integer type. pub bit_width: usize, -} - -/// Compile-time type information about unsigned integer types. -#[derive(Debug)] -#[non_exhaustive] -#[unstable(feature = "type_info", issue = "146922")] -pub struct Uint { - /// The bit width of the unsigned integer type. - pub bit_width: usize, + /// Whether the integer type is signed. + pub signed: bool, } /// Compile-time type information about floating-point types. diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs index 5dd8f4034d11..fc13637a5574 100644 --- a/library/coretests/tests/mem/type_info.rs +++ b/library/coretests/tests/mem/type_info.rs @@ -38,7 +38,7 @@ fn test_tuples() { assert_tuple_arity::<(u8, u8), 2>(); const { - match Type::of::<(u8, u8)>().kind { + match Type::of::<(i8, u8)>().kind { TypeKind::Tuple(tup) => { let [a, b] = tup.fields else { unreachable!() }; @@ -46,9 +46,9 @@ fn test_tuples() { assert!(b.offset == 1); match (a.ty.info().kind, b.ty.info().kind) { - (TypeKind::Uint(a), TypeKind::Uint(b)) => { - assert!(a.bit_width == 8); - assert!(b.bit_width == 8); + (TypeKind::Int(a), TypeKind::Int(b)) => { + assert!(a.bit_width == 8 && a.signed); + assert!(b.bit_width == 8 && !b.signed); } _ => unreachable!(), } @@ -71,18 +71,22 @@ fn test_primitives() { let Type { kind: Int(ty), size, .. } = (const { Type::of::() }) else { panic!() }; assert_eq!(size, Some(4)); assert_eq!(ty.bit_width, 32); + assert!(ty.signed); let Type { kind: Int(ty), size, .. } = (const { Type::of::() }) else { panic!() }; assert_eq!(size, Some(size_of::())); assert_eq!(ty.bit_width, size_of::() * 8); + assert!(ty.signed); - let Type { kind: Uint(ty), size, .. } = (const { Type::of::() }) else { panic!() }; + let Type { kind: Int(ty), size, .. } = (const { Type::of::() }) else { panic!() }; assert_eq!(size, Some(4)); assert_eq!(ty.bit_width, 32); + assert!(!ty.signed); - let Type { kind: Uint(ty), size, .. } = (const { Type::of::() }) else { panic!() }; + let Type { kind: Int(ty), size, .. } = (const { Type::of::() }) else { panic!() }; assert_eq!(size, Some(size_of::())); assert_eq!(ty.bit_width, size_of::() * 8); + assert!(!ty.signed); let Type { kind: Float(ty), size, .. } = (const { Type::of::() }) else { panic!() }; assert_eq!(size, Some(4)); diff --git a/tests/ui/reflection/dump.bit32.run.stdout b/tests/ui/reflection/dump.bit32.run.stdout index c6df7b00bf4a..483efdbbd12a 100644 --- a/tests/ui/reflection/dump.bit32.run.stdout +++ b/tests/ui/reflection/dump.bit32.run.stdout @@ -36,6 +36,7 @@ Type { kind: Int( Int { bit_width: 8, + signed: true, }, ), size: Some( @@ -46,6 +47,7 @@ Type { kind: Int( Int { bit_width: 32, + signed: true, }, ), size: Some( @@ -56,6 +58,7 @@ Type { kind: Int( Int { bit_width: 64, + signed: true, }, ), size: Some( @@ -66,6 +69,7 @@ Type { kind: Int( Int { bit_width: 128, + signed: true, }, ), size: Some( @@ -76,6 +80,7 @@ Type { kind: Int( Int { bit_width: 32, + signed: true, }, ), size: Some( @@ -83,9 +88,10 @@ Type { ), } Type { - kind: Uint( - Uint { + kind: Int( + Int { bit_width: 8, + signed: false, }, ), size: Some( @@ -93,9 +99,10 @@ Type { ), } Type { - kind: Uint( - Uint { + kind: Int( + Int { bit_width: 32, + signed: false, }, ), size: Some( @@ -103,9 +110,10 @@ Type { ), } Type { - kind: Uint( - Uint { + kind: Int( + Int { bit_width: 64, + signed: false, }, ), size: Some( @@ -113,9 +121,10 @@ Type { ), } Type { - kind: Uint( - Uint { + kind: Int( + Int { bit_width: 128, + signed: false, }, ), size: Some( @@ -123,9 +132,10 @@ Type { ), } Type { - kind: Uint( - Uint { + kind: Int( + Int { bit_width: 32, + signed: false, }, ), size: Some( diff --git a/tests/ui/reflection/dump.bit64.run.stdout b/tests/ui/reflection/dump.bit64.run.stdout index 0f39e3e4c6b0..681e81b71d56 100644 --- a/tests/ui/reflection/dump.bit64.run.stdout +++ b/tests/ui/reflection/dump.bit64.run.stdout @@ -36,6 +36,7 @@ Type { kind: Int( Int { bit_width: 8, + signed: true, }, ), size: Some( @@ -46,6 +47,7 @@ Type { kind: Int( Int { bit_width: 32, + signed: true, }, ), size: Some( @@ -56,6 +58,7 @@ Type { kind: Int( Int { bit_width: 64, + signed: true, }, ), size: Some( @@ -66,6 +69,7 @@ Type { kind: Int( Int { bit_width: 128, + signed: true, }, ), size: Some( @@ -76,6 +80,7 @@ Type { kind: Int( Int { bit_width: 64, + signed: true, }, ), size: Some( @@ -83,9 +88,10 @@ Type { ), } Type { - kind: Uint( - Uint { + kind: Int( + Int { bit_width: 8, + signed: false, }, ), size: Some( @@ -93,9 +99,10 @@ Type { ), } Type { - kind: Uint( - Uint { + kind: Int( + Int { bit_width: 32, + signed: false, }, ), size: Some( @@ -103,9 +110,10 @@ Type { ), } Type { - kind: Uint( - Uint { + kind: Int( + Int { bit_width: 64, + signed: false, }, ), size: Some( @@ -113,9 +121,10 @@ Type { ), } Type { - kind: Uint( - Uint { + kind: Int( + Int { bit_width: 128, + signed: false, }, ), size: Some( @@ -123,9 +132,10 @@ Type { ), } Type { - kind: Uint( - Uint { + kind: Int( + Int { bit_width: 64, + signed: false, }, ), size: Some( From 0dc5b52e8eef98e973d9935c45e8dc3d7fbd6a1d Mon Sep 17 00:00:00 2001 From: Usman Akinyemi Date: Fri, 16 Jan 2026 04:25:12 +0530 Subject: [PATCH 0748/1061] simplify words initialization using Rc::new_zeroed Now that Rc::new_zeroed is stable, remove the cfg(feature = "nightly") branch and the temporary zeroed array on stable. This avoids copying a potentially large [Word; CHUNK_WORDS] into the Rc. Signed-off-by: Usman Akinyemi --- compiler/rustc_index/src/bit_set.rs | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index a9bdf597e128..184fa409d960 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -634,22 +634,12 @@ impl ChunkedBitSet { match *chunk { Zeros => { if chunk_domain_size > 1 { - #[cfg(feature = "nightly")] let mut words = { // We take some effort to avoid copying the words. let words = Rc::<[Word; CHUNK_WORDS]>::new_zeroed(); // SAFETY: `words` can safely be all zeroes. unsafe { words.assume_init() } }; - #[cfg(not(feature = "nightly"))] - let mut words = { - // FIXME: unconditionally use `Rc::new_zeroed` once it is stable (#129396). - let words = mem::MaybeUninit::<[Word; CHUNK_WORDS]>::zeroed(); - // SAFETY: `words` can safely be all zeroes. - let words = unsafe { words.assume_init() }; - // Unfortunate possibly-large copy - Rc::new(words) - }; let words_ref = Rc::get_mut(&mut words).unwrap(); let (word_index, mask) = chunk_word_index_and_mask(elem); @@ -695,22 +685,12 @@ impl ChunkedBitSet { Zeros => false, Ones => { if chunk_domain_size > 1 { - #[cfg(feature = "nightly")] let mut words = { // We take some effort to avoid copying the words. let words = Rc::<[Word; CHUNK_WORDS]>::new_zeroed(); // SAFETY: `words` can safely be all zeroes. unsafe { words.assume_init() } }; - #[cfg(not(feature = "nightly"))] - let mut words = { - // FIXME: unconditionally use `Rc::new_zeroed` once it is stable (#129396). - let words = mem::MaybeUninit::<[Word; CHUNK_WORDS]>::zeroed(); - // SAFETY: `words` can safely be all zeroes. - let words = unsafe { words.assume_init() }; - // Unfortunate possibly-large copy - Rc::new(words) - }; let words_ref = Rc::get_mut(&mut words).unwrap(); // Set only the bits in use. From 676d71a45b4fa9966e77e9d4fe6508d8bbea7d29 Mon Sep 17 00:00:00 2001 From: Hugh Date: Thu, 15 Jan 2026 16:22:23 -0800 Subject: [PATCH 0749/1061] Defer is_from_proc_macro check and add tests Move the is_from_proc_macro check inside check_fn_inner to be called only right before emitting lints, rather than at the entry points. This avoids the expensive check when early returns would prevent any lint emission anyway. Add tests for proc-macro generated code covering all check locations: - Standalone functions - Methods in impl blocks - Trait methods - Impl blocks with extra lifetimes --- clippy_lints/src/lifetimes.rs | 46 +++++++++++++++++--------- tests/ui/extra_unused_lifetimes.rs | 32 ++++++++++++++++++ tests/ui/extra_unused_lifetimes.stderr | 14 ++++---- tests/ui/needless_lifetimes.fixed | 25 +++++++++++++- tests/ui/needless_lifetimes.rs | 25 +++++++++++++- 5 files changed, 118 insertions(+), 24 deletions(-) diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 8917c90262a4..679fb983d532 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -149,10 +149,9 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { .. } = item.kind { - if is_from_proc_macro(cx, item) { - return; - } - check_fn_inner(cx, sig, Some(id), None, generics, item.span, true, self.msrv); + check_fn_inner(cx, sig, Some(id), None, generics, item.span, true, self.msrv, || { + is_from_proc_macro(cx, item) + }); } else if let ItemKind::Impl(impl_) = &item.kind && !item.span.from_expansion() && !is_from_proc_macro(cx, item) @@ -162,9 +161,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { - if let ImplItemKind::Fn(ref sig, id) = item.kind - && !is_from_proc_macro(cx, item) - { + if let ImplItemKind::Fn(ref sig, id) = item.kind { let report_extra_lifetimes = trait_ref_of_method(cx, item.owner_id).is_none(); check_fn_inner( cx, @@ -175,19 +172,28 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { item.span, report_extra_lifetimes, self.msrv, + || is_from_proc_macro(cx, item), ); } } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { - if let TraitItemKind::Fn(ref sig, ref body) = item.kind - && !is_from_proc_macro(cx, item) - { + if let TraitItemKind::Fn(ref sig, ref body) = item.kind { let (body, trait_sig) = match *body { TraitFn::Required(sig) => (None, Some(sig)), TraitFn::Provided(id) => (Some(id), None), }; - check_fn_inner(cx, sig, body, trait_sig, item.generics, item.span, true, self.msrv); + check_fn_inner( + cx, + sig, + body, + trait_sig, + item.generics, + item.span, + true, + self.msrv, + || is_from_proc_macro(cx, item), + ); } } } @@ -202,6 +208,7 @@ fn check_fn_inner<'tcx>( span: Span, report_extra_lifetimes: bool, msrv: Msrv, + is_from_proc_macro: impl FnOnce() -> bool, ) { if span.in_external_macro(cx.sess().source_map()) || has_where_lifetimes(cx, generics) { return; @@ -253,10 +260,19 @@ fn check_fn_inner<'tcx>( } } - if let Some((elidable_lts, usages)) = could_use_elision(cx, sig.decl, body, trait_sig, generics.params, msrv) { - if usages.iter().any(|usage| !usage.ident.span.eq_ctxt(span)) { - return; - } + let elidable = could_use_elision(cx, sig.decl, body, trait_sig, generics.params, msrv); + let has_elidable_lts = elidable + .as_ref() + .is_some_and(|(_, usages)| !usages.iter().any(|usage| !usage.ident.span.eq_ctxt(span))); + + // Only check is_from_proc_macro if we're about to emit a lint (it's an expensive check) + if (has_elidable_lts || report_extra_lifetimes) && is_from_proc_macro() { + return; + } + + if let Some((elidable_lts, usages)) = elidable + && has_elidable_lts + { // async functions have usages whose spans point at the lifetime declaration which messes up // suggestions let include_suggestions = !sig.header.is_async(); diff --git a/tests/ui/extra_unused_lifetimes.rs b/tests/ui/extra_unused_lifetimes.rs index 5fdcd5a7e078..677523489599 100644 --- a/tests/ui/extra_unused_lifetimes.rs +++ b/tests/ui/extra_unused_lifetimes.rs @@ -1,4 +1,5 @@ //@aux-build:proc_macro_derive.rs +//@aux-build:proc_macros.rs #![allow( unused, @@ -11,6 +12,7 @@ #[macro_use] extern crate proc_macro_derive; +extern crate proc_macros; fn empty() {} @@ -148,4 +150,34 @@ mod issue_13578 { impl<'a, T: 'a> Foo for Option where &'a T: Foo {} } +// no lint on proc macro generated code +mod proc_macro_generated { + use proc_macros::external; + + // no lint on external macro (extra unused lifetimes in impl block) + external! { + struct ExternalImplStruct; + + impl<'a> ExternalImplStruct { + fn foo() {} + } + } + + // no lint on external macro (extra unused lifetimes in method) + external! { + struct ExternalMethodStruct; + + impl ExternalMethodStruct { + fn bar<'a>(&self) {} + } + } + + // no lint on external macro (extra unused lifetimes in trait method) + external! { + trait ExternalUnusedLifetimeTrait { + fn unused_lt<'a>(x: u8) {} + } + } +} + fn main() {} diff --git a/tests/ui/extra_unused_lifetimes.stderr b/tests/ui/extra_unused_lifetimes.stderr index 0cecbbe80f76..d748376d476c 100644 --- a/tests/ui/extra_unused_lifetimes.stderr +++ b/tests/ui/extra_unused_lifetimes.stderr @@ -1,5 +1,5 @@ error: this lifetime isn't used in the function definition - --> tests/ui/extra_unused_lifetimes.rs:19:14 + --> tests/ui/extra_unused_lifetimes.rs:21:14 | LL | fn unused_lt<'a>(x: u8) {} | ^^ @@ -8,37 +8,37 @@ LL | fn unused_lt<'a>(x: u8) {} = help: to override `-D warnings` add `#[allow(clippy::extra_unused_lifetimes)]` error: this lifetime isn't used in the function definition - --> tests/ui/extra_unused_lifetimes.rs:47:10 + --> tests/ui/extra_unused_lifetimes.rs:49:10 | LL | fn x<'a>(&self) {} | ^^ error: this lifetime isn't used in the function definition - --> tests/ui/extra_unused_lifetimes.rs:74:22 + --> tests/ui/extra_unused_lifetimes.rs:76:22 | LL | fn unused_lt<'a>(x: u8) {} | ^^ error: this lifetime isn't used in the impl - --> tests/ui/extra_unused_lifetimes.rs:86:10 + --> tests/ui/extra_unused_lifetimes.rs:88:10 | LL | impl<'a> std::ops::AddAssign<&Scalar> for &mut Scalar { | ^^ error: this lifetime isn't used in the impl - --> tests/ui/extra_unused_lifetimes.rs:93:10 + --> tests/ui/extra_unused_lifetimes.rs:95:10 | LL | impl<'b> Scalar { | ^^ error: this lifetime isn't used in the function definition - --> tests/ui/extra_unused_lifetimes.rs:95:26 + --> tests/ui/extra_unused_lifetimes.rs:97:26 | LL | pub fn something<'c>() -> Self { | ^^ error: this lifetime isn't used in the impl - --> tests/ui/extra_unused_lifetimes.rs:125:10 + --> tests/ui/extra_unused_lifetimes.rs:127:10 | LL | impl<'a, T: Source + ?Sized + 'a> Source for Box { | ^^ diff --git a/tests/ui/needless_lifetimes.fixed b/tests/ui/needless_lifetimes.fixed index 15ca409c95bd..90a07454b4d7 100644 --- a/tests/ui/needless_lifetimes.fixed +++ b/tests/ui/needless_lifetimes.fixed @@ -470,13 +470,36 @@ mod in_macro { } } - // no lint on external macro + // no lint on external macro (standalone function) external! { fn needless_lifetime<'a>(x: &'a u8) -> &'a u8 { unimplemented!() } } + // no lint on external macro (method in impl block) + external! { + struct ExternalStruct; + + impl ExternalStruct { + fn needless_lifetime_method<'a>(x: &'a u8) -> &'a u8 { + unimplemented!() + } + } + } + + // no lint on external macro (trait method) + external! { + trait ExternalTrait { + fn needless_lifetime_trait_method<'a>(x: &'a u8) -> &'a u8; + } + } + + // no lint on external macro (extra unused lifetimes in function) + external! { + fn extra_unused_lifetime<'a>(x: u8) {} + } + inline! { fn f<$'a>(arg: &$'a str) -> &$'a str { arg diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs index af9649d72987..6df38897f42d 100644 --- a/tests/ui/needless_lifetimes.rs +++ b/tests/ui/needless_lifetimes.rs @@ -470,13 +470,36 @@ mod in_macro { } } - // no lint on external macro + // no lint on external macro (standalone function) external! { fn needless_lifetime<'a>(x: &'a u8) -> &'a u8 { unimplemented!() } } + // no lint on external macro (method in impl block) + external! { + struct ExternalStruct; + + impl ExternalStruct { + fn needless_lifetime_method<'a>(x: &'a u8) -> &'a u8 { + unimplemented!() + } + } + } + + // no lint on external macro (trait method) + external! { + trait ExternalTrait { + fn needless_lifetime_trait_method<'a>(x: &'a u8) -> &'a u8; + } + } + + // no lint on external macro (extra unused lifetimes in function) + external! { + fn extra_unused_lifetime<'a>(x: u8) {} + } + inline! { fn f<$'a>(arg: &$'a str) -> &$'a str { arg From 02c5f9a5b455ecf4e9eeeb0510c8ba65ff39ce28 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 15 Jan 2026 16:22:18 +1100 Subject: [PATCH 0750/1061] Add a snapshot test for string patterns in THIR --- tests/ui/thir-print/str-patterns.rs | 17 ++ tests/ui/thir-print/str-patterns.stdout | 310 ++++++++++++++++++++++++ 2 files changed, 327 insertions(+) create mode 100644 tests/ui/thir-print/str-patterns.rs create mode 100644 tests/ui/thir-print/str-patterns.stdout diff --git a/tests/ui/thir-print/str-patterns.rs b/tests/ui/thir-print/str-patterns.rs new file mode 100644 index 000000000000..4ad782f63a50 --- /dev/null +++ b/tests/ui/thir-print/str-patterns.rs @@ -0,0 +1,17 @@ +#![crate_type = "rlib"] +//@ edition: 2024 +//@ compile-flags: -Zunpretty=thir-flat +//@ check-pass + +// Snapshot test capturing the THIR pattern structure produced by +// string-literal and string-constant patterns. + +pub fn hello_world(x: &str) { + match x { + "hello" => {} + CONSTANT => {} + _ => {} + } +} + +const CONSTANT: &str = "constant"; diff --git a/tests/ui/thir-print/str-patterns.stdout b/tests/ui/thir-print/str-patterns.stdout new file mode 100644 index 000000000000..8f8944ad4e09 --- /dev/null +++ b/tests/ui/thir-print/str-patterns.stdout @@ -0,0 +1,310 @@ +DefId(0:3 ~ str_patterns[fc71]::hello_world): +Thir { + body_type: Fn( + fn(&'{erased} str), + ), + arms: [ + Arm { + pattern: Pat { + ty: &'{erased} str, + span: $DIR/str-patterns.rs:11:9: 11:16 (#0), + extra: None, + kind: Constant { + value: Value { + ty: &'{erased} str, + valtree: Branch( + [ + 104_u8, + 101_u8, + 108_u8, + 108_u8, + 111_u8, + ], + ), + }, + }, + }, + guard: None, + body: e3, + hir_id: HirId(DefId(0:3 ~ str_patterns[fc71]::hello_world).9), + scope: Node(9), + span: $DIR/str-patterns.rs:11:9: 11:22 (#0), + }, + Arm { + pattern: Pat { + ty: &'{erased} str, + span: $DIR/str-patterns.rs:12:9: 12:17 (#0), + extra: Some( + PatExtra { + expanded_const: Some( + DefId(0:4 ~ str_patterns[fc71]::CONSTANT), + ), + ascriptions: [], + }, + ), + kind: Constant { + value: Value { + ty: &'{erased} str, + valtree: Branch( + [ + 99_u8, + 111_u8, + 110_u8, + 115_u8, + 116_u8, + 97_u8, + 110_u8, + 116_u8, + ], + ), + }, + }, + }, + guard: None, + body: e5, + hir_id: HirId(DefId(0:3 ~ str_patterns[fc71]::hello_world).15), + scope: Node(15), + span: $DIR/str-patterns.rs:12:9: 12:23 (#0), + }, + Arm { + pattern: Pat { + ty: &'{erased} str, + span: $DIR/str-patterns.rs:13:9: 13:10 (#0), + extra: None, + kind: Wild, + }, + guard: None, + body: e7, + hir_id: HirId(DefId(0:3 ~ str_patterns[fc71]::hello_world).19), + scope: Node(19), + span: $DIR/str-patterns.rs:13:9: 13:16 (#0), + }, + ], + blocks: [ + Block { + targeted_by_break: false, + region_scope: Node(11), + span: $DIR/str-patterns.rs:11:20: 11:22 (#0), + stmts: [], + expr: None, + safety_mode: Safe, + }, + Block { + targeted_by_break: false, + region_scope: Node(17), + span: $DIR/str-patterns.rs:12:21: 12:23 (#0), + stmts: [], + expr: None, + safety_mode: Safe, + }, + Block { + targeted_by_break: false, + region_scope: Node(21), + span: $DIR/str-patterns.rs:13:14: 13:16 (#0), + stmts: [], + expr: None, + safety_mode: Safe, + }, + Block { + targeted_by_break: false, + region_scope: Node(3), + span: $DIR/str-patterns.rs:9:29: 15:2 (#0), + stmts: [], + expr: Some( + e9, + ), + safety_mode: Safe, + }, + ], + exprs: [ + Expr { + kind: VarRef { + id: LocalVarId( + HirId(DefId(0:3 ~ str_patterns[fc71]::hello_world).2), + ), + }, + ty: &'{erased} str, + temp_scope_id: 5, + span: $DIR/str-patterns.rs:10:11: 10:12 (#0), + }, + Expr { + kind: Scope { + region_scope: Node(5), + hir_id: HirId(DefId(0:3 ~ str_patterns[fc71]::hello_world).5), + value: e0, + }, + ty: &'{erased} str, + temp_scope_id: 5, + span: $DIR/str-patterns.rs:10:11: 10:12 (#0), + }, + Expr { + kind: Block { + block: b0, + }, + ty: (), + temp_scope_id: 10, + span: $DIR/str-patterns.rs:11:20: 11:22 (#0), + }, + Expr { + kind: Scope { + region_scope: Node(10), + hir_id: HirId(DefId(0:3 ~ str_patterns[fc71]::hello_world).10), + value: e2, + }, + ty: (), + temp_scope_id: 10, + span: $DIR/str-patterns.rs:11:20: 11:22 (#0), + }, + Expr { + kind: Block { + block: b1, + }, + ty: (), + temp_scope_id: 16, + span: $DIR/str-patterns.rs:12:21: 12:23 (#0), + }, + Expr { + kind: Scope { + region_scope: Node(16), + hir_id: HirId(DefId(0:3 ~ str_patterns[fc71]::hello_world).16), + value: e4, + }, + ty: (), + temp_scope_id: 16, + span: $DIR/str-patterns.rs:12:21: 12:23 (#0), + }, + Expr { + kind: Block { + block: b2, + }, + ty: (), + temp_scope_id: 20, + span: $DIR/str-patterns.rs:13:14: 13:16 (#0), + }, + Expr { + kind: Scope { + region_scope: Node(20), + hir_id: HirId(DefId(0:3 ~ str_patterns[fc71]::hello_world).20), + value: e6, + }, + ty: (), + temp_scope_id: 20, + span: $DIR/str-patterns.rs:13:14: 13:16 (#0), + }, + Expr { + kind: Match { + scrutinee: e1, + arms: [ + a0, + a1, + a2, + ], + match_source: Normal, + }, + ty: (), + temp_scope_id: 4, + span: $DIR/str-patterns.rs:10:5: 14:6 (#0), + }, + Expr { + kind: Scope { + region_scope: Node(4), + hir_id: HirId(DefId(0:3 ~ str_patterns[fc71]::hello_world).4), + value: e8, + }, + ty: (), + temp_scope_id: 4, + span: $DIR/str-patterns.rs:10:5: 14:6 (#0), + }, + Expr { + kind: Block { + block: b3, + }, + ty: (), + temp_scope_id: 22, + span: $DIR/str-patterns.rs:9:29: 15:2 (#0), + }, + Expr { + kind: Scope { + region_scope: Node(22), + hir_id: HirId(DefId(0:3 ~ str_patterns[fc71]::hello_world).22), + value: e10, + }, + ty: (), + temp_scope_id: 22, + span: $DIR/str-patterns.rs:9:29: 15:2 (#0), + }, + ], + stmts: [], + params: [ + Param { + pat: Some( + Pat { + ty: &'{erased} str, + span: $DIR/str-patterns.rs:9:20: 9:21 (#0), + extra: None, + kind: Binding { + name: "x", + mode: BindingMode( + No, + Not, + ), + var: LocalVarId( + HirId(DefId(0:3 ~ str_patterns[fc71]::hello_world).2), + ), + ty: &'{erased} str, + subpattern: None, + is_primary: true, + is_shorthand: false, + }, + }, + ), + ty: &'{erased} str, + ty_span: Some( + $DIR/str-patterns.rs:9:23: 9:27 (#0), + ), + self_kind: None, + hir_id: Some( + HirId(DefId(0:3 ~ str_patterns[fc71]::hello_world).1), + ), + }, + ], +} + +DefId(0:4 ~ str_patterns[fc71]::CONSTANT): +Thir { + body_type: Const( + &'{erased} str, + ), + arms: [], + blocks: [], + exprs: [ + Expr { + kind: Literal { + lit: Spanned { + node: Str( + "constant", + Cooked, + ), + span: $DIR/str-patterns.rs:17:24: 17:34 (#0), + }, + neg: false, + }, + ty: &'{erased} str, + temp_scope_id: 5, + span: $DIR/str-patterns.rs:17:24: 17:34 (#0), + }, + Expr { + kind: Scope { + region_scope: Node(5), + hir_id: HirId(DefId(0:4 ~ str_patterns[fc71]::CONSTANT).5), + value: e0, + }, + ty: &'{erased} str, + temp_scope_id: 5, + span: $DIR/str-patterns.rs:17:24: 17:34 (#0), + }, + ], + stmts: [], + params: [], +} + From 066eb6d2eaea164d3623df9b2bde383e9c8917f3 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 15 Jan 2026 00:17:06 +1100 Subject: [PATCH 0751/1061] THIR patterns: Always use type `str` for string-constant-value nodes --- .../src/builder/matches/match_pair.rs | 16 +---- .../src/builder/matches/mod.rs | 6 +- .../src/builder/matches/test.rs | 62 +++++++---------- .../src/thir/pattern/const_to_pat.rs | 45 ++++++------ compiler/rustc_pattern_analysis/src/rustc.rs | 20 ++---- ....constant_eq.SimplifyCfg-initial.after.mir | 37 ++++++---- tests/ui/thir-print/str-patterns.stdout | 68 +++++++++++-------- 7 files changed, 118 insertions(+), 136 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index 3edd0234b0ad..e80e29415e6f 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -2,7 +2,6 @@ use std::sync::Arc; use rustc_abi::FieldIdx; use rustc_middle::mir::*; -use rustc_middle::span_bug; use rustc_middle::thir::*; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; @@ -160,10 +159,7 @@ impl<'tcx> MatchPairTree<'tcx> { } PatKind::Constant { value } => { - // CAUTION: The type of the pattern node (`pattern.ty`) is - // _often_ the same as the type of the const value (`value.ty`), - // but there are some cases where those types differ - // (e.g. when `deref!(..)` patterns interact with `String`). + assert_eq!(pattern.ty, value.ty); // Classify the constant-pattern into further kinds, to // reduce the number of ad-hoc type tests needed later on. @@ -175,16 +171,6 @@ impl<'tcx> MatchPairTree<'tcx> { } else if pat_ty.is_floating_point() { PatConstKind::Float } else if pat_ty.is_str() { - // Deref-patterns can cause string-literal patterns to have - // type `str` instead of the usual `&str`. - if !cx.tcx.features().deref_patterns() { - span_bug!( - pattern.span, - "const pattern has type `str` but deref_patterns is not enabled" - ); - } - PatConstKind::String - } else if pat_ty.is_imm_ref_str() { PatConstKind::String } else { // FIXME(Zalathar): This still covers several different diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 0463f7c914a4..ddd70a3b597c 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -1339,11 +1339,9 @@ enum TestKind<'tcx> { /// Tests the place against a string constant using string equality. StringEq { - /// Constant `&str` value to test against. + /// Constant string value to test against. + /// Note that this value has type `str` (not `&str`). value: ty::Value<'tcx>, - /// Type of the corresponding pattern node. Usually `&str`, but could - /// be `str` for patterns like `deref!("..."): String`. - pat_ty: Ty<'tcx>, }, /// Tests the place against a constant using scalar equality. diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index c2e39d47a92c..bab9f38f084d 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -9,10 +9,10 @@ use std::sync::Arc; use rustc_data_structures::fx::FxIndexMap; use rustc_hir::{LangItem, RangeEnd}; +use rustc_middle::bug; use rustc_middle::mir::*; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt}; -use rustc_middle::{bug, span_bug}; use rustc_span::def_id::DefId; use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; @@ -39,7 +39,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TestKind::SwitchInt } TestableCase::Constant { value, kind: PatConstKind::String } => { - TestKind::StringEq { value, pat_ty: match_pair.pattern_ty } + TestKind::StringEq { value } } TestableCase::Constant { value, kind: PatConstKind::Float | PatConstKind::Other } => { TestKind::ScalarEq { value, pat_ty: match_pair.pattern_ty } @@ -141,47 +141,33 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.terminate(block, self.source_info(match_start_span), terminator); } - TestKind::StringEq { value, pat_ty } => { + TestKind::StringEq { value } => { let tcx = self.tcx; let success_block = target_block(TestBranch::Success); let fail_block = target_block(TestBranch::Failure); - let expected_value_ty = value.ty; + let ref_str_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, tcx.types.str_); + assert!(ref_str_ty.is_imm_ref_str(), "{ref_str_ty:?}"); + + // The string constant we're testing against has type `str`, but + // calling `::eq` requires `&str` operands. + // + // Because `str` and `&str` have the same valtree representation, + // we can "cast" to the desired type by just replacing the type. + assert!(value.ty.is_str(), "unexpected value type for StringEq test: {value:?}"); + let expected_value = ty::Value { ty: ref_str_ty, valtree: value.valtree }; let expected_value_operand = - self.literal_operand(test.span, Const::from_ty_value(tcx, value)); + self.literal_operand(test.span, Const::from_ty_value(tcx, expected_value)); - let mut actual_value_ty = pat_ty; - let mut actual_value_place = place; - - match pat_ty.kind() { - ty::Str => { - // String literal patterns may have type `str` if `deref_patterns` is - // enabled, in order to allow `deref!("..."): String`. In this case, `value` - // is of type `&str`, so we compare it to `&place`. - if !tcx.features().deref_patterns() { - span_bug!( - test.span, - "matching on `str` went through without enabling deref_patterns" - ); - } - let re_erased = tcx.lifetimes.re_erased; - let ref_str_ty = Ty::new_imm_ref(tcx, re_erased, tcx.types.str_); - let ref_place = self.temp(ref_str_ty, test.span); - // `let ref_place: &str = &place;` - self.cfg.push_assign( - block, - self.source_info(test.span), - ref_place, - Rvalue::Ref(re_erased, BorrowKind::Shared, place), - ); - actual_value_place = ref_place; - actual_value_ty = ref_str_ty; - } - _ => {} - } - - assert_eq!(expected_value_ty, actual_value_ty); - assert!(actual_value_ty.is_imm_ref_str()); + // Similarly, the scrutinized place has type `str`, but we need `&str`. + // Get a reference by doing `let actual_value_ref_place: &str = &place`. + let actual_value_ref_place = self.temp(ref_str_ty, test.span); + self.cfg.push_assign( + block, + self.source_info(test.span), + actual_value_ref_place, + Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Shared, place), + ); // Compare two strings using `::eq`. // (Interestingly this means that exhaustiveness analysis relies, for soundness, @@ -192,7 +178,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fail_block, source_info, expected_value_operand, - Operand::Copy(actual_value_place), + Operand::Copy(actual_value_ref_place), ); } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 02409d2bae9f..70bc142131e4 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -289,32 +289,29 @@ impl<'tcx> ConstToPat<'tcx> { suffix: Box::new([]), }, ty::Str => { - // String literal patterns may have type `str` if `deref_patterns` is enabled, in - // order to allow `deref!("..."): String`. Since we need a `&str` for the comparison - // when lowering to MIR in `Builder::perform_test`, treat the constant as a `&str`. - // This works because `str` and `&str` have the same valtree representation. - let ref_str_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty); - PatKind::Constant { value: ty::Value { ty: ref_str_ty, valtree: cv } } + // Constant/literal patterns of type `&str` are lowered to a + // `PatKind::Deref` wrapping a `PatKind::Constant` of type `str`. + // This pattern node is the `str` constant part. + // + // Under `feature(deref_patterns)`, string literal patterns can also + // have type `str` directly, without the `&`, in order to allow things + // like `deref!("...")` to work when the scrutinee is `String`. + PatKind::Constant { value: ty::Value { ty, valtree: cv } } } - ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() { - // `&str` is represented as a valtree, let's keep using this - // optimization for now. - ty::Str => PatKind::Constant { value: ty::Value { ty, valtree: cv } }, - // All other references are converted into deref patterns and then recursively - // convert the dereferenced constant to a pattern that is the sub-pattern of the - // deref pattern. - _ => { - if !pointee_ty.is_sized(tcx, self.typing_env) && !pointee_ty.is_slice() { - return self.mk_err( - tcx.dcx().create_err(UnsizedPattern { span, non_sm_ty: *pointee_ty }), - ty, - ); - } else { - // References have the same valtree representation as their pointee. - PatKind::Deref { subpattern: self.valtree_to_pat(cv, *pointee_ty) } - } + ty::Ref(_, pointee_ty, ..) => { + if pointee_ty.is_str() + || pointee_ty.is_slice() + || pointee_ty.is_sized(tcx, self.typing_env) + { + // References have the same valtree representation as their pointee. + PatKind::Deref { subpattern: self.valtree_to_pat(cv, *pointee_ty) } + } else { + return self.mk_err( + tcx.dcx().create_err(UnsizedPattern { span, non_sm_ty: *pointee_ty }), + ty, + ); } - }, + } ty::Float(flt) => { let v = cv.to_leaf(); let is_nan = match flt { diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 721635ed48ff..5e75192ff309 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -583,19 +583,13 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { fields = vec![]; arity = 0; } - ty::Ref(_, t, _) if t.is_str() => { - // We want a `&str` constant to behave like a `Deref` pattern, to be compatible - // with other `Deref` patterns. This could have been done in `const_to_pat`, - // but that causes issues with the rest of the matching code. - // So here, the constructor for a `"foo"` pattern is `&` (represented by - // `Ref`), and has one field. That field has constructor `Str(value)` and no - // subfields. - // Note: `t` is `str`, not `&str`. - let ty = self.reveal_opaque_ty(*t); - let subpattern = DeconstructedPat::new(Str(*value), Vec::new(), 0, ty, pat); - ctor = Ref; - fields = vec![subpattern.at_index(0)]; - arity = 1; + ty::Str => { + // For constant/literal patterns of type `&str`, the THIR + // pattern is a `PatKind::Deref` of type `&str` wrapping a + // `PatKind::Const` of type `str`. + ctor = Str(*value); + fields = vec![]; + arity = 0; } // All constants that can be structurally matched have already been expanded // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are diff --git a/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir index b8f54fef0faf..4d13d087586e 100644 --- a/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir @@ -7,11 +7,14 @@ fn constant_eq(_1: &str, _2: bool) -> u32 { let mut _3: (&str, bool); let mut _4: &str; let mut _5: bool; - let mut _6: &&str; - let mut _7: &bool; - let mut _8: bool; - let mut _9: bool; + let mut _6: &str; + let mut _7: &&str; + let mut _8: &bool; + let mut _9: &str; let mut _10: bool; + let mut _11: &str; + let mut _12: bool; + let mut _13: bool; bb0: { StorageLive(_3); @@ -23,7 +26,8 @@ fn constant_eq(_1: &str, _2: bool) -> u32 { StorageDead(_5); StorageDead(_4); PlaceMention(_3); - _9 = ::eq(copy (_3.0: &str), const "a") -> [return: bb9, unwind: bb19]; + _11 = &(*(_3.0: &str)); + _12 = ::eq(copy _11, const "a") -> [return: bb9, unwind: bb19]; } bb1: { @@ -43,7 +47,8 @@ fn constant_eq(_1: &str, _2: bool) -> u32 { } bb5: { - _8 = ::eq(copy (_3.0: &str), const "b") -> [return: bb8, unwind: bb19]; + _9 = &(*(_3.0: &str)); + _10 = ::eq(copy _9, const "b") -> [return: bb8, unwind: bb19]; } bb6: { @@ -55,11 +60,11 @@ fn constant_eq(_1: &str, _2: bool) -> u32 { } bb8: { - switchInt(move _8) -> [0: bb1, otherwise: bb6]; + switchInt(move _10) -> [0: bb1, otherwise: bb6]; } bb9: { - switchInt(move _9) -> [0: bb5, otherwise: bb2]; + switchInt(move _12) -> [0: bb5, otherwise: bb2]; } bb10: { @@ -87,23 +92,25 @@ fn constant_eq(_1: &str, _2: bool) -> u32 { } bb15: { - _6 = &fake shallow (_3.0: &str); - _7 = &fake shallow (_3.1: bool); - StorageLive(_10); - _10 = const true; - switchInt(move _10) -> [0: bb17, otherwise: bb16]; + _6 = &fake shallow (*(_3.0: &str)); + _7 = &fake shallow (_3.0: &str); + _8 = &fake shallow (_3.1: bool); + StorageLive(_13); + _13 = const true; + switchInt(move _13) -> [0: bb17, otherwise: bb16]; } bb16: { - StorageDead(_10); + StorageDead(_13); FakeRead(ForMatchGuard, _6); FakeRead(ForMatchGuard, _7); + FakeRead(ForMatchGuard, _8); _0 = const 1_u32; goto -> bb18; } bb17: { - StorageDead(_10); + StorageDead(_13); falseEdge -> [real: bb3, imaginary: bb5]; } diff --git a/tests/ui/thir-print/str-patterns.stdout b/tests/ui/thir-print/str-patterns.stdout index 8f8944ad4e09..6941ab15130f 100644 --- a/tests/ui/thir-print/str-patterns.stdout +++ b/tests/ui/thir-print/str-patterns.stdout @@ -9,18 +9,25 @@ Thir { ty: &'{erased} str, span: $DIR/str-patterns.rs:11:9: 11:16 (#0), extra: None, - kind: Constant { - value: Value { - ty: &'{erased} str, - valtree: Branch( - [ - 104_u8, - 101_u8, - 108_u8, - 108_u8, - 111_u8, - ], - ), + kind: Deref { + subpattern: Pat { + ty: str, + span: $DIR/str-patterns.rs:11:9: 11:16 (#0), + extra: None, + kind: Constant { + value: Value { + ty: str, + valtree: Branch( + [ + 104_u8, + 101_u8, + 108_u8, + 108_u8, + 111_u8, + ], + ), + }, + }, }, }, }, @@ -42,21 +49,28 @@ Thir { ascriptions: [], }, ), - kind: Constant { - value: Value { - ty: &'{erased} str, - valtree: Branch( - [ - 99_u8, - 111_u8, - 110_u8, - 115_u8, - 116_u8, - 97_u8, - 110_u8, - 116_u8, - ], - ), + kind: Deref { + subpattern: Pat { + ty: str, + span: $DIR/str-patterns.rs:12:9: 12:17 (#0), + extra: None, + kind: Constant { + value: Value { + ty: str, + valtree: Branch( + [ + 99_u8, + 111_u8, + 110_u8, + 115_u8, + 116_u8, + 97_u8, + 110_u8, + 116_u8, + ], + ), + }, + }, }, }, }, From e673bf57c224f2449f810911f94c909a7ffd5f8c Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 15 Jan 2026 16:44:14 +1100 Subject: [PATCH 0752/1061] Also remove `pat_ty` from `TestKind::ScalarEq` --- compiler/rustc_mir_build/src/builder/matches/mod.rs | 6 +----- compiler/rustc_mir_build/src/builder/matches/test.rs | 12 ++++-------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index ddd70a3b597c..11a181cfa8ce 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -1345,11 +1345,7 @@ enum TestKind<'tcx> { }, /// Tests the place against a constant using scalar equality. - ScalarEq { - value: ty::Value<'tcx>, - /// Type of the corresponding pattern node. - pat_ty: Ty<'tcx>, - }, + ScalarEq { value: ty::Value<'tcx> }, /// Test whether the value falls within an inclusive or exclusive range. Range(Arc>), diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index bab9f38f084d..5c3173a7b148 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -42,7 +42,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TestKind::StringEq { value } } TestableCase::Constant { value, kind: PatConstKind::Float | PatConstKind::Other } => { - TestKind::ScalarEq { value, pat_ty: match_pair.pattern_ty } + TestKind::ScalarEq { value } } TestableCase::Range(ref range) => { @@ -182,7 +182,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); } - TestKind::ScalarEq { value, pat_ty } => { + TestKind::ScalarEq { value } => { let tcx = self.tcx; let success_block = target_block(TestBranch::Success); let fail_block = target_block(TestBranch::Failure); @@ -191,12 +191,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut expected_value_operand = self.literal_operand(test.span, Const::from_ty_value(tcx, value)); - let mut actual_value_ty = pat_ty; let mut actual_value_place = place; - match pat_ty.kind() { + match value.ty.kind() { &ty::Pat(base, _) => { - assert_eq!(pat_ty, value.ty); assert!(base.is_trivially_pure_clone_copy()); let transmuted_place = self.temp(base, test.span); @@ -220,15 +218,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); actual_value_place = transmuted_place; - actual_value_ty = base; expected_value_operand = Operand::Copy(transmuted_expect); expected_value_ty = base; } _ => {} } - assert_eq!(expected_value_ty, actual_value_ty); - assert!(actual_value_ty.is_scalar()); + assert!(expected_value_ty.is_scalar()); self.compare( block, From 8dfb888812dd3727cb2edca012cfac220db1d061 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 16 Jan 2026 09:27:45 +0800 Subject: [PATCH 0753/1061] Disable `dump-ice-to-disk` on `i686-pc-windows-msvc` Sometimes the middle frames of the ICE backtrace becomes `` on `i686-pc-windows-msvc` which then makes this test flaky. --- tests/run-make/dump-ice-to-disk/rmake.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/run-make/dump-ice-to-disk/rmake.rs b/tests/run-make/dump-ice-to-disk/rmake.rs index 09a34cdeb5e7..319cbc6e0ca8 100644 --- a/tests/run-make/dump-ice-to-disk/rmake.rs +++ b/tests/run-make/dump-ice-to-disk/rmake.rs @@ -18,13 +18,16 @@ //! # Test history //! //! The previous rmake.rs iteration of this test was flaky for unknown reason on -//! `i686-pc-windows-gnu` *specifically*, so assertion failures in this test was made extremely -//! verbose to help diagnose why the ICE messages was different. It appears that backtraces on -//! `i686-pc-windows-gnu` specifically are quite unpredictable in how many backtrace frames are -//! involved. +//! `i686-pc-windows-gnu`, so assertion failures in this test was made extremely verbose to help +//! diagnose why the ICE messages was different. It appears that backtraces on `i686-pc-windows-gnu` +//! specifically are quite unpredictable in how many backtrace frames are involved. +//! +//! Disabled on `i686-pc-windows-msvc` as well, because sometimes the middle portion of the ICE +//! backtrace becomes ``. //@ ignore-cross-compile (exercising ICE dump on host) //@ ignore-i686-pc-windows-gnu (unwind mechanism produces unpredictable backtraces) +//@ ignore-i686-pc-windows-msvc (sometimes partial backtrace becomes ``) use std::cell::OnceCell; use std::path::{Path, PathBuf}; From bfd1a9a86f5f344f09a550338eeb08c29458015c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 16 Jan 2026 02:14:01 +0000 Subject: [PATCH 0754/1061] Use default_field_values more in `Resolver` Provide `const` functions to get around lack of `const Default` for `FxHash*` types. Use default field values in `Resolver` more. --- compiler/rustc_data_structures/src/fx.rs | 15 +++++ compiler/rustc_resolve/src/lib.rs | 77 ++++++++---------------- 2 files changed, 41 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_data_structures/src/fx.rs b/compiler/rustc_data_structures/src/fx.rs index c1a5c8ebc764..026ec5c230ec 100644 --- a/compiler/rustc_data_structures/src/fx.rs +++ b/compiler/rustc_data_structures/src/fx.rs @@ -28,3 +28,18 @@ macro_rules! define_stable_id_collections { pub type $entry_name<'a, T> = $crate::fx::IndexEntry<'a, $key, T>; }; } + +pub mod default { + use super::{FxBuildHasher, FxHashMap, FxHashSet}; + + // FIXME: These two functions will become unnecessary after + // lands and we start using the corresponding + // `rustc-hash` version. After that we can use `Default::default()` instead. + pub const fn fx_hash_map() -> FxHashMap { + FxHashMap::with_hasher(FxBuildHasher) + } + + pub const fn fx_hash_set() -> FxHashSet { + FxHashSet::with_hasher(FxBuildHasher) + } +} diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 2c22aacb3241..b7efff929f70 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -45,7 +45,7 @@ use rustc_ast::{ self as ast, AngleBracketedArg, CRATE_NODE_ID, Crate, Expr, ExprKind, GenericArg, GenericArgs, NodeId, Path, attr, }; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, default}; use rustc_data_structures::intern::Interned; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{FreezeReadGuard, FreezeWriteGuard}; @@ -1129,7 +1129,7 @@ pub struct Resolver<'ra, 'tcx> { /// Span of the privacy modifier in fields of an item `DefId` accessible with dot syntax. /// Used for hints during error reporting. - field_visibility_spans: FxHashMap>, + field_visibility_spans: FxHashMap> = default::fx_hash_map(), /// All imports known to succeed or fail. determined_imports: Vec> = Vec::new(), @@ -1146,7 +1146,7 @@ pub struct Resolver<'ra, 'tcx> { /// Resolutions for import nodes, which have multiple resolutions in different namespaces. import_res_map: NodeMap>>, /// An import will be inserted into this map if it has been used. - import_use_map: FxHashMap, Used>, + import_use_map: FxHashMap, Used> = default::fx_hash_map(), /// Resolutions for labels (node IDs of their corresponding blocks or loops). label_res_map: NodeMap, /// Resolutions for lifetimes. @@ -1190,7 +1190,7 @@ pub struct Resolver<'ra, 'tcx> { glob_map: FxIndexMap>, glob_error: Option = None, visibilities_for_hashing: Vec<(LocalDefId, Visibility)> = Vec::new(), - used_imports: FxHashSet, + used_imports: FxHashSet = default::fx_hash_set(), maybe_unused_trait_imports: FxIndexSet, /// Privacy errors are delayed until the end in order to deduplicate them. @@ -1206,30 +1206,30 @@ pub struct Resolver<'ra, 'tcx> { /// When a type is re-exported that has an inaccessible constructor because it has fields that /// are inaccessible from the import's scope, we mark that as the type won't be able to be built /// through the re-export. We use this information to extend the existing diagnostic. - inaccessible_ctor_reexport: FxHashMap, + inaccessible_ctor_reexport: FxHashMap = default::fx_hash_map(), arenas: &'ra ResolverArenas<'ra>, dummy_decl: Decl<'ra>, builtin_type_decls: FxHashMap>, builtin_attr_decls: FxHashMap>, registered_tool_decls: FxHashMap>, - macro_names: FxHashSet, - builtin_macros: FxHashMap, + macro_names: FxHashSet = default::fx_hash_set(), + builtin_macros: FxHashMap = default::fx_hash_map(), registered_tools: &'tcx RegisteredTools, macro_use_prelude: FxIndexMap>, /// Eagerly populated map of all local macro definitions. - local_macro_map: FxHashMap, + local_macro_map: FxHashMap = default::fx_hash_map(), /// Lazily populated cache of macro definitions loaded from external crates. extern_macro_map: CacheRefCell>, dummy_ext_bang: Arc, dummy_ext_derive: Arc, non_macro_attr: &'ra MacroData, - local_macro_def_scopes: FxHashMap>, - ast_transform_scopes: FxHashMap>, + local_macro_def_scopes: FxHashMap> = default::fx_hash_map(), + ast_transform_scopes: FxHashMap> = default::fx_hash_map(), unused_macros: FxIndexMap, /// A map from the macro to all its potentially unused arms. unused_macro_rules: FxIndexMap>, - proc_macro_stubs: FxHashSet, + proc_macro_stubs: FxHashSet = default::fx_hash_set(), /// Traces collected during macro resolution and validated when it's complete. single_segment_macro_resolutions: CmRefCell, Option>, Option)>>, @@ -1239,23 +1239,23 @@ pub struct Resolver<'ra, 'tcx> { /// `derive(Copy)` marks items they are applied to so they are treated specially later. /// Derive macros cannot modify the item themselves and have to store the markers in the global /// context, so they attach the markers to derive container IDs using this resolver table. - containers_deriving_copy: FxHashSet, + containers_deriving_copy: FxHashSet = default::fx_hash_set(), /// Parent scopes in which the macros were invoked. /// FIXME: `derives` are missing in these parent scopes and need to be taken from elsewhere. - invocation_parent_scopes: FxHashMap>, + invocation_parent_scopes: FxHashMap> = default::fx_hash_map(), /// `macro_rules` scopes *produced* by expanding the macro invocations, /// include all the `macro_rules` items and other invocations generated by them. - output_macro_rules_scopes: FxHashMap>, + output_macro_rules_scopes: FxHashMap> = default::fx_hash_map(), /// `macro_rules` scopes produced by `macro_rules` item definitions. - macro_rules_scopes: FxHashMap>, + macro_rules_scopes: FxHashMap> = default::fx_hash_map(), /// Helper attributes that are in scope for the given expansion. - helper_attrs: FxHashMap)>>, + helper_attrs: FxHashMap)>> = default::fx_hash_map(), /// Ready or in-progress results of resolving paths inside the `#[derive(...)]` attribute /// with the given `ExpnId`. - derive_data: FxHashMap, + derive_data: FxHashMap = default::fx_hash_map(), /// Avoid duplicated errors for "name already defined". - name_already_seen: FxHashMap, + name_already_seen: FxHashMap = default::fx_hash_map(), potentially_unused_imports: Vec> = Vec::new(), @@ -1275,14 +1275,14 @@ pub struct Resolver<'ra, 'tcx> { disambiguator: DisambiguatorState, /// Indices of unnamed struct or variant fields with unresolved attributes. - placeholder_field_indices: FxHashMap, + placeholder_field_indices: FxHashMap = default::fx_hash_map(), /// When collecting definitions from an AST fragment produced by a macro invocation `ExpnId` /// we know what parent node that fragment should be attached to thanks to this table, /// and how the `impl Trait` fragments were introduced. invocation_parents: FxHashMap, /// Amount of lifetime parameters for each item in the crate. - item_generics_num_lifetimes: FxHashMap, + item_generics_num_lifetimes: FxHashMap = default::fx_hash_map(), delegation_fn_sigs: LocalDefIdMap, delegation_infos: LocalDefIdMap, @@ -1293,7 +1293,7 @@ pub struct Resolver<'ra, 'tcx> { proc_macros: Vec = Vec::new(), confused_type_with_std_module: FxIndexMap, /// Whether lifetime elision was successful. - lifetime_elision_allowed: FxHashSet, + lifetime_elision_allowed: FxHashSet = default::fx_hash_set(), /// Names of items that were stripped out via cfg with their corresponding cfg meta item. stripped_cfg_items: Vec> = Vec::new(), @@ -1304,19 +1304,19 @@ pub struct Resolver<'ra, 'tcx> { all_macro_rules: UnordSet, /// Invocation ids of all glob delegations. - glob_delegation_invoc_ids: FxHashSet, + glob_delegation_invoc_ids: FxHashSet = default::fx_hash_set(), /// Analogue of module `unexpanded_invocations` but in trait impls, excluding glob delegations. /// Needed because glob delegations wait for all other neighboring macros to expand. - impl_unexpanded_invocations: FxHashMap>, + impl_unexpanded_invocations: FxHashMap> = default::fx_hash_map(), /// Simplified analogue of module `resolutions` but in trait impls, excluding glob delegations. /// Needed because glob delegations exclude explicitly defined names. - impl_binding_keys: FxHashMap>, + impl_binding_keys: FxHashMap> = default::fx_hash_map(), /// This is the `Span` where an `extern crate foo;` suggestion would be inserted, if `foo` /// could be a crate that wasn't imported. For diagnostics use only. current_crate_outer_attr_insert_span: Span, - mods_with_parse_errors: FxHashSet, + mods_with_parse_errors: FxHashSet = default::fx_hash_set(), /// Whether `Resolver::register_macros_for_all_crates` has been called once already, as we /// don't need to run it more than once. @@ -1325,7 +1325,7 @@ pub struct Resolver<'ra, 'tcx> { // Stores pre-expansion and pre-placeholder-fragment-insertion names for `impl Trait` types // that were encountered during resolution. These names are used to generate item names // for APITs, so we don't want to leak details of resolution into these names. - impl_trait_names: FxHashMap, + impl_trait_names: FxHashMap = default::fx_hash_map(), } /// This provides memory for the rest of the crate. The `'ra` lifetime that is @@ -1598,12 +1598,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { field_names: Default::default(), field_defaults: Default::default(), - field_visibility_spans: FxHashMap::default(), pat_span_map: Default::default(), partial_res_map: Default::default(), import_res_map: Default::default(), - import_use_map: Default::default(), label_res_map: Default::default(), lifetimes_res_map: Default::default(), extra_lifetime_params_map: Default::default(), @@ -1616,12 +1614,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { local_module_map, extern_module_map: Default::default(), block_map: Default::default(), - ast_transform_scopes: FxHashMap::default(), glob_map: Default::default(), - used_imports: FxHashSet::default(), maybe_unused_trait_imports: Default::default(), - inaccessible_ctor_reexport: Default::default(), arenas, dummy_decl: arenas.new_pub_def_decl(Res::Err, DUMMY_SP, LocalExpnId::ROOT), @@ -1649,52 +1644,32 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { (*ident, decl) }) .collect(), - macro_names: FxHashSet::default(), - builtin_macros: Default::default(), registered_tools, macro_use_prelude: Default::default(), - local_macro_map: Default::default(), extern_macro_map: Default::default(), dummy_ext_bang: Arc::new(SyntaxExtension::dummy_bang(edition)), dummy_ext_derive: Arc::new(SyntaxExtension::dummy_derive(edition)), non_macro_attr: arenas .alloc_macro(MacroData::new(Arc::new(SyntaxExtension::non_macro_attr(edition)))), - invocation_parent_scopes: Default::default(), - output_macro_rules_scopes: Default::default(), - macro_rules_scopes: Default::default(), - helper_attrs: Default::default(), - derive_data: Default::default(), - local_macro_def_scopes: FxHashMap::default(), - name_already_seen: FxHashMap::default(), struct_constructors: Default::default(), unused_macros: Default::default(), unused_macro_rules: Default::default(), - proc_macro_stubs: Default::default(), single_segment_macro_resolutions: Default::default(), multi_segment_macro_resolutions: Default::default(), builtin_attrs: Default::default(), - containers_deriving_copy: Default::default(), lint_buffer: LintBuffer::default(), node_id_to_def_id, disambiguator: DisambiguatorState::new(), - placeholder_field_indices: Default::default(), invocation_parents, - item_generics_num_lifetimes: Default::default(), trait_impls: Default::default(), confused_type_with_std_module: Default::default(), - lifetime_elision_allowed: Default::default(), stripped_cfg_items: Default::default(), effective_visibilities: Default::default(), doc_link_resolutions: Default::default(), doc_link_traits_in_scope: Default::default(), all_macro_rules: Default::default(), delegation_fn_sigs: Default::default(), - glob_delegation_invoc_ids: Default::default(), - impl_unexpanded_invocations: Default::default(), - impl_binding_keys: Default::default(), current_crate_outer_attr_insert_span, - mods_with_parse_errors: Default::default(), - impl_trait_names: Default::default(), delegation_infos: Default::default(), .. }; From 2766ccfd4e419bae7d1b30d0f1e80d423bffee83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 16 Jan 2026 02:23:44 +0000 Subject: [PATCH 0755/1061] Make `UnordSet` and `UnordMap` `const Default` and use it in `Resolver` --- compiler/rustc_data_structures/src/lib.rs | 2 ++ compiler/rustc_data_structures/src/unord.rs | 10 +++--- compiler/rustc_resolve/src/lib.rs | 34 ++++++++------------- 3 files changed, 19 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 41f6292e740b..ff1dd41c82cc 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -18,6 +18,8 @@ #![feature(assert_matches)] #![feature(auto_traits)] #![feature(cfg_select)] +#![feature(const_default)] +#![feature(const_trait_impl)] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] #![feature(extend_one)] diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs index 3d44fb1fd48d..0a9a86d7a43b 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -8,7 +8,7 @@ use std::hash::Hash; use std::iter::{Product, Sum}; use std::ops::Index; -use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet}; use rustc_macros::{Decodable_NoContext, Encodable_NoContext}; use crate::fingerprint::Fingerprint; @@ -241,10 +241,10 @@ pub struct UnordSet { impl UnordCollection for UnordSet {} -impl Default for UnordSet { +impl const Default for UnordSet { #[inline] fn default() -> Self { - Self { inner: FxHashSet::default() } + Self { inner: FxHashSet::with_hasher(FxBuildHasher) } } } @@ -438,10 +438,10 @@ pub struct UnordMap { impl UnordCollection for UnordMap {} -impl Default for UnordMap { +impl const Default for UnordMap { #[inline] fn default() -> Self { - Self { inner: FxHashMap::default() } + Self { inner: FxHashMap::with_hasher(FxBuildHasher) } } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index b7efff929f70..c31cec482351 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -13,6 +13,8 @@ #![feature(arbitrary_self_types)] #![feature(assert_matches)] #![feature(box_patterns)] +#![feature(const_default)] +#![feature(const_trait_impl)] #![feature(control_flow_into_value)] #![feature(decl_macro)] #![feature(default_field_values)] @@ -1113,7 +1115,7 @@ pub struct Resolver<'ra, 'tcx> { tcx: TyCtxt<'tcx>, /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`. - expn_that_defined: UnordMap, + expn_that_defined: UnordMap = Default::default(), graph_root: Module<'ra>, @@ -1124,8 +1126,8 @@ pub struct Resolver<'ra, 'tcx> { extern_prelude: FxIndexMap>, /// N.B., this is used only for better diagnostics, not name resolution itself. - field_names: LocalDefIdMap>, - field_defaults: LocalDefIdMap>, + field_names: LocalDefIdMap> = Default::default(), + field_defaults: LocalDefIdMap> = Default::default(), /// Span of the privacy modifier in fields of an item `DefId` accessible with dot syntax. /// Used for hints during error reporting. @@ -1155,9 +1157,9 @@ pub struct Resolver<'ra, 'tcx> { extra_lifetime_params_map: NodeMap>, /// `CrateNum` resolutions of `extern crate` items. - extern_crate_map: UnordMap, - module_children: LocalDefIdMap>, - ambig_module_children: LocalDefIdMap>, + extern_crate_map: UnordMap = Default::default(), + module_children: LocalDefIdMap> = Default::default(), + ambig_module_children: LocalDefIdMap> = Default::default(), trait_map: NodeMap>, /// A map from nodes to anonymous modules. @@ -1264,7 +1266,7 @@ pub struct Resolver<'ra, 'tcx> { /// Table for mapping struct IDs into struct constructor IDs, /// it's not used during normal resolution, only for better error reporting. /// Also includes of list of each fields visibility - struct_constructors: LocalDefIdMap<(Res, Visibility, Vec>)>, + struct_constructors: LocalDefIdMap<(Res, Visibility, Vec>)> = Default::default(), lint_buffer: LintBuffer, @@ -1283,8 +1285,8 @@ pub struct Resolver<'ra, 'tcx> { /// Amount of lifetime parameters for each item in the crate. item_generics_num_lifetimes: FxHashMap = default::fx_hash_map(), - delegation_fn_sigs: LocalDefIdMap, - delegation_infos: LocalDefIdMap, + delegation_fn_sigs: LocalDefIdMap = Default::default(), + delegation_infos: LocalDefIdMap = Default::default(), main_def: Option = None, trait_impls: FxIndexMap>, @@ -1301,7 +1303,7 @@ pub struct Resolver<'ra, 'tcx> { effective_visibilities: EffectiveVisibilities, doc_link_resolutions: FxIndexMap, doc_link_traits_in_scope: FxIndexMap>, - all_macro_rules: UnordSet, + all_macro_rules: UnordSet = Default::default(), /// Invocation ids of all glob delegations. glob_delegation_invoc_ids: FxHashSet = default::fx_hash_set(), @@ -1587,8 +1589,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut resolver = Resolver { tcx, - expn_that_defined: Default::default(), - // The outermost module has def ID 0; this is not reflected in the // AST. graph_root, @@ -1596,18 +1596,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { prelude: None, extern_prelude, - field_names: Default::default(), - field_defaults: Default::default(), - pat_span_map: Default::default(), partial_res_map: Default::default(), import_res_map: Default::default(), label_res_map: Default::default(), lifetimes_res_map: Default::default(), extra_lifetime_params_map: Default::default(), - extern_crate_map: Default::default(), - module_children: Default::default(), - ambig_module_children: Default::default(), trait_map: NodeMap::default(), empty_module, local_modules, @@ -1651,7 +1645,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { dummy_ext_derive: Arc::new(SyntaxExtension::dummy_derive(edition)), non_macro_attr: arenas .alloc_macro(MacroData::new(Arc::new(SyntaxExtension::non_macro_attr(edition)))), - struct_constructors: Default::default(), unused_macros: Default::default(), unused_macro_rules: Default::default(), single_segment_macro_resolutions: Default::default(), @@ -1667,10 +1660,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { effective_visibilities: Default::default(), doc_link_resolutions: Default::default(), doc_link_traits_in_scope: Default::default(), - all_macro_rules: Default::default(), - delegation_fn_sigs: Default::default(), current_crate_outer_attr_insert_span, - delegation_infos: Default::default(), .. }; From dd4d60f701ae8bf43fb10f69260b8ffb07faa6be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 16 Jan 2026 02:28:49 +0000 Subject: [PATCH 0756/1061] Provide default field in `Resolver` for `NodeMap` fields --- compiler/rustc_resolve/src/lib.rs | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index c31cec482351..cd4d738663d4 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1141,26 +1141,26 @@ pub struct Resolver<'ra, 'tcx> { // Spans for local variables found during pattern resolution. // Used for suggestions during error reporting. - pat_span_map: NodeMap, + pat_span_map: NodeMap = Default::default(), /// Resolutions for nodes that have a single resolution. - partial_res_map: NodeMap, + partial_res_map: NodeMap = Default::default(), /// Resolutions for import nodes, which have multiple resolutions in different namespaces. - import_res_map: NodeMap>>, + import_res_map: NodeMap>> = Default::default(), /// An import will be inserted into this map if it has been used. import_use_map: FxHashMap, Used> = default::fx_hash_map(), /// Resolutions for labels (node IDs of their corresponding blocks or loops). - label_res_map: NodeMap, + label_res_map: NodeMap = Default::default(), /// Resolutions for lifetimes. - lifetimes_res_map: NodeMap, + lifetimes_res_map: NodeMap = Default::default(), /// Lifetime parameters that lowering will have to introduce. - extra_lifetime_params_map: NodeMap>, + extra_lifetime_params_map: NodeMap> = Default::default(), /// `CrateNum` resolutions of `extern crate` items. extern_crate_map: UnordMap = Default::default(), module_children: LocalDefIdMap> = Default::default(), ambig_module_children: LocalDefIdMap> = Default::default(), - trait_map: NodeMap>, + trait_map: NodeMap> = Default::default(), /// A map from nodes to anonymous modules. /// Anonymous modules are pseudo-modules that are implicitly created around items @@ -1176,7 +1176,7 @@ pub struct Resolver<'ra, 'tcx> { /// /// There will be an anonymous module created around `g` with the ID of the /// entry block for `f`. - block_map: NodeMap>, + block_map: NodeMap> = Default::default(), /// A fake module that contains no definition and no prelude. Used so that /// some AST passes can generate identifiers that only resolve to local or /// lang items. @@ -1596,18 +1596,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { prelude: None, extern_prelude, - pat_span_map: Default::default(), - partial_res_map: Default::default(), - import_res_map: Default::default(), - label_res_map: Default::default(), - lifetimes_res_map: Default::default(), - extra_lifetime_params_map: Default::default(), - trait_map: NodeMap::default(), empty_module, local_modules, local_module_map, extern_module_map: Default::default(), - block_map: Default::default(), glob_map: Default::default(), maybe_unused_trait_imports: Default::default(), From 664e19bc3a68c88dfa433fefe39a8e0338315eb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 16 Jan 2026 02:34:19 +0000 Subject: [PATCH 0757/1061] Make `DisambiguatorState` `const`-buildable --- compiler/rustc_hir/src/definitions.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 01f84c90ec7a..5e361891f6d0 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -103,7 +103,7 @@ pub struct DisambiguatorState { } impl DisambiguatorState { - pub fn new() -> Self { + pub const fn new() -> Self { Self { next: Default::default() } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index cd4d738663d4..3bee1efba886 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1237,7 +1237,7 @@ pub struct Resolver<'ra, 'tcx> { CmRefCell, Option>, Option)>>, multi_segment_macro_resolutions: CmRefCell, Span, MacroKind, ParentScope<'ra>, Option, Namespace)>>, - builtin_attrs: Vec<(Ident, ParentScope<'ra>)>, + builtin_attrs: Vec<(Ident, ParentScope<'ra>)> = Vec::new(), /// `derive(Copy)` marks items they are applied to so they are treated specially later. /// Derive macros cannot modify the item themselves and have to store the markers in the global /// context, so they attach the markers to derive container IDs using this resolver table. @@ -1274,7 +1274,7 @@ pub struct Resolver<'ra, 'tcx> { node_id_to_def_id: NodeMap>, - disambiguator: DisambiguatorState, + disambiguator: DisambiguatorState = DisambiguatorState::new(), /// Indices of unnamed struct or variant fields with unresolved attributes. placeholder_field_indices: FxHashMap = default::fx_hash_map(), @@ -1641,10 +1641,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { unused_macro_rules: Default::default(), single_segment_macro_resolutions: Default::default(), multi_segment_macro_resolutions: Default::default(), - builtin_attrs: Default::default(), lint_buffer: LintBuffer::default(), node_id_to_def_id, - disambiguator: DisambiguatorState::new(), invocation_parents, trait_impls: Default::default(), confused_type_with_std_module: Default::default(), From 2b139b786ee2bf21b8250f6dfb800a85ad2f8db3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 16 Jan 2026 02:36:07 +0000 Subject: [PATCH 0758/1061] `prelude` is already defaulted --- compiler/rustc_resolve/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 3bee1efba886..d62635759981 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1593,7 +1593,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // AST. graph_root, assert_speculative: false, // Only set/cleared in Resolver::resolve_imports for now - prelude: None, extern_prelude, empty_module, From 9f6e7473d6ac3e7e1596bef17cfbfda4e563ffc7 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 16 Jan 2026 14:54:14 +1100 Subject: [PATCH 0759/1061] Fix a typo. --- compiler/rustc_middle/src/query/plumbing.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 8d01d9482ed4..9300c942a525 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -278,7 +278,7 @@ macro_rules! define_callbacks { ($V) ); - /// This function takes `ProvidedValue` and coverts it to an erased `Value` by + /// This function takes `ProvidedValue` and converts it to an erased `Value` by /// allocating it on an arena if the query has the `arena_cache` modifier. The /// value is then erased and returned. This will happen when computing the query /// using a provider or decoding a stored result. From 4c2e447027399f4ebe98563177c68831898c16e6 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 16 Jan 2026 14:54:48 +1100 Subject: [PATCH 0760/1061] Rename `fatal_cycle` as `cycle_fatal`. To be consistent with the closely related `cycle_stash` and `cycle_delay_bug`. --- compiler/rustc_macros/src/query.rs | 12 ++++----- compiler/rustc_middle/src/query/mod.rs | 28 ++++++++++----------- compiler/rustc_middle/src/query/plumbing.rs | 2 +- compiler/rustc_query_impl/src/plumbing.rs | 2 +- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 5d32950875ad..104e95277a1a 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -93,7 +93,7 @@ struct QueryModifiers { cache: Option<(Option, Block)>, /// A cycle error for this query aborting the compilation with a fatal error. - fatal_cycle: Option, + cycle_fatal: Option, /// A cycle error results in a delay_bug call cycle_delay_bug: Option, @@ -136,7 +136,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { let mut arena_cache = None; let mut cache = None; let mut desc = None; - let mut fatal_cycle = None; + let mut cycle_fatal = None; let mut cycle_delay_bug = None; let mut cycle_stash = None; let mut no_hash = None; @@ -189,8 +189,8 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { try_insert!(cache = (args, block)); } else if modifier == "arena_cache" { try_insert!(arena_cache = modifier); - } else if modifier == "fatal_cycle" { - try_insert!(fatal_cycle = modifier); + } else if modifier == "cycle_fatal" { + try_insert!(cycle_fatal = modifier); } else if modifier == "cycle_delay_bug" { try_insert!(cycle_delay_bug = modifier); } else if modifier == "cycle_stash" { @@ -220,7 +220,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { arena_cache, cache, desc, - fatal_cycle, + cycle_fatal, cycle_delay_bug, cycle_stash, no_hash, @@ -366,8 +366,8 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream { } passthrough!( - fatal_cycle, arena_cache, + cycle_fatal, cycle_delay_bug, cycle_stash, no_hash, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 5f40c36423b3..fc1bf78c82f3 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -28,7 +28,7 @@ //! - `desc { ... }`: Sets the human-readable description for diagnostics and profiling. Required for every query. //! - `arena_cache`: Use an arena for in-memory caching of the query result. //! - `cache_on_disk_if { ... }`: Cache the query result to disk if the provided block evaluates to true. -//! - `fatal_cycle`: If a dependency cycle is detected, abort compilation with a fatal error. +//! - `cycle_fatal`: If a dependency cycle is detected, abort compilation with a fatal error. //! - `cycle_delay_bug`: If a dependency cycle is detected, emit a delayed bug instead of aborting immediately. //! - `cycle_stash`: If a dependency cycle is detected, stash the error for later handling. //! - `no_hash`: Do not hash the query result for incremental compilation; just mark as dirty if recomputed. @@ -160,7 +160,7 @@ pub mod plumbing; // The result type of each query must implement `Clone`, and additionally // `ty::query::values::Value`, which produces an appropriate placeholder // (error) value if the query resulted in a query cycle. -// Queries marked with `fatal_cycle` do not need the latter implementation, +// Queries marked with `cycle_fatal` do not need the latter implementation, // as they will raise an fatal error on query cycles instead. rustc_queries! { /// This exists purely for testing the interactions between delayed bugs and incremental. @@ -584,7 +584,7 @@ rustc_queries! { } query is_panic_runtime(_: CrateNum) -> bool { - fatal_cycle + cycle_fatal desc { "checking if the crate is_panic_runtime" } separate_provide_extern } @@ -1315,7 +1315,7 @@ rustc_queries! { /// Return the set of (transitive) callees that may result in a recursive call to `key`, /// if we were able to walk all callees. query mir_callgraph_cyclic(key: LocalDefId) -> &'tcx Option> { - fatal_cycle + cycle_fatal arena_cache desc { |tcx| "computing (transitive) callees of `{}` that may recurse", @@ -1326,7 +1326,7 @@ rustc_queries! { /// Obtain all the calls into other local functions query mir_inliner_callees(key: ty::InstanceKind<'tcx>) -> &'tcx [(DefId, GenericArgsRef<'tcx>)] { - fatal_cycle + cycle_fatal desc { |tcx| "computing all local function calls in `{}`", tcx.def_path_str(key.def_id()), @@ -1822,31 +1822,31 @@ rustc_queries! { } query is_compiler_builtins(_: CrateNum) -> bool { - fatal_cycle + cycle_fatal desc { "checking if the crate is_compiler_builtins" } separate_provide_extern } query has_global_allocator(_: CrateNum) -> bool { // This query depends on untracked global state in CStore eval_always - fatal_cycle + cycle_fatal desc { "checking if the crate has_global_allocator" } separate_provide_extern } query has_alloc_error_handler(_: CrateNum) -> bool { // This query depends on untracked global state in CStore eval_always - fatal_cycle + cycle_fatal desc { "checking if the crate has_alloc_error_handler" } separate_provide_extern } query has_panic_handler(_: CrateNum) -> bool { - fatal_cycle + cycle_fatal desc { "checking if the crate has_panic_handler" } separate_provide_extern } query is_profiler_runtime(_: CrateNum) -> bool { - fatal_cycle + cycle_fatal desc { "checking if a crate is `#![profiler_runtime]`" } separate_provide_extern } @@ -1855,22 +1855,22 @@ rustc_queries! { cache_on_disk_if { true } } query required_panic_strategy(_: CrateNum) -> Option { - fatal_cycle + cycle_fatal desc { "getting a crate's required panic strategy" } separate_provide_extern } query panic_in_drop_strategy(_: CrateNum) -> PanicStrategy { - fatal_cycle + cycle_fatal desc { "getting a crate's configured panic-in-drop strategy" } separate_provide_extern } query is_no_builtins(_: CrateNum) -> bool { - fatal_cycle + cycle_fatal desc { "getting whether a crate has `#![no_builtins]`" } separate_provide_extern } query symbol_mangling_version(_: CrateNum) -> SymbolManglingVersion { - fatal_cycle + cycle_fatal desc { "getting a crate's symbol mangling version" } separate_provide_extern } diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 9300c942a525..25c9a0a81ab4 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -532,7 +532,7 @@ macro_rules! define_feedable { // The result type of each query must implement `Clone`, and additionally // `ty::query::values::Value`, which produces an appropriate placeholder // (error) value if the query resulted in a query cycle. -// Queries marked with `fatal_cycle` do not need the latter implementation, +// Queries marked with `cycle_fatal` do not need the latter implementation, // as they will raise an fatal error on query cycles instead. mod sealed { diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 39b6fac4ebc0..c98affe0cb19 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -219,7 +219,7 @@ macro_rules! handle_cycle_error { ([]) => {{ rustc_query_system::HandleCycleError::Error }}; - ([(fatal_cycle) $($rest:tt)*]) => {{ + ([(cycle_fatal) $($rest:tt)*]) => {{ rustc_query_system::HandleCycleError::Fatal }}; ([(cycle_stash) $($rest:tt)*]) => {{ From 2e58d05a0a40533914aeaf11cf664ba41d070955 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 16 Jan 2026 15:51:13 +1100 Subject: [PATCH 0761/1061] Add test from #124901. Issue #124901 was an OOM caused by a query cycle. It was fixed by a complex change in PR #138672, but that PR did not add the test case. Let's add it now, because it's the only known reproducer of the OOM. --- tests/ui/resolve/query-cycle-issue-124901.rs | 24 +++++++++++++++++++ .../resolve/query-cycle-issue-124901.stderr | 9 +++++++ 2 files changed, 33 insertions(+) create mode 100644 tests/ui/resolve/query-cycle-issue-124901.rs create mode 100644 tests/ui/resolve/query-cycle-issue-124901.stderr diff --git a/tests/ui/resolve/query-cycle-issue-124901.rs b/tests/ui/resolve/query-cycle-issue-124901.rs new file mode 100644 index 000000000000..6cb1e58b6258 --- /dev/null +++ b/tests/ui/resolve/query-cycle-issue-124901.rs @@ -0,0 +1,24 @@ +//~ ERROR: cycle detected when looking up span for `Default` +trait Default { + type Id; + + fn intu(&self) -> &Self::Id; +} + +impl, U: Copy> Default for U { + default type Id = T; + fn intu(&self) -> &Self::Id { + self + } +} + +fn specialization(t: T) -> U { + *t.intu() +} + +use std::num::NonZero; + +fn main() { + let assert_eq = NonZero::>>(0); + assert_eq!(specialization, None); +} diff --git a/tests/ui/resolve/query-cycle-issue-124901.stderr b/tests/ui/resolve/query-cycle-issue-124901.stderr new file mode 100644 index 000000000000..9c1d7b1de33a --- /dev/null +++ b/tests/ui/resolve/query-cycle-issue-124901.stderr @@ -0,0 +1,9 @@ +error[E0391]: cycle detected when looking up span for `Default` + | + = note: ...which immediately requires looking up span for `Default` again + = note: cycle used when perform lints prior to AST lowering + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0391`. From 8fa2f693bb566cd99aae6c057c890b1f2e42c773 Mon Sep 17 00:00:00 2001 From: Felix Rath Date: Wed, 13 Aug 2025 13:05:07 +0200 Subject: [PATCH 0762/1061] Implement incremental caching for derive macro expansions --- Cargo.lock | 2 + compiler/rustc_ast/src/ast.rs | 3 +- compiler/rustc_ast/src/token.rs | 16 +- compiler/rustc_ast/src/tokenstream.rs | 20 +-- compiler/rustc_expand/Cargo.toml | 2 + compiler/rustc_expand/src/lib.rs | 4 + compiler/rustc_expand/src/proc_macro.rs | 168 ++++++++++++++---- .../src/persist/dirty_clean.rs | 36 ++-- compiler/rustc_interface/src/passes.rs | 1 + compiler/rustc_middle/src/arena.rs | 1 + .../rustc_middle/src/dep_graph/dep_node.rs | 6 + compiler/rustc_middle/src/dep_graph/mod.rs | 2 +- compiler/rustc_middle/src/query/erase.rs | 5 + compiler/rustc_middle/src/query/keys.rs | 16 +- compiler/rustc_middle/src/query/mod.rs | 14 +- .../rustc_middle/src/query/on_disk_cache.rs | 7 + .../rustc_query_system/src/dep_graph/graph.rs | 12 ++ compiler/rustc_session/src/options.rs | 2 + compiler/rustc_span/src/hygiene.rs | 6 + .../auxiliary/derive_nothing.rs | 15 ++ .../proc_macro_unchanged.rs | 18 ++ 21 files changed, 284 insertions(+), 72 deletions(-) create mode 100644 tests/incremental/derive_macro_expansion/auxiliary/derive_nothing.rs create mode 100644 tests/incremental/derive_macro_expansion/proc_macro_unchanged.rs diff --git a/Cargo.lock b/Cargo.lock index bf28939ac87b..d83bdf767e5c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3887,11 +3887,13 @@ dependencies = [ "rustc_lexer", "rustc_lint_defs", "rustc_macros", + "rustc_middle", "rustc_parse", "rustc_proc_macro", "rustc_serialize", "rustc_session", "rustc_span", + "scoped-tls", "smallvec", "thin-vec", "tracing", diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 079238b12bfd..b2b1f997ac54 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3348,7 +3348,8 @@ impl UseTree { /// Distinguishes between `Attribute`s that decorate items and Attributes that /// are contained as statements within items. These two cases need to be /// distinguished for pretty-printing. -#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy, HashStable_Generic, Walkable)] +#[derive(Clone, PartialEq, Eq, Hash, Debug, Copy)] +#[derive(Encodable, Decodable, HashStable_Generic, Walkable)] pub enum AttrStyle { Outer, Inner, diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index accf4d181632..453e7443d324 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -40,13 +40,13 @@ impl DocFragmentKind { } } -#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)] pub enum CommentKind { Line, Block, } -#[derive(Copy, Clone, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Encodable, Decodable, HashStable_Generic)] pub enum InvisibleOrigin { // From the expansion of a metavariable in a declarative macro. MetaVar(MetaVarKind), @@ -123,7 +123,7 @@ impl fmt::Display for MetaVarKind { /// Describes how a sequence of token trees is delimited. /// Cannot use `proc_macro::Delimiter` directly because this /// structure should implement some additional traits. -#[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)] pub enum Delimiter { /// `( ... )` Parenthesis, @@ -186,7 +186,7 @@ impl Delimiter { // type. This means that float literals like `1f32` are classified by this type // as `Int`. Only upon conversion to `ast::LitKind` will such a literal be // given the `Float` kind. -#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)] pub enum LitKind { Bool, // AST only, must never appear in a `Token` Byte, @@ -203,7 +203,7 @@ pub enum LitKind { } /// A literal token. -#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)] pub struct Lit { pub kind: LitKind, pub symbol: Symbol, @@ -349,7 +349,7 @@ fn ident_can_begin_type(name: Symbol, span: Span, is_raw: IdentIsRaw) -> bool { .contains(&name) } -#[derive(PartialEq, Encodable, Decodable, Debug, Copy, Clone, HashStable_Generic)] +#[derive(PartialEq, Eq, Encodable, Decodable, Hash, Debug, Copy, Clone, HashStable_Generic)] pub enum IdentIsRaw { No, Yes, @@ -376,7 +376,7 @@ impl From for IdentIsRaw { } } -#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)] pub enum TokenKind { /* Expression-operator symbols. */ /// `=` @@ -526,7 +526,7 @@ pub enum TokenKind { Eof, } -#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)] pub struct Token { pub kind: TokenKind, pub span: Span, diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 4111182c3b7d..e346a56bcf40 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -5,6 +5,7 @@ //! which are themselves a single [`Token`] or a `Delimited` subsequence of tokens. use std::borrow::Cow; +use std::hash::Hash; use std::ops::Range; use std::sync::Arc; use std::{cmp, fmt, iter, mem}; @@ -22,7 +23,7 @@ use crate::token::{self, Delimiter, Token, TokenKind}; use crate::{AttrVec, Attribute}; /// Part of a `TokenStream`. -#[derive(Debug, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)] pub enum TokenTree { /// A single token. Should never be `OpenDelim` or `CloseDelim`, because /// delimiters are implicitly represented by `Delimited`. @@ -538,7 +539,7 @@ pub struct AttrsTarget { /// compound token. Used for conversions to `proc_macro::Spacing`. Also used to /// guide pretty-printing, which is where the `JointHidden` value (which isn't /// part of `proc_macro::Spacing`) comes in useful. -#[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)] pub enum Spacing { /// The token cannot join with the following token to form a compound /// token. @@ -595,7 +596,7 @@ pub enum Spacing { } /// A `TokenStream` is an abstract sequence of tokens, organized into [`TokenTree`]s. -#[derive(Clone, Debug, Default, Encodable, Decodable)] +#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Encodable, Decodable)] pub struct TokenStream(pub(crate) Arc>); impl TokenStream { @@ -811,14 +812,6 @@ impl TokenStream { } } -impl PartialEq for TokenStream { - fn eq(&self, other: &TokenStream) -> bool { - self.iter().eq(other.iter()) - } -} - -impl Eq for TokenStream {} - impl FromIterator for TokenStream { fn from_iter>(iter: I) -> Self { TokenStream::new(iter.into_iter().collect::>()) @@ -970,7 +963,8 @@ impl TokenCursor { } } -#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic, Walkable)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Encodable, Decodable, HashStable_Generic, Walkable)] pub struct DelimSpan { pub open: Span, pub close: Span, @@ -994,7 +988,7 @@ impl DelimSpan { } } -#[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)] pub struct DelimSpacing { pub open: Spacing, pub close: Spacing, diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml index f897833d85c0..a18506c42afc 100644 --- a/compiler/rustc_expand/Cargo.toml +++ b/compiler/rustc_expand/Cargo.toml @@ -21,6 +21,7 @@ rustc_hir = { path = "../rustc_hir" } rustc_lexer = { path = "../rustc_lexer" } rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_macros = { path = "../rustc_macros" } +rustc_middle = { path = "../rustc_middle" } rustc_parse = { path = "../rustc_parse" } # We must use the proc_macro version that we will compile proc-macros against, # not the one from our own sysroot. @@ -28,6 +29,7 @@ rustc_proc_macro = { path = "../rustc_proc_macro" } rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } +scoped-tls = "1.0" smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec = "0.2.12" tracing = "0.1" diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 5eefa4bcdf6b..5ac7ec0cd035 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -29,4 +29,8 @@ pub mod module; #[allow(rustc::untranslatable_diagnostic)] pub mod proc_macro; +pub fn provide(providers: &mut rustc_middle::query::Providers) { + providers.derive_macro_expansion = proc_macro::provide_derive_macro_expansion; +} + rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 9bfda8764f55..5e7a272bcba4 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -1,9 +1,11 @@ use rustc_ast::tokenstream::TokenStream; use rustc_errors::ErrorGuaranteed; +use rustc_middle::ty::{self, TyCtxt}; use rustc_parse::parser::{ForceCollect, Parser}; +use rustc_session::Session; use rustc_session::config::ProcMacroExecutionStrategy; -use rustc_span::Span; use rustc_span::profiling::SpannedEventArgRecorder; +use rustc_span::{LocalExpnId, Span}; use {rustc_ast as ast, rustc_proc_macro as pm}; use crate::base::{self, *}; @@ -30,9 +32,9 @@ impl pm::bridge::server::MessagePipe for MessagePipe { } } -fn exec_strategy(ecx: &ExtCtxt<'_>) -> impl pm::bridge::server::ExecutionStrategy + 'static { +fn exec_strategy(sess: &Session) -> impl pm::bridge::server::ExecutionStrategy + 'static { pm::bridge::server::MaybeCrossThread::>::new( - ecx.sess.opts.unstable_opts.proc_macro_execution_strategy + sess.opts.unstable_opts.proc_macro_execution_strategy == ProcMacroExecutionStrategy::CrossThread, ) } @@ -54,7 +56,7 @@ impl base::BangProcMacro for BangProcMacro { }); let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace; - let strategy = exec_strategy(ecx); + let strategy = exec_strategy(ecx.sess); let server = proc_macro_server::Rustc::new(ecx); self.client.run(&strategy, server, input, proc_macro_backtrace).map_err(|e| { ecx.dcx().emit_err(errors::ProcMacroPanicked { @@ -85,7 +87,7 @@ impl base::AttrProcMacro for AttrProcMacro { }); let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace; - let strategy = exec_strategy(ecx); + let strategy = exec_strategy(ecx.sess); let server = proc_macro_server::Rustc::new(ecx); self.client.run(&strategy, server, annotation, annotated, proc_macro_backtrace).map_err( |e| { @@ -101,7 +103,7 @@ impl base::AttrProcMacro for AttrProcMacro { } pub struct DeriveProcMacro { - pub client: pm::bridge::client::Client, + pub client: DeriveClient, } impl MultiItemModifier for DeriveProcMacro { @@ -113,6 +115,13 @@ impl MultiItemModifier for DeriveProcMacro { item: Annotatable, _is_derive_const: bool, ) -> ExpandResult, Annotatable> { + let _timer = ecx.sess.prof.generic_activity_with_arg_recorder( + "expand_derive_proc_macro_outer", + |recorder| { + recorder.record_arg_with_span(ecx.sess.source_map(), ecx.expansion_descr(), span); + }, + ); + // We need special handling for statement items // (e.g. `fn foo() { #[derive(Debug)] struct Bar; }`) let is_stmt = matches!(item, Annotatable::Stmt(..)); @@ -123,36 +132,31 @@ impl MultiItemModifier for DeriveProcMacro { // altogether. See #73345. crate::base::ann_pretty_printing_compatibility_hack(&item, &ecx.sess.psess); let input = item.to_tokens(); - let stream = { - let _timer = - ecx.sess.prof.generic_activity_with_arg_recorder("expand_proc_macro", |recorder| { - recorder.record_arg_with_span( - ecx.sess.source_map(), - ecx.expansion_descr(), - span, - ); - }); - let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace; - let strategy = exec_strategy(ecx); - let server = proc_macro_server::Rustc::new(ecx); - match self.client.run(&strategy, server, input, proc_macro_backtrace) { - Ok(stream) => stream, - Err(e) => { - ecx.dcx().emit_err({ - errors::ProcMacroDerivePanicked { - span, - message: e.as_str().map(|message| { - errors::ProcMacroDerivePanickedHelp { message: message.into() } - }), - } - }); - return ExpandResult::Ready(vec![]); - } - } + + let invoc_id = ecx.current_expansion.id; + + let res = if ecx.sess.opts.incremental.is_some() + && ecx.sess.opts.unstable_opts.cache_proc_macros + { + ty::tls::with(|tcx| { + let input = &*tcx.arena.alloc(input); + let key: (LocalExpnId, &TokenStream) = (invoc_id, input); + + QueryDeriveExpandCtx::enter(ecx, self.client, move || { + tcx.derive_macro_expansion(key).cloned() + }) + }) + } else { + expand_derive_macro(invoc_id, input, ecx, self.client) + }; + + let Ok(output) = res else { + // error will already have been emitted + return ExpandResult::Ready(vec![]); }; let error_count_before = ecx.dcx().err_count(); - let mut parser = Parser::new(&ecx.sess.psess, stream, Some("proc-macro derive")); + let mut parser = Parser::new(&ecx.sess.psess, output, Some("proc-macro derive")); let mut items = vec![]; loop { @@ -180,3 +184,101 @@ impl MultiItemModifier for DeriveProcMacro { ExpandResult::Ready(items) } } + +/// Provide a query for computing the output of a derive macro. +pub(super) fn provide_derive_macro_expansion<'tcx>( + tcx: TyCtxt<'tcx>, + key: (LocalExpnId, &'tcx TokenStream), +) -> Result<&'tcx TokenStream, ()> { + let (invoc_id, input) = key; + + // Make sure that we invalidate the query when the crate defining the proc macro changes + let _ = tcx.crate_hash(invoc_id.expn_data().macro_def_id.unwrap().krate); + + QueryDeriveExpandCtx::with(|ecx, client| { + expand_derive_macro(invoc_id, input.clone(), ecx, client).map(|ts| &*tcx.arena.alloc(ts)) + }) +} + +type DeriveClient = pm::bridge::client::Client; + +fn expand_derive_macro( + invoc_id: LocalExpnId, + input: TokenStream, + ecx: &mut ExtCtxt<'_>, + client: DeriveClient, +) -> Result { + let _timer = + ecx.sess.prof.generic_activity_with_arg_recorder("expand_proc_macro", |recorder| { + let invoc_expn_data = invoc_id.expn_data(); + let span = invoc_expn_data.call_site; + let event_arg = invoc_expn_data.kind.descr(); + recorder.record_arg_with_span(ecx.sess.source_map(), event_arg.clone(), span); + }); + + let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace; + let strategy = exec_strategy(ecx.sess); + let server = proc_macro_server::Rustc::new(ecx); + + match client.run(&strategy, server, input, proc_macro_backtrace) { + Ok(stream) => Ok(stream), + Err(e) => { + let invoc_expn_data = invoc_id.expn_data(); + let span = invoc_expn_data.call_site; + ecx.dcx().emit_err({ + errors::ProcMacroDerivePanicked { + span, + message: e.as_str().map(|message| errors::ProcMacroDerivePanickedHelp { + message: message.into(), + }), + } + }); + Err(()) + } + } +} + +/// Stores the context necessary to expand a derive proc macro via a query. +struct QueryDeriveExpandCtx { + /// Type-erased version of `&mut ExtCtxt` + expansion_ctx: *mut (), + client: DeriveClient, +} + +impl QueryDeriveExpandCtx { + /// Store the extension context and the client into the thread local value. + /// It will be accessible via the `with` method while `f` is active. + fn enter(ecx: &mut ExtCtxt<'_>, client: DeriveClient, f: F) -> R + where + F: FnOnce() -> R, + { + // We need erasure to get rid of the lifetime + let ctx = Self { expansion_ctx: ecx as *mut _ as *mut (), client }; + DERIVE_EXPAND_CTX.set(&ctx, || f()) + } + + /// Accesses the thread local value of the derive expansion context. + /// Must be called while the `enter` function is active. + fn with(f: F) -> R + where + F: for<'a, 'b> FnOnce(&'b mut ExtCtxt<'a>, DeriveClient) -> R, + { + DERIVE_EXPAND_CTX.with(|ctx| { + let ectx = { + let casted = ctx.expansion_ctx.cast::>(); + // SAFETY: We can only get the value from `with` while the `enter` function + // is active (on the callstack), and that function's signature ensures that the + // lifetime is valid. + // If `with` is called at some other time, it will panic due to usage of + // `scoped_tls::with`. + unsafe { casted.as_mut().unwrap() } + }; + + f(ectx, ctx.client) + }) + } +} + +// When we invoke a query to expand a derive proc macro, we need to provide it with the expansion +// context and derive Client. We do that using a thread-local. +scoped_tls::scoped_thread_local!(static DERIVE_EXPAND_CTX: QueryDeriveExpandCtx); diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index 64166255fa48..71fb18895246 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -26,7 +26,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::{ Attribute, ImplItemKind, ItemKind as HirItem, Node as HirNode, TraitItemKind, intravisit, }; -use rustc_middle::dep_graph::{DepNode, DepNodeExt, label_strs}; +use rustc_middle::dep_graph::{DepNode, DepNodeExt, dep_kind_from_label, label_strs}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_span::{Span, Symbol, sym}; @@ -357,17 +357,6 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { } } - fn assert_loaded_from_disk(&self, item_span: Span, dep_node: DepNode) { - debug!("assert_loaded_from_disk({:?})", dep_node); - - if !self.tcx.dep_graph.debug_was_loaded_from_disk(dep_node) { - let dep_node_str = self.dep_node_str(&dep_node); - self.tcx - .dcx() - .emit_err(errors::NotLoaded { span: item_span, dep_node_str: &dep_node_str }); - } - } - fn check_item(&mut self, item_id: LocalDefId) { let item_span = self.tcx.def_span(item_id.to_def_id()); let def_path_hash = self.tcx.def_path_hash(item_id.to_def_id()); @@ -385,8 +374,27 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { self.assert_dirty(item_span, dep_node); } for label in assertion.loaded_from_disk.items().into_sorted_stable_ord() { - let dep_node = DepNode::from_label_string(self.tcx, label, def_path_hash).unwrap(); - self.assert_loaded_from_disk(item_span, dep_node); + match DepNode::from_label_string(self.tcx, label, def_path_hash) { + Ok(dep_node) => { + if !self.tcx.dep_graph.debug_was_loaded_from_disk(dep_node) { + let dep_node_str = self.dep_node_str(&dep_node); + self.tcx.dcx().emit_err(errors::NotLoaded { + span: item_span, + dep_node_str: &dep_node_str, + }); + } + } + // Opaque/unit hash, we only know the dep kind + Err(()) => { + let dep_kind = dep_kind_from_label(label); + if !self.tcx.dep_graph.debug_dep_kind_was_loaded_from_disk(dep_kind) { + self.tcx.dcx().emit_err(errors::NotLoaded { + span: item_span, + dep_node_str: &label, + }); + } + } + } } } } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 35ab202d4c27..12a6a616d64f 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -889,6 +889,7 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock = LazyLock::new(|| { providers.queries.env_var_os = env_var_os; limits::provide(&mut providers.queries); proc_macro_decls::provide(&mut providers.queries); + rustc_expand::provide(&mut providers.queries); rustc_const_eval::provide(providers); rustc_middle::hir::provide(&mut providers.queries); rustc_borrowck::provide(&mut providers.queries); diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 4fa39eb83e9e..0bdc1bfd45ee 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -119,6 +119,7 @@ macro_rules! arena_types { [decode] specialization_graph: rustc_middle::traits::specialization_graph::Graph, [] crate_inherent_impls: rustc_middle::ty::CrateInherentImpls, [] hir_owner_nodes: rustc_hir::OwnerNodes<'tcx>, + [decode] token_stream: rustc_ast::tokenstream::TokenStream, ]); ) } diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 0c757a390ca0..3ee1db67911f 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -176,6 +176,12 @@ impl DepNodeExt for DepNode { } } +/// Maps a query label to its DepKind. Panics if a query with the given label does not exist. +pub fn dep_kind_from_label(label: &str) -> DepKind { + dep_kind_from_label_string(label) + .unwrap_or_else(|_| panic!("Query label {label} does not exist")) +} + impl<'tcx> DepNodeParams> for () { #[inline(always)] fn fingerprint_style() -> FingerprintStyle { diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index 781e3e442e64..b24ea4acc6b7 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -8,7 +8,7 @@ use crate::ty::{self, TyCtxt}; #[macro_use] mod dep_node; -pub use dep_node::{DepKind, DepNode, DepNodeExt, dep_kinds, label_strs}; +pub use dep_node::{DepKind, DepNode, DepNodeExt, dep_kind_from_label, dep_kinds, label_strs}; pub(crate) use dep_node::{make_compile_codegen_unit, make_compile_mono_item, make_metadata}; pub use rustc_query_system::dep_graph::debug::{DepNodeFilter, EdgeFilter}; pub use rustc_query_system::dep_graph::{ diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 711a597d4603..940cc30c17e6 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -2,6 +2,7 @@ use std::ffi::OsStr; use std::intrinsics::transmute_unchecked; use std::mem::MaybeUninit; +use rustc_ast::tokenstream::TokenStream; use rustc_span::ErrorGuaranteed; use rustc_span::source_map::Spanned; @@ -188,6 +189,10 @@ impl EraseType >()]; } +impl EraseType for Result<&'_ TokenStream, ()> { + type Result = [u8; size_of::>()]; +} + impl EraseType for Option<&'_ T> { type Result = [u8; size_of::>()]; } diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 4d914c42cfc6..dd9ba4325545 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -2,11 +2,12 @@ use std::ffi::OsStr; +use rustc_ast::tokenstream::TokenStream; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalModDefId, ModDefId}; use rustc_hir::hir_id::{HirId, OwnerId}; use rustc_query_system::dep_graph::DepNodeIndex; use rustc_query_system::query::{DefIdCache, DefaultCache, SingleCache, VecCache}; -use rustc_span::{DUMMY_SP, Ident, Span, Symbol}; +use rustc_span::{DUMMY_SP, Ident, LocalExpnId, Span, Symbol}; use crate::infer::canonical::CanonicalQueryInput; use crate::mir::mono::CollectionMode; @@ -616,6 +617,19 @@ impl Key for (LocalDefId, HirId) { } } +impl<'tcx> Key for (LocalExpnId, &'tcx TokenStream) { + type Cache = DefaultCache; + + fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { + self.0.expn_data().call_site + } + + #[inline(always)] + fn key_as_def_id(&self) -> Option { + None + } +} + impl<'tcx> Key for (ValidityRequirement, ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) { type Cache = DefaultCache; diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 5f40c36423b3..9335afe760ae 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -70,6 +70,7 @@ use std::sync::Arc; use rustc_abi::Align; use rustc_arena::TypedArena; use rustc_ast::expand::allocator::AllocatorKind; +use rustc_ast::tokenstream::TokenStream; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::steal::Steal; @@ -96,7 +97,7 @@ use rustc_session::cstore::{ use rustc_session::lint::LintExpectationId; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::source_map::Spanned; -use rustc_span::{DUMMY_SP, Span, Symbol}; +use rustc_span::{DUMMY_SP, LocalExpnId, Span, Symbol}; use rustc_target::spec::PanicStrategy; use {rustc_abi as abi, rustc_ast as ast, rustc_hir as hir}; @@ -163,6 +164,17 @@ pub mod plumbing; // Queries marked with `fatal_cycle` do not need the latter implementation, // as they will raise an fatal error on query cycles instead. rustc_queries! { + /// Caches the expansion of a derive proc macro, e.g. `#[derive(Serialize)]`. + /// The key is: + /// - A unique key corresponding to the invocation of a macro. + /// - Token stream which serves as an input to the macro. + /// + /// The output is the token stream generated by the proc macro. + query derive_macro_expansion(key: (LocalExpnId, &'tcx TokenStream)) -> Result<&'tcx TokenStream, ()> { + desc { "expanding a derive (proc) macro" } + cache_on_disk_if { true } + } + /// This exists purely for testing the interactions between delayed bugs and incremental. query trigger_delayed_bug(key: DefId) { desc { "triggering a delayed bug for testing incremental" } diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 29cceb708850..5ef0c2500e7a 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -785,6 +785,13 @@ impl<'a, 'tcx> Decodable> } } +impl<'a, 'tcx> Decodable> for &'tcx rustc_ast::tokenstream::TokenStream { + #[inline] + fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { + RefDecodable::decode(d) + } +} + macro_rules! impl_ref_decoder { (<$tcx:tt> $($ty:ty,)*) => { $(impl<'a, $tcx> Decodable> for &$tcx [$ty] { diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 8634274c3a75..0b50d376b552 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -795,6 +795,18 @@ impl DepGraph { self.data.as_ref().unwrap().debug_loaded_from_disk.lock().contains(&dep_node) } + pub fn debug_dep_kind_was_loaded_from_disk(&self, dep_kind: DepKind) -> bool { + // We only check if we have a dep node corresponding to the given dep kind. + #[allow(rustc::potential_query_instability)] + self.data + .as_ref() + .unwrap() + .debug_loaded_from_disk + .lock() + .iter() + .any(|node| node.kind == dep_kind) + } + #[cfg(debug_assertions)] #[inline(always)] pub(crate) fn register_dep_node_debug_str(&self, dep_node: DepNode, debug_str_gen: F) diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 99ab13403812..96bdcf8beffb 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2278,6 +2278,8 @@ options! { "set options for branch target identification and pointer authentication on AArch64"), build_sdylib_interface: bool = (false, parse_bool, [UNTRACKED], "whether the stable interface is being built"), + cache_proc_macros: bool = (false, parse_bool, [TRACKED], + "cache the results of derive proc macro invocations (potentially unsound!) (default: no"), cf_protection: CFProtection = (CFProtection::None, parse_cfprotection, [TRACKED], "instrument control-flow architecture protection"), check_cfg_all_expected: bool = (false, parse_bool, [UNTRACKED], diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 51da538de94d..d94d82835d65 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -1571,3 +1571,9 @@ impl HashStable for ExpnId { hash.hash_stable(ctx, hasher); } } + +impl HashStable for LocalExpnId { + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { + self.to_expn_id().hash_stable(hcx, hasher); + } +} diff --git a/tests/incremental/derive_macro_expansion/auxiliary/derive_nothing.rs b/tests/incremental/derive_macro_expansion/auxiliary/derive_nothing.rs new file mode 100644 index 000000000000..24957b052856 --- /dev/null +++ b/tests/incremental/derive_macro_expansion/auxiliary/derive_nothing.rs @@ -0,0 +1,15 @@ +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_derive(Nothing)] +pub fn derive(_input: TokenStream) -> TokenStream { + return r#" + pub mod nothing_mod { + pub fn nothing() { + eprintln!("nothing"); + } + } + "# + .parse() + .unwrap(); +} diff --git a/tests/incremental/derive_macro_expansion/proc_macro_unchanged.rs b/tests/incremental/derive_macro_expansion/proc_macro_unchanged.rs new file mode 100644 index 000000000000..64364e31bc45 --- /dev/null +++ b/tests/incremental/derive_macro_expansion/proc_macro_unchanged.rs @@ -0,0 +1,18 @@ +// This test tests that derive proc macro execution is cached. + +//@ proc-macro:derive_nothing.rs +//@ revisions:rpass1 rpass2 +//@ compile-flags: -Zquery-dep-graph -Zcache-proc-macros +//@ ignore-backends: gcc + +#![feature(rustc_attrs)] + +#[macro_use] +extern crate derive_nothing; + +#[cfg(any(rpass1, rpass2))] +#[rustc_clean(cfg = "rpass2", loaded_from_disk = "derive_macro_expansion")] +#[derive(Nothing)] +pub struct Foo; + +fn main() {} From 48bcaf7ed1795ceb8b1e4ad4822e7e85e2cb5de5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 16 Jan 2026 18:34:46 +1100 Subject: [PATCH 0763/1061] Revert the `QueryStackFrameExtra`/`QueryStackDeferred` split. PR #138672 introduced a complex and invasive split of `QueryStackFrame` to avoid a query cycle. This commit reverts that change because there is a much simpler change that fixes the problem, which will be in the next commit. --- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/query/plumbing.rs | 2 +- compiler/rustc_middle/src/values.rs | 4 +- compiler/rustc_query_impl/src/lib.rs | 11 +- compiler/rustc_query_impl/src/plumbing.rs | 86 ++++-------- .../rustc_query_system/src/query/config.rs | 5 +- compiler/rustc_query_system/src/query/job.rs | 131 ++++++++---------- compiler/rustc_query_system/src/query/mod.rs | 129 ++++------------- .../rustc_query_system/src/query/plumbing.rs | 61 ++++---- 9 files changed, 145 insertions(+), 286 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index fc1bf78c82f3..285097832ba9 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -87,7 +87,7 @@ use rustc_index::IndexVec; use rustc_lint_defs::LintId; use rustc_macros::rustc_queries; use rustc_query_system::ich::StableHashingContext; -use rustc_query_system::query::{QueryMode, QueryStackDeferred, QueryState}; +use rustc_query_system::query::{QueryMode, QueryState}; use rustc_session::Limits; use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; use rustc_session::cstore::{ diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 25c9a0a81ab4..df333e68add1 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -431,7 +431,7 @@ macro_rules! define_callbacks { #[derive(Default)] pub struct QueryStates<'tcx> { $( - pub $name: QueryState<$($K)*, QueryStackDeferred<'tcx>>, + pub $name: QueryState<$($K)*>, )* } diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index bc73d36216ef..8d614a535498 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -88,7 +88,7 @@ impl<'tcx> Value> for Representability { if info.query.dep_kind == dep_kinds::representability && let Some(field_id) = info.query.def_id && let Some(field_id) = field_id.as_local() - && let Some(DefKind::Field) = info.query.info.def_kind + && let Some(DefKind::Field) = info.query.def_kind { let parent_id = tcx.parent(field_id.to_def_id()); let item_id = match tcx.def_kind(parent_id) { @@ -224,7 +224,7 @@ impl<'tcx, T> Value> for Result> continue; }; let frame_span = - frame.query.info.default_span(cycle[(i + 1) % cycle.len()].span); + frame.query.default_span(cycle[(i + 1) % cycle.len()].span); if frame_span.is_dummy() { continue; } diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 6904af771f0c..f763b707aa23 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -21,8 +21,8 @@ use rustc_middle::ty::TyCtxt; use rustc_query_system::dep_graph::SerializedDepNodeIndex; use rustc_query_system::ich::StableHashingContext; use rustc_query_system::query::{ - CycleError, HashResult, QueryCache, QueryConfig, QueryMap, QueryMode, QueryStackDeferred, - QueryState, get_query_incr, get_query_non_incr, + CycleError, HashResult, QueryCache, QueryConfig, QueryMap, QueryMode, QueryState, + get_query_incr, get_query_non_incr, }; use rustc_query_system::{HandleCycleError, Value}; use rustc_span::{ErrorGuaranteed, Span}; @@ -79,10 +79,7 @@ where } #[inline(always)] - fn query_state<'a>( - self, - qcx: QueryCtxt<'tcx>, - ) -> &'a QueryState> + fn query_state<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a QueryState where QueryCtxt<'tcx>: 'a, { @@ -91,7 +88,7 @@ where unsafe { &*(&qcx.tcx.query_system.states as *const QueryStates<'tcx>) .byte_add(self.dynamic.query_state) - .cast::>>() + .cast::>() } } diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index c98affe0cb19..ba1a358d2415 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -6,7 +6,6 @@ use std::num::NonZero; use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_data_structures::unord::UnordMap; use rustc_hashes::Hash64; use rustc_hir::limit::Limit; @@ -27,8 +26,8 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_query_system::dep_graph::{DepNodeParams, HasDepContext}; use rustc_query_system::ich::StableHashingContext; use rustc_query_system::query::{ - QueryCache, QueryConfig, QueryContext, QueryJobId, QueryMap, QuerySideEffect, - QueryStackDeferred, QueryStackFrame, QueryStackFrameExtra, force_query, + QueryCache, QueryConfig, QueryContext, QueryJobId, QueryMap, QuerySideEffect, QueryStackFrame, + force_query, }; use rustc_query_system::{QueryOverflow, QueryOverflowNote}; use rustc_serialize::{Decodable, Encodable}; @@ -67,9 +66,7 @@ impl<'tcx> HasDepContext for QueryCtxt<'tcx> { } } -impl<'tcx> QueryContext for QueryCtxt<'tcx> { - type QueryInfo = QueryStackDeferred<'tcx>; - +impl QueryContext for QueryCtxt<'_> { #[inline] fn jobserver_proxy(&self) -> &Proxy { &*self.jobserver_proxy @@ -98,10 +95,7 @@ impl<'tcx> QueryContext for QueryCtxt<'tcx> { /// Prefer passing `false` to `require_complete` to avoid potential deadlocks, /// especially when called from within a deadlock handler, unless a /// complete map is needed and no deadlock is possible at this call site. - fn collect_active_jobs( - self, - require_complete: bool, - ) -> Result>, QueryMap>> { + fn collect_active_jobs(self, require_complete: bool) -> Result { let mut jobs = QueryMap::default(); let mut complete = true; @@ -114,13 +108,6 @@ impl<'tcx> QueryContext for QueryCtxt<'tcx> { if complete { Ok(jobs) } else { Err(jobs) } } - fn lift_query_info( - self, - info: &QueryStackDeferred<'tcx>, - ) -> rustc_query_system::query::QueryStackFrameExtra { - info.extract() - } - // Interactions with on_disk_cache fn load_side_effect( self, @@ -181,10 +168,7 @@ impl<'tcx> QueryContext for QueryCtxt<'tcx> { self.sess.dcx().emit_fatal(QueryOverflow { span: info.job.span, - note: QueryOverflowNote { - desc: self.lift_query_info(&info.query.info).description, - depth, - }, + note: QueryOverflowNote { desc: info.query.description, depth }, suggested_limit, crate_name: self.crate_name(LOCAL_CRATE), }); @@ -321,17 +305,16 @@ macro_rules! should_ever_cache_on_disk { }; } -fn create_query_frame_extra<'tcx, K: Key + Copy + 'tcx>( - (tcx, key, kind, name, do_describe): ( - TyCtxt<'tcx>, - K, - DepKind, - &'static str, - fn(TyCtxt<'tcx>, K) -> String, - ), -) -> QueryStackFrameExtra { - let def_id = key.key_as_def_id(); - +pub(crate) fn create_query_frame< + 'tcx, + K: Copy + Key + for<'a> HashStable>, +>( + tcx: TyCtxt<'tcx>, + do_describe: fn(TyCtxt<'tcx>, K) -> String, + key: K, + kind: DepKind, + name: &'static str, +) -> QueryStackFrame { // If reduced queries are requested, we may be printing a query stack due // to a panic. Avoid using `default_span` and `def_kind` in that case. let reduce_queries = with_reduced_queries(); @@ -343,6 +326,7 @@ fn create_query_frame_extra<'tcx, K: Key + Copy + 'tcx>( } else { description }; + let span = if kind == dep_graph::dep_kinds::def_span || reduce_queries { // The `def_span` query is used to calculate `default_span`, // so exit to avoid infinite recursion. @@ -351,41 +335,25 @@ fn create_query_frame_extra<'tcx, K: Key + Copy + 'tcx>( Some(key.default_span(tcx)) }; + let def_id = key.key_as_def_id(); + let def_kind = if kind == dep_graph::dep_kinds::def_kind || reduce_queries { // Try to avoid infinite recursion. None } else { def_id.and_then(|def_id| def_id.as_local()).map(|def_id| tcx.def_kind(def_id)) }; - QueryStackFrameExtra::new(description, span, def_kind) -} -pub(crate) fn create_query_frame< - 'tcx, - K: Copy + DynSend + DynSync + Key + for<'a> HashStable> + 'tcx, ->( - tcx: TyCtxt<'tcx>, - do_describe: fn(TyCtxt<'tcx>, K) -> String, - key: K, - kind: DepKind, - name: &'static str, -) -> QueryStackFrame> { - let def_id = key.key_as_def_id(); - - let hash = || { - tcx.with_stable_hashing_context(|mut hcx| { - let mut hasher = StableHasher::new(); - kind.as_usize().hash_stable(&mut hcx, &mut hasher); - key.hash_stable(&mut hcx, &mut hasher); - hasher.finish::() - }) - }; let def_id_for_ty_in_cycle = key.def_id_for_ty_in_cycle(); - let info = - QueryStackDeferred::new((tcx, key, kind, name, do_describe), create_query_frame_extra); + let hash = tcx.with_stable_hashing_context(|mut hcx| { + let mut hasher = StableHasher::new(); + kind.as_usize().hash_stable(&mut hcx, &mut hasher); + key.hash_stable(&mut hcx, &mut hasher); + hasher.finish::() + }); - QueryStackFrame::new(info, kind, hash, def_id, def_id_for_ty_in_cycle) + QueryStackFrame::new(description, span, def_id, def_kind, kind, def_id_for_ty_in_cycle, hash) } pub(crate) fn encode_query_results<'a, 'tcx, Q>( @@ -737,7 +705,7 @@ macro_rules! define_queries { pub(crate) fn collect_active_jobs<'tcx>( tcx: TyCtxt<'tcx>, - qmap: &mut QueryMap>, + qmap: &mut QueryMap, require_complete: bool, ) -> Option<()> { let make_query = |tcx, key| { @@ -821,7 +789,7 @@ macro_rules! define_queries { // These arrays are used for iteration and can't be indexed by `DepKind`. const COLLECT_ACTIVE_JOBS: &[ - for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap>, bool) -> Option<()> + for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap, bool) -> Option<()> ] = &[$(query_impl::$name::collect_active_jobs),*]; diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index e508eadb73b0..371b896400a5 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -6,7 +6,6 @@ use std::hash::Hash; use rustc_data_structures::fingerprint::Fingerprint; use rustc_span::ErrorGuaranteed; -use super::QueryStackFrameExtra; use crate::dep_graph::{DepKind, DepNode, DepNodeParams, SerializedDepNodeIndex}; use crate::error::HandleCycleError; use crate::ich::StableHashingContext; @@ -28,7 +27,7 @@ pub trait QueryConfig: Copy { fn format_value(self) -> fn(&Self::Value) -> String; // Don't use this method to access query results, instead use the methods on TyCtxt - fn query_state<'a>(self, tcx: Qcx) -> &'a QueryState + fn query_state<'a>(self, tcx: Qcx) -> &'a QueryState where Qcx: 'a; @@ -58,7 +57,7 @@ pub trait QueryConfig: Copy { fn value_from_cycle_error( self, tcx: Qcx::DepContext, - cycle_error: &CycleError, + cycle_error: &CycleError, guar: ErrorGuaranteed, ) -> Self::Value; diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 7d9b594d501f..4a9b6a0d557c 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -1,4 +1,3 @@ -use std::fmt::Debug; use std::hash::Hash; use std::io::Write; use std::iter; @@ -12,7 +11,6 @@ use rustc_hir::def::DefKind; use rustc_session::Session; use rustc_span::{DUMMY_SP, Span}; -use super::QueryStackFrameExtra; use crate::dep_graph::DepContext; use crate::error::CycleStack; use crate::query::plumbing::CycleError; @@ -20,54 +18,45 @@ use crate::query::{QueryContext, QueryStackFrame}; /// Represents a span and a query key. #[derive(Clone, Debug)] -pub struct QueryInfo { +pub struct QueryInfo { /// The span corresponding to the reason for which this query was required. pub span: Span, - pub query: QueryStackFrame, + pub query: QueryStackFrame, } -impl QueryInfo { - pub(crate) fn lift>( - &self, - qcx: Qcx, - ) -> QueryInfo { - QueryInfo { span: self.span, query: self.query.lift(qcx) } - } -} - -pub type QueryMap = FxHashMap>; +pub type QueryMap = FxHashMap; /// A value uniquely identifying an active query job. #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] pub struct QueryJobId(pub NonZero); impl QueryJobId { - fn query(self, map: &QueryMap) -> QueryStackFrame { + fn query(self, map: &QueryMap) -> QueryStackFrame { map.get(&self).unwrap().query.clone() } - fn span(self, map: &QueryMap) -> Span { + fn span(self, map: &QueryMap) -> Span { map.get(&self).unwrap().job.span } - fn parent(self, map: &QueryMap) -> Option { + fn parent(self, map: &QueryMap) -> Option { map.get(&self).unwrap().job.parent } - fn latch(self, map: &QueryMap) -> Option<&QueryLatch> { + fn latch(self, map: &QueryMap) -> Option<&QueryLatch> { map.get(&self).unwrap().job.latch.as_ref() } } #[derive(Clone, Debug)] -pub struct QueryJobInfo { - pub query: QueryStackFrame, - pub job: QueryJob, +pub struct QueryJobInfo { + pub query: QueryStackFrame, + pub job: QueryJob, } /// Represents an active query job. #[derive(Debug)] -pub struct QueryJob { +pub struct QueryJob { pub id: QueryJobId, /// The span corresponding to the reason for which this query was required. @@ -77,23 +66,23 @@ pub struct QueryJob { pub parent: Option, /// The latch that is used to wait on this job. - latch: Option>, + latch: Option, } -impl Clone for QueryJob { +impl Clone for QueryJob { fn clone(&self) -> Self { Self { id: self.id, span: self.span, parent: self.parent, latch: self.latch.clone() } } } -impl QueryJob { +impl QueryJob { /// Creates a new query job. #[inline] pub fn new(id: QueryJobId, span: Span, parent: Option) -> Self { QueryJob { id, span, parent, latch: None } } - pub(super) fn latch(&mut self) -> QueryLatch { + pub(super) fn latch(&mut self) -> QueryLatch { if self.latch.is_none() { self.latch = Some(QueryLatch::new()); } @@ -113,12 +102,12 @@ impl QueryJob { } impl QueryJobId { - pub(super) fn find_cycle_in_stack( + pub(super) fn find_cycle_in_stack( &self, - query_map: QueryMap, + query_map: QueryMap, current_job: &Option, span: Span, - ) -> CycleError { + ) -> CycleError { // Find the waitee amongst `current_job` parents let mut cycle = Vec::new(); let mut current_job = Option::clone(current_job); @@ -152,7 +141,7 @@ impl QueryJobId { #[cold] #[inline(never)] - pub fn find_dep_kind_root(&self, query_map: QueryMap) -> (QueryJobInfo, usize) { + pub fn find_dep_kind_root(&self, query_map: QueryMap) -> (QueryJobInfo, usize) { let mut depth = 1; let info = query_map.get(&self).unwrap(); let dep_kind = info.query.dep_kind; @@ -172,31 +161,31 @@ impl QueryJobId { } #[derive(Debug)] -struct QueryWaiter { +struct QueryWaiter { query: Option, condvar: Condvar, span: Span, - cycle: Mutex>>, + cycle: Mutex>, } #[derive(Debug)] -struct QueryLatchInfo { +struct QueryLatchInfo { complete: bool, - waiters: Vec>>, + waiters: Vec>, } #[derive(Debug)] -pub(super) struct QueryLatch { - info: Arc>>, +pub(super) struct QueryLatch { + info: Arc>, } -impl Clone for QueryLatch { +impl Clone for QueryLatch { fn clone(&self) -> Self { Self { info: Arc::clone(&self.info) } } } -impl QueryLatch { +impl QueryLatch { fn new() -> Self { QueryLatch { info: Arc::new(Mutex::new(QueryLatchInfo { complete: false, waiters: Vec::new() })), @@ -209,7 +198,7 @@ impl QueryLatch { qcx: impl QueryContext, query: Option, span: Span, - ) -> Result<(), CycleError> { + ) -> Result<(), CycleError> { let waiter = Arc::new(QueryWaiter { query, span, cycle: Mutex::new(None), condvar: Condvar::new() }); self.wait_on_inner(qcx, &waiter); @@ -224,7 +213,7 @@ impl QueryLatch { } /// Awaits the caller on this latch by blocking the current thread. - fn wait_on_inner(&self, qcx: impl QueryContext, waiter: &Arc>) { + fn wait_on_inner(&self, qcx: impl QueryContext, waiter: &Arc) { let mut info = self.info.lock(); if !info.complete { // We push the waiter on to the `waiters` list. It can be accessed inside @@ -260,7 +249,7 @@ impl QueryLatch { /// Removes a single waiter from the list of waiters. /// This is used to break query cycles. - fn extract_waiter(&self, waiter: usize) -> Arc> { + fn extract_waiter(&self, waiter: usize) -> Arc { let mut info = self.info.lock(); debug_assert!(!info.complete); // Remove the waiter from the list of waiters @@ -280,11 +269,7 @@ type Waiter = (QueryJobId, usize); /// For visits of resumable waiters it returns Some(Some(Waiter)) which has the /// required information to resume the waiter. /// If all `visit` calls returns None, this function also returns None. -fn visit_waiters( - query_map: &QueryMap, - query: QueryJobId, - mut visit: F, -) -> Option> +fn visit_waiters(query_map: &QueryMap, query: QueryJobId, mut visit: F) -> Option> where F: FnMut(Span, QueryJobId) -> Option>, { @@ -314,8 +299,8 @@ where /// `span` is the reason for the `query` to execute. This is initially DUMMY_SP. /// If a cycle is detected, this initial value is replaced with the span causing /// the cycle. -fn cycle_check( - query_map: &QueryMap, +fn cycle_check( + query_map: &QueryMap, query: QueryJobId, span: Span, stack: &mut Vec<(Span, QueryJobId)>, @@ -354,8 +339,8 @@ fn cycle_check( /// Finds out if there's a path to the compiler root (aka. code which isn't in a query) /// from `query` without going through any of the queries in `visited`. /// This is achieved with a depth first search. -fn connected_to_root( - query_map: &QueryMap, +fn connected_to_root( + query_map: &QueryMap, query: QueryJobId, visited: &mut FxHashSet, ) -> bool { @@ -376,7 +361,7 @@ fn connected_to_root( } // Deterministically pick an query from a list -fn pick_query<'a, I: Clone, T, F>(query_map: &QueryMap, queries: &'a [T], f: F) -> &'a T +fn pick_query<'a, T, F>(query_map: &QueryMap, queries: &'a [T], f: F) -> &'a T where F: Fn(&T) -> (Span, QueryJobId), { @@ -401,10 +386,10 @@ where /// the function return true. /// If a cycle was not found, the starting query is removed from `jobs` and /// the function returns false. -fn remove_cycle( - query_map: &QueryMap, +fn remove_cycle( + query_map: &QueryMap, jobs: &mut Vec, - wakelist: &mut Vec>>, + wakelist: &mut Vec>, ) -> bool { let mut visited = FxHashSet::default(); let mut stack = Vec::new(); @@ -505,10 +490,7 @@ fn remove_cycle( /// uses a query latch and then resuming that waiter. /// There may be multiple cycles involved in a deadlock, so this searches /// all active queries for cycles before finally resuming all the waiters at once. -pub fn break_query_cycles( - query_map: QueryMap, - registry: &rustc_thread_pool::Registry, -) { +pub fn break_query_cycles(query_map: QueryMap, registry: &rustc_thread_pool::Registry) { let mut wakelist = Vec::new(); // It is OK per the comments: // - https://github.com/rust-lang/rust/pull/131200#issuecomment-2798854932 @@ -559,7 +541,7 @@ pub fn report_cycle<'a>( ) -> Diag<'a> { assert!(!stack.is_empty()); - let span = stack[0].query.info.default_span(stack[1 % stack.len()].span); + let span = stack[0].query.default_span(stack[1 % stack.len()].span); let mut cycle_stack = Vec::new(); @@ -568,31 +550,31 @@ pub fn report_cycle<'a>( for i in 1..stack.len() { let query = &stack[i].query; - let span = query.info.default_span(stack[(i + 1) % stack.len()].span); - cycle_stack.push(CycleStack { span, desc: query.info.description.to_owned() }); + let span = query.default_span(stack[(i + 1) % stack.len()].span); + cycle_stack.push(CycleStack { span, desc: query.description.to_owned() }); } let mut cycle_usage = None; if let Some((span, ref query)) = *usage { cycle_usage = Some(crate::error::CycleUsage { - span: query.info.default_span(span), - usage: query.info.description.to_string(), + span: query.default_span(span), + usage: query.description.to_string(), }); } - let alias = - if stack.iter().all(|entry| matches!(entry.query.info.def_kind, Some(DefKind::TyAlias))) { - Some(crate::error::Alias::Ty) - } else if stack.iter().all(|entry| entry.query.info.def_kind == Some(DefKind::TraitAlias)) { - Some(crate::error::Alias::Trait) - } else { - None - }; + let alias = if stack.iter().all(|entry| matches!(entry.query.def_kind, Some(DefKind::TyAlias))) + { + Some(crate::error::Alias::Ty) + } else if stack.iter().all(|entry| entry.query.def_kind == Some(DefKind::TraitAlias)) { + Some(crate::error::Alias::Trait) + } else { + None + }; let cycle_diag = crate::error::Cycle { span, cycle_stack, - stack_bottom: stack[0].query.info.description.to_owned(), + stack_bottom: stack[0].query.description.to_owned(), alias, cycle_usage, stack_count, @@ -628,7 +610,6 @@ pub fn print_query_stack( let Some(query_info) = query_map.get(&query) else { break; }; - let query_extra = qcx.lift_query_info(&query_info.query.info); if Some(count_printed) < limit_frames || limit_frames.is_none() { // Only print to stderr as many stack frames as `num_frames` when present. // FIXME: needs translation @@ -636,7 +617,7 @@ pub fn print_query_stack( #[allow(rustc::untranslatable_diagnostic)] dcx.struct_failure_note(format!( "#{} [{:?}] {}", - count_printed, query_info.query.dep_kind, query_extra.description + count_printed, query_info.query.dep_kind, query_info.query.description )) .with_span(query_info.job.span) .emit(); @@ -649,7 +630,7 @@ pub fn print_query_stack( "#{} [{}] {}", count_total, qcx.dep_context().dep_kind_info(query_info.query.dep_kind).name, - query_extra.description + query_info.query.description ); } diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index ce3456d532e6..b524756d81b6 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -1,23 +1,4 @@ -mod plumbing; -use std::fmt::Debug; -use std::marker::PhantomData; -use std::mem::transmute; -use std::sync::Arc; - -pub use self::plumbing::*; - -mod job; -pub use self::job::{ - QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryMap, break_query_cycles, print_query_stack, - report_cycle, -}; - -mod caches; -pub use self::caches::{DefIdCache, DefaultCache, QueryCache, SingleCache, VecCache}; - -mod config; use rustc_data_structures::jobserver::Proxy; -use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_errors::DiagInner; use rustc_hashes::Hash64; use rustc_hir::def::DefKind; @@ -25,66 +6,49 @@ use rustc_macros::{Decodable, Encodable}; use rustc_span::Span; use rustc_span::def_id::DefId; +pub use self::caches::{DefIdCache, DefaultCache, QueryCache, SingleCache, VecCache}; pub use self::config::{HashResult, QueryConfig}; +pub use self::job::{ + QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryMap, break_query_cycles, print_query_stack, + report_cycle, +}; +pub use self::plumbing::*; use crate::dep_graph::{DepKind, DepNodeIndex, HasDepContext, SerializedDepNodeIndex}; +mod caches; +mod config; +mod job; +mod plumbing; + /// Description of a frame in the query stack. /// /// This is mostly used in case of cycles for error reporting. #[derive(Clone, Debug)] -pub struct QueryStackFrame { - /// This field initially stores a `QueryStackDeferred` during collection, - /// but can later be changed to `QueryStackFrameExtra` containing concrete information - /// by calling `lift`. This is done so that collecting query does not need to invoke - /// queries, instead `lift` will call queries in a more appropriate location. - pub info: I, - +pub struct QueryStackFrame { + pub description: String, + span: Option, + pub def_id: Option, + pub def_kind: Option, + /// A def-id that is extracted from a `Ty` in a query key + pub def_id_for_ty_in_cycle: Option, pub dep_kind: DepKind, /// This hash is used to deterministically pick /// a query to remove cycles in the parallel compiler. hash: Hash64, - pub def_id: Option, - /// A def-id that is extracted from a `Ty` in a query key - pub def_id_for_ty_in_cycle: Option, } -impl QueryStackFrame { +impl QueryStackFrame { #[inline] pub fn new( - info: I, - dep_kind: DepKind, - hash: impl FnOnce() -> Hash64, + description: String, + span: Option, def_id: Option, + def_kind: Option, + dep_kind: DepKind, def_id_for_ty_in_cycle: Option, + hash: Hash64, ) -> Self { - Self { info, def_id, dep_kind, hash: hash(), def_id_for_ty_in_cycle } - } - - fn lift>( - &self, - qcx: Qcx, - ) -> QueryStackFrame { - QueryStackFrame { - info: qcx.lift_query_info(&self.info), - dep_kind: self.dep_kind, - hash: self.hash, - def_id: self.def_id, - def_id_for_ty_in_cycle: self.def_id_for_ty_in_cycle, - } - } -} - -#[derive(Clone, Debug)] -pub struct QueryStackFrameExtra { - pub description: String, - span: Option, - pub def_kind: Option, -} - -impl QueryStackFrameExtra { - #[inline] - pub fn new(description: String, span: Option, def_kind: Option) -> Self { - Self { description, span, def_kind } + Self { description, span, def_id, def_kind, def_id_for_ty_in_cycle, dep_kind, hash } } // FIXME(eddyb) Get more valid `Span`s on queries. @@ -97,40 +61,6 @@ impl QueryStackFrameExtra { } } -/// Track a 'side effect' for a particular query. -/// This is used to hold a closure which can create `QueryStackFrameExtra`. -#[derive(Clone)] -pub struct QueryStackDeferred<'tcx> { - _dummy: PhantomData<&'tcx ()>, - - // `extract` may contain references to 'tcx, but we can't tell drop checking that it won't - // access it in the destructor. - extract: Arc QueryStackFrameExtra + DynSync + DynSend>, -} - -impl<'tcx> QueryStackDeferred<'tcx> { - pub fn new( - context: C, - extract: fn(C) -> QueryStackFrameExtra, - ) -> Self { - let extract: Arc QueryStackFrameExtra + DynSync + DynSend + 'tcx> = - Arc::new(move || extract(context)); - // SAFETY: The `extract` closure does not access 'tcx in its destructor as the only - // captured variable is `context` which is Copy and cannot have a destructor. - Self { _dummy: PhantomData, extract: unsafe { transmute(extract) } } - } - - pub fn extract(&self) -> QueryStackFrameExtra { - (self.extract)() - } -} - -impl<'tcx> Debug for QueryStackDeferred<'tcx> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str("QueryStackDeferred") - } -} - /// Tracks 'side effects' for a particular query. /// This struct is saved to disk along with the query result, /// and loaded from disk if we mark the query as green. @@ -150,8 +80,6 @@ pub enum QuerySideEffect { } pub trait QueryContext: HasDepContext { - type QueryInfo: Clone; - /// Gets a jobserver reference which is used to release then acquire /// a token while waiting on a query. fn jobserver_proxy(&self) -> &Proxy; @@ -161,12 +89,7 @@ pub trait QueryContext: HasDepContext { /// Get the query information from the TLS context. fn current_query_job(self) -> Option; - fn collect_active_jobs( - self, - require_complete: bool, - ) -> Result, QueryMap>; - - fn lift_query_info(self, info: &Self::QueryInfo) -> QueryStackFrameExtra; + fn collect_active_jobs(self, require_complete: bool) -> Result; /// Load a side effect associated to the node in the previous session. fn load_side_effect( diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index dea47c8fa787..fa5a94d65188 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -18,7 +18,7 @@ use rustc_errors::{Diag, FatalError, StashKey}; use rustc_span::{DUMMY_SP, Span}; use tracing::instrument; -use super::{QueryConfig, QueryStackFrameExtra}; +use super::QueryConfig; use crate::HandleCycleError; use crate::dep_graph::{DepContext, DepGraphData, DepNode, DepNodeIndex, DepNodeParams}; use crate::ich::StableHashingContext; @@ -31,23 +31,23 @@ fn equivalent_key(k: &K) -> impl Fn(&(K, V)) -> bool + '_ { move |x| x.0 == *k } -pub struct QueryState { - active: Sharded)>>, +pub struct QueryState { + active: Sharded>, } /// Indicates the state of a query for a given key in a query map. -enum QueryResult { +enum QueryResult { /// An already executing query. The query job can be used to await for its completion. - Started(QueryJob), + Started(QueryJob), /// The query panicked. Queries trying to wait on this will raise a fatal error which will /// silently panic. Poisoned, } -impl QueryResult { +impl QueryResult { /// Unwraps the query job expecting that it has started. - fn expect_job(self) -> QueryJob { + fn expect_job(self) -> QueryJob { match self { Self::Started(job) => job, Self::Poisoned => { @@ -57,7 +57,7 @@ impl QueryResult { } } -impl QueryState +impl QueryState where K: Eq + Hash + Copy + Debug, { @@ -68,13 +68,13 @@ where pub fn collect_active_jobs( &self, qcx: Qcx, - make_query: fn(Qcx, K) -> QueryStackFrame, - jobs: &mut QueryMap, + make_query: fn(Qcx, K) -> QueryStackFrame, + jobs: &mut QueryMap, require_complete: bool, ) -> Option<()> { let mut active = Vec::new(); - let mut collect = |iter: LockGuard<'_, HashTable<(K, QueryResult)>>| { + let mut collect = |iter: LockGuard<'_, HashTable<(K, QueryResult)>>| { for (k, v) in iter.iter() { if let QueryResult::Started(ref job) = *v { active.push((*k, job.clone())); @@ -105,19 +105,19 @@ where } } -impl Default for QueryState { - fn default() -> QueryState { +impl Default for QueryState { + fn default() -> QueryState { QueryState { active: Default::default() } } } /// A type representing the responsibility to execute the job in the `job` field. /// This will poison the relevant query if dropped. -struct JobOwner<'tcx, K, I> +struct JobOwner<'tcx, K> where K: Eq + Hash + Copy, { - state: &'tcx QueryState, + state: &'tcx QueryState, key: K, } @@ -159,7 +159,7 @@ where } Stash => { let guar = if let Some(root) = cycle_error.cycle.first() - && let Some(span) = root.query.info.span + && let Some(span) = root.query.span { error.stash(span, StashKey::Cycle).unwrap() } else { @@ -170,7 +170,7 @@ where } } -impl<'tcx, K, I> JobOwner<'tcx, K, I> +impl<'tcx, K> JobOwner<'tcx, K> where K: Eq + Hash + Copy, { @@ -207,7 +207,7 @@ where } } -impl<'tcx, K, I> Drop for JobOwner<'tcx, K, I> +impl<'tcx, K> Drop for JobOwner<'tcx, K> where K: Eq + Hash + Copy, { @@ -235,19 +235,10 @@ where } #[derive(Clone, Debug)] -pub struct CycleError { +pub struct CycleError { /// The query and related span that uses the cycle. - pub usage: Option<(Span, QueryStackFrame)>, - pub cycle: Vec>, -} - -impl CycleError { - fn lift>(&self, qcx: Qcx) -> CycleError { - CycleError { - usage: self.usage.as_ref().map(|(span, frame)| (*span, frame.lift(qcx))), - cycle: self.cycle.iter().map(|info| info.lift(qcx)).collect(), - } - } + pub usage: Option<(Span, QueryStackFrame)>, + pub cycle: Vec, } /// Checks whether there is already a value for this key in the in-memory @@ -284,10 +275,10 @@ where { // Ensure there was no errors collecting all active jobs. // We need the complete map to ensure we find a cycle to break. - let query_map = qcx.collect_active_jobs(false).ok().expect("failed to collect active queries"); + let query_map = qcx.collect_active_jobs(false).expect("failed to collect active queries"); let error = try_execute.find_cycle_in_stack(query_map, &qcx.current_query_job(), span); - (mk_cycle(query, qcx, error.lift(qcx)), None) + (mk_cycle(query, qcx, error), None) } #[inline(always)] @@ -296,7 +287,7 @@ fn wait_for_query( qcx: Qcx, span: Span, key: Q::Key, - latch: QueryLatch, + latch: QueryLatch, current: Option, ) -> (Q::Value, Option) where @@ -336,7 +327,7 @@ where (v, Some(index)) } - Err(cycle) => (mk_cycle(query, qcx, cycle.lift(qcx)), None), + Err(cycle) => (mk_cycle(query, qcx, cycle), None), } } @@ -414,7 +405,7 @@ where fn execute_job( query: Q, qcx: Qcx, - state: &QueryState, + state: &QueryState, key: Q::Key, key_hash: u64, id: QueryJobId, From 90e4a421623ed4e9f8e1985795456f734ec822a1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 16 Jan 2026 19:18:16 +1100 Subject: [PATCH 0764/1061] Use `with_reduced_queries` to avoid query cycles. This changes the error message of `query-cycle-issue-124901.rs`, which doesn't matter much. --- compiler/rustc_query_impl/src/plumbing.rs | 10 ++++++---- tests/ui/resolve/query-cycle-issue-124901.rs | 2 +- tests/ui/resolve/query-cycle-issue-124901.stderr | 9 ++++++--- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index ba1a358d2415..67ab1114af62 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -327,21 +327,23 @@ pub(crate) fn create_query_frame< description }; - let span = if kind == dep_graph::dep_kinds::def_span || reduce_queries { + let span = if reduce_queries { // The `def_span` query is used to calculate `default_span`, // so exit to avoid infinite recursion. None } else { - Some(key.default_span(tcx)) + Some(tcx.with_reduced_queries(|| key.default_span(tcx))) }; let def_id = key.key_as_def_id(); - let def_kind = if kind == dep_graph::dep_kinds::def_kind || reduce_queries { + let def_kind = if reduce_queries { // Try to avoid infinite recursion. None } else { - def_id.and_then(|def_id| def_id.as_local()).map(|def_id| tcx.def_kind(def_id)) + def_id + .and_then(|def_id| def_id.as_local()) + .map(|def_id| tcx.with_reduced_queries(|| tcx.def_kind(def_id))) }; let def_id_for_ty_in_cycle = key.def_id_for_ty_in_cycle(); diff --git a/tests/ui/resolve/query-cycle-issue-124901.rs b/tests/ui/resolve/query-cycle-issue-124901.rs index 6cb1e58b6258..ccaee0e6bc6f 100644 --- a/tests/ui/resolve/query-cycle-issue-124901.rs +++ b/tests/ui/resolve/query-cycle-issue-124901.rs @@ -1,4 +1,4 @@ -//~ ERROR: cycle detected when looking up span for `Default` +//~ ERROR: cycle detected when getting HIR ID of `Default` trait Default { type Id; diff --git a/tests/ui/resolve/query-cycle-issue-124901.stderr b/tests/ui/resolve/query-cycle-issue-124901.stderr index 9c1d7b1de33a..3679925c6db4 100644 --- a/tests/ui/resolve/query-cycle-issue-124901.stderr +++ b/tests/ui/resolve/query-cycle-issue-124901.stderr @@ -1,7 +1,10 @@ -error[E0391]: cycle detected when looking up span for `Default` +error[E0391]: cycle detected when getting HIR ID of `Default` | - = note: ...which immediately requires looking up span for `Default` again - = note: cycle used when perform lints prior to AST lowering + = note: ...which requires getting the crate HIR... + = note: ...which requires perform lints prior to AST lowering... + = note: ...which requires looking up span for `Default`... + = note: ...which again requires getting HIR ID of `Default`, completing the cycle + = note: cycle used when getting the resolver for lowering = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: aborting due to 1 previous error From db36c093ca556bc711c167f508c54bda6d3ba5af Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 16 Jan 2026 10:21:06 +0100 Subject: [PATCH 0765/1061] remove lcnr from compiler review rotation --- triagebot.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 456fd696af43..e51622f1e5a9 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1458,7 +1458,6 @@ compiler = [ "@jieyouxu", "@jdonszelmann", "@JonathanBrouwer", - "@lcnr", "@madsmtm", "@mati865", "@Nadrieril", From f19591ad27ba306ffe0d2665790894420e0f96bc Mon Sep 17 00:00:00 2001 From: Redddy Date: Fri, 16 Jan 2026 18:39:38 +0900 Subject: [PATCH 0766/1061] Add rust-analyzer setup for out-of-tree rustc_private crates --- .../remarks-on-perma-unstable-features.md | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/rustc-driver/remarks-on-perma-unstable-features.md b/src/doc/rustc-dev-guide/src/rustc-driver/remarks-on-perma-unstable-features.md index b434cfc9cf14..3c2fe133be84 100644 --- a/src/doc/rustc-dev-guide/src/rustc-driver/remarks-on-perma-unstable-features.md +++ b/src/doc/rustc-dev-guide/src/rustc-driver/remarks-on-perma-unstable-features.md @@ -49,6 +49,29 @@ For custom-built toolchains or environments not using rustup, additional configu ``` 3. **Check version compatibility**: Ensure your LLVM version is compatible with your Rust toolchain +### Configuring `rust-analyzer` for Out-of-Tree Projects + +When developing out-of-tree projects that use `rustc_private` crates, you can configure `rust-analyzer` to recognize these crates. + +#### Configuration Steps + +1. **Set rust-analyzer configuration** + Configure `rust-analyzer.rustc.source` to `"discover"` in your editor settings. + For VS Code, add to `rust_analyzer_settings.json`: + ```json + { + "rust-analyzer.rustc.source": "discover" + } + ``` +2. **Add metadata to Cargo.toml** + Add the following to the `Cargo.toml` of every crate that uses `rustc_private`: + ```toml + [package.metadata.rust-analyzer] + rustc_private = true + ``` + +This configuration allows `rust-analyzer` to properly recognize and provide IDE support for `rustc_private` crates in out-of-tree projects. + ### Additional Resources - [GitHub Issue #137421](https://github.com/rust-lang/rust/issues/137421): Explains that `rustc_private` linker failures often occur because `llvm-tools` is not installed From 21f269e72ed90f73abbd531243d6f563d2689650 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 16 Jan 2026 10:47:01 +0100 Subject: [PATCH 0767/1061] add RPITIT cycle issue --- .../src/solve/candidate-preference.md | 41 ++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/solve/candidate-preference.md b/src/doc/rustc-dev-guide/src/solve/candidate-preference.md index 8b28f56760a7..d5a75b41ff1f 100644 --- a/src/doc/rustc-dev-guide/src/solve/candidate-preference.md +++ b/src/doc/rustc-dev-guide/src/solve/candidate-preference.md @@ -260,11 +260,13 @@ We prefer builtin trait object impls over user-written impls. This is **unsound* The candidate preference behavior during normalization is implemented in [`fn assemble_and_merge_candidates`]. -### Where-bounds shadow impls +### Trait where-bounds shadow impls Normalization of associated items does not consider impls if the corresponding trait goal has been proven via a `ParamEnv` or `AliasBound` candidate. This means that for where-bounds which do not constrain associated types, the associated types remain *rigid*. +#### Using impls results in different region constraints + This is necessary to avoid unnecessary region constraints from applying impls. ```rust trait Trait<'a> { @@ -286,6 +288,39 @@ where } ``` +#### RPITIT `type_of` cycles + +We currently have to avoid impl candidates if there are where-bounds to avoid query cycles for RPITIT, see [#139762]. It feels desirable to me to stop relying on auto-trait leakage of during RPITIT computation to remove this issue, see [#139788]. + +```rust +use std::future::Future; +pub trait ReactiveFunction: Send { + type Output; + + fn invoke(self) -> Self::Output; +} + +trait AttributeValue { + fn resolve(self) -> impl Future + Send; +} + +impl AttributeValue for F +where + F: ReactiveFunction, + V: AttributeValue, +{ + async fn resolve(self) { + // We're awaiting `::{synthetic#0}` here. + // Normalizing that one via the the impl we're currently in + // relies on `collect_return_position_impl_trait_in_trait_tys` which + // ends up relying on auto-trait leakage when checking that the + // opaque return type of this function implements the `Send` item + // bound of the trait definition. + self.invoke().resolve().await + } +} +``` + ### We always consider `AliasBound` candidates In case the where-bound does not specify the associated item, we consider `AliasBound` candidates instead of treating the alias as rigid, even though the trait goal was proven via a `ParamEnv` candidate. @@ -424,4 +459,6 @@ where [`fn assemble_and_merge_candidates`]: https://github.com/rust-lang/rust/blob/e3ee7f7aea5b45af3b42b5e4713da43876a65ac9/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs#L920-L1003 [trait-system-refactor-initiative#76]: https://github.com/rust-lang/trait-system-refactor-initiative/issues/76 [#24066]: https://github.com/rust-lang/rust/issues/24066 -[#133044]: https://github.com/rust-lang/rust/issues/133044 \ No newline at end of file +[#133044]: https://github.com/rust-lang/rust/issues/133044 +[#139762]: https://github.com/rust-lang/rust/pull/139762 +[#139788]: https://github.com/rust-lang/rust/issues/139788 \ No newline at end of file From 908ae5a86f5191bf316456dcc9257a942d8bce7f Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 16 Jan 2026 10:48:01 +0100 Subject: [PATCH 0768/1061] move section --- .../src/solve/candidate-preference.md | 121 +++++++++--------- 1 file changed, 61 insertions(+), 60 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/solve/candidate-preference.md b/src/doc/rustc-dev-guide/src/solve/candidate-preference.md index d5a75b41ff1f..461523424b3c 100644 --- a/src/doc/rustc-dev-guide/src/solve/candidate-preference.md +++ b/src/doc/rustc-dev-guide/src/solve/candidate-preference.md @@ -260,66 +260,6 @@ We prefer builtin trait object impls over user-written impls. This is **unsound* The candidate preference behavior during normalization is implemented in [`fn assemble_and_merge_candidates`]. -### Trait where-bounds shadow impls - -Normalization of associated items does not consider impls if the corresponding trait goal has been proven via a `ParamEnv` or `AliasBound` candidate. -This means that for where-bounds which do not constrain associated types, the associated types remain *rigid*. - -#### Using impls results in different region constraints - -This is necessary to avoid unnecessary region constraints from applying impls. -```rust -trait Trait<'a> { - type Assoc; -} -impl Trait<'static> for u32 { - type Assoc = u32; -} - -fn bar<'b, T: Trait<'b>>() -> T::Assoc { todo!() } -fn foo<'a>() -where - u32: Trait<'a>, -{ - // Normalizing the return type would use the impl, proving - // the `T: Trait` where-bound would use the where-bound, resulting - // in different region constraints. - bar::<'_, u32>(); -} -``` - -#### RPITIT `type_of` cycles - -We currently have to avoid impl candidates if there are where-bounds to avoid query cycles for RPITIT, see [#139762]. It feels desirable to me to stop relying on auto-trait leakage of during RPITIT computation to remove this issue, see [#139788]. - -```rust -use std::future::Future; -pub trait ReactiveFunction: Send { - type Output; - - fn invoke(self) -> Self::Output; -} - -trait AttributeValue { - fn resolve(self) -> impl Future + Send; -} - -impl AttributeValue for F -where - F: ReactiveFunction, - V: AttributeValue, -{ - async fn resolve(self) { - // We're awaiting `::{synthetic#0}` here. - // Normalizing that one via the the impl we're currently in - // relies on `collect_return_position_impl_trait_in_trait_tys` which - // ends up relying on auto-trait leakage when checking that the - // opaque return type of this function implements the `Send` item - // bound of the trait definition. - self.invoke().resolve().await - } -} -``` ### We always consider `AliasBound` candidates @@ -453,6 +393,67 @@ where } ``` +### Trait where-bounds shadow impls + +Normalization of associated items does not consider impls if the corresponding trait goal has been proven via a `ParamEnv` or `AliasBound` candidate. +This means that for where-bounds which do not constrain associated types, the associated types remain *rigid*. + +#### Using impls results in different region constraints + +This is necessary to avoid unnecessary region constraints from applying impls. +```rust +trait Trait<'a> { + type Assoc; +} +impl Trait<'static> for u32 { + type Assoc = u32; +} + +fn bar<'b, T: Trait<'b>>() -> T::Assoc { todo!() } +fn foo<'a>() +where + u32: Trait<'a>, +{ + // Normalizing the return type would use the impl, proving + // the `T: Trait` where-bound would use the where-bound, resulting + // in different region constraints. + bar::<'_, u32>(); +} +``` + +#### RPITIT `type_of` cycles + +We currently have to avoid impl candidates if there are where-bounds to avoid query cycles for RPITIT, see [#139762]. It feels desirable to me to stop relying on auto-trait leakage of during RPITIT computation to remove this issue, see [#139788]. + +```rust +use std::future::Future; +pub trait ReactiveFunction: Send { + type Output; + + fn invoke(self) -> Self::Output; +} + +trait AttributeValue { + fn resolve(self) -> impl Future + Send; +} + +impl AttributeValue for F +where + F: ReactiveFunction, + V: AttributeValue, +{ + async fn resolve(self) { + // We're awaiting `::{synthetic#0}` here. + // Normalizing that one via the the impl we're currently in + // relies on `collect_return_position_impl_trait_in_trait_tys` which + // ends up relying on auto-trait leakage when checking that the + // opaque return type of this function implements the `Send` item + // bound of the trait definition. + self.invoke().resolve().await + } +} +``` + [`Candidate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_next_trait_solver/solve/assembly/struct.Candidate.html [`CandidateSource`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_next_trait_solver/solve/enum.CandidateSource.html [`fn merge_trait_candidates`]: https://github.com/rust-lang/rust/blob/e3ee7f7aea5b45af3b42b5e4713da43876a65ac9/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs#L1342-L1424 From 9e4c55ac8d9d1083983bdc2c35a3513cddb3fc69 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 16 Jan 2026 19:26:34 +0900 Subject: [PATCH 0769/1061] Rename "remarks on perma unstable features" to "external rustc_drivers" --- src/doc/rustc-dev-guide/src/SUMMARY.md | 2 +- ...-on-perma-unstable-features.md => external-rustc-drivers.md} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/doc/rustc-dev-guide/src/rustc-driver/{remarks-on-perma-unstable-features.md => external-rustc-drivers.md} (98%) diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index 2dd07144a78c..daaaef42d909 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -140,7 +140,7 @@ - [Command-line arguments](./cli.md) - [rustc_driver and rustc_interface](./rustc-driver/intro.md) - - [Remarks on perma-unstable features](./rustc-driver/remarks-on-perma-unstable-features.md) + - [External rustc_drivers](./rustc-driver/external-rustc-drivers.md) - [Example: Type checking](./rustc-driver/interacting-with-the-ast.md) - [Example: Getting diagnostics](./rustc-driver/getting-diagnostics.md) - [Errors and lints](diagnostics.md) diff --git a/src/doc/rustc-dev-guide/src/rustc-driver/remarks-on-perma-unstable-features.md b/src/doc/rustc-dev-guide/src/rustc-driver/external-rustc-drivers.md similarity index 98% rename from src/doc/rustc-dev-guide/src/rustc-driver/remarks-on-perma-unstable-features.md rename to src/doc/rustc-dev-guide/src/rustc-driver/external-rustc-drivers.md index 3c2fe133be84..1049d7a82ddd 100644 --- a/src/doc/rustc-dev-guide/src/rustc-driver/remarks-on-perma-unstable-features.md +++ b/src/doc/rustc-dev-guide/src/rustc-driver/external-rustc-drivers.md @@ -1,4 +1,4 @@ -# Remarks on perma unstable features +# External `rustc_driver`s ## `rustc_private` From 75445635784ebf4683a6d22aa8b9563469bd0e0c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 15 Jan 2026 16:48:30 +0100 Subject: [PATCH 0770/1061] Only enable rustdoc `--generate-macro-expansion` option for stage builds higher than 1 --- src/bootstrap/src/core/build_steps/doc.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index fa36a6471cae..d8e8f65caa98 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -932,7 +932,13 @@ impl Step for Rustc { // see https://github.com/rust-lang/rust/pull/122066#issuecomment-1983049222 // If there is any bug, please comment out the next line. cargo.rustdocflag("--generate-link-to-definition"); - cargo.rustdocflag("--generate-macro-expansion"); + // FIXME: Currently, `--generate-macro-expansion` option is buggy in `beta` rustdoc. To + // allow CI to pass, we only enable the option in stage 2 and higher. + // cfg(bootstrap) + // ^ Adding this so it's not forgotten when the new release is done. + if builder.top_stage > 1 { + cargo.rustdocflag("--generate-macro-expansion"); + } compile::rustc_cargo(builder, &mut cargo, target, &build_compiler, &self.crates); cargo.arg("-Zskip-rustdoc-fingerprint"); From 567b569e2bb131abcbf77eef7d98b7f50d47465a Mon Sep 17 00:00:00 2001 From: Clara Engler Date: Fri, 16 Jan 2026 10:39:35 +0100 Subject: [PATCH 0771/1061] time: Add saturating arithmetic for `SystemTime` This commit implements the following methods: * `SystemTime::saturating_add` * `SystemTime::saturating_sub` * `SystemTime::saturating_duration_since` The implementation of these methods is rather trivial, as the main logic lies behind the constants `SystemTime::MIN` and `SystemTime::MAX`. --- library/std/src/time.rs | 50 +++++++++++++++++++++++++++++++++++++++ library/std/tests/time.rs | 39 ++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 3d09824019e3..1805d8926098 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -682,6 +682,56 @@ impl SystemTime { pub fn checked_sub(&self, duration: Duration) -> Option { self.0.checked_sub_duration(&duration).map(SystemTime) } + + /// Saturating [`SystemTime`] addition, computing `self + duration`, + /// returning [`SystemTime::MAX`] if overflow occurred. + /// + /// In the case that the `duration` is smaller than the time precision of + /// the operating system, `self` will be returned. + #[unstable(feature = "time_saturating_systemtime", issue = "151199")] + pub fn saturating_add(&self, duration: Duration) -> SystemTime { + self.checked_add(duration).unwrap_or(SystemTime::MAX) + } + + /// Saturating [`SystemTime`] subtraction, computing `self - duration`, + /// returning [`SystemTime::MIN`] if overflow occurred. + /// + /// In the case that the `duration` is smaller than the time precision of + /// the operating system, `self` will be returned. + #[unstable(feature = "time_saturating_systemtime", issue = "151199")] + pub fn saturating_sub(&self, duration: Duration) -> SystemTime { + self.checked_sub(duration).unwrap_or(SystemTime::MIN) + } + + /// Saturating computation of time elapsed from an earlier point in time, + /// returning [`Duration::ZERO`] in the case that `earlier` is later or + /// equal to `self`. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(time_saturating_systemtime)] + /// use std::time::{Duration, SystemTime}; + /// + /// let now = SystemTime::now(); + /// let prev = now.saturating_sub(Duration::new(1, 0)); + /// + /// // now - prev should return non-zero. + /// assert_eq!(now.saturating_duration_since(prev), Duration::new(1, 0)); + /// assert!(now.duration_since(prev).is_ok()); + /// + /// // prev - now should return zero (and fail with the non-saturating). + /// assert_eq!(prev.saturating_duration_since(now), Duration::ZERO); + /// assert!(prev.duration_since(now).is_err()); + /// + /// // now - now should return zero (and work with the non-saturating). + /// assert_eq!(now.saturating_duration_since(now), Duration::ZERO); + /// assert!(now.duration_since(now).is_ok()); + /// ``` + #[unstable(feature = "time_saturating_systemtime", issue = "151199")] + pub fn saturating_duration_since(&self, earlier: SystemTime) -> Duration { + self.duration_since(earlier).unwrap_or(Duration::ZERO) + } } #[stable(feature = "time2", since = "1.8.0")] diff --git a/library/std/tests/time.rs b/library/std/tests/time.rs index 0ef89bb09c63..b73e7bc3962e 100644 --- a/library/std/tests/time.rs +++ b/library/std/tests/time.rs @@ -1,5 +1,6 @@ #![feature(duration_constants)] #![feature(time_systemtime_limits)] +#![feature(time_saturating_systemtime)] use std::fmt::Debug; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; @@ -269,3 +270,41 @@ fn system_time_max_min() { assert!(SystemTime::MIN.checked_add(MIN_INTERVAL).is_some()); assert!(SystemTime::MIN.checked_sub(MIN_INTERVAL).is_none()); } + +#[test] +fn system_time_saturating() { + // Perform saturating addition on SystemTime::MAX to see how it behaves. + assert_eq!(SystemTime::MAX.saturating_add(Duration::ZERO), SystemTime::MAX); + assert_eq!(SystemTime::MAX.saturating_add(Duration::new(1, 0)), SystemTime::MAX); + assert!(SystemTime::MAX.checked_add(Duration::new(1, 0)).is_none()); + assert_eq!( + SystemTime::MAX.saturating_sub(Duration::new(1, 0)), + SystemTime::MAX.checked_sub(Duration::new(1, 0)).unwrap() + ); + + // Perform saturating subtraction on SystemTime::MIn to see how it behaves. + assert_eq!(SystemTime::MIN.saturating_sub(Duration::ZERO), SystemTime::MIN); + assert_eq!(SystemTime::MIN.saturating_sub(Duration::new(1, 0)), SystemTime::MIN); + assert!(SystemTime::MIN.checked_sub(Duration::new(1, 0)).is_none()); + assert_eq!( + SystemTime::MIN.saturating_add(Duration::new(1, 0)), + SystemTime::MIN.checked_add(Duration::new(1, 0)).unwrap() + ); + + // Check saturating_duration_since with various constant values. + assert!(SystemTime::MAX.saturating_duration_since(SystemTime::MIN) >= Duration::ZERO); + assert_eq!(SystemTime::MAX.saturating_duration_since(SystemTime::MAX), Duration::ZERO); + assert!(SystemTime::MAX.duration_since(SystemTime::MAX).is_ok()); + assert_eq!(SystemTime::MIN.saturating_duration_since(SystemTime::MAX), Duration::ZERO); + assert!(SystemTime::MIN.duration_since(SystemTime::MAX).is_err()); + assert_eq!( + (SystemTime::UNIX_EPOCH + Duration::new(1, 0)) + .saturating_duration_since(SystemTime::UNIX_EPOCH), + Duration::new(1, 0) + ); + assert_eq!( + SystemTime::UNIX_EPOCH + .saturating_duration_since(SystemTime::UNIX_EPOCH + Duration::new(1, 0)), + Duration::ZERO + ); +} From d028956f11c85206f6d02c5dd38ccf5f4ce24b91 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Fri, 16 Jan 2026 10:22:43 +0100 Subject: [PATCH 0772/1061] Add an additional help note to the ambiguity lint error This PR adds an additional help note to the ambiguity lint error output to ask users updating their dependencies. This hopefully helps with cases like https://github.com/rust-lang/rust/issues/149845 where newer crate versions are fixed. --- compiler/rustc_resolve/src/diagnostics.rs | 15 +++++++++++++++ compiler/rustc_resolve/src/errors.rs | 6 ++++++ tests/ui/imports/ambiguous-2.stderr | 4 ++++ tests/ui/imports/ambiguous-4.stderr | 4 ++++ .../ui/imports/glob-conflict-cross-crate-1.stderr | 8 ++++++++ .../ui/imports/glob-conflict-cross-crate-2.stderr | 4 ++++ .../ui/imports/glob-conflict-cross-crate-3.stderr | 4 ++++ tests/ui/imports/issue-114682-2.stderr | 8 ++++++++ tests/ui/imports/issue-114682-4.stderr | 4 ++++ tests/ui/imports/issue-114682-5.stderr | 4 ++++ tests/ui/imports/issue-114682-6.stderr | 4 ++++ 11 files changed, 65 insertions(+) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index e9f94dedf522..4f371643ed24 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2064,9 +2064,24 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; let (b1_note, b1_help_msgs) = could_refer_to(b1, scope1, ""); let (b2_note, b2_help_msgs) = could_refer_to(b2, scope2, " also"); + let help = if kind == AmbiguityKind::GlobVsGlob + && b1 + .parent_module + .and_then(|m| m.opt_def_id()) + .map(|d| !d.is_local()) + .unwrap_or_default() + { + Some(&[ + "consider updating this dependency to resolve this error", + "if updating the dependency does not resolve the problem report the problem to the author of the relevant crate", + ] as &[_]) + } else { + None + }; errors::Ambiguity { ident, + help, kind: kind.descr(), b1_note, b1_help_msgs, diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 8880c2ba2666..d614219e8eab 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1464,6 +1464,7 @@ pub(crate) struct UnknownDiagnosticAttributeTypoSugg { pub(crate) struct Ambiguity { pub ident: Ident, pub kind: &'static str, + pub help: Option<&'static [&'static str]>, pub b1_note: Spanned, pub b1_help_msgs: Vec, pub b2_note: Spanned, @@ -1476,6 +1477,11 @@ impl Ambiguity { diag.span_label(self.ident.span, "ambiguous name"); diag.note(format!("ambiguous because of {}", self.kind)); diag.span_note(self.b1_note.span, self.b1_note.node); + if let Some(help) = self.help { + for help in help { + diag.help(*help); + } + } for help_msg in self.b1_help_msgs { diag.help(help_msg); } diff --git a/tests/ui/imports/ambiguous-2.stderr b/tests/ui/imports/ambiguous-2.stderr index a0222099239a..5b12491af19d 100644 --- a/tests/ui/imports/ambiguous-2.stderr +++ b/tests/ui/imports/ambiguous-2.stderr @@ -12,6 +12,8 @@ note: `id` could refer to the function defined here | LL | pub use self::evp::*; | ^^^^^^^^^ + = help: consider updating this dependency to resolve this error + = help: if updating the dependency does not resolve the problem report the problem to the author of the relevant crate note: `id` could also refer to the function defined here --> $DIR/auxiliary/../ambiguous-1.rs:15:13 | @@ -36,6 +38,8 @@ note: `id` could refer to the function defined here | LL | pub use self::evp::*; | ^^^^^^^^^ + = help: consider updating this dependency to resolve this error + = help: if updating the dependency does not resolve the problem report the problem to the author of the relevant crate note: `id` could also refer to the function defined here --> $DIR/auxiliary/../ambiguous-1.rs:15:13 | diff --git a/tests/ui/imports/ambiguous-4.stderr b/tests/ui/imports/ambiguous-4.stderr index 6c1a2679fcae..691dd33a398a 100644 --- a/tests/ui/imports/ambiguous-4.stderr +++ b/tests/ui/imports/ambiguous-4.stderr @@ -12,6 +12,8 @@ note: `id` could refer to the function defined here | LL | pub use evp::*; | ^^^ + = help: consider updating this dependency to resolve this error + = help: if updating the dependency does not resolve the problem report the problem to the author of the relevant crate note: `id` could also refer to the function defined here --> $DIR/auxiliary/../ambiguous-4-extern.rs:14:9 | @@ -36,6 +38,8 @@ note: `id` could refer to the function defined here | LL | pub use evp::*; | ^^^ + = help: consider updating this dependency to resolve this error + = help: if updating the dependency does not resolve the problem report the problem to the author of the relevant crate note: `id` could also refer to the function defined here --> $DIR/auxiliary/../ambiguous-4-extern.rs:14:9 | diff --git a/tests/ui/imports/glob-conflict-cross-crate-1.stderr b/tests/ui/imports/glob-conflict-cross-crate-1.stderr index 440113653675..4eb27729b41a 100644 --- a/tests/ui/imports/glob-conflict-cross-crate-1.stderr +++ b/tests/ui/imports/glob-conflict-cross-crate-1.stderr @@ -12,6 +12,8 @@ note: `f` could refer to the function defined here | LL | pub use m1::*; | ^^ + = help: consider updating this dependency to resolve this error + = help: if updating the dependency does not resolve the problem report the problem to the author of the relevant crate note: `f` could also refer to the function defined here --> $DIR/auxiliary/glob-conflict.rs:13:9 | @@ -33,6 +35,8 @@ note: `f` could refer to the function defined here | LL | pub use m1::*; | ^^ + = help: consider updating this dependency to resolve this error + = help: if updating the dependency does not resolve the problem report the problem to the author of the relevant crate note: `f` could also refer to the function defined here --> $DIR/auxiliary/glob-conflict.rs:13:9 | @@ -56,6 +60,8 @@ note: `f` could refer to the function defined here | LL | pub use m1::*; | ^^ + = help: consider updating this dependency to resolve this error + = help: if updating the dependency does not resolve the problem report the problem to the author of the relevant crate note: `f` could also refer to the function defined here --> $DIR/auxiliary/glob-conflict.rs:13:9 | @@ -78,6 +84,8 @@ note: `f` could refer to the function defined here | LL | pub use m1::*; | ^^ + = help: consider updating this dependency to resolve this error + = help: if updating the dependency does not resolve the problem report the problem to the author of the relevant crate note: `f` could also refer to the function defined here --> $DIR/auxiliary/glob-conflict.rs:13:9 | diff --git a/tests/ui/imports/glob-conflict-cross-crate-2.stderr b/tests/ui/imports/glob-conflict-cross-crate-2.stderr index 2ee519a364b3..6ff36477e45f 100644 --- a/tests/ui/imports/glob-conflict-cross-crate-2.stderr +++ b/tests/ui/imports/glob-conflict-cross-crate-2.stderr @@ -12,6 +12,8 @@ note: `C` could refer to the type alias defined here | LL | pub use a::*; | ^ + = help: consider updating this dependency to resolve this error + = help: if updating the dependency does not resolve the problem report the problem to the author of the relevant crate note: `C` could also refer to the type alias defined here --> $DIR/auxiliary/glob-conflict-cross-crate-2-extern.rs:10:9 | @@ -36,6 +38,8 @@ note: `C` could refer to the type alias defined here | LL | pub use a::*; | ^ + = help: consider updating this dependency to resolve this error + = help: if updating the dependency does not resolve the problem report the problem to the author of the relevant crate note: `C` could also refer to the type alias defined here --> $DIR/auxiliary/glob-conflict-cross-crate-2-extern.rs:10:9 | diff --git a/tests/ui/imports/glob-conflict-cross-crate-3.stderr b/tests/ui/imports/glob-conflict-cross-crate-3.stderr index c7457efe866e..9b6867774ebe 100644 --- a/tests/ui/imports/glob-conflict-cross-crate-3.stderr +++ b/tests/ui/imports/glob-conflict-cross-crate-3.stderr @@ -12,6 +12,8 @@ note: `C` could refer to the type alias defined here | LL | pub use a::*; | ^ + = help: consider updating this dependency to resolve this error + = help: if updating the dependency does not resolve the problem report the problem to the author of the relevant crate note: `C` could also refer to the type alias defined here --> $DIR/auxiliary/glob-conflict-cross-crate-2-extern.rs:10:9 | @@ -58,6 +60,8 @@ note: `C` could refer to the type alias defined here | LL | pub use a::*; | ^ + = help: consider updating this dependency to resolve this error + = help: if updating the dependency does not resolve the problem report the problem to the author of the relevant crate note: `C` could also refer to the type alias defined here --> $DIR/auxiliary/glob-conflict-cross-crate-2-extern.rs:10:9 | diff --git a/tests/ui/imports/issue-114682-2.stderr b/tests/ui/imports/issue-114682-2.stderr index f93e4409f0c4..92fac9f0a424 100644 --- a/tests/ui/imports/issue-114682-2.stderr +++ b/tests/ui/imports/issue-114682-2.stderr @@ -12,6 +12,8 @@ note: `max` could refer to the type alias defined here | LL | pub use self::e::*; | ^^^^^^^ + = help: consider updating this dependency to resolve this error + = help: if updating the dependency does not resolve the problem report the problem to the author of the relevant crate note: `max` could also refer to the module defined here --> $DIR/auxiliary/issue-114682-2-extern.rs:16:9 | @@ -33,6 +35,8 @@ note: `max` could refer to the type alias defined here | LL | pub use self::e::*; | ^^^^^^^ + = help: consider updating this dependency to resolve this error + = help: if updating the dependency does not resolve the problem report the problem to the author of the relevant crate note: `max` could also refer to the module defined here --> $DIR/auxiliary/issue-114682-2-extern.rs:16:9 | @@ -56,6 +60,8 @@ note: `max` could refer to the type alias defined here | LL | pub use self::e::*; | ^^^^^^^ + = help: consider updating this dependency to resolve this error + = help: if updating the dependency does not resolve the problem report the problem to the author of the relevant crate note: `max` could also refer to the module defined here --> $DIR/auxiliary/issue-114682-2-extern.rs:16:9 | @@ -78,6 +84,8 @@ note: `max` could refer to the type alias defined here | LL | pub use self::e::*; | ^^^^^^^ + = help: consider updating this dependency to resolve this error + = help: if updating the dependency does not resolve the problem report the problem to the author of the relevant crate note: `max` could also refer to the module defined here --> $DIR/auxiliary/issue-114682-2-extern.rs:16:9 | diff --git a/tests/ui/imports/issue-114682-4.stderr b/tests/ui/imports/issue-114682-4.stderr index 12cb9ae95a42..5b012e21ea81 100644 --- a/tests/ui/imports/issue-114682-4.stderr +++ b/tests/ui/imports/issue-114682-4.stderr @@ -12,6 +12,8 @@ note: `Result` could refer to the type alias defined here | LL | pub use a::*; | ^ + = help: consider updating this dependency to resolve this error + = help: if updating the dependency does not resolve the problem report the problem to the author of the relevant crate note: `Result` could also refer to the type alias defined here --> $DIR/auxiliary/issue-114682-4-extern.rs:10:9 | @@ -51,6 +53,8 @@ note: `Result` could refer to the type alias defined here | LL | pub use a::*; | ^ + = help: consider updating this dependency to resolve this error + = help: if updating the dependency does not resolve the problem report the problem to the author of the relevant crate note: `Result` could also refer to the type alias defined here --> $DIR/auxiliary/issue-114682-4-extern.rs:10:9 | diff --git a/tests/ui/imports/issue-114682-5.stderr b/tests/ui/imports/issue-114682-5.stderr index 74b42e0990b7..5937f6f33117 100644 --- a/tests/ui/imports/issue-114682-5.stderr +++ b/tests/ui/imports/issue-114682-5.stderr @@ -40,6 +40,8 @@ note: `issue_114682_5_extern_1` could refer to the module defined here | LL | pub use crate::types::*; | ^^^^^^^^^^^^ + = help: consider updating this dependency to resolve this error + = help: if updating the dependency does not resolve the problem report the problem to the author of the relevant crate note: `issue_114682_5_extern_1` could also refer to the crate defined here --> $DIR/auxiliary/issue-114682-5-extern-2.rs:7:13 | @@ -67,6 +69,8 @@ note: `issue_114682_5_extern_1` could refer to the module defined here | LL | pub use crate::types::*; | ^^^^^^^^^^^^ + = help: consider updating this dependency to resolve this error + = help: if updating the dependency does not resolve the problem report the problem to the author of the relevant crate note: `issue_114682_5_extern_1` could also refer to the crate defined here --> $DIR/auxiliary/issue-114682-5-extern-2.rs:7:13 | diff --git a/tests/ui/imports/issue-114682-6.stderr b/tests/ui/imports/issue-114682-6.stderr index 37f8f6c16ff2..a2e9afb6eedb 100644 --- a/tests/ui/imports/issue-114682-6.stderr +++ b/tests/ui/imports/issue-114682-6.stderr @@ -12,6 +12,8 @@ note: `log` could refer to the function defined here | LL | pub use self::a::*; | ^^^^^^^ + = help: consider updating this dependency to resolve this error + = help: if updating the dependency does not resolve the problem report the problem to the author of the relevant crate note: `log` could also refer to the function defined here --> $DIR/auxiliary/issue-114682-6-extern.rs:9:9 | @@ -36,6 +38,8 @@ note: `log` could refer to the function defined here | LL | pub use self::a::*; | ^^^^^^^ + = help: consider updating this dependency to resolve this error + = help: if updating the dependency does not resolve the problem report the problem to the author of the relevant crate note: `log` could also refer to the function defined here --> $DIR/auxiliary/issue-114682-6-extern.rs:9:9 | From 19e0d7914f2865c707ace136fd33ab6f8c2931fb Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Fri, 16 Jan 2026 13:08:09 +0000 Subject: [PATCH 0773/1061] Mention `cast_signed` in docs of `cast_possible_wrap` changelog: [`cast_possible_wrap`]: mention `cast_{un,}signed()` methods in doc I was evaluating this lint recently, and accepted using it because these methods exist. But the docs on the lint don't mention it, so I thought it would be prudent to include it in the docs. See also https://github.com/rust-lang/rust-clippy/pull/15384 Co-authored-by: Kaur Kuut Co-authored-by: Samuel Tardieu --- clippy_lints/src/casts/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 7220a8a80066..3c9ebef73f0d 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -145,6 +145,12 @@ declare_clippy_lint! { /// let _ = i32::try_from(u32::MAX).ok(); /// ``` /// + /// If the wrapping is intended, you can use: + /// ```no_run + /// let _ = u32::MAX.cast_signed(); + /// let _ = (-1i32).cast_unsigned(); + /// ``` + /// #[clippy::version = "pre 1.29.0"] pub CAST_POSSIBLE_WRAP, pedantic, From e45e4a7cc65242f5dd2a750ec8860952b0f69949 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Fri, 16 Jan 2026 13:31:38 +0000 Subject: [PATCH 0774/1061] delete weird `fd_read` feature --- library/std/src/sys/net/connection/socket/windows.rs | 1 - src/doc/unstable-book/src/library-features/fd-read.md | 5 ----- 2 files changed, 6 deletions(-) delete mode 100644 src/doc/unstable-book/src/library-features/fd-read.md diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs index 3f99249efc47..b23fb9c09f87 100644 --- a/library/std/src/sys/net/connection/socket/windows.rs +++ b/library/std/src/sys/net/connection/socket/windows.rs @@ -451,7 +451,6 @@ impl Socket { } } -#[unstable(reason = "not public", issue = "none", feature = "fd_read")] impl<'a> Read for &'a Socket { fn read(&mut self, buf: &mut [u8]) -> io::Result { (**self).read(buf) diff --git a/src/doc/unstable-book/src/library-features/fd-read.md b/src/doc/unstable-book/src/library-features/fd-read.md deleted file mode 100644 index e78d4330abfc..000000000000 --- a/src/doc/unstable-book/src/library-features/fd-read.md +++ /dev/null @@ -1,5 +0,0 @@ -# `fd_read` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- From f13b1549cee9d2c7e47084f9e8d57f8fbec45382 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Fri, 16 Jan 2026 13:32:24 +0000 Subject: [PATCH 0775/1061] remove `reason = "recently added"` from `#[unstable(...)]` --- library/core/src/iter/adapters/array_chunks.rs | 12 ++++++------ library/core/src/iter/adapters/intersperse.rs | 16 ++++++++-------- library/core/src/iter/adapters/map_windows.rs | 12 ++++++------ library/core/src/iter/adapters/mod.rs | 6 +++--- library/core/src/iter/mod.rs | 6 +++--- library/core/src/iter/traits/double_ended.rs | 2 +- library/core/src/iter/traits/iterator.rs | 12 ++++++------ library/std/src/io/mod.rs | 2 +- library/std/src/os/unix/io/mod.rs | 6 +++--- 9 files changed, 37 insertions(+), 37 deletions(-) diff --git a/library/core/src/iter/adapters/array_chunks.rs b/library/core/src/iter/adapters/array_chunks.rs index 21f46ab8b6a4..7c003cff10c7 100644 --- a/library/core/src/iter/adapters/array_chunks.rs +++ b/library/core/src/iter/adapters/array_chunks.rs @@ -15,7 +15,7 @@ use crate::ops::{ControlFlow, NeverShortCircuit, Try}; /// method on [`Iterator`]. See its documentation for more. #[derive(Debug, Clone)] #[must_use = "iterators are lazy and do nothing unless consumed"] -#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] +#[unstable(feature = "iter_array_chunks", issue = "100450")] pub struct ArrayChunks { iter: I, remainder: Option>, @@ -44,7 +44,7 @@ where /// assert_eq!(rem.next(), Some(5)); /// assert_eq!(rem.next(), None); /// ``` - #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] + #[unstable(feature = "iter_array_chunks", issue = "100450")] #[inline] pub fn into_remainder(mut self) -> array::IntoIter { if self.remainder.is_none() { @@ -54,7 +54,7 @@ where } } -#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] +#[unstable(feature = "iter_array_chunks", issue = "100450")] impl Iterator for ArrayChunks where I: Iterator, @@ -108,7 +108,7 @@ where } } -#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] +#[unstable(feature = "iter_array_chunks", issue = "100450")] impl DoubleEndedIterator for ArrayChunks where I: DoubleEndedIterator + ExactSizeIterator, @@ -173,13 +173,13 @@ where } } -#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] +#[unstable(feature = "iter_array_chunks", issue = "100450")] impl FusedIterator for ArrayChunks where I: FusedIterator {} #[unstable(issue = "none", feature = "trusted_fused")] unsafe impl TrustedFused for ArrayChunks where I: TrustedFused + Iterator {} -#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] +#[unstable(feature = "iter_array_chunks", issue = "100450")] impl ExactSizeIterator for ArrayChunks where I: ExactSizeIterator, diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs index 843479e2a27a..bb94ed0a0a17 100644 --- a/library/core/src/iter/adapters/intersperse.rs +++ b/library/core/src/iter/adapters/intersperse.rs @@ -5,7 +5,7 @@ use crate::iter::{Fuse, FusedIterator}; /// /// This `struct` is created by [`Iterator::intersperse`]. See its documentation /// for more information. -#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +#[unstable(feature = "iter_intersperse", issue = "79524")] #[derive(Debug, Clone)] pub struct Intersperse where @@ -17,7 +17,7 @@ where iter: Fuse, } -#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +#[unstable(feature = "iter_intersperse", issue = "79524")] impl FusedIterator for Intersperse where I: FusedIterator, @@ -34,7 +34,7 @@ where } } -#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +#[unstable(feature = "iter_intersperse", issue = "79524")] impl Iterator for Intersperse where I: Iterator, @@ -87,7 +87,7 @@ where /// /// This `struct` is created by [`Iterator::intersperse_with`]. See its /// documentation for more information. -#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +#[unstable(feature = "iter_intersperse", issue = "79524")] pub struct IntersperseWith where I: Iterator, @@ -98,7 +98,7 @@ where iter: Fuse, } -#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +#[unstable(feature = "iter_intersperse", issue = "79524")] impl FusedIterator for IntersperseWith where I: FusedIterator, @@ -106,7 +106,7 @@ where { } -#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +#[unstable(feature = "iter_intersperse", issue = "79524")] impl fmt::Debug for IntersperseWith where I: Iterator + fmt::Debug, @@ -123,7 +123,7 @@ where } } -#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +#[unstable(feature = "iter_intersperse", issue = "79524")] impl Clone for IntersperseWith where I: Iterator + Clone, @@ -150,7 +150,7 @@ where } } -#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +#[unstable(feature = "iter_intersperse", issue = "79524")] impl Iterator for IntersperseWith where I: Iterator, diff --git a/library/core/src/iter/adapters/map_windows.rs b/library/core/src/iter/adapters/map_windows.rs index 0dada9eb6aac..cef556319143 100644 --- a/library/core/src/iter/adapters/map_windows.rs +++ b/library/core/src/iter/adapters/map_windows.rs @@ -7,7 +7,7 @@ use crate::{fmt, ptr}; /// This `struct` is created by the [`Iterator::map_windows`]. See its /// documentation for more information. #[must_use = "iterators are lazy and do nothing unless consumed"] -#[unstable(feature = "iter_map_windows", reason = "recently added", issue = "87155")] +#[unstable(feature = "iter_map_windows", issue = "87155")] pub struct MapWindows { f: F, inner: MapWindowsInner, @@ -234,7 +234,7 @@ impl Drop for Buffer { } } -#[unstable(feature = "iter_map_windows", reason = "recently added", issue = "87155")] +#[unstable(feature = "iter_map_windows", issue = "87155")] impl Iterator for MapWindows where I: Iterator, @@ -255,7 +255,7 @@ where // Note that even if the inner iterator not fused, the `MapWindows` is still fused, // because we don't allow "holes" in the mapping window. -#[unstable(feature = "iter_map_windows", reason = "recently added", issue = "87155")] +#[unstable(feature = "iter_map_windows", issue = "87155")] impl FusedIterator for MapWindows where I: Iterator, @@ -263,7 +263,7 @@ where { } -#[unstable(feature = "iter_map_windows", reason = "recently added", issue = "87155")] +#[unstable(feature = "iter_map_windows", issue = "87155")] impl ExactSizeIterator for MapWindows where I: ExactSizeIterator, @@ -271,14 +271,14 @@ where { } -#[unstable(feature = "iter_map_windows", reason = "recently added", issue = "87155")] +#[unstable(feature = "iter_map_windows", issue = "87155")] impl fmt::Debug for MapWindows { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("MapWindows").field("iter", &self.inner.iter).finish() } } -#[unstable(feature = "iter_map_windows", reason = "recently added", issue = "87155")] +#[unstable(feature = "iter_map_windows", issue = "87155")] impl Clone for MapWindows where I: Iterator + Clone, diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 1ff5093922b6..d0b89fdbb584 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -28,7 +28,7 @@ mod take; mod take_while; mod zip; -#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] +#[unstable(feature = "iter_array_chunks", issue = "100450")] pub use self::array_chunks::ArrayChunks; #[unstable(feature = "std_internals", issue = "none")] pub use self::by_ref_sized::ByRefSized; @@ -40,11 +40,11 @@ pub use self::cloned::Cloned; pub use self::copied::Copied; #[stable(feature = "iterator_flatten", since = "1.29.0")] pub use self::flatten::Flatten; -#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +#[unstable(feature = "iter_intersperse", issue = "79524")] pub use self::intersperse::{Intersperse, IntersperseWith}; #[stable(feature = "iter_map_while", since = "1.57.0")] pub use self::map_while::MapWhile; -#[unstable(feature = "iter_map_windows", reason = "recently added", issue = "87155")] +#[unstable(feature = "iter_map_windows", issue = "87155")] pub use self::map_windows::MapWindows; #[stable(feature = "iterator_step_by", since = "1.28.0")] pub use self::step_by::StepBy; diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index c7e1c4ef767b..d532f1e56807 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -382,7 +382,7 @@ macro_rules! impl_fold_via_try_fold { }; } -#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] +#[unstable(feature = "iter_array_chunks", issue = "100450")] pub use self::adapters::ArrayChunks; #[unstable(feature = "std_internals", issue = "none")] pub use self::adapters::ByRefSized; @@ -394,7 +394,7 @@ pub use self::adapters::Copied; pub use self::adapters::Flatten; #[stable(feature = "iter_map_while", since = "1.57.0")] pub use self::adapters::MapWhile; -#[unstable(feature = "iter_map_windows", reason = "recently added", issue = "87155")] +#[unstable(feature = "iter_map_windows", issue = "87155")] pub use self::adapters::MapWindows; #[unstable(feature = "inplace_iteration", issue = "none")] pub use self::adapters::SourceIter; @@ -414,7 +414,7 @@ pub use self::adapters::{ Chain, Cycle, Enumerate, Filter, FilterMap, FlatMap, Fuse, Inspect, Map, Peekable, Rev, Scan, Skip, SkipWhile, Take, TakeWhile, Zip, }; -#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +#[unstable(feature = "iter_intersperse", issue = "79524")] pub use self::adapters::{Intersperse, IntersperseWith}; #[unstable( feature = "step_trait", diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index da0b05063657..9f7ac7da2dbd 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -134,7 +134,7 @@ pub trait DoubleEndedIterator: Iterator { /// [`Ok(())`]: Ok /// [`Err(k)`]: Err #[inline] - #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] + #[unstable(feature = "iter_advance_by", issue = "77404")] fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { for i in 0..n { if self.next_back().is_none() { diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 419f66089b10..81901fc011be 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -106,7 +106,7 @@ pub trait Iterator { /// assert_eq!(third, "those"); /// ``` #[inline] - #[unstable(feature = "iter_next_chunk", reason = "recently added", issue = "98326")] + #[unstable(feature = "iter_next_chunk", issue = "98326")] fn next_chunk( &mut self, ) -> Result<[Self::Item; N], array::IntoIter> @@ -297,7 +297,7 @@ pub trait Iterator { /// assert_eq!(iter.advance_by(100), Err(NonZero::new(99).unwrap())); // only `4` was skipped /// ``` #[inline] - #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] + #[unstable(feature = "iter_advance_by", issue = "77404")] fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { /// Helper trait to specialize `advance_by` via `try_fold` for `Sized` iterators. trait SpecAdvanceBy { @@ -656,7 +656,7 @@ pub trait Iterator { /// [`Clone`]: crate::clone::Clone /// [`intersperse_with`]: Iterator::intersperse_with #[inline] - #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] + #[unstable(feature = "iter_intersperse", issue = "79524")] fn intersperse(self, separator: Self::Item) -> Intersperse where Self: Sized, @@ -714,7 +714,7 @@ pub trait Iterator { /// [`Clone`]: crate::clone::Clone /// [`intersperse`]: Iterator::intersperse #[inline] - #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] + #[unstable(feature = "iter_intersperse", issue = "79524")] fn intersperse_with(self, separator: G) -> IntersperseWith where Self: Sized, @@ -1713,7 +1713,7 @@ pub trait Iterator { /// assert_eq!(iter.next(), None); /// ``` #[inline] - #[unstable(feature = "iter_map_windows", reason = "recently added", issue = "87155")] + #[unstable(feature = "iter_map_windows", issue = "87155")] fn map_windows(self, f: F) -> MapWindows where Self: Sized, @@ -3554,7 +3554,7 @@ pub trait Iterator { /// } /// ``` #[track_caller] - #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] + #[unstable(feature = "iter_array_chunks", issue = "100450")] fn array_chunks(self) -> ArrayChunks where Self: Sized, diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index b7756befa11e..623c34c6d291 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2431,7 +2431,7 @@ pub trait BufRead: Read { /// } /// # std::io::Result::Ok(()) /// ``` - #[unstable(feature = "buf_read_has_data_left", reason = "recently added", issue = "86423")] + #[unstable(feature = "buf_read_has_data_left", issue = "86423")] fn has_data_left(&mut self) -> Result { self.fill_buf().map(|b| !b.is_empty()) } diff --git a/library/std/src/os/unix/io/mod.rs b/library/std/src/os/unix/io/mod.rs index 708ebaec362e..18b0f70c0687 100644 --- a/library/std/src/os/unix/io/mod.rs +++ b/library/std/src/os/unix/io/mod.rs @@ -102,7 +102,7 @@ use crate::sys::cvt; #[cfg(test)] mod tests; -#[unstable(feature = "stdio_swap", issue = "150667", reason = "recently added")] +#[unstable(feature = "stdio_swap", issue = "150667")] pub trait StdioExt: crate::sealed::Sealed { /// Redirects the stdio file descriptor to point to the file description underpinning `fd`. /// @@ -159,7 +159,7 @@ pub trait StdioExt: crate::sealed::Sealed { } macro io_ext_impl($stdio_ty:ty, $stdio_lock_ty:ty, $writer:literal) { - #[unstable(feature = "stdio_swap", issue = "150667", reason = "recently added")] + #[unstable(feature = "stdio_swap", issue = "150667")] impl StdioExt for $stdio_ty { fn set_fd>(&mut self, fd: T) -> io::Result<()> { self.lock().set_fd(fd) @@ -174,7 +174,7 @@ macro io_ext_impl($stdio_ty:ty, $stdio_lock_ty:ty, $writer:literal) { } } - #[unstable(feature = "stdio_swap", issue = "150667", reason = "recently added")] + #[unstable(feature = "stdio_swap", issue = "150667")] impl StdioExt for $stdio_lock_ty { fn set_fd>(&mut self, fd: T) -> io::Result<()> { #[cfg($writer)] From 69da4016aaa085c185aa7f6251555ac226d35f51 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Fri, 16 Jan 2026 13:34:34 +0000 Subject: [PATCH 0776/1061] remove `reason = "new API"` from `#[unstable(...)]` --- library/alloc/src/boxed.rs | 8 ++++---- library/alloc/src/collections/mod.rs | 2 +- library/alloc/src/string.rs | 2 +- library/alloc/src/vec/mod.rs | 14 +++++++------- library/core/src/iter/traits/iterator.rs | 10 +++++----- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 60758551cc04..de9c92db11d3 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1313,7 +1313,7 @@ impl Box { /// ``` /// /// [memory layout]: self#memory-layout - #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] + #[unstable(feature = "box_vec_non_null", issue = "130364")] #[inline] #[must_use = "call `drop(Box::from_non_null(ptr))` if you intend to drop the `Box`"] pub unsafe fn from_non_null(ptr: NonNull) -> Self { @@ -1431,7 +1431,7 @@ impl Box { /// /// [memory layout]: self#memory-layout #[must_use = "losing the pointer will leak memory"] - #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] + #[unstable(feature = "box_vec_non_null", issue = "130364")] #[inline] pub fn into_non_null(b: Self) -> NonNull { // SAFETY: `Box` is guaranteed to be non-null. @@ -1540,7 +1540,7 @@ impl Box { /// /// [memory layout]: self#memory-layout #[unstable(feature = "allocator_api", issue = "32838")] - // #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] + // #[unstable(feature = "box_vec_non_null", issue = "130364")] #[inline] pub unsafe fn from_non_null_in(raw: NonNull, alloc: A) -> Self { // SAFETY: guaranteed by the caller. @@ -1655,7 +1655,7 @@ impl Box { /// [memory layout]: self#memory-layout #[must_use = "losing the pointer will leak memory"] #[unstable(feature = "allocator_api", issue = "32838")] - // #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] + // #[unstable(feature = "box_vec_non_null", issue = "130364")] #[inline] pub fn into_non_null_with_allocator(b: Self) -> (NonNull, A) { let (ptr, alloc) = Box::into_raw_with_allocator(b); diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs index e09326759fd1..d306d2016ea2 100644 --- a/library/alloc/src/collections/mod.rs +++ b/library/alloc/src/collections/mod.rs @@ -156,7 +156,7 @@ impl const From for TryReserveError { } } -#[unstable(feature = "try_reserve_kind", reason = "new API", issue = "48043")] +#[unstable(feature = "try_reserve_kind", issue = "48043")] #[rustc_const_unstable(feature = "const_convert", issue = "143773")] #[cfg(not(test))] impl const From for TryReserveErrorKind { diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 1e7f4f208a7f..4100ee55a4c7 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1563,7 +1563,7 @@ impl String { /// assert_eq!("bna", s); /// ``` #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "string_remove_matches", reason = "new API", issue = "72826")] + #[unstable(feature = "string_remove_matches", issue = "72826")] pub fn remove_matches(&mut self, pat: P) { use core::str::pattern::Searcher; diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 379e964f0a0c..93432f3e049e 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -743,7 +743,7 @@ impl Vec { /// } /// ``` #[inline] - #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] + #[unstable(feature = "box_vec_non_null", issue = "130364")] pub unsafe fn from_parts(ptr: NonNull, length: usize, capacity: usize) -> Self { unsafe { Self::from_parts_in(ptr, length, capacity, Global) } } @@ -793,7 +793,7 @@ impl Vec { /// ``` #[cfg(not(no_global_oom_handling))] #[inline] - #[unstable(feature = "vec_from_fn", reason = "new API", issue = "149698")] + #[unstable(feature = "vec_from_fn", issue = "149698")] pub fn from_fn(length: usize, f: F) -> Self where F: FnMut(usize) -> T, @@ -878,7 +878,7 @@ impl Vec { /// assert_eq!(rebuilt, [4294967295, 0, 1]); /// ``` #[must_use = "losing the pointer will leak memory"] - #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] + #[unstable(feature = "box_vec_non_null", issue = "130364")] pub fn into_parts(self) -> (NonNull, usize, usize) { let (ptr, len, capacity) = self.into_raw_parts(); // SAFETY: A `Vec` always has a non-null pointer. @@ -1291,7 +1291,7 @@ impl Vec { /// } /// ``` #[inline] - #[unstable(feature = "allocator_api", reason = "new API", issue = "32838")] + #[unstable(feature = "allocator_api", issue = "32838")] // #[unstable(feature = "box_vec_non_null", issue = "130364")] pub unsafe fn from_parts_in(ptr: NonNull, length: usize, capacity: usize, alloc: A) -> Self { ub_checks::assert_unsafe_precondition!( @@ -1390,7 +1390,7 @@ impl Vec { /// ``` #[must_use = "losing the pointer will leak memory"] #[unstable(feature = "allocator_api", issue = "32838")] - // #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] + // #[unstable(feature = "box_vec_non_null", issue = "130364")] pub fn into_parts_with_alloc(self) -> (NonNull, usize, usize, A) { let (ptr, len, capacity, alloc) = self.into_raw_parts_with_alloc(); // SAFETY: A `Vec` always has a non-null pointer. @@ -1994,8 +1994,8 @@ impl Vec { /// [`as_mut_ptr`]: Vec::as_mut_ptr /// [`as_ptr`]: Vec::as_ptr /// [`as_non_null`]: Vec::as_non_null - #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] - #[rustc_const_unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] + #[unstable(feature = "box_vec_non_null", issue = "130364")] + #[rustc_const_unstable(feature = "box_vec_non_null", issue = "130364")] #[inline] pub const fn as_non_null(&mut self) -> NonNull { self.buf.non_null() diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 81901fc011be..dc484e2a27f6 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -2177,7 +2177,7 @@ pub trait Iterator { /// assert_eq!(vec, vec![1, 2, 3, 1, 2, 3]); /// ``` #[inline] - #[unstable(feature = "iter_collect_into", reason = "new API", issue = "94780")] + #[unstable(feature = "iter_collect_into", issue = "94780")] fn collect_into>(self, collection: &mut E) -> &mut E where Self: Sized, @@ -2271,7 +2271,7 @@ pub trait Iterator { /// assert!(a[..i].iter().all(|n| n % 2 == 0)); // evens /// assert!(a[i..].iter().all(|n| n % 2 == 1)); // odds /// ``` - #[unstable(feature = "iter_partition_in_place", reason = "new API", issue = "62543")] + #[unstable(feature = "iter_partition_in_place", issue = "62543")] fn partition_in_place<'a, T: 'a, P>(mut self, ref mut predicate: P) -> usize where Self: Sized + DoubleEndedIterator, @@ -2328,7 +2328,7 @@ pub trait Iterator { /// assert!("Iterator".chars().is_partitioned(char::is_uppercase)); /// assert!(!"IntoIterator".chars().is_partitioned(char::is_uppercase)); /// ``` - #[unstable(feature = "iter_is_partitioned", reason = "new API", issue = "62544")] + #[unstable(feature = "iter_is_partitioned", issue = "62544")] fn is_partitioned

(mut self, mut predicate: P) -> bool where Self: Sized, @@ -2707,7 +2707,7 @@ pub trait Iterator { /// assert_eq!(max, Ok(Some("5"))); /// ``` #[inline] - #[unstable(feature = "iterator_try_reduce", reason = "new API", issue = "87053")] + #[unstable(feature = "iterator_try_reduce", issue = "87053")] fn try_reduce( &mut self, f: impl FnMut(Self::Item, Self::Item) -> R, @@ -2980,7 +2980,7 @@ pub trait Iterator { /// assert_eq!(result, None); /// ``` #[inline] - #[unstable(feature = "try_find", reason = "new API", issue = "63178")] + #[unstable(feature = "try_find", issue = "63178")] fn try_find( &mut self, f: impl FnMut(&Self::Item) -> R, From 8cb5da3aadbc086fc464d06dc5bd0b5db80d8eb6 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Fri, 16 Jan 2026 13:35:40 +0000 Subject: [PATCH 0777/1061] remove `reason = "recently redesigned"` from `#[unstable(...)]` --- library/core/src/iter/range.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 9e43d5688cec..9d4015ac8c37 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -254,7 +254,7 @@ macro_rules! step_integer_impls { } => { $( #[allow(unreachable_patterns)] - #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] + #[unstable(feature = "step_trait", issue = "42168")] impl Step for $u_narrower { step_identical_methods!(); step_unsigned_methods!(); @@ -288,7 +288,7 @@ macro_rules! step_integer_impls { } #[allow(unreachable_patterns)] - #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] + #[unstable(feature = "step_trait", issue = "42168")] impl Step for $i_narrower { step_identical_methods!(); step_signed_methods!($u_narrower); @@ -354,7 +354,7 @@ macro_rules! step_integer_impls { $( #[allow(unreachable_patterns)] - #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] + #[unstable(feature = "step_trait", issue = "42168")] impl Step for $u_wider { step_identical_methods!(); step_unsigned_methods!(); @@ -384,7 +384,7 @@ macro_rules! step_integer_impls { } #[allow(unreachable_patterns)] - #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] + #[unstable(feature = "step_trait", issue = "42168")] impl Step for $i_wider { step_identical_methods!(); step_signed_methods!($u_wider); @@ -441,7 +441,7 @@ step_integer_impls! { wider than usize: [u32 i32], [u64 i64], [u128 i128]; } -#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] +#[unstable(feature = "step_trait", issue = "42168")] impl Step for char { #[inline] fn steps_between(&start: &char, &end: &char) -> (usize, Option) { @@ -528,7 +528,7 @@ impl Step for char { } } -#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] +#[unstable(feature = "step_trait", issue = "42168")] impl Step for AsciiChar { #[inline] fn steps_between(&start: &AsciiChar, &end: &AsciiChar) -> (usize, Option) { @@ -570,7 +570,7 @@ impl Step for AsciiChar { } } -#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] +#[unstable(feature = "step_trait", issue = "42168")] impl Step for Ipv4Addr { #[inline] fn steps_between(&start: &Ipv4Addr, &end: &Ipv4Addr) -> (usize, Option) { @@ -602,7 +602,7 @@ impl Step for Ipv4Addr { } } -#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] +#[unstable(feature = "step_trait", issue = "42168")] impl Step for Ipv6Addr { #[inline] fn steps_between(&start: &Ipv6Addr, &end: &Ipv6Addr) -> (usize, Option) { From 2f3b9ce72c700766ad7e331b698afb38fd04f9b6 Mon Sep 17 00:00:00 2001 From: Dima Khort Date: Wed, 14 Jan 2026 00:31:54 +0100 Subject: [PATCH 0778/1061] feat(strlen_on_c_strings): suggest .count_bytes() --- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/strlen_on_c_strings.rs | 31 +++++++++++++---- clippy_utils/src/msrvs.rs | 2 +- tests/ui/strlen_on_c_strings.fixed | 42 ++++++++++++++++------ tests/ui/strlen_on_c_strings.rs | 22 ++++++++++++ tests/ui/strlen_on_c_strings.stderr | 46 +++++++++++++++++++------ 6 files changed, 116 insertions(+), 29 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ef2461f8b097..bd9db80d98ad 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -718,7 +718,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co Box::new(|_| Box::::default()), Box::new(move |tcx| Box::new(disallowed_types::DisallowedTypes::new(tcx, conf))), Box::new(move |tcx| Box::new(missing_enforced_import_rename::ImportRename::new(tcx, conf))), - Box::new(|_| Box::new(strlen_on_c_strings::StrlenOnCStrings)), + Box::new(move |_| Box::new(strlen_on_c_strings::StrlenOnCStrings::new(conf))), Box::new(move |_| Box::new(self_named_constructors::SelfNamedConstructors)), Box::new(move |_| Box::new(iter_not_returning_iterator::IterNotReturningIterator)), Box::new(move |_| Box::new(manual_assert::ManualAssert)), diff --git a/clippy_lints/src/strlen_on_c_strings.rs b/clippy_lints/src/strlen_on_c_strings.rs index 5eb160720c52..962ab9cce14c 100644 --- a/clippy_lints/src/strlen_on_c_strings.rs +++ b/clippy_lints/src/strlen_on_c_strings.rs @@ -1,4 +1,6 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeDef; use clippy_utils::source::snippet_with_context; use clippy_utils::visitors::is_expr_unsafe; @@ -6,12 +8,12 @@ use clippy_utils::{match_libc_symbol, sym}; use rustc_errors::Applicability; use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, LangItem, Node, UnsafeSource}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does /// Checks for usage of `libc::strlen` on a `CString` or `CStr` value, - /// and suggest calling `as_bytes().len()` or `to_bytes().len()` respectively instead. + /// and suggest calling `count_bytes()` instead. /// /// ### Why is this bad? /// libc::strlen is an unsafe function, which we don't need to call @@ -27,15 +29,25 @@ declare_clippy_lint! { /// ```rust, no_run /// use std::ffi::CString; /// let cstring = CString::new("foo").expect("CString::new failed"); - /// let len = cstring.as_bytes().len(); + /// let len = cstring.count_bytes(); /// ``` #[clippy::version = "1.55.0"] pub STRLEN_ON_C_STRINGS, complexity, - "using `libc::strlen` on a `CString` or `CStr` value, while `as_bytes().len()` or `to_bytes().len()` respectively can be used instead" + "using `libc::strlen` on a `CString` or `CStr` value, while `count_bytes()` can be used instead" } -declare_lint_pass!(StrlenOnCStrings => [STRLEN_ON_C_STRINGS]); +pub struct StrlenOnCStrings { + msrv: Msrv, +} + +impl StrlenOnCStrings { + pub fn new(conf: &Conf) -> Self { + Self { msrv: conf.msrv } + } +} + +impl_lint_pass!(StrlenOnCStrings => [STRLEN_ON_C_STRINGS]); impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { @@ -80,7 +92,14 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings { |diag| { let mut app = Applicability::MachineApplicable; let val_name = snippet_with_context(cx, self_arg.span, ctxt, "_", &mut app).0; - diag.span_suggestion(span, "use", format!("{val_name}.to_bytes().len()"), app); + + let suggestion = if self.msrv.meets(cx, msrvs::CSTR_COUNT_BYTES) { + format!("{val_name}.count_bytes()") + } else { + format!("{val_name}.to_bytes().len()") + }; + + diag.span_suggestion(span, "use", suggestion, app); }, ); } diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 39a2c2df1f81..18fab6035f28 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -32,7 +32,7 @@ msrv_aliases! { 1,82,0 { IS_NONE_OR, REPEAT_N, RAW_REF_OP, SPECIALIZED_TO_STRING_FOR_REFS } 1,81,0 { LINT_REASONS_STABILIZATION, ERROR_IN_CORE, EXPLICIT_SELF_TYPE_ELISION, DURATION_ABS_DIFF } 1,80,0 { BOX_INTO_ITER, LAZY_CELL } - 1,79,0 { CONST_BLOCKS } + 1,79,0 { CONST_BLOCKS, CSTR_COUNT_BYTES } 1,77,0 { C_STR_LITERALS } 1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT } 1,75,0 { OPTION_AS_SLICE } diff --git a/tests/ui/strlen_on_c_strings.fixed b/tests/ui/strlen_on_c_strings.fixed index 33a328af6df4..6604da70874d 100644 --- a/tests/ui/strlen_on_c_strings.fixed +++ b/tests/ui/strlen_on_c_strings.fixed @@ -7,40 +7,62 @@ use std::ffi::{CStr, CString}; fn main() { // CString let cstring = CString::new("foo").expect("CString::new failed"); - let _ = cstring.to_bytes().len(); + let _ = cstring.count_bytes(); //~^ ERROR: using `libc::strlen` on a `CString` value // CStr let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); - let _ = cstr.to_bytes().len(); + let _ = cstr.count_bytes(); //~^ ERROR: using `libc::strlen` on a `CStr` value - let _ = cstr.to_bytes().len(); + let _ = cstr.count_bytes(); //~^ ERROR: using `libc::strlen` on a `CStr` value let pcstr: *const &CStr = &cstr; - let _ = unsafe { (*pcstr).to_bytes().len() }; + let _ = unsafe { (*pcstr).count_bytes() }; //~^ ERROR: using `libc::strlen` on a `CStr` value unsafe fn unsafe_identity(x: T) -> T { x } - let _ = unsafe { unsafe_identity(cstr).to_bytes().len() }; + let _ = unsafe { unsafe_identity(cstr).count_bytes() }; //~^ ERROR: using `libc::strlen` on a `CStr` value - let _ = unsafe { unsafe_identity(cstr) }.to_bytes().len(); + let _ = unsafe { unsafe_identity(cstr) }.count_bytes(); //~^ ERROR: using `libc::strlen` on a `CStr` value let f: unsafe fn(_) -> _ = unsafe_identity; - let _ = unsafe { f(cstr).to_bytes().len() }; + let _ = unsafe { f(cstr).count_bytes() }; //~^ ERROR: using `libc::strlen` on a `CStr` value } // make sure we lint types that _adjust_ to `CStr` fn adjusted(box_cstring: Box, box_cstr: Box, arc_cstring: std::sync::Arc) { - let _ = box_cstring.to_bytes().len(); + let _ = box_cstring.count_bytes(); //~^ ERROR: using `libc::strlen` on a type that dereferences to `CStr` - let _ = box_cstr.to_bytes().len(); + let _ = box_cstr.count_bytes(); //~^ ERROR: using `libc::strlen` on a type that dereferences to `CStr` - let _ = arc_cstring.to_bytes().len(); + let _ = arc_cstring.count_bytes(); //~^ ERROR: using `libc::strlen` on a type that dereferences to `CStr` } + +#[clippy::msrv = "1.78"] +fn msrv_1_78() { + let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); + let _ = cstr.to_bytes().len(); + //~^ strlen_on_c_strings + + let cstring = CString::new("foo").expect("CString::new failed"); + let _ = cstring.to_bytes().len(); + //~^ strlen_on_c_strings +} + +#[clippy::msrv = "1.79"] +fn msrv_1_79() { + let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); + let _ = cstr.count_bytes(); + //~^ strlen_on_c_strings + + let cstring = CString::new("foo").expect("CString::new failed"); + let _ = cstring.count_bytes(); + //~^ strlen_on_c_strings +} diff --git a/tests/ui/strlen_on_c_strings.rs b/tests/ui/strlen_on_c_strings.rs index 3c11c3a05269..11fbdf585064 100644 --- a/tests/ui/strlen_on_c_strings.rs +++ b/tests/ui/strlen_on_c_strings.rs @@ -44,3 +44,25 @@ fn adjusted(box_cstring: Box, box_cstr: Box, arc_cstring: std::sy let _ = unsafe { libc::strlen(arc_cstring.as_ptr()) }; //~^ ERROR: using `libc::strlen` on a type that dereferences to `CStr` } + +#[clippy::msrv = "1.78"] +fn msrv_1_78() { + let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); + let _ = unsafe { libc::strlen(cstr.as_ptr()) }; + //~^ strlen_on_c_strings + + let cstring = CString::new("foo").expect("CString::new failed"); + let _ = unsafe { libc::strlen(cstring.as_ptr()) }; + //~^ strlen_on_c_strings +} + +#[clippy::msrv = "1.79"] +fn msrv_1_79() { + let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); + let _ = unsafe { libc::strlen(cstr.as_ptr()) }; + //~^ strlen_on_c_strings + + let cstring = CString::new("foo").expect("CString::new failed"); + let _ = unsafe { libc::strlen(cstring.as_ptr()) }; + //~^ strlen_on_c_strings +} diff --git a/tests/ui/strlen_on_c_strings.stderr b/tests/ui/strlen_on_c_strings.stderr index 2b059872a2da..1f1b5ccdb0ef 100644 --- a/tests/ui/strlen_on_c_strings.stderr +++ b/tests/ui/strlen_on_c_strings.stderr @@ -2,7 +2,7 @@ error: using `libc::strlen` on a `CString` value --> tests/ui/strlen_on_c_strings.rs:10:13 | LL | let _ = unsafe { libc::strlen(cstring.as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `cstring.to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `cstring.count_bytes()` | = note: `-D clippy::strlen-on-c-strings` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::strlen_on_c_strings)]` @@ -11,55 +11,79 @@ error: using `libc::strlen` on a `CStr` value --> tests/ui/strlen_on_c_strings.rs:15:13 | LL | let _ = unsafe { libc::strlen(cstr.as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `cstr.to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `cstr.count_bytes()` error: using `libc::strlen` on a `CStr` value --> tests/ui/strlen_on_c_strings.rs:18:13 | LL | let _ = unsafe { strlen(cstr.as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `cstr.to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `cstr.count_bytes()` error: using `libc::strlen` on a `CStr` value --> tests/ui/strlen_on_c_strings.rs:22:22 | LL | let _ = unsafe { strlen((*pcstr).as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `(*pcstr).to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `(*pcstr).count_bytes()` error: using `libc::strlen` on a `CStr` value --> tests/ui/strlen_on_c_strings.rs:28:22 | LL | let _ = unsafe { strlen(unsafe_identity(cstr).as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `unsafe_identity(cstr).to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `unsafe_identity(cstr).count_bytes()` error: using `libc::strlen` on a `CStr` value --> tests/ui/strlen_on_c_strings.rs:30:13 | LL | let _ = unsafe { strlen(unsafe { unsafe_identity(cstr) }.as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `unsafe { unsafe_identity(cstr) }.to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `unsafe { unsafe_identity(cstr) }.count_bytes()` error: using `libc::strlen` on a `CStr` value --> tests/ui/strlen_on_c_strings.rs:34:22 | LL | let _ = unsafe { strlen(f(cstr).as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `f(cstr).to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `f(cstr).count_bytes()` error: using `libc::strlen` on a type that dereferences to `CStr` --> tests/ui/strlen_on_c_strings.rs:40:13 | LL | let _ = unsafe { libc::strlen(box_cstring.as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `box_cstring.to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `box_cstring.count_bytes()` error: using `libc::strlen` on a type that dereferences to `CStr` --> tests/ui/strlen_on_c_strings.rs:42:13 | LL | let _ = unsafe { libc::strlen(box_cstr.as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `box_cstr.to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `box_cstr.count_bytes()` error: using `libc::strlen` on a type that dereferences to `CStr` --> tests/ui/strlen_on_c_strings.rs:44:13 | LL | let _ = unsafe { libc::strlen(arc_cstring.as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `arc_cstring.to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `arc_cstring.count_bytes()` -error: aborting due to 10 previous errors +error: using `libc::strlen` on a `CStr` value + --> tests/ui/strlen_on_c_strings.rs:51:13 + | +LL | let _ = unsafe { libc::strlen(cstr.as_ptr()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `cstr.to_bytes().len()` + +error: using `libc::strlen` on a `CString` value + --> tests/ui/strlen_on_c_strings.rs:55:13 + | +LL | let _ = unsafe { libc::strlen(cstring.as_ptr()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `cstring.to_bytes().len()` + +error: using `libc::strlen` on a `CStr` value + --> tests/ui/strlen_on_c_strings.rs:62:13 + | +LL | let _ = unsafe { libc::strlen(cstr.as_ptr()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `cstr.count_bytes()` + +error: using `libc::strlen` on a `CString` value + --> tests/ui/strlen_on_c_strings.rs:66:13 + | +LL | let _ = unsafe { libc::strlen(cstring.as_ptr()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `cstring.count_bytes()` + +error: aborting due to 14 previous errors From 7d3bf37c4ddacf866129c90b58e0a4e7728368f2 Mon Sep 17 00:00:00 2001 From: Daedalus <16168171+RedDaedalus@users.noreply.github.com> Date: Mon, 12 Jan 2026 19:02:03 -0700 Subject: [PATCH 0779/1061] fix fallback impl for select_unpredictable intrinsic --- library/core/src/intrinsics/mod.rs | 15 +++++++++------ .../intrinsics/select-unpredictable-drop.rs | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 src/tools/miri/tests/pass/intrinsics/select-unpredictable-drop.rs diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 20f34036b25c..ac3456eb904e 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -55,7 +55,7 @@ #![allow(missing_docs)] use crate::ffi::va_list::{VaArgSafe, VaList}; -use crate::marker::{ConstParamTy, Destruct, DiscriminantKind, PointeeSized, Tuple}; +use crate::marker::{ConstParamTy, DiscriminantKind, PointeeSized, Tuple}; use crate::{mem, ptr}; mod bounds; @@ -482,11 +482,14 @@ pub const fn unlikely(b: bool) -> bool { #[rustc_nounwind] #[miri::intrinsic_fallback_is_spec] #[inline] -pub const fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T -where - T: [const] Destruct, -{ - if b { true_val } else { false_val } +pub const fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { + if b { + forget(false_val); + true_val + } else { + forget(true_val); + false_val + } } /// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited: diff --git a/src/tools/miri/tests/pass/intrinsics/select-unpredictable-drop.rs b/src/tools/miri/tests/pass/intrinsics/select-unpredictable-drop.rs new file mode 100644 index 000000000000..ecf9f4b92058 --- /dev/null +++ b/src/tools/miri/tests/pass/intrinsics/select-unpredictable-drop.rs @@ -0,0 +1,19 @@ +//! Check that `select_unpredictable` properly forgets the value it does not select. +#![feature(core_intrinsics)] +use std::cell::Cell; +use std::intrinsics::select_unpredictable; + +fn main() { + let (true_val, false_val) = (Cell::new(false), Cell::new(false)); + _ = select_unpredictable(true, TraceDrop(&true_val), TraceDrop(&false_val)); + assert!(true_val.get()); + assert!(!false_val.get()); +} + +struct TraceDrop<'a>(&'a Cell); + +impl<'a> Drop for TraceDrop<'a> { + fn drop(&mut self) { + self.0.set(true); + } +} From 41daada3bbc5d5fb10119218c3b737854a27ce61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 16 Jan 2026 09:23:00 +0100 Subject: [PATCH 0780/1061] Ship LLVM (`rust-dev`) in fast try builds again --- src/tools/opt-dist/src/main.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs index b52dab001ef5..cdbeee63d6c2 100644 --- a/src/tools/opt-dist/src/main.rs +++ b/src/tools/opt-dist/src/main.rs @@ -442,11 +442,12 @@ fn main() -> anyhow::Result<()> { // Skip components that are not needed for fast try builds to speed them up if is_fast_try_build() { log::info!("Skipping building of unimportant components for a fast try build"); + // Note for future onlookers: do not ignore rust-dev here. We need it for try builds when + // a PR makes a change to how LLVM is built. for target in [ "rust-docs", "rustc-docs", "rustc-dev", - "rust-dev", "rust-docs-json", "rust-analyzer", "rustc-src", From 035bcfa46d2892f873b59f9981999bb17f2df4a7 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Fri, 16 Jan 2026 13:54:40 +0000 Subject: [PATCH 0781/1061] remove `reason = "unstable"` from `#[unstable(...)]` --- library/std/src/os/unix/net/mod.rs | 2 +- library/std/src/os/unix/net/stream.rs | 2 +- library/std/src/os/unix/net/ucred.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/os/unix/net/mod.rs b/library/std/src/os/unix/net/mod.rs index 94523d7d1e45..a44b23a77d2d 100644 --- a/library/std/src/os/unix/net/mod.rs +++ b/library/std/src/os/unix/net/mod.rs @@ -47,5 +47,5 @@ pub use self::stream::*; target_vendor = "apple", target_os = "cygwin", ))] -#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] +#[unstable(feature = "peer_credentials_unix_socket", issue = "42839")] pub use self::ucred::*; diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index c0a8045884a5..30124d96951e 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -251,7 +251,7 @@ impl UnixStream { /// Ok(()) /// } /// ``` - #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] + #[unstable(feature = "peer_credentials_unix_socket", issue = "42839")] #[cfg(any( target_os = "android", target_os = "linux", diff --git a/library/std/src/os/unix/net/ucred.rs b/library/std/src/os/unix/net/ucred.rs index 36fb9c46b4ab..1395d2ef4be3 100644 --- a/library/std/src/os/unix/net/ucred.rs +++ b/library/std/src/os/unix/net/ucred.rs @@ -7,7 +7,7 @@ use libc::{gid_t, pid_t, uid_t}; /// Credentials for a UNIX process for credentials passing. -#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] +#[unstable(feature = "peer_credentials_unix_socket", issue = "42839")] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct UCred { /// The UID part of the peer credential. This is the effective UID of the process at the domain From 1f691f7dbd8fce50a265d43baf004d7bf2247828 Mon Sep 17 00:00:00 2001 From: Alex Celeste Date: Fri, 16 Jan 2026 12:34:51 +0000 Subject: [PATCH 0782/1061] Add missing closing brackets to THIR output. Closing brackets were missing on AdtDef, the field_types list in FruInfo, and InlineAsmExpr, breaking folding in some editors; Fields were incorrectly (?) indexed in the list for functional update syntax, showing the (implicit, irrelevant) iteration index instead of the field index; also spurious colon after Pat. --- compiler/rustc_mir_build/src/thir/print.rs | 10 +- tests/ui/thir-print/c-variadic.stdout | 4 +- tests/ui/thir-print/offset_of.stdout | 18 +- .../thir-print/thir-tree-field-expr-index.rs | 25 + .../thir-tree-field-expr-index.stdout | 921 ++++++++++++++++++ .../ui/thir-print/thir-tree-loop-match.stdout | 6 +- tests/ui/thir-print/thir-tree-match.stdout | 16 +- tests/ui/unpretty/box.stdout | 2 +- 8 files changed, 978 insertions(+), 24 deletions(-) create mode 100644 tests/ui/thir-print/thir-tree-field-expr-index.rs create mode 100644 tests/ui/thir-print/thir-tree-field-expr-index.stdout diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 2cafb73a74a4..a87257fa79bf 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -618,8 +618,8 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, format!("args: {:?}", adt_expr.args), depth_lvl + 1); print_indented!(self, format!("user_ty: {:?}", adt_expr.user_ty), depth_lvl + 1); - for (i, field_expr) in adt_expr.fields.iter().enumerate() { - print_indented!(self, format!("field {}:", i), depth_lvl + 1); + for field_expr in adt_expr.fields.iter() { + print_indented!(self, format!("field {}:", field_expr.name.as_u32()), depth_lvl + 1); self.print_expr(field_expr.expr, depth_lvl + 2); } @@ -643,6 +643,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, format!("variants: {:?}", adt_def.variants()), depth_lvl + 1); print_indented!(self, format!("flags: {:?}", adt_def.flags()), depth_lvl + 1); print_indented!(self, format!("repr: {:?}", adt_def.repr()), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); } fn print_fru_info(&mut self, fru_info: &FruInfo<'tcx>, depth_lvl: usize) { @@ -653,6 +654,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { for ty in fru_info.field_types.iter() { print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 2); } + print_indented!(self, "]", depth_lvl + 1); print_indented!(self, "}", depth_lvl); } @@ -683,7 +685,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { fn print_pat(&mut self, pat: &Pat<'tcx>, depth_lvl: usize) { let &Pat { ty, span, ref kind, ref extra } = pat; - print_indented!(self, "Pat: {", depth_lvl); + print_indented!(self, "Pat {", depth_lvl); print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1); print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); self.print_pat_extra(extra.as_deref(), depth_lvl + 1); @@ -913,6 +915,8 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, format!("options: {:?}", options), depth_lvl + 1); print_indented!(self, format!("line_spans: {:?}", line_spans), depth_lvl + 1); + + print_indented!(self, "}", depth_lvl); } fn print_inline_operand(&mut self, operand: &InlineAsmOperand<'tcx>, depth_lvl: usize) { diff --git a/tests/ui/thir-print/c-variadic.stdout b/tests/ui/thir-print/c-variadic.stdout index a3e3fa5e0008..a426902b2deb 100644 --- a/tests/ui/thir-print/c-variadic.stdout +++ b/tests/ui/thir-print/c-variadic.stdout @@ -6,7 +6,7 @@ params: [ self_kind: None hir_id: Some(HirId(DefId(0:3 ~ c_variadic[a5de]::foo).1)) param: Some( - Pat: { + Pat { ty: i32 span: $DIR/c-variadic.rs:7:26: 7:27 (#0) kind: PatKind { @@ -21,7 +21,7 @@ params: [ self_kind: None hir_id: Some(HirId(DefId(0:3 ~ c_variadic[a5de]::foo).3)) param: Some( - Pat: { + Pat { ty: std::ffi::VaList<'{erased}> span: $DIR/c-variadic.rs:7:34: 7:37 (#0) kind: PatKind { diff --git a/tests/ui/thir-print/offset_of.stdout b/tests/ui/thir-print/offset_of.stdout index 29399bb98e32..b3791a2446cb 100644 --- a/tests/ui/thir-print/offset_of.stdout +++ b/tests/ui/thir-print/offset_of.stdout @@ -27,7 +27,7 @@ body: remainder_scope: Remainder { block: 1, first_statement_index: 0} init_scope: Node(2) pattern: - Pat: { + Pat { ty: usize span: $DIR/offset_of.rs:37:9: 37:10 (#0) kind: PatKind { @@ -76,7 +76,7 @@ body: remainder_scope: Remainder { block: 1, first_statement_index: 1} init_scope: Node(12) pattern: - Pat: { + Pat { ty: usize span: $DIR/offset_of.rs:38:9: 38:10 (#0) kind: PatKind { @@ -125,7 +125,7 @@ body: remainder_scope: Remainder { block: 1, first_statement_index: 2} init_scope: Node(22) pattern: - Pat: { + Pat { ty: usize span: $DIR/offset_of.rs:39:9: 39:10 (#0) kind: PatKind { @@ -174,7 +174,7 @@ body: remainder_scope: Remainder { block: 1, first_statement_index: 3} init_scope: Node(32) pattern: - Pat: { + Pat { ty: usize span: $DIR/offset_of.rs:40:9: 40:11 (#0) kind: PatKind { @@ -223,7 +223,7 @@ body: remainder_scope: Remainder { block: 1, first_statement_index: 4} init_scope: Node(42) pattern: - Pat: { + Pat { ty: usize span: $DIR/offset_of.rs:41:9: 41:11 (#0) kind: PatKind { @@ -823,7 +823,7 @@ body: remainder_scope: Remainder { block: 1, first_statement_index: 0} init_scope: Node(2) pattern: - Pat: { + Pat { ty: usize span: $DIR/offset_of.rs:45:9: 45:11 (#0) kind: PatKind { @@ -872,7 +872,7 @@ body: remainder_scope: Remainder { block: 1, first_statement_index: 1} init_scope: Node(14) pattern: - Pat: { + Pat { ty: usize span: $DIR/offset_of.rs:46:9: 46:11 (#0) kind: PatKind { @@ -921,7 +921,7 @@ body: remainder_scope: Remainder { block: 1, first_statement_index: 2} init_scope: Node(26) pattern: - Pat: { + Pat { ty: usize span: $DIR/offset_of.rs:47:9: 47:11 (#0) kind: PatKind { @@ -970,7 +970,7 @@ body: remainder_scope: Remainder { block: 1, first_statement_index: 3} init_scope: Node(38) pattern: - Pat: { + Pat { ty: usize span: $DIR/offset_of.rs:48:9: 48:11 (#0) kind: PatKind { diff --git a/tests/ui/thir-print/thir-tree-field-expr-index.rs b/tests/ui/thir-print/thir-tree-field-expr-index.rs new file mode 100644 index 000000000000..399b78528289 --- /dev/null +++ b/tests/ui/thir-print/thir-tree-field-expr-index.rs @@ -0,0 +1,25 @@ +//@ check-pass +//@ compile-flags: -Zunpretty=thir-tree + +struct S { + a: u32, + b: u32, + c: u32, + d: u32, + e: u32, +} + +fn update(x: u32) { + let s = S { a: x, b: x, c: x, d: x, e: x }; + + S { a: x , ..s }; + S { b: x , ..s }; + S { c: x , ..s }; + S { d: x , ..s }; + S { e: x , ..s }; + + S { b: x, d: x, ..s }; + S { a: x, c: x, e: x, ..s }; +} + +fn main() {} diff --git a/tests/ui/thir-print/thir-tree-field-expr-index.stdout b/tests/ui/thir-print/thir-tree-field-expr-index.stdout new file mode 100644 index 000000000000..5bf97a185290 --- /dev/null +++ b/tests/ui/thir-print/thir-tree-field-expr-index.stdout @@ -0,0 +1,921 @@ +DefId(0:9 ~ thir_tree_field_expr_index[5059]::update): +params: [ + Param { + ty: u32 + ty_span: Some($DIR/thir-tree-field-expr-index.rs:12:14: 12:17 (#0)) + self_kind: None + hir_id: Some(HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).1)) + param: Some( + Pat { + ty: u32 + span: $DIR/thir-tree-field-expr-index.rs:12:11: 12:12 (#0) + kind: PatKind { + Binding { + name: "x" + mode: BindingMode(No, Not) + var: LocalVarId(HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).2)) + ty: u32 + is_primary: true + is_shorthand: false + subpattern: None + } + } + } + ) + } +] +body: + Expr { + ty: () + temp_scope_id: 89 + span: $DIR/thir-tree-field-expr-index.rs:12:19: 23:2 (#0) + kind: + Scope { + region_scope: Node(89) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).89) + value: + Expr { + ty: () + temp_scope_id: 89 + span: $DIR/thir-tree-field-expr-index.rs:12:19: 23:2 (#0) + kind: + Block { + targeted_by_break: false + span: $DIR/thir-tree-field-expr-index.rs:12:19: 23:2 (#0) + region_scope: Node(3) + safety_mode: Safe + stmts: [ + Stmt { + kind: Let { + remainder_scope: Remainder { block: 3, first_statement_index: 0} + init_scope: Node(4) + pattern: + Pat { + ty: S + span: $DIR/thir-tree-field-expr-index.rs:13:7: 13:8 (#0) + kind: PatKind { + Binding { + name: "s" + mode: BindingMode(No, Not) + var: LocalVarId(HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).23)) + ty: S + is_primary: true + is_shorthand: false + subpattern: None + } + } + } + , + initializer: Some( + Expr { + ty: S + temp_scope_id: 5 + span: $DIR/thir-tree-field-expr-index.rs:13:11: 13:45 (#0) + kind: + Scope { + region_scope: Node(5) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).5) + value: + Expr { + ty: S + temp_scope_id: 5 + span: $DIR/thir-tree-field-expr-index.rs:13:11: 13:45 (#0) + kind: + Adt { + adt_def: + AdtDef { + did: DefId(0:3 ~ thir_tree_field_expr_index[5059]::S) + variants: [VariantDef { def_id: DefId(0:3 ~ thir_tree_field_expr_index[5059]::S), ctor: None, name: "S", discr: Relative(0), fields: [FieldDef { did: DefId(0:4 ~ thir_tree_field_expr_index[5059]::S::a), name: "a", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:5 ~ thir_tree_field_expr_index[5059]::S::b), name: "b", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:6 ~ thir_tree_field_expr_index[5059]::S::c), name: "c", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:7 ~ thir_tree_field_expr_index[5059]::S::d), name: "d", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:8 ~ thir_tree_field_expr_index[5059]::S::e), name: "e", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }], tainted: None, flags: }] + flags: IS_STRUCT + repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 7076349371981215213 } + } + variant_index: 0 + args: [] + user_ty: None + field 0: + Expr { + ty: u32 + temp_scope_id: 8 + span: $DIR/thir-tree-field-expr-index.rs:13:18: 13:19 (#0) + kind: + Scope { + region_scope: Node(8) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).8) + value: + Expr { + ty: u32 + temp_scope_id: 8 + span: $DIR/thir-tree-field-expr-index.rs:13:18: 13:19 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).2)) + } + } + } + } + field 1: + Expr { + ty: u32 + temp_scope_id: 11 + span: $DIR/thir-tree-field-expr-index.rs:13:24: 13:25 (#0) + kind: + Scope { + region_scope: Node(11) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).11) + value: + Expr { + ty: u32 + temp_scope_id: 11 + span: $DIR/thir-tree-field-expr-index.rs:13:24: 13:25 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).2)) + } + } + } + } + field 2: + Expr { + ty: u32 + temp_scope_id: 14 + span: $DIR/thir-tree-field-expr-index.rs:13:30: 13:31 (#0) + kind: + Scope { + region_scope: Node(14) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).14) + value: + Expr { + ty: u32 + temp_scope_id: 14 + span: $DIR/thir-tree-field-expr-index.rs:13:30: 13:31 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).2)) + } + } + } + } + field 3: + Expr { + ty: u32 + temp_scope_id: 17 + span: $DIR/thir-tree-field-expr-index.rs:13:36: 13:37 (#0) + kind: + Scope { + region_scope: Node(17) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).17) + value: + Expr { + ty: u32 + temp_scope_id: 17 + span: $DIR/thir-tree-field-expr-index.rs:13:36: 13:37 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).2)) + } + } + } + } + field 4: + Expr { + ty: u32 + temp_scope_id: 20 + span: $DIR/thir-tree-field-expr-index.rs:13:42: 13:43 (#0) + kind: + Scope { + region_scope: Node(20) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).20) + value: + Expr { + ty: u32 + temp_scope_id: 20 + span: $DIR/thir-tree-field-expr-index.rs:13:42: 13:43 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).2)) + } + } + } + } + base: None + } + } + } + } + ) + else_block: None + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).22) + span: $DIR/thir-tree-field-expr-index.rs:13:3: 13:45 (#0) + } + } + Stmt { + kind: Expr { + scope: Node(31) + expr: + Expr { + ty: S + temp_scope_id: 24 + span: $DIR/thir-tree-field-expr-index.rs:15:3: 15:19 (#0) + kind: + Scope { + region_scope: Node(24) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).24) + value: + Expr { + ty: S + temp_scope_id: 24 + span: $DIR/thir-tree-field-expr-index.rs:15:3: 15:19 (#0) + kind: + Adt { + adt_def: + AdtDef { + did: DefId(0:3 ~ thir_tree_field_expr_index[5059]::S) + variants: [VariantDef { def_id: DefId(0:3 ~ thir_tree_field_expr_index[5059]::S), ctor: None, name: "S", discr: Relative(0), fields: [FieldDef { did: DefId(0:4 ~ thir_tree_field_expr_index[5059]::S::a), name: "a", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:5 ~ thir_tree_field_expr_index[5059]::S::b), name: "b", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:6 ~ thir_tree_field_expr_index[5059]::S::c), name: "c", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:7 ~ thir_tree_field_expr_index[5059]::S::d), name: "d", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:8 ~ thir_tree_field_expr_index[5059]::S::e), name: "e", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }], tainted: None, flags: }] + flags: IS_STRUCT + repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 7076349371981215213 } + } + variant_index: 0 + args: [] + user_ty: None + field 0: + Expr { + ty: u32 + temp_scope_id: 29 + span: $DIR/thir-tree-field-expr-index.rs:15:10: 15:11 (#0) + kind: + Scope { + region_scope: Node(29) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).29) + value: + Expr { + ty: u32 + temp_scope_id: 29 + span: $DIR/thir-tree-field-expr-index.rs:15:10: 15:11 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).2)) + } + } + } + } + base: + FruInfo { + base: + Expr { + ty: S + temp_scope_id: 25 + span: $DIR/thir-tree-field-expr-index.rs:15:16: 15:17 (#0) + kind: + Scope { + region_scope: Node(25) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).25) + value: + Expr { + ty: S + temp_scope_id: 25 + span: $DIR/thir-tree-field-expr-index.rs:15:16: 15:17 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).23)) + } + } + } + } + field_types: [ + ty: u32 + ty: u32 + ty: u32 + ty: u32 + ty: u32 + ] + } + } + } + } + } + } + } + Stmt { + kind: Expr { + scope: Node(39) + expr: + Expr { + ty: S + temp_scope_id: 32 + span: $DIR/thir-tree-field-expr-index.rs:16:3: 16:19 (#0) + kind: + Scope { + region_scope: Node(32) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).32) + value: + Expr { + ty: S + temp_scope_id: 32 + span: $DIR/thir-tree-field-expr-index.rs:16:3: 16:19 (#0) + kind: + Adt { + adt_def: + AdtDef { + did: DefId(0:3 ~ thir_tree_field_expr_index[5059]::S) + variants: [VariantDef { def_id: DefId(0:3 ~ thir_tree_field_expr_index[5059]::S), ctor: None, name: "S", discr: Relative(0), fields: [FieldDef { did: DefId(0:4 ~ thir_tree_field_expr_index[5059]::S::a), name: "a", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:5 ~ thir_tree_field_expr_index[5059]::S::b), name: "b", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:6 ~ thir_tree_field_expr_index[5059]::S::c), name: "c", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:7 ~ thir_tree_field_expr_index[5059]::S::d), name: "d", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:8 ~ thir_tree_field_expr_index[5059]::S::e), name: "e", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }], tainted: None, flags: }] + flags: IS_STRUCT + repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 7076349371981215213 } + } + variant_index: 0 + args: [] + user_ty: None + field 1: + Expr { + ty: u32 + temp_scope_id: 37 + span: $DIR/thir-tree-field-expr-index.rs:16:10: 16:11 (#0) + kind: + Scope { + region_scope: Node(37) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).37) + value: + Expr { + ty: u32 + temp_scope_id: 37 + span: $DIR/thir-tree-field-expr-index.rs:16:10: 16:11 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).2)) + } + } + } + } + base: + FruInfo { + base: + Expr { + ty: S + temp_scope_id: 33 + span: $DIR/thir-tree-field-expr-index.rs:16:16: 16:17 (#0) + kind: + Scope { + region_scope: Node(33) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).33) + value: + Expr { + ty: S + temp_scope_id: 33 + span: $DIR/thir-tree-field-expr-index.rs:16:16: 16:17 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).23)) + } + } + } + } + field_types: [ + ty: u32 + ty: u32 + ty: u32 + ty: u32 + ty: u32 + ] + } + } + } + } + } + } + } + Stmt { + kind: Expr { + scope: Node(47) + expr: + Expr { + ty: S + temp_scope_id: 40 + span: $DIR/thir-tree-field-expr-index.rs:17:3: 17:19 (#0) + kind: + Scope { + region_scope: Node(40) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).40) + value: + Expr { + ty: S + temp_scope_id: 40 + span: $DIR/thir-tree-field-expr-index.rs:17:3: 17:19 (#0) + kind: + Adt { + adt_def: + AdtDef { + did: DefId(0:3 ~ thir_tree_field_expr_index[5059]::S) + variants: [VariantDef { def_id: DefId(0:3 ~ thir_tree_field_expr_index[5059]::S), ctor: None, name: "S", discr: Relative(0), fields: [FieldDef { did: DefId(0:4 ~ thir_tree_field_expr_index[5059]::S::a), name: "a", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:5 ~ thir_tree_field_expr_index[5059]::S::b), name: "b", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:6 ~ thir_tree_field_expr_index[5059]::S::c), name: "c", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:7 ~ thir_tree_field_expr_index[5059]::S::d), name: "d", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:8 ~ thir_tree_field_expr_index[5059]::S::e), name: "e", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }], tainted: None, flags: }] + flags: IS_STRUCT + repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 7076349371981215213 } + } + variant_index: 0 + args: [] + user_ty: None + field 2: + Expr { + ty: u32 + temp_scope_id: 45 + span: $DIR/thir-tree-field-expr-index.rs:17:10: 17:11 (#0) + kind: + Scope { + region_scope: Node(45) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).45) + value: + Expr { + ty: u32 + temp_scope_id: 45 + span: $DIR/thir-tree-field-expr-index.rs:17:10: 17:11 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).2)) + } + } + } + } + base: + FruInfo { + base: + Expr { + ty: S + temp_scope_id: 41 + span: $DIR/thir-tree-field-expr-index.rs:17:16: 17:17 (#0) + kind: + Scope { + region_scope: Node(41) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).41) + value: + Expr { + ty: S + temp_scope_id: 41 + span: $DIR/thir-tree-field-expr-index.rs:17:16: 17:17 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).23)) + } + } + } + } + field_types: [ + ty: u32 + ty: u32 + ty: u32 + ty: u32 + ty: u32 + ] + } + } + } + } + } + } + } + Stmt { + kind: Expr { + scope: Node(55) + expr: + Expr { + ty: S + temp_scope_id: 48 + span: $DIR/thir-tree-field-expr-index.rs:18:3: 18:19 (#0) + kind: + Scope { + region_scope: Node(48) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).48) + value: + Expr { + ty: S + temp_scope_id: 48 + span: $DIR/thir-tree-field-expr-index.rs:18:3: 18:19 (#0) + kind: + Adt { + adt_def: + AdtDef { + did: DefId(0:3 ~ thir_tree_field_expr_index[5059]::S) + variants: [VariantDef { def_id: DefId(0:3 ~ thir_tree_field_expr_index[5059]::S), ctor: None, name: "S", discr: Relative(0), fields: [FieldDef { did: DefId(0:4 ~ thir_tree_field_expr_index[5059]::S::a), name: "a", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:5 ~ thir_tree_field_expr_index[5059]::S::b), name: "b", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:6 ~ thir_tree_field_expr_index[5059]::S::c), name: "c", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:7 ~ thir_tree_field_expr_index[5059]::S::d), name: "d", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:8 ~ thir_tree_field_expr_index[5059]::S::e), name: "e", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }], tainted: None, flags: }] + flags: IS_STRUCT + repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 7076349371981215213 } + } + variant_index: 0 + args: [] + user_ty: None + field 3: + Expr { + ty: u32 + temp_scope_id: 53 + span: $DIR/thir-tree-field-expr-index.rs:18:10: 18:11 (#0) + kind: + Scope { + region_scope: Node(53) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).53) + value: + Expr { + ty: u32 + temp_scope_id: 53 + span: $DIR/thir-tree-field-expr-index.rs:18:10: 18:11 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).2)) + } + } + } + } + base: + FruInfo { + base: + Expr { + ty: S + temp_scope_id: 49 + span: $DIR/thir-tree-field-expr-index.rs:18:16: 18:17 (#0) + kind: + Scope { + region_scope: Node(49) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).49) + value: + Expr { + ty: S + temp_scope_id: 49 + span: $DIR/thir-tree-field-expr-index.rs:18:16: 18:17 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).23)) + } + } + } + } + field_types: [ + ty: u32 + ty: u32 + ty: u32 + ty: u32 + ty: u32 + ] + } + } + } + } + } + } + } + Stmt { + kind: Expr { + scope: Node(63) + expr: + Expr { + ty: S + temp_scope_id: 56 + span: $DIR/thir-tree-field-expr-index.rs:19:3: 19:19 (#0) + kind: + Scope { + region_scope: Node(56) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).56) + value: + Expr { + ty: S + temp_scope_id: 56 + span: $DIR/thir-tree-field-expr-index.rs:19:3: 19:19 (#0) + kind: + Adt { + adt_def: + AdtDef { + did: DefId(0:3 ~ thir_tree_field_expr_index[5059]::S) + variants: [VariantDef { def_id: DefId(0:3 ~ thir_tree_field_expr_index[5059]::S), ctor: None, name: "S", discr: Relative(0), fields: [FieldDef { did: DefId(0:4 ~ thir_tree_field_expr_index[5059]::S::a), name: "a", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:5 ~ thir_tree_field_expr_index[5059]::S::b), name: "b", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:6 ~ thir_tree_field_expr_index[5059]::S::c), name: "c", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:7 ~ thir_tree_field_expr_index[5059]::S::d), name: "d", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:8 ~ thir_tree_field_expr_index[5059]::S::e), name: "e", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }], tainted: None, flags: }] + flags: IS_STRUCT + repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 7076349371981215213 } + } + variant_index: 0 + args: [] + user_ty: None + field 4: + Expr { + ty: u32 + temp_scope_id: 61 + span: $DIR/thir-tree-field-expr-index.rs:19:10: 19:11 (#0) + kind: + Scope { + region_scope: Node(61) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).61) + value: + Expr { + ty: u32 + temp_scope_id: 61 + span: $DIR/thir-tree-field-expr-index.rs:19:10: 19:11 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).2)) + } + } + } + } + base: + FruInfo { + base: + Expr { + ty: S + temp_scope_id: 57 + span: $DIR/thir-tree-field-expr-index.rs:19:16: 19:17 (#0) + kind: + Scope { + region_scope: Node(57) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).57) + value: + Expr { + ty: S + temp_scope_id: 57 + span: $DIR/thir-tree-field-expr-index.rs:19:16: 19:17 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).23)) + } + } + } + } + field_types: [ + ty: u32 + ty: u32 + ty: u32 + ty: u32 + ty: u32 + ] + } + } + } + } + } + } + } + Stmt { + kind: Expr { + scope: Node(74) + expr: + Expr { + ty: S + temp_scope_id: 64 + span: $DIR/thir-tree-field-expr-index.rs:21:3: 21:24 (#0) + kind: + Scope { + region_scope: Node(64) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).64) + value: + Expr { + ty: S + temp_scope_id: 64 + span: $DIR/thir-tree-field-expr-index.rs:21:3: 21:24 (#0) + kind: + Adt { + adt_def: + AdtDef { + did: DefId(0:3 ~ thir_tree_field_expr_index[5059]::S) + variants: [VariantDef { def_id: DefId(0:3 ~ thir_tree_field_expr_index[5059]::S), ctor: None, name: "S", discr: Relative(0), fields: [FieldDef { did: DefId(0:4 ~ thir_tree_field_expr_index[5059]::S::a), name: "a", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:5 ~ thir_tree_field_expr_index[5059]::S::b), name: "b", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:6 ~ thir_tree_field_expr_index[5059]::S::c), name: "c", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:7 ~ thir_tree_field_expr_index[5059]::S::d), name: "d", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:8 ~ thir_tree_field_expr_index[5059]::S::e), name: "e", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }], tainted: None, flags: }] + flags: IS_STRUCT + repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 7076349371981215213 } + } + variant_index: 0 + args: [] + user_ty: None + field 1: + Expr { + ty: u32 + temp_scope_id: 69 + span: $DIR/thir-tree-field-expr-index.rs:21:10: 21:11 (#0) + kind: + Scope { + region_scope: Node(69) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).69) + value: + Expr { + ty: u32 + temp_scope_id: 69 + span: $DIR/thir-tree-field-expr-index.rs:21:10: 21:11 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).2)) + } + } + } + } + field 3: + Expr { + ty: u32 + temp_scope_id: 72 + span: $DIR/thir-tree-field-expr-index.rs:21:16: 21:17 (#0) + kind: + Scope { + region_scope: Node(72) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).72) + value: + Expr { + ty: u32 + temp_scope_id: 72 + span: $DIR/thir-tree-field-expr-index.rs:21:16: 21:17 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).2)) + } + } + } + } + base: + FruInfo { + base: + Expr { + ty: S + temp_scope_id: 65 + span: $DIR/thir-tree-field-expr-index.rs:21:21: 21:22 (#0) + kind: + Scope { + region_scope: Node(65) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).65) + value: + Expr { + ty: S + temp_scope_id: 65 + span: $DIR/thir-tree-field-expr-index.rs:21:21: 21:22 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).23)) + } + } + } + } + field_types: [ + ty: u32 + ty: u32 + ty: u32 + ty: u32 + ty: u32 + ] + } + } + } + } + } + } + } + Stmt { + kind: Expr { + scope: Node(88) + expr: + Expr { + ty: S + temp_scope_id: 75 + span: $DIR/thir-tree-field-expr-index.rs:22:3: 22:30 (#0) + kind: + Scope { + region_scope: Node(75) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).75) + value: + Expr { + ty: S + temp_scope_id: 75 + span: $DIR/thir-tree-field-expr-index.rs:22:3: 22:30 (#0) + kind: + Adt { + adt_def: + AdtDef { + did: DefId(0:3 ~ thir_tree_field_expr_index[5059]::S) + variants: [VariantDef { def_id: DefId(0:3 ~ thir_tree_field_expr_index[5059]::S), ctor: None, name: "S", discr: Relative(0), fields: [FieldDef { did: DefId(0:4 ~ thir_tree_field_expr_index[5059]::S::a), name: "a", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:5 ~ thir_tree_field_expr_index[5059]::S::b), name: "b", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:6 ~ thir_tree_field_expr_index[5059]::S::c), name: "c", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:7 ~ thir_tree_field_expr_index[5059]::S::d), name: "d", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }, FieldDef { did: DefId(0:8 ~ thir_tree_field_expr_index[5059]::S::e), name: "e", vis: Restricted(DefId(0:0 ~ thir_tree_field_expr_index[5059])), safety: Safe, value: None }], tainted: None, flags: }] + flags: IS_STRUCT + repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 7076349371981215213 } + } + variant_index: 0 + args: [] + user_ty: None + field 0: + Expr { + ty: u32 + temp_scope_id: 80 + span: $DIR/thir-tree-field-expr-index.rs:22:10: 22:11 (#0) + kind: + Scope { + region_scope: Node(80) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).80) + value: + Expr { + ty: u32 + temp_scope_id: 80 + span: $DIR/thir-tree-field-expr-index.rs:22:10: 22:11 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).2)) + } + } + } + } + field 2: + Expr { + ty: u32 + temp_scope_id: 83 + span: $DIR/thir-tree-field-expr-index.rs:22:16: 22:17 (#0) + kind: + Scope { + region_scope: Node(83) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).83) + value: + Expr { + ty: u32 + temp_scope_id: 83 + span: $DIR/thir-tree-field-expr-index.rs:22:16: 22:17 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).2)) + } + } + } + } + field 4: + Expr { + ty: u32 + temp_scope_id: 86 + span: $DIR/thir-tree-field-expr-index.rs:22:22: 22:23 (#0) + kind: + Scope { + region_scope: Node(86) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).86) + value: + Expr { + ty: u32 + temp_scope_id: 86 + span: $DIR/thir-tree-field-expr-index.rs:22:22: 22:23 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).2)) + } + } + } + } + base: + FruInfo { + base: + Expr { + ty: S + temp_scope_id: 76 + span: $DIR/thir-tree-field-expr-index.rs:22:27: 22:28 (#0) + kind: + Scope { + region_scope: Node(76) + hir_id: HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).76) + value: + Expr { + ty: S + temp_scope_id: 76 + span: $DIR/thir-tree-field-expr-index.rs:22:27: 22:28 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:9 ~ thir_tree_field_expr_index[5059]::update).23)) + } + } + } + } + field_types: [ + ty: u32 + ty: u32 + ty: u32 + ty: u32 + ty: u32 + ] + } + } + } + } + } + } + } + ] + expr: [] + } + } + } + } + + +DefId(0:10 ~ thir_tree_field_expr_index[5059]::main): +params: [ +] +body: + Expr { + ty: () + temp_scope_id: 2 + span: $DIR/thir-tree-field-expr-index.rs:25:11: 25:13 (#0) + kind: + Scope { + region_scope: Node(2) + hir_id: HirId(DefId(0:10 ~ thir_tree_field_expr_index[5059]::main).2) + value: + Expr { + ty: () + temp_scope_id: 2 + span: $DIR/thir-tree-field-expr-index.rs:25:11: 25:13 (#0) + kind: + Block { + targeted_by_break: false + span: $DIR/thir-tree-field-expr-index.rs:25:11: 25:13 (#0) + region_scope: Node(1) + safety_mode: Safe + stmts: [] + expr: [] + } + } + } + } + + diff --git a/tests/ui/thir-print/thir-tree-loop-match.stdout b/tests/ui/thir-print/thir-tree-loop-match.stdout index 4a1b2aaf67f5..1bfd3f0952a3 100644 --- a/tests/ui/thir-print/thir-tree-loop-match.stdout +++ b/tests/ui/thir-print/thir-tree-loop-match.stdout @@ -6,7 +6,7 @@ params: [ self_kind: None hir_id: Some(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).1)) param: Some( - Pat: { + Pat { ty: bool span: $DIR/thir-tree-loop-match.rs:7:12: 7:21 (#0) kind: PatKind { @@ -117,7 +117,7 @@ body: arms: [ Arm { pattern: - Pat: { + Pat { ty: bool span: $DIR/thir-tree-loop-match.rs:12:17: 12:21 (#0) kind: PatKind { @@ -215,7 +215,7 @@ body: } Arm { pattern: - Pat: { + Pat { ty: bool span: $DIR/thir-tree-loop-match.rs:16:17: 16:22 (#0) kind: PatKind { diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout index a6d23ee204cb..31f8d368736c 100644 --- a/tests/ui/thir-print/thir-tree-match.stdout +++ b/tests/ui/thir-print/thir-tree-match.stdout @@ -6,7 +6,7 @@ params: [ self_kind: None hir_id: Some(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).1)) param: Some( - Pat: { + Pat { ty: Foo span: $DIR/thir-tree-match.rs:15:14: 15:17 (#0) kind: PatKind { @@ -85,7 +85,7 @@ body: arms: [ Arm { pattern: - Pat: { + Pat { ty: Foo span: $DIR/thir-tree-match.rs:17:9: 17:32 (#0) kind: PatKind { @@ -96,10 +96,11 @@ body: variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] flags: IS_ENUM repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 13397682652773712997 } + } args: [] variant_index: 0 subpatterns: [ - Pat: { + Pat { ty: Bar span: $DIR/thir-tree-match.rs:17:21: 17:31 (#0) kind: PatKind { @@ -110,6 +111,7 @@ body: variants: [VariantDef { def_id: DefId(0:4 ~ thir_tree_match[fcf8]::Bar::First), ctor: Some((Const, DefId(0:5 ~ thir_tree_match[fcf8]::Bar::First::{constructor#0}))), name: "First", discr: Relative(0), fields: [], tainted: None, flags: }, VariantDef { def_id: DefId(0:6 ~ thir_tree_match[fcf8]::Bar::Second), ctor: Some((Const, DefId(0:7 ~ thir_tree_match[fcf8]::Bar::Second::{constructor#0}))), name: "Second", discr: Relative(1), fields: [], tainted: None, flags: }, VariantDef { def_id: DefId(0:8 ~ thir_tree_match[fcf8]::Bar::Third), ctor: Some((Const, DefId(0:9 ~ thir_tree_match[fcf8]::Bar::Third::{constructor#0}))), name: "Third", discr: Relative(2), fields: [], tainted: None, flags: }] flags: IS_ENUM repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 7908585036048874241 } + } args: [] variant_index: 0 subpatterns: [] @@ -147,7 +149,7 @@ body: } Arm { pattern: - Pat: { + Pat { ty: Foo span: $DIR/thir-tree-match.rs:18:9: 18:23 (#0) kind: PatKind { @@ -158,10 +160,11 @@ body: variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] flags: IS_ENUM repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 13397682652773712997 } + } args: [] variant_index: 0 subpatterns: [ - Pat: { + Pat { ty: Bar span: $DIR/thir-tree-match.rs:18:21: 18:22 (#0) kind: PatKind { @@ -199,7 +202,7 @@ body: } Arm { pattern: - Pat: { + Pat { ty: Foo span: $DIR/thir-tree-match.rs:19:9: 19:20 (#0) kind: PatKind { @@ -210,6 +213,7 @@ body: variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] flags: IS_ENUM repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 13397682652773712997 } + } args: [] variant_index: 1 subpatterns: [] diff --git a/tests/ui/unpretty/box.stdout b/tests/ui/unpretty/box.stdout index 123273be4efe..2576a2aa125d 100644 --- a/tests/ui/unpretty/box.stdout +++ b/tests/ui/unpretty/box.stdout @@ -27,7 +27,7 @@ body: remainder_scope: Remainder { block: 1, first_statement_index: 0} init_scope: Node(2) pattern: - Pat: { + Pat { ty: std::boxed::Box span: $DIR/box.rs:7:9: 7:10 (#0) kind: PatKind { From 5f58acba529112e75692833212ea25ad337828ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 16 Jan 2026 04:17:24 +0000 Subject: [PATCH 0783/1061] Add `const Default` impls for `HashSet` and `HashMap` with custom `Hasher` --- library/core/src/hash/mod.rs | 3 ++- library/core/src/hash/sip.rs | 9 ++++++--- library/std/src/collections/hash/map.rs | 5 +++-- library/std/src/collections/hash/map/tests.rs | 3 +++ library/std/src/collections/hash/set.rs | 7 ++++--- library/std/src/collections/hash/set/tests.rs | 2 ++ library/std/src/hash/random.rs | 6 ++++-- 7 files changed, 24 insertions(+), 11 deletions(-) diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs index c3f3cd729425..a800e1b41fbe 100644 --- a/library/core/src/hash/mod.rs +++ b/library/core/src/hash/mod.rs @@ -784,7 +784,8 @@ impl Clone for BuildHasherDefault { } #[stable(since = "1.7.0", feature = "build_hasher")] -impl Default for BuildHasherDefault { +#[rustc_const_unstable(feature = "const_default", issue = "143894")] +impl const Default for BuildHasherDefault { fn default() -> BuildHasherDefault { Self::new() } diff --git a/library/core/src/hash/sip.rs b/library/core/src/hash/sip.rs index 4f2e8a22d180..4569c7da035d 100644 --- a/library/core/src/hash/sip.rs +++ b/library/core/src/hash/sip.rs @@ -166,16 +166,18 @@ impl SipHasher13 { /// Creates a new `SipHasher13` with the two initial keys set to 0. #[inline] #[unstable(feature = "hashmap_internals", issue = "none")] + #[rustc_const_unstable(feature = "const_default", issue = "143894")] #[deprecated(since = "1.13.0", note = "use `std::hash::DefaultHasher` instead")] - pub fn new() -> SipHasher13 { + pub const fn new() -> SipHasher13 { SipHasher13::new_with_keys(0, 0) } /// Creates a `SipHasher13` that is keyed off the provided keys. #[inline] #[unstable(feature = "hashmap_internals", issue = "none")] + #[rustc_const_unstable(feature = "const_default", issue = "143894")] #[deprecated(since = "1.13.0", note = "use `std::hash::DefaultHasher` instead")] - pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 { + pub const fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 { SipHasher13 { hasher: Hasher::new_with_keys(key0, key1) } } } @@ -338,7 +340,8 @@ impl Clone for Hasher { } } -impl Default for Hasher { +#[rustc_const_unstable(feature = "const_default", issue = "143894")] +impl const Default for Hasher { /// Creates a `Hasher` with the two initial keys set to 0. #[inline] fn default() -> Hasher { diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index ad6328f76ed6..b82beb3b8b2e 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -1444,9 +1444,10 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Default for HashMap +#[rustc_const_unstable(feature = "const_default", issue = "143894")] +impl const Default for HashMap where - S: Default, + S: [const] Default, { /// Creates an empty `HashMap`, with the `Default` value for the hasher. #[inline] diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs index 9f7df20a1d7e..cc1a9900bec9 100644 --- a/library/std/src/collections/hash/map/tests.rs +++ b/library/std/src/collections/hash/map/tests.rs @@ -1053,4 +1053,7 @@ fn const_with_hasher() { assert_eq!(y.len(), 0); y.insert((), ()); assert_eq!(y.len(), 1); + + const Z: HashMap<(), (), BuildHasherDefault> = Default::default(); + assert_eq!(X, Z); } diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index 02a4a0d9c815..3f3d601e4d30 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -1236,14 +1236,15 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Default for HashSet +#[rustc_const_unstable(feature = "const_default", issue = "143894")] +impl const Default for HashSet where - S: Default, + S: [const] Default, { /// Creates an empty `HashSet` with the `Default` value for the hasher. #[inline] fn default() -> HashSet { - HashSet { base: Default::default() } + HashSet { base: base::HashSet::with_hasher(Default::default()) } } } diff --git a/library/std/src/collections/hash/set/tests.rs b/library/std/src/collections/hash/set/tests.rs index 8ee8a3e8bf6a..d7bbc7bdc6a5 100644 --- a/library/std/src/collections/hash/set/tests.rs +++ b/library/std/src/collections/hash/set/tests.rs @@ -504,7 +504,9 @@ fn from_array() { #[test] fn const_with_hasher() { const X: HashSet<(), ()> = HashSet::with_hasher(()); + const Y: HashSet<(), ()> = Default::default(); assert_eq!(X.len(), 0); + assert_eq!(Y.len(), 0); } #[test] diff --git a/library/std/src/hash/random.rs b/library/std/src/hash/random.rs index 236803b24a2e..fab090e31f03 100644 --- a/library/std/src/hash/random.rs +++ b/library/std/src/hash/random.rs @@ -105,14 +105,16 @@ impl DefaultHasher { #[stable(feature = "hashmap_default_hasher", since = "1.13.0")] #[inline] #[allow(deprecated)] + #[rustc_const_unstable(feature = "const_default", issue = "143894")] #[must_use] - pub fn new() -> DefaultHasher { + pub const fn new() -> DefaultHasher { DefaultHasher(SipHasher13::new_with_keys(0, 0)) } } #[stable(feature = "hashmap_default_hasher", since = "1.13.0")] -impl Default for DefaultHasher { +#[rustc_const_unstable(feature = "const_default", issue = "143894")] +impl const Default for DefaultHasher { /// Creates a new `DefaultHasher` using [`new`]. /// See its documentation for more. /// From 4cb70c8e4a18c073703d3ccda8adeb2931fe4fc6 Mon Sep 17 00:00:00 2001 From: linshuy2 Date: Fri, 16 Jan 2026 03:46:38 +0000 Subject: [PATCH 0784/1061] fix: `unnecessary_sort_by` FN on field access --- .../src/methods/unnecessary_sort_by.rs | 24 ++++++++++----- tests/ui/unnecessary_sort_by.fixed | 30 +++++++++++++++++++ tests/ui/unnecessary_sort_by.rs | 30 +++++++++++++++++++ tests/ui/unnecessary_sort_by.stderr | 20 ++++++++++++- 4 files changed, 96 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs index 9dddbe814317..c7339a3bdd05 100644 --- a/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -2,12 +2,11 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; use clippy_utils::std_or_core; use clippy_utils::sugg::Sugg; -use clippy_utils::ty::implements_trait; +use clippy_utils::ty::{implements_trait, is_copy}; use rustc_errors::Applicability; use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath}; use rustc_lint::LateContext; -use rustc_middle::ty; -use rustc_middle::ty::GenericArgKind; +use rustc_middle::ty::{self, GenericArgKind, Ty}; use rustc_span::sym; use rustc_span::symbol::{Ident, Symbol}; use std::iter; @@ -70,7 +69,7 @@ fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: Ident, b_expr: &Expr<'_>, b_ident: mirrored_exprs(left_block, a_ident, right_block, b_ident) }, (ExprKind::Field(left_expr, left_ident), ExprKind::Field(right_expr, right_ident)) => { - left_ident.name == right_ident.name && mirrored_exprs(left_expr, a_ident, right_expr, right_ident) + left_ident.name == right_ident.name && mirrored_exprs(left_expr, a_ident, right_expr, b_ident) }, // Two paths: either one is a and the other is b, or they're identical to each other ( @@ -159,7 +158,11 @@ fn detect_lint<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, arg: &Expr<'_>) -> return Some(LintTrigger::Sort); } - if !expr_borrows(cx, left_expr) { + let left_expr_ty = cx.typeck_results().expr_ty(left_expr); + if !expr_borrows(left_expr_ty) + // Don't lint if the closure is accessing non-Copy fields + && (!expr_is_field_access(left_expr) || is_copy(cx, left_expr_ty)) + { return Some(LintTrigger::SortByKey(SortByKeyDetection { closure_arg, closure_body, @@ -171,11 +174,18 @@ fn detect_lint<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, arg: &Expr<'_>) -> None } -fn expr_borrows(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - let ty = cx.typeck_results().expr_ty(expr); +fn expr_borrows(ty: Ty<'_>) -> bool { matches!(ty.kind(), ty::Ref(..)) || ty.walk().any(|arg| matches!(arg.kind(), GenericArgKind::Lifetime(_))) } +fn expr_is_field_access(expr: &Expr<'_>) -> bool { + match expr.kind { + ExprKind::Field(_, _) => true, + ExprKind::AddrOf(_, Mutability::Not, inner) => expr_is_field_access(inner), + _ => false, + } +} + pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, diff --git a/tests/ui/unnecessary_sort_by.fixed b/tests/ui/unnecessary_sort_by.fixed index 5255ab173efb..372cf683f223 100644 --- a/tests/ui/unnecessary_sort_by.fixed +++ b/tests/ui/unnecessary_sort_by.fixed @@ -111,3 +111,33 @@ fn main() { issue_5754::test(); issue_6001::test(); } + +fn issue16405() { + let mut v: Vec<(i32, &str)> = vec![(1, "foo"), (2, "bar")]; + + v.sort_by_key(|a| a.0); + //~^ unnecessary_sort_by + + struct Item { + key: i32, + value: String, + } + + let mut items = vec![ + Item { + key: 2, + value: "b".to_string(), + }, + Item { + key: 1, + value: "a".to_string(), + }, + ]; + items.sort_by_key(|item1| item1.key); + //~^ unnecessary_sort_by + + items.sort_by(|item1, item2| item1.value.cmp(&item2.value)); + + items.sort_by_key(|item1| item1.value.clone()); + //~^ unnecessary_sort_by +} diff --git a/tests/ui/unnecessary_sort_by.rs b/tests/ui/unnecessary_sort_by.rs index 65db7ca3f137..7dd274623b35 100644 --- a/tests/ui/unnecessary_sort_by.rs +++ b/tests/ui/unnecessary_sort_by.rs @@ -111,3 +111,33 @@ fn main() { issue_5754::test(); issue_6001::test(); } + +fn issue16405() { + let mut v: Vec<(i32, &str)> = vec![(1, "foo"), (2, "bar")]; + + v.sort_by(|a, b| a.0.cmp(&b.0)); + //~^ unnecessary_sort_by + + struct Item { + key: i32, + value: String, + } + + let mut items = vec![ + Item { + key: 2, + value: "b".to_string(), + }, + Item { + key: 1, + value: "a".to_string(), + }, + ]; + items.sort_by(|item1, item2| item1.key.cmp(&item2.key)); + //~^ unnecessary_sort_by + + items.sort_by(|item1, item2| item1.value.cmp(&item2.value)); + + items.sort_by(|item1, item2| item1.value.clone().cmp(&item2.value.clone())); + //~^ unnecessary_sort_by +} diff --git a/tests/ui/unnecessary_sort_by.stderr b/tests/ui/unnecessary_sort_by.stderr index a066554037fe..b555245b0d01 100644 --- a/tests/ui/unnecessary_sort_by.stderr +++ b/tests/ui/unnecessary_sort_by.stderr @@ -73,5 +73,23 @@ error: consider using `sort_unstable_by_key` LL | args.sort_unstable_by(|a, b| b.name().cmp(&a.name())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_unstable_by_key(|b| std::cmp::Reverse(b.name()))` -error: aborting due to 12 previous errors +error: consider using `sort_by_key` + --> tests/ui/unnecessary_sort_by.rs:118:5 + | +LL | v.sort_by(|a, b| a.0.cmp(&b.0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.sort_by_key(|a| a.0)` + +error: consider using `sort_by_key` + --> tests/ui/unnecessary_sort_by.rs:136:5 + | +LL | items.sort_by(|item1, item2| item1.key.cmp(&item2.key)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `items.sort_by_key(|item1| item1.key)` + +error: consider using `sort_by_key` + --> tests/ui/unnecessary_sort_by.rs:141:5 + | +LL | items.sort_by(|item1, item2| item1.value.clone().cmp(&item2.value.clone())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `items.sort_by_key(|item1| item1.value.clone())` + +error: aborting due to 15 previous errors From 03fd408af5657404b1d165f7c7679918ed0f536a Mon Sep 17 00:00:00 2001 From: linshuy2 Date: Fri, 16 Jan 2026 05:08:40 +0000 Subject: [PATCH 0785/1061] Apply `unnecessary_sort_by` to Clippy itself --- clippy_utils/src/ty/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_utils/src/ty/mod.rs b/clippy_utils/src/ty/mod.rs index a90d64e972c1..979170d72006 100644 --- a/clippy_utils/src/ty/mod.rs +++ b/clippy_utils/src/ty/mod.rs @@ -824,7 +824,7 @@ impl AdtVariantInfo { } }) .collect::>(); - variants_size.sort_by(|a, b| b.size.cmp(&a.size)); + variants_size.sort_by_key(|b| std::cmp::Reverse(b.size)); variants_size } } From b7e4315b3287ba27cbaf396a0f3d7baf7c237ecd Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Thu, 15 Jan 2026 20:35:35 +0100 Subject: [PATCH 0786/1061] Do not output an error if standard output is full on --help/--version This matches rustc's behavior. --- src/driver.rs | 13 ++++++++----- src/main.rs | 17 +++++++++++------ 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/driver.rs b/src/driver.rs index 8693973ef78c..6094c8445398 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -32,11 +32,10 @@ use rustc_span::symbol::Symbol; use std::env; use std::fs::read_to_string; +use std::io::Write as _; use std::path::Path; use std::process::exit; -use anstream::println; - /// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If /// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`. fn arg_value<'a>(args: &'a [String], find_arg: &str, pred: impl Fn(&str) -> bool) -> Option<&'a str> { @@ -186,7 +185,9 @@ impl rustc_driver::Callbacks for ClippyCallbacks { } fn display_help() { - println!("{}", help_message()); + if writeln!(&mut anstream::stdout().lock(), "{}", help_message()).is_err() { + exit(rustc_driver::EXIT_FAILURE); + } } const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml"; @@ -253,8 +254,10 @@ pub fn main() { if orig_args.iter().any(|a| a == "--version" || a == "-V") { let version_info = rustc_tools_util::get_version_info!(); - println!("{version_info}"); - exit(0); + match writeln!(&mut anstream::stdout().lock(), "{version_info}") { + Ok(()) => exit(rustc_driver::EXIT_SUCCESS), + Err(_) => exit(rustc_driver::EXIT_FAILURE), + } } // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. diff --git a/src/main.rs b/src/main.rs index 688161c7bfcb..98b888444831 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,19 +4,24 @@ // warn on lints, that are included in `rust-lang/rust`s bootstrap #![warn(rust_2018_idioms, unused_lifetimes)] -use std::env; -use std::path::PathBuf; -use std::process::{self, Command}; +extern crate rustc_driver; -use anstream::println; +use std::env; +use std::io::Write as _; +use std::path::PathBuf; +use std::process::{self, Command, exit}; fn show_help() { - println!("{}", help_message()); + if writeln!(&mut anstream::stdout().lock(), "{}", help_message()).is_err() { + exit(rustc_driver::EXIT_FAILURE); + } } fn show_version() { let version_info = rustc_tools_util::get_version_info!(); - println!("{version_info}"); + if writeln!(&mut anstream::stdout().lock(), "{version_info}").is_err() { + exit(rustc_driver::EXIT_FAILURE); + } } pub fn main() { From bad82f22a9f1e1972fb5000e5e1c03fc3281aa7a Mon Sep 17 00:00:00 2001 From: tuturuu Date: Fri, 16 Jan 2026 17:51:43 +0100 Subject: [PATCH 0787/1061] move tests --- .../elided-self-lifetime-in-trait-fn.rs} | 0 .../elided-self-lifetime-in-trait-fn.stderr} | 2 +- .../struct_pattern_on_tuple_enum_in_match.rs} | 0 .../struct_pattern_on_tuple_enum_in_match.stderr} | 2 +- .../trait_more_private_than_item.rs} | 0 .../trait_more_private_than_item.stderr} | 4 ++-- .../{issues/issue-18119.rs => resolve/impl-on-non-type.rs} | 0 .../issue-18119.stderr => resolve/impl-on-non-type.stderr} | 6 +++--- .../issue-17994.rs => type-alias/unused_type_parameter.rs} | 0 .../unused_type_parameter.stderr} | 2 +- 10 files changed, 8 insertions(+), 8 deletions(-) rename tests/ui/{issues/issue-16683.rs => lifetimes/elided-self-lifetime-in-trait-fn.rs} (100%) rename tests/ui/{issues/issue-16683.stderr => lifetimes/elided-self-lifetime-in-trait-fn.stderr} (87%) rename tests/ui/{issues/issue-17405.rs => mismatched_types/struct_pattern_on_tuple_enum_in_match.rs} (100%) rename tests/ui/{issues/issue-17405.stderr => mismatched_types/struct_pattern_on_tuple_enum_in_match.stderr} (82%) rename tests/ui/{issues/issue-18389.rs => privacy/trait_more_private_than_item.rs} (100%) rename tests/ui/{issues/issue-18389.stderr => privacy/trait_more_private_than_item.stderr} (85%) rename tests/ui/{issues/issue-18119.rs => resolve/impl-on-non-type.rs} (100%) rename tests/ui/{issues/issue-18119.stderr => resolve/impl-on-non-type.stderr} (78%) rename tests/ui/{issues/issue-17994.rs => type-alias/unused_type_parameter.rs} (100%) rename tests/ui/{issues/issue-17994.stderr => type-alias/unused_type_parameter.stderr} (88%) diff --git a/tests/ui/issues/issue-16683.rs b/tests/ui/lifetimes/elided-self-lifetime-in-trait-fn.rs similarity index 100% rename from tests/ui/issues/issue-16683.rs rename to tests/ui/lifetimes/elided-self-lifetime-in-trait-fn.rs diff --git a/tests/ui/issues/issue-16683.stderr b/tests/ui/lifetimes/elided-self-lifetime-in-trait-fn.stderr similarity index 87% rename from tests/ui/issues/issue-16683.stderr rename to tests/ui/lifetimes/elided-self-lifetime-in-trait-fn.stderr index 39b22ed1f156..127f1ab99457 100644 --- a/tests/ui/issues/issue-16683.stderr +++ b/tests/ui/lifetimes/elided-self-lifetime-in-trait-fn.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/issue-16683.rs:4:9 + --> $DIR/elided-self-lifetime-in-trait-fn.rs:4:9 | LL | trait T<'a> { | -- lifetime `'a` defined here diff --git a/tests/ui/issues/issue-17405.rs b/tests/ui/mismatched_types/struct_pattern_on_tuple_enum_in_match.rs similarity index 100% rename from tests/ui/issues/issue-17405.rs rename to tests/ui/mismatched_types/struct_pattern_on_tuple_enum_in_match.rs diff --git a/tests/ui/issues/issue-17405.stderr b/tests/ui/mismatched_types/struct_pattern_on_tuple_enum_in_match.stderr similarity index 82% rename from tests/ui/issues/issue-17405.stderr rename to tests/ui/mismatched_types/struct_pattern_on_tuple_enum_in_match.stderr index 47f5bf4dc330..52da5c9b9cb3 100644 --- a/tests/ui/issues/issue-17405.stderr +++ b/tests/ui/mismatched_types/struct_pattern_on_tuple_enum_in_match.stderr @@ -1,5 +1,5 @@ error[E0574]: expected struct, variant or union type, found enum `Foo` - --> $DIR/issue-17405.rs:7:9 + --> $DIR/struct_pattern_on_tuple_enum_in_match.rs:7:9 | LL | Foo { i } => () | ^^^ not a struct, variant or union type diff --git a/tests/ui/issues/issue-18389.rs b/tests/ui/privacy/trait_more_private_than_item.rs similarity index 100% rename from tests/ui/issues/issue-18389.rs rename to tests/ui/privacy/trait_more_private_than_item.rs diff --git a/tests/ui/issues/issue-18389.stderr b/tests/ui/privacy/trait_more_private_than_item.stderr similarity index 85% rename from tests/ui/issues/issue-18389.stderr rename to tests/ui/privacy/trait_more_private_than_item.stderr index 4706d1ba1779..7ec3a1030599 100644 --- a/tests/ui/issues/issue-18389.stderr +++ b/tests/ui/privacy/trait_more_private_than_item.stderr @@ -1,5 +1,5 @@ warning: trait `Private<::P, ::R>` is more private than the item `Public` - --> $DIR/issue-18389.rs:9:1 + --> $DIR/trait_more_private_than_item.rs:9:1 | LL | / pub trait Public: Private< LL | | @@ -9,7 +9,7 @@ LL | | > { | |_^ trait `Public` is reachable at visibility `pub` | note: but trait `Private<::P, ::R>` is only usable at visibility `pub(crate)` - --> $DIR/issue-18389.rs:6:1 + --> $DIR/trait_more_private_than_item.rs:6:1 | LL | trait Private { | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/issues/issue-18119.rs b/tests/ui/resolve/impl-on-non-type.rs similarity index 100% rename from tests/ui/issues/issue-18119.rs rename to tests/ui/resolve/impl-on-non-type.rs diff --git a/tests/ui/issues/issue-18119.stderr b/tests/ui/resolve/impl-on-non-type.stderr similarity index 78% rename from tests/ui/issues/issue-18119.stderr rename to tests/ui/resolve/impl-on-non-type.stderr index ddee5a9da7a4..e29ac90b297c 100644 --- a/tests/ui/issues/issue-18119.stderr +++ b/tests/ui/resolve/impl-on-non-type.stderr @@ -1,17 +1,17 @@ error[E0573]: expected type, found constant `X` - --> $DIR/issue-18119.rs:5:6 + --> $DIR/impl-on-non-type.rs:5:6 | LL | impl X {} | ^ not a type error[E0573]: expected type, found static `Y` - --> $DIR/issue-18119.rs:7:6 + --> $DIR/impl-on-non-type.rs:7:6 | LL | impl Y {} | ^ not a type error[E0573]: expected type, found function `foo` - --> $DIR/issue-18119.rs:9:6 + --> $DIR/impl-on-non-type.rs:9:6 | LL | impl foo {} | ^^^ not a type diff --git a/tests/ui/issues/issue-17994.rs b/tests/ui/type-alias/unused_type_parameter.rs similarity index 100% rename from tests/ui/issues/issue-17994.rs rename to tests/ui/type-alias/unused_type_parameter.rs diff --git a/tests/ui/issues/issue-17994.stderr b/tests/ui/type-alias/unused_type_parameter.stderr similarity index 88% rename from tests/ui/issues/issue-17994.stderr rename to tests/ui/type-alias/unused_type_parameter.stderr index f149e5d08faa..4c9f356ebbee 100644 --- a/tests/ui/issues/issue-17994.stderr +++ b/tests/ui/type-alias/unused_type_parameter.stderr @@ -1,5 +1,5 @@ error[E0091]: type parameter `T` is never used - --> $DIR/issue-17994.rs:2:10 + --> $DIR/unused_type_parameter.rs:2:10 | LL | type Huh where T: Tr = isize; | ^ unused type parameter From 9d1a1ae298f47bbc319ae5ea8c5e6164e9ad8a46 Mon Sep 17 00:00:00 2001 From: tuturuu Date: Fri, 16 Jan 2026 18:15:09 +0100 Subject: [PATCH 0788/1061] add tests metadata, regenerate stderr --- tests/ui/lifetimes/elided-self-lifetime-in-trait-fn.rs | 1 + tests/ui/lifetimes/elided-self-lifetime-in-trait-fn.stderr | 2 +- .../struct_pattern_on_tuple_enum_in_match.rs | 1 + .../struct_pattern_on_tuple_enum_in_match.stderr | 2 +- tests/ui/privacy/trait_more_private_than_item.rs | 1 + tests/ui/privacy/trait_more_private_than_item.stderr | 4 ++-- tests/ui/resolve/impl-on-non-type.rs | 1 + tests/ui/resolve/impl-on-non-type.stderr | 6 +++--- tests/ui/type-alias/unused_type_parameter.rs | 1 + tests/ui/type-alias/unused_type_parameter.stderr | 2 +- 10 files changed, 13 insertions(+), 8 deletions(-) diff --git a/tests/ui/lifetimes/elided-self-lifetime-in-trait-fn.rs b/tests/ui/lifetimes/elided-self-lifetime-in-trait-fn.rs index 72fa21bddd18..5ac39c6f5d9b 100644 --- a/tests/ui/lifetimes/elided-self-lifetime-in-trait-fn.rs +++ b/tests/ui/lifetimes/elided-self-lifetime-in-trait-fn.rs @@ -1,3 +1,4 @@ +//! regression test for trait T<'a> { fn a(&'a self) -> &'a bool; fn b(&self) { diff --git a/tests/ui/lifetimes/elided-self-lifetime-in-trait-fn.stderr b/tests/ui/lifetimes/elided-self-lifetime-in-trait-fn.stderr index 127f1ab99457..383afaf782f9 100644 --- a/tests/ui/lifetimes/elided-self-lifetime-in-trait-fn.stderr +++ b/tests/ui/lifetimes/elided-self-lifetime-in-trait-fn.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/elided-self-lifetime-in-trait-fn.rs:4:9 + --> $DIR/elided-self-lifetime-in-trait-fn.rs:5:9 | LL | trait T<'a> { | -- lifetime `'a` defined here diff --git a/tests/ui/mismatched_types/struct_pattern_on_tuple_enum_in_match.rs b/tests/ui/mismatched_types/struct_pattern_on_tuple_enum_in_match.rs index 14781a7d3f7e..a82778841939 100644 --- a/tests/ui/mismatched_types/struct_pattern_on_tuple_enum_in_match.rs +++ b/tests/ui/mismatched_types/struct_pattern_on_tuple_enum_in_match.rs @@ -1,3 +1,4 @@ +//! regression test for enum Foo { Bar(isize) } diff --git a/tests/ui/mismatched_types/struct_pattern_on_tuple_enum_in_match.stderr b/tests/ui/mismatched_types/struct_pattern_on_tuple_enum_in_match.stderr index 52da5c9b9cb3..c9cc1580b480 100644 --- a/tests/ui/mismatched_types/struct_pattern_on_tuple_enum_in_match.stderr +++ b/tests/ui/mismatched_types/struct_pattern_on_tuple_enum_in_match.stderr @@ -1,5 +1,5 @@ error[E0574]: expected struct, variant or union type, found enum `Foo` - --> $DIR/struct_pattern_on_tuple_enum_in_match.rs:7:9 + --> $DIR/struct_pattern_on_tuple_enum_in_match.rs:8:9 | LL | Foo { i } => () | ^^^ not a struct, variant or union type diff --git a/tests/ui/privacy/trait_more_private_than_item.rs b/tests/ui/privacy/trait_more_private_than_item.rs index 0ab3f1454572..f55a494abd21 100644 --- a/tests/ui/privacy/trait_more_private_than_item.rs +++ b/tests/ui/privacy/trait_more_private_than_item.rs @@ -1,3 +1,4 @@ +//! regression test for //@ check-pass use std::any::Any; diff --git a/tests/ui/privacy/trait_more_private_than_item.stderr b/tests/ui/privacy/trait_more_private_than_item.stderr index 7ec3a1030599..03bffcd390c5 100644 --- a/tests/ui/privacy/trait_more_private_than_item.stderr +++ b/tests/ui/privacy/trait_more_private_than_item.stderr @@ -1,5 +1,5 @@ warning: trait `Private<::P, ::R>` is more private than the item `Public` - --> $DIR/trait_more_private_than_item.rs:9:1 + --> $DIR/trait_more_private_than_item.rs:10:1 | LL | / pub trait Public: Private< LL | | @@ -9,7 +9,7 @@ LL | | > { | |_^ trait `Public` is reachable at visibility `pub` | note: but trait `Private<::P, ::R>` is only usable at visibility `pub(crate)` - --> $DIR/trait_more_private_than_item.rs:6:1 + --> $DIR/trait_more_private_than_item.rs:7:1 | LL | trait Private { | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/resolve/impl-on-non-type.rs b/tests/ui/resolve/impl-on-non-type.rs index e48dc51a2c64..3db13d520f9f 100644 --- a/tests/ui/resolve/impl-on-non-type.rs +++ b/tests/ui/resolve/impl-on-non-type.rs @@ -1,3 +1,4 @@ +//! regression test for const X: u8 = 1; static Y: u8 = 1; fn foo() {} diff --git a/tests/ui/resolve/impl-on-non-type.stderr b/tests/ui/resolve/impl-on-non-type.stderr index e29ac90b297c..99cc405015b5 100644 --- a/tests/ui/resolve/impl-on-non-type.stderr +++ b/tests/ui/resolve/impl-on-non-type.stderr @@ -1,17 +1,17 @@ error[E0573]: expected type, found constant `X` - --> $DIR/impl-on-non-type.rs:5:6 + --> $DIR/impl-on-non-type.rs:6:6 | LL | impl X {} | ^ not a type error[E0573]: expected type, found static `Y` - --> $DIR/impl-on-non-type.rs:7:6 + --> $DIR/impl-on-non-type.rs:8:6 | LL | impl Y {} | ^ not a type error[E0573]: expected type, found function `foo` - --> $DIR/impl-on-non-type.rs:9:6 + --> $DIR/impl-on-non-type.rs:10:6 | LL | impl foo {} | ^^^ not a type diff --git a/tests/ui/type-alias/unused_type_parameter.rs b/tests/ui/type-alias/unused_type_parameter.rs index ab37a172eaa7..64fb98be1bf7 100644 --- a/tests/ui/type-alias/unused_type_parameter.rs +++ b/tests/ui/type-alias/unused_type_parameter.rs @@ -1,3 +1,4 @@ +//! regression test for trait Tr {} type Huh where T: Tr = isize; //~ ERROR type parameter `T` is never used fn main() {} diff --git a/tests/ui/type-alias/unused_type_parameter.stderr b/tests/ui/type-alias/unused_type_parameter.stderr index 4c9f356ebbee..a9ddbc8c5001 100644 --- a/tests/ui/type-alias/unused_type_parameter.stderr +++ b/tests/ui/type-alias/unused_type_parameter.stderr @@ -1,5 +1,5 @@ error[E0091]: type parameter `T` is never used - --> $DIR/unused_type_parameter.rs:2:10 + --> $DIR/unused_type_parameter.rs:3:10 | LL | type Huh where T: Tr = isize; | ^ unused type parameter From 4530e26f4eec47b92061d9ab3fca18ed8db97e63 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Fri, 16 Jan 2026 17:47:42 +0100 Subject: [PATCH 0789/1061] compiletest: Add `AuxCrate` struct with docs. To make the code clearer. --- src/tools/compiletest/src/directives.rs | 2 +- .../compiletest/src/directives/auxiliary.rs | 24 +++++++++++++------ src/tools/compiletest/src/runtest.rs | 8 +++---- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 624f4dd7c2b1..0263b91f50b8 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -8,8 +8,8 @@ use tracing::*; use crate::common::{CodegenBackend, Config, Debugger, FailMode, PassMode, RunFailMode, TestMode}; use crate::debuggers::{extract_cdb_version, extract_gdb_version}; -pub(crate) use crate::directives::auxiliary::AuxProps; use crate::directives::auxiliary::parse_and_update_aux; +pub(crate) use crate::directives::auxiliary::{AuxCrate, AuxProps}; use crate::directives::directive_names::{ KNOWN_DIRECTIVE_NAMES_SET, KNOWN_HTMLDOCCK_DIRECTIVE_NAMES, KNOWN_JSONDOCCK_DIRECTIVE_NAMES, }; diff --git a/src/tools/compiletest/src/directives/auxiliary.rs b/src/tools/compiletest/src/directives/auxiliary.rs index 40e2e7049c8f..1b72931949c5 100644 --- a/src/tools/compiletest/src/directives/auxiliary.rs +++ b/src/tools/compiletest/src/directives/auxiliary.rs @@ -7,6 +7,16 @@ use super::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE, PROC use crate::common::Config; use crate::directives::DirectiveLine; +/// The value of an `aux-crate` directive. +#[derive(Clone, Debug, Default)] +pub struct AuxCrate { + /// With `aux-crate: foo=bar.rs` this will be `foo`. + /// With `aux-crate: noprelude:foo=bar.rs` this will be `noprelude:foo`. + pub name: String, + /// With `aux-crate: foo=bar.rs` this will be `bar.rs`. + pub path: String, +} + /// Properties parsed from `aux-*` test directives. #[derive(Clone, Debug, Default)] pub(crate) struct AuxProps { @@ -17,7 +27,7 @@ pub(crate) struct AuxProps { pub(crate) bins: Vec, /// Similar to `builds`, but a list of NAME=somelib.rs of dependencies /// to build and pass with the `--extern` flag. - pub(crate) crates: Vec<(String, String)>, + pub(crate) crates: Vec, /// Same as `builds`, but for proc-macros. pub(crate) proc_macros: Vec, /// Similar to `builds`, but also uses the resulting dylib as a @@ -34,7 +44,7 @@ impl AuxProps { iter::empty() .chain(builds.iter().map(String::as_str)) .chain(bins.iter().map(String::as_str)) - .chain(crates.iter().map(|(_, path)| path.as_str())) + .chain(crates.iter().map(|c| c.path.as_str())) .chain(proc_macros.iter().map(String::as_str)) .chain(codegen_backend.iter().map(String::as_str)) } @@ -63,10 +73,10 @@ pub(super) fn parse_and_update_aux( } } -fn parse_aux_crate(r: String) -> (String, String) { +fn parse_aux_crate(r: String) -> AuxCrate { let mut parts = r.trim().splitn(2, '='); - ( - parts.next().expect("missing aux-crate name (e.g. log=log.rs)").to_string(), - parts.next().expect("missing aux-crate value (e.g. log=log.rs)").to_string(), - ) + AuxCrate { + name: parts.next().expect("missing aux-crate name (e.g. log=log.rs)").to_string(), + path: parts.next().expect("missing aux-crate value (e.g. log=log.rs)").to_string(), + } } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 6efdb5a99ee2..901ce8421ebf 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -18,7 +18,7 @@ use crate::common::{ TestSuite, UI_EXTENSIONS, UI_FIXED, UI_RUN_STDERR, UI_RUN_STDOUT, UI_STDERR, UI_STDOUT, UI_SVG, UI_WINDOWS_SVG, expected_output_path, incremental_dir, output_base_dir, output_base_name, }; -use crate::directives::TestProps; +use crate::directives::{AuxCrate, TestProps}; use crate::errors::{Error, ErrorKind, load_errors}; use crate::output_capture::ConsoleOut; use crate::read2::{Truncated, read2_abbreviated}; @@ -1285,9 +1285,9 @@ impl<'test> TestCx<'test> { } }; - for (aux_name, aux_path) in &self.props.aux.crates { - let aux_type = self.build_auxiliary(&aux_path, &aux_dir, None); - add_extern(rustc, aux_name, aux_path, aux_type); + for AuxCrate { name, path } in &self.props.aux.crates { + let aux_type = self.build_auxiliary(&path, &aux_dir, None); + add_extern(rustc, name, path, aux_type); } for proc_macro in &self.props.aux.proc_macros { From b323651ded6429a4205af1de65af01503dfe59eb Mon Sep 17 00:00:00 2001 From: tuturuu Date: Fri, 16 Jan 2026 20:55:37 +0100 Subject: [PATCH 0790/1061] move struct_pattern_on_tuple_enum to ui/pattern --- .../struct_pattern_on_tuple_enum.rs} | 0 .../struct_pattern_on_tuple_enum.stderr} | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/ui/{mismatched_types/struct_pattern_on_tuple_enum_in_match.rs => pattern/struct_pattern_on_tuple_enum.rs} (100%) rename tests/ui/{mismatched_types/struct_pattern_on_tuple_enum_in_match.stderr => pattern/struct_pattern_on_tuple_enum.stderr} (82%) diff --git a/tests/ui/mismatched_types/struct_pattern_on_tuple_enum_in_match.rs b/tests/ui/pattern/struct_pattern_on_tuple_enum.rs similarity index 100% rename from tests/ui/mismatched_types/struct_pattern_on_tuple_enum_in_match.rs rename to tests/ui/pattern/struct_pattern_on_tuple_enum.rs diff --git a/tests/ui/mismatched_types/struct_pattern_on_tuple_enum_in_match.stderr b/tests/ui/pattern/struct_pattern_on_tuple_enum.stderr similarity index 82% rename from tests/ui/mismatched_types/struct_pattern_on_tuple_enum_in_match.stderr rename to tests/ui/pattern/struct_pattern_on_tuple_enum.stderr index c9cc1580b480..a322b363aa9c 100644 --- a/tests/ui/mismatched_types/struct_pattern_on_tuple_enum_in_match.stderr +++ b/tests/ui/pattern/struct_pattern_on_tuple_enum.stderr @@ -1,5 +1,5 @@ error[E0574]: expected struct, variant or union type, found enum `Foo` - --> $DIR/struct_pattern_on_tuple_enum_in_match.rs:8:9 + --> $DIR/struct_pattern_on_tuple_enum.rs:8:9 | LL | Foo { i } => () | ^^^ not a struct, variant or union type From 5c85d522d0083bee0d5fd7f26868fa0e62372485 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Tue, 13 Jan 2026 09:52:36 -0800 Subject: [PATCH 0791/1061] Generate global openmp metadata to trigger llvm openmp-opt pass --- compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs | 4 ++++ tests/codegen-llvm/gpu_offload/gpu_host.rs | 2 ++ 2 files changed, 6 insertions(+) diff --git a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs index b8eb4f038216..084d40317ba8 100644 --- a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs +++ b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs @@ -55,6 +55,10 @@ impl<'ll> OffloadGlobals<'ll> { let init_ty = cx.type_func(&[], cx.type_void()); let init_rtls = declare_offload_fn(cx, "__tgt_init_all_rtls", init_ty); + // We want LLVM's openmp-opt pass to pick up and optimize this module, since it covers both + // openmp and offload optimizations. + llvm::add_module_flag_u32(cx.llmod(), llvm::ModuleFlagMergeBehavior::Max, "openmp", 51); + OffloadGlobals { launcher_fn, launcher_ty, diff --git a/tests/codegen-llvm/gpu_offload/gpu_host.rs b/tests/codegen-llvm/gpu_offload/gpu_host.rs index dcbd65b14427..27ff6f325aa0 100644 --- a/tests/codegen-llvm/gpu_offload/gpu_host.rs +++ b/tests/codegen-llvm/gpu_offload/gpu_host.rs @@ -104,3 +104,5 @@ pub fn _kernel_1(x: &mut [f32; 256]) { // CHECK-NEXT: call void @__tgt_unregister_lib(ptr nonnull %EmptyDesc) // CHECK-NEXT: ret void // CHECK-NEXT: } + +// CHECK: !{i32 7, !"openmp", i32 51} From c9bbf951c22fff8a9c1bc4cfc4c04b43bd0fe431 Mon Sep 17 00:00:00 2001 From: linshuy2 Date: Fri, 16 Jan 2026 20:22:33 +0000 Subject: [PATCH 0792/1061] Allow `unnecessary_sort_by` to lint closures with input patterns --- .../src/methods/unnecessary_sort_by.rs | 288 +++++++++++++----- clippy_utils/src/ty/mod.rs | 15 + tests/ui/unnecessary_sort_by.fixed | 32 ++ tests/ui/unnecessary_sort_by.rs | 32 ++ tests/ui/unnecessary_sort_by.stderr | 44 ++- 5 files changed, 341 insertions(+), 70 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs index c7339a3bdd05..ac13fc0b6850 100644 --- a/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -1,42 +1,51 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::std_or_core; use clippy_utils::sugg::Sugg; -use clippy_utils::ty::{implements_trait, is_copy}; +use clippy_utils::ty::{implements_trait, is_copy, peel_n_ty_refs}; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath}; use rustc_lint::LateContext; use rustc_middle::ty::{self, GenericArgKind, Ty}; -use rustc_span::sym; -use rustc_span::symbol::{Ident, Symbol}; +use rustc_span::symbol::Ident; +use rustc_span::{Span, sym}; use std::iter; +use std::ops::Not; use super::UNNECESSARY_SORT_BY; -enum LintTrigger<'tcx> { +enum LintTrigger { Sort, - SortByKey(SortByKeyDetection<'tcx>), + SortByKey(SortByKeyDetection), } -struct SortByKeyDetection<'tcx> { - closure_arg: Symbol, - closure_body: &'tcx Expr<'tcx>, +struct SortByKeyDetection { + closure_arg: Span, + closure_body: String, reverse: bool, + applicability: Applicability, } /// Detect if the two expressions are mirrored (identical, except one /// contains a and the other replaces it with b) -fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: Ident, b_expr: &Expr<'_>, b_ident: Ident) -> bool { +fn mirrored_exprs( + a_expr: &Expr<'_>, + b_expr: &Expr<'_>, + binding_map: &BindingMap, + binding_source: BindingSource, +) -> bool { match (a_expr.kind, b_expr.kind) { // Two arrays with mirrored contents - (ExprKind::Array(left_exprs), ExprKind::Array(right_exprs)) => { - iter::zip(left_exprs, right_exprs).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident)) - }, + (ExprKind::Array(left_exprs), ExprKind::Array(right_exprs)) => iter::zip(left_exprs, right_exprs) + .all(|(left, right)| mirrored_exprs(left, right, binding_map, binding_source)), // The two exprs are function calls. // Check to see that the function itself and its arguments are mirrored (ExprKind::Call(left_expr, left_args), ExprKind::Call(right_expr, right_args)) => { - mirrored_exprs(left_expr, a_ident, right_expr, b_ident) - && iter::zip(left_args, right_args).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident)) + mirrored_exprs(left_expr, right_expr, binding_map, binding_source) + && iter::zip(left_args, right_args) + .all(|(left, right)| mirrored_exprs(left, right, binding_map, binding_source)) }, // The two exprs are method calls. // Check to see that the function is the same and the arguments and receivers are mirrored @@ -45,31 +54,31 @@ fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: Ident, b_expr: &Expr<'_>, b_ident: ExprKind::MethodCall(right_segment, right_receiver, right_args, _), ) => { left_segment.ident == right_segment.ident - && iter::zip(left_args, right_args).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident)) - && mirrored_exprs(left_receiver, a_ident, right_receiver, b_ident) + && iter::zip(left_args, right_args) + .all(|(left, right)| mirrored_exprs(left, right, binding_map, binding_source)) + && mirrored_exprs(left_receiver, right_receiver, binding_map, binding_source) }, // Two tuples with mirrored contents - (ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => { - iter::zip(left_exprs, right_exprs).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident)) - }, + (ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => iter::zip(left_exprs, right_exprs) + .all(|(left, right)| mirrored_exprs(left, right, binding_map, binding_source)), // Two binary ops, which are the same operation and which have mirrored arguments (ExprKind::Binary(left_op, left_left, left_right), ExprKind::Binary(right_op, right_left, right_right)) => { left_op.node == right_op.node - && mirrored_exprs(left_left, a_ident, right_left, b_ident) - && mirrored_exprs(left_right, a_ident, right_right, b_ident) + && mirrored_exprs(left_left, right_left, binding_map, binding_source) + && mirrored_exprs(left_right, right_right, binding_map, binding_source) }, // Two unary ops, which are the same operation and which have the same argument (ExprKind::Unary(left_op, left_expr), ExprKind::Unary(right_op, right_expr)) => { - left_op == right_op && mirrored_exprs(left_expr, a_ident, right_expr, b_ident) + left_op == right_op && mirrored_exprs(left_expr, right_expr, binding_map, binding_source) }, // The two exprs are literals of some kind (ExprKind::Lit(left_lit), ExprKind::Lit(right_lit)) => left_lit.node == right_lit.node, - (ExprKind::Cast(left, _), ExprKind::Cast(right, _)) => mirrored_exprs(left, a_ident, right, b_ident), + (ExprKind::Cast(left, _), ExprKind::Cast(right, _)) => mirrored_exprs(left, right, binding_map, binding_source), (ExprKind::DropTemps(left_block), ExprKind::DropTemps(right_block)) => { - mirrored_exprs(left_block, a_ident, right_block, b_ident) + mirrored_exprs(left_block, right_block, binding_map, binding_source) }, (ExprKind::Field(left_expr, left_ident), ExprKind::Field(right_expr, right_ident)) => { - left_ident.name == right_ident.name && mirrored_exprs(left_expr, a_ident, right_expr, b_ident) + left_ident.name == right_ident.name && mirrored_exprs(left_expr, right_expr, binding_map, binding_source) }, // Two paths: either one is a and the other is b, or they're identical to each other ( @@ -89,60 +98,174 @@ fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: Ident, b_expr: &Expr<'_>, b_ident: )), ) => { (iter::zip(left_segments, right_segments).all(|(left, right)| left.ident == right.ident) - && left_segments - .iter() - .all(|seg| seg.ident != a_ident && seg.ident != b_ident)) + && left_segments.iter().all(|seg| { + !binding_map.contains_key(&BindingKey { + ident: seg.ident, + source: BindingSource::Left, + }) && !binding_map.contains_key(&BindingKey { + ident: seg.ident, + source: BindingSource::Right, + }) + })) || (left_segments.len() == 1 - && left_segments[0].ident == a_ident && right_segments.len() == 1 - && right_segments[0].ident == b_ident) + && binding_map + .get(&BindingKey { + ident: left_segments[0].ident, + source: binding_source, + }) + .is_some_and(|value| value.mirrored.ident == right_segments[0].ident)) }, // Matching expressions, but one or both is borrowed ( ExprKind::AddrOf(left_kind, Mutability::Not, left_expr), ExprKind::AddrOf(right_kind, Mutability::Not, right_expr), - ) => left_kind == right_kind && mirrored_exprs(left_expr, a_ident, right_expr, b_ident), - (_, ExprKind::AddrOf(_, Mutability::Not, right_expr)) => mirrored_exprs(a_expr, a_ident, right_expr, b_ident), - (ExprKind::AddrOf(_, Mutability::Not, left_expr), _) => mirrored_exprs(left_expr, a_ident, b_expr, b_ident), + ) => left_kind == right_kind && mirrored_exprs(left_expr, right_expr, binding_map, binding_source), + (_, ExprKind::AddrOf(_, Mutability::Not, right_expr)) => { + mirrored_exprs(a_expr, right_expr, binding_map, binding_source) + }, + (ExprKind::AddrOf(_, Mutability::Not, left_expr), _) => { + mirrored_exprs(left_expr, b_expr, binding_map, binding_source) + }, _ => false, } } -fn detect_lint<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, arg: &Expr<'_>) -> Option> { +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +enum BindingSource { + Left, + Right, +} + +impl Not for BindingSource { + type Output = BindingSource; + + fn not(self) -> Self::Output { + match self { + BindingSource::Left => BindingSource::Right, + BindingSource::Right => BindingSource::Left, + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +struct BindingKey { + /// The identifier of the binding. + ident: Ident, + /// The source of the binding. + source: BindingSource, +} + +struct BindingValue { + /// The mirrored binding. + mirrored: BindingKey, + /// The number of refs the binding is wrapped in. + n_refs: usize, +} + +/// A map from binding info to the number of refs the binding is wrapped in. +type BindingMap = FxHashMap; +/// Extract the binding pairs, if the two patterns are mirrored. The pats are assumed to be used in +/// closure inputs and thus irrefutable. +fn mapping_of_mirrored_pats(a_pat: &Pat<'_>, b_pat: &Pat<'_>) -> Option { + fn mapping_of_mirrored_pats_inner( + a_pat: &Pat<'_>, + b_pat: &Pat<'_>, + mapping: &mut BindingMap, + n_refs: usize, + ) -> bool { + match (&a_pat.kind, &b_pat.kind) { + (PatKind::Tuple(a_pats, a_dots), PatKind::Tuple(b_pats, b_dots)) => { + a_dots == b_dots + && a_pats.len() == b_pats.len() + && iter::zip(a_pats.iter(), b_pats.iter()) + .all(|(a, b)| mapping_of_mirrored_pats_inner(a, b, mapping, n_refs)) + }, + (PatKind::Binding(_, _, a_ident, _), PatKind::Binding(_, _, b_ident, _)) => { + let a_key = BindingKey { + ident: *a_ident, + source: BindingSource::Left, + }; + let b_key = BindingKey { + ident: *b_ident, + source: BindingSource::Right, + }; + let a_value = BindingValue { + mirrored: b_key, + n_refs, + }; + let b_value = BindingValue { + mirrored: a_key, + n_refs, + }; + mapping.insert(a_key, a_value); + mapping.insert(b_key, b_value); + true + }, + (PatKind::Wild, PatKind::Wild) => true, + (PatKind::TupleStruct(_, a_pats, a_dots), PatKind::TupleStruct(_, b_pats, b_dots)) => { + a_dots == b_dots + && a_pats.len() == b_pats.len() + && iter::zip(a_pats.iter(), b_pats.iter()) + .all(|(a, b)| mapping_of_mirrored_pats_inner(a, b, mapping, n_refs)) + }, + (PatKind::Struct(_, a_fields, a_rest), PatKind::Struct(_, b_fields, b_rest)) => { + a_rest == b_rest + && a_fields.len() == b_fields.len() + && iter::zip(a_fields.iter(), b_fields.iter()).all(|(a_field, b_field)| { + a_field.ident == b_field.ident + && mapping_of_mirrored_pats_inner(a_field.pat, b_field.pat, mapping, n_refs) + }) + }, + (PatKind::Ref(a_inner, _, _), PatKind::Ref(b_inner, _, _)) => { + mapping_of_mirrored_pats_inner(a_inner, b_inner, mapping, n_refs + 1) + }, + (PatKind::Slice(a_elems, None, a_rest), PatKind::Slice(b_elems, None, b_rest)) => { + a_elems.len() == b_elems.len() + && iter::zip(a_elems.iter(), b_elems.iter()) + .all(|(a, b)| mapping_of_mirrored_pats_inner(a, b, mapping, n_refs)) + && a_rest.len() == b_rest.len() + && iter::zip(a_rest.iter(), b_rest.iter()) + .all(|(a, b)| mapping_of_mirrored_pats_inner(a, b, mapping, n_refs)) + }, + _ => false, + } + } + + let mut mapping = FxHashMap::default(); + if mapping_of_mirrored_pats_inner(a_pat, b_pat, &mut mapping, 0) { + return Some(mapping); + } + + None +} + +fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>) -> Option { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) && let Some(impl_id) = cx.tcx.impl_of_assoc(method_id) && cx.tcx.type_of(impl_id).instantiate_identity().is_slice() && let ExprKind::Closure(&Closure { body, .. }) = arg.kind && let closure_body = cx.tcx.hir_body(body) - && let &[ - Param { - pat: - &Pat { - kind: PatKind::Binding(_, _, left_ident, _), - .. - }, - .. - }, - Param { - pat: - &Pat { - kind: PatKind::Binding(_, _, right_ident, _), - .. - }, - .. - }, - ] = closure_body.params + && let &[Param { pat: l_pat, .. }, Param { pat: r_pat, .. }] = closure_body.params + && let Some(binding_map) = mapping_of_mirrored_pats(l_pat, r_pat) && let ExprKind::MethodCall(method_path, left_expr, [right_expr], _) = closure_body.value.kind && method_path.ident.name == sym::cmp && let Some(ord_trait) = cx.tcx.get_diagnostic_item(sym::Ord) && cx.ty_based_def(closure_body.value).opt_parent(cx).opt_def_id() == Some(ord_trait) { - let (closure_body, closure_arg, reverse) = if mirrored_exprs(left_expr, left_ident, right_expr, right_ident) { - (left_expr, left_ident.name, false) - } else if mirrored_exprs(left_expr, right_ident, right_expr, left_ident) { - (left_expr, right_ident.name, true) + let (closure_body, closure_arg, reverse) = + if mirrored_exprs(left_expr, right_expr, &binding_map, BindingSource::Left) { + (left_expr, l_pat.span, false) + } else if mirrored_exprs(left_expr, right_expr, &binding_map, BindingSource::Right) { + (left_expr, r_pat.span, true) + } else { + return None; + }; + + let mut applicability = if reverse { + Applicability::MaybeIncorrect } else { - return None; + Applicability::MachineApplicable }; if let ExprKind::Path(QPath::Resolved( @@ -152,10 +275,39 @@ fn detect_lint<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, arg: &Expr<'_>) -> .. }, )) = left_expr.kind - && *left_name == left_ident - && implements_trait(cx, cx.typeck_results().expr_ty(left_expr), ord_trait, &[]) { - return Some(LintTrigger::Sort); + if let PatKind::Binding(_, _, left_ident, _) = l_pat.kind + && *left_name == left_ident + && implements_trait(cx, cx.typeck_results().expr_ty(left_expr), ord_trait, &[]) + { + return Some(LintTrigger::Sort); + } + + let mut left_expr_ty = cx.typeck_results().expr_ty(left_expr); + let left_ident_n_refs = binding_map + .get(&BindingKey { + ident: *left_name, + source: BindingSource::Left, + }) + .map_or(0, |value| value.n_refs); + // Peel off the outer-most ref which is introduced by the closure, if it is not already peeled + // by the pattern + if left_ident_n_refs == 0 { + (left_expr_ty, _) = peel_n_ty_refs(left_expr_ty, 1); + } + if !reverse && is_copy(cx, left_expr_ty) { + let mut closure_body = + snippet_with_applicability(cx, closure_body.span, "_", &mut applicability).to_string(); + if left_ident_n_refs == 0 { + closure_body = format!("*{closure_body}"); + } + return Some(LintTrigger::SortByKey(SortByKeyDetection { + closure_arg, + closure_body, + reverse, + applicability, + })); + } } let left_expr_ty = cx.typeck_results().expr_ty(left_expr); @@ -163,10 +315,12 @@ fn detect_lint<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, arg: &Expr<'_>) -> // Don't lint if the closure is accessing non-Copy fields && (!expr_is_field_access(left_expr) || is_copy(cx, left_expr_ty)) { + let closure_body = Sugg::hir_with_applicability(cx, closure_body, "_", &mut applicability).to_string(); return Some(LintTrigger::SortByKey(SortByKeyDetection { closure_arg, closure_body, reverse, + applicability, })); } } @@ -212,22 +366,18 @@ pub(super) fn check<'tcx>( expr.span, format!("consider using `{method}`"), |diag| { - let mut app = if trigger.reverse { - Applicability::MaybeIncorrect - } else { - Applicability::MachineApplicable - }; + let mut app = trigger.applicability; let recv = Sugg::hir_with_applicability(cx, recv, "(_)", &mut app); - let closure_body = Sugg::hir_with_applicability(cx, trigger.closure_body, "_", &mut app); let closure_body = if trigger.reverse { - format!("{std_or_core}::cmp::Reverse({closure_body})") + format!("{std_or_core}::cmp::Reverse({})", trigger.closure_body) } else { - closure_body.to_string() + trigger.closure_body }; + let closure_arg = snippet_with_applicability(cx, trigger.closure_arg, "_", &mut app); diag.span_suggestion( expr.span, "try", - format!("{recv}.{method}(|{}| {})", trigger.closure_arg, closure_body), + format!("{recv}.{method}(|{closure_arg}| {closure_body})"), app, ); }, diff --git a/clippy_utils/src/ty/mod.rs b/clippy_utils/src/ty/mod.rs index 979170d72006..a0fa5e714289 100644 --- a/clippy_utils/src/ty/mod.rs +++ b/clippy_utils/src/ty/mod.rs @@ -438,6 +438,21 @@ pub fn peel_and_count_ty_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize, Option, n: usize) -> (Ty<'_>, Option) { + let mut mutbl = None; + for _ in 0..n { + if let ty::Ref(_, dest_ty, m) = ty.kind() { + ty = *dest_ty; + mutbl.replace(mutbl.map_or(*m, |mutbl: Mutability| mutbl.min(*m))); + } else { + break; + } + } + (ty, mutbl) +} + /// Checks whether `a` and `b` are same types having same `Const` generic args, but ignores /// lifetimes. /// diff --git a/tests/ui/unnecessary_sort_by.fixed b/tests/ui/unnecessary_sort_by.fixed index 372cf683f223..6870470e74c5 100644 --- a/tests/ui/unnecessary_sort_by.fixed +++ b/tests/ui/unnecessary_sort_by.fixed @@ -141,3 +141,35 @@ fn issue16405() { items.sort_by_key(|item1| item1.value.clone()); //~^ unnecessary_sort_by } + +fn issue16348() { + let mut v: Vec<(i32, &str)> = vec![(1, "foo"), (2, "bar")]; + v.sort_by_key(|(_, s1)| *s1); + //~^ unnecessary_sort_by + + struct Foo { + bar: i32, + } + let mut v: Vec = vec![Foo { bar: 1 }, Foo { bar: 2 }]; + v.sort_by_key(|Foo { bar: b1 }| *b1); + //~^ unnecessary_sort_by + + struct Baz(i32); + let mut v: Vec = vec![Baz(1), Baz(2)]; + v.sort_by_key(|Baz(b1)| *b1); + //~^ unnecessary_sort_by + + v.sort_by_key(|&Baz(b1)| b1); + //~^ unnecessary_sort_by + + let mut v: Vec<&i32> = vec![&1, &2]; + v.sort_by_key(|&&b1| b1); + //~^ unnecessary_sort_by + + let mut v: Vec<[i32; 2]> = vec![[1, 2], [3, 4]]; + v.sort_by_key(|[a1, b1]| *a1); + //~^ unnecessary_sort_by + + v.sort_by_key(|[a1, b1]| a1 - b1); + //~^ unnecessary_sort_by +} diff --git a/tests/ui/unnecessary_sort_by.rs b/tests/ui/unnecessary_sort_by.rs index 7dd274623b35..d95306176817 100644 --- a/tests/ui/unnecessary_sort_by.rs +++ b/tests/ui/unnecessary_sort_by.rs @@ -141,3 +141,35 @@ fn issue16405() { items.sort_by(|item1, item2| item1.value.clone().cmp(&item2.value.clone())); //~^ unnecessary_sort_by } + +fn issue16348() { + let mut v: Vec<(i32, &str)> = vec![(1, "foo"), (2, "bar")]; + v.sort_by(|(_, s1), (_, s2)| s1.cmp(s2)); + //~^ unnecessary_sort_by + + struct Foo { + bar: i32, + } + let mut v: Vec = vec![Foo { bar: 1 }, Foo { bar: 2 }]; + v.sort_by(|Foo { bar: b1 }, Foo { bar: b2 }| b1.cmp(b2)); + //~^ unnecessary_sort_by + + struct Baz(i32); + let mut v: Vec = vec![Baz(1), Baz(2)]; + v.sort_by(|Baz(b1), Baz(b2)| b1.cmp(b2)); + //~^ unnecessary_sort_by + + v.sort_by(|&Baz(b1), &Baz(b2)| b1.cmp(&b2)); + //~^ unnecessary_sort_by + + let mut v: Vec<&i32> = vec![&1, &2]; + v.sort_by(|&&b1, &&b2| b1.cmp(&b2)); + //~^ unnecessary_sort_by + + let mut v: Vec<[i32; 2]> = vec![[1, 2], [3, 4]]; + v.sort_by(|[a1, b1], [a2, b2]| a1.cmp(a2)); + //~^ unnecessary_sort_by + + v.sort_by(|[a1, b1], [a2, b2]| (a1 - b1).cmp(&(a2 - b2))); + //~^ unnecessary_sort_by +} diff --git a/tests/ui/unnecessary_sort_by.stderr b/tests/ui/unnecessary_sort_by.stderr index b555245b0d01..b23d27c3729f 100644 --- a/tests/ui/unnecessary_sort_by.stderr +++ b/tests/ui/unnecessary_sort_by.stderr @@ -91,5 +91,47 @@ error: consider using `sort_by_key` LL | items.sort_by(|item1, item2| item1.value.clone().cmp(&item2.value.clone())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `items.sort_by_key(|item1| item1.value.clone())` -error: aborting due to 15 previous errors +error: consider using `sort_by_key` + --> tests/ui/unnecessary_sort_by.rs:147:5 + | +LL | v.sort_by(|(_, s1), (_, s2)| s1.cmp(s2)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.sort_by_key(|(_, s1)| *s1)` + +error: consider using `sort_by_key` + --> tests/ui/unnecessary_sort_by.rs:154:5 + | +LL | v.sort_by(|Foo { bar: b1 }, Foo { bar: b2 }| b1.cmp(b2)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.sort_by_key(|Foo { bar: b1 }| *b1)` + +error: consider using `sort_by_key` + --> tests/ui/unnecessary_sort_by.rs:159:5 + | +LL | v.sort_by(|Baz(b1), Baz(b2)| b1.cmp(b2)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.sort_by_key(|Baz(b1)| *b1)` + +error: consider using `sort_by_key` + --> tests/ui/unnecessary_sort_by.rs:162:5 + | +LL | v.sort_by(|&Baz(b1), &Baz(b2)| b1.cmp(&b2)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.sort_by_key(|&Baz(b1)| b1)` + +error: consider using `sort_by_key` + --> tests/ui/unnecessary_sort_by.rs:166:5 + | +LL | v.sort_by(|&&b1, &&b2| b1.cmp(&b2)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.sort_by_key(|&&b1| b1)` + +error: consider using `sort_by_key` + --> tests/ui/unnecessary_sort_by.rs:170:5 + | +LL | v.sort_by(|[a1, b1], [a2, b2]| a1.cmp(a2)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.sort_by_key(|[a1, b1]| *a1)` + +error: consider using `sort_by_key` + --> tests/ui/unnecessary_sort_by.rs:173:5 + | +LL | v.sort_by(|[a1, b1], [a2, b2]| (a1 - b1).cmp(&(a2 - b2))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.sort_by_key(|[a1, b1]| a1 - b1)` + +error: aborting due to 22 previous errors From 5937b8ba10651eef9e328c6d6f054ba09726ead2 Mon Sep 17 00:00:00 2001 From: linshuy2 Date: Fri, 16 Jan 2026 20:33:32 +0000 Subject: [PATCH 0793/1061] Apply `unnecessary_sort_by` to Clippy itself --- clippy_utils/src/ty/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_utils/src/ty/mod.rs b/clippy_utils/src/ty/mod.rs index a0fa5e714289..747dc1f13ab5 100644 --- a/clippy_utils/src/ty/mod.rs +++ b/clippy_utils/src/ty/mod.rs @@ -830,7 +830,7 @@ impl AdtVariantInfo { .enumerate() .map(|(i, f)| (i, approx_ty_size(cx, f.ty(cx.tcx, subst)))) .collect::>(); - fields_size.sort_by(|(_, a_size), (_, b_size)| a_size.cmp(b_size)); + fields_size.sort_by_key(|(_, a_size)| *a_size); Self { ind: i, From 500c94f94517a7bf2df86e04bb900ab35aca1678 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Fri, 16 Jan 2026 15:45:53 -0500 Subject: [PATCH 0794/1061] Update cargo submodule --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 6d1bd93c47f0..85eff7c80277 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 6d1bd93c47f059ec1344cb31e68a2fb284cbc6b1 +Subproject commit 85eff7c80277b57f78b11e28d14154ab12fcf643 From 196c098d24f54b661f76c2f9a3e1d74b8a5ce9b7 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Fri, 16 Jan 2026 22:42:53 +0100 Subject: [PATCH 0795/1061] `unnecessary_sort_by`: reduce suggestion diffs Now, only `call_span` is replaced, so the receiver is not a part of the diff. This also removes the need to create a snippet for the receiver. --- clippy_lints/src/methods/mod.rs | 4 +- .../src/methods/unnecessary_sort_by.rs | 18 +- tests/ui/unnecessary_sort_by.stderr | 175 +++++++++++++++--- tests/ui/unnecessary_sort_by_no_std.stderr | 15 +- 4 files changed, 178 insertions(+), 34 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 659a704a1ecb..376e93aa7e7d 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -5532,10 +5532,10 @@ impl Methods { stable_sort_primitive::check(cx, expr, recv); }, (sym::sort_by, [arg]) => { - unnecessary_sort_by::check(cx, expr, recv, arg, false); + unnecessary_sort_by::check(cx, expr, call_span, arg, false); }, (sym::sort_unstable_by, [arg]) => { - unnecessary_sort_by::check(cx, expr, recv, arg, true); + unnecessary_sort_by::check(cx, expr, call_span, arg, true); }, (sym::split, [arg]) => { str_split::check(cx, expr, recv, arg); diff --git a/clippy_lints/src/methods/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs index ac13fc0b6850..3f81a6ecd2f8 100644 --- a/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -343,7 +343,7 @@ fn expr_is_field_access(expr: &Expr<'_>) -> bool { pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, - recv: &'tcx Expr<'_>, + call_span: Span, arg: &'tcx Expr<'_>, is_unstable: bool, ) { @@ -367,17 +367,16 @@ pub(super) fn check<'tcx>( format!("consider using `{method}`"), |diag| { let mut app = trigger.applicability; - let recv = Sugg::hir_with_applicability(cx, recv, "(_)", &mut app); let closure_body = if trigger.reverse { format!("{std_or_core}::cmp::Reverse({})", trigger.closure_body) } else { trigger.closure_body }; let closure_arg = snippet_with_applicability(cx, trigger.closure_arg, "_", &mut app); - diag.span_suggestion( - expr.span, + diag.span_suggestion_verbose( + call_span, "try", - format!("{recv}.{method}(|{closure_arg}| {closure_body})"), + format!("{method}(|{closure_arg}| {closure_body})"), app, ); }, @@ -391,9 +390,12 @@ pub(super) fn check<'tcx>( expr.span, format!("consider using `{method}`"), |diag| { - let mut app = Applicability::MachineApplicable; - let recv = Sugg::hir_with_applicability(cx, recv, "(_)", &mut app); - diag.span_suggestion(expr.span, "try", format!("{recv}.{method}()"), app); + diag.span_suggestion_verbose( + call_span, + "try", + format!("{method}()"), + Applicability::MachineApplicable, + ); }, ); }, diff --git a/tests/ui/unnecessary_sort_by.stderr b/tests/ui/unnecessary_sort_by.stderr index b23d27c3729f..cc545d604ff3 100644 --- a/tests/ui/unnecessary_sort_by.stderr +++ b/tests/ui/unnecessary_sort_by.stderr @@ -2,136 +2,267 @@ error: consider using `sort` --> tests/ui/unnecessary_sort_by.rs:12:5 | LL | vec.sort_by(|a, b| a.cmp(b)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unnecessary-sort-by` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_sort_by)]` +help: try + | +LL - vec.sort_by(|a, b| a.cmp(b)); +LL + vec.sort(); + | error: consider using `sort_unstable` --> tests/ui/unnecessary_sort_by.rs:14:5 | LL | vec.sort_unstable_by(|a, b| a.cmp(b)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - vec.sort_unstable_by(|a, b| a.cmp(b)); +LL + vec.sort_unstable(); + | error: consider using `sort_by_key` --> tests/ui/unnecessary_sort_by.rs:16:5 | LL | vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| (a + 5).abs())` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs())); +LL + vec.sort_by_key(|a| (a + 5).abs()); + | error: consider using `sort_unstable_by_key` --> tests/ui/unnecessary_sort_by.rs:18:5 | LL | vec.sort_unstable_by(|a, b| id(-a).cmp(&id(-b))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|a| id(-a))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - vec.sort_unstable_by(|a, b| id(-a).cmp(&id(-b))); +LL + vec.sort_unstable_by_key(|a| id(-a)); + | error: consider using `sort_by_key` --> tests/ui/unnecessary_sort_by.rs:22:5 | LL | vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|b| std::cmp::Reverse((b + 5).abs()))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs())); +LL + vec.sort_by_key(|b| std::cmp::Reverse((b + 5).abs())); + | error: consider using `sort_unstable_by_key` --> tests/ui/unnecessary_sort_by.rs:24:5 | LL | vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|b| std::cmp::Reverse(id(-b)))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a))); +LL + vec.sort_unstable_by_key(|b| std::cmp::Reverse(id(-b))); + | error: consider using `sort_by_key` --> tests/ui/unnecessary_sort_by.rs:35:5 | LL | vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| (***a).abs())` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs())); +LL + vec.sort_by_key(|a| (***a).abs()); + | error: consider using `sort_unstable_by_key` --> tests/ui/unnecessary_sort_by.rs:37:5 | LL | vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|a| (***a).abs())` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs())); +LL + vec.sort_unstable_by_key(|a| (***a).abs()); + | error: consider using `sort_by_key` --> tests/ui/unnecessary_sort_by.rs:97:9 | LL | args.sort_by(|a, b| a.name().cmp(&b.name())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_by_key(|a| a.name())` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - args.sort_by(|a, b| a.name().cmp(&b.name())); +LL + args.sort_by_key(|a| a.name()); + | error: consider using `sort_unstable_by_key` --> tests/ui/unnecessary_sort_by.rs:99:9 | LL | args.sort_unstable_by(|a, b| a.name().cmp(&b.name())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_unstable_by_key(|a| a.name())` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - args.sort_unstable_by(|a, b| a.name().cmp(&b.name())); +LL + args.sort_unstable_by_key(|a| a.name()); + | error: consider using `sort_by_key` --> tests/ui/unnecessary_sort_by.rs:102:9 | LL | args.sort_by(|a, b| b.name().cmp(&a.name())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_by_key(|b| std::cmp::Reverse(b.name()))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - args.sort_by(|a, b| b.name().cmp(&a.name())); +LL + args.sort_by_key(|b| std::cmp::Reverse(b.name())); + | error: consider using `sort_unstable_by_key` --> tests/ui/unnecessary_sort_by.rs:104:9 | LL | args.sort_unstable_by(|a, b| b.name().cmp(&a.name())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_unstable_by_key(|b| std::cmp::Reverse(b.name()))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - args.sort_unstable_by(|a, b| b.name().cmp(&a.name())); +LL + args.sort_unstable_by_key(|b| std::cmp::Reverse(b.name())); + | error: consider using `sort_by_key` --> tests/ui/unnecessary_sort_by.rs:118:5 | LL | v.sort_by(|a, b| a.0.cmp(&b.0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.sort_by_key(|a| a.0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - v.sort_by(|a, b| a.0.cmp(&b.0)); +LL + v.sort_by_key(|a| a.0); + | error: consider using `sort_by_key` --> tests/ui/unnecessary_sort_by.rs:136:5 | LL | items.sort_by(|item1, item2| item1.key.cmp(&item2.key)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `items.sort_by_key(|item1| item1.key)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - items.sort_by(|item1, item2| item1.key.cmp(&item2.key)); +LL + items.sort_by_key(|item1| item1.key); + | error: consider using `sort_by_key` --> tests/ui/unnecessary_sort_by.rs:141:5 | LL | items.sort_by(|item1, item2| item1.value.clone().cmp(&item2.value.clone())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `items.sort_by_key(|item1| item1.value.clone())` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - items.sort_by(|item1, item2| item1.value.clone().cmp(&item2.value.clone())); +LL + items.sort_by_key(|item1| item1.value.clone()); + | error: consider using `sort_by_key` --> tests/ui/unnecessary_sort_by.rs:147:5 | LL | v.sort_by(|(_, s1), (_, s2)| s1.cmp(s2)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.sort_by_key(|(_, s1)| *s1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - v.sort_by(|(_, s1), (_, s2)| s1.cmp(s2)); +LL + v.sort_by_key(|(_, s1)| *s1); + | error: consider using `sort_by_key` --> tests/ui/unnecessary_sort_by.rs:154:5 | LL | v.sort_by(|Foo { bar: b1 }, Foo { bar: b2 }| b1.cmp(b2)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.sort_by_key(|Foo { bar: b1 }| *b1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - v.sort_by(|Foo { bar: b1 }, Foo { bar: b2 }| b1.cmp(b2)); +LL + v.sort_by_key(|Foo { bar: b1 }| *b1); + | error: consider using `sort_by_key` --> tests/ui/unnecessary_sort_by.rs:159:5 | LL | v.sort_by(|Baz(b1), Baz(b2)| b1.cmp(b2)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.sort_by_key(|Baz(b1)| *b1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - v.sort_by(|Baz(b1), Baz(b2)| b1.cmp(b2)); +LL + v.sort_by_key(|Baz(b1)| *b1); + | error: consider using `sort_by_key` --> tests/ui/unnecessary_sort_by.rs:162:5 | LL | v.sort_by(|&Baz(b1), &Baz(b2)| b1.cmp(&b2)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.sort_by_key(|&Baz(b1)| b1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - v.sort_by(|&Baz(b1), &Baz(b2)| b1.cmp(&b2)); +LL + v.sort_by_key(|&Baz(b1)| b1); + | error: consider using `sort_by_key` --> tests/ui/unnecessary_sort_by.rs:166:5 | LL | v.sort_by(|&&b1, &&b2| b1.cmp(&b2)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.sort_by_key(|&&b1| b1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - v.sort_by(|&&b1, &&b2| b1.cmp(&b2)); +LL + v.sort_by_key(|&&b1| b1); + | error: consider using `sort_by_key` --> tests/ui/unnecessary_sort_by.rs:170:5 | LL | v.sort_by(|[a1, b1], [a2, b2]| a1.cmp(a2)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.sort_by_key(|[a1, b1]| *a1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - v.sort_by(|[a1, b1], [a2, b2]| a1.cmp(a2)); +LL + v.sort_by_key(|[a1, b1]| *a1); + | error: consider using `sort_by_key` --> tests/ui/unnecessary_sort_by.rs:173:5 | LL | v.sort_by(|[a1, b1], [a2, b2]| (a1 - b1).cmp(&(a2 - b2))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.sort_by_key(|[a1, b1]| a1 - b1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - v.sort_by(|[a1, b1], [a2, b2]| (a1 - b1).cmp(&(a2 - b2))); +LL + v.sort_by_key(|[a1, b1]| a1 - b1); + | error: aborting due to 22 previous errors diff --git a/tests/ui/unnecessary_sort_by_no_std.stderr b/tests/ui/unnecessary_sort_by_no_std.stderr index de3ef4123514..b4dd6a6dbdc5 100644 --- a/tests/ui/unnecessary_sort_by_no_std.stderr +++ b/tests/ui/unnecessary_sort_by_no_std.stderr @@ -2,16 +2,27 @@ error: consider using `sort_by_key` --> tests/ui/unnecessary_sort_by_no_std.rs:10:5 | LL | vec.sort_by(|a, b| (a + 1).cmp(&(b + 1))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| a + 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unnecessary-sort-by` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_sort_by)]` +help: try + | +LL - vec.sort_by(|a, b| (a + 1).cmp(&(b + 1))); +LL + vec.sort_by_key(|a| a + 1); + | error: consider using `sort_by_key` --> tests/ui/unnecessary_sort_by_no_std.rs:19:5 | LL | vec.sort_by(|a, b| (b + 1).cmp(&(a + 1))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|b| core::cmp::Reverse(b + 1))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - vec.sort_by(|a, b| (b + 1).cmp(&(a + 1))); +LL + vec.sort_by_key(|b| core::cmp::Reverse(b + 1)); + | error: aborting due to 2 previous errors From bcde8c10707c521480d1beb1bf4dd0fc72cc3902 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sat, 17 Jan 2026 00:00:06 +0100 Subject: [PATCH 0796/1061] Do not consider binary operators as commutative by default Only `==` (and thus `!=`) are supposed to be commutative according to Rust's documentation. Do not make assumptions about other operators whose meaning may depend on the types on which they apply. However, special-case operators known to be commutative for primitive types such as addition or multiplication. --- clippy_utils/src/hir_utils.rs | 31 ++-- tests/ui/if_same_then_else.rs | 84 +++++++++-- tests/ui/if_same_then_else.stderr | 230 ++++++++++++++++++++++++++++-- 3 files changed, 309 insertions(+), 36 deletions(-) diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index bdc1550d69b7..79994d8a3c23 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -505,7 +505,7 @@ impl HirEqInterExpr<'_, '_, '_> { (ExprKind::Block(l, _), ExprKind::Block(r, _)) => self.eq_block(l, r), (ExprKind::Binary(l_op, ll, lr), ExprKind::Binary(r_op, rl, rr)) => { l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) - || swap_binop(l_op.node, ll, lr).is_some_and(|(l_op, ll, lr)| { + || swap_binop(self.inner.cx, l_op.node, ll, lr).is_some_and(|(l_op, ll, lr)| { l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) }) }, @@ -939,26 +939,35 @@ fn reduce_exprkind<'hir>(cx: &LateContext<'_>, kind: &'hir ExprKind<'hir>) -> &' } fn swap_binop<'a>( + cx: &LateContext<'_>, binop: BinOpKind, lhs: &'a Expr<'a>, rhs: &'a Expr<'a>, ) -> Option<(BinOpKind, &'a Expr<'a>, &'a Expr<'a>)> { match binop { - BinOpKind::Add | BinOpKind::Eq | BinOpKind::Ne | BinOpKind::BitAnd | BinOpKind::BitXor | BinOpKind::BitOr => { - Some((binop, rhs, lhs)) - }, + // `==` and `!=`, are commutative + BinOpKind::Eq | BinOpKind::Ne => Some((binop, rhs, lhs)), + // Comparisons can be reversed BinOpKind::Lt => Some((BinOpKind::Gt, rhs, lhs)), BinOpKind::Le => Some((BinOpKind::Ge, rhs, lhs)), BinOpKind::Ge => Some((BinOpKind::Le, rhs, lhs)), BinOpKind::Gt => Some((BinOpKind::Lt, rhs, lhs)), - BinOpKind::Mul // Not always commutative, e.g. with matrices. See issue #5698 - | BinOpKind::Shl - | BinOpKind::Shr - | BinOpKind::Rem - | BinOpKind::Sub - | BinOpKind::Div + // Non-commutative operators + BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Rem | BinOpKind::Sub | BinOpKind::Div => None, + // We know that those operators are commutative for primitive types, + // and we don't assume anything for other types + BinOpKind::Mul + | BinOpKind::Add | BinOpKind::And - | BinOpKind::Or => None, + | BinOpKind::Or + | BinOpKind::BitAnd + | BinOpKind::BitXor + | BinOpKind::BitOr => cx + .typeck_results() + .expr_ty_adjusted(lhs) + .peel_refs() + .is_primitive() + .then_some((binop, rhs, lhs)), } } diff --git a/tests/ui/if_same_then_else.rs b/tests/ui/if_same_then_else.rs index 6d2e63e7299a..6e0e2c5ea720 100644 --- a/tests/ui/if_same_then_else.rs +++ b/tests/ui/if_same_then_else.rs @@ -11,6 +11,8 @@ unreachable_code )] +use std::ops::*; + struct Foo { bar: u8, } @@ -133,18 +135,6 @@ fn func() { fn f(val: &[u8]) {} -mod issue_5698 { - fn mul_not_always_commutative(x: i32, y: i32) -> i32 { - if x == 42 { - x * y - } else if x == 21 { - y * x - } else { - 0 - } - } -} - mod issue_8836 { fn do_not_lint() { if true { @@ -245,3 +235,73 @@ mod issue_11213 { } fn main() {} + +fn issue16416(x: bool, a: T, b: T) +where + T: Add + Sub + Mul + Div + Rem + BitAnd + BitOr + BitXor + PartialEq + Eq + PartialOrd + Ord + Shr + Shl + Copy, +{ + // Non-guaranteed-commutative operators + _ = if x { a * b } else { b * a }; + _ = if x { a + b } else { b + a }; + _ = if x { a - b } else { b - a }; + _ = if x { a / b } else { b / a }; + _ = if x { a % b } else { b % a }; + _ = if x { a << b } else { b << a }; + _ = if x { a >> b } else { b >> a }; + _ = if x { a & b } else { b & a }; + _ = if x { a ^ b } else { b ^ a }; + _ = if x { a | b } else { b | a }; + + // Guaranteed commutative operators + //~v if_same_then_else + _ = if x { a == b } else { b == a }; + //~v if_same_then_else + _ = if x { a != b } else { b != a }; + + // Symetric operators + //~v if_same_then_else + _ = if x { a < b } else { b > a }; + //~v if_same_then_else + _ = if x { a <= b } else { b >= a }; + //~v if_same_then_else + _ = if x { a > b } else { b < a }; + //~v if_same_then_else + _ = if x { a >= b } else { b <= a }; +} + +fn issue16416_prim(x: bool, a: u32, b: u32) { + // Non-commutative operators + _ = if x { a - b } else { b - a }; + _ = if x { a / b } else { b / a }; + _ = if x { a % b } else { b % a }; + _ = if x { a << b } else { b << a }; + _ = if x { a >> b } else { b >> a }; + + // Commutative operators on primitive types + //~v if_same_then_else + _ = if x { a * b } else { b * a }; + //~v if_same_then_else + _ = if x { a + b } else { b + a }; + //~v if_same_then_else + _ = if x { a & b } else { b & a }; + //~v if_same_then_else + _ = if x { a ^ b } else { b ^ a }; + //~v if_same_then_else + _ = if x { a | b } else { b | a }; + + // Always commutative operators + //~v if_same_then_else + _ = if x { a == b } else { b == a }; + //~v if_same_then_else + _ = if x { a != b } else { b != a }; + + // Symetric operators + //~v if_same_then_else + _ = if x { a < b } else { b > a }; + //~v if_same_then_else + _ = if x { a <= b } else { b >= a }; + //~v if_same_then_else + _ = if x { a > b } else { b < a }; + //~v if_same_then_else + _ = if x { a >= b } else { b <= a }; +} diff --git a/tests/ui/if_same_then_else.stderr b/tests/ui/if_same_then_else.stderr index b76da3fb1cb5..57396a566941 100644 --- a/tests/ui/if_same_then_else.stderr +++ b/tests/ui/if_same_then_else.stderr @@ -1,5 +1,5 @@ error: this `if` has identical blocks - --> tests/ui/if_same_then_else.rs:23:13 + --> tests/ui/if_same_then_else.rs:25:13 | LL | if true { | _____________^ @@ -12,7 +12,7 @@ LL | | } else { | |_____^ | note: same as this - --> tests/ui/if_same_then_else.rs:31:12 + --> tests/ui/if_same_then_else.rs:33:12 | LL | } else { | ____________^ @@ -27,43 +27,43 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::if_same_then_else)]` error: this `if` has identical blocks - --> tests/ui/if_same_then_else.rs:67:21 + --> tests/ui/if_same_then_else.rs:69:21 | LL | let _ = if true { 0.0 } else { 0.0 }; | ^^^^^^^ | note: same as this - --> tests/ui/if_same_then_else.rs:67:34 + --> tests/ui/if_same_then_else.rs:69:34 | LL | let _ = if true { 0.0 } else { 0.0 }; | ^^^^^^^ error: this `if` has identical blocks - --> tests/ui/if_same_then_else.rs:70:21 + --> tests/ui/if_same_then_else.rs:72:21 | LL | let _ = if true { -0.0 } else { -0.0 }; | ^^^^^^^^ | note: same as this - --> tests/ui/if_same_then_else.rs:70:35 + --> tests/ui/if_same_then_else.rs:72:35 | LL | let _ = if true { -0.0 } else { -0.0 }; | ^^^^^^^^ error: this `if` has identical blocks - --> tests/ui/if_same_then_else.rs:82:21 + --> tests/ui/if_same_then_else.rs:84:21 | LL | let _ = if true { 42 } else { 42 }; | ^^^^^^ | note: same as this - --> tests/ui/if_same_then_else.rs:82:33 + --> tests/ui/if_same_then_else.rs:84:33 | LL | let _ = if true { 42 } else { 42 }; | ^^^^^^ error: this `if` has identical blocks - --> tests/ui/if_same_then_else.rs:85:13 + --> tests/ui/if_same_then_else.rs:87:13 | LL | if true { | _____________^ @@ -76,7 +76,7 @@ LL | | } else { | |_____^ | note: same as this - --> tests/ui/if_same_then_else.rs:92:12 + --> tests/ui/if_same_then_else.rs:94:12 | LL | } else { | ____________^ @@ -89,7 +89,7 @@ LL | | } | |_____^ error: this `if` has identical blocks - --> tests/ui/if_same_then_else.rs:238:14 + --> tests/ui/if_same_then_else.rs:228:14 | LL | if x { | ______________^ @@ -98,7 +98,7 @@ LL | | } else { | |_________^ | note: same as this - --> tests/ui/if_same_then_else.rs:240:16 + --> tests/ui/if_same_then_else.rs:230:16 | LL | } else { | ________________^ @@ -106,5 +106,209 @@ LL | | 0_u8.is_power_of_two() LL | | } | |_________^ -error: aborting due to 6 previous errors +error: this `if` has identical blocks + --> tests/ui/if_same_then_else.rs:257:14 + | +LL | _ = if x { a == b } else { b == a }; + | ^^^^^^^^^^ + | +note: same as this + --> tests/ui/if_same_then_else.rs:257:30 + | +LL | _ = if x { a == b } else { b == a }; + | ^^^^^^^^^^ + +error: this `if` has identical blocks + --> tests/ui/if_same_then_else.rs:259:14 + | +LL | _ = if x { a != b } else { b != a }; + | ^^^^^^^^^^ + | +note: same as this + --> tests/ui/if_same_then_else.rs:259:30 + | +LL | _ = if x { a != b } else { b != a }; + | ^^^^^^^^^^ + +error: this `if` has identical blocks + --> tests/ui/if_same_then_else.rs:263:14 + | +LL | _ = if x { a < b } else { b > a }; + | ^^^^^^^^^ + | +note: same as this + --> tests/ui/if_same_then_else.rs:263:29 + | +LL | _ = if x { a < b } else { b > a }; + | ^^^^^^^^^ + +error: this `if` has identical blocks + --> tests/ui/if_same_then_else.rs:265:14 + | +LL | _ = if x { a <= b } else { b >= a }; + | ^^^^^^^^^^ + | +note: same as this + --> tests/ui/if_same_then_else.rs:265:30 + | +LL | _ = if x { a <= b } else { b >= a }; + | ^^^^^^^^^^ + +error: this `if` has identical blocks + --> tests/ui/if_same_then_else.rs:267:14 + | +LL | _ = if x { a > b } else { b < a }; + | ^^^^^^^^^ + | +note: same as this + --> tests/ui/if_same_then_else.rs:267:29 + | +LL | _ = if x { a > b } else { b < a }; + | ^^^^^^^^^ + +error: this `if` has identical blocks + --> tests/ui/if_same_then_else.rs:269:14 + | +LL | _ = if x { a >= b } else { b <= a }; + | ^^^^^^^^^^ + | +note: same as this + --> tests/ui/if_same_then_else.rs:269:30 + | +LL | _ = if x { a >= b } else { b <= a }; + | ^^^^^^^^^^ + +error: this `if` has identical blocks + --> tests/ui/if_same_then_else.rs:282:14 + | +LL | _ = if x { a * b } else { b * a }; + | ^^^^^^^^^ + | +note: same as this + --> tests/ui/if_same_then_else.rs:282:29 + | +LL | _ = if x { a * b } else { b * a }; + | ^^^^^^^^^ + +error: this `if` has identical blocks + --> tests/ui/if_same_then_else.rs:284:14 + | +LL | _ = if x { a + b } else { b + a }; + | ^^^^^^^^^ + | +note: same as this + --> tests/ui/if_same_then_else.rs:284:29 + | +LL | _ = if x { a + b } else { b + a }; + | ^^^^^^^^^ + +error: this `if` has identical blocks + --> tests/ui/if_same_then_else.rs:286:14 + | +LL | _ = if x { a & b } else { b & a }; + | ^^^^^^^^^ + | +note: same as this + --> tests/ui/if_same_then_else.rs:286:29 + | +LL | _ = if x { a & b } else { b & a }; + | ^^^^^^^^^ + +error: this `if` has identical blocks + --> tests/ui/if_same_then_else.rs:288:14 + | +LL | _ = if x { a ^ b } else { b ^ a }; + | ^^^^^^^^^ + | +note: same as this + --> tests/ui/if_same_then_else.rs:288:29 + | +LL | _ = if x { a ^ b } else { b ^ a }; + | ^^^^^^^^^ + +error: this `if` has identical blocks + --> tests/ui/if_same_then_else.rs:290:14 + | +LL | _ = if x { a | b } else { b | a }; + | ^^^^^^^^^ + | +note: same as this + --> tests/ui/if_same_then_else.rs:290:29 + | +LL | _ = if x { a | b } else { b | a }; + | ^^^^^^^^^ + +error: this `if` has identical blocks + --> tests/ui/if_same_then_else.rs:294:14 + | +LL | _ = if x { a == b } else { b == a }; + | ^^^^^^^^^^ + | +note: same as this + --> tests/ui/if_same_then_else.rs:294:30 + | +LL | _ = if x { a == b } else { b == a }; + | ^^^^^^^^^^ + +error: this `if` has identical blocks + --> tests/ui/if_same_then_else.rs:296:14 + | +LL | _ = if x { a != b } else { b != a }; + | ^^^^^^^^^^ + | +note: same as this + --> tests/ui/if_same_then_else.rs:296:30 + | +LL | _ = if x { a != b } else { b != a }; + | ^^^^^^^^^^ + +error: this `if` has identical blocks + --> tests/ui/if_same_then_else.rs:300:14 + | +LL | _ = if x { a < b } else { b > a }; + | ^^^^^^^^^ + | +note: same as this + --> tests/ui/if_same_then_else.rs:300:29 + | +LL | _ = if x { a < b } else { b > a }; + | ^^^^^^^^^ + +error: this `if` has identical blocks + --> tests/ui/if_same_then_else.rs:302:14 + | +LL | _ = if x { a <= b } else { b >= a }; + | ^^^^^^^^^^ + | +note: same as this + --> tests/ui/if_same_then_else.rs:302:30 + | +LL | _ = if x { a <= b } else { b >= a }; + | ^^^^^^^^^^ + +error: this `if` has identical blocks + --> tests/ui/if_same_then_else.rs:304:14 + | +LL | _ = if x { a > b } else { b < a }; + | ^^^^^^^^^ + | +note: same as this + --> tests/ui/if_same_then_else.rs:304:29 + | +LL | _ = if x { a > b } else { b < a }; + | ^^^^^^^^^ + +error: this `if` has identical blocks + --> tests/ui/if_same_then_else.rs:306:14 + | +LL | _ = if x { a >= b } else { b <= a }; + | ^^^^^^^^^^ + | +note: same as this + --> tests/ui/if_same_then_else.rs:306:30 + | +LL | _ = if x { a >= b } else { b <= a }; + | ^^^^^^^^^^ + +error: aborting due to 23 previous errors From dd61de95e47de79c4676c528f275cd07654fe377 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sat, 17 Jan 2026 00:41:20 +0100 Subject: [PATCH 0797/1061] Remove empty stderr file from tests --- tests/ui/manual_take_nocore.stderr | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tests/ui/manual_take_nocore.stderr diff --git a/tests/ui/manual_take_nocore.stderr b/tests/ui/manual_take_nocore.stderr deleted file mode 100644 index e69de29bb2d1..000000000000 From 79f12eb1ed02e763dafe13938996f69e6b0b5f7a Mon Sep 17 00:00:00 2001 From: dianne Date: Fri, 16 Jan 2026 15:42:25 -0800 Subject: [PATCH 0798/1061] remove some confusing mutation `oprnd_t` was used both for the type of the operand of a unary operator and for the type of the operator expression as a whole. Now it's only used for the operand's type. --- compiler/rustc_hir_typeck/src/expr.rs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 9f3ff0b2d03c..1d7faf1345cf 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -434,14 +434,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::UnOp::Not | hir::UnOp::Neg => expected, hir::UnOp::Deref => NoExpectation, }; - let mut oprnd_t = self.check_expr_with_expectation(oprnd, expected_inner); + let oprnd_t = self.check_expr_with_expectation(oprnd, expected_inner); - if !oprnd_t.references_error() { - oprnd_t = self.structurally_resolve_type(expr.span, oprnd_t); + if let Err(guar) = oprnd_t.error_reported() { + Ty::new_error(tcx, guar) + } else { + let oprnd_t = self.structurally_resolve_type(expr.span, oprnd_t); match unop { hir::UnOp::Deref => { if let Some(ty) = self.lookup_derefing(expr, oprnd, oprnd_t) { - oprnd_t = ty; + ty } else { let mut err = self.dcx().create_err(CantDereference { span: expr.span, ty: oprnd_t }); @@ -451,26 +453,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); } - oprnd_t = Ty::new_error(tcx, err.emit()); + Ty::new_error(tcx, err.emit()) } } hir::UnOp::Not => { let result = self.check_user_unop(expr, oprnd_t, unop, expected_inner); // If it's builtin, we can reuse the type, this helps inference. - if !(oprnd_t.is_integral() || *oprnd_t.kind() == ty::Bool) { - oprnd_t = result; + if oprnd_t.is_integral() || *oprnd_t.kind() == ty::Bool { + oprnd_t + } else { + result } } hir::UnOp::Neg => { let result = self.check_user_unop(expr, oprnd_t, unop, expected_inner); // If it's builtin, we can reuse the type, this helps inference. - if !oprnd_t.is_numeric() { - oprnd_t = result; - } + if oprnd_t.is_numeric() { oprnd_t } else { result } } } } - oprnd_t } fn check_expr_addr_of( From 91bbb692d5a32faae9a8fb3f212f518bd98ff3cd Mon Sep 17 00:00:00 2001 From: dianne Date: Fri, 16 Jan 2026 15:51:29 -0800 Subject: [PATCH 0799/1061] re-style `check_expr_unop` --- compiler/rustc_hir_typeck/src/expr.rs | 54 +++++++++++---------------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 1d7faf1345cf..885af3b909b8 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -437,39 +437,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let oprnd_t = self.check_expr_with_expectation(oprnd, expected_inner); if let Err(guar) = oprnd_t.error_reported() { - Ty::new_error(tcx, guar) - } else { - let oprnd_t = self.structurally_resolve_type(expr.span, oprnd_t); - match unop { - hir::UnOp::Deref => { - if let Some(ty) = self.lookup_derefing(expr, oprnd, oprnd_t) { - ty - } else { - let mut err = - self.dcx().create_err(CantDereference { span: expr.span, ty: oprnd_t }); - let sp = tcx.sess.source_map().start_point(expr.span).with_parent(None); - if let Some(sp) = - tcx.sess.psess.ambiguous_block_expr_parse.borrow().get(&sp) - { - err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); - } - Ty::new_error(tcx, err.emit()) - } - } - hir::UnOp::Not => { - let result = self.check_user_unop(expr, oprnd_t, unop, expected_inner); - // If it's builtin, we can reuse the type, this helps inference. - if oprnd_t.is_integral() || *oprnd_t.kind() == ty::Bool { - oprnd_t - } else { - result - } - } - hir::UnOp::Neg => { - let result = self.check_user_unop(expr, oprnd_t, unop, expected_inner); - // If it's builtin, we can reuse the type, this helps inference. - if oprnd_t.is_numeric() { oprnd_t } else { result } + return Ty::new_error(tcx, guar); + } + + let oprnd_t = self.structurally_resolve_type(expr.span, oprnd_t); + match unop { + hir::UnOp::Deref => self.lookup_derefing(expr, oprnd, oprnd_t).unwrap_or_else(|| { + let mut err = + self.dcx().create_err(CantDereference { span: expr.span, ty: oprnd_t }); + let sp = tcx.sess.source_map().start_point(expr.span).with_parent(None); + if let Some(sp) = tcx.sess.psess.ambiguous_block_expr_parse.borrow().get(&sp) { + err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); } + Ty::new_error(tcx, err.emit()) + }), + hir::UnOp::Not => { + let result = self.check_user_unop(expr, oprnd_t, unop, expected_inner); + // If it's builtin, we can reuse the type, this helps inference. + if oprnd_t.is_integral() || *oprnd_t.kind() == ty::Bool { oprnd_t } else { result } + } + hir::UnOp::Neg => { + let result = self.check_user_unop(expr, oprnd_t, unop, expected_inner); + // If it's builtin, we can reuse the type, this helps inference. + if oprnd_t.is_numeric() { oprnd_t } else { result } } } } From 696f616b78940380e34f06f6d094c17ab7c647a4 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Fri, 16 Jan 2026 23:59:16 +0000 Subject: [PATCH 0800/1061] Remove known problems from `comparison_chain` This reverts commit e42ba4829c02e8308ae142b5a2fd5efb6ccf0a7b, reversing changes made to d75bc868caee77f1b29763f8ba5a00494ed52f6b. --- clippy_lints/src/comparison_chain.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index 238ebd4a444c..a2ddf3dad7a2 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -17,10 +17,6 @@ declare_clippy_lint! { /// `if` is not guaranteed to be exhaustive and conditionals can get /// repetitive /// - /// ### Known problems - /// The match statement may be slower due to the compiler - /// not inlining the call to cmp. See issue [#5354](https://github.com/rust-lang/rust-clippy/issues/5354) - /// /// ### Example /// ```rust,ignore /// # fn a() {} From c7031e93c50ad46601993efe6d7e6139977bd1a2 Mon Sep 17 00:00:00 2001 From: Jamie Hill-Daniel Date: Fri, 16 Jan 2026 18:31:11 +0000 Subject: [PATCH 0801/1061] feat: Support references in reflection type info --- .../src/const_eval/type_info.rs | 35 ++++++++++++++- compiler/rustc_span/src/symbol.rs | 2 + library/core/src/mem/type_info.rs | 13 ++++++ library/coretests/tests/mem/type_info.rs | 32 +++++++++++++- tests/ui/reflection/dump.bit32.run.stdout | 43 +++++++++++++++++-- tests/ui/reflection/dump.bit64.run.stdout | 43 +++++++++++++++++-- tests/ui/reflection/dump.rs | 1 + 7 files changed, 161 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/type_info.rs b/compiler/rustc_const_eval/src/const_eval/type_info.rs index 5d37db06d76a..3c6064d3f87d 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -1,4 +1,5 @@ use rustc_abi::FieldIdx; +use rustc_ast::Mutability; use rustc_hir::LangItem; use rustc_middle::mir::interpret::{CtfeProvenance, Scalar}; use rustc_middle::span_bug; @@ -103,12 +104,19 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { let (variant, _variant_place) = downcast(sym::Str)?; variant } + ty::Ref(_, ty, mutability) => { + let (variant, variant_place) = downcast(sym::Reference)?; + let reference_place = + self.project_field(&variant_place, FieldIdx::ZERO)?; + self.write_reference_type_info(reference_place, *ty, *mutability)?; + + variant + } ty::Adt(_, _) | ty::Foreign(_) | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(..) - | ty::Ref(..) | ty::FnDef(..) | ty::FnPtr(..) | ty::UnsafeBinder(..) @@ -279,4 +287,29 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { } interp_ok(()) } + + pub(crate) fn write_reference_type_info( + &mut self, + place: impl Writeable<'tcx, CtfeProvenance>, + ty: Ty<'tcx>, + mutability: Mutability, + ) -> InterpResult<'tcx> { + // Iterate over all fields of `type_info::Reference`. + for (field_idx, field) in + place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated() + { + let field_place = self.project_field(&place, field_idx)?; + + match field.name { + // Write the `TypeId` of the reference's inner type to the `ty` field. + sym::pointee => self.write_type_id(ty, &field_place)?, + // Write the boolean representing the reference's mutability to the `mutable` field. + sym::mutable => { + self.write_scalar(Scalar::from_bool(mutability.is_mut()), &field_place)? + } + other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"), + } + } + interp_ok(()) + } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 51920db8cd79..f0576002354d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -343,6 +343,7 @@ symbols! { RefCell, RefCellRef, RefCellRefMut, + Reference, Relaxed, Release, Result, @@ -1521,6 +1522,7 @@ symbols! { must_use, mut_preserve_binding_mode_2024, mut_ref, + mutable, naked, naked_asm, naked_functions, diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index 2e3bdb45ce05..ee647ef55840 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -55,6 +55,8 @@ pub enum TypeKind { Float(Float), /// String slice type. Str(Str), + /// References. + Reference(Reference), /// FIXME(#146922): add all the common types Other, } @@ -133,3 +135,14 @@ pub struct Float { pub struct Str { // No additional information to provide for now. } + +/// Compile-time type information about references. +#[derive(Debug)] +#[non_exhaustive] +#[unstable(feature = "type_info", issue = "146922")] +pub struct Reference { + /// The type of the value being referred to. + pub pointee: TypeId, + /// Whether this reference is mutable or not. + pub mutable: bool, +} diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs index fc13637a5574..7df632981ce1 100644 --- a/library/coretests/tests/mem/type_info.rs +++ b/library/coretests/tests/mem/type_info.rs @@ -1,4 +1,4 @@ -use std::any::TypeId; +use std::any::{Any, TypeId}; use std::mem::type_info::{Type, TypeKind}; #[test] @@ -95,3 +95,33 @@ fn test_primitives() { let Type { kind: Str(_ty), size, .. } = (const { Type::of::() }) else { panic!() }; assert_eq!(size, None); } + +#[test] +fn test_references() { + // Immutable reference. + match const { Type::of::<&u8>() }.kind { + TypeKind::Reference(reference) => { + assert_eq!(reference.pointee, TypeId::of::()); + assert!(!reference.mutable); + } + _ => unreachable!(), + } + + // Mutable pointer. + match const { Type::of::<&mut u64>() }.kind { + TypeKind::Reference(reference) => { + assert_eq!(reference.pointee, TypeId::of::()); + assert!(reference.mutable); + } + _ => unreachable!(), + } + + // Wide pointer. + match const { Type::of::<&dyn Any>() }.kind { + TypeKind::Reference(reference) => { + assert_eq!(reference.pointee, TypeId::of::()); + assert!(!reference.mutable); + } + _ => unreachable!(), + } +} diff --git a/tests/ui/reflection/dump.bit32.run.stdout b/tests/ui/reflection/dump.bit32.run.stdout index 483efdbbd12a..8d0398bdd53a 100644 --- a/tests/ui/reflection/dump.bit32.run.stdout +++ b/tests/ui/reflection/dump.bit32.run.stdout @@ -155,19 +155,34 @@ Type { ), } Type { - kind: Other, + kind: Reference( + Reference { + pointee: TypeId(0xda1b6da9bd297bb2900de9303aadea79), + mutable: false, + }, + ), size: Some( 8, ), } Type { - kind: Other, + kind: Reference( + Reference { + pointee: TypeId(0x474ccf3b5db264ef53916706f7d7bb2c), + mutable: false, + }, + ), size: Some( 8, ), } Type { - kind: Other, + kind: Reference( + Reference { + pointee: TypeId(0x641e3def269c37acc6dcb92bf8c5f196), + mutable: false, + }, + ), size: Some( 8, ), @@ -182,3 +197,25 @@ Type { kind: Other, size: None, } +Type { + kind: Reference( + Reference { + pointee: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), + mutable: false, + }, + ), + size: Some( + 4, + ), +} +Type { + kind: Reference( + Reference { + pointee: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), + mutable: true, + }, + ), + size: Some( + 4, + ), +} diff --git a/tests/ui/reflection/dump.bit64.run.stdout b/tests/ui/reflection/dump.bit64.run.stdout index 681e81b71d56..3564922fc171 100644 --- a/tests/ui/reflection/dump.bit64.run.stdout +++ b/tests/ui/reflection/dump.bit64.run.stdout @@ -155,19 +155,34 @@ Type { ), } Type { - kind: Other, + kind: Reference( + Reference { + pointee: TypeId(0xda1b6da9bd297bb2900de9303aadea79), + mutable: false, + }, + ), size: Some( 16, ), } Type { - kind: Other, + kind: Reference( + Reference { + pointee: TypeId(0x474ccf3b5db264ef53916706f7d7bb2c), + mutable: false, + }, + ), size: Some( 16, ), } Type { - kind: Other, + kind: Reference( + Reference { + pointee: TypeId(0x641e3def269c37acc6dcb92bf8c5f196), + mutable: false, + }, + ), size: Some( 16, ), @@ -182,3 +197,25 @@ Type { kind: Other, size: None, } +Type { + kind: Reference( + Reference { + pointee: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), + mutable: false, + }, + ), + size: Some( + 8, + ), +} +Type { + kind: Reference( + Reference { + pointee: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), + mutable: true, + }, + ), + size: Some( + 8, + ), +} diff --git a/tests/ui/reflection/dump.rs b/tests/ui/reflection/dump.rs index 584b7c8ed4ae..d42216a62fdc 100644 --- a/tests/ui/reflection/dump.rs +++ b/tests/ui/reflection/dump.rs @@ -40,5 +40,6 @@ fn main() { Foo, Bar, &Unsized, &str, &[u8], str, [u8], + &u8, &mut u8, } } From 27b02796609e43103ce06a5c38cfc82e029c53c7 Mon Sep 17 00:00:00 2001 From: Asuna Date: Sat, 17 Jan 2026 01:53:08 +0100 Subject: [PATCH 0802/1061] Change field `bit_width: usize` to `bits: u32` in type info --- .../src/const_eval/type_info.rs | 8 ++++---- compiler/rustc_span/src/symbol.rs | 2 +- library/core/src/mem/type_info.rs | 4 ++-- library/coretests/tests/mem/type_info.rs | 14 ++++++------- tests/ui/reflection/dump.bit32.run.stdout | 20 +++++++++---------- tests/ui/reflection/dump.bit64.run.stdout | 20 +++++++++---------- 6 files changed, 34 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/type_info.rs b/compiler/rustc_const_eval/src/const_eval/type_info.rs index 5d37db06d76a..195714b1c0e6 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -249,8 +249,8 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { { let field_place = self.project_field(&place, field_idx)?; match field.name { - sym::bit_width => self.write_scalar( - ScalarInt::try_from_target_usize(bit_width, self.tcx.tcx).unwrap(), + sym::bits => self.write_scalar( + Scalar::from_u32(bit_width.try_into().expect("bit_width overflowed")), &field_place, )?, sym::signed => self.write_scalar(Scalar::from_bool(signed), &field_place)?, @@ -270,8 +270,8 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { { let field_place = self.project_field(&place, field_idx)?; match field.name { - sym::bit_width => self.write_scalar( - ScalarInt::try_from_target_usize(bit_width, self.tcx.tcx).unwrap(), + sym::bits => self.write_scalar( + Scalar::from_u32(bit_width.try_into().expect("bit_width overflowed")), &field_place, )?, other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 51920db8cd79..2bd9ee6a6123 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -589,12 +589,12 @@ symbols! { binaryheap_iter, bind_by_move_pattern_guards, bindings_after_at, - bit_width, bitand, bitand_assign, bitor, bitor_assign, bitreverse, + bits, bitxor, bitxor_assign, black_box, diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index 2e3bdb45ce05..5a105573db77 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -112,7 +112,7 @@ pub struct Char { #[unstable(feature = "type_info", issue = "146922")] pub struct Int { /// The bit width of the signed integer type. - pub bit_width: usize, + pub bits: u32, /// Whether the integer type is signed. pub signed: bool, } @@ -123,7 +123,7 @@ pub struct Int { #[unstable(feature = "type_info", issue = "146922")] pub struct Float { /// The bit width of the floating-point type. - pub bit_width: usize, + pub bits: u32, } /// Compile-time type information about string slice types. diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs index fc13637a5574..53195fc5be0e 100644 --- a/library/coretests/tests/mem/type_info.rs +++ b/library/coretests/tests/mem/type_info.rs @@ -47,8 +47,8 @@ fn test_tuples() { match (a.ty.info().kind, b.ty.info().kind) { (TypeKind::Int(a), TypeKind::Int(b)) => { - assert!(a.bit_width == 8 && a.signed); - assert!(b.bit_width == 8 && !b.signed); + assert!(a.bits == 8 && a.signed); + assert!(b.bits == 8 && !b.signed); } _ => unreachable!(), } @@ -70,27 +70,27 @@ fn test_primitives() { let Type { kind: Int(ty), size, .. } = (const { Type::of::() }) else { panic!() }; assert_eq!(size, Some(4)); - assert_eq!(ty.bit_width, 32); + assert_eq!(ty.bits, 32); assert!(ty.signed); let Type { kind: Int(ty), size, .. } = (const { Type::of::() }) else { panic!() }; assert_eq!(size, Some(size_of::())); - assert_eq!(ty.bit_width, size_of::() * 8); + assert_eq!(ty.bits as usize, size_of::() * 8); assert!(ty.signed); let Type { kind: Int(ty), size, .. } = (const { Type::of::() }) else { panic!() }; assert_eq!(size, Some(4)); - assert_eq!(ty.bit_width, 32); + assert_eq!(ty.bits, 32); assert!(!ty.signed); let Type { kind: Int(ty), size, .. } = (const { Type::of::() }) else { panic!() }; assert_eq!(size, Some(size_of::())); - assert_eq!(ty.bit_width, size_of::() * 8); + assert_eq!(ty.bits as usize, size_of::() * 8); assert!(!ty.signed); let Type { kind: Float(ty), size, .. } = (const { Type::of::() }) else { panic!() }; assert_eq!(size, Some(4)); - assert_eq!(ty.bit_width, 32); + assert_eq!(ty.bits, 32); let Type { kind: Str(_ty), size, .. } = (const { Type::of::() }) else { panic!() }; assert_eq!(size, None); diff --git a/tests/ui/reflection/dump.bit32.run.stdout b/tests/ui/reflection/dump.bit32.run.stdout index 483efdbbd12a..c086cdd11aff 100644 --- a/tests/ui/reflection/dump.bit32.run.stdout +++ b/tests/ui/reflection/dump.bit32.run.stdout @@ -35,7 +35,7 @@ Type { Type { kind: Int( Int { - bit_width: 8, + bits: 8, signed: true, }, ), @@ -46,7 +46,7 @@ Type { Type { kind: Int( Int { - bit_width: 32, + bits: 32, signed: true, }, ), @@ -57,7 +57,7 @@ Type { Type { kind: Int( Int { - bit_width: 64, + bits: 64, signed: true, }, ), @@ -68,7 +68,7 @@ Type { Type { kind: Int( Int { - bit_width: 128, + bits: 128, signed: true, }, ), @@ -79,7 +79,7 @@ Type { Type { kind: Int( Int { - bit_width: 32, + bits: 32, signed: true, }, ), @@ -90,7 +90,7 @@ Type { Type { kind: Int( Int { - bit_width: 8, + bits: 8, signed: false, }, ), @@ -101,7 +101,7 @@ Type { Type { kind: Int( Int { - bit_width: 32, + bits: 32, signed: false, }, ), @@ -112,7 +112,7 @@ Type { Type { kind: Int( Int { - bit_width: 64, + bits: 64, signed: false, }, ), @@ -123,7 +123,7 @@ Type { Type { kind: Int( Int { - bit_width: 128, + bits: 128, signed: false, }, ), @@ -134,7 +134,7 @@ Type { Type { kind: Int( Int { - bit_width: 32, + bits: 32, signed: false, }, ), diff --git a/tests/ui/reflection/dump.bit64.run.stdout b/tests/ui/reflection/dump.bit64.run.stdout index 681e81b71d56..5f82ab44a91d 100644 --- a/tests/ui/reflection/dump.bit64.run.stdout +++ b/tests/ui/reflection/dump.bit64.run.stdout @@ -35,7 +35,7 @@ Type { Type { kind: Int( Int { - bit_width: 8, + bits: 8, signed: true, }, ), @@ -46,7 +46,7 @@ Type { Type { kind: Int( Int { - bit_width: 32, + bits: 32, signed: true, }, ), @@ -57,7 +57,7 @@ Type { Type { kind: Int( Int { - bit_width: 64, + bits: 64, signed: true, }, ), @@ -68,7 +68,7 @@ Type { Type { kind: Int( Int { - bit_width: 128, + bits: 128, signed: true, }, ), @@ -79,7 +79,7 @@ Type { Type { kind: Int( Int { - bit_width: 64, + bits: 64, signed: true, }, ), @@ -90,7 +90,7 @@ Type { Type { kind: Int( Int { - bit_width: 8, + bits: 8, signed: false, }, ), @@ -101,7 +101,7 @@ Type { Type { kind: Int( Int { - bit_width: 32, + bits: 32, signed: false, }, ), @@ -112,7 +112,7 @@ Type { Type { kind: Int( Int { - bit_width: 64, + bits: 64, signed: false, }, ), @@ -123,7 +123,7 @@ Type { Type { kind: Int( Int { - bit_width: 128, + bits: 128, signed: false, }, ), @@ -134,7 +134,7 @@ Type { Type { kind: Int( Int { - bit_width: 64, + bits: 64, signed: false, }, ), From 4c93efae2b741b9df51fd55364ad08d57c2f196d Mon Sep 17 00:00:00 2001 From: Keith-Cancel Date: Tue, 13 Jan 2026 13:02:33 -0800 Subject: [PATCH 0803/1061] Fix ICE: When Trying to check visibility of a #[type_const], check RHS instead. We want to evaluate the rhs of a type_const. Also added an early return/guard in eval_in_interpreter which is used in functions like `eval_to_allocation_raw_provider` Lastly add a debug assert to `thir_body()` if we have gotten there with a type_const something as gone wrong. Get rid of a call to is_type_const() and instead use a match arm. Change this is_type_const() check to a debug_assert!() Change to use an if else statment instead. Update type_const-pub.rs Fix formatting. Noticed that this is the same check as is_type_const() centralize it. Add test case for pub type_const. --- .../rustc_const_eval/src/const_eval/eval_queries.rs | 4 +++- compiler/rustc_metadata/src/rmeta/encoder.rs | 5 ++--- compiler/rustc_mir_build/src/thir/cx/mod.rs | 2 ++ compiler/rustc_passes/src/reachable.rs | 5 ++++- tests/ui/const-generics/mgca/type_const-pub.rs | 10 ++++++++++ 5 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 tests/ui/const-generics/mgca/type_const-pub.rs diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index beea1b4a28c9..5383ab3547af 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -394,8 +394,10 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>( typing_env: ty::TypingEnv<'tcx>, ) -> Result { let def = cid.instance.def.def_id(); - let is_static = tcx.is_static(def); + // #[type_const] don't have bodys + debug_assert!(!tcx.is_type_const(def), "CTFE tried to evaluate type-const: {:?}", def); + let is_static = tcx.is_static(def); let mut ecx = InterpCx::new( tcx, tcx.def_span(def), diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index a62826cd7cec..4fcc7f064f3f 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1379,9 +1379,8 @@ fn should_encode_const(def_kind: DefKind) -> bool { } fn should_encode_const_of_item<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, def_kind: DefKind) -> bool { - matches!(def_kind, DefKind::Const | DefKind::AssocConst) - && find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TypeConst(_)) - // AssocConst ==> assoc item has value + // AssocConst ==> assoc item has value + tcx.is_type_const(def_id) && (!matches!(def_kind, DefKind::AssocConst) || assoc_item_has_value(tcx, def_id)) } diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 79e85a243f40..b08d1d4bcf27 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -18,6 +18,8 @@ pub(crate) fn thir_body( tcx: TyCtxt<'_>, owner_def: LocalDefId, ) -> Result<(&Steal>, ExprId), ErrorGuaranteed> { + debug_assert!(!tcx.is_type_const(owner_def.to_def_id()), "thir_body queried for type_const"); + let body = tcx.hir_body_owned_by(owner_def); let mut cx = ThirBuildCx::new(tcx, owner_def); if let Some(reported) = cx.typeck_results.tainted_by_errors { diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index b9323e91ca83..d9565e2dae0e 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -209,7 +209,10 @@ impl<'tcx> ReachableContext<'tcx> { self.visit_nested_body(body); } } - + // For #[type_const] we want to evaluate the RHS. + hir::ItemKind::Const(_, _, _, init @ hir::ConstItemRhs::TypeConst(_)) => { + self.visit_const_item_rhs(init); + } hir::ItemKind::Const(_, _, _, init) => { // Only things actually ending up in the final constant value are reachable // for codegen. Everything else is only needed during const-eval, so even if diff --git a/tests/ui/const-generics/mgca/type_const-pub.rs b/tests/ui/const-generics/mgca/type_const-pub.rs new file mode 100644 index 000000000000..fc5b1ce36a14 --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-pub.rs @@ -0,0 +1,10 @@ +//@ check-pass +// This previously caused an ICE when checking reachability of a pub const item +// This is because reachability also tried to evaluate the #[type_const] which +// requires the item have a body. #[type_const] do not have bodies. +#![expect(incomplete_features)] +#![feature(min_generic_const_args)] + +#[type_const] +pub const TYPE_CONST : usize = 1; +fn main() {} From ac8e8505b7c12d826f970e8e8ec8c18b067c6dc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Fri, 16 Jan 2026 21:08:01 +0100 Subject: [PATCH 0804/1061] rustdoc: Stop unconditionally evaluating the initializer of associated consts --- src/librustdoc/html/render/mod.rs | 9 ++--- .../anchors/anchors.no_const_anchor2.html | 2 +- tests/rustdoc-html/attributes.rs | 2 +- .../constant/assoc-const-has-projection-ty.rs | 31 +++++++++++++++++ tests/rustdoc-html/constant/assoc-consts.rs | 2 +- .../rustdoc-html/deref/deref-to-primitive.rs | 2 +- tests/rustdoc-html/display-hidden-items.rs | 4 +-- .../impl/impl-associated-items-order.rs | 4 +-- tests/rustdoc-ui/diverging-assoc-consts.rs | 33 +++++++++++++++++++ 9 files changed, 75 insertions(+), 14 deletions(-) create mode 100644 tests/rustdoc-html/constant/assoc-const-has-projection-ty.rs create mode 100644 tests/rustdoc-ui/diverging-assoc-consts.rs diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 63de870f07f4..e6fca29e23e5 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1050,14 +1050,11 @@ fn assoc_const( ty = print_type(ty, cx), )?; if let AssocConstValue::TraitDefault(konst) | AssocConstValue::Impl(konst) = value { - // FIXME: `.value()` uses `clean::utils::format_integer_with_underscore_sep` under the - // hood which adds noisy underscores and a type suffix to number literals. - // This hurts readability in this context especially when more complex expressions - // are involved and it doesn't add much of value. - // Find a way to print constants here without all that jazz. - let repr = konst.value(tcx).unwrap_or_else(|| konst.expr(tcx)); + let repr = konst.expr(tcx); if match value { AssocConstValue::TraitDefault(_) => true, // always show + // FIXME: Comparing against the special string "_" denoting overly complex const exprs + // is rather hacky; `ConstKind::expr` should have a richer return type. AssocConstValue::Impl(_) => repr != "_", // show if there is a meaningful value to show AssocConstValue::None => unreachable!(), } { diff --git a/tests/rustdoc-html/anchors/anchors.no_const_anchor2.html b/tests/rustdoc-html/anchors/anchors.no_const_anchor2.html index 091dac3e4b26..310957ac1ae0 100644 --- a/tests/rustdoc-html/anchors/anchors.no_const_anchor2.html +++ b/tests/rustdoc-html/anchors/anchors.no_const_anchor2.html @@ -1 +1 @@ -

Source

pub const X: i32 = 0i32

\ No newline at end of file +
Source

pub const X: i32 = 0

\ No newline at end of file diff --git a/tests/rustdoc-html/attributes.rs b/tests/rustdoc-html/attributes.rs index 429a42a7252c..6032c3d38801 100644 --- a/tests/rustdoc-html/attributes.rs +++ b/tests/rustdoc-html/attributes.rs @@ -59,7 +59,7 @@ pub enum Enum { pub trait Trait { //@ has 'foo/trait.Trait.html' //@ has - '//*[@id="associatedconstant.BAR"]/*[@class="code-header"]/*[@class="code-attribute"]' '#[unsafe(link_section = "bar")]' - //@ has - '//*[@id="associatedconstant.BAR"]/*[@class="code-header"]' 'const BAR: u32 = 0u32' + //@ has - '//*[@id="associatedconstant.BAR"]/*[@class="code-header"]' 'const BAR: u32 = 0' #[unsafe(link_section = "bar")] const BAR: u32 = 0; diff --git a/tests/rustdoc-html/constant/assoc-const-has-projection-ty.rs b/tests/rustdoc-html/constant/assoc-const-has-projection-ty.rs new file mode 100644 index 000000000000..ed0789dade57 --- /dev/null +++ b/tests/rustdoc-html/constant/assoc-const-has-projection-ty.rs @@ -0,0 +1,31 @@ +// Ensure that we properly print the value `1` as `1` in the initializer of associated constants +// that have user type "projection". +// +// We once used to evaluate the initializer in rustdoc and use rustc's MIR pretty-printer to +// render the resulting MIR const value. This pretty printer matches on the type to interpret +// the data and falls back to a cryptic `"{transmute(0x$data): $ty}"` for types it can't handle. +// Crucially, when constructing the MIR const we passed the unnormalized type of the initializer, +// i.e., the projection `::Ty` instead of the normalized `u32` which the +// pretty printer obviously can't handle. +// +// Now we no longer evaluate it and use a custom printer for the const expr. +// +// issue: + +#![crate_name = "it"] + +pub trait Trait { + type Ty; + + const CT: Self::Ty; +} + +pub struct Struct; + +impl Trait for Struct { + type Ty = u32; + + //@ has it/struct.Struct.html + //@ has - '//*[@id="associatedconstant.CT"]' 'const CT: Self::Ty = 1' + const CT: Self::Ty = 1; +} diff --git a/tests/rustdoc-html/constant/assoc-consts.rs b/tests/rustdoc-html/constant/assoc-consts.rs index 247b5b180a86..0994ec7517e3 100644 --- a/tests/rustdoc-html/constant/assoc-consts.rs +++ b/tests/rustdoc-html/constant/assoc-consts.rs @@ -1,6 +1,6 @@ pub trait Foo { //@ has assoc_consts/trait.Foo.html '//pre[@class="rust item-decl"]' \ - // 'const FOO: usize = 13usize;' + // 'const FOO: usize = _;' //@ has - '//*[@id="associatedconstant.FOO"]' 'const FOO: usize' const FOO: usize = 12 + 1; //@ has - '//*[@id="associatedconstant.FOO_NO_DEFAULT"]' 'const FOO_NO_DEFAULT: bool' diff --git a/tests/rustdoc-html/deref/deref-to-primitive.rs b/tests/rustdoc-html/deref/deref-to-primitive.rs index 7a5a3cd8fd65..6fdc382b2213 100644 --- a/tests/rustdoc-html/deref/deref-to-primitive.rs +++ b/tests/rustdoc-html/deref/deref-to-primitive.rs @@ -3,7 +3,7 @@ //@ has 'foo/struct.Foo.html' //@ has - '//*[@id="deref-methods-i32"]' 'Methods from Deref' //@ has - '//*[@id="deref-methods-i32-1"]//*[@id="associatedconstant.BITS"]/h4' \ -// 'pub const BITS: u32 = 32u32' +// 'pub const BITS: u32 = u32::BITS' pub struct Foo(i32); impl std::ops::Deref for Foo { diff --git a/tests/rustdoc-html/display-hidden-items.rs b/tests/rustdoc-html/display-hidden-items.rs index 40cd636e2fe2..8b0854d1ade8 100644 --- a/tests/rustdoc-html/display-hidden-items.rs +++ b/tests/rustdoc-html/display-hidden-items.rs @@ -20,7 +20,7 @@ pub trait TraitHidden {} //@ has 'foo/index.html' '//dt/a[@class="trait"]' 'Trait' pub trait Trait { //@ has 'foo/trait.Trait.html' - //@ has - '//*[@id="associatedconstant.BAR"]/*[@class="code-header"]' '#[doc(hidden)] const BAR: u32 = 0u32' + //@ has - '//*[@id="associatedconstant.BAR"]/*[@class="code-header"]' '#[doc(hidden)] const BAR: u32 = 0' #[doc(hidden)] const BAR: u32 = 0; @@ -44,7 +44,7 @@ impl Struct { } impl Trait for Struct { - //@ has - '//*[@id="associatedconstant.BAR"]/*[@class="code-header"]' '#[doc(hidden)] const BAR: u32 = 0u32' + //@ has - '//*[@id="associatedconstant.BAR"]/*[@class="code-header"]' '#[doc(hidden)] const BAR: u32 = 0' //@ has - '//*[@id="method.foo"]/*[@class="code-header"]' '#[doc(hidden)] fn foo()' } //@ has - '//*[@id="impl-TraitHidden-for-Struct"]/*[@class="code-header"]' 'impl TraitHidden for Struct' diff --git a/tests/rustdoc-html/impl/impl-associated-items-order.rs b/tests/rustdoc-html/impl/impl-associated-items-order.rs index 759e0f0b4009..3f1d04720163 100644 --- a/tests/rustdoc-html/impl/impl-associated-items-order.rs +++ b/tests/rustdoc-html/impl/impl-associated-items-order.rs @@ -16,7 +16,7 @@ impl Bar { // 'pub fn foo()' pub fn foo() {} //@ has - '//*[@id="implementations-list"]//*[@class="impl-items"]/section[1]/h4' \ - // 'pub const X: u8 = 12u8' + // 'pub const X: u8 = 12' pub const X: u8 = 12; //@ has - '//*[@id="implementations-list"]//*[@class="impl-items"]/section[2]/h4' \ // 'pub type Y = u8' @@ -34,7 +34,7 @@ impl Foo for Bar { // 'type Z = u8' type Z = u8; //@ has - '//*[@id="trait-implementations-list"]//*[@class="impl-items"]/section[1]/h4' \ - // 'const W: u32 = 12u32' + // 'const W: u32 = 12' const W: u32 = 12; //@ has - '//*[@id="trait-implementations-list"]//*[@class="impl-items"]/section[3]/h4' \ // 'fn yeay()' diff --git a/tests/rustdoc-ui/diverging-assoc-consts.rs b/tests/rustdoc-ui/diverging-assoc-consts.rs new file mode 100644 index 000000000000..fd0a177e7c4b --- /dev/null +++ b/tests/rustdoc-ui/diverging-assoc-consts.rs @@ -0,0 +1,33 @@ +// Ensure that we don't unconditionally evaluate the initializer of associated constants. +// +// We once used to evaluate them so we could display more kinds of expressions +// (like `1 + 1` as `2`) given the fact that we generally only want to render +// literals (otherwise we would risk dumping extremely large exprs or leaking +// private struct fields). +// +// However, that deviated from rustc's behavior, made rustdoc accept less code +// and was understandably surprising to users. So let's not. +// +// In the future we *might* provide users a mechanism to control this behavior. +// E.g., via a new `#[doc(...)]` attribute. +// +// See also: +// issue: +// issue: + +//@ check-pass + +pub struct Type; + +impl Type { + pub const K0: () = panic!(); + pub const K1: std::convert::Infallible = loop {}; +} + +pub trait Trait { + const K2: i32 = panic!(); +} + +impl Trait for Type { + const K2: i32 = loop {}; +} From ebfd22796fa3eb0bc52612ce7b45cd789f8cb089 Mon Sep 17 00:00:00 2001 From: Oscar Bray Date: Sat, 17 Jan 2026 12:02:37 +0000 Subject: [PATCH 0805/1061] Port #[needs_allocator] to attribute parser --- compiler/rustc_attr_parsing/src/attributes/link_attrs.rs | 9 +++++++++ compiler/rustc_attr_parsing/src/context.rs | 3 ++- compiler/rustc_hir/src/attrs/data_structures.rs | 3 +++ compiler/rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 2 +- 6 files changed, 17 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 61f975555884..2a04b55f469e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -658,3 +658,12 @@ impl SingleAttributeParser for LinkageParser { Some(AttributeKind::Linkage(linkage, cx.attr_span)) } } + +pub(crate) struct NeedsAllocatorParser; + +impl NoArgsAttributeParser for NeedsAllocatorParser { + const PATH: &[Symbol] = &[sym::needs_allocator]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsAllocator; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 2a2fccd32202..449894f7834b 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -41,7 +41,7 @@ use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; use crate::attributes::instruction_set::InstructionSetParser; use crate::attributes::link_attrs::{ ExportStableParser, FfiConstParser, FfiPureParser, LinkNameParser, LinkOrdinalParser, - LinkParser, LinkSectionParser, LinkageParser, StdInternalSymbolParser, + LinkParser, LinkSectionParser, LinkageParser, NeedsAllocatorParser, StdInternalSymbolParser, }; use crate::attributes::lint_helpers::{ AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser, @@ -259,6 +259,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 126fb8eac11b..7b7fae9fdcca 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -840,6 +840,9 @@ pub enum AttributeKind { /// Represents `#[naked]` Naked(Span), + /// Represents `#[needs_allocator]` + NeedsAllocator, + /// Represents `#[no_core]` NoCore(Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 760e7c76df35..dff8a5727771 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -75,6 +75,7 @@ impl AttributeKind { MustNotSupend { .. } => Yes, MustUse { .. } => Yes, Naked(..) => No, + NeedsAllocator => No, NoCore(..) => No, NoImplicitPrelude(..) => No, NoLink => No, diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index a62826cd7cec..dbcb44e3220e 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -742,7 +742,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { proc_macro_data, debugger_visualizers, compiler_builtins: ast::attr::contains_name(attrs, sym::compiler_builtins), - needs_allocator: ast::attr::contains_name(attrs, sym::needs_allocator), + needs_allocator: find_attr!(attrs, AttributeKind::NeedsAllocator), needs_panic_runtime: ast::attr::contains_name(attrs, sym::needs_panic_runtime), no_builtins: ast::attr::contains_name(attrs, sym::no_builtins), panic_runtime: ast::attr::contains_name(attrs, sym::panic_runtime), diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index f57bd62d3e99..4b71d4755cb6 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -315,6 +315,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcDumpPredicates | AttributeKind::RustcDumpDefParents | AttributeKind::RustcDumpVtable(..) + | AttributeKind::NeedsAllocator ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); @@ -346,7 +347,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::prelude_import | sym::panic_handler | sym::lang - | sym::needs_allocator | sym::default_lib_allocator | sym::rustc_diagnostic_item | sym::rustc_no_mir_inline From fe63539778fd3ae3b7aae1e03b96f10991f41d16 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 17 Jan 2026 14:18:11 +0100 Subject: [PATCH 0806/1061] Explicitly list crate level attrs --- compiler/rustc_passes/src/check_attr.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index f57bd62d3e99..a4aed2b92804 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -389,13 +389,25 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::rustc_partition_reused | sym::rustc_partition_codegened | sym::rustc_expected_cgu_reuse - | sym::rustc_nounwind, + | sym::rustc_nounwind + // crate-level attrs, are checked below + | sym::feature + | sym::register_tool + | sym::rustc_no_implicit_bounds + | sym::test_runner + | sym::reexport_test_harness_main + | sym::no_main + | sym::no_builtins + | sym::crate_type + | sym::compiler_builtins + | sym::profiler_runtime + | sym::needs_panic_runtime + | sym::panic_runtime + | sym::rustc_preserve_ub_checks, .. ] => {} [name, rest@..] => { match BUILTIN_ATTRIBUTE_MAP.get(name) { - // checked below - Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) => {} Some(_) => { if rest.len() > 0 && AttributeParser::::is_parsed_attribute(slice::from_ref(name)) { // Check if we tried to use a builtin attribute as an attribute namespace, like `#[must_use::skip]`. From ad3e082afe997060dc1be247dc227db3e8d250d6 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sat, 17 Jan 2026 10:19:26 -0500 Subject: [PATCH 0807/1061] Bump version to 1.95.0 --- src/version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version b/src/version index 8db4a57b3d02..55f6ae93382d 100644 --- a/src/version +++ b/src/version @@ -1 +1 @@ -1.94.0 +1.95.0 From 308b736541d4fdc000cf8abb1577f0d55e05c77c Mon Sep 17 00:00:00 2001 From: Redddy Date: Thu, 15 Jan 2026 23:56:14 +0900 Subject: [PATCH 0808/1061] Added section on using GitHub Dev for PR inspection --- src/doc/rustc-dev-guide/src/git.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/git.md b/src/doc/rustc-dev-guide/src/git.md index e7e84e2ea7f5..abe72b29cb1e 100644 --- a/src/doc/rustc-dev-guide/src/git.md +++ b/src/doc/rustc-dev-guide/src/git.md @@ -495,6 +495,14 @@ command to check it out locally. See for more info. ![`gh` suggestion](./img/github-cli.png) +### Using GitHub dev + +As an alternative to the GitHub web UI, GitHub Dev provides a web-based editor for browsing +repository and PRs. It can be opened by replacing `github.com` with `github.dev` in the URL +or by pressing `.` on a GitHub page. +See [the docs for github.dev editor](https://docs.github.com/en/codespaces/the-githubdev-web-based-editor) +for more details. + ### Moving large sections of code Git and Github's default diff view for large moves *within* a file is quite poor; it will show each From b3a5f53e8f50e5c2532b52cb7dc9222692e739f4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 17 Jan 2026 17:02:46 +0100 Subject: [PATCH 0809/1061] rustdoc: Fix ICE when deprecated note is not resolved on the correct `DefId` --- .../passes/collect_intra_doc_links.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 018e20b76dc8..a68e9dc87ae5 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -11,10 +11,11 @@ use rustc_ast::util::comments::may_have_doc_links; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_errors::{Applicability, Diag, DiagMessage}; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::Namespace::*; use rustc_hir::def::{DefKind, MacroKinds, Namespace, PerNS}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE}; -use rustc_hir::{Mutability, Safety}; +use rustc_hir::{Attribute, Mutability, Safety}; use rustc_middle::ty::{Ty, TyCtxt}; use rustc_middle::{bug, span_bug, ty}; use rustc_resolve::rustdoc::pulldown_cmark::LinkType; @@ -1108,10 +1109,8 @@ impl LinkCollector<'_, '_> { // Also resolve links in the note text of `#[deprecated]`. for attr in &item.attrs.other_attrs { - let rustc_hir::Attribute::Parsed(rustc_hir::attrs::AttributeKind::Deprecation { - span, - deprecation, - }) = attr + let Attribute::Parsed(AttributeKind::Deprecation { span: depr_span, deprecation }) = + attr else { continue; }; @@ -1128,8 +1127,14 @@ impl LinkCollector<'_, '_> { // inlined item. // let item_id = if let Some(inline_stmt_id) = item.inline_stmt_id - && item.span(tcx).is_none_or(|item_span| !item_span.inner().contains(*span)) - { + && tcx.get_all_attrs(inline_stmt_id).iter().any(|attr| { + matches!( + attr, + Attribute::Parsed(AttributeKind::Deprecation { + span: attr_span, .. + }) if attr_span == depr_span, + ) + }) { inline_stmt_id.to_def_id() } else { item.item_id.expect_def_id() From 1faaa769615cda3c662f96b5f48678e6f97ee245 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 17 Jan 2026 17:03:04 +0100 Subject: [PATCH 0810/1061] Add regression test for ICE when deprecated note is not resolved on the correct `DefId` --- .../deprecated-note-from-reexported.rs | 16 +++++++++ .../deprecated-note-from-reexported.stderr | 34 +++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 tests/rustdoc-ui/intra-doc/deprecated-note-from-reexported.rs create mode 100644 tests/rustdoc-ui/intra-doc/deprecated-note-from-reexported.stderr diff --git a/tests/rustdoc-ui/intra-doc/deprecated-note-from-reexported.rs b/tests/rustdoc-ui/intra-doc/deprecated-note-from-reexported.rs new file mode 100644 index 000000000000..3d1e48a4c638 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/deprecated-note-from-reexported.rs @@ -0,0 +1,16 @@ +// This test ensures that the intra-doc link from reexported deprecated attribute note +// are resolved where they are declared. + +#![deny(rustdoc::broken_intra_doc_links)] + +#[doc(inline)] +pub use bar::sql_function_proc as sql_function; + +pub fn define_sql_function() {} + +pub mod bar { + #[deprecated(note = "Use [`define_sql_function`] instead")] + //~^ ERROR: unresolved link + //~| ERROR: unresolved link + pub fn sql_function_proc() {} +} diff --git a/tests/rustdoc-ui/intra-doc/deprecated-note-from-reexported.stderr b/tests/rustdoc-ui/intra-doc/deprecated-note-from-reexported.stderr new file mode 100644 index 000000000000..25f10b24d9fb --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/deprecated-note-from-reexported.stderr @@ -0,0 +1,34 @@ +error: unresolved link to `define_sql_function` + --> $DIR/deprecated-note-from-reexported.rs:12:25 + | +LL | #[deprecated(note = "Use [`define_sql_function`] instead")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the link appears in this line: + + Use [`define_sql_function`] instead + ^^^^^^^^^^^^^^^^^^^^^ + = note: no item named `define_sql_function` in scope + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` +note: the lint level is defined here + --> $DIR/deprecated-note-from-reexported.rs:4:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unresolved link to `define_sql_function` + --> $DIR/deprecated-note-from-reexported.rs:12:25 + | +LL | #[deprecated(note = "Use [`define_sql_function`] instead")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the link appears in this line: + + Use [`define_sql_function`] instead + ^^^^^^^^^^^^^^^^^^^^^ + = note: no item named `define_sql_function` in scope + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors + From a0f9a15b4a916c92d51131418e9fe080c83f9d3c Mon Sep 17 00:00:00 2001 From: Andreas Liljeqvist Date: Sat, 17 Jan 2026 11:36:25 +0100 Subject: [PATCH 0811/1061] Fix is_ascii performance regression on AVX-512 CPUs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When `[u8]::is_ascii()` is compiled with `-C target-cpu=native` on AVX-512 CPUs, LLVM generates inefficient code. Because `is_ascii` is marked `#[inline]`, it gets inlined and recompiled with the user's target settings. The previous implementation used a counting loop that LLVM auto-vectorizes to `pmovmskb` on SSE2, but with AVX-512 enabled, LLVM uses k-registers and extracts bits individually with ~31 `kshiftrd` instructions. This fix replaces the counting loop with explicit SSE2 intrinsics (`_mm_loadu_si128`, `_mm_or_si128`, `_mm_movemask_epi8`) for x86_64. `_mm_movemask_epi8` compiles to `pmovmskb`, forcing efficient codegen regardless of CPU features. Benchmark results on AMD Ryzen 5 7500F (Zen 4 with AVX-512): - Default build: ~73 GB/s → ~74 GB/s (no regression) - With -C target-cpu=native: ~3 GB/s → ~67 GB/s (22x improvement) The loongarch64 implementation retains the original counting loop since it doesn't have this issue. Regression from: https://github.com/rust-lang/rust/pull/130733 --- library/core/src/slice/ascii.rs | 86 +++++++++++++++++--- tests/assembly-llvm/slice-is-ascii-avx512.rs | 18 ++++ tests/codegen-llvm/slice-is-ascii.rs | 9 +- 3 files changed, 98 insertions(+), 15 deletions(-) create mode 100644 tests/assembly-llvm/slice-is-ascii-avx512.rs diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index 3e8c553f9f15..c9e168d6cbf8 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -3,10 +3,7 @@ use core::ascii::EscapeDefault; use crate::fmt::{self, Write}; -#[cfg(not(any( - all(target_arch = "x86_64", target_feature = "sse2"), - all(target_arch = "loongarch64", target_feature = "lsx") -)))] +#[cfg(not(all(target_arch = "loongarch64", target_feature = "lsx")))] use crate::intrinsics::const_eval_select; use crate::{ascii, iter, ops}; @@ -463,19 +460,84 @@ const fn is_ascii(s: &[u8]) -> bool { ) } -/// ASCII test optimized to use the `pmovmskb` instruction on `x86-64` and the -/// `vmskltz.b` instruction on `loongarch64`. +/// SSE2 implementation using `_mm_movemask_epi8` (compiles to `pmovmskb`) to +/// avoid LLVM's broken AVX-512 auto-vectorization of counting loops. +/// +/// # Safety +/// Requires SSE2 support (guaranteed on x86_64). +#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] +#[target_feature(enable = "sse2")] +unsafe fn is_ascii_sse2(bytes: &[u8]) -> bool { + use crate::arch::x86_64::{__m128i, _mm_loadu_si128, _mm_movemask_epi8, _mm_or_si128}; + + const CHUNK_SIZE: usize = 32; + + let mut i = 0; + + while i + CHUNK_SIZE <= bytes.len() { + // SAFETY: We have verified that `i + CHUNK_SIZE <= bytes.len()`. + let ptr = unsafe { bytes.as_ptr().add(i) }; + + // Load two 16-byte chunks and combine them. + // SAFETY: We verified `i + 32 <= len`, so ptr is valid for 32 bytes. + // `_mm_loadu_si128` allows unaligned loads. + let chunk1 = unsafe { _mm_loadu_si128(ptr as *const __m128i) }; + // SAFETY: Same as above - ptr.add(16) is within the valid 32-byte range. + let chunk2 = unsafe { _mm_loadu_si128(ptr.add(16) as *const __m128i) }; + + // OR them together - if any byte has the high bit set, the result will too + let combined = _mm_or_si128(chunk1, chunk2); + + // Create a mask from the MSBs of each byte. + // If any byte is >= 128, its MSB is 1, so the mask will be non-zero. + let mask = _mm_movemask_epi8(combined); + + if mask != 0 { + return false; + } + + i += CHUNK_SIZE; + } + + // Handle remaining bytes with simple loop + while i < bytes.len() { + if !bytes[i].is_ascii() { + return false; + } + i += 1; + } + + true +} + +/// ASCII test optimized to use the `pmovmskb` instruction on `x86-64`. +/// +/// Uses explicit SSE2 intrinsics to prevent LLVM from auto-vectorizing with +/// broken AVX-512 code that extracts mask bits one-by-one. +#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] +#[inline] +#[rustc_allow_const_fn_unstable(const_eval_select)] +const fn is_ascii(bytes: &[u8]) -> bool { + const_eval_select!( + @capture { bytes: &[u8] } -> bool: + if const { + is_ascii_simple(bytes) + } else { + // SAFETY: SSE2 is guaranteed available on x86_64 + unsafe { is_ascii_sse2(bytes) } + } + ) +} + +/// ASCII test optimized to use the `vmskltz.b` instruction on `loongarch64`. /// /// Other platforms are not likely to benefit from this code structure, so they /// use SWAR techniques to test for ASCII in `usize`-sized chunks. -#[cfg(any( - all(target_arch = "x86_64", target_feature = "sse2"), - all(target_arch = "loongarch64", target_feature = "lsx") -))] +#[cfg(all(target_arch = "loongarch64", target_feature = "lsx"))] #[inline] const fn is_ascii(bytes: &[u8]) -> bool { // Process chunks of 32 bytes at a time in the fast path to enable - // auto-vectorization and use of `pmovmskb`. Two 128-bit vector registers + // auto-vectorization and use of `vmskltz.b`. Two 128-bit vector registers // can be OR'd together and then the resulting vector can be tested for // non-ASCII bytes. const CHUNK_SIZE: usize = 32; @@ -485,7 +547,7 @@ const fn is_ascii(bytes: &[u8]) -> bool { while i + CHUNK_SIZE <= bytes.len() { let chunk_end = i + CHUNK_SIZE; - // Get LLVM to produce a `pmovmskb` instruction on x86-64 which + // Get LLVM to produce a `vmskltz.b` instruction on loongarch64 which // creates a mask from the most significant bit of each byte. // ASCII bytes are less than 128 (0x80), so their most significant // bit is unset. diff --git a/tests/assembly-llvm/slice-is-ascii-avx512.rs b/tests/assembly-llvm/slice-is-ascii-avx512.rs new file mode 100644 index 000000000000..d3a441fec96c --- /dev/null +++ b/tests/assembly-llvm/slice-is-ascii-avx512.rs @@ -0,0 +1,18 @@ +//@ only-x86_64 +//@ compile-flags: -C opt-level=3 -C target-cpu=znver4 +//@ compile-flags: -C llvm-args=-x86-asm-syntax=intel +//@ assembly-output: emit-asm +#![crate_type = "lib"] + +// Verify is_ascii uses pmovmskb/vpmovmskb instead of kshiftrd with AVX-512. +// The fix uses explicit SSE2 intrinsics to avoid LLVM's broken auto-vectorization. +// +// See: https://github.com/rust-lang/rust/issues/129293 + +// CHECK-LABEL: test_is_ascii +#[no_mangle] +pub fn test_is_ascii(s: &[u8]) -> bool { + // CHECK-NOT: kshiftrd + // CHECK-NOT: kshiftrq + s.is_ascii() +} diff --git a/tests/codegen-llvm/slice-is-ascii.rs b/tests/codegen-llvm/slice-is-ascii.rs index 67537c871a0a..1f41b69e4396 100644 --- a/tests/codegen-llvm/slice-is-ascii.rs +++ b/tests/codegen-llvm/slice-is-ascii.rs @@ -1,10 +1,13 @@ -//@ only-x86_64 -//@ compile-flags: -C opt-level=3 -C target-cpu=x86-64 +//@ only-loongarch64 +//@ compile-flags: -C opt-level=3 #![crate_type = "lib"] -/// Check that the fast-path of `is_ascii` uses a `pmovmskb` instruction. +/// Check that the fast-path of `is_ascii` uses a `vmskltz.b` instruction. /// Platforms lacking an equivalent instruction use other techniques for /// optimizing `is_ascii`. +/// +/// Note: x86_64 uses explicit SSE2 intrinsics instead of relying on +/// auto-vectorization. See `slice-is-ascii-avx512.rs`. // CHECK-LABEL: @is_ascii_autovectorized #[no_mangle] pub fn is_ascii_autovectorized(s: &[u8]) -> bool { From 4d2f6a0843b161df938c341ecf142e636cd54b5b Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sun, 18 Jan 2026 04:34:46 +0900 Subject: [PATCH 0812/1061] fix ICE on inconsistent import resolution with macro-attributed extern crate --- compiler/rustc_resolve/src/imports.rs | 2 +- .../resolve/ice-inconsistent-resolution-151213.rs | 14 ++++++++++++++ .../ice-inconsistent-resolution-151213.stderr | 14 ++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 tests/ui/resolve/ice-inconsistent-resolution-151213.rs create mode 100644 tests/ui/resolve/ice-inconsistent-resolution-151213.stderr diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 451779ae32c6..016fc407daab 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -989,7 +989,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { PathResult::Module(module) => { // Consistency checks, analogous to `finalize_macro_resolutions`. if let Some(initial_module) = import.imported_module.get() { - if module != initial_module && no_ambiguity { + if module != initial_module && no_ambiguity && !self.issue_145575_hack_applied { span_bug!(import.span, "inconsistent resolution for an import"); } } else if self.privacy_errors.is_empty() { diff --git a/tests/ui/resolve/ice-inconsistent-resolution-151213.rs b/tests/ui/resolve/ice-inconsistent-resolution-151213.rs new file mode 100644 index 000000000000..ea0f1c2858ef --- /dev/null +++ b/tests/ui/resolve/ice-inconsistent-resolution-151213.rs @@ -0,0 +1,14 @@ +//@ edition: 2024 + +#[attr] +//~^ ERROR cannot find attribute `attr` in this scope +extern crate core as std; +//~^ ERROR macro-expanded `extern crate` items cannot shadow names passed with `--extern` + +mod inner { + use std::str; + + use crate::*; +} + +fn main() {} diff --git a/tests/ui/resolve/ice-inconsistent-resolution-151213.stderr b/tests/ui/resolve/ice-inconsistent-resolution-151213.stderr new file mode 100644 index 000000000000..deb1e6c3e1cf --- /dev/null +++ b/tests/ui/resolve/ice-inconsistent-resolution-151213.stderr @@ -0,0 +1,14 @@ +error: macro-expanded `extern crate` items cannot shadow names passed with `--extern` + --> $DIR/ice-inconsistent-resolution-151213.rs:5:1 + | +LL | extern crate core as std; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: cannot find attribute `attr` in this scope + --> $DIR/ice-inconsistent-resolution-151213.rs:3:3 + | +LL | #[attr] + | ^^^^ + +error: aborting due to 2 previous errors + From b49539e0490188136ae5805e144967ad6d510a2b Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 17 Jan 2026 15:08:53 -0800 Subject: [PATCH 0813/1061] Include a link to `count_ones` in the docs for `uN::count_zeros` --- library/core/src/num/uint_macros.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index eea5ce348355..57f0cd48fbe8 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -93,6 +93,28 @@ macro_rules! uint_impl { #[doc = concat!("let max = ", stringify!($SelfT),"::MAX;")] /// assert_eq!(max.count_zeros(), 0); /// ``` + /// + /// This is heavily dependent on the width of the type, and thus + /// might give surprising results depending on type inference: + /// ``` + /// # fn foo(_: u8) {} + /// # fn bar(_: u16) {} + /// let lucky = 7; + /// foo(lucky); + /// assert_eq!(lucky.count_zeros(), 5); + /// assert_eq!(lucky.count_ones(), 3); + /// + /// let lucky = 7; + /// bar(lucky); + /// assert_eq!(lucky.count_zeros(), 13); + /// assert_eq!(lucky.count_ones(), 3); + /// ``` + /// You might want to use [`Self::count_ones`] instead, or emphasize + /// the type you're using in the call rather than method syntax: + /// ``` + /// let small = 1; + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::count_zeros(small), ", stringify!($BITS_MINUS_ONE) ,");")] + /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_math", since = "1.32.0")] #[must_use = "this returns the result of the operation, \ From 216ca145fd5967d1ff8731b8cc76eca7b53cff03 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sat, 17 Jan 2026 21:43:50 -0500 Subject: [PATCH 0814/1061] remove trailing periods in built-in attribute gate messages --- compiler/rustc_feature/src/builtin_attrs.rs | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 22753adb4c99..1fd6c3c10fab 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -678,7 +678,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!( rustc_pass_indirectly_in_non_rustic_abis, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No, - "types marked with `#[rustc_pass_indirectly_in_non_rustic_abis]` are always passed indirectly by non-Rustic abis." + "types marked with `#[rustc_pass_indirectly_in_non_rustic_abis]` are always passed indirectly by non-Rustic ABIs" ), // Limits: @@ -1275,38 +1275,38 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!( rustc_as_ptr, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, - "`#[rustc_as_ptr]` is used to mark functions returning pointers to their inner allocations." + "`#[rustc_as_ptr]` is used to mark functions returning pointers to their inner allocations" ), rustc_attr!( rustc_should_not_be_called_on_const_items, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, - "`#[rustc_should_not_be_called_on_const_items]` is used to mark methods that don't make sense to be called on interior mutable consts." + "`#[rustc_should_not_be_called_on_const_items]` is used to mark methods that don't make sense to be called on interior mutable consts" ), rustc_attr!( rustc_pass_by_value, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, - "`#[rustc_pass_by_value]` is used to mark types that must be passed by value instead of reference." + "`#[rustc_pass_by_value]` is used to mark types that must be passed by value instead of reference" ), rustc_attr!( rustc_never_returns_null_ptr, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, - "`#[rustc_never_returns_null_ptr]` is used to mark functions returning non-null pointers." + "`#[rustc_never_returns_null_ptr]` is used to mark functions returning non-null pointers" ), rustc_attr!( rustc_no_implicit_autorefs, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, - "`#[rustc_no_implicit_autorefs]` is used to mark functions for which an autoref to the dereference of a raw pointer should not be used as an argument." + "`#[rustc_no_implicit_autorefs]` is used to mark functions for which an autoref to the dereference of a raw pointer should not be used as an argument" ), rustc_attr!( rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No, - "`#![rustc_coherence_is_core]` allows inherent methods on builtin types, only intended to be used in `core`." + "`#![rustc_coherence_is_core]` allows inherent methods on builtin types, only intended to be used in `core`" ), rustc_attr!( rustc_coinductive, AttributeType::Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, - "`#[rustc_coinductive]` changes a trait to be coinductive, allowing cycles in the trait solver." + "`#[rustc_coinductive]` changes a trait to be coinductive, allowing cycles in the trait solver" ), rustc_attr!( rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No, - "`#[rustc_allow_incoherent_impl]` has to be added to all impl items of an incoherent inherent impl." + "`#[rustc_allow_incoherent_impl]` has to be added to all impl items of an incoherent inherent impl" ), rustc_attr!( rustc_preserve_ub_checks, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No, @@ -1333,7 +1333,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, "`#[rustc_has_incoherent_inherent_impls]` allows the addition of incoherent inherent impls for \ - the given type by annotating all impl items with `#[rustc_allow_incoherent_impl]`." + the given type by annotating all impl items with `#[rustc_allow_incoherent_impl]`" ), BuiltinAttribute { @@ -1396,7 +1396,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ EncodeCrossCrate::No, "the `#[rustc_skip_during_method_dispatch]` attribute is used to exclude a trait \ from method dispatch when the receiver is of the following type, for compatibility in \ - editions < 2021 (array) or editions < 2024 (boxed_slice)." + editions < 2021 (array) or editions < 2024 (boxed_slice)" ), rustc_attr!( rustc_must_implement_one_of, Normal, template!(List: &["function1, function2, ..."]), From 7510f747a8599c430a054ba58d53dc8dae1465ee Mon Sep 17 00:00:00 2001 From: mu001999 Date: Sun, 18 Jan 2026 11:40:42 +0800 Subject: [PATCH 0815/1061] Normalize type_const items even with feature `generic_const_exprs` --- .../rustc_trait_selection/src/traits/normalize.rs | 7 ++++++- tests/crashes/138089.rs | 2 ++ .../const-generics/mgca/cyclic-type-const-151251.rs | 11 +++++++++++ .../mgca/cyclic-type-const-151251.stderr | 11 +++++++++++ 4 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/ui/const-generics/mgca/cyclic-type-const-151251.rs create mode 100644 tests/ui/const-generics/mgca/cyclic-type-const-151251.stderr diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 71e9914f93fa..24854990fe71 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -433,7 +433,12 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx #[instrument(skip(self), level = "debug")] fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { let tcx = self.selcx.tcx(); - if tcx.features().generic_const_exprs() || !needs_normalization(self.selcx.infcx, &ct) { + + if tcx.features().generic_const_exprs() + // Normalize type_const items even with feature `generic_const_exprs`. + && !matches!(ct.kind(), ty::ConstKind::Unevaluated(uv) if tcx.is_type_const(uv.def)) + || !needs_normalization(self.selcx.infcx, &ct) + { return ct; } diff --git a/tests/crashes/138089.rs b/tests/crashes/138089.rs index 054d1b216959..f4864971ae5d 100644 --- a/tests/crashes/138089.rs +++ b/tests/crashes/138089.rs @@ -1,4 +1,6 @@ //@ known-bug: #138089 +//@ needs-rustc-debug-assertions + #![feature(generic_const_exprs)] #![feature(min_generic_const_args)] #![feature(inherent_associated_types)] diff --git a/tests/ui/const-generics/mgca/cyclic-type-const-151251.rs b/tests/ui/const-generics/mgca/cyclic-type-const-151251.rs new file mode 100644 index 000000000000..823a6d58bf47 --- /dev/null +++ b/tests/ui/const-generics/mgca/cyclic-type-const-151251.rs @@ -0,0 +1,11 @@ +//@ needs-rustc-debug-assertions + +#![feature(min_generic_const_args)] +#![feature(generic_const_exprs)] +#![expect(incomplete_features)] + +#[type_const] +const A: u8 = A; +//~^ ERROR overflow normalizing the unevaluated constant `A` + +fn main() {} diff --git a/tests/ui/const-generics/mgca/cyclic-type-const-151251.stderr b/tests/ui/const-generics/mgca/cyclic-type-const-151251.stderr new file mode 100644 index 000000000000..1ce2af817277 --- /dev/null +++ b/tests/ui/const-generics/mgca/cyclic-type-const-151251.stderr @@ -0,0 +1,11 @@ +error[E0275]: overflow normalizing the unevaluated constant `A` + --> $DIR/cyclic-type-const-151251.rs:8:1 + | +LL | const A: u8 = A; + | ^^^^^^^^^^^ + | + = note: in case this is a recursive type alias, consider using a struct, enum, or union instead + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. From cf5a7da23f59af669aab128d919d04b96d9ec08b Mon Sep 17 00:00:00 2001 From: tuturuu Date: Sun, 18 Jan 2026 05:16:29 +0100 Subject: [PATCH 0816/1061] move some tests --- .../associated-type-as-value.rs} | 0 .../associated-type-as-value.stderr} | 0 tests/ui/{issues/issue-17441.rs => cast/cast-to-unsized-type.rs} | 0 .../issue-17441.stderr => cast/cast-to-unsized-type.stderr} | 0 .../issue-2995.rs => cast/non-primitive-isize-ref-cast.rs} | 0 .../non-primitive-isize-ref-cast.stderr} | 0 .../ui/{issues/issue-19922.rs => enum/enum-nonexisting-field.rs} | 0 .../issue-19922.stderr => enum/enum-nonexisting-field.stderr} | 0 .../ui/{issues/issue-17351.rs => lint/unused/unused-trait-fn.rs} | 0 .../issue-17351.stderr => lint/unused/unused-trait-fn.stderr} | 0 .../issue-22599.rs => lint/unused/unused-var-in-match-arm.rs} | 0 .../unused/unused-var-in-match-arm.stderr} | 0 .../issue-19692.rs => methods/method-not-found-on-struct.rs} | 0 .../method-not-found-on-struct.stderr} | 0 .../{issues/issue-34209.rs => pattern/enum-variant-not-found.rs} | 0 .../issue-34209.stderr => pattern/enum-variant-not-found.stderr} | 0 .../issue-16745.rs => pattern/match-constant-and-byte-literal.rs} | 0 .../auxiliary/imported-enum-is-private.rs} | 0 .../issue-11680.rs => privacy/imported-enum-is-private.rs} | 0 .../imported-enum-is-private.stderr} | 0 .../issue-26472.rs => privacy/private-struct-field-in-module.rs} | 0 .../private-struct-field-in-module.stderr} | 0 .../panic-with-unspecified-type.rs} | 0 .../panic-with-unspecified-type.stderr} | 0 .../send-with-unspecified-type.rs} | 0 .../send-with-unspecified-type.stderr} | 0 .../swap-with-unspecified-type.rs} | 0 .../swap-with-unspecified-type.stderr} | 0 .../issue-35241.rs => type/struct-constructor-as-value.rs} | 0 .../struct-constructor-as-value.stderr} | 0 30 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{issues/issue-38919.rs => associated-types/associated-type-as-value.rs} (100%) rename tests/ui/{issues/issue-38919.stderr => associated-types/associated-type-as-value.stderr} (100%) rename tests/ui/{issues/issue-17441.rs => cast/cast-to-unsized-type.rs} (100%) rename tests/ui/{issues/issue-17441.stderr => cast/cast-to-unsized-type.stderr} (100%) rename tests/ui/{issues/issue-2995.rs => cast/non-primitive-isize-ref-cast.rs} (100%) rename tests/ui/{issues/issue-2995.stderr => cast/non-primitive-isize-ref-cast.stderr} (100%) rename tests/ui/{issues/issue-19922.rs => enum/enum-nonexisting-field.rs} (100%) rename tests/ui/{issues/issue-19922.stderr => enum/enum-nonexisting-field.stderr} (100%) rename tests/ui/{issues/issue-17351.rs => lint/unused/unused-trait-fn.rs} (100%) rename tests/ui/{issues/issue-17351.stderr => lint/unused/unused-trait-fn.stderr} (100%) rename tests/ui/{issues/issue-22599.rs => lint/unused/unused-var-in-match-arm.rs} (100%) rename tests/ui/{issues/issue-22599.stderr => lint/unused/unused-var-in-match-arm.stderr} (100%) rename tests/ui/{issues/issue-19692.rs => methods/method-not-found-on-struct.rs} (100%) rename tests/ui/{issues/issue-19692.stderr => methods/method-not-found-on-struct.stderr} (100%) rename tests/ui/{issues/issue-34209.rs => pattern/enum-variant-not-found.rs} (100%) rename tests/ui/{issues/issue-34209.stderr => pattern/enum-variant-not-found.stderr} (100%) rename tests/ui/{issues/issue-16745.rs => pattern/match-constant-and-byte-literal.rs} (100%) rename tests/ui/{issues/auxiliary/issue-11680.rs => privacy/auxiliary/imported-enum-is-private.rs} (100%) rename tests/ui/{issues/issue-11680.rs => privacy/imported-enum-is-private.rs} (100%) rename tests/ui/{issues/issue-11680.stderr => privacy/imported-enum-is-private.stderr} (100%) rename tests/ui/{issues/issue-26472.rs => privacy/private-struct-field-in-module.rs} (100%) rename tests/ui/{issues/issue-26472.stderr => privacy/private-struct-field-in-module.stderr} (100%) rename tests/ui/{issues/issue-16966.rs => type-inference/panic-with-unspecified-type.rs} (100%) rename tests/ui/{issues/issue-16966.stderr => type-inference/panic-with-unspecified-type.stderr} (100%) rename tests/ui/{issues/issue-25368.rs => type-inference/send-with-unspecified-type.rs} (100%) rename tests/ui/{issues/issue-25368.stderr => type-inference/send-with-unspecified-type.stderr} (100%) rename tests/ui/{issues/issue-24013.rs => type-inference/swap-with-unspecified-type.rs} (100%) rename tests/ui/{issues/issue-24013.stderr => type-inference/swap-with-unspecified-type.stderr} (100%) rename tests/ui/{issues/issue-35241.rs => type/struct-constructor-as-value.rs} (100%) rename tests/ui/{issues/issue-35241.stderr => type/struct-constructor-as-value.stderr} (100%) diff --git a/tests/ui/issues/issue-38919.rs b/tests/ui/associated-types/associated-type-as-value.rs similarity index 100% rename from tests/ui/issues/issue-38919.rs rename to tests/ui/associated-types/associated-type-as-value.rs diff --git a/tests/ui/issues/issue-38919.stderr b/tests/ui/associated-types/associated-type-as-value.stderr similarity index 100% rename from tests/ui/issues/issue-38919.stderr rename to tests/ui/associated-types/associated-type-as-value.stderr diff --git a/tests/ui/issues/issue-17441.rs b/tests/ui/cast/cast-to-unsized-type.rs similarity index 100% rename from tests/ui/issues/issue-17441.rs rename to tests/ui/cast/cast-to-unsized-type.rs diff --git a/tests/ui/issues/issue-17441.stderr b/tests/ui/cast/cast-to-unsized-type.stderr similarity index 100% rename from tests/ui/issues/issue-17441.stderr rename to tests/ui/cast/cast-to-unsized-type.stderr diff --git a/tests/ui/issues/issue-2995.rs b/tests/ui/cast/non-primitive-isize-ref-cast.rs similarity index 100% rename from tests/ui/issues/issue-2995.rs rename to tests/ui/cast/non-primitive-isize-ref-cast.rs diff --git a/tests/ui/issues/issue-2995.stderr b/tests/ui/cast/non-primitive-isize-ref-cast.stderr similarity index 100% rename from tests/ui/issues/issue-2995.stderr rename to tests/ui/cast/non-primitive-isize-ref-cast.stderr diff --git a/tests/ui/issues/issue-19922.rs b/tests/ui/enum/enum-nonexisting-field.rs similarity index 100% rename from tests/ui/issues/issue-19922.rs rename to tests/ui/enum/enum-nonexisting-field.rs diff --git a/tests/ui/issues/issue-19922.stderr b/tests/ui/enum/enum-nonexisting-field.stderr similarity index 100% rename from tests/ui/issues/issue-19922.stderr rename to tests/ui/enum/enum-nonexisting-field.stderr diff --git a/tests/ui/issues/issue-17351.rs b/tests/ui/lint/unused/unused-trait-fn.rs similarity index 100% rename from tests/ui/issues/issue-17351.rs rename to tests/ui/lint/unused/unused-trait-fn.rs diff --git a/tests/ui/issues/issue-17351.stderr b/tests/ui/lint/unused/unused-trait-fn.stderr similarity index 100% rename from tests/ui/issues/issue-17351.stderr rename to tests/ui/lint/unused/unused-trait-fn.stderr diff --git a/tests/ui/issues/issue-22599.rs b/tests/ui/lint/unused/unused-var-in-match-arm.rs similarity index 100% rename from tests/ui/issues/issue-22599.rs rename to tests/ui/lint/unused/unused-var-in-match-arm.rs diff --git a/tests/ui/issues/issue-22599.stderr b/tests/ui/lint/unused/unused-var-in-match-arm.stderr similarity index 100% rename from tests/ui/issues/issue-22599.stderr rename to tests/ui/lint/unused/unused-var-in-match-arm.stderr diff --git a/tests/ui/issues/issue-19692.rs b/tests/ui/methods/method-not-found-on-struct.rs similarity index 100% rename from tests/ui/issues/issue-19692.rs rename to tests/ui/methods/method-not-found-on-struct.rs diff --git a/tests/ui/issues/issue-19692.stderr b/tests/ui/methods/method-not-found-on-struct.stderr similarity index 100% rename from tests/ui/issues/issue-19692.stderr rename to tests/ui/methods/method-not-found-on-struct.stderr diff --git a/tests/ui/issues/issue-34209.rs b/tests/ui/pattern/enum-variant-not-found.rs similarity index 100% rename from tests/ui/issues/issue-34209.rs rename to tests/ui/pattern/enum-variant-not-found.rs diff --git a/tests/ui/issues/issue-34209.stderr b/tests/ui/pattern/enum-variant-not-found.stderr similarity index 100% rename from tests/ui/issues/issue-34209.stderr rename to tests/ui/pattern/enum-variant-not-found.stderr diff --git a/tests/ui/issues/issue-16745.rs b/tests/ui/pattern/match-constant-and-byte-literal.rs similarity index 100% rename from tests/ui/issues/issue-16745.rs rename to tests/ui/pattern/match-constant-and-byte-literal.rs diff --git a/tests/ui/issues/auxiliary/issue-11680.rs b/tests/ui/privacy/auxiliary/imported-enum-is-private.rs similarity index 100% rename from tests/ui/issues/auxiliary/issue-11680.rs rename to tests/ui/privacy/auxiliary/imported-enum-is-private.rs diff --git a/tests/ui/issues/issue-11680.rs b/tests/ui/privacy/imported-enum-is-private.rs similarity index 100% rename from tests/ui/issues/issue-11680.rs rename to tests/ui/privacy/imported-enum-is-private.rs diff --git a/tests/ui/issues/issue-11680.stderr b/tests/ui/privacy/imported-enum-is-private.stderr similarity index 100% rename from tests/ui/issues/issue-11680.stderr rename to tests/ui/privacy/imported-enum-is-private.stderr diff --git a/tests/ui/issues/issue-26472.rs b/tests/ui/privacy/private-struct-field-in-module.rs similarity index 100% rename from tests/ui/issues/issue-26472.rs rename to tests/ui/privacy/private-struct-field-in-module.rs diff --git a/tests/ui/issues/issue-26472.stderr b/tests/ui/privacy/private-struct-field-in-module.stderr similarity index 100% rename from tests/ui/issues/issue-26472.stderr rename to tests/ui/privacy/private-struct-field-in-module.stderr diff --git a/tests/ui/issues/issue-16966.rs b/tests/ui/type-inference/panic-with-unspecified-type.rs similarity index 100% rename from tests/ui/issues/issue-16966.rs rename to tests/ui/type-inference/panic-with-unspecified-type.rs diff --git a/tests/ui/issues/issue-16966.stderr b/tests/ui/type-inference/panic-with-unspecified-type.stderr similarity index 100% rename from tests/ui/issues/issue-16966.stderr rename to tests/ui/type-inference/panic-with-unspecified-type.stderr diff --git a/tests/ui/issues/issue-25368.rs b/tests/ui/type-inference/send-with-unspecified-type.rs similarity index 100% rename from tests/ui/issues/issue-25368.rs rename to tests/ui/type-inference/send-with-unspecified-type.rs diff --git a/tests/ui/issues/issue-25368.stderr b/tests/ui/type-inference/send-with-unspecified-type.stderr similarity index 100% rename from tests/ui/issues/issue-25368.stderr rename to tests/ui/type-inference/send-with-unspecified-type.stderr diff --git a/tests/ui/issues/issue-24013.rs b/tests/ui/type-inference/swap-with-unspecified-type.rs similarity index 100% rename from tests/ui/issues/issue-24013.rs rename to tests/ui/type-inference/swap-with-unspecified-type.rs diff --git a/tests/ui/issues/issue-24013.stderr b/tests/ui/type-inference/swap-with-unspecified-type.stderr similarity index 100% rename from tests/ui/issues/issue-24013.stderr rename to tests/ui/type-inference/swap-with-unspecified-type.stderr diff --git a/tests/ui/issues/issue-35241.rs b/tests/ui/type/struct-constructor-as-value.rs similarity index 100% rename from tests/ui/issues/issue-35241.rs rename to tests/ui/type/struct-constructor-as-value.rs diff --git a/tests/ui/issues/issue-35241.stderr b/tests/ui/type/struct-constructor-as-value.stderr similarity index 100% rename from tests/ui/issues/issue-35241.stderr rename to tests/ui/type/struct-constructor-as-value.stderr From 2c7969a0cd4217900f96511b16117a0ef31836c4 Mon Sep 17 00:00:00 2001 From: tuturuu Date: Sun, 18 Jan 2026 06:10:16 +0100 Subject: [PATCH 0817/1061] add metadata and bless moved tests --- .../ui/associated-types/associated-type-as-value.rs | 2 ++ .../associated-types/associated-type-as-value.stderr | 2 +- tests/ui/cast/cast-to-unsized-type.rs | 2 ++ tests/ui/cast/cast-to-unsized-type.stderr | 12 ++++++------ tests/ui/cast/non-primitive-isize-ref-cast.rs | 2 ++ tests/ui/cast/non-primitive-isize-ref-cast.stderr | 2 +- tests/ui/enum/enum-nonexisting-field.rs | 2 ++ tests/ui/enum/enum-nonexisting-field.stderr | 2 +- tests/ui/lint/unused/unused-trait-fn.rs | 1 + tests/ui/lint/unused/unused-trait-fn.stderr | 2 +- tests/ui/lint/unused/unused-var-in-match-arm.rs | 1 + tests/ui/lint/unused/unused-var-in-match-arm.stderr | 4 ++-- tests/ui/methods/method-not-found-on-struct.rs | 2 ++ tests/ui/methods/method-not-found-on-struct.stderr | 2 +- tests/ui/pattern/enum-variant-not-found.rs | 2 ++ tests/ui/pattern/enum-variant-not-found.stderr | 2 +- tests/ui/pattern/match-constant-and-byte-literal.rs | 1 + .../ui/privacy/auxiliary/imported-enum-is-private.rs | 2 ++ tests/ui/privacy/imported-enum-is-private.rs | 5 +++-- tests/ui/privacy/imported-enum-is-private.stderr | 8 ++++---- tests/ui/privacy/private-struct-field-in-module.rs | 2 ++ .../ui/privacy/private-struct-field-in-module.stderr | 4 ++-- .../ui/type-inference/panic-with-unspecified-type.rs | 1 + .../panic-with-unspecified-type.stderr | 2 +- .../ui/type-inference/send-with-unspecified-type.rs | 2 ++ .../type-inference/send-with-unspecified-type.stderr | 2 +- .../ui/type-inference/swap-with-unspecified-type.rs | 2 ++ .../type-inference/swap-with-unspecified-type.stderr | 2 +- tests/ui/type/struct-constructor-as-value.rs | 2 ++ tests/ui/type/struct-constructor-as-value.stderr | 2 +- 30 files changed, 53 insertions(+), 26 deletions(-) diff --git a/tests/ui/associated-types/associated-type-as-value.rs b/tests/ui/associated-types/associated-type-as-value.rs index 3d28f1936b47..ddc808236658 100644 --- a/tests/ui/associated-types/associated-type-as-value.rs +++ b/tests/ui/associated-types/associated-type-as-value.rs @@ -1,3 +1,5 @@ +//! regression test for + fn foo() { T::Item; //~ ERROR no associated item named `Item` found } diff --git a/tests/ui/associated-types/associated-type-as-value.stderr b/tests/ui/associated-types/associated-type-as-value.stderr index 4a4bd2ee43d8..c553582b3907 100644 --- a/tests/ui/associated-types/associated-type-as-value.stderr +++ b/tests/ui/associated-types/associated-type-as-value.stderr @@ -1,5 +1,5 @@ error[E0599]: no associated item named `Item` found for type parameter `T` in the current scope - --> $DIR/issue-38919.rs:2:8 + --> $DIR/associated-type-as-value.rs:4:8 | LL | fn foo() { | - associated item `Item` not found for this type parameter diff --git a/tests/ui/cast/cast-to-unsized-type.rs b/tests/ui/cast/cast-to-unsized-type.rs index e5f83c4ebadd..4c7ca49fd98d 100644 --- a/tests/ui/cast/cast-to-unsized-type.rs +++ b/tests/ui/cast/cast-to-unsized-type.rs @@ -1,3 +1,5 @@ +//! regression test for + fn main() { let _foo = &[1_usize, 2] as [usize]; //~^ ERROR cast to unsized type: `&[usize; 2]` as `[usize]` diff --git a/tests/ui/cast/cast-to-unsized-type.stderr b/tests/ui/cast/cast-to-unsized-type.stderr index 96aad879e24d..087cfac77484 100644 --- a/tests/ui/cast/cast-to-unsized-type.stderr +++ b/tests/ui/cast/cast-to-unsized-type.stderr @@ -1,5 +1,5 @@ error[E0620]: cast to unsized type: `&[usize; 2]` as `[usize]` - --> $DIR/issue-17441.rs:2:16 + --> $DIR/cast-to-unsized-type.rs:4:16 | LL | let _foo = &[1_usize, 2] as [usize]; | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -10,7 +10,7 @@ LL | let _foo = &[1_usize, 2] as &[usize]; | + error[E0620]: cast to unsized type: `Box` as `dyn Debug` - --> $DIR/issue-17441.rs:5:16 + --> $DIR/cast-to-unsized-type.rs:7:16 | LL | let _bar = Box::new(1_usize) as dyn std::fmt::Debug; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -21,25 +21,25 @@ LL | let _bar = Box::new(1_usize) as Box; | ++++ + error[E0620]: cast to unsized type: `usize` as `dyn Debug` - --> $DIR/issue-17441.rs:8:16 + --> $DIR/cast-to-unsized-type.rs:10:16 | LL | let _baz = 1_usize as dyn std::fmt::Debug; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider using a box or reference as appropriate - --> $DIR/issue-17441.rs:8:16 + --> $DIR/cast-to-unsized-type.rs:10:16 | LL | let _baz = 1_usize as dyn std::fmt::Debug; | ^^^^^^^ error[E0620]: cast to unsized type: `[usize; 2]` as `[usize]` - --> $DIR/issue-17441.rs:11:17 + --> $DIR/cast-to-unsized-type.rs:13:17 | LL | let _quux = [1_usize, 2] as [usize]; | ^^^^^^^^^^^^^^^^^^^^^^^ | help: consider using a box or reference as appropriate - --> $DIR/issue-17441.rs:11:17 + --> $DIR/cast-to-unsized-type.rs:13:17 | LL | let _quux = [1_usize, 2] as [usize]; | ^^^^^^^^^^^^ diff --git a/tests/ui/cast/non-primitive-isize-ref-cast.rs b/tests/ui/cast/non-primitive-isize-ref-cast.rs index 0da7909480d2..95259456eede 100644 --- a/tests/ui/cast/non-primitive-isize-ref-cast.rs +++ b/tests/ui/cast/non-primitive-isize-ref-cast.rs @@ -1,3 +1,5 @@ +//! regression test for + fn bad (p: *const isize) { let _q: &isize = p as &isize; //~ ERROR non-primitive cast } diff --git a/tests/ui/cast/non-primitive-isize-ref-cast.stderr b/tests/ui/cast/non-primitive-isize-ref-cast.stderr index f4a08e1751fc..3f4c171d3dc7 100644 --- a/tests/ui/cast/non-primitive-isize-ref-cast.stderr +++ b/tests/ui/cast/non-primitive-isize-ref-cast.stderr @@ -1,5 +1,5 @@ error[E0605]: non-primitive cast: `*const isize` as `&isize` - --> $DIR/issue-2995.rs:2:22 + --> $DIR/non-primitive-isize-ref-cast.rs:4:22 | LL | let _q: &isize = p as &isize; | ^^^^^^^^^^^ invalid cast diff --git a/tests/ui/enum/enum-nonexisting-field.rs b/tests/ui/enum/enum-nonexisting-field.rs index fede86f22afd..837430340f33 100644 --- a/tests/ui/enum/enum-nonexisting-field.rs +++ b/tests/ui/enum/enum-nonexisting-field.rs @@ -1,3 +1,5 @@ +//! regression test for + enum Homura { Akemi { madoka: () } } diff --git a/tests/ui/enum/enum-nonexisting-field.stderr b/tests/ui/enum/enum-nonexisting-field.stderr index 0355d3a89710..22bfa08dadb3 100644 --- a/tests/ui/enum/enum-nonexisting-field.stderr +++ b/tests/ui/enum/enum-nonexisting-field.stderr @@ -1,5 +1,5 @@ error[E0559]: variant `Homura::Akemi` has no field named `kaname` - --> $DIR/issue-19922.rs:6:34 + --> $DIR/enum-nonexisting-field.rs:8:34 | LL | let homura = Homura::Akemi { kaname: () }; | ^^^^^^ `Homura::Akemi` does not have this field diff --git a/tests/ui/lint/unused/unused-trait-fn.rs b/tests/ui/lint/unused/unused-trait-fn.rs index 86049377198c..57b39c0de17e 100644 --- a/tests/ui/lint/unused/unused-trait-fn.rs +++ b/tests/ui/lint/unused/unused-trait-fn.rs @@ -1,3 +1,4 @@ +//! regression test for //@ run-pass trait Str { fn foo(&self) {} } //~ WARN method `foo` is never used diff --git a/tests/ui/lint/unused/unused-trait-fn.stderr b/tests/ui/lint/unused/unused-trait-fn.stderr index 043d4ffc7808..f33fed29c94c 100644 --- a/tests/ui/lint/unused/unused-trait-fn.stderr +++ b/tests/ui/lint/unused/unused-trait-fn.stderr @@ -1,5 +1,5 @@ warning: method `foo` is never used - --> $DIR/issue-17351.rs:3:16 + --> $DIR/unused-trait-fn.rs:4:16 | LL | trait Str { fn foo(&self) {} } | --- ^^^ diff --git a/tests/ui/lint/unused/unused-var-in-match-arm.rs b/tests/ui/lint/unused/unused-var-in-match-arm.rs index 05096e5c1853..780225f98dbb 100644 --- a/tests/ui/lint/unused/unused-var-in-match-arm.rs +++ b/tests/ui/lint/unused/unused-var-in-match-arm.rs @@ -1,3 +1,4 @@ +//! regression test for #![deny(unused_variables)] fn f(_: i32) {} diff --git a/tests/ui/lint/unused/unused-var-in-match-arm.stderr b/tests/ui/lint/unused/unused-var-in-match-arm.stderr index b599f6febe31..a1b9849293ef 100644 --- a/tests/ui/lint/unused/unused-var-in-match-arm.stderr +++ b/tests/ui/lint/unused/unused-var-in-match-arm.stderr @@ -1,11 +1,11 @@ error: unused variable: `a` - --> $DIR/issue-22599.rs:8:19 + --> $DIR/unused-var-in-match-arm.rs:9:19 | LL | v = match 0 { a => 0 }; | ^ help: if this is intentional, prefix it with an underscore: `_a` | note: the lint level is defined here - --> $DIR/issue-22599.rs:1:9 + --> $DIR/unused-var-in-match-arm.rs:2:9 | LL | #![deny(unused_variables)] | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/methods/method-not-found-on-struct.rs b/tests/ui/methods/method-not-found-on-struct.rs index 99eccc8a8175..b2a457ed19e5 100644 --- a/tests/ui/methods/method-not-found-on-struct.rs +++ b/tests/ui/methods/method-not-found-on-struct.rs @@ -1,3 +1,5 @@ +//! regression test for + struct Homura; fn akemi(homura: Homura) { diff --git a/tests/ui/methods/method-not-found-on-struct.stderr b/tests/ui/methods/method-not-found-on-struct.stderr index 1e3d7a2e2f51..3bf775f30a7a 100644 --- a/tests/ui/methods/method-not-found-on-struct.stderr +++ b/tests/ui/methods/method-not-found-on-struct.stderr @@ -1,5 +1,5 @@ error[E0599]: no method named `kaname` found for struct `Homura` in the current scope - --> $DIR/issue-19692.rs:4:40 + --> $DIR/method-not-found-on-struct.rs:6:40 | LL | struct Homura; | ------------- method `kaname` not found for this struct diff --git a/tests/ui/pattern/enum-variant-not-found.rs b/tests/ui/pattern/enum-variant-not-found.rs index 632ddb91b36f..e78e28abeb6e 100644 --- a/tests/ui/pattern/enum-variant-not-found.rs +++ b/tests/ui/pattern/enum-variant-not-found.rs @@ -1,3 +1,5 @@ +//! regression test for + enum S { A, } diff --git a/tests/ui/pattern/enum-variant-not-found.stderr b/tests/ui/pattern/enum-variant-not-found.stderr index 83b40d0c0816..6db4cf79d6b3 100644 --- a/tests/ui/pattern/enum-variant-not-found.stderr +++ b/tests/ui/pattern/enum-variant-not-found.stderr @@ -1,5 +1,5 @@ error[E0599]: no variant named `B` found for enum `S` - --> $DIR/issue-34209.rs:7:12 + --> $DIR/enum-variant-not-found.rs:9:12 | LL | enum S { | ------ variant `B` not found here diff --git a/tests/ui/pattern/match-constant-and-byte-literal.rs b/tests/ui/pattern/match-constant-and-byte-literal.rs index 99c85bcffcf8..7a793478016d 100644 --- a/tests/ui/pattern/match-constant-and-byte-literal.rs +++ b/tests/ui/pattern/match-constant-and-byte-literal.rs @@ -1,3 +1,4 @@ +//! regression test for //@ run-pass fn main() { const X: u8 = 0; diff --git a/tests/ui/privacy/auxiliary/imported-enum-is-private.rs b/tests/ui/privacy/auxiliary/imported-enum-is-private.rs index 74abbf0bf8cd..ea847d9aff13 100644 --- a/tests/ui/privacy/auxiliary/imported-enum-is-private.rs +++ b/tests/ui/privacy/auxiliary/imported-enum-is-private.rs @@ -1,3 +1,5 @@ +//! auxiliary crate for + enum Foo { Bar(isize) } diff --git a/tests/ui/privacy/imported-enum-is-private.rs b/tests/ui/privacy/imported-enum-is-private.rs index 9f3dfebcc812..b628676a25c6 100644 --- a/tests/ui/privacy/imported-enum-is-private.rs +++ b/tests/ui/privacy/imported-enum-is-private.rs @@ -1,6 +1,7 @@ -//@ aux-build:issue-11680.rs +//! regression test for +//@ aux-build:imported-enum-is-private.rs -extern crate issue_11680 as other; +extern crate imported_enum_is_private as other; fn main() { let _b = other::Foo::Bar(1); diff --git a/tests/ui/privacy/imported-enum-is-private.stderr b/tests/ui/privacy/imported-enum-is-private.stderr index 5bcf93de811f..cae1ebb0e29e 100644 --- a/tests/ui/privacy/imported-enum-is-private.stderr +++ b/tests/ui/privacy/imported-enum-is-private.stderr @@ -1,5 +1,5 @@ error[E0603]: enum `Foo` is private - --> $DIR/issue-11680.rs:6:21 + --> $DIR/imported-enum-is-private.rs:7:21 | LL | let _b = other::Foo::Bar(1); | ^^^ --- tuple variant `Bar` is not publicly re-exported @@ -7,13 +7,13 @@ LL | let _b = other::Foo::Bar(1); | private enum | note: the enum `Foo` is defined here - --> $DIR/auxiliary/issue-11680.rs:1:1 + --> $DIR/auxiliary/imported-enum-is-private.rs:3:1 | LL | enum Foo { | ^^^^^^^^ error[E0603]: enum `Foo` is private - --> $DIR/issue-11680.rs:9:27 + --> $DIR/imported-enum-is-private.rs:10:27 | LL | let _b = other::test::Foo::Bar(1); | ^^^ --- tuple variant `Bar` is not publicly re-exported @@ -21,7 +21,7 @@ LL | let _b = other::test::Foo::Bar(1); | private enum | note: the enum `Foo` is defined here - --> $DIR/auxiliary/issue-11680.rs:6:5 + --> $DIR/auxiliary/imported-enum-is-private.rs:8:5 | LL | enum Foo { | ^^^^^^^^ diff --git a/tests/ui/privacy/private-struct-field-in-module.rs b/tests/ui/privacy/private-struct-field-in-module.rs index b100c59ad0bd..7ed8def1c691 100644 --- a/tests/ui/privacy/private-struct-field-in-module.rs +++ b/tests/ui/privacy/private-struct-field-in-module.rs @@ -1,3 +1,5 @@ +//! regression test for + mod sub { pub struct S { len: usize } impl S { diff --git a/tests/ui/privacy/private-struct-field-in-module.stderr b/tests/ui/privacy/private-struct-field-in-module.stderr index d7134bff1761..2394686f69ca 100644 --- a/tests/ui/privacy/private-struct-field-in-module.stderr +++ b/tests/ui/privacy/private-struct-field-in-module.stderr @@ -1,5 +1,5 @@ error[E0616]: field `len` of struct `S` is private - --> $DIR/issue-26472.rs:11:15 + --> $DIR/private-struct-field-in-module.rs:13:15 | LL | let v = s.len; | ^^^ private field @@ -10,7 +10,7 @@ LL | let v = s.len(); | ++ error[E0616]: field `len` of struct `S` is private - --> $DIR/issue-26472.rs:12:7 + --> $DIR/private-struct-field-in-module.rs:14:7 | LL | s.len = v; | ^^^ private field diff --git a/tests/ui/type-inference/panic-with-unspecified-type.rs b/tests/ui/type-inference/panic-with-unspecified-type.rs index 66a3fadac8d9..0f96759e8144 100644 --- a/tests/ui/type-inference/panic-with-unspecified-type.rs +++ b/tests/ui/type-inference/panic-with-unspecified-type.rs @@ -1,3 +1,4 @@ +//! regression test for //@ edition:2015..2021 fn main() { panic!(std::default::Default::default()); diff --git a/tests/ui/type-inference/panic-with-unspecified-type.stderr b/tests/ui/type-inference/panic-with-unspecified-type.stderr index e294d8830de0..5f08a7552632 100644 --- a/tests/ui/type-inference/panic-with-unspecified-type.stderr +++ b/tests/ui/type-inference/panic-with-unspecified-type.stderr @@ -1,5 +1,5 @@ error[E0283]: type annotations needed - --> $DIR/issue-16966.rs:3:12 + --> $DIR/panic-with-unspecified-type.rs:4:12 | LL | panic!(std::default::Default::default()); | -------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- diff --git a/tests/ui/type-inference/send-with-unspecified-type.rs b/tests/ui/type-inference/send-with-unspecified-type.rs index 4be83457f7a8..4c2de025d69c 100644 --- a/tests/ui/type-inference/send-with-unspecified-type.rs +++ b/tests/ui/type-inference/send-with-unspecified-type.rs @@ -1,3 +1,5 @@ +//! regression test for + use std::sync::mpsc::channel; use std::thread::spawn; use std::marker::PhantomData; diff --git a/tests/ui/type-inference/send-with-unspecified-type.stderr b/tests/ui/type-inference/send-with-unspecified-type.stderr index 23f1441e69dc..85692e8ad0cd 100644 --- a/tests/ui/type-inference/send-with-unspecified-type.stderr +++ b/tests/ui/type-inference/send-with-unspecified-type.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/issue-25368.rs:11:27 + --> $DIR/send-with-unspecified-type.rs:13:27 | LL | tx.send(Foo{ foo: PhantomData }); | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `PhantomData` diff --git a/tests/ui/type-inference/swap-with-unspecified-type.rs b/tests/ui/type-inference/swap-with-unspecified-type.rs index c6d301671272..db415df19e99 100644 --- a/tests/ui/type-inference/swap-with-unspecified-type.rs +++ b/tests/ui/type-inference/swap-with-unspecified-type.rs @@ -1,3 +1,5 @@ +//! regression test for + fn main() { use std::mem::{transmute, swap}; let a = 1; diff --git a/tests/ui/type-inference/swap-with-unspecified-type.stderr b/tests/ui/type-inference/swap-with-unspecified-type.stderr index 37a86ecc5437..eaaed559ebf1 100644 --- a/tests/ui/type-inference/swap-with-unspecified-type.stderr +++ b/tests/ui/type-inference/swap-with-unspecified-type.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/issue-24013.rs:5:13 + --> $DIR/swap-with-unspecified-type.rs:7:13 | LL | unsafe {swap::<&mut _>(transmute(&a), transmute(&b))}; | ^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `swap` diff --git a/tests/ui/type/struct-constructor-as-value.rs b/tests/ui/type/struct-constructor-as-value.rs index 2fa762475da9..9cac1caf86ec 100644 --- a/tests/ui/type/struct-constructor-as-value.rs +++ b/tests/ui/type/struct-constructor-as-value.rs @@ -1,3 +1,5 @@ +//! regression test for + struct Foo(u32); fn test() -> Foo { Foo } //~ ERROR mismatched types diff --git a/tests/ui/type/struct-constructor-as-value.stderr b/tests/ui/type/struct-constructor-as-value.stderr index 6f6602793fdb..5915f971b324 100644 --- a/tests/ui/type/struct-constructor-as-value.stderr +++ b/tests/ui/type/struct-constructor-as-value.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-35241.rs:3:20 + --> $DIR/struct-constructor-as-value.rs:5:20 | LL | struct Foo(u32); | ---------- `Foo` defines a struct constructor here, which should be called From db9f9e65013419e87af78c54727f1b4f44bf75b2 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Sun, 18 Jan 2026 13:38:19 +0800 Subject: [PATCH 0818/1061] Use find_attr instead of attr::contains_name in lower_const_item_rhs --- compiler/rustc_ast_lowering/src/lib.rs | 2 +- .../type-const-assoc-const-without-body.rs | 19 +++++++++++++++++++ ...type-const-assoc-const-without-body.stderr | 10 ++++++++++ ...const-inherent-assoc-const-without-body.rs | 12 ++++++++++++ ...t-inherent-assoc-const-without-body.stderr | 17 +++++++++++++++++ 5 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 tests/ui/const-generics/mgca/type-const-assoc-const-without-body.rs create mode 100644 tests/ui/const-generics/mgca/type-const-assoc-const-without-body.stderr create mode 100644 tests/ui/const-generics/mgca/type-const-inherent-assoc-const-without-body.rs create mode 100644 tests/ui/const-generics/mgca/type-const-inherent-assoc-const-without-body.stderr diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 51d1fd20cec6..8c6ee9d6bc63 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2384,7 +2384,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { Some(ConstItemRhs::TypeConst(anon)) => { hir::ConstItemRhs::TypeConst(self.lower_anon_const_to_const_arg_and_alloc(anon)) } - None if attr::contains_name(attrs, sym::type_const) => { + None if find_attr!(attrs, AttributeKind::TypeConst(_)) => { let const_arg = ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Error( diff --git a/tests/ui/const-generics/mgca/type-const-assoc-const-without-body.rs b/tests/ui/const-generics/mgca/type-const-assoc-const-without-body.rs new file mode 100644 index 000000000000..158a7addd10d --- /dev/null +++ b/tests/ui/const-generics/mgca/type-const-assoc-const-without-body.rs @@ -0,0 +1,19 @@ +//@ needs-rustc-debug-assertions + +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +trait Tr { + #[type_const] + const SIZE: usize; +} + +struct T; + +impl Tr for T { + #[type_const] + const SIZE: usize; + //~^ ERROR associated constant in `impl` without body +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/type-const-assoc-const-without-body.stderr b/tests/ui/const-generics/mgca/type-const-assoc-const-without-body.stderr new file mode 100644 index 000000000000..2db677aa0ca6 --- /dev/null +++ b/tests/ui/const-generics/mgca/type-const-assoc-const-without-body.stderr @@ -0,0 +1,10 @@ +error: associated constant in `impl` without body + --> $DIR/type-const-assoc-const-without-body.rs:15:5 + | +LL | const SIZE: usize; + | ^^^^^^^^^^^^^^^^^- + | | + | help: provide a definition for the constant: `= ;` + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/type-const-inherent-assoc-const-without-body.rs b/tests/ui/const-generics/mgca/type-const-inherent-assoc-const-without-body.rs new file mode 100644 index 000000000000..85b2327d3351 --- /dev/null +++ b/tests/ui/const-generics/mgca/type-const-inherent-assoc-const-without-body.rs @@ -0,0 +1,12 @@ +//@ needs-rustc-debug-assertions + +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +impl S { //~ ERROR cannot find type `S` in this scope + #[type_const] + const SIZE: usize; + //~^ ERROR associated constant in `impl` without body +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/type-const-inherent-assoc-const-without-body.stderr b/tests/ui/const-generics/mgca/type-const-inherent-assoc-const-without-body.stderr new file mode 100644 index 000000000000..ac520a4e6946 --- /dev/null +++ b/tests/ui/const-generics/mgca/type-const-inherent-assoc-const-without-body.stderr @@ -0,0 +1,17 @@ +error: associated constant in `impl` without body + --> $DIR/type-const-inherent-assoc-const-without-body.rs:8:5 + | +LL | const SIZE: usize; + | ^^^^^^^^^^^^^^^^^- + | | + | help: provide a definition for the constant: `= ;` + +error[E0425]: cannot find type `S` in this scope + --> $DIR/type-const-inherent-assoc-const-without-body.rs:6:6 + | +LL | impl S { + | ^ not found in this scope + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0425`. From eed703ccc0d534f38e5d7eca30c6675364566b69 Mon Sep 17 00:00:00 2001 From: Oscar Bray Date: Sun, 18 Jan 2026 08:22:33 +0000 Subject: [PATCH 0819/1061] Fix typo. Match "build-rust-analyzer" in src/building/how-to-build-and-run.md and in the default editor settings from the rustc repo. --- src/doc/rustc-dev-guide/src/building/suggested.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/building/suggested.md b/src/doc/rustc-dev-guide/src/building/suggested.md index 1c75de3e9042..c87dc6b28d87 100644 --- a/src/doc/rustc-dev-guide/src/building/suggested.md +++ b/src/doc/rustc-dev-guide/src/building/suggested.md @@ -97,7 +97,7 @@ for two reasons: additional rebuilds in some cases. To avoid these problems: -- Add `--build-dir=build/rust-analyzer` to all of the custom `x` commands in +- Add `--build-dir=build-rust-analyzer` to all of the custom `x` commands in your editor's rust-analyzer configuration. (Feel free to choose a different directory name if desired.) - Modify the `rust-analyzer.rustfmt.overrideCommand` setting so that it points From 97603c0df04af46512957dda2b5d9dbba73353e3 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 18 Jan 2026 18:00:08 +1100 Subject: [PATCH 0820/1061] Use `ty::Value` in more places throughout `const_to_pat` --- .../src/thir/pattern/const_to_pat.rs | 85 +++++++++---------- 1 file changed, 39 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 70bc142131e4..7fbf8cd11466 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -13,9 +13,7 @@ use rustc_infer::traits::Obligation; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::span_bug; use rustc_middle::thir::{FieldPat, Pat, PatKind}; -use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitableExt, TypeVisitor, ValTree, -}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitableExt, TypeVisitor}; use rustc_span::def_id::DefId; use rustc_span::{DUMMY_SP, Span}; use rustc_trait_selection::traits::ObligationCause; @@ -48,7 +46,7 @@ impl<'tcx> PatCtxt<'tcx> { match c.kind() { ty::ConstKind::Unevaluated(uv) => convert.unevaluated_to_pat(uv, ty), - ty::ConstKind::Value(cv) => convert.valtree_to_pat(cv.valtree, cv.ty), + ty::ConstKind::Value(value) => convert.valtree_to_pat(value), _ => span_bug!(span, "Invalid `ConstKind` for `const_to_pat`: {:?}", c), } } @@ -175,7 +173,7 @@ impl<'tcx> ConstToPat<'tcx> { }; // Lower the valtree to a THIR pattern. - let mut thir_pat = self.valtree_to_pat(valtree, ty); + let mut thir_pat = self.valtree_to_pat(ty::Value { ty, valtree }); if !thir_pat.references_error() { // Always check for `PartialEq` if we had no other errors yet. @@ -192,31 +190,32 @@ impl<'tcx> ConstToPat<'tcx> { thir_pat } - fn field_pats( + fn lower_field_values_to_fieldpats( &self, - vals: impl Iterator, Ty<'tcx>)>, + values: impl Iterator>, ) -> Vec> { - vals.enumerate() - .map(|(idx, (val, ty))| { - let field = FieldIdx::new(idx); - // Patterns can only use monomorphic types. - let ty = self.tcx.normalize_erasing_regions(self.typing_env, ty); - FieldPat { field, pattern: *self.valtree_to_pat(val, ty) } + values + .enumerate() + .map(|(index, value)| FieldPat { + field: FieldIdx::new(index), + pattern: *self.valtree_to_pat(value), }) .collect() } // Recursive helper for `to_pat`; invoke that (instead of calling this directly). - // FIXME(valtrees): Accept `ty::Value` instead of `Ty` and `ty::ValTree` separately. #[instrument(skip(self), level = "debug")] - fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> Box> { + fn valtree_to_pat(&self, value: ty::Value<'tcx>) -> Box> { let span = self.span; let tcx = self.tcx; + let ty::Value { ty, valtree } = value; + let kind = match ty.kind() { + // Extremely important check for all ADTs! + // Make sure they are eligible to be used in patterns, and if not, emit an error. ty::Adt(adt_def, _) if !self.type_marked_structural(ty) => { - // Extremely important check for all ADTs! Make sure they opted-in to be used in - // patterns. - debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty); + // This ADT cannot be used as a constant in patterns. + debug!(?adt_def, ?value.ty, "ADT type in pattern is not `type_marked_structural`"); let PartialEqImplStatus { is_derived, structural_partial_eq, non_blanket_impl, .. } = type_has_partial_eq_impl(self.tcx, self.typing_env, ty); @@ -239,51 +238,43 @@ impl<'tcx> ConstToPat<'tcx> { return self.mk_err(tcx.dcx().create_err(err), ty); } ty::Adt(adt_def, args) if adt_def.is_enum() => { - let (&variant_index, fields) = cv.to_branch().split_first().unwrap(); + let (&variant_index, fields) = valtree.to_branch().split_first().unwrap(); let variant_index = VariantIdx::from_u32(variant_index.to_leaf().to_u32()); PatKind::Variant { adt_def: *adt_def, args, variant_index, - subpatterns: self.field_pats( - fields.iter().map(|ct| ct.to_value().valtree).zip( - adt_def.variants()[variant_index] - .fields - .iter() - .map(|field| field.ty(tcx, args)), - ), - ), + subpatterns: self + .lower_field_values_to_fieldpats(fields.iter().map(|ct| ct.to_value())), } } - ty::Adt(def, args) => { + ty::Adt(def, _) => { assert!(!def.is_union()); // Valtree construction would never succeed for unions. PatKind::Leaf { - subpatterns: self.field_pats( - cv.to_branch().iter().map(|ct| ct.to_value().valtree).zip( - def.non_enum_variant().fields.iter().map(|field| field.ty(tcx, args)), - ), + subpatterns: self.lower_field_values_to_fieldpats( + valtree.to_branch().iter().map(|ct| ct.to_value()), ), } } - ty::Tuple(fields) => PatKind::Leaf { - subpatterns: self.field_pats( - cv.to_branch().iter().map(|ct| ct.to_value().valtree).zip(fields.iter()), + ty::Tuple(_) => PatKind::Leaf { + subpatterns: self.lower_field_values_to_fieldpats( + valtree.to_branch().iter().map(|ct| ct.to_value()), ), }, - ty::Slice(elem_ty) => PatKind::Slice { - prefix: cv + ty::Slice(_) => PatKind::Slice { + prefix: valtree .to_branch() .iter() - .map(|val| *self.valtree_to_pat(val.to_value().valtree, *elem_ty)) + .map(|val| *self.valtree_to_pat(val.to_value())) .collect(), slice: None, suffix: Box::new([]), }, - ty::Array(elem_ty, _) => PatKind::Array { - prefix: cv + ty::Array(_, _) => PatKind::Array { + prefix: valtree .to_branch() .iter() - .map(|val| *self.valtree_to_pat(val.to_value().valtree, *elem_ty)) + .map(|val| *self.valtree_to_pat(val.to_value())) .collect(), slice: None, suffix: Box::new([]), @@ -296,7 +287,7 @@ impl<'tcx> ConstToPat<'tcx> { // Under `feature(deref_patterns)`, string literal patterns can also // have type `str` directly, without the `&`, in order to allow things // like `deref!("...")` to work when the scrutinee is `String`. - PatKind::Constant { value: ty::Value { ty, valtree: cv } } + PatKind::Constant { value } } ty::Ref(_, pointee_ty, ..) => { if pointee_ty.is_str() @@ -304,7 +295,9 @@ impl<'tcx> ConstToPat<'tcx> { || pointee_ty.is_sized(tcx, self.typing_env) { // References have the same valtree representation as their pointee. - PatKind::Deref { subpattern: self.valtree_to_pat(cv, *pointee_ty) } + PatKind::Deref { + subpattern: self.valtree_to_pat(ty::Value { ty: *pointee_ty, valtree }), + } } else { return self.mk_err( tcx.dcx().create_err(UnsizedPattern { span, non_sm_ty: *pointee_ty }), @@ -313,7 +306,7 @@ impl<'tcx> ConstToPat<'tcx> { } } ty::Float(flt) => { - let v = cv.to_leaf(); + let v = valtree.to_leaf(); let is_nan = match flt { ty::FloatTy::F16 => v.to_f16().is_nan(), ty::FloatTy::F32 => v.to_f32().is_nan(), @@ -325,13 +318,13 @@ impl<'tcx> ConstToPat<'tcx> { // Also see . return self.mk_err(tcx.dcx().create_err(NaNPattern { span }), ty); } else { - PatKind::Constant { value: ty::Value { ty, valtree: cv } } + PatKind::Constant { value } } } ty::Pat(..) | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => { // The raw pointers we see here have been "vetted" by valtree construction to be // just integers, so we simply allow them. - PatKind::Constant { value: ty::Value { ty, valtree: cv } } + PatKind::Constant { value } } ty::FnPtr(..) => { unreachable!( From c5785601773223450e8d1b8d553cac32de01840f Mon Sep 17 00:00:00 2001 From: yukang Date: Fri, 28 Nov 2025 14:07:18 +0800 Subject: [PATCH 0821/1061] Surpress suggestion from unstable items on stable channel --- compiler/rustc_resolve/src/diagnostics.rs | 1 + .../issue-149402-suggest-unresolve/foo.rs | 6 ++++ .../nightly.err | 18 ++++++++++++ .../output.diff | 16 ++++++++++ .../issue-149402-suggest-unresolve/rmake.rs | 29 +++++++++++++++++++ .../issue-149402-suggest-unresolve/stable.err | 9 ++++++ 6 files changed, 79 insertions(+) create mode 100644 tests/run-make/issue-149402-suggest-unresolve/foo.rs create mode 100644 tests/run-make/issue-149402-suggest-unresolve/nightly.err create mode 100644 tests/run-make/issue-149402-suggest-unresolve/output.diff create mode 100644 tests/run-make/issue-149402-suggest-unresolve/rmake.rs create mode 100644 tests/run-make/issue-149402-suggest-unresolve/stable.err diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index d704280f3fa2..9fc32b31b32a 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1610,6 +1610,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } + suggestions.retain(|suggestion| suggestion.is_stable || self.tcx.sess.is_nightly_build()); suggestions } diff --git a/tests/run-make/issue-149402-suggest-unresolve/foo.rs b/tests/run-make/issue-149402-suggest-unresolve/foo.rs new file mode 100644 index 000000000000..8456990829b4 --- /dev/null +++ b/tests/run-make/issue-149402-suggest-unresolve/foo.rs @@ -0,0 +1,6 @@ +fn foo() { + let x = Vec::new(); + x.push(Complete::Item { name: "hello" }); +} + +fn main() {} diff --git a/tests/run-make/issue-149402-suggest-unresolve/nightly.err b/tests/run-make/issue-149402-suggest-unresolve/nightly.err new file mode 100644 index 000000000000..8659f0170df3 --- /dev/null +++ b/tests/run-make/issue-149402-suggest-unresolve/nightly.err @@ -0,0 +1,18 @@ +error[E0433]: failed to resolve: use of undeclared type `Complete` + --> foo.rs:3:12 + | +3 | x.push(Complete::Item { name: "hello" }); + | ^^^^^^^^ use of undeclared type `Complete` + | +help: there is an enum variant `core::ops::CoroutineState::Complete` and 1 other; try using the variant's enum + | +3 - x.push(Complete::Item { name: "hello" }); +3 + x.push(core::ops::CoroutineState::Item { name: "hello" }); + | +3 - x.push(Complete::Item { name: "hello" }); +3 + x.push(std::ops::CoroutineState::Item { name: "hello" }); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/run-make/issue-149402-suggest-unresolve/output.diff b/tests/run-make/issue-149402-suggest-unresolve/output.diff new file mode 100644 index 000000000000..196c0326a714 --- /dev/null +++ b/tests/run-make/issue-149402-suggest-unresolve/output.diff @@ -0,0 +1,16 @@ +@@ -3,6 +3,15 @@ + | + 3 | x.push(Complete::Item { name: "hello" }); + | ^^^^^^^^ use of undeclared type `Complete` ++ | ++help: there is an enum variant `core::ops::CoroutineState::Complete` and 1 other; try using the variant's enum ++ | ++3 - x.push(Complete::Item { name: "hello" }); ++3 + x.push(core::ops::CoroutineState::Item { name: "hello" }); ++ | ++3 - x.push(Complete::Item { name: "hello" }); ++3 + x.push(std::ops::CoroutineState::Item { name: "hello" }); ++ | + + error: aborting due to 1 previous error + diff --git a/tests/run-make/issue-149402-suggest-unresolve/rmake.rs b/tests/run-make/issue-149402-suggest-unresolve/rmake.rs new file mode 100644 index 000000000000..5bca0c0206cb --- /dev/null +++ b/tests/run-make/issue-149402-suggest-unresolve/rmake.rs @@ -0,0 +1,29 @@ +//! Check that unstable name-resolution suggestions are omitted on stable. +//! +//! Regression test for . +//! +//@ only-nightly +//@ needs-target-std + +use run_make_support::{diff, rustc, similar}; + +fn main() { + let stable_like = rustc() + .env("RUSTC_BOOTSTRAP", "-1") + .edition("2024") + .input("foo.rs") + .run_fail() + .stderr_utf8(); + + assert!(!stable_like.contains("CoroutineState::Complete")); + diff().expected_file("stable.err").actual_text("stable_like", &stable_like).run(); + + let nightly = rustc().edition("2024").input("foo.rs").run_fail().stderr_utf8(); + + assert!(nightly.contains("CoroutineState::Complete")); + diff().expected_file("nightly.err").actual_text("nightly", &nightly).run(); + + let stderr_diff = + similar::TextDiff::from_lines(&stable_like, &nightly).unified_diff().to_string(); + diff().expected_file("output.diff").actual_text("diff", stderr_diff).run(); +} diff --git a/tests/run-make/issue-149402-suggest-unresolve/stable.err b/tests/run-make/issue-149402-suggest-unresolve/stable.err new file mode 100644 index 000000000000..6e82fe1a67ea --- /dev/null +++ b/tests/run-make/issue-149402-suggest-unresolve/stable.err @@ -0,0 +1,9 @@ +error[E0433]: failed to resolve: use of undeclared type `Complete` + --> foo.rs:3:12 + | +3 | x.push(Complete::Item { name: "hello" }); + | ^^^^^^^^ use of undeclared type `Complete` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0433`. From f3e73dced1144f3b7cc81b34c45fdafec66e29f2 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Sun, 30 Nov 2025 17:02:07 +0100 Subject: [PATCH 0822/1061] Supress some lookup errors if a module contains `compile_error!` The problem is that when a macro expand to `compile_error!` because its input is malformed, the actual error message from the `compile_error!` might be hidden in a long list of other messages about using items that should have otherwise been generated by the macro. So suppress error about missing items in that module. Fixes issue 68838 --- .../rustc_builtin_macros/src/compile_error.rs | 1 + compiler/rustc_expand/src/base.rs | 4 ++ compiler/rustc_resolve/src/ident.rs | 3 +- compiler/rustc_resolve/src/macros.rs | 8 ++++ .../compile_error_macro-suppress-errors.rs | 40 ++++++++++++++++ ...compile_error_macro-suppress-errors.stderr | 46 +++++++++++++++++++ 6 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 tests/ui/macros/compile_error_macro-suppress-errors.rs create mode 100644 tests/ui/macros/compile_error_macro-suppress-errors.stderr diff --git a/compiler/rustc_builtin_macros/src/compile_error.rs b/compiler/rustc_builtin_macros/src/compile_error.rs index 7fc4b437c1d8..df64d8f314db 100644 --- a/compiler/rustc_builtin_macros/src/compile_error.rs +++ b/compiler/rustc_builtin_macros/src/compile_error.rs @@ -22,6 +22,7 @@ pub(crate) fn expand_compile_error<'cx>( #[expect(rustc::diagnostic_outside_of_impl, reason = "diagnostic message is specified by user")] #[expect(rustc::untranslatable_diagnostic, reason = "diagnostic message is specified by user")] let guar = cx.dcx().span_err(sp, var.to_string()); + cx.resolver.mark_scope_with_compile_error(cx.current_expansion.lint_node_id); ExpandResult::Ready(DummyResult::any(sp, guar)) } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index bf653fac5253..a1fc9694d663 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1173,6 +1173,10 @@ pub trait ResolverExpand { /// Record the name of an opaque `Ty::ImplTrait` pre-expansion so that it can be used /// to generate an item name later that does not reference placeholder macros. fn insert_impl_trait_name(&mut self, id: NodeId, name: Symbol); + + /// Mark the scope as having a compile error so that error for lookup in this scope + /// should be suppressed + fn mark_scope_with_compile_error(&mut self, parent_node: NodeId); } pub trait LintStoreExpand { diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index f7e628048ccd..79d08828ccc4 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1711,7 +1711,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { diag_metadata: Option<&DiagMetadata<'_>>, ) -> PathResult<'ra> { let mut module = None; - let mut module_had_parse_errors = false; + let mut module_had_parse_errors = !self.mods_with_parse_errors.is_empty() + && self.mods_with_parse_errors.contains(&parent_scope.module.nearest_parent_mod()); let mut allow_super = true; let mut second_binding = None; diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 38628332f43e..7246eded2e72 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -166,6 +166,14 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { self.invocation_parents[&id].parent_def } + fn mark_scope_with_compile_error(&mut self, id: NodeId) { + if let Some(id) = self.opt_local_def_id(id) + && self.tcx.def_kind(id).is_module_like() + { + self.mods_with_parse_errors.insert(id.to_def_id()); + } + } + fn resolve_dollar_crates(&self) { hygiene::update_dollar_crate_names(|ctxt| { let ident = Ident::new(kw::DollarCrate, DUMMY_SP.with_ctxt(ctxt)); diff --git a/tests/ui/macros/compile_error_macro-suppress-errors.rs b/tests/ui/macros/compile_error_macro-suppress-errors.rs new file mode 100644 index 000000000000..b2b6a8ae0088 --- /dev/null +++ b/tests/ui/macros/compile_error_macro-suppress-errors.rs @@ -0,0 +1,40 @@ +pub mod some_module { + compile_error!("Error in a module"); //~ ERROR: Error in a module + + fn abc() -> Hello { + let _: self::SomeType = self::Hello::new(); + let _: SomeType = Hello::new(); + } + + mod inner_module { + use super::Hello; + use crate::another_module::NotExist; //~ ERROR: unresolved import `crate::another_module::NotExist` + use crate::some_module::World; + struct Foo { + bar: crate::some_module::Xyz, + error: self::MissingType, //~ ERROR: cannot find type `MissingType` in module `self` + } + } +} + +pub mod another_module { + use crate::some_module::NotExist; + fn error_in_this_function() { + compile_error!("Error in a function"); //~ ERROR: Error in a function + } +} + +fn main() { + // these errors are suppressed because of the compile_error! macro + + let _ = some_module::some_function(); + let _: some_module::SomeType = some_module::Hello::new(); + + // these errors are not suppressed + + let _ = another_module::some_function(); + //~^ ERROR: cannot find function `some_function` in module `another_module` + let _: another_module::SomeType = another_module::Hello::new(); + //~^ ERROR: cannot find type `SomeType` in module `another_module` + //~^^ ERROR: failed to resolve: could not find `Hello` in `another_module` +} diff --git a/tests/ui/macros/compile_error_macro-suppress-errors.stderr b/tests/ui/macros/compile_error_macro-suppress-errors.stderr new file mode 100644 index 000000000000..73b156359624 --- /dev/null +++ b/tests/ui/macros/compile_error_macro-suppress-errors.stderr @@ -0,0 +1,46 @@ +error: Error in a module + --> $DIR/compile_error_macro-suppress-errors.rs:2:5 + | +LL | compile_error!("Error in a module"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Error in a function + --> $DIR/compile_error_macro-suppress-errors.rs:23:9 + | +LL | compile_error!("Error in a function"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0432]: unresolved import `crate::another_module::NotExist` + --> $DIR/compile_error_macro-suppress-errors.rs:11:13 + | +LL | use crate::another_module::NotExist; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `NotExist` in `another_module` + +error[E0433]: failed to resolve: could not find `Hello` in `another_module` + --> $DIR/compile_error_macro-suppress-errors.rs:37:55 + | +LL | let _: another_module::SomeType = another_module::Hello::new(); + | ^^^^^ could not find `Hello` in `another_module` + +error[E0425]: cannot find type `MissingType` in module `self` + --> $DIR/compile_error_macro-suppress-errors.rs:15:26 + | +LL | error: self::MissingType, + | ^^^^^^^^^^^ not found in `self` + +error[E0425]: cannot find function `some_function` in module `another_module` + --> $DIR/compile_error_macro-suppress-errors.rs:35:29 + | +LL | let _ = another_module::some_function(); + | ^^^^^^^^^^^^^ not found in `another_module` + +error[E0425]: cannot find type `SomeType` in module `another_module` + --> $DIR/compile_error_macro-suppress-errors.rs:37:28 + | +LL | let _: another_module::SomeType = another_module::Hello::new(); + | ^^^^^^^^ not found in `another_module` + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0425, E0432, E0433. +For more information about an error, try `rustc --explain E0425`. From 2ef85d7894ff46efdd6ab49393ecc88aaf60b0e5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Jan 2026 15:30:05 +0100 Subject: [PATCH 0823/1061] use epoll_ctl_add more often --- .../pass-dep/libc/libc-epoll-blocking.rs | 50 ++++------ .../pass-dep/libc/libc-epoll-no-blocking.rs | 94 +++++++------------ 2 files changed, 49 insertions(+), 95 deletions(-) diff --git a/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs b/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs index d5a59796de02..f9615fc6e414 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs @@ -21,9 +21,6 @@ fn main() { multiple_events_wake_multiple_threads(); } -// Using `as` cast since `EPOLLET` wraps around -const EPOLL_IN_OUT_ET: i32 = (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET) as _; - // This test allows epoll_wait to block, then unblock without notification. fn test_epoll_block_without_notification() { // Create an epoll instance. @@ -34,10 +31,10 @@ fn test_epoll_block_without_notification() { let fd = errno_result(unsafe { libc::eventfd(0, flags) }).unwrap(); // Register eventfd with epoll. - epoll_ctl_add(epfd, fd, EPOLL_IN_OUT_ET).unwrap(); + epoll_ctl_add(epfd, fd, libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap(); // epoll_wait to clear notification. - check_epoll_wait::<1>(epfd, &[Ev { events: libc::EPOLLOUT as _, data: fd }], 0); + check_epoll_wait::<1>(epfd, &[Ev { events: libc::EPOLLOUT, data: fd }], 0); // This epoll wait blocks, and timeout without notification. check_epoll_wait::<1>(epfd, &[], 5); @@ -53,21 +50,17 @@ fn test_epoll_block_then_unblock() { errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }); // Register one side of the socketpair with epoll. - epoll_ctl_add(epfd, fds[0], EPOLL_IN_OUT_ET).unwrap(); + epoll_ctl_add(epfd, fds[0], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap(); // epoll_wait to clear notification. - check_epoll_wait::<1>(epfd, &[Ev { events: libc::EPOLLOUT as _, data: fds[0] }], 0); + check_epoll_wait::<1>(epfd, &[Ev { events: libc::EPOLLOUT, data: fds[0] }], 0); // epoll_wait before triggering notification so it will block then get unblocked before timeout. let thread1 = thread::spawn(move || { thread::yield_now(); write_all_from_slice(fds[1], b"abcde").unwrap(); }); - check_epoll_wait::<1>( - epfd, - &[Ev { events: (libc::EPOLLIN | libc::EPOLLOUT) as _, data: fds[0] }], - 10, - ); + check_epoll_wait::<1>(epfd, &[Ev { events: libc::EPOLLIN | libc::EPOLLOUT, data: fds[0] }], 10); thread1.join().unwrap(); } @@ -81,10 +74,10 @@ fn test_notification_after_timeout() { errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }); // Register one side of the socketpair with epoll. - epoll_ctl_add(epfd, fds[0], EPOLL_IN_OUT_ET).unwrap(); + epoll_ctl_add(epfd, fds[0], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap(); // epoll_wait to clear notification. - check_epoll_wait::<1>(epfd, &[Ev { events: libc::EPOLLOUT as _, data: fds[0] }], 0); + check_epoll_wait::<1>(epfd, &[Ev { events: libc::EPOLLOUT, data: fds[0] }], 0); // epoll_wait timeouts without notification. check_epoll_wait::<1>(epfd, &[], 10); @@ -93,11 +86,7 @@ fn test_notification_after_timeout() { write_all_from_slice(fds[1], b"abcde").unwrap(); // Check the result of the notification. - check_epoll_wait::<1>( - epfd, - &[Ev { events: (libc::EPOLLIN | libc::EPOLLOUT) as _, data: fds[0] }], - 10, - ); + check_epoll_wait::<1>(epfd, &[Ev { events: libc::EPOLLIN | libc::EPOLLOUT, data: fds[0] }], 10); } // This test shows a data_race before epoll had vector clocks added. @@ -110,7 +99,7 @@ fn test_epoll_race() { let fd = errno_result(unsafe { libc::eventfd(0, flags) }).unwrap(); // Register eventfd with the epoll instance. - epoll_ctl_add(epfd, fd, EPOLL_IN_OUT_ET).unwrap(); + epoll_ctl_add(epfd, fd, libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap(); static mut VAL: u8 = 0; let thread1 = thread::spawn(move || { @@ -121,11 +110,7 @@ fn test_epoll_race() { }); thread::yield_now(); // epoll_wait for the event to happen. - check_epoll_wait::<8>( - epfd, - &[Ev { events: (libc::EPOLLIN | libc::EPOLLOUT) as _, data: fd }], - -1, - ); + check_epoll_wait::<8>(epfd, &[Ev { events: (libc::EPOLLIN | libc::EPOLLOUT), data: fd }], -1); // Read from the static mut variable. #[allow(static_mut_refs)] unsafe { @@ -151,7 +136,7 @@ fn wakeup_on_new_interest() { let t = std::thread::spawn(move || { check_epoll_wait::<8>( epfd, - &[Ev { events: (libc::EPOLLIN | libc::EPOLLOUT) as _, data: fds[1] }], + &[Ev { events: libc::EPOLLIN | libc::EPOLLOUT, data: fds[1] }], -1, ); }); @@ -159,7 +144,8 @@ fn wakeup_on_new_interest() { std::thread::yield_now(); // Register fd[1] with EPOLLIN|EPOLLOUT|EPOLLET|EPOLLRDHUP - epoll_ctl_add(epfd, fds[1], EPOLL_IN_OUT_ET | libc::EPOLLRDHUP as i32).unwrap(); + epoll_ctl_add(epfd, fds[1], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET | libc::EPOLLRDHUP) + .unwrap(); // This should wake up the thread. t.join().unwrap(); @@ -178,14 +164,12 @@ fn multiple_events_wake_multiple_threads() { let fd2 = errno_result(unsafe { libc::dup(fd1) }).unwrap(); // Register both with epoll. - epoll_ctl_add(epfd, fd1, EPOLL_IN_OUT_ET).unwrap(); - epoll_ctl_add(epfd, fd2, EPOLL_IN_OUT_ET).unwrap(); + epoll_ctl_add(epfd, fd1, libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap(); + epoll_ctl_add(epfd, fd2, libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap(); // Consume the initial events. - let expected = [ - Ev { events: libc::EPOLLOUT as _, data: fd1 }, - Ev { events: libc::EPOLLOUT as _, data: fd2 }, - ]; + let expected = + [Ev { events: libc::EPOLLOUT, data: fd1 }, Ev { events: libc::EPOLLOUT, data: fd2 }]; check_epoll_wait::<8>(epfd, &expected, -1); // Block two threads on the epoll, both wanting to get just one event. diff --git a/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs b/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs index 490895c8541b..63300c9a433c 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs @@ -32,9 +32,6 @@ fn main() { test_issue_4374_reads(); } -// Using `as` cast since `EPOLLET` wraps around -const EPOLL_IN_OUT_ET: u32 = (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET) as _; - #[track_caller] fn check_epoll_wait(epfd: i32, expected_notifications: &[(u32, u64)]) { let epoll_event = libc::epoll_event { events: 0, u64: 0 }; @@ -145,7 +142,10 @@ fn test_epoll_ctl_del() { assert_eq!(res, 5); // Register fd[1] with EPOLLIN|EPOLLOUT|EPOLLET - let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: u64::try_from(fds[1]).unwrap() }; + let mut ev = libc::epoll_event { + events: (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET) as u32, + u64: u64::try_from(fds[1]).unwrap(), + }; let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[1], &mut ev) }; assert_eq!(res, 0); @@ -173,11 +173,8 @@ fn test_two_epoll_instance() { assert_eq!(res, 5); // Register one side of the socketpair with EPOLLIN | EPOLLOUT | EPOLLET. - let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: u64::try_from(fds[1]).unwrap() }; - let res = unsafe { libc::epoll_ctl(epfd1, libc::EPOLL_CTL_ADD, fds[1], &mut ev) }; - assert_eq!(res, 0); - let res = unsafe { libc::epoll_ctl(epfd2, libc::EPOLL_CTL_ADD, fds[1], &mut ev) }; - assert_eq!(res, 0); + epoll_ctl_add(epfd1, fds[1], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap(); + epoll_ctl_add(epfd2, fds[1], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap(); // Notification should be received from both instance of epoll. let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap(); @@ -201,7 +198,10 @@ fn test_two_same_fd_in_same_epoll_instance() { assert_ne!(newfd, -1); // Register both fd to the same epoll instance. - let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: 5 as u64 }; + let mut ev = libc::epoll_event { + events: (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).cast_unsigned(), + u64: 5u64, + }; let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[1], &mut ev) }; assert_eq!(res, 0); let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, newfd, &mut ev) }; @@ -214,7 +214,7 @@ fn test_two_same_fd_in_same_epoll_instance() { // Two notification should be received. let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap(); - let expected_value = 5 as u64; + let expected_value = 5u64; check_epoll_wait::<8>( epfd, &[(expected_event, expected_value), (expected_event, expected_value)], @@ -233,9 +233,7 @@ fn test_epoll_eventfd() { let epfd = errno_result(unsafe { libc::epoll_create1(0) }).unwrap(); // Register eventfd with EPOLLIN | EPOLLOUT | EPOLLET - let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: u64::try_from(fd).unwrap() }; - let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd, &mut ev) }; - assert_eq!(res, 0); + epoll_ctl_add(epfd, fd, libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap(); // Check result from epoll_wait. let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap(); @@ -278,12 +276,8 @@ fn test_epoll_socketpair_both_sides() { errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }); // Register both fd to the same epoll instance. - let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fds[0] as u64 }; - let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[0], &mut ev) }; - assert_eq!(res, 0); - let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fds[1] as u64 }; - let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[1], &mut ev) }; - assert_eq!(res, 0); + epoll_ctl_add(epfd, fds[0], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap(); + epoll_ctl_add(epfd, fds[1], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap(); // Write to fds[1]. // (We do the write after the register here, unlike in `test_epoll_socketpair`, to ensure @@ -326,9 +320,7 @@ fn test_closed_fd() { let fd = errno_result(unsafe { libc::eventfd(0, flags) }).unwrap(); // Register eventfd with EPOLLIN | EPOLLOUT | EPOLLET - let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: u64::try_from(fd).unwrap() }; - let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd, &mut ev) }; - assert_eq!(res, 0); + epoll_ctl_add(epfd, fd, libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap(); // Write to the eventfd instance. let sized_8_data: [u8; 8] = 1_u64.to_ne_bytes(); @@ -360,9 +352,7 @@ fn test_not_fully_closed_fd() { let newfd = errno_result(unsafe { libc::dup(fd) }).unwrap(); // Register eventfd with EPOLLIN | EPOLLOUT | EPOLLET - let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: u64::try_from(fd).unwrap() }; - let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd, &mut ev) }; - assert_eq!(res, 0); + epoll_ctl_add(epfd, fd, libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap(); // Close the original fd that being used to register with epoll. errno_check(unsafe { libc::close(fd) }); @@ -402,7 +392,7 @@ fn test_event_overwrite() { // Register eventfd with EPOLLIN | EPOLLOUT | EPOLLET let mut ev = libc::epoll_event { - events: (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET) as _, + events: (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).cast_unsigned(), u64: u64::try_from(fd).unwrap(), }; let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd, &mut ev) }; @@ -431,13 +421,13 @@ fn test_socketpair_read() { // Register both fd to the same epoll instance. let mut ev = libc::epoll_event { - events: (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET) as _, + events: (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).cast_unsigned(), u64: fds[0] as u64, }; let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[0], &mut ev) }; assert_eq!(res, 0); let mut ev = libc::epoll_event { - events: (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET) as _, + events: (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).cast_unsigned(), u64: fds[1] as u64, }; let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[1], &mut ev) }; @@ -493,7 +483,7 @@ fn test_no_notification_for_unregister_flag() { // Register fd[0] with EPOLLOUT|EPOLLET. let mut ev = libc::epoll_event { - events: (libc::EPOLLOUT | libc::EPOLLET) as _, + events: (libc::EPOLLOUT | libc::EPOLLET).cast_unsigned(), u64: u64::try_from(fds[0]).unwrap(), }; let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[0], &mut ev) }; @@ -543,19 +533,15 @@ fn test_socketpair_epollerr() { errno_check(unsafe { libc::close(fds[1]) }); // Register fd[1] with EPOLLIN|EPOLLOUT|EPOLLET|EPOLLRDHUP - let mut ev = libc::epoll_event { - events: (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET | libc::EPOLLRDHUP) as _, - u64: u64::try_from(fds[1]).unwrap(), - }; - let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[0], &mut ev) }; - assert_ne!(res, -1); + epoll_ctl_add(epfd, fds[0], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET | libc::EPOLLRDHUP) + .unwrap(); // Check result from epoll_wait. let expected_event = u32::try_from( libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLHUP | libc::EPOLLRDHUP | libc::EPOLLERR, ) .unwrap(); - let expected_value = u64::try_from(fds[1]).unwrap(); + let expected_value = u64::try_from(fds[0]).unwrap(); check_epoll_wait::<8>(epfd, &[(expected_event, expected_value)]); } @@ -570,12 +556,8 @@ fn test_epoll_lost_events() { errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }); // Register both fd to the same epoll instance. - let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fds[0] as u64 }; - let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[0], &mut ev) }; - assert_eq!(res, 0); - let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fds[1] as u64 }; - let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[1], &mut ev) }; - assert_eq!(res, 0); + epoll_ctl_add(epfd, fds[0], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap(); + epoll_ctl_add(epfd, fds[1], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap(); // Two notification should be received. But we only provide buffer for one event. let expected_event0 = u32::try_from(libc::EPOLLOUT).unwrap(); @@ -601,12 +583,8 @@ fn test_ready_list_fetching_logic() { let fd1 = errno_result(unsafe { libc::eventfd(0, flags) }).unwrap(); // Register both fd to the same epoll instance. At this point, both of them are on the ready list. - let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fd0 as u64 }; - let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd0, &mut ev) }; - assert_eq!(res, 0); - let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fd1 as u64 }; - let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd1, &mut ev) }; - assert_eq!(res, 0); + epoll_ctl_add(epfd, fd0, libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap(); + epoll_ctl_add(epfd, fd1, libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap(); // Close fd0 so the first entry in the ready list will be empty. errno_check(unsafe { libc::close(fd0) }); @@ -643,9 +621,7 @@ fn test_epoll_ctl_notification() { errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }); // Register one side of the socketpair with epoll. - let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fds[0] as u64 }; - let res = unsafe { libc::epoll_ctl(epfd0, libc::EPOLL_CTL_ADD, fds[0], &mut ev) }; - assert_eq!(res, 0); + epoll_ctl_add(epfd0, fds[0], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap(); // epoll_wait to clear notification for epfd0. let expected_event = u32::try_from(libc::EPOLLOUT).unwrap(); @@ -657,9 +633,7 @@ fn test_epoll_ctl_notification() { assert_ne!(epfd1, -1); // Register the same file description for epfd1. - let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fds[0] as u64 }; - let res = unsafe { libc::epoll_ctl(epfd1, libc::EPOLL_CTL_ADD, fds[0], &mut ev) }; - assert_eq!(res, 0); + epoll_ctl_add(epfd1, fds[0], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap(); check_epoll_wait::<1>(epfd1, &[(expected_event, expected_value)]); // Previously this epoll_wait will receive a notification, but we shouldn't return notification @@ -683,7 +657,7 @@ fn test_issue_3858() { // Register eventfd with EPOLLIN | EPOLLET. let mut ev = libc::epoll_event { - events: (libc::EPOLLIN | libc::EPOLLET) as _, + events: (libc::EPOLLIN | libc::EPOLLET).cast_unsigned(), u64: u64::try_from(fd).unwrap(), }; let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd, &mut ev) }; @@ -715,9 +689,7 @@ fn test_issue_4374() { assert_eq!(unsafe { libc::fcntl(fds[1], libc::F_SETFL, libc::O_NONBLOCK) }, 0); // Register fds[0] with epoll while it is writable (but not readable). - let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fds[0] as u64 }; - let res = unsafe { libc::epoll_ctl(epfd0, libc::EPOLL_CTL_ADD, fds[0], &mut ev) }; - assert_eq!(res, 0); + epoll_ctl_add(epfd0, fds[0], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap(); // Fill up fds[0] so that it is not writable any more. let zeros = [0u8; 512]; @@ -754,9 +726,7 @@ fn test_issue_4374_reads() { assert_eq!(res, 5); // Register fds[0] with epoll while it is readable. - let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fds[0] as u64 }; - let res = unsafe { libc::epoll_ctl(epfd0, libc::EPOLL_CTL_ADD, fds[0], &mut ev) }; - assert_eq!(res, 0); + epoll_ctl_add(epfd0, fds[0], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap(); // Read fds[0] so it is no longer readable. let mut buf = [0u8; 512]; From b35f80f7f71336b1b22c5de4af9eb8e6b59cb8f5 Mon Sep 17 00:00:00 2001 From: oligamiq Date: Sun, 18 Jan 2026 23:37:51 +0900 Subject: [PATCH 0824/1061] fix: thread creation failed on the wasm32-wasip1-threads target. --- library/std/src/sys/thread/unix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/thread/unix.rs b/library/std/src/sys/thread/unix.rs index 6f23c28c04d6..5a210703ce9b 100644 --- a/library/std/src/sys/thread/unix.rs +++ b/library/std/src/sys/thread/unix.rs @@ -49,7 +49,7 @@ impl Thread { // WASI does not support threading via pthreads. While wasi-libc provides // pthread stubs, pthread_create returns EAGAIN, which causes confusing // errors. We return UNSUPPORTED_PLATFORM directly instead. - if cfg!(target_os = "wasi") { + if cfg!(all(target_os = "wasi", not(target_feature = "atomics"))) { return Err(io::Error::UNSUPPORTED_PLATFORM); } From ea77786cdb7e94006f74399ee67ff57068773375 Mon Sep 17 00:00:00 2001 From: Oscar Bray Date: Sun, 18 Jan 2026 16:48:45 +0000 Subject: [PATCH 0825/1061] Port #![no_main] to the attribute parser. --- .../src/attributes/crate_level.rs | 9 ++ compiler/rustc_attr_parsing/src/context.rs | 7 +- .../rustc_hir/src/attrs/data_structures.rs | 3 + .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 1 + compiler/rustc_passes/src/entry.rs | 5 +- .../issue-43106-gating-of-builtin-attrs.rs | 12 +- ...issue-43106-gating-of-builtin-attrs.stderr | 131 ++++++++++-------- 8 files changed, 96 insertions(+), 73 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index 5604fbd25edc..ab99186777f9 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -136,6 +136,15 @@ impl NoArgsAttributeParser for NoStdParser { const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoStd; } +pub(crate) struct NoMainParser; + +impl NoArgsAttributeParser for NoMainParser { + const PATH: &[Symbol] = &[sym::no_main]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoMain; +} + pub(crate) struct RustcCoherenceIsCoreParser; impl NoArgsAttributeParser for RustcCoherenceIsCoreParser { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 449894f7834b..c5b98139074e 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -28,9 +28,9 @@ use crate::attributes::codegen_attrs::{ }; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::crate_level::{ - CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoStdParser, PatternComplexityLimitParser, - RecursionLimitParser, RustcCoherenceIsCoreParser, TypeLengthLimitParser, - WindowsSubsystemParser, + CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoMainParser, NoStdParser, + PatternComplexityLimitParser, RecursionLimitParser, RustcCoherenceIsCoreParser, + TypeLengthLimitParser, WindowsSubsystemParser, }; use crate::attributes::debugger::DebuggerViualizerParser; use crate::attributes::deprecation::DeprecationParser; @@ -263,6 +263,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 7b7fae9fdcca..119bf554b2ae 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -852,6 +852,9 @@ pub enum AttributeKind { /// Represents `#[no_link]` NoLink, + /// Represents `#[no_main]` + NoMain, + /// Represents `#[no_mangle]` NoMangle(Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index dff8a5727771..7ba268c16271 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -79,6 +79,7 @@ impl AttributeKind { NoCore(..) => No, NoImplicitPrelude(..) => No, NoLink => No, + NoMain => No, NoMangle(..) => Yes, // Needed for rustdoc NoStd(..) => No, NonExhaustive(..) => Yes, // Needed for rustdoc diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 4b71d4755cb6..50e80cabdb07 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -297,6 +297,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::PatternComplexityLimit { .. } | AttributeKind::NoCore { .. } | AttributeKind::NoStd { .. } + | AttributeKind::NoMain | AttributeKind::ObjcClass { .. } | AttributeKind::ObjcSelector { .. } | AttributeKind::RustcCoherenceIsCore(..) diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index c02a01c1b823..bd737518ed47 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -1,4 +1,3 @@ -use rustc_ast::attr; use rustc_ast::entry::EntryPointType; use rustc_errors::codes::*; use rustc_hir::attrs::AttributeKind; @@ -7,7 +6,7 @@ use rustc_hir::{CRATE_HIR_ID, ItemId, Node, find_attr}; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::config::{CrateType, EntryFnType, sigpipe}; -use rustc_span::{RemapPathScopeComponents, Span, sym}; +use rustc_span::{RemapPathScopeComponents, Span}; use crate::errors::{ExternMain, MultipleRustcMain, NoMainErr}; @@ -30,7 +29,7 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> { } // If the user wants no main function at all, then stop here. - if attr::contains_name(tcx.hir_attrs(CRATE_HIR_ID), sym::no_main) { + if find_attr!(tcx.hir_attrs(CRATE_HIR_ID), AttributeKind::NoMain) { return None; } diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs index 6716e78a7197..3e3235e658f6 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs @@ -884,26 +884,26 @@ mod feature { #[no_main] //~^ WARN crate-level attribute should be an inner attribute -//~| HELP add a `!` mod no_main_1 { + //~^ NOTE: This attribute does not have an `!`, which means it is applied to this module mod inner { #![no_main] } -//~^ WARN crate-level attribute should be in the root module + //~^ WARN the `#![no_main]` attribute can only be used at the crate root #[no_main] fn f() { } //~^ WARN crate-level attribute should be an inner attribute - //~| HELP add a `!` + //~| NOTE This attribute does not have an `!`, which means it is applied to this function #[no_main] struct S; //~^ WARN crate-level attribute should be an inner attribute - //~| HELP add a `!` + //~| NOTE This attribute does not have an `!`, which means it is applied to this struct #[no_main] type T = S; //~^ WARN crate-level attribute should be an inner attribute - //~| HELP add a `!` + //~| NOTE This attribute does not have an `!`, which means it is applied to this type alias #[no_main] impl S { } //~^ WARN crate-level attribute should be an inner attribute - //~| HELP add a `!` + //~| NOTE This attribute does not have an `!`, which means it is applied to this implementation } #[no_builtins] diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr index 8ed39a0079ba..d89aec222be8 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr @@ -240,17 +240,6 @@ help: add a `!` LL | #![feature(x0600)] | + -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:885:1 - | -LL | #[no_main] - | ^^^^^^^^^^ - | -help: add a `!` - | -LL | #![no_main] - | + - warning: crate-level attribute should be an inner attribute --> $DIR/issue-43106-gating-of-builtin-attrs.rs:909:1 | @@ -476,56 +465,6 @@ help: add a `!` LL | #![feature(x0600)] impl S { } | + -warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:889:17 - | -LL | mod inner { #![no_main] } - | ^^^^^^^^^^^ - -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:892:5 - | -LL | #[no_main] fn f() { } - | ^^^^^^^^^^ - | -help: add a `!` - | -LL | #![no_main] fn f() { } - | + - -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:896:5 - | -LL | #[no_main] struct S; - | ^^^^^^^^^^ - | -help: add a `!` - | -LL | #![no_main] struct S; - | + - -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:900:5 - | -LL | #[no_main] type T = S; - | ^^^^^^^^^^ - | -help: add a `!` - | -LL | #![no_main] type T = S; - | + - -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:904:5 - | -LL | #[no_main] impl S { } - | ^^^^^^^^^^ - | -help: add a `!` - | -LL | #![no_main] impl S { } - | + - warning: crate-level attribute should be in the root module --> $DIR/issue-43106-gating-of-builtin-attrs.rs:913:17 | @@ -1407,6 +1346,76 @@ note: This attribute does not have an `!`, which means it is applied to this imp LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^ +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_main]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:885:1 + | +LL | #[no_main] + | ^^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this module + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:887:1 + | +LL | / mod no_main_1 { +LL | | +LL | | mod inner { #![no_main] } +... | +LL | | } + | |_^ + +warning: the `#![no_main]` attribute can only be used at the crate root + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:889:17 + | +LL | mod inner { #![no_main] } + | ^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_main]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:892:5 + | +LL | #[no_main] fn f() { } + | ^^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this function + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:892:16 + | +LL | #[no_main] fn f() { } + | ^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_main]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:896:5 + | +LL | #[no_main] struct S; + | ^^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this struct + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:896:16 + | +LL | #[no_main] struct S; + | ^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_main]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:900:5 + | +LL | #[no_main] type T = S; + | ^^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this type alias + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:900:16 + | +LL | #[no_main] type T = S; + | ^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_main]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:904:5 + | +LL | #[no_main] impl S { } + | ^^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this implementation block + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:904:16 + | +LL | #[no_main] impl S { } + | ^^^^^^^^^^ + warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` --> $DIR/issue-43106-gating-of-builtin-attrs.rs:933:1 | From c367dfde6972ba60eca9f295d68be2f80060742e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Jan 2026 18:08:16 +0100 Subject: [PATCH 0826/1061] shims: add FIXME for missing direct tests --- .../src/shims/unix/android/foreign_items.rs | 6 ++++ .../miri/src/shims/unix/foreign_items.rs | 19 ++++++++++++ .../src/shims/unix/freebsd/foreign_items.rs | 3 ++ .../src/shims/unix/linux/foreign_items.rs | 5 +++ .../src/shims/unix/macos/foreign_items.rs | 11 +++++++ .../src/shims/unix/solarish/foreign_items.rs | 5 +++ .../miri/src/shims/windows/foreign_items.rs | 31 +++++++++++++++++++ .../fail-dep/concurrency/windows_join_main.rs | 2 +- 8 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/tools/miri/src/shims/unix/android/foreign_items.rs b/src/tools/miri/src/shims/unix/android/foreign_items.rs index 2b290b68c78c..f00bfb0a2078 100644 --- a/src/tools/miri/src/shims/unix/android/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/android/foreign_items.rs @@ -28,21 +28,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match link_name.as_str() { // File related shims "stat" => { + // FIXME: This does not have a direct test (#3179). let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let result = this.stat(path, buf)?; this.write_scalar(result, dest)?; } "lstat" => { + // FIXME: This does not have a direct test (#3179). let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let result = this.lstat(path, buf)?; this.write_scalar(result, dest)?; } "readdir" => { + // FIXME: This does not have a direct test (#3179). let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let result = this.readdir64("dirent", dirp)?; this.write_scalar(result, dest)?; } "pread64" => { + // FIXME: This does not have a direct test (#3179). let [fd, buf, count, offset] = this.check_shim_sig( shim_sig!(extern "C" fn(i32, *mut _, usize, libc::off64_t) -> isize), link_name, @@ -56,6 +60,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.read(fd, buf, count, Some(offset), dest)?; } "pwrite64" => { + // FIXME: This does not have a direct test (#3179). let [fd, buf, n, offset] = this.check_shim_sig( shim_sig!(extern "C" fn(i32, *const _, usize, libc::off64_t) -> isize), link_name, @@ -70,6 +75,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write(fd, buf, count, Some(offset), dest)?; } "lseek64" => { + // FIXME: This does not have a direct test (#3179). let [fd, offset, whence] = this.check_shim_sig( shim_sig!(extern "C" fn(i32, libc::off64_t, i32) -> libc::off64_t), link_name, diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 8eacdc3583d4..04ec260eccd0 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -143,6 +143,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "getcwd" => { + // FIXME: This does not have a direct test (#3179). let [buf, size] = this.check_shim_sig( shim_sig!(extern "C" fn(*mut _, usize) -> *mut _), link_name, @@ -153,6 +154,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_pointer(result, dest)?; } "chdir" => { + // FIXME: This does not have a direct test (#3179). let [path] = this.check_shim_sig( shim_sig!(extern "C" fn(*const _) -> i32), link_name, @@ -209,6 +211,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write(fd, buf, count, None, dest)?; } "pread" => { + // FIXME: This does not have a direct test (#3179). let [fd, buf, count, offset] = this.check_shim_sig( shim_sig!(extern "C" fn(i32, *mut _, usize, libc::off_t) -> isize), link_name, @@ -222,6 +225,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.read(fd, buf, count, Some(offset), dest)?; } "pwrite" => { + // FIXME: This does not have a direct test (#3179). let [fd, buf, n, offset] = this.check_shim_sig( shim_sig!(extern "C" fn(i32, *const _, usize, libc::off_t) -> isize), link_name, @@ -299,6 +303,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "unlink" => { + // FIXME: This does not have a direct test (#3179). let [path] = this.check_shim_sig( shim_sig!(extern "C" fn(*const _) -> i32), link_name, @@ -309,6 +314,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "symlink" => { + // FIXME: This does not have a direct test (#3179). let [target, linkpath] = this.check_shim_sig( shim_sig!(extern "C" fn(*const _, *const _) -> i32), link_name, @@ -324,6 +330,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "rename" => { + // FIXME: This does not have a direct test (#3179). let [oldpath, newpath] = this.check_shim_sig( shim_sig!(extern "C" fn(*const _, *const _) -> i32), link_name, @@ -334,6 +341,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "mkdir" => { + // FIXME: This does not have a direct test (#3179). let [path, mode] = this.check_shim_sig( shim_sig!(extern "C" fn(*const _, libc::mode_t) -> i32), link_name, @@ -344,6 +352,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "rmdir" => { + // FIXME: This does not have a direct test (#3179). let [path] = this.check_shim_sig( shim_sig!(extern "C" fn(*const _) -> i32), link_name, @@ -354,6 +363,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "opendir" => { + // FIXME: This does not have a direct test (#3179). let [name] = this.check_shim_sig( shim_sig!(extern "C" fn(*const _) -> *mut _), link_name, @@ -364,6 +374,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "closedir" => { + // FIXME: This does not have a direct test (#3179). let [dirp] = this.check_shim_sig( shim_sig!(extern "C" fn(*mut _) -> i32), link_name, @@ -374,6 +385,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "lseek" => { + // FIXME: This does not have a direct test (#3179). let [fd, offset, whence] = this.check_shim_sig( shim_sig!(extern "C" fn(i32, libc::off_t, i32) -> libc::off_t), link_name, @@ -398,6 +410,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "fsync" => { + // FIXME: This does not have a direct test (#3179). let [fd] = this.check_shim_sig( shim_sig!(extern "C" fn(i32) -> i32), link_name, @@ -408,6 +421,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "fdatasync" => { + // FIXME: This does not have a direct test (#3179). let [fd] = this.check_shim_sig( shim_sig!(extern "C" fn(i32) -> i32), link_name, @@ -659,6 +673,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } "pthread_key_delete" => { + // FIXME: This does not have a direct test (#3179). let [key] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let key = this.read_scalar(key)?.to_bits(key.layout.size)?; this.machine.tls.delete_tls_key(key)?; @@ -666,6 +681,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } "pthread_getspecific" => { + // FIXME: This does not have a direct test (#3179). let [key] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let key = this.read_scalar(key)?.to_bits(key.layout.size)?; let active_thread = this.active_thread(); @@ -673,6 +689,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { + // FIXME: This does not have a direct test (#3179). let [key, new_ptr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let key = this.read_scalar(key)?.to_bits(key.layout.size)?; @@ -833,6 +850,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } "sched_yield" => { + // FIXME: This does not have a direct test (#3179). let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; this.sched_yield()?; this.write_null(dest)?; @@ -941,6 +959,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "pthread_atfork" => { + // FIXME: This does not have a direct test (#3179). let [prepare, parent, child] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; this.read_pointer(prepare)?; diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs index fb2d3f758420..b94ee27c46a0 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -139,11 +139,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // For those, we both intercept `func` and `call@FBSD_1.0` symbols cases // since freebsd 12 the former form can be expected. "stat" | "stat@FBSD_1.0" => { + // FIXME: This does not have a direct test (#3179). let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let result = this.stat(path, buf)?; this.write_scalar(result, dest)?; } "lstat" | "lstat@FBSD_1.0" => { + // FIXME: This does not have a direct test (#3179). let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let result = this.lstat(path, buf)?; this.write_scalar(result, dest)?; @@ -154,6 +156,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "readdir" | "readdir@FBSD_1.0" => { + // FIXME: This does not have a direct test (#3179). let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let result = this.readdir64("dirent", dirp)?; this.write_scalar(result, dest)?; diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index a7cb2ed11b2b..426bc28ce887 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -45,6 +45,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "pread64" => { + // FIXME: This does not have a direct test (#3179). let [fd, buf, count, offset] = this.check_shim_sig( shim_sig!(extern "C" fn(i32, *mut _, usize, libc::off64_t) -> isize), link_name, @@ -58,6 +59,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.read(fd, buf, count, Some(offset), dest)?; } "pwrite64" => { + // FIXME: This does not have a direct test (#3179). let [fd, buf, n, offset] = this.check_shim_sig( shim_sig!(extern "C" fn(i32, *const _, usize, libc::off64_t) -> isize), link_name, @@ -72,6 +74,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write(fd, buf, count, Some(offset), dest)?; } "lseek64" => { + // FIXME: This does not have a direct test (#3179). let [fd, offset, whence] = this.check_shim_sig( shim_sig!(extern "C" fn(i32, libc::off64_t, i32) -> libc::off64_t), link_name, @@ -111,6 +114,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "readdir64" => { + // FIXME: This does not have a direct test (#3179). let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let result = this.readdir64("dirent64", dirp)?; this.write_scalar(result, dest)?; @@ -122,6 +126,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "statx" => { + // FIXME: This does not have a direct test (#3179). let [dirfd, pathname, flags, mask, statxbuf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?; diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index f798f64441b1..204934f4c41d 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -47,11 +47,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "stat" | "stat$INODE64" => { + // FIXME: This does not have a direct test (#3179). let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let result = this.stat(path, buf)?; this.write_scalar(result, dest)?; } "lstat" | "lstat$INODE64" => { + // FIXME: This does not have a direct test (#3179). let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let result = this.lstat(path, buf)?; this.write_scalar(result, dest)?; @@ -62,11 +64,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "opendir$INODE64" => { + // FIXME: This does not have a direct test (#3179). let [name] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir_r" | "readdir_r$INODE64" => { + // FIXME: This does not have a direct test (#3179). let [dirp, entry, result] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let result = this.macos_readdir_r(dirp, entry, result)?; @@ -87,6 +91,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Environment related shims "_NSGetEnviron" => { + // FIXME: This does not have a direct test (#3179). let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let environ = this.machine.env_vars.unix().environ(); this.write_pointer(environ, dest)?; @@ -111,6 +116,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "mach_timebase_info" => { + // FIXME: This does not have a direct test (#3179). let [info] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let result = this.mach_timebase_info(info)?; this.write_scalar(result, dest)?; @@ -118,14 +124,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Access to command-line arguments "_NSGetArgc" => { + // FIXME: This does not have a direct test (#3179). let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; this.write_pointer(this.machine.argc.expect("machine must be initialized"), dest)?; } "_NSGetArgv" => { + // FIXME: This does not have a direct test (#3179). let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; this.write_pointer(this.machine.argv.expect("machine must be initialized"), dest)?; } "_NSGetExecutablePath" => { + // FIXME: This does not have a direct test (#3179). let [buf, bufsize] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; this.check_no_isolation("`_NSGetExecutablePath`")?; @@ -168,12 +177,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Querying system information "pthread_get_stackaddr_np" => { + // FIXME: This does not have a direct test (#3179). let [thread] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; this.read_target_usize(thread)?; let stack_addr = Scalar::from_uint(this.machine.stack_addr, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { + // FIXME: This does not have a direct test (#3179). let [thread] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; this.read_target_usize(thread)?; let stack_size = Scalar::from_uint(this.machine.stack_size, this.pointer_size()); diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs index fa8c86b025a7..f3918fdccf12 100644 --- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs @@ -91,16 +91,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // File related shims "stat" => { + // FIXME: This does not have a direct test (#3179). let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let result = this.stat(path, buf)?; this.write_scalar(result, dest)?; } "lstat" => { + // FIXME: This does not have a direct test (#3179). let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let result = this.lstat(path, buf)?; this.write_scalar(result, dest)?; } "readdir" => { + // FIXME: This does not have a direct test (#3179). let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let result = this.readdir64("dirent", dirp)?; this.write_scalar(result, dest)?; @@ -122,6 +125,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "stack_getbounds" => { + // FIXME: This does not have a direct test (#3179). let [stack] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let stack = this.deref_pointer_as(stack, this.libc_ty_layout("stack_t"))?; @@ -140,6 +144,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "pset_info" => { + // FIXME: This does not have a direct test (#3179). let [pset, tpe, cpus, list] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; // We do not need to handle the current process cpu mask, available_parallelism diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index 1905fb22e26a..0bdf6bb78505 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -148,6 +148,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match link_name.as_str() { // Environment related shims "GetEnvironmentVariableW" => { + // FIXME: This does not have a direct test (#3179). let [name, buf, size] = this.check_shim_sig( shim_sig!(extern "system" fn(*const _, *mut _, u32) -> u32), link_name, @@ -158,6 +159,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "SetEnvironmentVariableW" => { + // FIXME: This does not have a direct test (#3179). let [name, value] = this.check_shim_sig( shim_sig!(extern "system" fn(*const _, *const _) -> winapi::BOOL), link_name, @@ -168,6 +170,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "GetEnvironmentStringsW" => { + // FIXME: This does not have a direct test (#3179). let [] = this.check_shim_sig( shim_sig!(extern "system" fn() -> *mut _), link_name, @@ -178,6 +181,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_pointer(result, dest)?; } "FreeEnvironmentStringsW" => { + // FIXME: This does not have a direct test (#3179). let [env_block] = this.check_shim_sig( shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL), link_name, @@ -188,6 +192,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "GetCurrentDirectoryW" => { + // FIXME: This does not have a direct test (#3179). let [size, buf] = this.check_shim_sig( shim_sig!(extern "system" fn(u32, *mut _) -> u32), link_name, @@ -198,6 +203,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "SetCurrentDirectoryW" => { + // FIXME: This does not have a direct test (#3179). let [path] = this.check_shim_sig( shim_sig!(extern "system" fn(*const _) -> winapi::BOOL), link_name, @@ -208,6 +214,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "GetUserProfileDirectoryW" => { + // FIXME: This does not have a direct test (#3179). let [token, buf, size] = this.check_shim_sig( shim_sig!(extern "system" fn(winapi::HANDLE, *mut _, *mut _) -> winapi::BOOL), link_name, @@ -218,6 +225,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "GetCurrentProcessId" => { + // FIXME: This does not have a direct test (#3179). let [] = this.check_shim_sig( shim_sig!(extern "system" fn() -> u32), link_name, @@ -314,6 +322,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { )?; } "GetFullPathNameW" => { + // FIXME: This does not have a direct test (#3179). let [filename, size, buffer, filepart] = this.check_shim_sig( shim_sig!(extern "system" fn(*const _, u32, *mut _, *mut _) -> u32), link_name, @@ -445,6 +454,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Allocation "HeapAlloc" => { + // FIXME: This does not have a direct test (#3179). let [handle, flags, size] = this.check_shim_sig( shim_sig!(extern "system" fn(winapi::HANDLE, u32, usize) -> *mut _), link_name, @@ -472,6 +482,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_pointer(ptr, dest)?; } "HeapFree" => { + // FIXME: This does not have a direct test (#3179). let [handle, flags, ptr] = this.check_shim_sig( shim_sig!(extern "system" fn(winapi::HANDLE, u32, *mut _) -> winapi::BOOL), link_name, @@ -489,6 +500,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_i32(1), dest)?; } "HeapReAlloc" => { + // FIXME: This does not have a direct test (#3179). let [handle, flags, old_ptr, size] = this.check_shim_sig( shim_sig!(extern "system" fn(winapi::HANDLE, u32, *mut _, usize) -> *mut _), link_name, @@ -514,6 +526,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_pointer(new_ptr, dest)?; } "LocalFree" => { + // FIXME: This does not have a direct test (#3179). let [ptr] = this.check_shim_sig( shim_sig!(extern "system" fn(winapi::HLOCAL) -> winapi::HLOCAL), link_name, @@ -577,6 +590,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Querying system information "GetSystemInfo" => { + // FIXME: This does not have a direct test (#3179). // Also called from `page_size` crate. let [system_info] = this.check_shim_sig( shim_sig!(extern "system" fn(*mut _) -> ()), @@ -658,6 +672,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Access to command-line arguments "GetCommandLineW" => { + // FIXME: This does not have a direct test (#3179). let [] = this.check_shim_sig( shim_sig!(extern "system" fn() -> *mut _), link_name, @@ -672,6 +687,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Time related shims "GetSystemTimeAsFileTime" | "GetSystemTimePreciseAsFileTime" => { + // FIXME: This does not have a direct test (#3179). let [filetime] = this.check_shim_sig( shim_sig!(extern "system" fn(*mut _) -> ()), link_name, @@ -681,6 +697,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.GetSystemTimeAsFileTime(link_name.as_str(), filetime)?; } "QueryPerformanceCounter" => { + // FIXME: This does not have a direct test (#3179). let [performance_count] = this.check_shim_sig( shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL), link_name, @@ -691,6 +708,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "QueryPerformanceFrequency" => { + // FIXME: This does not have a direct test (#3179). let [frequency] = this.check_shim_sig( shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL), link_name, @@ -701,6 +719,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "Sleep" => { + // FIXME: This does not have a direct test (#3179). let [timeout] = this.check_shim_sig( shim_sig!(extern "system" fn(u32) -> ()), link_name, @@ -711,6 +730,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.Sleep(timeout)?; } "CreateWaitableTimerExW" => { + // FIXME: This does not have a direct test (#3179). let [attributes, name, flags, access] = this.check_shim_sig( shim_sig!(extern "system" fn(*mut _, *const _, u32, u32) -> winapi::HANDLE), link_name, @@ -748,6 +768,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "WaitOnAddress" => { + // FIXME: This does not have a direct test (#3179). let [ptr_op, compare_op, size_op, timeout_op] = this.check_shim_sig( // First pointer is volatile shim_sig!(extern "system" fn(*mut _, *mut _, usize, u32) -> winapi::BOOL), @@ -759,6 +780,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.WaitOnAddress(ptr_op, compare_op, size_op, timeout_op, dest)?; } "WakeByAddressSingle" => { + // FIXME: This does not have a direct test (#3179). let [ptr_op] = this.check_shim_sig( shim_sig!(extern "system" fn(*mut _) -> ()), link_name, @@ -769,6 +791,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.WakeByAddressSingle(ptr_op)?; } "WakeByAddressAll" => { + // FIXME: This does not have a direct test (#3179). let [ptr_op] = this.check_shim_sig( shim_sig!(extern "system" fn(*mut _) -> ()), link_name, @@ -781,6 +804,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Dynamic symbol loading "GetProcAddress" => { + // FIXME: This does not have a direct test (#3179). let [module, proc_name] = this.check_shim_sig( shim_sig!(extern "system" fn(winapi::HMODULE, *const _) -> winapi::FARPROC), link_name, @@ -936,6 +960,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Miscellaneous "ExitProcess" => { + // FIXME: This does not have a direct test (#3179). let [code] = this.check_shim_sig( shim_sig!(extern "system" fn(u32) -> ()), link_name, @@ -962,6 +987,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_bool(true), dest)?; } "ProcessPrng" => { + // FIXME: This does not have a direct test (#3179). // used by `std` let [ptr, len] = this.check_shim_sig( shim_sig!(extern "system" fn(*mut _, usize) -> winapi::BOOL), @@ -1014,6 +1040,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; // STATUS_SUCCESS } "GetConsoleScreenBufferInfo" => { + // FIXME: This does not have a direct test (#3179). // `term` needs this, so we fake it. let [console, buffer_info] = this.check_shim_sig( shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> winapi::BOOL), @@ -1029,6 +1056,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } "GetStdHandle" => { + // FIXME: This does not have a direct test (#3179). let [which] = this.check_shim_sig( shim_sig!(extern "system" fn(u32) -> winapi::HANDLE), link_name, @@ -1080,6 +1108,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(ret, dest)?; } "GetModuleFileNameW" => { + // FIXME: This does not have a direct test (#3179). let [handle, filename, size] = this.check_shim_sig( shim_sig!(extern "system" fn(winapi::HMODULE, *mut _, u32) -> u32), link_name, @@ -1118,6 +1147,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } "FormatMessageW" => { + // FIXME: This does not have a direct test (#3179). let [flags, module, message_id, language_id, buffer, size, arguments] = this .check_shim_sig( shim_sig!( @@ -1159,6 +1189,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "_Unwind_RaiseException" => { + // FIXME: This does not have a direct test (#3179). // This is not formally part of POSIX, but it is very wide-spread on POSIX systems. // It was originally specified as part of the Itanium C++ ABI: // https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#base-throw. diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs index da549a8d117d..a71778b1d0d4 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs @@ -12,7 +12,7 @@ use windows_sys::Win32::System::Threading::{INFINITE, WaitForSingleObject}; // XXX HACK: This is how miri represents the handle for thread 0. // This value can be "legitimately" obtained by using `GetCurrentThread` with `DuplicateHandle` -// but miri does not implement `DuplicateHandle` yet. +// but miri does not implement `DuplicateHandle` yet. (FIXME: it does now.) const MAIN_THREAD: HANDLE = (2i32 << 29) as HANDLE; fn main() { From ec787b07fd34fd68a35a6d9b07927dd06dad6da4 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 18 Jan 2026 18:26:59 +0100 Subject: [PATCH 0827/1061] Remove `DiagMessage::Translated` in favour of `DiagMessage::Str` --- compiler/rustc_error_messages/src/lib.rs | 22 +++++----------------- compiler/rustc_errors/src/lib.rs | 2 +- compiler/rustc_errors/src/translation.rs | 2 +- 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 085403c8ef36..c0737edd7d65 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -244,13 +244,6 @@ type FluentId = Cow<'static, str>; pub enum SubdiagMessage { /// Non-translatable diagnostic message. Str(Cow<'static, str>), - /// Translatable message which has already been translated eagerly. - /// - /// Some diagnostics have repeated subdiagnostics where the same interpolated variables would - /// be instantiated multiple times with different values. These subdiagnostics' messages - /// are translated when they are added to the parent diagnostic, producing this variant of - /// `DiagMessage`. - Translated(Cow<'static, str>), /// Identifier of a Fluent message. Instances of this variant are generated by the /// `Subdiagnostic` derive. FluentIdentifier(FluentId), @@ -285,15 +278,13 @@ impl From> for SubdiagMessage { #[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] #[rustc_diagnostic_item = "DiagMessage"] pub enum DiagMessage { - /// Non-translatable diagnostic message. - Str(Cow<'static, str>), - /// Translatable message which has been already translated. + /// Non-translatable diagnostic message or a message that has been translated eagerly. /// /// Some diagnostics have repeated subdiagnostics where the same interpolated variables would /// be instantiated multiple times with different values. These subdiagnostics' messages - /// are translated when they are added to the parent diagnostic, producing this variant of - /// `DiagMessage`. - Translated(Cow<'static, str>), + /// are translated when they are added to the parent diagnostic. This is one of the ways + /// this variant of `DiagMessage` is produced. + Str(Cow<'static, str>), /// Identifier for a Fluent message (with optional attribute) corresponding to the diagnostic /// message. Yet to be translated. /// @@ -311,7 +302,6 @@ impl DiagMessage { pub fn with_subdiagnostic_message(&self, sub: SubdiagMessage) -> Self { let attr = match sub { SubdiagMessage::Str(s) => return DiagMessage::Str(s), - SubdiagMessage::Translated(s) => return DiagMessage::Translated(s), SubdiagMessage::FluentIdentifier(id) => { return DiagMessage::FluentIdentifier(id, None); } @@ -320,7 +310,6 @@ impl DiagMessage { match self { DiagMessage::Str(s) => DiagMessage::Str(s.clone()), - DiagMessage::Translated(s) => DiagMessage::Translated(s.clone()), DiagMessage::FluentIdentifier(id, _) => { DiagMessage::FluentIdentifier(id.clone(), Some(attr)) } @@ -329,7 +318,7 @@ impl DiagMessage { pub fn as_str(&self) -> Option<&str> { match self { - DiagMessage::Translated(s) | DiagMessage::Str(s) => Some(s), + DiagMessage::Str(s) => Some(s), DiagMessage::FluentIdentifier(_, _) => None, } } @@ -360,7 +349,6 @@ impl From for SubdiagMessage { fn from(val: DiagMessage) -> Self { match val { DiagMessage::Str(s) => SubdiagMessage::Str(s), - DiagMessage::Translated(s) => SubdiagMessage::Translated(s), DiagMessage::FluentIdentifier(id, None) => SubdiagMessage::FluentIdentifier(id), // There isn't really a sensible behaviour for this because it loses information but // this is the most sensible of the behaviours. diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 148368045f4f..102dd840556b 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1745,7 +1745,7 @@ impl DiagCtxtInner { message: DiagMessage, args: impl Iterator>, ) -> SubdiagMessage { - SubdiagMessage::Translated(Cow::from(self.eagerly_translate_to_string(message, args))) + SubdiagMessage::Str(Cow::from(self.eagerly_translate_to_string(message, args))) } /// Translate `message` eagerly with `args` to `String`. diff --git a/compiler/rustc_errors/src/translation.rs b/compiler/rustc_errors/src/translation.rs index c0bcec093c7e..5bffd74740dc 100644 --- a/compiler/rustc_errors/src/translation.rs +++ b/compiler/rustc_errors/src/translation.rs @@ -76,7 +76,7 @@ impl Translator { ) -> Result, TranslateError<'a>> { trace!(?message, ?args); let (identifier, attr) = match message { - DiagMessage::Str(msg) | DiagMessage::Translated(msg) => { + DiagMessage::Str(msg) => { return Ok(Cow::Borrowed(msg)); } DiagMessage::FluentIdentifier(identifier, attr) => (identifier, attr), From 85200a4ef0e889c35473dad54a3b04ab8540fce6 Mon Sep 17 00:00:00 2001 From: Clara Engler Date: Fri, 16 Jan 2026 18:10:08 +0100 Subject: [PATCH 0828/1061] option: Use Option::map in Option::cloned This commit removes a repetitive match statement in favor of Option::map for Option::cloned. --- library/core/src/option.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index ed31d4efaa75..eb4f978b7c19 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -2103,10 +2103,7 @@ impl Option<&T> { where T: Clone, { - match self { - Some(t) => Some(t.clone()), - None => None, - } + self.map(T::clone) } } @@ -2154,10 +2151,7 @@ impl Option<&mut T> { where T: Clone, { - match self { - Some(t) => Some(t.clone()), - None => None, - } + self.as_deref().map(T::clone) } } From 43fb39f3fed61e05520aebe23d3c5815fbc896f4 Mon Sep 17 00:00:00 2001 From: chillfish8 Date: Sun, 11 Jan 2026 21:56:30 +0000 Subject: [PATCH 0829/1061] Add avx512 `pack*` family of instructions --- src/tools/miri/src/shims/x86/avx512.rs | 34 ++++- .../pass/shims/x86/intrinsics-x86-avx512.rs | 130 +++++++++++++++++- 2 files changed, 161 insertions(+), 3 deletions(-) diff --git a/src/tools/miri/src/shims/x86/avx512.rs b/src/tools/miri/src/shims/x86/avx512.rs index 9231fc446919..b057a78b6c8e 100644 --- a/src/tools/miri/src/shims/x86/avx512.rs +++ b/src/tools/miri/src/shims/x86/avx512.rs @@ -3,7 +3,7 @@ use rustc_middle::ty::Ty; use rustc_span::Symbol; use rustc_target::callconv::FnAbi; -use super::{permute, pmaddbw, pmaddwd, psadbw, pshufb}; +use super::{packssdw, packsswb, packusdw, packuswb, permute, pmaddbw, pmaddwd, psadbw, pshufb}; use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} @@ -130,6 +130,38 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { vpdpbusd(this, src, a, b, dest)?; } + // Used to implement the _mm512_packs_epi16 function + "packsswb.512" => { + this.expect_target_feature_for_intrinsic(link_name, "avx512bw")?; + + let [a, b] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + + packsswb(this, a, b, dest)?; + } + // Used to implement the _mm512_packus_epi16 function + "packuswb.512" => { + this.expect_target_feature_for_intrinsic(link_name, "avx512bw")?; + + let [a, b] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + + packuswb(this, a, b, dest)?; + } + // Used to implement the _mm512_packs_epi32 function + "packssdw.512" => { + this.expect_target_feature_for_intrinsic(link_name, "avx512bw")?; + + let [a, b] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + + packssdw(this, a, b, dest)?; + } + // Used to implement the _mm512_packus_epi32 function + "packusdw.512" => { + this.expect_target_feature_for_intrinsic(link_name, "avx512bw")?; + + let [a, b] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + + packusdw(this, a, b, dest)?; + } _ => return interp_ok(EmulateItemResult::NotSupported), } interp_ok(EmulateItemResult::NeedsReturn) diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs index 7cc554ef5a3c..e1e23eda8428 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs @@ -1,6 +1,6 @@ // We're testing x86 target specific features //@only-target: x86_64 i686 -//@compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bitalg,+avx512vpopcntdq,+avx512vnni +//@compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bw,+avx512bitalg,+avx512vpopcntdq,+avx512vnni #[cfg(target_arch = "x86")] use std::arch::x86::*; @@ -11,12 +11,14 @@ use std::mem::transmute; fn main() { assert!(is_x86_feature_detected!("avx512f")); assert!(is_x86_feature_detected!("avx512vl")); + assert!(is_x86_feature_detected!("avx512bw")); assert!(is_x86_feature_detected!("avx512bitalg")); assert!(is_x86_feature_detected!("avx512vpopcntdq")); assert!(is_x86_feature_detected!("avx512vnni")); unsafe { test_avx512(); + test_avx512bw(); test_avx512bitalg(); test_avx512vpopcntdq(); test_avx512ternarylogic(); @@ -579,9 +581,133 @@ unsafe fn test_avx512vnni() { test_mm512_dpbusd_epi32(); } +#[target_feature(enable = "avx512bw")] +unsafe fn test_avx512bw() { + #[target_feature(enable = "avx512bw")] + unsafe fn test_mm512_packs_epi16() { + let a = _mm512_set1_epi16(120); + + // Because `packs` instructions do signed saturation, we expect + // that any value over `i8::MAX` will be saturated to `i8::MAX`, and any value + // less than `i8::MIN` will also be saturated to `i8::MIN`. + let b = _mm512_set_epi16( + 200, 200, 200, 200, 200, 200, 200, 200, -200, -200, -200, -200, -200, -200, -200, -200, + 200, 200, 200, 200, 200, 200, 200, 200, -200, -200, -200, -200, -200, -200, -200, -200, + ); + + // The pack* family of instructions in x86 operate in blocks + // of 128-bit lanes, meaning the first 128-bit lane in `a` is converted and written + // then the first 128-bit lane of `b`, followed by the second 128-bit lane in `a`, etc... + // Because we are going from 16-bits to 8-bits our 128-bit block becomes 64-bits in + // the output register. + // This leaves us with 8x 8-bit values interleaved in the final register. + #[rustfmt::skip] + const DST: [i8; 64] = [ + 120, 120, 120, 120, 120, 120, 120, 120, + i8::MIN, i8::MIN, i8::MIN, i8::MIN, i8::MIN, i8::MIN, i8::MIN, i8::MIN, + 120, 120, 120, 120, 120, 120, 120, 120, + i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, + 120, 120, 120, 120, 120, 120, 120, 120, + i8::MIN, i8::MIN, i8::MIN, i8::MIN, i8::MIN, i8::MIN, i8::MIN, i8::MIN, + 120, 120, 120, 120, 120, 120, 120, 120, + i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, + ]; + let dst = _mm512_loadu_si512(DST.as_ptr().cast::<__m512i>()); + assert_eq_m512i(_mm512_packs_epi16(a, b), dst); + } + test_mm512_packs_epi16(); + + #[target_feature(enable = "avx512bw")] + unsafe fn test_mm512_packus_epi16() { + let a = _mm512_set1_epi16(120); + + // Because `packus` instructions do unsigned saturation, we expect + // that any value over `u8::MAX` will be saturated to `u8::MAX`, and any value + // less than `u8::MIN` will also be saturated to `u8::MIN`. + let b = _mm512_set_epi16( + 300, 300, 300, 300, 300, 300, 300, 300, -200, -200, -200, -200, -200, -200, -200, -200, + 300, 300, 300, 300, 300, 300, 300, 300, -200, -200, -200, -200, -200, -200, -200, -200, + ); + + // See `test_mm512_packs_epi16` for an explanation of the output structure. + #[rustfmt::skip] + const DST: [u8; 64] = [ + 120, 120, 120, 120, 120, 120, 120, 120, + u8::MIN, u8::MIN, u8::MIN, u8::MIN, u8::MIN, u8::MIN, u8::MIN, u8::MIN, + 120, 120, 120, 120, 120, 120, 120, 120, + u8::MAX, u8::MAX, u8::MAX, u8::MAX, u8::MAX, u8::MAX, u8::MAX, u8::MAX, + 120, 120, 120, 120, 120, 120, 120, 120, + u8::MIN, u8::MIN, u8::MIN, u8::MIN, u8::MIN, u8::MIN, u8::MIN, u8::MIN, + 120, 120, 120, 120, 120, 120, 120, 120, + u8::MAX, u8::MAX, u8::MAX, u8::MAX, u8::MAX, u8::MAX, u8::MAX, u8::MAX, + ]; + let dst = _mm512_loadu_si512(DST.as_ptr().cast::<__m512i>()); + assert_eq_m512i(_mm512_packus_epi16(a, b), dst); + } + test_mm512_packus_epi16(); + + #[target_feature(enable = "avx512bw")] + unsafe fn test_mm512_packs_epi32() { + let a = _mm512_set1_epi32(8_000); + + // Because `packs` instructions do signed saturation, we expect + // that any value over `i16::MAX` will be saturated to `i16::MAX`, and any value + // less than `i16::MIN` will also be saturated to `i16::MIN`. + let b = _mm512_set_epi32( + 50_000, 50_000, 50_000, 50_000, -50_000, -50_000, -50_000, -50_000, 50_000, 50_000, + 50_000, 50_000, -50_000, -50_000, -50_000, -50_000, + ); + + // See `test_mm512_packs_epi16` for an explanation of the output structure. + #[rustfmt::skip] + const DST: [i16; 32] = [ + 8_000, 8_000, 8_000, 8_000, + i16::MIN, i16::MIN, i16::MIN, i16::MIN, + 8_000, 8_000, 8_000, 8_000, + i16::MAX, i16::MAX, i16::MAX, i16::MAX, + 8_000, 8_000, 8_000, 8_000, + i16::MIN, i16::MIN, i16::MIN, i16::MIN, + 8_000, 8_000, 8_000, 8_000, + i16::MAX, i16::MAX, i16::MAX, i16::MAX, + ]; + let dst = _mm512_loadu_si512(DST.as_ptr().cast::<__m512i>()); + assert_eq_m512i(_mm512_packs_epi32(a, b), dst); + } + test_mm512_packs_epi32(); + + #[target_feature(enable = "avx512bw")] + unsafe fn test_mm512_packus_epi32() { + let a = _mm512_set1_epi32(8_000); + + // Because `packus` instructions do unsigned saturation, we expect + // that any value over `u16::MAX` will be saturated to `u16::MAX`, and any value + // less than `u16::MIN` will also be saturated to `u16::MIN`. + let b = _mm512_set_epi32( + 80_000, 80_000, 80_000, 80_000, -50_000, -50_000, -50_000, -50_000, 80_000, 80_000, + 80_000, 80_000, -50_000, -50_000, -50_000, -50_000, + ); + + // See `test_mm512_packs_epi16` for an explanation of the output structure. + #[rustfmt::skip] + const DST: [u16; 32] = [ + 8_000, 8_000, 8_000, 8_000, + u16::MIN, u16::MIN, u16::MIN, u16::MIN, + 8_000, 8_000, 8_000, 8_000, + u16::MAX, u16::MAX, u16::MAX, u16::MAX, + 8_000, 8_000, 8_000, 8_000, + u16::MIN, u16::MIN, u16::MIN, u16::MIN, + 8_000, 8_000, 8_000, 8_000, + u16::MAX, u16::MAX, u16::MAX, u16::MAX, + ]; + let dst = _mm512_loadu_si512(DST.as_ptr().cast::<__m512i>()); + assert_eq_m512i(_mm512_packus_epi32(a, b), dst); + } + test_mm512_packus_epi32(); +} + #[track_caller] unsafe fn assert_eq_m512i(a: __m512i, b: __m512i) { - assert_eq!(transmute::<_, [i32; 16]>(a), transmute::<_, [i32; 16]>(b)) + assert_eq!(transmute::<_, [u16; 32]>(a), transmute::<_, [u16; 32]>(b)) } #[track_caller] From 858fb400225aca8bc3a666ba9e1a039b03cc3131 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Sun, 18 Jan 2026 20:06:15 +0100 Subject: [PATCH 0830/1061] Port #[rustc_allocator] to attr parser --- compiler/rustc_attr_parsing/src/attributes/mod.rs | 1 + .../src/attributes/rustc_allocator.rs | 11 +++++++++++ compiler/rustc_attr_parsing/src/context.rs | 15 +++++++++------ compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 4 +++- compiler/rustc_hir/src/attrs/data_structures.rs | 3 +++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 2 +- 7 files changed, 29 insertions(+), 8 deletions(-) create mode 100644 compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 64aa7a66b019..0d328d5cc6a7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -58,6 +58,7 @@ pub(crate) mod pin_v2; pub(crate) mod proc_macro_attrs; pub(crate) mod prototype; pub(crate) mod repr; +pub(crate) mod rustc_allocator; pub(crate) mod rustc_dump; pub(crate) mod rustc_internal; pub(crate) mod semantics; diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs new file mode 100644 index 000000000000..d7925f6fc372 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs @@ -0,0 +1,11 @@ +use super::prelude::*; + +pub(crate) struct RustcAllocatorParser; + +impl NoArgsAttributeParser for RustcAllocatorParser { + const PATH: &[Symbol] = &[sym::rustc_allocator]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcAllocator; +} \ No newline at end of file diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 449894f7834b..652a5e2cf1c6 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -64,17 +64,19 @@ use crate::attributes::proc_macro_attrs::{ }; use crate::attributes::prototype::CustomMirParser; use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; +use crate::attributes::rustc_allocator::RustcAllocatorParser; use crate::attributes::rustc_dump::{ RustcDumpDefParents, RustcDumpItemBounds, RustcDumpPredicates, RustcDumpUserArgs, RustcDumpVtable, }; use crate::attributes::rustc_internal::{ - RustcHasIncoherentInherentImplsParser, RustcLayoutScalarValidRangeEndParser, - RustcLayoutScalarValidRangeStartParser, RustcLegacyConstGenericsParser, - RustcLintDiagnosticsParser, RustcLintOptDenyFieldAccessParser, RustcLintOptTyParser, - RustcLintQueryInstabilityParser, RustcLintUntrackedQueryInformationParser, RustcMainParser, - RustcMustImplementOneOfParser, RustcNeverReturnsNullPointerParser, - RustcNoImplicitAutorefsParser, RustcObjectLifetimeDefaultParser, RustcScalableVectorParser, + RustcHasIncoherentInherentImplsParser, + RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser, + RustcLegacyConstGenericsParser, RustcLintDiagnosticsParser, RustcLintOptDenyFieldAccessParser, + RustcLintOptTyParser, RustcLintQueryInstabilityParser, + RustcLintUntrackedQueryInformationParser, RustcMainParser, RustcMustImplementOneOfParser, + RustcNeverReturnsNullPointerParser, RustcNoImplicitAutorefsParser, + RustcObjectLifetimeDefaultParser, RustcScalableVectorParser, RustcSimdMonomorphizeLaneLimitParser, }; use crate::attributes::semantics::MayDangleParser; @@ -273,6 +275,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index fa02c5c51f7c..c3bf92df34a0 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -335,6 +335,9 @@ fn process_builtin_attrs( AttributeKind::InstructionSet(instruction_set) => { codegen_fn_attrs.instruction_set = Some(*instruction_set) } + AttributeKind::RustcAllocator => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR + } _ => {} } } @@ -344,7 +347,6 @@ fn process_builtin_attrs( }; match name { - sym::rustc_allocator => codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR, sym::rustc_nounwind => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND, sym::rustc_reallocator => codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR, sym::rustc_deallocator => codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 7b7fae9fdcca..b884372c2a7c 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -906,6 +906,9 @@ pub enum AttributeKind { /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations). Repr { reprs: ThinVec<(ReprAttr, Span)>, first_span: Span }, + /// Represents `#[rustc_allocator]` + RustcAllocator, + /// Represents `#[rustc_builtin_macro]`. RustcBuiltinMacro { builtin_name: Option, helper_attrs: ThinVec, span: Span }, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index dff8a5727771..e81e74435e51 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -97,6 +97,7 @@ impl AttributeKind { PubTransparent(..) => Yes, RecursionLimit { .. } => No, Repr { .. } => No, + RustcAllocator => No, RustcBuiltinMacro { .. } => Yes, RustcCoherenceIsCore(..) => No, RustcDumpDefParents => No, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 4b71d4755cb6..c4de0f44a648 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -316,6 +316,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcDumpDefParents | AttributeKind::RustcDumpVtable(..) | AttributeKind::NeedsAllocator + | AttributeKind::RustcAllocator ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); @@ -360,7 +361,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::rustc_do_not_const_check | sym::rustc_reservation_impl | sym::rustc_doc_primitive - | sym::rustc_allocator | sym::rustc_deallocator | sym::rustc_reallocator | sym::rustc_conversion_suggestion From 027a6f268f4989198db21aded966c22eb48311cf Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Sun, 18 Jan 2026 19:35:33 +0100 Subject: [PATCH 0831/1061] Port `#[rustc_deallocator]` to attr parser --- .../src/attributes/rustc_allocator.rs | 12 +++++++++++- compiler/rustc_attr_parsing/src/context.rs | 16 ++++++++-------- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 4 +++- compiler/rustc_hir/src/attrs/data_structures.rs | 3 +++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 2 +- 6 files changed, 27 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs index d7925f6fc372..8eb252d3ff8d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs @@ -8,4 +8,14 @@ impl NoArgsAttributeParser for RustcAllocatorParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcAllocator; -} \ No newline at end of file +} + +pub(crate) struct RustcDeallocatorParser; + +impl NoArgsAttributeParser for RustcDeallocatorParser { + const PATH: &[Symbol] = &[sym::rustc_deallocator]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDeallocator; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 652a5e2cf1c6..454a2b427313 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -64,19 +64,18 @@ use crate::attributes::proc_macro_attrs::{ }; use crate::attributes::prototype::CustomMirParser; use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; -use crate::attributes::rustc_allocator::RustcAllocatorParser; +use crate::attributes::rustc_allocator::{RustcAllocatorParser, RustcDeallocatorParser}; use crate::attributes::rustc_dump::{ RustcDumpDefParents, RustcDumpItemBounds, RustcDumpPredicates, RustcDumpUserArgs, RustcDumpVtable, }; use crate::attributes::rustc_internal::{ - RustcHasIncoherentInherentImplsParser, - RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser, - RustcLegacyConstGenericsParser, RustcLintDiagnosticsParser, RustcLintOptDenyFieldAccessParser, - RustcLintOptTyParser, RustcLintQueryInstabilityParser, - RustcLintUntrackedQueryInformationParser, RustcMainParser, RustcMustImplementOneOfParser, - RustcNeverReturnsNullPointerParser, RustcNoImplicitAutorefsParser, - RustcObjectLifetimeDefaultParser, RustcScalableVectorParser, + RustcHasIncoherentInherentImplsParser, RustcLayoutScalarValidRangeEndParser, + RustcLayoutScalarValidRangeStartParser, RustcLegacyConstGenericsParser, + RustcLintDiagnosticsParser, RustcLintOptDenyFieldAccessParser, RustcLintOptTyParser, + RustcLintQueryInstabilityParser, RustcLintUntrackedQueryInformationParser, RustcMainParser, + RustcMustImplementOneOfParser, RustcNeverReturnsNullPointerParser, + RustcNoImplicitAutorefsParser, RustcObjectLifetimeDefaultParser, RustcScalableVectorParser, RustcSimdMonomorphizeLaneLimitParser, }; use crate::attributes::semantics::MayDangleParser; @@ -277,6 +276,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index c3bf92df34a0..70328c14b19c 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -338,6 +338,9 @@ fn process_builtin_attrs( AttributeKind::RustcAllocator => { codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR } + AttributeKind::RustcDeallocator => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR + } _ => {} } } @@ -349,7 +352,6 @@ fn process_builtin_attrs( match name { sym::rustc_nounwind => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND, sym::rustc_reallocator => codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR, - sym::rustc_deallocator => codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR, sym::rustc_allocator_zeroed => { codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED } diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index b884372c2a7c..6f91dd48cb5a 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -915,6 +915,9 @@ pub enum AttributeKind { /// Represents `#[rustc_coherence_is_core]` RustcCoherenceIsCore(Span), + /// Represents `#[rustc_deallocator]` + RustcDeallocator, + /// Represents `#[rustc_dump_def_parents]` RustcDumpDefParents, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index e81e74435e51..9fcaf77f69a4 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -100,6 +100,7 @@ impl AttributeKind { RustcAllocator => No, RustcBuiltinMacro { .. } => Yes, RustcCoherenceIsCore(..) => No, + RustcDeallocator => No, RustcDumpDefParents => No, RustcDumpItemBounds => No, RustcDumpPredicates => No, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index c4de0f44a648..83a4bd9f0cda 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -317,6 +317,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcDumpVtable(..) | AttributeKind::NeedsAllocator | AttributeKind::RustcAllocator + | AttributeKind::RustcDeallocator ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); @@ -361,7 +362,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::rustc_do_not_const_check | sym::rustc_reservation_impl | sym::rustc_doc_primitive - | sym::rustc_deallocator | sym::rustc_reallocator | sym::rustc_conversion_suggestion | sym::rustc_allocator_zeroed From 9a7614da04b5b3258b24ce64e197dd2989cff1d9 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Sun, 18 Jan 2026 19:40:19 +0100 Subject: [PATCH 0832/1061] Port `#[rustc_reallocator]` to attr parser --- .../src/attributes/rustc_allocator.rs | 10 ++++++++++ compiler/rustc_attr_parsing/src/context.rs | 5 ++++- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 4 +++- compiler/rustc_hir/src/attrs/data_structures.rs | 3 +++ compiler/rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 2 +- 6 files changed, 22 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs index 8eb252d3ff8d..9324f0c01156 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs @@ -19,3 +19,13 @@ impl NoArgsAttributeParser for RustcDeallocatorParser { AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDeallocator; } + +pub(crate) struct RustcReallocatorParser; + +impl NoArgsAttributeParser for RustcReallocatorParser { + const PATH: &[Symbol] = &[sym::rustc_reallocator]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcReallocator; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 454a2b427313..19e03f1ad3eb 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -64,7 +64,9 @@ use crate::attributes::proc_macro_attrs::{ }; use crate::attributes::prototype::CustomMirParser; use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; -use crate::attributes::rustc_allocator::{RustcAllocatorParser, RustcDeallocatorParser}; +use crate::attributes::rustc_allocator::{ + RustcAllocatorParser, RustcDeallocatorParser, RustcReallocatorParser, +}; use crate::attributes::rustc_dump::{ RustcDumpDefParents, RustcDumpItemBounds, RustcDumpPredicates, RustcDumpUserArgs, RustcDumpVtable, @@ -291,6 +293,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 70328c14b19c..86ea1ac94b4e 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -341,6 +341,9 @@ fn process_builtin_attrs( AttributeKind::RustcDeallocator => { codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR } + AttributeKind::RustcReallocator => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR + } _ => {} } } @@ -351,7 +354,6 @@ fn process_builtin_attrs( match name { sym::rustc_nounwind => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND, - sym::rustc_reallocator => codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR, sym::rustc_allocator_zeroed => { codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED } diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 6f91dd48cb5a..95c4b28f1421 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -978,6 +978,9 @@ pub enum AttributeKind { /// Represents `#[rustc_pass_indirectly_in_non_rustic_abis]` RustcPassIndirectlyInNonRusticAbis(Span), + /// Represents `#[rustc_reallocator]` + RustcReallocator, + /// Represents `#[rustc_scalable_vector(N)]` RustcScalableVector { /// The base multiple of lanes that are in a scalable vector, if provided. `element_count` diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 9fcaf77f69a4..0dd2cefc83cf 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -121,6 +121,7 @@ impl AttributeKind { RustcNoImplicitAutorefs => Yes, RustcObjectLifetimeDefault => No, RustcPassIndirectlyInNonRusticAbis(..) => No, + RustcReallocator => No, RustcScalableVector { .. } => Yes, RustcShouldNotBeCalledOnConstItems(..) => Yes, RustcSimdMonomorphizeLaneLimit(..) => Yes, // Affects layout computation, which needs to work cross-crate diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 83a4bd9f0cda..4e904b6f11ad 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -318,6 +318,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::NeedsAllocator | AttributeKind::RustcAllocator | AttributeKind::RustcDeallocator + | AttributeKind::RustcReallocator ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); @@ -362,7 +363,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::rustc_do_not_const_check | sym::rustc_reservation_impl | sym::rustc_doc_primitive - | sym::rustc_reallocator | sym::rustc_conversion_suggestion | sym::rustc_allocator_zeroed | sym::rustc_allocator_zeroed_variant From 21c9bd7692a9ed139e12c2bfc367b9c71160fcd5 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Sun, 18 Jan 2026 19:47:09 +0100 Subject: [PATCH 0833/1061] Port `#[rustc_allocator_zeroed]` to attr parser --- .../src/attributes/rustc_allocator.rs | 10 ++++++++++ compiler/rustc_attr_parsing/src/context.rs | 4 +++- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 6 +++--- compiler/rustc_hir/src/attrs/data_structures.rs | 3 +++ compiler/rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 2 +- 6 files changed, 21 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs index 9324f0c01156..4622348ef1db 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs @@ -10,6 +10,16 @@ impl NoArgsAttributeParser for RustcAllocatorParser { const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcAllocator; } +pub(crate) struct RustcAllocatorZeroedParser; + +impl NoArgsAttributeParser for RustcAllocatorZeroedParser { + const PATH: &[Symbol] = &[sym::rustc_allocator_zeroed]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcAllocatorZeroed; +} + pub(crate) struct RustcDeallocatorParser; impl NoArgsAttributeParser for RustcDeallocatorParser { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 19e03f1ad3eb..7e69cbf1ff6d 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -65,7 +65,8 @@ use crate::attributes::proc_macro_attrs::{ use crate::attributes::prototype::CustomMirParser; use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; use crate::attributes::rustc_allocator::{ - RustcAllocatorParser, RustcDeallocatorParser, RustcReallocatorParser, + RustcAllocatorParser, RustcAllocatorZeroedParser, RustcDeallocatorParser, + RustcReallocatorParser, }; use crate::attributes::rustc_dump::{ RustcDumpDefParents, RustcDumpItemBounds, RustcDumpPredicates, RustcDumpUserArgs, @@ -277,6 +278,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 86ea1ac94b4e..1b0427e7e676 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -344,6 +344,9 @@ fn process_builtin_attrs( AttributeKind::RustcReallocator => { codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR } + AttributeKind::RustcAllocatorZeroed => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED + } _ => {} } } @@ -354,9 +357,6 @@ fn process_builtin_attrs( match name { sym::rustc_nounwind => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND, - sym::rustc_allocator_zeroed => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED - } sym::patchable_function_entry => { codegen_fn_attrs.patchable_function_entry = parse_patchable_function_entry(tcx, attr); diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 95c4b28f1421..1c0562d38d8a 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -909,6 +909,9 @@ pub enum AttributeKind { /// Represents `#[rustc_allocator]` RustcAllocator, + /// Represents `#[rustc_allocator_zeroed]` + RustcAllocatorZeroed, + /// Represents `#[rustc_builtin_macro]`. RustcBuiltinMacro { builtin_name: Option, helper_attrs: ThinVec, span: Span }, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 0dd2cefc83cf..803aca49b406 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -98,6 +98,7 @@ impl AttributeKind { RecursionLimit { .. } => No, Repr { .. } => No, RustcAllocator => No, + RustcAllocatorZeroed => No, RustcBuiltinMacro { .. } => Yes, RustcCoherenceIsCore(..) => No, RustcDeallocator => No, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 4e904b6f11ad..ca0d6b90a1c4 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -317,6 +317,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcDumpVtable(..) | AttributeKind::NeedsAllocator | AttributeKind::RustcAllocator + | AttributeKind::RustcAllocatorZeroed | AttributeKind::RustcDeallocator | AttributeKind::RustcReallocator ) => { /* do nothing */ } @@ -364,7 +365,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::rustc_reservation_impl | sym::rustc_doc_primitive | sym::rustc_conversion_suggestion - | sym::rustc_allocator_zeroed | sym::rustc_allocator_zeroed_variant | sym::rustc_deprecated_safe_2024 | sym::rustc_test_marker From 9a931e8bf2c4a329df8f32d587e056d7b127ec5a Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Sun, 18 Jan 2026 20:02:41 +0100 Subject: [PATCH 0834/1061] Port `#[rustc_allocator_zeroed_variant]` to attr parser --- .../src/attributes/rustc_allocator.rs | 19 +++++++++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 5 +++-- compiler/rustc_codegen_llvm/src/attributes.rs | 5 ++--- .../rustc_hir/src/attrs/data_structures.rs | 3 +++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 2 +- 6 files changed, 29 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs index 4622348ef1db..5782f9473a99 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs @@ -20,6 +20,25 @@ impl NoArgsAttributeParser for RustcAllocatorZeroedParser { const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcAllocatorZeroed; } +pub(crate) struct RustcAllocatorZeroedVariantParser; + +impl SingleAttributeParser for RustcAllocatorZeroedVariantParser { + const PATH: &[Symbol] = &[sym::rustc_allocator_zeroed_variant]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]); + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "function"); + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { + let Some(name) = args.name_value().and_then(NameValueParser::value_as_str) else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + + Some(AttributeKind::RustcAllocatorZeroedVariant { name }) + } +} + pub(crate) struct RustcDeallocatorParser; impl NoArgsAttributeParser for RustcDeallocatorParser { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 7e69cbf1ff6d..7c0182c7e063 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -65,8 +65,8 @@ use crate::attributes::proc_macro_attrs::{ use crate::attributes::prototype::CustomMirParser; use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; use crate::attributes::rustc_allocator::{ - RustcAllocatorParser, RustcAllocatorZeroedParser, RustcDeallocatorParser, - RustcReallocatorParser, + RustcAllocatorParser, RustcAllocatorZeroedParser, RustcAllocatorZeroedVariantParser, + RustcDeallocatorParser, RustcReallocatorParser, }; use crate::attributes::rustc_dump::{ RustcDumpDefParents, RustcDumpItemBounds, RustcDumpPredicates, RustcDumpUserArgs, @@ -227,6 +227,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, Single, Single, diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index a25ce9e5a90a..28e91a25a21a 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -1,6 +1,7 @@ //! Set and unset common attributes on LLVM values. use rustc_hir::attrs::{InlineAttr, InstructionSetAttr, OptimizeAttr, RtsanSetting}; use rustc_hir::def_id::DefId; +use rustc_hir::find_attr; use rustc_middle::middle::codegen_fn_attrs::{ CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, SanitizerFnAttrs, }; @@ -470,9 +471,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( { to_add.push(create_alloc_family_attr(cx.llcx)); if let Some(instance) = instance - && let Some(zv) = - tcx.get_attr(instance.def_id(), rustc_span::sym::rustc_allocator_zeroed_variant) - && let Some(name) = zv.value_str() + && let Some(name) = find_attr!(tcx.get_all_attrs(instance.def_id()), rustc_hir::attrs::AttributeKind::RustcAllocatorZeroedVariant {name} => name) { to_add.push(llvm::CreateAttrStringValue( cx.llcx, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 1c0562d38d8a..eff871cb8bb4 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -912,6 +912,9 @@ pub enum AttributeKind { /// Represents `#[rustc_allocator_zeroed]` RustcAllocatorZeroed, + /// Represents `#[rustc_allocator_zeroed_variant]` + RustcAllocatorZeroedVariant { name: Symbol }, + /// Represents `#[rustc_builtin_macro]`. RustcBuiltinMacro { builtin_name: Option, helper_attrs: ThinVec, span: Span }, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 803aca49b406..28b41ac70925 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -99,6 +99,7 @@ impl AttributeKind { Repr { .. } => No, RustcAllocator => No, RustcAllocatorZeroed => No, + RustcAllocatorZeroedVariant { .. } => Yes, RustcBuiltinMacro { .. } => Yes, RustcCoherenceIsCore(..) => No, RustcDeallocator => No, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ca0d6b90a1c4..1e723dd6b464 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -318,6 +318,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::NeedsAllocator | AttributeKind::RustcAllocator | AttributeKind::RustcAllocatorZeroed + | AttributeKind::RustcAllocatorZeroedVariant { .. } | AttributeKind::RustcDeallocator | AttributeKind::RustcReallocator ) => { /* do nothing */ } @@ -365,7 +366,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::rustc_reservation_impl | sym::rustc_doc_primitive | sym::rustc_conversion_suggestion - | sym::rustc_allocator_zeroed_variant | sym::rustc_deprecated_safe_2024 | sym::rustc_test_marker | sym::rustc_abi From 2b8f4a562f24afcb45f4f12b109c13beb5b45f75 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sun, 29 Sep 2024 00:27:50 +0200 Subject: [PATCH 0835/1061] avoid phi node for pointers flowing into Vec appends --- library/alloc/src/slice.rs | 11 ++++--- library/alloc/src/vec/mod.rs | 6 +++- .../lib-optimizations/append-elements.rs | 33 +++++++++++++++++++ 3 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 tests/codegen-llvm/lib-optimizations/append-elements.rs diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index e7d0fc3454ee..634747ca3f84 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -444,13 +444,16 @@ impl [T] { impl ConvertVec for T { #[inline] fn to_vec(s: &[Self], alloc: A) -> Vec { - let mut v = Vec::with_capacity_in(s.len(), alloc); + let len = s.len(); + let mut v = Vec::with_capacity_in(len, alloc); // SAFETY: // allocated above with the capacity of `s`, and initialize to `s.len()` in // ptr::copy_to_non_overlapping below. - unsafe { - s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len()); - v.set_len(s.len()); + if len > 0 { + unsafe { + s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), len); + v.set_len(len); + } } v } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 379e964f0a0c..ac86399df7ab 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2818,7 +2818,11 @@ impl Vec { let count = other.len(); self.reserve(count); let len = self.len(); - unsafe { ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count) }; + if count > 0 { + unsafe { + ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count) + }; + } self.len += count; } diff --git a/tests/codegen-llvm/lib-optimizations/append-elements.rs b/tests/codegen-llvm/lib-optimizations/append-elements.rs new file mode 100644 index 000000000000..b8657104d665 --- /dev/null +++ b/tests/codegen-llvm/lib-optimizations/append-elements.rs @@ -0,0 +1,33 @@ +//@ compile-flags: -O -Zmerge-functions=disabled +//@ needs-deterministic-layouts +//@ min-llvm-version: 21 +#![crate_type = "lib"] + +//! Check that a temporary intermediate allocations can eliminated and replaced +//! with memcpy forwarding. +//! This requires Vec code to be structured in a way that avoids phi nodes from the +//! zero-capacity length flowing into the memcpy arguments. + +// CHECK-LABEL: @vec_append_with_temp_alloc +// CHECK-SAME: ptr{{.*}}[[DST:%[a-z]+]]{{.*}}ptr{{.*}}[[SRC:%[a-z]+]] +#[no_mangle] +pub fn vec_append_with_temp_alloc(dst: &mut Vec, src: &[u8]) { + // CHECK-NOT: call void @llvm.memcpy + // CHECK: call void @llvm.memcpy.{{.*}}[[DST]].i{{.*}}[[SRC]] + // CHECK-NOT: call void @llvm.memcpy + let temp = src.to_vec(); + dst.extend(&temp); + // CHECK: ret +} + +// CHECK-LABEL: @string_append_with_temp_alloc +// CHECK-SAME: ptr{{.*}}[[DST:%[a-z]+]]{{.*}}ptr{{.*}}[[SRC:%[a-z]+]] +#[no_mangle] +pub fn string_append_with_temp_alloc(dst: &mut String, src: &str) { + // CHECK-NOT: call void @llvm.memcpy + // CHECK: call void @llvm.memcpy.{{.*}}[[DST]].i{{.*}}[[SRC]] + // CHECK-NOT: call void @llvm.memcpy + let temp = src.to_string(); + dst.push_str(&temp); + // CHECK: ret +} From 7216b035fa406b924099d1b1e8c4f392e4e02597 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 18 Jan 2026 21:27:40 +0100 Subject: [PATCH 0836/1061] Factor out diagnostic slug checking from `DiagnosticDerive` and `LintDiagnosticDerive` --- .../src/diagnostics/diagnostic.rs | 100 +++--------------- .../src/diagnostics/diagnostic_builder.rs | 49 +++++++++ 2 files changed, 66 insertions(+), 83 deletions(-) diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index 185d07049669..7e784e3464e9 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -4,12 +4,10 @@ use std::cell::RefCell; use proc_macro2::TokenStream; use quote::quote; -use syn::spanned::Spanned; use synstructure::Structure; use crate::diagnostics::diagnostic_builder::DiagnosticDeriveKind; -use crate::diagnostics::error::{DiagnosticDeriveError, span_err}; -use crate::diagnostics::utils::SetOnce; +use crate::diagnostics::error::DiagnosticDeriveError; /// The central struct for constructing the `into_diag` method from an annotated struct. pub(crate) struct DiagnosticDerive<'a> { @@ -29,36 +27,16 @@ impl<'a> DiagnosticDerive<'a> { let preamble = builder.preamble(variant); let body = builder.body(variant); - let init = match builder.slug.value_ref() { - None => { - span_err(builder.span, "diagnostic slug not specified") - .help( - "specify the slug as the first argument to the `#[diag(...)]` \ - attribute, such as `#[diag(hir_analysis_example_error)]`", - ) - .emit(); - return DiagnosticDeriveError::ErrorHandled.to_compile_error(); - } - Some(slug) - if let Some(Mismatch { slug_name, crate_name, slug_prefix }) = - Mismatch::check(slug) => - { - span_err(slug.span().unwrap(), "diagnostic slug and crate name do not match") - .note(format!("slug is `{slug_name}` but the crate name is `{crate_name}`")) - .help(format!("expected a slug starting with `{slug_prefix}_...`")) - .emit(); - return DiagnosticDeriveError::ErrorHandled.to_compile_error(); - } - Some(slug) => { - slugs.borrow_mut().push(slug.clone()); - quote! { - let mut diag = rustc_errors::Diag::new( - dcx, - level, - crate::fluent_generated::#slug - ); - } - } + let Some(slug) = builder.primary_message() else { + return DiagnosticDeriveError::ErrorHandled.to_compile_error(); + }; + slugs.borrow_mut().push(slug.clone()); + let init = quote! { + let mut diag = rustc_errors::Diag::new( + dcx, + level, + crate::fluent_generated::#slug + ); }; let formatting_init = &builder.formatting_init; @@ -113,32 +91,12 @@ impl<'a> LintDiagnosticDerive<'a> { let preamble = builder.preamble(variant); let body = builder.body(variant); - let primary_message = match builder.slug.value_ref() { - None => { - span_err(builder.span, "diagnostic slug not specified") - .help( - "specify the slug as the first argument to the attribute, such as \ - `#[diag(compiletest_example)]`", - ) - .emit(); - DiagnosticDeriveError::ErrorHandled.to_compile_error() - } - Some(slug) - if let Some(Mismatch { slug_name, crate_name, slug_prefix }) = - Mismatch::check(slug) => - { - span_err(slug.span().unwrap(), "diagnostic slug and crate name do not match") - .note(format!("slug is `{slug_name}` but the crate name is `{crate_name}`")) - .help(format!("expected a slug starting with `{slug_prefix}_...`")) - .emit(); - DiagnosticDeriveError::ErrorHandled.to_compile_error() - } - Some(slug) => { - slugs.borrow_mut().push(slug.clone()); - quote! { - diag.primary_message(crate::fluent_generated::#slug); - } - } + let Some(slug) = builder.primary_message() else { + return DiagnosticDeriveError::ErrorHandled.to_compile_error(); + }; + slugs.borrow_mut().push(slug.clone()); + let primary_message = quote! { + diag.primary_message(crate::fluent_generated::#slug); }; let formatting_init = &builder.formatting_init; @@ -172,30 +130,6 @@ impl<'a> LintDiagnosticDerive<'a> { } } -struct Mismatch { - slug_name: String, - crate_name: String, - slug_prefix: String, -} - -impl Mismatch { - /// Checks whether the slug starts with the crate name it's in. - fn check(slug: &syn::Path) -> Option { - // If this is missing we're probably in a test, so bail. - let crate_name = std::env::var("CARGO_CRATE_NAME").ok()?; - - // If we're not in a "rustc_" crate, bail. - let Some(("rustc", slug_prefix)) = crate_name.split_once('_') else { return None }; - - let slug_name = slug.segments.first()?.ident.to_string(); - if !slug_name.starts_with(slug_prefix) { - Some(Mismatch { slug_name, slug_prefix: slug_prefix.to_string(), crate_name }) - } else { - None - } - } -} - /// Generates a `#[test]` that verifies that all referenced variables /// exist on this structure. fn generate_test(slug: &syn::Path, structure: &Structure<'_>) -> TokenStream { diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 1055f27c1e48..cbc70b55d7ee 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -110,6 +110,31 @@ impl DiagnosticDeriveKind { } impl DiagnosticDeriveVariantBuilder { + pub(crate) fn primary_message(&self) -> Option<&Path> { + match self.slug.value_ref() { + None => { + span_err(self.span, "diagnostic slug not specified") + .help( + "specify the slug as the first argument to the `#[diag(...)]` \ + attribute, such as `#[diag(hir_analysis_example_error)]`", + ) + .emit(); + None + } + Some(slug) + if let Some(Mismatch { slug_name, crate_name, slug_prefix }) = + Mismatch::check(slug) => + { + span_err(slug.span().unwrap(), "diagnostic slug and crate name do not match") + .note(format!("slug is `{slug_name}` but the crate name is `{crate_name}`")) + .help(format!("expected a slug starting with `{slug_prefix}_...`")) + .emit(); + None + } + Some(slug) => Some(slug), + } + } + /// Generates calls to `code` and similar functions based on the attributes on the type or /// variant. pub(crate) fn preamble(&mut self, variant: &VariantInfo<'_>) -> TokenStream { @@ -504,3 +529,27 @@ impl DiagnosticDeriveVariantBuilder { } } } + +struct Mismatch { + slug_name: String, + crate_name: String, + slug_prefix: String, +} + +impl Mismatch { + /// Checks whether the slug starts with the crate name it's in. + fn check(slug: &syn::Path) -> Option { + // If this is missing we're probably in a test, so bail. + let crate_name = std::env::var("CARGO_CRATE_NAME").ok()?; + + // If we're not in a "rustc_" crate, bail. + let Some(("rustc", slug_prefix)) = crate_name.split_once('_') else { return None }; + + let slug_name = slug.segments.first()?.ident.to_string(); + if slug_name.starts_with(slug_prefix) { + return None; + } + + Some(Mismatch { slug_name, slug_prefix: slug_prefix.to_string(), crate_name }) + } +} From 7ec4a8e798cc37bdf4c9cac1c4a481f6c1d22a0d Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 18 Jan 2026 22:36:39 +0100 Subject: [PATCH 0837/1061] Update uitests --- tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index 90ad21ef08f9..77c48aceca8e 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -384,7 +384,7 @@ error: derive(Diagnostic): diagnostic slug not specified LL | #[lint(no_crate_example, code = E0123)] | ^ | - = help: specify the slug as the first argument to the attribute, such as `#[diag(compiletest_example)]` + = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: derive(Diagnostic): attribute specified multiple times --> $DIR/diagnostic-derive.rs:613:53 From e668836c929e1a30b0c53583567e7c6cf42fe4da Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 18 Jan 2026 22:40:55 +0100 Subject: [PATCH 0838/1061] Fix capitalization of error messages --- compiler/rustc_attr_parsing/messages.ftl | 2 +- compiler/rustc_const_eval/messages.ftl | 12 ++++++------ compiler/rustc_lint/messages.ftl | 2 +- compiler/rustc_monomorphize/messages.ftl | 2 +- compiler/rustc_passes/messages.ftl | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 4b4358ab0a9c..3e4c1a9dfad8 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -230,7 +230,7 @@ attr_parsing_unstable_cfg_target_compact = compact `cfg(target(..))` is experimental and subject to change attr_parsing_unstable_feature_bound_incompatible_stability = item annotated with `#[unstable_feature_bound]` should not be stable - .help = If this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]` + .help = if this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]` attr_parsing_unsupported_instruction_set = target `{$current_target}` does not support `#[instruction_set({$instruction_set}::*)]` diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 38ab46a7bb5b..4aa0a0b2a96f 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -140,9 +140,9 @@ const_eval_incompatible_return_types = const_eval_interior_mutable_borrow_escaping = interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed .label = this borrow of an interior mutable value refers to such a temporary - .note = Temporaries in constants and statics can have their lifetime extended until the end of the program - .note2 = To avoid accidentally creating global mutable state, such temporaries must be immutable - .help = If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + .note = temporaries in constants and statics can have their lifetime extended until the end of the program + .note2 = to avoid accidentally creating global mutable state, such temporaries must be immutable + .help = if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` const_eval_intern_kind = {$kind -> [static] static @@ -225,9 +225,9 @@ const_eval_modified_global = const_eval_mutable_borrow_escaping = mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed .label = this mutable borrow refers to such a temporary - .note = Temporaries in constants and statics can have their lifetime extended until the end of the program - .note2 = To avoid accidentally creating global mutable state, such temporaries must be immutable - .help = If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + .note = temporaries in constants and statics can have their lifetime extended until the end of the program + .note2 = to avoid accidentally creating global mutable state, such temporaries must be immutable + .help = if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind} diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index f5b882494863..e38130aa9a29 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -542,7 +542,7 @@ lint_invalid_style = {$is_used_as_inner -> [false] crate-level attribute should be an inner attribute: add an exclamation mark: `#![{$name}]` *[other] the `#![{$name}]` attribute can only be used at the crate root } - .note = This attribute does not have an `!`, which means it is applied to this {$target} + .note = this attribute does not have an `!`, which means it is applied to this {$target} lint_invalid_target = `#[{$name}]` attribute cannot be used on {$target} .warn = {-lint_previously_accepted} diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl index 09500ba73359..9c791208c093 100644 --- a/compiler/rustc_monomorphize/messages.ftl +++ b/compiler/rustc_monomorphize/messages.ftl @@ -62,7 +62,7 @@ monomorphize_encountered_error_while_instantiating_global_asm = monomorphize_large_assignments = moving {$size} bytes .label = value moved from here - .note = The current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + .note = the current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` monomorphize_no_optimized_mir = missing optimized MIR for `{$instance}` in the crate `{$crate_name}` diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 51c439b4243c..395d940ddae6 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -376,7 +376,7 @@ passes_no_main_function = } .consider_adding_main_to_file = consider adding a `main` function to `{$filename}` .consider_adding_main_at_crate = consider adding a `main` function at the crate level - .teach_note = If you don't know the basics of Rust, you can go look to the Rust Book to get started: https://doc.rust-lang.org/book/ + .teach_note = if you don't know the basics of Rust, you can go look to the Rust Book to get started: https://doc.rust-lang.org/book/ .non_function_main = non-function item at `crate::main` is found passes_non_exhaustive_with_default_field_values = From f5a1fc75ad10186b13ad34a65e176760b7306630 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 18 Jan 2026 22:41:00 +0100 Subject: [PATCH 0839/1061] Update uitests --- .../ui/attributes/crate-only-as-outer.stderr | 2 +- tests/ui/attributes/malformed-attrs.stderr | 2 +- tests/ui/attributes/malformed-no-std.stderr | 4 +- .../consts/const-mut-refs/issue-76510.stderr | 6 +- .../const-mut-refs/mut_ref_in_final.stderr | 36 +++++------ .../const-promoted-opaque.atomic.stderr | 6 +- .../issue-17718-const-bad-values.stderr | 6 +- .../ui/consts/issue-17718-const-borrow.stderr | 18 +++--- tests/ui/consts/partial_qualif.stderr | 6 +- tests/ui/consts/qualif_overwrite.stderr | 6 +- tests/ui/consts/qualif_overwrite_2.stderr | 6 +- tests/ui/consts/refs-to-cell-in-final.stderr | 18 +++--- .../consts/write_to_static_via_mut_ref.stderr | 6 +- tests/ui/error-codes/E0017.stderr | 12 ++-- tests/ui/error-codes/E0492.stderr | 12 ++-- .../issue-43106-gating-of-builtin-attrs.rs | 60 +++++++++---------- ...issue-43106-gating-of-builtin-attrs.stderr | 60 +++++++++---------- tests/ui/issues/issue-46604.stderr | 6 +- .../copy_into_box_rc_arc.stderr | 4 +- .../large_assignments/copy_into_fn.stderr | 6 +- .../lint/large_assignments/inline_mir.stderr | 4 +- .../large_future.attribute.stderr | 4 +- .../large_future.option.stderr | 4 +- .../move_into_box_rc_arc.stderr | 2 +- .../large_assignments/move_into_fn.stderr | 4 +- .../concat-in-crate-name-issue-137687.stderr | 2 +- .../unused/unused-attr-macro-rules.stderr | 2 +- .../statics/check-immutable-mut-slices.stderr | 6 +- ...eature_bound_incompatible_stability.stderr | 2 +- 29 files changed, 156 insertions(+), 156 deletions(-) diff --git a/tests/ui/attributes/crate-only-as-outer.stderr b/tests/ui/attributes/crate-only-as-outer.stderr index 270f02af9873..c1787a73d290 100644 --- a/tests/ui/attributes/crate-only-as-outer.stderr +++ b/tests/ui/attributes/crate-only-as-outer.stderr @@ -4,7 +4,7 @@ error: crate-level attribute should be an inner attribute: add an exclamation ma LL | #[crate_name = "owo"] | ^^^^^^^^^^^^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this function +note: this attribute does not have an `!`, which means it is applied to this function --> $DIR/crate-only-as-outer.rs:5:1 | LL | fn main() {} diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 04f51f54b2cd..3d51731df792 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -771,7 +771,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[crate_name] | ^^^^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this function +note: this attribute does not have an `!`, which means it is applied to this function --> $DIR/malformed-attrs.rs:116:1 | LL | / fn test() { diff --git a/tests/ui/attributes/malformed-no-std.stderr b/tests/ui/attributes/malformed-no-std.stderr index 89d7ee410d70..e994e28e030f 100644 --- a/tests/ui/attributes/malformed-no-std.stderr +++ b/tests/ui/attributes/malformed-no-std.stderr @@ -58,7 +58,7 @@ error: crate-level attribute should be an inner attribute: add an exclamation ma LL | #[no_std] | ^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this extern crate +note: this attribute does not have an `!`, which means it is applied to this extern crate --> $DIR/malformed-no-std.rs:26:1 | LL | extern crate core; @@ -75,7 +75,7 @@ error: crate-level attribute should be an inner attribute: add an exclamation ma LL | #[no_core] | ^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this extern crate +note: this attribute does not have an `!`, which means it is applied to this extern crate --> $DIR/malformed-no-std.rs:26:1 | LL | extern crate core; diff --git a/tests/ui/consts/const-mut-refs/issue-76510.stderr b/tests/ui/consts/const-mut-refs/issue-76510.stderr index 3a6c95141e52..82c9d523e738 100644 --- a/tests/ui/consts/const-mut-refs/issue-76510.stderr +++ b/tests/ui/consts/const-mut-refs/issue-76510.stderr @@ -4,9 +4,9 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended u LL | const S: &'static mut str = &mut " hello "; | ^^^^^^^^^^^^^^ this mutable borrow refers to such a temporary | - = note: Temporaries in constants and statics can have their lifetime extended until the end of the program - = note: To avoid accidentally creating global mutable state, such temporaries must be immutable - = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr b/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr index da6f2a28d5a8..8f54b4eda227 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr @@ -4,9 +4,9 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended u LL | const B: *mut i32 = &mut 4; | ^^^^^^ this mutable borrow refers to such a temporary | - = note: Temporaries in constants and statics can have their lifetime extended until the end of the program - = note: To avoid accidentally creating global mutable state, such temporaries must be immutable - = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error[E0764]: mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed --> $DIR/mut_ref_in_final.rs:21:35 @@ -14,9 +14,9 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended u LL | const B3: Option<&mut i32> = Some(&mut 42); | ^^^^^^^ this mutable borrow refers to such a temporary | - = note: Temporaries in constants and statics can have their lifetime extended until the end of the program - = note: To avoid accidentally creating global mutable state, such temporaries must be immutable - = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error[E0716]: temporary value dropped while borrowed --> $DIR/mut_ref_in_final.rs:24:42 @@ -86,9 +86,9 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended u LL | static RAW_MUT_CAST_S: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; | ^^^^^^^ this mutable borrow refers to such a temporary | - = note: Temporaries in constants and statics can have their lifetime extended until the end of the program - = note: To avoid accidentally creating global mutable state, such temporaries must be immutable - = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error[E0764]: mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed --> $DIR/mut_ref_in_final.rs:73:54 @@ -96,9 +96,9 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended u LL | static RAW_MUT_COERCE_S: SyncPtr = SyncPtr { x: &mut 0 }; | ^^^^^^ this mutable borrow refers to such a temporary | - = note: Temporaries in constants and statics can have their lifetime extended until the end of the program - = note: To avoid accidentally creating global mutable state, such temporaries must be immutable - = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error[E0764]: mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed --> $DIR/mut_ref_in_final.rs:75:52 @@ -106,9 +106,9 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended u LL | const RAW_MUT_CAST_C: SyncPtr = SyncPtr { x : &mut 42 as *mut _ as *const _ }; | ^^^^^^^ this mutable borrow refers to such a temporary | - = note: Temporaries in constants and statics can have their lifetime extended until the end of the program - = note: To avoid accidentally creating global mutable state, such temporaries must be immutable - = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error[E0764]: mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed --> $DIR/mut_ref_in_final.rs:77:53 @@ -116,9 +116,9 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended u LL | const RAW_MUT_COERCE_C: SyncPtr = SyncPtr { x: &mut 0 }; | ^^^^^^ this mutable borrow refers to such a temporary | - = note: Temporaries in constants and statics can have their lifetime extended until the end of the program - = note: To avoid accidentally creating global mutable state, such temporaries must be immutable - = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error[E0080]: constructing invalid value at ..0: encountered a dangling reference (0x2a[noalloc] has no provenance) --> $DIR/mut_ref_in_final.rs:86:5 diff --git a/tests/ui/consts/const-promoted-opaque.atomic.stderr b/tests/ui/consts/const-promoted-opaque.atomic.stderr index 64cc7b3a3292..ac31992d0631 100644 --- a/tests/ui/consts/const-promoted-opaque.atomic.stderr +++ b/tests/ui/consts/const-promoted-opaque.atomic.stderr @@ -13,9 +13,9 @@ error[E0492]: interior mutable shared borrows of temporaries that have their lif LL | const BAZ: &Foo = &FOO; | ^^^^ this borrow of an interior mutable value refers to such a temporary | - = note: Temporaries in constants and statics can have their lifetime extended until the end of the program - = note: To avoid accidentally creating global mutable state, such temporaries must be immutable - = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error[E0716]: temporary value dropped while borrowed --> $DIR/const-promoted-opaque.rs:40:26 diff --git a/tests/ui/consts/issue-17718-const-bad-values.stderr b/tests/ui/consts/issue-17718-const-bad-values.stderr index 11e11adcb5ae..eebfa5d6ea40 100644 --- a/tests/ui/consts/issue-17718-const-bad-values.stderr +++ b/tests/ui/consts/issue-17718-const-bad-values.stderr @@ -4,9 +4,9 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended u LL | const C1: &'static mut [usize] = &mut []; | ^^^^^^^ this mutable borrow refers to such a temporary | - = note: Temporaries in constants and statics can have their lifetime extended until the end of the program - = note: To avoid accidentally creating global mutable state, such temporaries must be immutable - = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error: aborting due to 1 previous error diff --git a/tests/ui/consts/issue-17718-const-borrow.stderr b/tests/ui/consts/issue-17718-const-borrow.stderr index 420a2c378a25..b801498c2028 100644 --- a/tests/ui/consts/issue-17718-const-borrow.stderr +++ b/tests/ui/consts/issue-17718-const-borrow.stderr @@ -4,9 +4,9 @@ error[E0492]: interior mutable shared borrows of temporaries that have their lif LL | const B: &'static UnsafeCell = &A; | ^^ this borrow of an interior mutable value refers to such a temporary | - = note: Temporaries in constants and statics can have their lifetime extended until the end of the program - = note: To avoid accidentally creating global mutable state, such temporaries must be immutable - = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed --> $DIR/issue-17718-const-borrow.rs:9:39 @@ -14,9 +14,9 @@ error[E0492]: interior mutable shared borrows of temporaries that have their lif LL | const E: &'static UnsafeCell = &D.a; | ^^^^ this borrow of an interior mutable value refers to such a temporary | - = note: Temporaries in constants and statics can have their lifetime extended until the end of the program - = note: To avoid accidentally creating global mutable state, such temporaries must be immutable - = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed --> $DIR/issue-17718-const-borrow.rs:11:23 @@ -24,9 +24,9 @@ error[E0492]: interior mutable shared borrows of temporaries that have their lif LL | const F: &'static C = &D; | ^^ this borrow of an interior mutable value refers to such a temporary | - = note: Temporaries in constants and statics can have their lifetime extended until the end of the program - = note: To avoid accidentally creating global mutable state, such temporaries must be immutable - = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error: aborting due to 3 previous errors diff --git a/tests/ui/consts/partial_qualif.stderr b/tests/ui/consts/partial_qualif.stderr index b7632eb868ac..f69fa1c46c01 100644 --- a/tests/ui/consts/partial_qualif.stderr +++ b/tests/ui/consts/partial_qualif.stderr @@ -4,9 +4,9 @@ error[E0492]: interior mutable shared borrows of temporaries that have their lif LL | &{a} | ^^^^ this borrow of an interior mutable value refers to such a temporary | - = note: Temporaries in constants and statics can have their lifetime extended until the end of the program - = note: To avoid accidentally creating global mutable state, such temporaries must be immutable - = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error: aborting due to 1 previous error diff --git a/tests/ui/consts/qualif_overwrite.stderr b/tests/ui/consts/qualif_overwrite.stderr index 4aaaa4b2ca90..1dc2bf7f1231 100644 --- a/tests/ui/consts/qualif_overwrite.stderr +++ b/tests/ui/consts/qualif_overwrite.stderr @@ -4,9 +4,9 @@ error[E0492]: interior mutable shared borrows of temporaries that have their lif LL | &{a} | ^^^^ this borrow of an interior mutable value refers to such a temporary | - = note: Temporaries in constants and statics can have their lifetime extended until the end of the program - = note: To avoid accidentally creating global mutable state, such temporaries must be immutable - = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error: aborting due to 1 previous error diff --git a/tests/ui/consts/qualif_overwrite_2.stderr b/tests/ui/consts/qualif_overwrite_2.stderr index bc1681418765..fb8ac601c67a 100644 --- a/tests/ui/consts/qualif_overwrite_2.stderr +++ b/tests/ui/consts/qualif_overwrite_2.stderr @@ -4,9 +4,9 @@ error[E0492]: interior mutable shared borrows of temporaries that have their lif LL | &{a.0} | ^^^^^^ this borrow of an interior mutable value refers to such a temporary | - = note: Temporaries in constants and statics can have their lifetime extended until the end of the program - = note: To avoid accidentally creating global mutable state, such temporaries must be immutable - = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error: aborting due to 1 previous error diff --git a/tests/ui/consts/refs-to-cell-in-final.stderr b/tests/ui/consts/refs-to-cell-in-final.stderr index ac866dbe7210..e30b5aa24e76 100644 --- a/tests/ui/consts/refs-to-cell-in-final.stderr +++ b/tests/ui/consts/refs-to-cell-in-final.stderr @@ -4,9 +4,9 @@ error[E0492]: interior mutable shared borrows of temporaries that have their lif LL | static RAW_SYNC_S: SyncPtr> = SyncPtr { x: &Cell::new(42) }; | ^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary | - = note: Temporaries in constants and statics can have their lifetime extended until the end of the program - = note: To avoid accidentally creating global mutable state, such temporaries must be immutable - = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed --> $DIR/refs-to-cell-in-final.rs:15:53 @@ -14,9 +14,9 @@ error[E0492]: interior mutable shared borrows of temporaries that have their lif LL | const RAW_SYNC_C: SyncPtr> = SyncPtr { x: &Cell::new(42) }; | ^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary | - = note: Temporaries in constants and statics can have their lifetime extended until the end of the program - = note: To avoid accidentally creating global mutable state, such temporaries must be immutable - = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed --> $DIR/refs-to-cell-in-final.rs:41:57 @@ -31,9 +31,9 @@ LL | | x LL | | }; | |_^ this borrow of an interior mutable value refers to such a temporary | - = note: Temporaries in constants and statics can have their lifetime extended until the end of the program - = note: To avoid accidentally creating global mutable state, such temporaries must be immutable - = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error: aborting due to 3 previous errors diff --git a/tests/ui/consts/write_to_static_via_mut_ref.stderr b/tests/ui/consts/write_to_static_via_mut_ref.stderr index ce44047f1550..be1f7178998a 100644 --- a/tests/ui/consts/write_to_static_via_mut_ref.stderr +++ b/tests/ui/consts/write_to_static_via_mut_ref.stderr @@ -4,9 +4,9 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended u LL | static OH_NO: &mut i32 = &mut 42; | ^^^^^^^ this mutable borrow refers to such a temporary | - = note: Temporaries in constants and statics can have their lifetime extended until the end of the program - = note: To avoid accidentally creating global mutable state, such temporaries must be immutable - = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error[E0594]: cannot assign to `*OH_NO`, as `OH_NO` is an immutable static item --> $DIR/write_to_static_via_mut_ref.rs:4:5 diff --git a/tests/ui/error-codes/E0017.stderr b/tests/ui/error-codes/E0017.stderr index fcc57b9e5c3c..70186165d862 100644 --- a/tests/ui/error-codes/E0017.stderr +++ b/tests/ui/error-codes/E0017.stderr @@ -19,9 +19,9 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended u LL | const CR: &'static mut i32 = &mut C; | ^^^^^^ this mutable borrow refers to such a temporary | - = note: Temporaries in constants and statics can have their lifetime extended until the end of the program - = note: To avoid accidentally creating global mutable state, such temporaries must be immutable - = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error[E0596]: cannot borrow immutable static item `X` as mutable --> $DIR/E0017.rs:11:39 @@ -52,9 +52,9 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended u LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ this mutable borrow refers to such a temporary | - = note: Temporaries in constants and statics can have their lifetime extended until the end of the program - = note: To avoid accidentally creating global mutable state, such temporaries must be immutable - = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error: aborting due to 3 previous errors; 2 warnings emitted diff --git a/tests/ui/error-codes/E0492.stderr b/tests/ui/error-codes/E0492.stderr index 43a3a872e4e7..a5057e8baedb 100644 --- a/tests/ui/error-codes/E0492.stderr +++ b/tests/ui/error-codes/E0492.stderr @@ -4,9 +4,9 @@ error[E0492]: interior mutable shared borrows of temporaries that have their lif LL | const B: &'static AtomicUsize = &A; | ^^ this borrow of an interior mutable value refers to such a temporary | - = note: Temporaries in constants and statics can have their lifetime extended until the end of the program - = note: To avoid accidentally creating global mutable state, such temporaries must be immutable - = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed --> $DIR/E0492.rs:5:34 @@ -14,9 +14,9 @@ error[E0492]: interior mutable shared borrows of temporaries that have their lif LL | static C: &'static AtomicUsize = &A; | ^^ this borrow of an interior mutable value refers to such a temporary | - = note: Temporaries in constants and statics can have their lifetime extended until the end of the program - = note: To avoid accidentally creating global mutable state, such temporaries must be immutable - = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error: aborting due to 2 previous errors diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs index 3e3235e658f6..ce2f9a4e6eeb 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs @@ -525,25 +525,25 @@ mod macro_escape { #[no_std] //~^ WARN crate-level attribute should be an inner attribute mod no_std { - //~^ NOTE This attribute does not have an `!`, which means it is applied to this module + //~^ NOTE this attribute does not have an `!`, which means it is applied to this module mod inner { #![no_std] } //~^ WARN the `#![no_std]` attribute can only be used at the crate root #[no_std] fn f() { } //~^ WARN crate-level attribute should be an inner attribute - //~| NOTE This attribute does not have an `!`, which means it is applied to this function + //~| NOTE this attribute does not have an `!`, which means it is applied to this function #[no_std] struct S; //~^ WARN crate-level attribute should be an inner attribute - //~| NOTE This attribute does not have an `!`, which means it is applied to this struct + //~| NOTE this attribute does not have an `!`, which means it is applied to this struct #[no_std] type T = S; //~^ WARN crate-level attribute should be an inner attribute - //~| NOTE This attribute does not have an `!`, which means it is applied to this type alias + //~| NOTE this attribute does not have an `!`, which means it is applied to this type alias #[no_std] impl S { } //~^ WARN crate-level attribute should be an inner attribute - //~| NOTE This attribute does not have an `!`, which means it is applied to this implementation block + //~| NOTE this attribute does not have an `!`, which means it is applied to this implementation block } // At time of authorship, #[proc_macro_derive = "2500"] signals error @@ -786,25 +786,25 @@ mod must_use { #[windows_subsystem = "windows"] //~^ WARN crate-level attribute should be an inner attribute mod windows_subsystem { - //~^ NOTE This attribute does not have an `!`, which means it is applied to this module + //~^ NOTE this attribute does not have an `!`, which means it is applied to this module mod inner { #![windows_subsystem="windows"] } //~^ WARN the `#![windows_subsystem]` attribute can only be used at the crate root #[windows_subsystem = "windows"] fn f() { } //~^ WARN crate-level attribute should be an inner attribute - //~| NOTE This attribute does not have an `!`, which means it is applied to this function + //~| NOTE this attribute does not have an `!`, which means it is applied to this function #[windows_subsystem = "windows"] struct S; //~^ WARN crate-level attribute should be an inner attribute - //~| NOTE This attribute does not have an `!`, which means it is applied to this struct + //~| NOTE this attribute does not have an `!`, which means it is applied to this struct #[windows_subsystem = "windows"] type T = S; //~^ WARN crate-level attribute should be an inner attribute - //~| NOTE This attribute does not have an `!`, which means it is applied to this type alias + //~| NOTE this attribute does not have an `!`, which means it is applied to this type alias #[windows_subsystem = "windows"] impl S { } //~^ WARN crate-level attribute should be an inner attribute - //~| NOTE This attribute does not have an `!`, which means it is applied to this implementation block + //~| NOTE this attribute does not have an `!`, which means it is applied to this implementation block } // BROKEN USES OF CRATE-LEVEL BUILT-IN ATTRIBUTES @@ -812,25 +812,25 @@ mod windows_subsystem { #[crate_name = "0900"] //~^ WARN crate-level attribute should be an inner attribute mod crate_name { -//~^ NOTE This attribute does not have an `!`, which means it is applied to this module +//~^ NOTE this attribute does not have an `!`, which means it is applied to this module mod inner { #![crate_name="0900"] } //~^ WARN the `#![crate_name]` attribute can only be used at the crate root #[crate_name = "0900"] fn f() { } //~^ WARN crate-level attribute should be an inner attribute - //~| NOTE This attribute does not have an `!`, which means it is applied to this function + //~| NOTE this attribute does not have an `!`, which means it is applied to this function #[crate_name = "0900"] struct S; //~^ WARN crate-level attribute should be an inner attribute - //~| NOTE This attribute does not have an `!`, which means it is applied to this struct + //~| NOTE this attribute does not have an `!`, which means it is applied to this struct #[crate_name = "0900"] type T = S; //~^ WARN crate-level attribute should be an inner attribute - //~| NOTE This attribute does not have an `!`, which means it is applied to this type alias + //~| NOTE this attribute does not have an `!`, which means it is applied to this type alias #[crate_name = "0900"] impl S { } //~^ WARN crate-level attribute should be an inner attribute - //~| NOTE This attribute does not have an `!`, which means it is applied to this implementation block + //~| NOTE this attribute does not have an `!`, which means it is applied to this implementation block } #[crate_type = "0800"] @@ -885,25 +885,25 @@ mod feature { #[no_main] //~^ WARN crate-level attribute should be an inner attribute mod no_main_1 { - //~^ NOTE: This attribute does not have an `!`, which means it is applied to this module + //~^ NOTE: this attribute does not have an `!`, which means it is applied to this module mod inner { #![no_main] } //~^ WARN the `#![no_main]` attribute can only be used at the crate root #[no_main] fn f() { } //~^ WARN crate-level attribute should be an inner attribute - //~| NOTE This attribute does not have an `!`, which means it is applied to this function + //~| NOTE this attribute does not have an `!`, which means it is applied to this function #[no_main] struct S; //~^ WARN crate-level attribute should be an inner attribute - //~| NOTE This attribute does not have an `!`, which means it is applied to this struct + //~| NOTE this attribute does not have an `!`, which means it is applied to this struct #[no_main] type T = S; //~^ WARN crate-level attribute should be an inner attribute - //~| NOTE This attribute does not have an `!`, which means it is applied to this type alias + //~| NOTE this attribute does not have an `!`, which means it is applied to this type alias #[no_main] impl S { } //~^ WARN crate-level attribute should be an inner attribute - //~| NOTE This attribute does not have an `!`, which means it is applied to this implementation + //~| NOTE this attribute does not have an `!`, which means it is applied to this implementation } #[no_builtins] @@ -933,49 +933,49 @@ mod no_builtins { #[recursion_limit="0200"] //~^ WARN crate-level attribute should be an inner attribute mod recursion_limit { - //~^ NOTE This attribute does not have an `!`, which means it is applied to this module + //~^ NOTE this attribute does not have an `!`, which means it is applied to this module mod inner { #![recursion_limit="0200"] } //~^ WARN the `#![recursion_limit]` attribute can only be used at the crate root #[recursion_limit="0200"] fn f() { } //~^ WARN crate-level attribute should be an inner attribute - //~| NOTE This attribute does not have an `!`, which means it is applied to this function + //~| NOTE this attribute does not have an `!`, which means it is applied to this function #[recursion_limit="0200"] struct S; //~^ WARN crate-level attribute should be an inner attribute - //~| NOTE This attribute does not have an `!`, which means it is applied to this struct + //~| NOTE this attribute does not have an `!`, which means it is applied to this struct #[recursion_limit="0200"] type T = S; //~^ WARN crate-level attribute should be an inner attribute - //~| NOTE This attribute does not have an `!`, which means it is applied to this type alias + //~| NOTE this attribute does not have an `!`, which means it is applied to this type alias #[recursion_limit="0200"] impl S { } //~^ WARN crate-level attribute should be an inner attribute - //~| NOTE This attribute does not have an `!`, which means it is applied to this implementation block + //~| NOTE this attribute does not have an `!`, which means it is applied to this implementation block } #[type_length_limit="0100"] //~^ WARN crate-level attribute should be an inner attribute mod type_length_limit { - //~^ NOTE This attribute does not have an `!`, which means it is applied to this module + //~^ NOTE this attribute does not have an `!`, which means it is applied to this module mod inner { #![type_length_limit="0100"] } //~^ WARN the `#![type_length_limit]` attribute can only be used at the crate root #[type_length_limit="0100"] fn f() { } //~^ WARN crate-level attribute should be an inner attribute - //~| NOTE This attribute does not have an `!`, which means it is applied to this function + //~| NOTE this attribute does not have an `!`, which means it is applied to this function #[type_length_limit="0100"] struct S; //~^ WARN crate-level attribute should be an inner attribute - //~| NOTE This attribute does not have an `!`, which means it is applied to this struct + //~| NOTE this attribute does not have an `!`, which means it is applied to this struct #[type_length_limit="0100"] type T = S; //~^ WARN crate-level attribute should be an inner attribute - //~| NOTE This attribute does not have an `!`, which means it is applied to this type alias + //~| NOTE this attribute does not have an `!`, which means it is applied to this type alias #[type_length_limit="0100"] impl S { } //~^ WARN crate-level attribute should be an inner attribute - //~| NOTE This attribute does not have an `!`, which means it is applied to this implementation block + //~| NOTE this attribute does not have an `!`, which means it is applied to this implementation block } fn main() {} diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr index d89aec222be8..cbb80ccd753c 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr @@ -935,7 +935,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[no_std] | ^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this module +note: this attribute does not have an `!`, which means it is applied to this module --> $DIR/issue-43106-gating-of-builtin-attrs.rs:527:1 | LL | / mod no_std { @@ -957,7 +957,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[no_std] fn f() { } | ^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this function +note: this attribute does not have an `!`, which means it is applied to this function --> $DIR/issue-43106-gating-of-builtin-attrs.rs:532:15 | LL | #[no_std] fn f() { } @@ -969,7 +969,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[no_std] struct S; | ^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this struct +note: this attribute does not have an `!`, which means it is applied to this struct --> $DIR/issue-43106-gating-of-builtin-attrs.rs:536:15 | LL | #[no_std] struct S; @@ -981,7 +981,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[no_std] type T = S; | ^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this type alias +note: this attribute does not have an `!`, which means it is applied to this type alias --> $DIR/issue-43106-gating-of-builtin-attrs.rs:540:15 | LL | #[no_std] type T = S; @@ -993,7 +993,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[no_std] impl S { } | ^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this implementation block +note: this attribute does not have an `!`, which means it is applied to this implementation block --> $DIR/issue-43106-gating-of-builtin-attrs.rs:544:15 | LL | #[no_std] impl S { } @@ -1212,7 +1212,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[windows_subsystem = "windows"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this module +note: this attribute does not have an `!`, which means it is applied to this module --> $DIR/issue-43106-gating-of-builtin-attrs.rs:788:1 | LL | / mod windows_subsystem { @@ -1234,7 +1234,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[windows_subsystem = "windows"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this function +note: this attribute does not have an `!`, which means it is applied to this function --> $DIR/issue-43106-gating-of-builtin-attrs.rs:793:38 | LL | #[windows_subsystem = "windows"] fn f() { } @@ -1246,7 +1246,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[windows_subsystem = "windows"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this struct +note: this attribute does not have an `!`, which means it is applied to this struct --> $DIR/issue-43106-gating-of-builtin-attrs.rs:797:38 | LL | #[windows_subsystem = "windows"] struct S; @@ -1258,7 +1258,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[windows_subsystem = "windows"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this type alias +note: this attribute does not have an `!`, which means it is applied to this type alias --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:38 | LL | #[windows_subsystem = "windows"] type T = S; @@ -1270,7 +1270,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[windows_subsystem = "windows"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this implementation block +note: this attribute does not have an `!`, which means it is applied to this implementation block --> $DIR/issue-43106-gating-of-builtin-attrs.rs:805:38 | LL | #[windows_subsystem = "windows"] impl S { } @@ -1282,7 +1282,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this module +note: this attribute does not have an `!`, which means it is applied to this module --> $DIR/issue-43106-gating-of-builtin-attrs.rs:814:1 | LL | / mod crate_name { @@ -1304,7 +1304,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this function +note: this attribute does not have an `!`, which means it is applied to this function --> $DIR/issue-43106-gating-of-builtin-attrs.rs:819:28 | LL | #[crate_name = "0900"] fn f() { } @@ -1316,7 +1316,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this struct +note: this attribute does not have an `!`, which means it is applied to this struct --> $DIR/issue-43106-gating-of-builtin-attrs.rs:823:28 | LL | #[crate_name = "0900"] struct S; @@ -1328,7 +1328,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this type alias +note: this attribute does not have an `!`, which means it is applied to this type alias --> $DIR/issue-43106-gating-of-builtin-attrs.rs:827:28 | LL | #[crate_name = "0900"] type T = S; @@ -1340,7 +1340,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this implementation block +note: this attribute does not have an `!`, which means it is applied to this implementation block --> $DIR/issue-43106-gating-of-builtin-attrs.rs:831:28 | LL | #[crate_name = "0900"] impl S { } @@ -1352,7 +1352,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[no_main] | ^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this module +note: this attribute does not have an `!`, which means it is applied to this module --> $DIR/issue-43106-gating-of-builtin-attrs.rs:887:1 | LL | / mod no_main_1 { @@ -1374,7 +1374,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[no_main] fn f() { } | ^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this function +note: this attribute does not have an `!`, which means it is applied to this function --> $DIR/issue-43106-gating-of-builtin-attrs.rs:892:16 | LL | #[no_main] fn f() { } @@ -1386,7 +1386,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[no_main] struct S; | ^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this struct +note: this attribute does not have an `!`, which means it is applied to this struct --> $DIR/issue-43106-gating-of-builtin-attrs.rs:896:16 | LL | #[no_main] struct S; @@ -1398,7 +1398,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[no_main] type T = S; | ^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this type alias +note: this attribute does not have an `!`, which means it is applied to this type alias --> $DIR/issue-43106-gating-of-builtin-attrs.rs:900:16 | LL | #[no_main] type T = S; @@ -1410,7 +1410,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[no_main] impl S { } | ^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this implementation block +note: this attribute does not have an `!`, which means it is applied to this implementation block --> $DIR/issue-43106-gating-of-builtin-attrs.rs:904:16 | LL | #[no_main] impl S { } @@ -1422,7 +1422,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this module +note: this attribute does not have an `!`, which means it is applied to this module --> $DIR/issue-43106-gating-of-builtin-attrs.rs:935:1 | LL | / mod recursion_limit { @@ -1444,7 +1444,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this function +note: this attribute does not have an `!`, which means it is applied to this function --> $DIR/issue-43106-gating-of-builtin-attrs.rs:940:31 | LL | #[recursion_limit="0200"] fn f() { } @@ -1456,7 +1456,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this struct +note: this attribute does not have an `!`, which means it is applied to this struct --> $DIR/issue-43106-gating-of-builtin-attrs.rs:944:31 | LL | #[recursion_limit="0200"] struct S; @@ -1468,7 +1468,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this type alias +note: this attribute does not have an `!`, which means it is applied to this type alias --> $DIR/issue-43106-gating-of-builtin-attrs.rs:948:31 | LL | #[recursion_limit="0200"] type T = S; @@ -1480,7 +1480,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this implementation block +note: this attribute does not have an `!`, which means it is applied to this implementation block --> $DIR/issue-43106-gating-of-builtin-attrs.rs:952:31 | LL | #[recursion_limit="0200"] impl S { } @@ -1492,7 +1492,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this module +note: this attribute does not have an `!`, which means it is applied to this module --> $DIR/issue-43106-gating-of-builtin-attrs.rs:959:1 | LL | / mod type_length_limit { @@ -1514,7 +1514,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this function +note: this attribute does not have an `!`, which means it is applied to this function --> $DIR/issue-43106-gating-of-builtin-attrs.rs:964:33 | LL | #[type_length_limit="0100"] fn f() { } @@ -1526,7 +1526,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this struct +note: this attribute does not have an `!`, which means it is applied to this struct --> $DIR/issue-43106-gating-of-builtin-attrs.rs:968:33 | LL | #[type_length_limit="0100"] struct S; @@ -1538,7 +1538,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this type alias +note: this attribute does not have an `!`, which means it is applied to this type alias --> $DIR/issue-43106-gating-of-builtin-attrs.rs:972:33 | LL | #[type_length_limit="0100"] type T = S; @@ -1550,7 +1550,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this implementation block +note: this attribute does not have an `!`, which means it is applied to this implementation block --> $DIR/issue-43106-gating-of-builtin-attrs.rs:976:33 | LL | #[type_length_limit="0100"] impl S { } diff --git a/tests/ui/issues/issue-46604.stderr b/tests/ui/issues/issue-46604.stderr index abe3ad476c60..21abc498de12 100644 --- a/tests/ui/issues/issue-46604.stderr +++ b/tests/ui/issues/issue-46604.stderr @@ -4,9 +4,9 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended u LL | static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; | ^^^^^^^^^^^^^^^^^^^^ this mutable borrow refers to such a temporary | - = note: Temporaries in constants and statics can have their lifetime extended until the end of the program - = note: To avoid accidentally creating global mutable state, such temporaries must be immutable - = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error[E0594]: cannot assign to `buf[_]`, as `buf` is an immutable static item --> $DIR/issue-46604.rs:6:5 diff --git a/tests/ui/lint/large_assignments/copy_into_box_rc_arc.stderr b/tests/ui/lint/large_assignments/copy_into_box_rc_arc.stderr index 6e42328a1113..b8e7abf4807c 100644 --- a/tests/ui/lint/large_assignments/copy_into_box_rc_arc.stderr +++ b/tests/ui/lint/large_assignments/copy_into_box_rc_arc.stderr @@ -4,7 +4,7 @@ error: moving 9999 bytes LL | let _ = NotBox::new(data); | ^^^^ value moved from here | - = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + = note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` note: the lint level is defined here --> $DIR/copy_into_box_rc_arc.rs:1:9 | @@ -19,7 +19,7 @@ LL | | data, LL | | } | |_________^ value moved from here | - = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + = note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` error: aborting due to 2 previous errors diff --git a/tests/ui/lint/large_assignments/copy_into_fn.stderr b/tests/ui/lint/large_assignments/copy_into_fn.stderr index f05fc33e17e1..a4c4800266af 100644 --- a/tests/ui/lint/large_assignments/copy_into_fn.stderr +++ b/tests/ui/lint/large_assignments/copy_into_fn.stderr @@ -4,7 +4,7 @@ error: moving 9999 bytes LL | one_arg(Data([0; 9999])); | ^^^^^^^^^^^^^^^ value moved from here | - = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + = note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` note: the lint level is defined here --> $DIR/copy_into_fn.rs:5:9 | @@ -17,7 +17,7 @@ error: moving 9999 bytes LL | many_args(Data([0; 9999]), true, Data([0; 9999])); | ^^^^^^^^^^^^^^^ value moved from here | - = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + = note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` error: moving 9999 bytes --> $DIR/copy_into_fn.rs:17:38 @@ -25,7 +25,7 @@ error: moving 9999 bytes LL | many_args(Data([0; 9999]), true, Data([0; 9999])); | ^^^^^^^^^^^^^^^ value moved from here | - = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + = note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` error: aborting due to 3 previous errors diff --git a/tests/ui/lint/large_assignments/inline_mir.stderr b/tests/ui/lint/large_assignments/inline_mir.stderr index 1a5fcb6c8fc1..b8170d8977d2 100644 --- a/tests/ui/lint/large_assignments/inline_mir.stderr +++ b/tests/ui/lint/large_assignments/inline_mir.stderr @@ -4,7 +4,7 @@ error: moving 9999 bytes LL | let cell = std::cell::UnsafeCell::new(data); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ value moved from here | - = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + = note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` note: the lint level is defined here --> $DIR/inline_mir.rs:2:9 | @@ -17,7 +17,7 @@ error: moving 9999 bytes LL | std::hint::black_box(cell); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ value moved from here | - = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + = note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` error: aborting due to 2 previous errors diff --git a/tests/ui/lint/large_assignments/large_future.attribute.stderr b/tests/ui/lint/large_assignments/large_future.attribute.stderr index 734b7ff7ba22..1580c31df3c2 100644 --- a/tests/ui/lint/large_assignments/large_future.attribute.stderr +++ b/tests/ui/lint/large_assignments/large_future.attribute.stderr @@ -4,7 +4,7 @@ error: moving 10024 bytes LL | let z = (x, 42); | ^ value moved from here | - = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + = note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` note: the lint level is defined here --> $DIR/large_future.rs:1:9 | @@ -17,7 +17,7 @@ error: moving 10024 bytes LL | let a = z.0; | ^^^ value moved from here | - = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + = note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` error: aborting due to 2 previous errors diff --git a/tests/ui/lint/large_assignments/large_future.option.stderr b/tests/ui/lint/large_assignments/large_future.option.stderr index 734b7ff7ba22..1580c31df3c2 100644 --- a/tests/ui/lint/large_assignments/large_future.option.stderr +++ b/tests/ui/lint/large_assignments/large_future.option.stderr @@ -4,7 +4,7 @@ error: moving 10024 bytes LL | let z = (x, 42); | ^ value moved from here | - = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + = note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` note: the lint level is defined here --> $DIR/large_future.rs:1:9 | @@ -17,7 +17,7 @@ error: moving 10024 bytes LL | let a = z.0; | ^^^ value moved from here | - = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + = note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` error: aborting due to 2 previous errors diff --git a/tests/ui/lint/large_assignments/move_into_box_rc_arc.stderr b/tests/ui/lint/large_assignments/move_into_box_rc_arc.stderr index a386de5e5e8e..35f30a79ad99 100644 --- a/tests/ui/lint/large_assignments/move_into_box_rc_arc.stderr +++ b/tests/ui/lint/large_assignments/move_into_box_rc_arc.stderr @@ -4,7 +4,7 @@ error: moving 9999 bytes LL | data, | ^^^^ value moved from here | - = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + = note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` note: the lint level is defined here --> $DIR/move_into_box_rc_arc.rs:1:9 | diff --git a/tests/ui/lint/large_assignments/move_into_fn.stderr b/tests/ui/lint/large_assignments/move_into_fn.stderr index 19ec6a51d2e7..4f4c710cacef 100644 --- a/tests/ui/lint/large_assignments/move_into_fn.stderr +++ b/tests/ui/lint/large_assignments/move_into_fn.stderr @@ -4,7 +4,7 @@ error: moving 9999 bytes LL | let data = Data([100; 9999]); | ^^^^^^^^^^^^^^^^^ value moved from here | - = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + = note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` note: the lint level is defined here --> $DIR/move_into_fn.rs:5:9 | @@ -17,7 +17,7 @@ error: moving 9999 bytes LL | take_data(data); | ^^^^ value moved from here | - = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + = note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` error: aborting due to 2 previous errors diff --git a/tests/ui/lint/unused/concat-in-crate-name-issue-137687.stderr b/tests/ui/lint/unused/concat-in-crate-name-issue-137687.stderr index b06e65af7bc7..5928eb6c58c4 100644 --- a/tests/ui/lint/unused/concat-in-crate-name-issue-137687.stderr +++ b/tests/ui/lint/unused/concat-in-crate-name-issue-137687.stderr @@ -17,7 +17,7 @@ error: crate-level attribute should be an inner attribute: add an exclamation ma LL | #[crate_name = concat !()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this macro def +note: this attribute does not have an `!`, which means it is applied to this macro def --> $DIR/concat-in-crate-name-issue-137687.rs:5:1 | LL | / macro_rules! a { diff --git a/tests/ui/lint/unused/unused-attr-macro-rules.stderr b/tests/ui/lint/unused/unused-attr-macro-rules.stderr index e251ec65622e..75e86d3c014f 100644 --- a/tests/ui/lint/unused/unused-attr-macro-rules.stderr +++ b/tests/ui/lint/unused/unused-attr-macro-rules.stderr @@ -27,7 +27,7 @@ error: crate-level attribute should be an inner attribute: add an exclamation ma LL | #[recursion_limit="1"] | ^^^^^^^^^^^^^^^^^^^^^^ | -note: This attribute does not have an `!`, which means it is applied to this macro def +note: this attribute does not have an `!`, which means it is applied to this macro def --> $DIR/unused-attr-macro-rules.rs:12:1 | LL | / macro_rules! foo { diff --git a/tests/ui/statics/check-immutable-mut-slices.stderr b/tests/ui/statics/check-immutable-mut-slices.stderr index a9486fc9d781..1e6dfb78c93d 100644 --- a/tests/ui/statics/check-immutable-mut-slices.stderr +++ b/tests/ui/statics/check-immutable-mut-slices.stderr @@ -4,9 +4,9 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended u LL | static TEST: &'static mut [isize] = &mut []; | ^^^^^^^ this mutable borrow refers to such a temporary | - = note: Temporaries in constants and statics can have their lifetime extended until the end of the program - = note: To avoid accidentally creating global mutable state, such temporaries must be immutable - = help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` + = note: temporaries in constants and statics can have their lifetime extended until the end of the program + = note: to avoid accidentally creating global mutable state, such temporaries must be immutable + = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error: aborting due to 1 previous error diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.stderr b/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.stderr index 9f07e63e4544..e144b981f3cd 100644 --- a/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.stderr +++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.stderr @@ -4,7 +4,7 @@ error: item annotated with `#[unstable_feature_bound]` should not be stable LL | fn bar() {} | ^^^^^^^^^^^ | - = help: If this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]` + = help: if this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]` error: aborting due to 1 previous error From 08432c892758a06a6bab9fa0584effb7e7881303 Mon Sep 17 00:00:00 2001 From: Andreas Liljeqvist Date: Sun, 18 Jan 2026 22:49:37 +0100 Subject: [PATCH 0840/1061] Optimize small input path for is_ascii on x86_64 For inputs smaller than 32 bytes, use usize-at-a-time processing instead of calling the SSE2 function. This avoids function call overhead from #[target_feature(enable = "sse2")] which prevents inlining. Also moves CHUNK_SIZE to module level so it can be shared between is_ascii and is_ascii_sse2. --- library/core/src/slice/ascii.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index c9e168d6cbf8..25b8a10af355 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -460,6 +460,10 @@ const fn is_ascii(s: &[u8]) -> bool { ) } +/// Chunk size for vectorized ASCII checking (two 16-byte SSE registers). +#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] +const CHUNK_SIZE: usize = 32; + /// SSE2 implementation using `_mm_movemask_epi8` (compiles to `pmovmskb`) to /// avoid LLVM's broken AVX-512 auto-vectorization of counting loops. /// @@ -470,8 +474,6 @@ const fn is_ascii(s: &[u8]) -> bool { unsafe fn is_ascii_sse2(bytes: &[u8]) -> bool { use crate::arch::x86_64::{__m128i, _mm_loadu_si128, _mm_movemask_epi8, _mm_or_si128}; - const CHUNK_SIZE: usize = 32; - let mut i = 0; while i + CHUNK_SIZE <= bytes.len() { @@ -518,11 +520,27 @@ unsafe fn is_ascii_sse2(bytes: &[u8]) -> bool { #[inline] #[rustc_allow_const_fn_unstable(const_eval_select)] const fn is_ascii(bytes: &[u8]) -> bool { + const USIZE_SIZE: usize = size_of::(); + const NONASCII_MASK: usize = usize::MAX / 255 * 0x80; + const_eval_select!( @capture { bytes: &[u8] } -> bool: if const { is_ascii_simple(bytes) } else { + // For small inputs, use usize-at-a-time processing to avoid SSE2 call overhead. + if bytes.len() < CHUNK_SIZE { + let chunks = bytes.chunks_exact(USIZE_SIZE); + let remainder = chunks.remainder(); + for chunk in chunks { + let word = usize::from_ne_bytes(chunk.try_into().unwrap()); + if (word & NONASCII_MASK) != 0 { + return false; + } + } + return remainder.iter().all(|b| b.is_ascii()); + } + // SAFETY: SSE2 is guaranteed available on x86_64 unsafe { is_ascii_sse2(bytes) } } From 3a8b57715f1e762fbb78edc89c767446b7fdc0ea Mon Sep 17 00:00:00 2001 From: KaiTomotake Date: Sun, 18 Jan 2026 22:43:35 +0900 Subject: [PATCH 0841/1061] add lint test Co-authored-by: Redddy --- .../unused_assignments_across_match_guards.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/ui/lint/unused/unused_assignments_across_match_guards.rs diff --git a/tests/ui/lint/unused/unused_assignments_across_match_guards.rs b/tests/ui/lint/unused/unused_assignments_across_match_guards.rs new file mode 100644 index 000000000000..666a529b8f85 --- /dev/null +++ b/tests/ui/lint/unused/unused_assignments_across_match_guards.rs @@ -0,0 +1,19 @@ +// Regression test for +// This test ensures that unused_assignments does not report assignments used in a match. +//@ check-pass + +fn pnk(x: usize) -> &'static str { + let mut k1 = "k1"; + let mut h1 = "h1"; + match x & 3 { + 3 if { k1 = "unused?"; false } => (), + _ if { h1 = k1; true } => (), + _ => (), + } + h1 +} + +#[deny(unused_assignments)] +fn main() { + pnk(3); +} From 3327a92b4353a03c60dbb2c58564be754e93db22 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 5 Nov 2025 20:40:15 +1100 Subject: [PATCH 0842/1061] Add some tests for trimmed paths in diagnostics --- .../auxiliary/doc_hidden_helper.rs | 18 +++++ tests/ui/trimmed-paths/core-unicode.rs | 19 ++++++ tests/ui/trimmed-paths/core-unicode.stderr | 14 ++++ tests/ui/trimmed-paths/doc-hidden.rs | 68 +++++++++++++++++++ tests/ui/trimmed-paths/doc-hidden.stderr | 39 +++++++++++ 5 files changed, 158 insertions(+) create mode 100644 tests/ui/trimmed-paths/auxiliary/doc_hidden_helper.rs create mode 100644 tests/ui/trimmed-paths/core-unicode.rs create mode 100644 tests/ui/trimmed-paths/core-unicode.stderr create mode 100644 tests/ui/trimmed-paths/doc-hidden.rs create mode 100644 tests/ui/trimmed-paths/doc-hidden.stderr diff --git a/tests/ui/trimmed-paths/auxiliary/doc_hidden_helper.rs b/tests/ui/trimmed-paths/auxiliary/doc_hidden_helper.rs new file mode 100644 index 000000000000..2e5e1591606e --- /dev/null +++ b/tests/ui/trimmed-paths/auxiliary/doc_hidden_helper.rs @@ -0,0 +1,18 @@ +//@ edition: 2024 + +pub struct ActuallyPub {} +#[doc(hidden)] +pub struct DocHidden {} + +pub mod pub_mod { + pub struct ActuallyPubInPubMod {} + #[doc(hidden)] + pub struct DocHiddenInPubMod {} +} + +#[doc(hidden)] +pub mod hidden_mod { + pub struct ActuallyPubInHiddenMod {} + #[doc(hidden)] + pub struct DocHiddenInHiddenMod {} +} diff --git a/tests/ui/trimmed-paths/core-unicode.rs b/tests/ui/trimmed-paths/core-unicode.rs new file mode 100644 index 000000000000..54bde92a5335 --- /dev/null +++ b/tests/ui/trimmed-paths/core-unicode.rs @@ -0,0 +1,19 @@ +//@ edition: 2024 + +// Test that the `#[doc(hidden)]` module `core::unicode` module does not +// disqualify another item named `unicode` from path trimming in diagnostics. + +use core::marker::PhantomData; + +mod inner { + #[expect(non_camel_case_types)] + pub(crate) enum unicode {} +} + +fn main() { + let PhantomData::<(inner::unicode, u32)> = PhantomData::<(u32, inner::unicode)>; + //~^ ERROR mismatched types [E0308] + //~| NOTE expected `PhantomData<(u32, unicode)>`, found `PhantomData<(unicode, u32)>` + //~| NOTE this expression has type `PhantomData<(u32, inner::unicode)>` + //~| NOTE expected struct `PhantomData<(u32, inner::unicode)>` +} diff --git a/tests/ui/trimmed-paths/core-unicode.stderr b/tests/ui/trimmed-paths/core-unicode.stderr new file mode 100644 index 000000000000..9023200d1c92 --- /dev/null +++ b/tests/ui/trimmed-paths/core-unicode.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/core-unicode.rs:14:9 + | +LL | let PhantomData::<(inner::unicode, u32)> = PhantomData::<(u32, inner::unicode)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------------------------ this expression has type `PhantomData<(u32, inner::unicode)>` + | | + | expected `PhantomData<(u32, unicode)>`, found `PhantomData<(unicode, u32)>` + | + = note: expected struct `PhantomData<(u32, inner::unicode)>` + found struct `PhantomData<(inner::unicode, u32)>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/trimmed-paths/doc-hidden.rs b/tests/ui/trimmed-paths/doc-hidden.rs new file mode 100644 index 000000000000..b73d04c3c6ae --- /dev/null +++ b/tests/ui/trimmed-paths/doc-hidden.rs @@ -0,0 +1,68 @@ +//@ edition: 2024 +//@ aux-crate: helper=doc_hidden_helper.rs + +// Test that `#[doc(hidden)]` items in other crates do not disqualify another +// item with the same name from path trimming in diagnostics. + +// Declare several modules and types whose short names match those in the aux crate. +// +// Of these, only `ActuallyPub` and `ActuallyPubInPubMod` should be disqualified +// from path trimming, because the other names only collide with `#[doc(hidden)]` +// names. +mod local { + pub(crate) struct ActuallyPub {} + pub(crate) struct DocHidden {} + + pub(crate) mod pub_mod { + pub(crate) struct ActuallyPubInPubMod {} + pub(crate) struct DocHiddenInPubMod {} + } + + pub(crate) mod hidden_mod { + pub(crate) struct ActuallyPubInHiddenMod {} + pub(crate) struct DocHiddenInHiddenMod {} + } +} + +fn main() { + uses_local(); + uses_helper(); +} + +fn uses_local() { + use local::{ActuallyPub, DocHidden}; + use local::pub_mod::{ActuallyPubInPubMod, DocHiddenInPubMod}; + use local::hidden_mod::{ActuallyPubInHiddenMod, DocHiddenInHiddenMod}; + + let _: ( + //~^ NOTE expected due to this + ActuallyPub, + DocHidden, + ActuallyPubInPubMod, + DocHiddenInPubMod, + ActuallyPubInHiddenMod, + DocHiddenInHiddenMod, + ) = 3u32; + //~^ ERROR mismatched types [E0308] + //~| NOTE expected `(ActuallyPub, ..., ..., ..., ..., ...)`, found `u32` + //~| NOTE expected tuple `(local::ActuallyPub, local::DocHidden, local::pub_mod::ActuallyPubInPubMod, local::pub_mod::DocHiddenInPubMod, local::hidden_mod::ActuallyPubInHiddenMod, local::hidden_mod::DocHiddenInHiddenMod)` +} + +fn uses_helper() { + use helper::{ActuallyPub, DocHidden}; + use helper::pub_mod::{ActuallyPubInPubMod, DocHiddenInPubMod}; + use helper::hidden_mod::{ActuallyPubInHiddenMod, DocHiddenInHiddenMod}; + + let _: ( + //~^ NOTE expected due to this + ActuallyPub, + DocHidden, + ActuallyPubInPubMod, + DocHiddenInPubMod, + ActuallyPubInHiddenMod, + DocHiddenInHiddenMod, + ) = 3u32; + //~^ ERROR mismatched types [E0308] + //~| NOTE expected `(ActuallyPub, ..., ..., ..., ..., ...)`, found `u32` + //~| NOTE expected tuple `(doc_hidden_helper::ActuallyPub, doc_hidden_helper::DocHidden, doc_hidden_helper::pub_mod::ActuallyPubInPubMod, doc_hidden_helper::pub_mod::DocHiddenInPubMod, doc_hidden_helper::hidden_mod::ActuallyPubInHiddenMod, doc_hidden_helper::hidden_mod::DocHiddenInHiddenMod)` +} diff --git a/tests/ui/trimmed-paths/doc-hidden.stderr b/tests/ui/trimmed-paths/doc-hidden.stderr new file mode 100644 index 000000000000..6f6f8f21fbe0 --- /dev/null +++ b/tests/ui/trimmed-paths/doc-hidden.stderr @@ -0,0 +1,39 @@ +error[E0308]: mismatched types + --> $DIR/doc-hidden.rs:45:9 + | +LL | let _: ( + | ____________- +LL | | +LL | | ActuallyPub, +LL | | DocHidden, +... | +LL | | DocHiddenInHiddenMod, +LL | | ) = 3u32; + | | - ^^^^ expected `(ActuallyPub, ..., ..., ..., ..., ...)`, found `u32` + | |_____| + | expected due to this + | + = note: expected tuple `(local::ActuallyPub, local::DocHidden, local::pub_mod::ActuallyPubInPubMod, local::pub_mod::DocHiddenInPubMod, local::hidden_mod::ActuallyPubInHiddenMod, local::hidden_mod::DocHiddenInHiddenMod)` + found type `u32` + +error[E0308]: mismatched types + --> $DIR/doc-hidden.rs:64:9 + | +LL | let _: ( + | ____________- +LL | | +LL | | ActuallyPub, +LL | | DocHidden, +... | +LL | | DocHiddenInHiddenMod, +LL | | ) = 3u32; + | | - ^^^^ expected `(ActuallyPub, ..., ..., ..., ..., ...)`, found `u32` + | |_____| + | expected due to this + | + = note: expected tuple `(doc_hidden_helper::ActuallyPub, doc_hidden_helper::DocHidden, doc_hidden_helper::pub_mod::ActuallyPubInPubMod, doc_hidden_helper::pub_mod::DocHiddenInPubMod, doc_hidden_helper::hidden_mod::ActuallyPubInHiddenMod, doc_hidden_helper::hidden_mod::DocHiddenInHiddenMod)` + found type `u32` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. From 2df2c72d7ae36d11313ed730960030cc5af9fb21 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 5 Nov 2025 18:56:10 +1100 Subject: [PATCH 0843/1061] Ignore `#[doc(hidden)]` items when computing trimmed paths --- compiler/rustc_middle/src/ty/print/pretty.rs | 7 ++++++ ...oo-{closure#0}-{closure#0}.built.after.mir | 2 +- ...-{closure#0}-{synthetic#0}.built.after.mir | 2 +- ...0}-{closure#0}-{closure#0}.built.after.mir | 2 +- ...-{closure#0}-{synthetic#0}.built.after.mir | 2 +- ...0}-{closure#1}-{closure#0}.built.after.mir | 2 +- ...-{closure#1}-{synthetic#0}.built.after.mir | 2 +- tests/mir-opt/box_expr.rs | 2 +- .../issue_101867.main.built.after.mir | 2 +- .../boxes.main.GVN.panic-abort.diff | 4 ++-- .../boxes.main.GVN.panic-unwind.diff | 4 ++-- ..._simplification.hello.GVN.panic-abort.diff | 2 +- ...simplification.hello.GVN.panic-unwind.diff | 2 +- .../transmute.unreachable_box.GVN.32bit.diff | 2 +- .../transmute.unreachable_box.GVN.64bit.diff | 2 +- ...n.DataflowConstProp.32bit.panic-abort.diff | 10 ++++----- ....DataflowConstProp.32bit.panic-unwind.diff | 10 ++++----- ...n.DataflowConstProp.64bit.panic-abort.diff | 10 ++++----- ....DataflowConstProp.64bit.panic-unwind.diff | 10 ++++----- ...oxed_slice.main.GVN.32bit.panic-abort.diff | 12 +++++----- ...xed_slice.main.GVN.32bit.panic-unwind.diff | 12 +++++----- ...oxed_slice.main.GVN.64bit.panic-abort.diff | 12 +++++----- ...xed_slice.main.GVN.64bit.panic-unwind.diff | 12 +++++----- ...reachable_box.DataflowConstProp.32bit.diff | 2 +- ...reachable_box.DataflowConstProp.64bit.diff | 2 +- ...ng_operand.test.GVN.32bit.panic-abort.diff | 2 +- ...ng_operand.test.GVN.64bit.panic-abort.diff | 2 +- ...onential_common.GVN.32bit.panic-abort.diff | 4 ++-- ...nential_common.GVN.32bit.panic-unwind.diff | 4 ++-- ...onential_common.GVN.64bit.panic-abort.diff | 4 ++-- ...nential_common.GVN.64bit.panic-unwind.diff | 4 ++-- tests/mir-opt/gvn.slices.GVN.panic-abort.diff | 8 +++---- .../mir-opt/gvn.slices.GVN.panic-unwind.diff | 8 +++---- .../gvn.wrap_unwrap.GVN.panic-abort.diff | 2 +- .../gvn.wrap_unwrap.GVN.panic-unwind.diff | 2 +- ...inline_diverging.g.Inline.panic-abort.diff | 2 +- ...nline_diverging.g.Inline.panic-unwind.diff | 2 +- .../inline_shims.drop.Inline.panic-abort.diff | 4 ++-- ..._conditions.JumpThreading.panic-abort.diff | 8 +++---- ...conditions.JumpThreading.panic-unwind.diff | 8 +++---- ...fg-pre-optimizations.after.panic-abort.mir | 2 +- ...g-pre-optimizations.after.panic-unwind.mir | 2 +- ...ace.PreCodegen.after.32bit.panic-abort.mir | 8 +++---- ...ce.PreCodegen.after.32bit.panic-unwind.mir | 8 +++---- ...ace.PreCodegen.after.64bit.panic-abort.mir | 8 +++---- ...ce.PreCodegen.after.64bit.panic-unwind.mir | 8 +++---- .../loops.vec_move.PreCodegen.after.mir | 4 ++-- ..._to_slice.PreCodegen.after.panic-abort.mir | 4 ++-- ...to_slice.PreCodegen.after.panic-unwind.mir | 4 ++-- ...mes.foo.ScalarReplacementOfAggregates.diff | 2 +- .../async-closures/def-path.stderr | 4 ++-- .../unsizing-wfcheck-issue-126272.stderr | 2 +- tests/ui/consts/const-eval/format.rs | 2 +- tests/ui/consts/const-eval/format.stderr | 2 +- .../contract-captures-via-closure-noncopy.rs | 2 +- ...ntract-captures-via-closure-noncopy.stderr | 4 ++-- ...derives-span-Eq-enum-struct-variant.stderr | 2 +- tests/ui/derives/derives-span-Eq-enum.stderr | 2 +- .../ui/derives/derives-span-Eq-struct.stderr | 2 +- .../derives-span-Eq-tuple-struct.stderr | 2 +- tests/ui/deriving/issue-103157.stderr | 2 +- tests/ui/issues/issue-27340.stderr | 2 +- tests/ui/kindck/kindck-send-object.stderr | 2 +- tests/ui/kindck/kindck-send-object1.stderr | 2 +- tests/ui/kindck/kindck-send-object2.stderr | 2 +- tests/ui/kindck/kindck-send-owned.stderr | 2 +- .../type-length-limit-enforcement.stderr | 4 +++- tests/ui/proc-macro/bad-projection.stderr | 2 +- tests/ui/proc-macro/proc-macro-abi.stderr | 12 +++++----- ...does-not-have-iter-interpolated-dup.stderr | 2 +- .../does-not-have-iter-interpolated.stderr | 2 +- tests/ui/proc-macro/quote/not-quotable.stderr | 2 +- .../signature-proc-macro-attribute.stderr | 16 +++++++------- .../signature-proc-macro-derive.stderr | 22 +++++++++---------- .../ui/proc-macro/signature-proc-macro.stderr | 22 +++++++++---------- tests/ui/proc-macro/signature.stderr | 2 +- ...lobal-variable-promotion-error-7364.stderr | 2 +- tests/ui/traits/const-traits/issue-79450.rs | 2 +- .../ui/traits/const-traits/issue-79450.stderr | 2 +- tests/ui/traits/cycle-cache-err-60010.stderr | 4 ++-- .../negated-auto-traits-error.stderr | 8 +++---- tests/ui/trimmed-paths/core-unicode.rs | 4 ++-- tests/ui/trimmed-paths/core-unicode.stderr | 6 ++--- tests/ui/trimmed-paths/doc-hidden.rs | 2 +- tests/ui/trimmed-paths/doc-hidden.stderr | 2 +- .../panic-with-unspecified-type.stderr | 2 +- .../ui/type/pattern_types/derives_fail.stderr | 2 +- tests/ui/union/union-derive-clone.stderr | 2 +- tests/ui/union/union-derive-eq.current.stderr | 2 +- tests/ui/union/union-derive-eq.next.stderr | 2 +- 90 files changed, 209 insertions(+), 200 deletions(-) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 2a65517de403..fd0a5ca309a4 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3421,6 +3421,13 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N def::Res::Def(DefKind::AssocTy, _) => {} def::Res::Def(DefKind::TyAlias, _) => {} def::Res::Def(defkind, def_id) => { + // Ignore external `#[doc(hidden)]` items and their descendants. + // They shouldn't prevent other items from being considered + // unique, and should be printed with a full path if necessary. + if tcx.is_doc_hidden(def_id) { + continue; + } + if let Some(ns) = defkind.ns() { collect_fn(&child.ident, ns, def_id); } diff --git a/tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#0}.built.after.mir b/tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#0}.built.after.mir index 9ff1a90ab820..4c9ca11f8283 100644 --- a/tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#0}.built.after.mir +++ b/tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#0}.built.after.mir @@ -1,6 +1,6 @@ // MIR for `foo::{closure#0}::{closure#0}` after built -fn foo::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_fake_read_for_by_move.rs:12:27: 15:6}, _2: ResumeTy) -> () +fn foo::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_fake_read_for_by_move.rs:12:27: 15:6}, _2: std::future::ResumeTy) -> () yields () { debug _task_context => _2; diff --git a/tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{synthetic#0}.built.after.mir b/tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{synthetic#0}.built.after.mir index 4b745caf48c5..e80fdea7051d 100644 --- a/tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{synthetic#0}.built.after.mir +++ b/tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{synthetic#0}.built.after.mir @@ -1,6 +1,6 @@ // MIR for `foo::{closure#0}::{synthetic#0}` after built -fn foo::{closure#0}::{synthetic#0}(_1: {async closure body@$DIR/async_closure_fake_read_for_by_move.rs:12:27: 15:6}, _2: ResumeTy) -> () +fn foo::{closure#0}::{synthetic#0}(_1: {async closure body@$DIR/async_closure_fake_read_for_by_move.rs:12:27: 15:6}, _2: std::future::ResumeTy) -> () yields () { debug _task_context => _2; diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.built.after.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.built.after.mir index 4d484b16b507..075065b4c090 100644 --- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.built.after.mir +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.built.after.mir @@ -1,6 +1,6 @@ // MIR for `main::{closure#0}::{closure#0}::{closure#0}` after built -fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:53:53: 56:10}, _2: ResumeTy) -> () +fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:53:53: 56:10}, _2: std::future::ResumeTy) -> () yields () { debug _task_context => _2; diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{synthetic#0}.built.after.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{synthetic#0}.built.after.mir index ace780f773e8..0f4e5f3cb02f 100644 --- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{synthetic#0}.built.after.mir +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{synthetic#0}.built.after.mir @@ -1,6 +1,6 @@ // MIR for `main::{closure#0}::{closure#0}::{synthetic#0}` after built -fn main::{closure#0}::{closure#0}::{synthetic#0}(_1: {async closure body@$DIR/async_closure_shims.rs:53:53: 56:10}, _2: ResumeTy) -> () +fn main::{closure#0}::{closure#0}::{synthetic#0}(_1: {async closure body@$DIR/async_closure_shims.rs:53:53: 56:10}, _2: std::future::ResumeTy) -> () yields () { debug _task_context => _2; diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.built.after.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.built.after.mir index f50ad689f447..18f4e741384f 100644 --- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.built.after.mir +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.built.after.mir @@ -1,6 +1,6 @@ // MIR for `main::{closure#0}::{closure#1}::{closure#0}` after built -fn main::{closure#0}::{closure#1}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10}, _2: ResumeTy) -> () +fn main::{closure#0}::{closure#1}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10}, _2: std::future::ResumeTy) -> () yields () { debug _task_context => _2; diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{synthetic#0}.built.after.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{synthetic#0}.built.after.mir index 62d8adeedcb6..257586c4a080 100644 --- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{synthetic#0}.built.after.mir +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{synthetic#0}.built.after.mir @@ -1,6 +1,6 @@ // MIR for `main::{closure#0}::{closure#1}::{synthetic#0}` after built -fn main::{closure#0}::{closure#1}::{synthetic#0}(_1: {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10}, _2: ResumeTy) -> () +fn main::{closure#0}::{closure#1}::{synthetic#0}(_1: {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10}, _2: std::future::ResumeTy) -> () yields () { debug _task_context => _2; diff --git a/tests/mir-opt/box_expr.rs b/tests/mir-opt/box_expr.rs index 6299c9871809..dbb07a028a93 100644 --- a/tests/mir-opt/box_expr.rs +++ b/tests/mir-opt/box_expr.rs @@ -8,7 +8,7 @@ fn main() { // CHECK-LABEL: fn main( // CHECK: [[ptr:_.*]] = move {{_.*}} as *const S (Transmute); // CHECK: [[nonnull:_.*]] = NonNull:: { pointer: move [[ptr]] }; - // CHECK: [[unique:_.*]] = Unique:: { pointer: move [[nonnull]], _marker: const PhantomData:: }; + // CHECK: [[unique:_.*]] = std::ptr::Unique:: { pointer: move [[nonnull]], _marker: const PhantomData:: }; // CHECK: [[box:_.*]] = Box::(move [[unique]], const std::alloc::Global); // CHECK: [[ptr:_.*]] = copy (([[box]].0: std::ptr::Unique).0: std::ptr::NonNull) as *const S (Transmute); // CHECK: (*[[ptr]]) = S::new() -> [return: [[ret:bb.*]], unwind: [[unwind:bb.*]]]; diff --git a/tests/mir-opt/building/issue_101867.main.built.after.mir b/tests/mir-opt/building/issue_101867.main.built.after.mir index 83281dea44db..cef4325b9a4d 100644 --- a/tests/mir-opt/building/issue_101867.main.built.after.mir +++ b/tests/mir-opt/building/issue_101867.main.built.after.mir @@ -32,7 +32,7 @@ fn main() -> () { bb1: { StorageLive(_3); StorageLive(_4); - _4 = begin_panic::<&str>(const "explicit panic") -> bb8; + _4 = std::rt::begin_panic::<&str>(const "explicit panic") -> bb8; } bb2: { diff --git a/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff index 95eaf18b4703..ecc4b35ebcb6 100644 --- a/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff +++ b/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff @@ -29,10 +29,10 @@ StorageLive(_5); - _6 = move _4 as *const i32 (Transmute); - _7 = NonNull:: { pointer: move _6 }; -- _8 = Unique:: { pointer: move _7, _marker: const PhantomData:: }; +- _8 = std::ptr::Unique:: { pointer: move _7, _marker: const PhantomData:: }; + _6 = copy _4 as *const i32 (PtrToPtr); + _7 = NonNull:: { pointer: copy _6 }; -+ _8 = Unique:: { pointer: copy _7, _marker: const PhantomData:: }; ++ _8 = std::ptr::Unique:: { pointer: copy _7, _marker: const PhantomData:: }; _5 = Box::(move _8, const std::alloc::Global); - _9 = copy ((_5.0: std::ptr::Unique).0: std::ptr::NonNull) as *const i32 (Transmute); - (*_9) = const 42_i32; diff --git a/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff index 6d8d3a0dcfe2..aba1a4f1df47 100644 --- a/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff +++ b/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff @@ -29,10 +29,10 @@ StorageLive(_5); - _6 = move _4 as *const i32 (Transmute); - _7 = NonNull:: { pointer: move _6 }; -- _8 = Unique:: { pointer: move _7, _marker: const PhantomData:: }; +- _8 = std::ptr::Unique:: { pointer: move _7, _marker: const PhantomData:: }; + _6 = copy _4 as *const i32 (PtrToPtr); + _7 = NonNull:: { pointer: copy _6 }; -+ _8 = Unique:: { pointer: copy _7, _marker: const PhantomData:: }; ++ _8 = std::ptr::Unique:: { pointer: copy _7, _marker: const PhantomData:: }; _5 = Box::(move _8, const std::alloc::Global); - _9 = copy ((_5.0: std::ptr::Unique).0: std::ptr::NonNull) as *const i32 (Transmute); - (*_9) = const 42_i32; diff --git a/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-abort.diff b/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-abort.diff index 5df2232053fe..2ecf41638125 100644 --- a/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-abort.diff +++ b/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-abort.diff @@ -10,7 +10,7 @@ } bb1: { - _1 = begin_panic::<&str>(const "explicit panic") -> unwind unreachable; + _1 = std::rt::begin_panic::<&str>(const "explicit panic") -> unwind unreachable; } bb2: { diff --git a/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-unwind.diff index 788a4424943e..06287b670dd4 100644 --- a/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-unwind.diff +++ b/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-unwind.diff @@ -10,7 +10,7 @@ } bb1: { - _1 = begin_panic::<&str>(const "explicit panic") -> unwind continue; + _1 = std::rt::begin_panic::<&str>(const "explicit panic") -> unwind continue; } bb2: { diff --git a/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.32bit.diff index b698d8f37357..bd24af602c88 100644 --- a/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.32bit.diff +++ b/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.32bit.diff @@ -13,7 +13,7 @@ StorageLive(_1); - _1 = const 1_usize as std::boxed::Box (Transmute); - _2 = copy ((_1.0: std::ptr::Unique).0: std::ptr::NonNull) as *const Never (Transmute); -+ _1 = const Box::(Unique:: {{ pointer: NonNull:: {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData:: }}, std::alloc::Global); ++ _1 = const Box::(std::ptr::Unique:: {{ pointer: NonNull:: {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData:: }}, std::alloc::Global); + _2 = const std::ptr::NonNull:: {{ pointer: {0x1 as *const Never} }} as *const Never (Transmute); unreachable; } diff --git a/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.64bit.diff index b698d8f37357..bd24af602c88 100644 --- a/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.64bit.diff +++ b/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.64bit.diff @@ -13,7 +13,7 @@ StorageLive(_1); - _1 = const 1_usize as std::boxed::Box (Transmute); - _2 = copy ((_1.0: std::ptr::Unique).0: std::ptr::NonNull) as *const Never (Transmute); -+ _1 = const Box::(Unique:: {{ pointer: NonNull:: {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData:: }}, std::alloc::Global); ++ _1 = const Box::(std::ptr::Unique:: {{ pointer: NonNull:: {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData:: }}, std::alloc::Global); + _2 = const std::ptr::NonNull:: {{ pointer: {0x1 as *const Never} }} as *const Never (Transmute); unreachable; } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff index 2c89670dcf7d..7a60070b7074 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff @@ -13,7 +13,7 @@ let mut _4: std::ptr::Unique<[bool; 0]>; scope 3 { } - scope 4 (inlined Unique::<[bool; 0]>::dangling) { + scope 4 (inlined std::ptr::Unique::<[bool; 0]>::dangling) { let mut _5: std::ptr::NonNull<[bool; 0]>; scope 5 (inlined NonNull::<[bool; 0]>::dangling) { let mut _6: std::num::NonZero; @@ -51,13 +51,13 @@ _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}; StorageDead(_7); StorageDead(_6); - _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; + _4 = const std::ptr::Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; StorageDead(_5); - _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; + _3 = const std::ptr::Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; StorageDead(_4); - _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); + _2 = const Box::<[bool]>(std::ptr::Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); StorageDead(_3); - _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }}; + _1 = const A {{ foo: Box::<[bool]>(std::ptr::Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }}; StorageDead(_2); _0 = const (); drop(_1) -> [return: bb1, unwind unreachable]; diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff index 8fecfe224cc6..d13d0d962a69 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff @@ -13,7 +13,7 @@ let mut _4: std::ptr::Unique<[bool; 0]>; scope 3 { } - scope 4 (inlined Unique::<[bool; 0]>::dangling) { + scope 4 (inlined std::ptr::Unique::<[bool; 0]>::dangling) { let mut _5: std::ptr::NonNull<[bool; 0]>; scope 5 (inlined NonNull::<[bool; 0]>::dangling) { let mut _6: std::num::NonZero; @@ -51,13 +51,13 @@ _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}; StorageDead(_7); StorageDead(_6); - _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; + _4 = const std::ptr::Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; StorageDead(_5); - _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; + _3 = const std::ptr::Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; StorageDead(_4); - _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); + _2 = const Box::<[bool]>(std::ptr::Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); StorageDead(_3); - _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }}; + _1 = const A {{ foo: Box::<[bool]>(std::ptr::Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }}; StorageDead(_2); _0 = const (); drop(_1) -> [return: bb1, unwind: bb2]; diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff index 976ea252c2f8..8701e879e959 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff @@ -13,7 +13,7 @@ let mut _4: std::ptr::Unique<[bool; 0]>; scope 3 { } - scope 4 (inlined Unique::<[bool; 0]>::dangling) { + scope 4 (inlined std::ptr::Unique::<[bool; 0]>::dangling) { let mut _5: std::ptr::NonNull<[bool; 0]>; scope 5 (inlined NonNull::<[bool; 0]>::dangling) { let mut _6: std::num::NonZero; @@ -51,13 +51,13 @@ _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}; StorageDead(_7); StorageDead(_6); - _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; + _4 = const std::ptr::Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; StorageDead(_5); - _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; + _3 = const std::ptr::Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; StorageDead(_4); - _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); + _2 = const Box::<[bool]>(std::ptr::Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); StorageDead(_3); - _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }}; + _1 = const A {{ foo: Box::<[bool]>(std::ptr::Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }}; StorageDead(_2); _0 = const (); drop(_1) -> [return: bb1, unwind unreachable]; diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff index 6c59f5e3e2e8..ac1c8d627baa 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff @@ -13,7 +13,7 @@ let mut _4: std::ptr::Unique<[bool; 0]>; scope 3 { } - scope 4 (inlined Unique::<[bool; 0]>::dangling) { + scope 4 (inlined std::ptr::Unique::<[bool; 0]>::dangling) { let mut _5: std::ptr::NonNull<[bool; 0]>; scope 5 (inlined NonNull::<[bool; 0]>::dangling) { let mut _6: std::num::NonZero; @@ -51,13 +51,13 @@ _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}; StorageDead(_7); StorageDead(_6); - _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; + _4 = const std::ptr::Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; StorageDead(_5); - _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; + _3 = const std::ptr::Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; StorageDead(_4); - _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); + _2 = const Box::<[bool]>(std::ptr::Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); StorageDead(_3); - _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }}; + _1 = const A {{ foo: Box::<[bool]>(std::ptr::Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }}; StorageDead(_2); _0 = const (); drop(_1) -> [return: bb1, unwind: bb2]; diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff index 1f9cf6d6aca8..0205d0cc3d16 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff @@ -13,7 +13,7 @@ let mut _4: std::ptr::Unique<[bool; 0]>; scope 3 { } - scope 4 (inlined Unique::<[bool; 0]>::dangling) { + scope 4 (inlined std::ptr::Unique::<[bool; 0]>::dangling) { let mut _5: std::ptr::NonNull<[bool; 0]>; scope 5 (inlined NonNull::<[bool; 0]>::dangling) { let mut _6: std::num::NonZero; @@ -54,17 +54,17 @@ + _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}; StorageDead(_7); StorageDead(_6); -- _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> }; -+ _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; +- _4 = std::ptr::Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> }; ++ _4 = const std::ptr::Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; StorageDead(_5); - _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize, Implicit)); -+ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; ++ _3 = const std::ptr::Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; StorageDead(_4); - _2 = Box::<[bool]>(copy _3, const std::alloc::Global); -+ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); ++ _2 = const Box::<[bool]>(std::ptr::Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); StorageDead(_3); - _1 = A { foo: move _2 }; -+ _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }}; ++ _1 = const A {{ foo: Box::<[bool]>(std::ptr::Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }}; StorageDead(_2); _0 = const (); drop(_1) -> [return: bb1, unwind unreachable]; diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff index a8760285fac1..f6babe35b5a0 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff @@ -13,7 +13,7 @@ let mut _4: std::ptr::Unique<[bool; 0]>; scope 3 { } - scope 4 (inlined Unique::<[bool; 0]>::dangling) { + scope 4 (inlined std::ptr::Unique::<[bool; 0]>::dangling) { let mut _5: std::ptr::NonNull<[bool; 0]>; scope 5 (inlined NonNull::<[bool; 0]>::dangling) { let mut _6: std::num::NonZero; @@ -54,17 +54,17 @@ + _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}; StorageDead(_7); StorageDead(_6); -- _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> }; -+ _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; +- _4 = std::ptr::Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> }; ++ _4 = const std::ptr::Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; StorageDead(_5); - _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize, Implicit)); -+ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; ++ _3 = const std::ptr::Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; StorageDead(_4); - _2 = Box::<[bool]>(copy _3, const std::alloc::Global); -+ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); ++ _2 = const Box::<[bool]>(std::ptr::Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); StorageDead(_3); - _1 = A { foo: move _2 }; -+ _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }}; ++ _1 = const A {{ foo: Box::<[bool]>(std::ptr::Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }}; StorageDead(_2); _0 = const (); drop(_1) -> [return: bb1, unwind: bb2]; diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff index c398ae70a1a3..204e59415c6b 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff @@ -13,7 +13,7 @@ let mut _4: std::ptr::Unique<[bool; 0]>; scope 3 { } - scope 4 (inlined Unique::<[bool; 0]>::dangling) { + scope 4 (inlined std::ptr::Unique::<[bool; 0]>::dangling) { let mut _5: std::ptr::NonNull<[bool; 0]>; scope 5 (inlined NonNull::<[bool; 0]>::dangling) { let mut _6: std::num::NonZero; @@ -54,17 +54,17 @@ + _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}; StorageDead(_7); StorageDead(_6); -- _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> }; -+ _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; +- _4 = std::ptr::Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> }; ++ _4 = const std::ptr::Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; StorageDead(_5); - _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize, Implicit)); -+ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; ++ _3 = const std::ptr::Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; StorageDead(_4); - _2 = Box::<[bool]>(copy _3, const std::alloc::Global); -+ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); ++ _2 = const Box::<[bool]>(std::ptr::Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); StorageDead(_3); - _1 = A { foo: move _2 }; -+ _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }}; ++ _1 = const A {{ foo: Box::<[bool]>(std::ptr::Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }}; StorageDead(_2); _0 = const (); drop(_1) -> [return: bb1, unwind unreachable]; diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff index 02934c02587d..0cf3f43c0464 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff @@ -13,7 +13,7 @@ let mut _4: std::ptr::Unique<[bool; 0]>; scope 3 { } - scope 4 (inlined Unique::<[bool; 0]>::dangling) { + scope 4 (inlined std::ptr::Unique::<[bool; 0]>::dangling) { let mut _5: std::ptr::NonNull<[bool; 0]>; scope 5 (inlined NonNull::<[bool; 0]>::dangling) { let mut _6: std::num::NonZero; @@ -54,17 +54,17 @@ + _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}; StorageDead(_7); StorageDead(_6); -- _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> }; -+ _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; +- _4 = std::ptr::Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> }; ++ _4 = const std::ptr::Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; StorageDead(_5); - _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize, Implicit)); -+ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; ++ _3 = const std::ptr::Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; StorageDead(_4); - _2 = Box::<[bool]>(copy _3, const std::alloc::Global); -+ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); ++ _2 = const Box::<[bool]>(std::ptr::Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); StorageDead(_3); - _1 = A { foo: move _2 }; -+ _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }}; ++ _1 = const A {{ foo: Box::<[bool]>(std::ptr::Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }}; StorageDead(_2); _0 = const (); drop(_1) -> [return: bb1, unwind: bb2]; diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff index fa6c2e29e072..3bc5f8507590 100644 --- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff @@ -12,7 +12,7 @@ bb0: { StorageLive(_1); - _1 = const 1_usize as std::boxed::Box (Transmute); -+ _1 = const Box::(Unique:: {{ pointer: NonNull:: {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData:: }}, std::alloc::Global); ++ _1 = const Box::(std::ptr::Unique:: {{ pointer: NonNull:: {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData:: }}, std::alloc::Global); _2 = copy ((_1.0: std::ptr::Unique).0: std::ptr::NonNull) as *const Never (Transmute); unreachable; } diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff index fa6c2e29e072..3bc5f8507590 100644 --- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff @@ -12,7 +12,7 @@ bb0: { StorageLive(_1); - _1 = const 1_usize as std::boxed::Box (Transmute); -+ _1 = const Box::(Unique:: {{ pointer: NonNull:: {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData:: }}, std::alloc::Global); ++ _1 = const Box::(std::ptr::Unique:: {{ pointer: NonNull:: {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData:: }}, std::alloc::Global); _2 = copy ((_1.0: std::ptr::Unique).0: std::ptr::NonNull) as *const Never (Transmute); unreachable; } diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff index bcf0ad7c165f..2e428b778504 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff @@ -133,7 +133,7 @@ - _13 = copy _12 as *const () (PtrToPtr); + _13 = copy _25 as *const () (PtrToPtr); _14 = NonNull::<()> { pointer: copy _13 }; - _15 = Unique::<()> { pointer: copy _14, _marker: const PhantomData::<()> }; + _15 = std::ptr::Unique::<()> { pointer: copy _14, _marker: const PhantomData::<()> }; _3 = Box::<()>(move _15, const std::alloc::Global); - (*_13) = move _4; + (*_13) = const (); diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff index 1b75a2bcba8b..4531720ee501 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff @@ -133,7 +133,7 @@ - _13 = copy _12 as *const () (PtrToPtr); + _13 = copy _25 as *const () (PtrToPtr); _14 = NonNull::<()> { pointer: copy _13 }; - _15 = Unique::<()> { pointer: copy _14, _marker: const PhantomData::<()> }; + _15 = std::ptr::Unique::<()> { pointer: copy _14, _marker: const PhantomData::<()> }; _3 = Box::<()>(move _15, const std::alloc::Global); - (*_13) = move _4; + (*_13) = const (); diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff index 2b77aa380a0f..88c77832a4e1 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff @@ -56,8 +56,8 @@ } bb1: { -- _5 = MinusPlus; -+ _5 = const MinusPlus; +- _5 = core::num::flt2dec::Sign::MinusPlus; ++ _5 = const core::num::flt2dec::Sign::MinusPlus; goto -> bb3; } diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff index ba6d2f3e155c..8a6e7fd35ccd 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff @@ -56,8 +56,8 @@ } bb1: { -- _5 = MinusPlus; -+ _5 = const MinusPlus; +- _5 = core::num::flt2dec::Sign::MinusPlus; ++ _5 = const core::num::flt2dec::Sign::MinusPlus; goto -> bb3; } diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff index bf6d9d864d57..ce10f4bb247a 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff @@ -56,8 +56,8 @@ } bb1: { -- _5 = MinusPlus; -+ _5 = const MinusPlus; +- _5 = core::num::flt2dec::Sign::MinusPlus; ++ _5 = const core::num::flt2dec::Sign::MinusPlus; goto -> bb3; } diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff index 01c87fd5317a..b19f2438d022 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff @@ -56,8 +56,8 @@ } bb1: { -- _5 = MinusPlus; -+ _5 = const MinusPlus; +- _5 = core::num::flt2dec::Sign::MinusPlus; ++ _5 = const core::num::flt2dec::Sign::MinusPlus; goto -> bb3; } diff --git a/tests/mir-opt/gvn.slices.GVN.panic-abort.diff b/tests/mir-opt/gvn.slices.GVN.panic-abort.diff index b7872fc9952b..247ddc73ec36 100644 --- a/tests/mir-opt/gvn.slices.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.slices.GVN.panic-abort.diff @@ -210,9 +210,9 @@ _26 = &(*_27); StorageLive(_28); - _28 = Option::>::None; -- _22 = assert_failed::<*const u8, *const u8>(move _23, move _24, move _26, move _28) -> unwind unreachable; +- _22 = core::panicking::assert_failed::<*const u8, *const u8>(move _23, move _24, move _26, move _28) -> unwind unreachable; + _28 = const Option::>::None; -+ _22 = assert_failed::<*const u8, *const u8>(const core::panicking::AssertKind::Eq, move _24, move _26, const Option::>::None) -> unwind unreachable; ++ _22 = core::panicking::assert_failed::<*const u8, *const u8>(const core::panicking::AssertKind::Eq, move _24, move _26, const Option::>::None) -> unwind unreachable; } bb7: { @@ -313,9 +313,9 @@ _52 = &(*_53); StorageLive(_54); - _54 = Option::>::None; -- _48 = assert_failed::<*const u8, *const u8>(move _49, move _50, move _52, move _54) -> unwind unreachable; +- _48 = core::panicking::assert_failed::<*const u8, *const u8>(move _49, move _50, move _52, move _54) -> unwind unreachable; + _54 = const Option::>::None; -+ _48 = assert_failed::<*const u8, *const u8>(const core::panicking::AssertKind::Eq, move _50, move _52, const Option::>::None) -> unwind unreachable; ++ _48 = core::panicking::assert_failed::<*const u8, *const u8>(const core::panicking::AssertKind::Eq, move _50, move _52, const Option::>::None) -> unwind unreachable; } } diff --git a/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff b/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff index 37817b48c199..f15c16f1ce0f 100644 --- a/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff @@ -210,9 +210,9 @@ _26 = &(*_27); StorageLive(_28); - _28 = Option::>::None; -- _22 = assert_failed::<*const u8, *const u8>(move _23, move _24, move _26, move _28) -> unwind continue; +- _22 = core::panicking::assert_failed::<*const u8, *const u8>(move _23, move _24, move _26, move _28) -> unwind continue; + _28 = const Option::>::None; -+ _22 = assert_failed::<*const u8, *const u8>(const core::panicking::AssertKind::Eq, move _24, move _26, const Option::>::None) -> unwind continue; ++ _22 = core::panicking::assert_failed::<*const u8, *const u8>(const core::panicking::AssertKind::Eq, move _24, move _26, const Option::>::None) -> unwind continue; } bb7: { @@ -313,9 +313,9 @@ _52 = &(*_53); StorageLive(_54); - _54 = Option::>::None; -- _48 = assert_failed::<*const u8, *const u8>(move _49, move _50, move _52, move _54) -> unwind continue; +- _48 = core::panicking::assert_failed::<*const u8, *const u8>(move _49, move _50, move _52, move _54) -> unwind continue; + _54 = const Option::>::None; -+ _48 = assert_failed::<*const u8, *const u8>(const core::panicking::AssertKind::Eq, move _50, move _52, const Option::>::None) -> unwind continue; ++ _48 = core::panicking::assert_failed::<*const u8, *const u8>(const core::panicking::AssertKind::Eq, move _50, move _52, const Option::>::None) -> unwind continue; } } diff --git a/tests/mir-opt/gvn.wrap_unwrap.GVN.panic-abort.diff b/tests/mir-opt/gvn.wrap_unwrap.GVN.panic-abort.diff index 3bbfd3a891eb..c3eb5d9092be 100644 --- a/tests/mir-opt/gvn.wrap_unwrap.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.wrap_unwrap.GVN.panic-abort.diff @@ -32,7 +32,7 @@ bb2: { StorageLive(_6); - _6 = begin_panic::<&str>(const "explicit panic") -> unwind unreachable; + _6 = std::rt::begin_panic::<&str>(const "explicit panic") -> unwind unreachable; } bb3: { diff --git a/tests/mir-opt/gvn.wrap_unwrap.GVN.panic-unwind.diff b/tests/mir-opt/gvn.wrap_unwrap.GVN.panic-unwind.diff index 03464f43f81e..ea1878be8cf6 100644 --- a/tests/mir-opt/gvn.wrap_unwrap.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.wrap_unwrap.GVN.panic-unwind.diff @@ -32,7 +32,7 @@ bb2: { StorageLive(_6); - _6 = begin_panic::<&str>(const "explicit panic") -> unwind continue; + _6 = std::rt::begin_panic::<&str>(const "explicit panic") -> unwind continue; } bb3: { diff --git a/tests/mir-opt/inline/inline_diverging.g.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_diverging.g.Inline.panic-abort.diff index 423de59e5754..66b1bc29877a 100644 --- a/tests/mir-opt/inline/inline_diverging.g.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_diverging.g.Inline.panic-abort.diff @@ -36,7 +36,7 @@ StorageLive(_6); - _6 = panic() -> unwind unreachable; + StorageLive(_7); -+ _7 = begin_panic::<&str>(const "explicit panic") -> unwind unreachable; ++ _7 = std::rt::begin_panic::<&str>(const "explicit panic") -> unwind unreachable; } + } + diff --git a/tests/mir-opt/inline/inline_diverging.g.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_diverging.g.Inline.panic-unwind.diff index 3689744dcb04..68dd9530137d 100644 --- a/tests/mir-opt/inline/inline_diverging.g.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/inline_diverging.g.Inline.panic-unwind.diff @@ -36,7 +36,7 @@ StorageLive(_6); - _6 = panic() -> unwind continue; + StorageLive(_7); -+ _7 = begin_panic::<&str>(const "explicit panic") -> unwind continue; ++ _7 = std::rt::begin_panic::<&str>(const "explicit panic") -> unwind continue; } + } + diff --git a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff index 9509739413b7..a74309e16e88 100644 --- a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff @@ -20,13 +20,13 @@ + scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) { + scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::) { + let mut _11: std::ptr::NonNull; -+ scope 7 (inlined Unique::::cast::) { ++ scope 7 (inlined std::ptr::Unique::::cast::) { + scope 8 (inlined NonNull::::cast::) { + scope 9 (inlined NonNull::::as_ptr) { + } + } + } -+ scope 10 (inlined Unique::::as_non_null_ptr) { ++ scope 10 (inlined std::ptr::Unique::::as_non_null_ptr) { + } + } + scope 11 (inlined NonNull::::as_ptr) { diff --git a/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff index 3cf28f4b60af..6c9cf0cf623b 100644 --- a/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff @@ -57,13 +57,13 @@ scope 11 (inlined alloc::raw_vec::RawVecInner::ptr::) { scope 12 (inlined alloc::raw_vec::RawVecInner::non_null::) { let mut _34: std::ptr::NonNull; - scope 13 (inlined Unique::::cast::) { + scope 13 (inlined std::ptr::Unique::::cast::) { scope 14 (inlined NonNull::::cast::) { scope 15 (inlined NonNull::::as_ptr) { } } } - scope 16 (inlined Unique::::as_non_null_ptr) { + scope 16 (inlined std::ptr::Unique::::as_non_null_ptr) { } } scope 17 (inlined NonNull::::as_ptr) { @@ -115,13 +115,13 @@ scope 34 (inlined alloc::raw_vec::RawVecInner::ptr::) { scope 35 (inlined alloc::raw_vec::RawVecInner::non_null::) { let mut _46: std::ptr::NonNull; - scope 36 (inlined Unique::::cast::) { + scope 36 (inlined std::ptr::Unique::::cast::) { scope 37 (inlined NonNull::::cast::) { scope 38 (inlined NonNull::::as_ptr) { } } } - scope 39 (inlined Unique::::as_non_null_ptr) { + scope 39 (inlined std::ptr::Unique::::as_non_null_ptr) { } } scope 40 (inlined NonNull::::as_ptr) { diff --git a/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff index 2f0d83f92792..49cd68577a12 100644 --- a/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff @@ -57,13 +57,13 @@ scope 11 (inlined alloc::raw_vec::RawVecInner::ptr::) { scope 12 (inlined alloc::raw_vec::RawVecInner::non_null::) { let mut _34: std::ptr::NonNull; - scope 13 (inlined Unique::::cast::) { + scope 13 (inlined std::ptr::Unique::::cast::) { scope 14 (inlined NonNull::::cast::) { scope 15 (inlined NonNull::::as_ptr) { } } } - scope 16 (inlined Unique::::as_non_null_ptr) { + scope 16 (inlined std::ptr::Unique::::as_non_null_ptr) { } } scope 17 (inlined NonNull::::as_ptr) { @@ -115,13 +115,13 @@ scope 34 (inlined alloc::raw_vec::RawVecInner::ptr::) { scope 35 (inlined alloc::raw_vec::RawVecInner::non_null::) { let mut _46: std::ptr::NonNull; - scope 36 (inlined Unique::::cast::) { + scope 36 (inlined std::ptr::Unique::::cast::) { scope 37 (inlined NonNull::::cast::) { scope 38 (inlined NonNull::::as_ptr) { } } } - scope 39 (inlined Unique::::as_non_null_ptr) { + scope 39 (inlined std::ptr::Unique::::as_non_null_ptr) { } } scope 40 (inlined NonNull::::as_ptr) { diff --git a/tests/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-pre-optimizations.after.panic-abort.mir b/tests/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-pre-optimizations.after.panic-abort.mir index 6e5f6dc9ea89..7933a36c92c2 100644 --- a/tests/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-pre-optimizations.after.panic-abort.mir +++ b/tests/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-pre-optimizations.after.panic-abort.mir @@ -24,7 +24,7 @@ fn unwrap(_1: Option) -> T { bb2: { StorageLive(_4); - _4 = begin_panic::<&str>(const "explicit panic") -> unwind unreachable; + _4 = std::rt::begin_panic::<&str>(const "explicit panic") -> unwind unreachable; } bb3: { diff --git a/tests/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-pre-optimizations.after.panic-unwind.mir b/tests/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-pre-optimizations.after.panic-unwind.mir index 758aa45f2a2b..04176b82ccd5 100644 --- a/tests/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-pre-optimizations.after.panic-unwind.mir +++ b/tests/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-pre-optimizations.after.panic-unwind.mir @@ -24,7 +24,7 @@ fn unwrap(_1: Option) -> T { bb2: { StorageLive(_4); - _4 = begin_panic::<&str>(const "explicit panic") -> bb4; + _4 = std::rt::begin_panic::<&str>(const "explicit panic") -> bb4; } bb3: { diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir index 013361d1d2fb..9202814adec7 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir @@ -14,14 +14,14 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { scope 4 { scope 12 (inlined Layout::size) { } - scope 13 (inlined Unique::<[T]>::cast::) { + scope 13 (inlined std::ptr::Unique::<[T]>::cast::) { scope 14 (inlined NonNull::<[T]>::cast::) { scope 15 (inlined NonNull::<[T]>::as_ptr) { } } } - scope 16 (inlined as From>>::from) { - scope 17 (inlined Unique::::as_non_null_ptr) { + scope 16 (inlined as From>>::from) { + scope 17 (inlined std::ptr::Unique::::as_non_null_ptr) { } } scope 18 (inlined ::deallocate) { @@ -45,7 +45,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } } } - scope 5 (inlined Unique::<[T]>::as_ptr) { + scope 5 (inlined std::ptr::Unique::<[T]>::as_ptr) { scope 6 (inlined NonNull::<[T]>::as_ptr) { } } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir index 013361d1d2fb..9202814adec7 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir @@ -14,14 +14,14 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { scope 4 { scope 12 (inlined Layout::size) { } - scope 13 (inlined Unique::<[T]>::cast::) { + scope 13 (inlined std::ptr::Unique::<[T]>::cast::) { scope 14 (inlined NonNull::<[T]>::cast::) { scope 15 (inlined NonNull::<[T]>::as_ptr) { } } } - scope 16 (inlined as From>>::from) { - scope 17 (inlined Unique::::as_non_null_ptr) { + scope 16 (inlined as From>>::from) { + scope 17 (inlined std::ptr::Unique::::as_non_null_ptr) { } } scope 18 (inlined ::deallocate) { @@ -45,7 +45,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } } } - scope 5 (inlined Unique::<[T]>::as_ptr) { + scope 5 (inlined std::ptr::Unique::<[T]>::as_ptr) { scope 6 (inlined NonNull::<[T]>::as_ptr) { } } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir index 013361d1d2fb..9202814adec7 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir @@ -14,14 +14,14 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { scope 4 { scope 12 (inlined Layout::size) { } - scope 13 (inlined Unique::<[T]>::cast::) { + scope 13 (inlined std::ptr::Unique::<[T]>::cast::) { scope 14 (inlined NonNull::<[T]>::cast::) { scope 15 (inlined NonNull::<[T]>::as_ptr) { } } } - scope 16 (inlined as From>>::from) { - scope 17 (inlined Unique::::as_non_null_ptr) { + scope 16 (inlined as From>>::from) { + scope 17 (inlined std::ptr::Unique::::as_non_null_ptr) { } } scope 18 (inlined ::deallocate) { @@ -45,7 +45,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } } } - scope 5 (inlined Unique::<[T]>::as_ptr) { + scope 5 (inlined std::ptr::Unique::<[T]>::as_ptr) { scope 6 (inlined NonNull::<[T]>::as_ptr) { } } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir index 013361d1d2fb..9202814adec7 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir @@ -14,14 +14,14 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { scope 4 { scope 12 (inlined Layout::size) { } - scope 13 (inlined Unique::<[T]>::cast::) { + scope 13 (inlined std::ptr::Unique::<[T]>::cast::) { scope 14 (inlined NonNull::<[T]>::cast::) { scope 15 (inlined NonNull::<[T]>::as_ptr) { } } } - scope 16 (inlined as From>>::from) { - scope 17 (inlined Unique::::as_non_null_ptr) { + scope 16 (inlined as From>>::from) { + scope 17 (inlined std::ptr::Unique::::as_non_null_ptr) { } } scope 18 (inlined ::deallocate) { @@ -45,7 +45,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } } } - scope 5 (inlined Unique::<[T]>::as_ptr) { + scope 5 (inlined std::ptr::Unique::<[T]>::as_ptr) { scope 6 (inlined NonNull::<[T]>::as_ptr) { } } diff --git a/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir index 6ab4b7712306..c8b9ff1dbed9 100644 --- a/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir @@ -139,14 +139,14 @@ fn vec_move(_1: Vec) -> () { debug self => _31; scope 23 (inlined alloc::raw_vec::RawVecInner::non_null::) { let mut _5: std::ptr::NonNull; - scope 24 (inlined Unique::::cast::) { + scope 24 (inlined std::ptr::Unique::::cast::) { scope 25 (inlined NonNull::::cast::) { let mut _6: *const impl Sized; scope 26 (inlined NonNull::::as_ptr) { } } } - scope 27 (inlined Unique::::as_non_null_ptr) { + scope 27 (inlined std::ptr::Unique::::as_non_null_ptr) { } } } diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir index 8308ecbad716..730aedf4f1a3 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir @@ -16,13 +16,13 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) { scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::) { let mut _2: std::ptr::NonNull; - scope 7 (inlined Unique::::cast::) { + scope 7 (inlined std::ptr::Unique::::cast::) { scope 8 (inlined NonNull::::cast::) { scope 9 (inlined NonNull::::as_ptr) { } } } - scope 10 (inlined Unique::::as_non_null_ptr) { + scope 10 (inlined std::ptr::Unique::::as_non_null_ptr) { } } scope 11 (inlined NonNull::::as_ptr) { diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir index 8308ecbad716..730aedf4f1a3 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir @@ -16,13 +16,13 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) { scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::) { let mut _2: std::ptr::NonNull; - scope 7 (inlined Unique::::cast::) { + scope 7 (inlined std::ptr::Unique::::cast::) { scope 8 (inlined NonNull::::cast::) { scope 9 (inlined NonNull::::as_ptr) { } } } - scope 10 (inlined Unique::::as_non_null_ptr) { + scope 10 (inlined std::ptr::Unique::::as_non_null_ptr) { } } scope 11 (inlined NonNull::::as_ptr) { diff --git a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff index 7012cc5aa7f6..f9965a529ebc 100644 --- a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff @@ -152,7 +152,7 @@ StorageDead(_22); StorageDead(_21); StorageDead(_20); - _10 = _eprint(move _11) -> [return: bb6, unwind unreachable]; + _10 = std::io::_eprint(move _11) -> [return: bb6, unwind unreachable]; } bb6: { diff --git a/tests/ui/async-await/async-closures/def-path.stderr b/tests/ui/async-await/async-closures/def-path.stderr index a507fa697604..e140e9b94b30 100644 --- a/tests/ui/async-await/async-closures/def-path.stderr +++ b/tests/ui/async-await/async-closures/def-path.stderr @@ -5,11 +5,11 @@ LL | let x = async || {}; | -- the expected `async` closure body LL | LL | let () = x(); - | ^^ --- this expression has type `{static main::{closure#0}::{closure#0} upvar_tys=?14t resume_ty=ResumeTy yield_ty=() return_ty=()}` + | ^^ --- this expression has type `{static main::{closure#0}::{closure#0} upvar_tys=?14t resume_ty=std::future::ResumeTy yield_ty=() return_ty=()}` | | | expected `async` closure body, found `()` | - = note: expected `async` closure body `{static main::{closure#0}::{closure#0} upvar_tys=?14t resume_ty=ResumeTy yield_ty=() return_ty=()}` + = note: expected `async` closure body `{static main::{closure#0}::{closure#0} upvar_tys=?14t resume_ty=std::future::ResumeTy yield_ty=() return_ty=()}` found unit type `()` error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.stderr b/tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.stderr index af29eaa35cb6..aecd97ef7763 100644 --- a/tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.stderr +++ b/tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.stderr @@ -99,7 +99,7 @@ LL | #[derive(Debug, PartialEq, Eq, ConstParamTy)] | ^^ unsatisfied trait bound introduced in this `derive` macro = note: 1 redundant requirement hidden = note: required for `&'static Bar` to implement `Eq` -note: required by a bound in `AssertParamIsEq` +note: required by a bound in `std::cmp::AssertParamIsEq` --> $SRC_DIR/core/src/cmp.rs:LL:COL error[E0277]: the size for values of type `dyn Debug` cannot be known at compilation time diff --git a/tests/ui/consts/const-eval/format.rs b/tests/ui/consts/const-eval/format.rs index a8085a786e18..f25c7018f826 100644 --- a/tests/ui/consts/const-eval/format.rs +++ b/tests/ui/consts/const-eval/format.rs @@ -6,7 +6,7 @@ const fn failure() { const fn print() { println!("{:?}", 0); //~^ ERROR cannot call non-const formatting macro in constant functions - //~| ERROR cannot call non-const function `_print` in constant functions + //~| ERROR cannot call non-const function `std::io::_print` in constant functions } const fn format_args() { diff --git a/tests/ui/consts/const-eval/format.stderr b/tests/ui/consts/const-eval/format.stderr index ea191eb5c098..06bada8da011 100644 --- a/tests/ui/consts/const-eval/format.stderr +++ b/tests/ui/consts/const-eval/format.stderr @@ -15,7 +15,7 @@ LL | println!("{:?}", 0); = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0015]: cannot call non-const function `_print` in constant functions +error[E0015]: cannot call non-const function `std::io::_print` in constant functions --> $DIR/format.rs:7:5 | LL | println!("{:?}", 0); diff --git a/tests/ui/contracts/contract-captures-via-closure-noncopy.rs b/tests/ui/contracts/contract-captures-via-closure-noncopy.rs index c7aa72d2b0f6..5153a7b48dcd 100644 --- a/tests/ui/contracts/contract-captures-via-closure-noncopy.rs +++ b/tests/ui/contracts/contract-captures-via-closure-noncopy.rs @@ -13,7 +13,7 @@ struct Baz { #[core::contracts::ensures({let old = x; move |ret:&Baz| ret.baz == old.baz*2 })] // Relevant thing is this: ^^^^^^^^^^^ // because we are capturing state that is non-Copy. -//~^^^ ERROR trait bound `Baz: std::marker::Copy` is not satisfied +//~^^^ ERROR trait bound `Baz: Copy` is not satisfied fn doubler(x: Baz) -> Baz { Baz { baz: x.baz + 10 } } diff --git a/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr b/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr index 5f55faed80c8..20c220e98bcc 100644 --- a/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr +++ b/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `Baz: std::marker::Copy` is not satisfied in `{closure@$DIR/contract-captures-via-closure-noncopy.rs:13:42: 13:57}` +error[E0277]: the trait bound `Baz: Copy` is not satisfied in `{closure@$DIR/contract-captures-via-closure-noncopy.rs:13:42: 13:57}` --> $DIR/contract-captures-via-closure-noncopy.rs:13:1 | LL | #[core::contracts::ensures({let old = x; move |ret:&Baz| ret.baz == old.baz*2 })] @@ -9,7 +9,7 @@ LL | #[core::contracts::ensures({let old = x; move |ret:&Baz| ret.baz == old.baz | unsatisfied trait bound | required by a bound introduced by this call | - = help: within `{closure@$DIR/contract-captures-via-closure-noncopy.rs:13:42: 13:57}`, the trait `std::marker::Copy` is not implemented for `Baz` + = help: within `{closure@$DIR/contract-captures-via-closure-noncopy.rs:13:42: 13:57}`, the trait `Copy` is not implemented for `Baz` note: required because it's used within this closure --> $DIR/contract-captures-via-closure-noncopy.rs:13:42 | diff --git a/tests/ui/derives/derives-span-Eq-enum-struct-variant.stderr b/tests/ui/derives/derives-span-Eq-enum-struct-variant.stderr index e0cb3c1b43da..42dc8d46b575 100644 --- a/tests/ui/derives/derives-span-Eq-enum-struct-variant.stderr +++ b/tests/ui/derives/derives-span-Eq-enum-struct-variant.stderr @@ -7,7 +7,7 @@ LL | #[derive(Eq,PartialEq)] LL | x: Error | ^^^^^^^^ the trait `Eq` is not implemented for `Error` | -note: required by a bound in `AssertParamIsEq` +note: required by a bound in `std::cmp::AssertParamIsEq` --> $SRC_DIR/core/src/cmp.rs:LL:COL help: consider annotating `Error` with `#[derive(Eq)]` | diff --git a/tests/ui/derives/derives-span-Eq-enum.stderr b/tests/ui/derives/derives-span-Eq-enum.stderr index 2f09b9ea385f..ef1d9e3242ad 100644 --- a/tests/ui/derives/derives-span-Eq-enum.stderr +++ b/tests/ui/derives/derives-span-Eq-enum.stderr @@ -7,7 +7,7 @@ LL | #[derive(Eq,PartialEq)] LL | Error | ^^^^^ the trait `Eq` is not implemented for `Error` | -note: required by a bound in `AssertParamIsEq` +note: required by a bound in `std::cmp::AssertParamIsEq` --> $SRC_DIR/core/src/cmp.rs:LL:COL help: consider annotating `Error` with `#[derive(Eq)]` | diff --git a/tests/ui/derives/derives-span-Eq-struct.stderr b/tests/ui/derives/derives-span-Eq-struct.stderr index c16d9118e10f..bae7bb0361df 100644 --- a/tests/ui/derives/derives-span-Eq-struct.stderr +++ b/tests/ui/derives/derives-span-Eq-struct.stderr @@ -7,7 +7,7 @@ LL | struct Struct { LL | x: Error | ^^^^^^^^ the trait `Eq` is not implemented for `Error` | -note: required by a bound in `AssertParamIsEq` +note: required by a bound in `std::cmp::AssertParamIsEq` --> $SRC_DIR/core/src/cmp.rs:LL:COL help: consider annotating `Error` with `#[derive(Eq)]` | diff --git a/tests/ui/derives/derives-span-Eq-tuple-struct.stderr b/tests/ui/derives/derives-span-Eq-tuple-struct.stderr index dac295eed919..13396cb27246 100644 --- a/tests/ui/derives/derives-span-Eq-tuple-struct.stderr +++ b/tests/ui/derives/derives-span-Eq-tuple-struct.stderr @@ -7,7 +7,7 @@ LL | struct Struct( LL | Error | ^^^^^ the trait `Eq` is not implemented for `Error` | -note: required by a bound in `AssertParamIsEq` +note: required by a bound in `std::cmp::AssertParamIsEq` --> $SRC_DIR/core/src/cmp.rs:LL:COL help: consider annotating `Error` with `#[derive(Eq)]` | diff --git a/tests/ui/deriving/issue-103157.stderr b/tests/ui/deriving/issue-103157.stderr index 51d4d0a89745..0e4a3f75db3f 100644 --- a/tests/ui/deriving/issue-103157.stderr +++ b/tests/ui/deriving/issue-103157.stderr @@ -18,7 +18,7 @@ LL | Float(Option), u16 and 4 others = note: required for `Option` to implement `Eq` -note: required by a bound in `AssertParamIsEq` +note: required by a bound in `std::cmp::AssertParamIsEq` --> $SRC_DIR/core/src/cmp.rs:LL:COL error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-27340.stderr b/tests/ui/issues/issue-27340.stderr index d5ff29a618b0..7cde901ffd95 100644 --- a/tests/ui/issues/issue-27340.stderr +++ b/tests/ui/issues/issue-27340.stderr @@ -16,7 +16,7 @@ LL | LL | struct Bar(Foo); | ^^^ the trait `Clone` is not implemented for `Foo` | -note: required by a bound in `AssertParamIsClone` +note: required by a bound in `std::clone::AssertParamIsClone` --> $SRC_DIR/core/src/clone.rs:LL:COL help: consider annotating `Foo` with `#[derive(Clone)]` | diff --git a/tests/ui/kindck/kindck-send-object.stderr b/tests/ui/kindck/kindck-send-object.stderr index 0e2ff1730c8d..b71d4029350e 100644 --- a/tests/ui/kindck/kindck-send-object.stderr +++ b/tests/ui/kindck/kindck-send-object.stderr @@ -19,7 +19,7 @@ LL | assert_send::>(); | ^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely | = help: the trait `Send` is not implemented for `dyn Dummy` - = note: required for `Unique` to implement `Send` + = note: required for `std::ptr::Unique` to implement `Send` note: required because it appears within the type `Box` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL note: required by a bound in `assert_send` diff --git a/tests/ui/kindck/kindck-send-object1.stderr b/tests/ui/kindck/kindck-send-object1.stderr index e3ff2eb9ff4c..2184ae704673 100644 --- a/tests/ui/kindck/kindck-send-object1.stderr +++ b/tests/ui/kindck/kindck-send-object1.stderr @@ -19,7 +19,7 @@ LL | assert_send::>(); | ^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be sent between threads safely | = help: the trait `Send` is not implemented for `(dyn Dummy + 'a)` - = note: required for `Unique<(dyn Dummy + 'a)>` to implement `Send` + = note: required for `std::ptr::Unique<(dyn Dummy + 'a)>` to implement `Send` note: required because it appears within the type `Box<(dyn Dummy + 'a)>` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL note: required by a bound in `assert_send` diff --git a/tests/ui/kindck/kindck-send-object2.stderr b/tests/ui/kindck/kindck-send-object2.stderr index 8898bf5b3fab..52a7055b4229 100644 --- a/tests/ui/kindck/kindck-send-object2.stderr +++ b/tests/ui/kindck/kindck-send-object2.stderr @@ -19,7 +19,7 @@ LL | assert_send::>(); | ^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely | = help: the trait `Send` is not implemented for `dyn Dummy` - = note: required for `Unique` to implement `Send` + = note: required for `std::ptr::Unique` to implement `Send` note: required because it appears within the type `Box` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL note: required by a bound in `assert_send` diff --git a/tests/ui/kindck/kindck-send-owned.stderr b/tests/ui/kindck/kindck-send-owned.stderr index 860a9391bbb0..c433d80cf140 100644 --- a/tests/ui/kindck/kindck-send-owned.stderr +++ b/tests/ui/kindck/kindck-send-owned.stderr @@ -5,7 +5,7 @@ LL | assert_send::>(); | ^^^^^^^^^^^^ `*mut u8` cannot be sent between threads safely | = help: the trait `Send` is not implemented for `*mut u8` - = note: required for `Unique<*mut u8>` to implement `Send` + = note: required for `std::ptr::Unique<*mut u8>` to implement `Send` note: required because it appears within the type `Box<*mut u8>` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL note: required by a bound in `assert_send` diff --git a/tests/ui/limits/type-length-limit-enforcement.stderr b/tests/ui/limits/type-length-limit-enforcement.stderr index bfea0b5a4482..82855bd75528 100644 --- a/tests/ui/limits/type-length-limit-enforcement.stderr +++ b/tests/ui/limits/type-length-limit-enforcement.stderr @@ -8,9 +8,11 @@ LL | drop::>(None); = note: the full name for the type has been written to '$TEST_BUILD_DIR/type-length-limit-enforcement.long-type-$LONG_TYPE_HASH.txt' = note: consider using `--verbose` to print the full type name to the console -error: reached the type-length limit while instantiating `<{closure@rt::lang_start<()>::{closure#0}} as FnMut<()>>::call_mut` +error: reached the type-length limit while instantiating `<{closure@...} as FnMut<()>>::call_mut` | = help: consider adding a `#![type_length_limit="10"]` attribute to your crate + = note: the full name for the type has been written to '$TEST_BUILD_DIR/type-length-limit-enforcement.long-type-$LONG_TYPE_HASH.txt' + = note: consider using `--verbose` to print the full type name to the console error: aborting due to 2 previous errors diff --git a/tests/ui/proc-macro/bad-projection.stderr b/tests/ui/proc-macro/bad-projection.stderr index f2981499367b..5b472d407044 100644 --- a/tests/ui/proc-macro/bad-projection.stderr +++ b/tests/ui/proc-macro/bad-projection.stderr @@ -33,7 +33,7 @@ LL | pub fn uwu() -> <() as Project>::Assoc {} | takes 0 arguments | required by a bound introduced by this call | -note: required by a bound in `ProcMacro::bang` +note: required by a bound in `proc_macro::bridge::client::ProcMacro::bang` --> $SRC_DIR/proc_macro/src/bridge/client.rs:LL:COL error[E0277]: the trait bound `(): Project` is not satisfied diff --git a/tests/ui/proc-macro/proc-macro-abi.stderr b/tests/ui/proc-macro/proc-macro-abi.stderr index ccc72e5187ed..ccefdbfa3a86 100644 --- a/tests/ui/proc-macro/proc-macro-abi.stderr +++ b/tests/ui/proc-macro/proc-macro-abi.stderr @@ -4,8 +4,8 @@ error: function-like proc macro has incorrect signature LL | pub extern "C" fn abi(a: TokenStream) -> TokenStream { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected "Rust" fn, found "C" fn | - = note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream` - found signature `extern "C" fn(proc_macro::TokenStream) -> proc_macro::TokenStream` + = note: expected signature `fn(TokenStream) -> TokenStream` + found signature `extern "C" fn(TokenStream) -> TokenStream` error: function-like proc macro has incorrect signature --> $DIR/proc-macro-abi.rs:17:1 @@ -13,8 +13,8 @@ error: function-like proc macro has incorrect signature LL | pub extern "system" fn abi2(a: TokenStream) -> TokenStream { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected "Rust" fn, found "system" fn | - = note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream` - found signature `extern "system" fn(proc_macro::TokenStream) -> proc_macro::TokenStream` + = note: expected signature `fn(TokenStream) -> TokenStream` + found signature `extern "system" fn(TokenStream) -> TokenStream` error: function-like proc macro has incorrect signature --> $DIR/proc-macro-abi.rs:23:1 @@ -22,8 +22,8 @@ error: function-like proc macro has incorrect signature LL | pub extern fn abi3(a: TokenStream) -> TokenStream { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected "Rust" fn, found "C" fn | - = note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream` - found signature `extern "C" fn(proc_macro::TokenStream) -> proc_macro::TokenStream` + = note: expected signature `fn(TokenStream) -> TokenStream` + found signature `extern "C" fn(TokenStream) -> TokenStream` error: aborting due to 3 previous errors diff --git a/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.stderr b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.stderr index 0bcea9b85f47..86a00713a456 100644 --- a/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.stderr +++ b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.stderr @@ -5,7 +5,7 @@ LL | quote!($($nonrep $nonrep)*); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | expected `HasIterator`, found `ThereIsNoIteratorInRepetition` - | here the type of `has_iter` is inferred to be `ThereIsNoIteratorInRepetition` + | here the type of `has_iter` is inferred to be `proc_macro::ThereIsNoIteratorInRepetition` error: aborting due to 1 previous error diff --git a/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.stderr b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.stderr index d945ab41a12e..325e50f9796a 100644 --- a/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.stderr +++ b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.stderr @@ -5,7 +5,7 @@ LL | quote!($($nonrep)*); | ^^^^^^^^^^^^^^^^^^^ | | | expected `HasIterator`, found `ThereIsNoIteratorInRepetition` - | here the type of `has_iter` is inferred to be `ThereIsNoIteratorInRepetition` + | here the type of `has_iter` is inferred to be `proc_macro::ThereIsNoIteratorInRepetition` error: aborting due to 1 previous error diff --git a/tests/ui/proc-macro/quote/not-quotable.stderr b/tests/ui/proc-macro/quote/not-quotable.stderr index b00d029946d6..4177d9c672b5 100644 --- a/tests/ui/proc-macro/quote/not-quotable.stderr +++ b/tests/ui/proc-macro/quote/not-quotable.stderr @@ -11,11 +11,11 @@ LL | let _ = quote! { $ip }; &T &mut T Box + CStr CString Cow<'_, T> Option Rc - bool and 24 others error: aborting due to 1 previous error diff --git a/tests/ui/proc-macro/signature-proc-macro-attribute.stderr b/tests/ui/proc-macro/signature-proc-macro-attribute.stderr index ce832eaa5c7a..9dfb081a10e6 100644 --- a/tests/ui/proc-macro/signature-proc-macro-attribute.stderr +++ b/tests/ui/proc-macro/signature-proc-macro-attribute.stderr @@ -4,8 +4,8 @@ error: attribute proc macro has incorrect signature LL | pub fn bad_input(input: String) -> TokenStream { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters | - = note: expected signature `fn(proc_macro::TokenStream, proc_macro::TokenStream) -> proc_macro::TokenStream` - found signature `fn(std::string::String) -> proc_macro::TokenStream` + = note: expected signature `fn(TokenStream, TokenStream) -> TokenStream` + found signature `fn(String) -> TokenStream` error: attribute proc macro has incorrect signature --> $DIR/signature-proc-macro-attribute.rs:16:1 @@ -13,8 +13,8 @@ error: attribute proc macro has incorrect signature LL | pub fn bad_output(input: TokenStream) -> String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters | - = note: expected signature `fn(proc_macro::TokenStream, proc_macro::TokenStream) -> proc_macro::TokenStream` - found signature `fn(proc_macro::TokenStream) -> std::string::String` + = note: expected signature `fn(TokenStream, TokenStream) -> TokenStream` + found signature `fn(TokenStream) -> String` error: attribute proc macro has incorrect signature --> $DIR/signature-proc-macro-attribute.rs:22:1 @@ -22,8 +22,8 @@ error: attribute proc macro has incorrect signature LL | pub fn bad_everything(input: String) -> String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters | - = note: expected signature `fn(proc_macro::TokenStream, proc_macro::TokenStream) -> proc_macro::TokenStream` - found signature `fn(std::string::String) -> std::string::String` + = note: expected signature `fn(TokenStream, TokenStream) -> TokenStream` + found signature `fn(String) -> String` error: attribute proc macro has incorrect signature --> $DIR/signature-proc-macro-attribute.rs:28:52 @@ -31,8 +31,8 @@ error: attribute proc macro has incorrect signature LL | pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream { | ^^^^^^ incorrect number of function parameters | - = note: expected signature `fn(proc_macro::TokenStream, proc_macro::TokenStream) -> proc_macro::TokenStream` - found signature `fn(proc_macro::TokenStream, proc_macro::TokenStream, std::string::String) -> proc_macro::TokenStream` + = note: expected signature `fn(TokenStream, TokenStream) -> TokenStream` + found signature `fn(TokenStream, TokenStream, String) -> TokenStream` error: aborting due to 4 previous errors diff --git a/tests/ui/proc-macro/signature-proc-macro-derive.stderr b/tests/ui/proc-macro/signature-proc-macro-derive.stderr index 03c6abad17d9..3539ae7c2e17 100644 --- a/tests/ui/proc-macro/signature-proc-macro-derive.stderr +++ b/tests/ui/proc-macro/signature-proc-macro-derive.stderr @@ -2,28 +2,28 @@ error: derive proc macro has incorrect signature --> $DIR/signature-proc-macro-derive.rs:10:25 | LL | pub fn bad_input(input: String) -> TokenStream { - | ^^^^^^ expected `proc_macro::TokenStream`, found `std::string::String` + | ^^^^^^ expected `TokenStream`, found `String` | - = note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream` - found signature `fn(std::string::String) -> proc_macro::TokenStream` + = note: expected signature `fn(TokenStream) -> TokenStream` + found signature `fn(String) -> TokenStream` error: derive proc macro has incorrect signature --> $DIR/signature-proc-macro-derive.rs:16:42 | LL | pub fn bad_output(input: TokenStream) -> String { - | ^^^^^^ expected `proc_macro::TokenStream`, found `std::string::String` + | ^^^^^^ expected `TokenStream`, found `String` | - = note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream` - found signature `fn(proc_macro::TokenStream) -> std::string::String` + = note: expected signature `fn(TokenStream) -> TokenStream` + found signature `fn(TokenStream) -> String` error: derive proc macro has incorrect signature --> $DIR/signature-proc-macro-derive.rs:22:30 | LL | pub fn bad_everything(input: String) -> String { - | ^^^^^^ expected `proc_macro::TokenStream`, found `std::string::String` + | ^^^^^^ expected `TokenStream`, found `String` | - = note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream` - found signature `fn(std::string::String) -> std::string::String` + = note: expected signature `fn(TokenStream) -> TokenStream` + found signature `fn(String) -> String` error: derive proc macro has incorrect signature --> $DIR/signature-proc-macro-derive.rs:28:36 @@ -31,8 +31,8 @@ error: derive proc macro has incorrect signature LL | pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream { | ^^^^^^^^^^^ incorrect number of function parameters | - = note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream` - found signature `fn(proc_macro::TokenStream, proc_macro::TokenStream, std::string::String) -> proc_macro::TokenStream` + = note: expected signature `fn(TokenStream) -> TokenStream` + found signature `fn(TokenStream, TokenStream, String) -> TokenStream` error: aborting due to 4 previous errors diff --git a/tests/ui/proc-macro/signature-proc-macro.stderr b/tests/ui/proc-macro/signature-proc-macro.stderr index dd2cb0570daa..1959d8c6d615 100644 --- a/tests/ui/proc-macro/signature-proc-macro.stderr +++ b/tests/ui/proc-macro/signature-proc-macro.stderr @@ -2,28 +2,28 @@ error: function-like proc macro has incorrect signature --> $DIR/signature-proc-macro.rs:10:25 | LL | pub fn bad_input(input: String) -> TokenStream { - | ^^^^^^ expected `proc_macro::TokenStream`, found `std::string::String` + | ^^^^^^ expected `TokenStream`, found `String` | - = note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream` - found signature `fn(std::string::String) -> proc_macro::TokenStream` + = note: expected signature `fn(TokenStream) -> TokenStream` + found signature `fn(String) -> TokenStream` error: function-like proc macro has incorrect signature --> $DIR/signature-proc-macro.rs:16:42 | LL | pub fn bad_output(input: TokenStream) -> String { - | ^^^^^^ expected `proc_macro::TokenStream`, found `std::string::String` + | ^^^^^^ expected `TokenStream`, found `String` | - = note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream` - found signature `fn(proc_macro::TokenStream) -> std::string::String` + = note: expected signature `fn(TokenStream) -> TokenStream` + found signature `fn(TokenStream) -> String` error: function-like proc macro has incorrect signature --> $DIR/signature-proc-macro.rs:22:30 | LL | pub fn bad_everything(input: String) -> String { - | ^^^^^^ expected `proc_macro::TokenStream`, found `std::string::String` + | ^^^^^^ expected `TokenStream`, found `String` | - = note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream` - found signature `fn(std::string::String) -> std::string::String` + = note: expected signature `fn(TokenStream) -> TokenStream` + found signature `fn(String) -> String` error: function-like proc macro has incorrect signature --> $DIR/signature-proc-macro.rs:28:36 @@ -31,8 +31,8 @@ error: function-like proc macro has incorrect signature LL | pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream { | ^^^^^^^^^^^ incorrect number of function parameters | - = note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream` - found signature `fn(proc_macro::TokenStream, proc_macro::TokenStream, std::string::String) -> proc_macro::TokenStream` + = note: expected signature `fn(TokenStream) -> TokenStream` + found signature `fn(TokenStream, TokenStream, String) -> TokenStream` error: aborting due to 4 previous errors diff --git a/tests/ui/proc-macro/signature.stderr b/tests/ui/proc-macro/signature.stderr index fd679442b6af..2c1973eb6e6d 100644 --- a/tests/ui/proc-macro/signature.stderr +++ b/tests/ui/proc-macro/signature.stderr @@ -4,7 +4,7 @@ error: derive proc macro has incorrect signature LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected safe fn, found unsafe fn | - = note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream` + = note: expected signature `fn(TokenStream) -> TokenStream` found signature `unsafe extern "C" fn(i32, u32) -> u32` error: aborting due to 1 previous error diff --git a/tests/ui/static/global-variable-promotion-error-7364.stderr b/tests/ui/static/global-variable-promotion-error-7364.stderr index b9d75676bef8..9f0026621c13 100644 --- a/tests/ui/static/global-variable-promotion-error-7364.stderr +++ b/tests/ui/static/global-variable-promotion-error-7364.stderr @@ -6,7 +6,7 @@ LL | static boxed: Box> = Box::new(RefCell::new(0)); | = help: the trait `Sync` is not implemented for `RefCell` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead - = note: required for `Unique>` to implement `Sync` + = note: required for `std::ptr::Unique>` to implement `Sync` note: required because it appears within the type `Box>` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL = note: shared static variables must have a type that implements `Sync` diff --git a/tests/ui/traits/const-traits/issue-79450.rs b/tests/ui/traits/const-traits/issue-79450.rs index e74da811fc80..c6234f8616d7 100644 --- a/tests/ui/traits/const-traits/issue-79450.rs +++ b/tests/ui/traits/const-traits/issue-79450.rs @@ -5,7 +5,7 @@ const trait Tr { fn req(&self); fn prov(&self) { - println!("lul"); //~ ERROR: cannot call non-const function `_print` in constant functions + println!("lul"); //~ ERROR: cannot call non-const function `std::io::_print` in constant functions self.req(); } } diff --git a/tests/ui/traits/const-traits/issue-79450.stderr b/tests/ui/traits/const-traits/issue-79450.stderr index c10023e9f0ef..702e93a76a8f 100644 --- a/tests/ui/traits/const-traits/issue-79450.stderr +++ b/tests/ui/traits/const-traits/issue-79450.stderr @@ -1,4 +1,4 @@ -error[E0015]: cannot call non-const function `_print` in constant functions +error[E0015]: cannot call non-const function `std::io::_print` in constant functions --> $DIR/issue-79450.rs:8:9 | LL | println!("lul"); diff --git a/tests/ui/traits/cycle-cache-err-60010.stderr b/tests/ui/traits/cycle-cache-err-60010.stderr index 4f5e31818321..9665d5badf59 100644 --- a/tests/ui/traits/cycle-cache-err-60010.stderr +++ b/tests/ui/traits/cycle-cache-err-60010.stderr @@ -6,7 +6,7 @@ LL | _parse: >::Data, | note: required because it appears within the type `PhantomData` --> $SRC_DIR/core/src/marker.rs:LL:COL -note: required because it appears within the type `Unique` +note: required because it appears within the type `std::ptr::Unique` --> $SRC_DIR/core/src/ptr/unique.rs:LL:COL note: required because it appears within the type `Box` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL @@ -45,7 +45,7 @@ LL | type Storage = SalsaStorage; | note: required because it appears within the type `PhantomData` --> $SRC_DIR/core/src/marker.rs:LL:COL -note: required because it appears within the type `Unique` +note: required because it appears within the type `std::ptr::Unique` --> $SRC_DIR/core/src/ptr/unique.rs:LL:COL note: required because it appears within the type `Box` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL diff --git a/tests/ui/traits/negative-impls/negated-auto-traits-error.stderr b/tests/ui/traits/negative-impls/negated-auto-traits-error.stderr index f450f786f608..b7d8484e1041 100644 --- a/tests/ui/traits/negative-impls/negated-auto-traits-error.stderr +++ b/tests/ui/traits/negative-impls/negated-auto-traits-error.stderr @@ -77,12 +77,12 @@ error[E0277]: `dummy2::TestType` cannot be sent between threads safely --> $DIR/negated-auto-traits-error.rs:48:13 | LL | is_send(Box::new(TestType)); - | ------- ^^^^^^^^^^^^^^^^^^ the trait `Send` is not implemented for `Unique` + | ------- ^^^^^^^^^^^^^^^^^^ the trait `Send` is not implemented for `std::ptr::Unique` | | | required by a bound introduced by this call | - = note: the trait bound `Unique: Send` is not satisfied - = note: required for `Unique` to implement `Send` + = note: the trait bound `std::ptr::Unique: Send` is not satisfied + = note: required for `std::ptr::Unique` to implement `Send` note: required because it appears within the type `Box` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL note: required by a bound in `is_send` @@ -113,7 +113,7 @@ note: required because it appears within the type `Outer2` | LL | struct Outer2(T); | ^^^^^^ - = note: required for `Unique>` to implement `Send` + = note: required for `std::ptr::Unique>` to implement `Send` note: required because it appears within the type `Box>` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL note: required by a bound in `is_send` diff --git a/tests/ui/trimmed-paths/core-unicode.rs b/tests/ui/trimmed-paths/core-unicode.rs index 54bde92a5335..4a3eeca62970 100644 --- a/tests/ui/trimmed-paths/core-unicode.rs +++ b/tests/ui/trimmed-paths/core-unicode.rs @@ -14,6 +14,6 @@ fn main() { let PhantomData::<(inner::unicode, u32)> = PhantomData::<(u32, inner::unicode)>; //~^ ERROR mismatched types [E0308] //~| NOTE expected `PhantomData<(u32, unicode)>`, found `PhantomData<(unicode, u32)>` - //~| NOTE this expression has type `PhantomData<(u32, inner::unicode)>` - //~| NOTE expected struct `PhantomData<(u32, inner::unicode)>` + //~| NOTE this expression has type `PhantomData<(u32, unicode)>` + //~| NOTE expected struct `PhantomData<(u32, unicode)>` } diff --git a/tests/ui/trimmed-paths/core-unicode.stderr b/tests/ui/trimmed-paths/core-unicode.stderr index 9023200d1c92..7351896b0b54 100644 --- a/tests/ui/trimmed-paths/core-unicode.stderr +++ b/tests/ui/trimmed-paths/core-unicode.stderr @@ -2,12 +2,12 @@ error[E0308]: mismatched types --> $DIR/core-unicode.rs:14:9 | LL | let PhantomData::<(inner::unicode, u32)> = PhantomData::<(u32, inner::unicode)>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------------------------ this expression has type `PhantomData<(u32, inner::unicode)>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------------------------ this expression has type `PhantomData<(u32, unicode)>` | | | expected `PhantomData<(u32, unicode)>`, found `PhantomData<(unicode, u32)>` | - = note: expected struct `PhantomData<(u32, inner::unicode)>` - found struct `PhantomData<(inner::unicode, u32)>` + = note: expected struct `PhantomData<(u32, unicode)>` + found struct `PhantomData<(unicode, u32)>` error: aborting due to 1 previous error diff --git a/tests/ui/trimmed-paths/doc-hidden.rs b/tests/ui/trimmed-paths/doc-hidden.rs index b73d04c3c6ae..c3125385c7e4 100644 --- a/tests/ui/trimmed-paths/doc-hidden.rs +++ b/tests/ui/trimmed-paths/doc-hidden.rs @@ -45,7 +45,7 @@ fn uses_local() { ) = 3u32; //~^ ERROR mismatched types [E0308] //~| NOTE expected `(ActuallyPub, ..., ..., ..., ..., ...)`, found `u32` - //~| NOTE expected tuple `(local::ActuallyPub, local::DocHidden, local::pub_mod::ActuallyPubInPubMod, local::pub_mod::DocHiddenInPubMod, local::hidden_mod::ActuallyPubInHiddenMod, local::hidden_mod::DocHiddenInHiddenMod)` + //~| NOTE expected tuple `(local::ActuallyPub, DocHidden, local::pub_mod::ActuallyPubInPubMod, DocHiddenInPubMod, ActuallyPubInHiddenMod, DocHiddenInHiddenMod)` } fn uses_helper() { diff --git a/tests/ui/trimmed-paths/doc-hidden.stderr b/tests/ui/trimmed-paths/doc-hidden.stderr index 6f6f8f21fbe0..167c92c50a35 100644 --- a/tests/ui/trimmed-paths/doc-hidden.stderr +++ b/tests/ui/trimmed-paths/doc-hidden.stderr @@ -13,7 +13,7 @@ LL | | ) = 3u32; | |_____| | expected due to this | - = note: expected tuple `(local::ActuallyPub, local::DocHidden, local::pub_mod::ActuallyPubInPubMod, local::pub_mod::DocHiddenInPubMod, local::hidden_mod::ActuallyPubInHiddenMod, local::hidden_mod::DocHiddenInHiddenMod)` + = note: expected tuple `(local::ActuallyPub, DocHidden, local::pub_mod::ActuallyPubInPubMod, DocHiddenInPubMod, ActuallyPubInHiddenMod, DocHiddenInHiddenMod)` found type `u32` error[E0308]: mismatched types diff --git a/tests/ui/type-inference/panic-with-unspecified-type.stderr b/tests/ui/type-inference/panic-with-unspecified-type.stderr index 5f08a7552632..cd8485f392bc 100644 --- a/tests/ui/type-inference/panic-with-unspecified-type.stderr +++ b/tests/ui/type-inference/panic-with-unspecified-type.stderr @@ -8,7 +8,7 @@ LL | panic!(std::default::Default::default()); | required by a bound introduced by this call | = note: cannot satisfy `_: Any` -note: required by a bound in `begin_panic` +note: required by a bound in `std::rt::begin_panic` --> $SRC_DIR/std/src/panicking.rs:LL:COL error: aborting due to 1 previous error diff --git a/tests/ui/type/pattern_types/derives_fail.stderr b/tests/ui/type/pattern_types/derives_fail.stderr index 6b2e27494f0e..45c9bae1f280 100644 --- a/tests/ui/type/pattern_types/derives_fail.stderr +++ b/tests/ui/type/pattern_types/derives_fail.stderr @@ -16,7 +16,7 @@ LL | #[repr(transparent)] LL | struct Nanoseconds(NanoI32); | ^^^^^^^ the trait `Eq` is not implemented for `(i32) is 0..=999999999` | -note: required by a bound in `AssertParamIsEq` +note: required by a bound in `std::cmp::AssertParamIsEq` --> $SRC_DIR/core/src/cmp.rs:LL:COL error[E0277]: `(i32) is 0..=999999999` doesn't implement `Debug` diff --git a/tests/ui/union/union-derive-clone.stderr b/tests/ui/union/union-derive-clone.stderr index 679ab6a38e49..18f862aaa7d6 100644 --- a/tests/ui/union/union-derive-clone.stderr +++ b/tests/ui/union/union-derive-clone.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `U1: Copy` is not satisfied LL | #[derive(Clone)] | ^^^^^ the trait `Copy` is not implemented for `U1` | -note: required by a bound in `AssertParamIsCopy` +note: required by a bound in `std::clone::AssertParamIsCopy` --> $SRC_DIR/core/src/clone.rs:LL:COL help: consider annotating `U1` with `#[derive(Copy)]` | diff --git a/tests/ui/union/union-derive-eq.current.stderr b/tests/ui/union/union-derive-eq.current.stderr index a0339687dad4..df8e6db887bc 100644 --- a/tests/ui/union/union-derive-eq.current.stderr +++ b/tests/ui/union/union-derive-eq.current.stderr @@ -7,7 +7,7 @@ LL | union U2 { LL | a: PartialEqNotEq, | ^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `PartialEqNotEq` | -note: required by a bound in `AssertParamIsEq` +note: required by a bound in `std::cmp::AssertParamIsEq` --> $SRC_DIR/core/src/cmp.rs:LL:COL help: consider annotating `PartialEqNotEq` with `#[derive(Eq)]` | diff --git a/tests/ui/union/union-derive-eq.next.stderr b/tests/ui/union/union-derive-eq.next.stderr index a0339687dad4..df8e6db887bc 100644 --- a/tests/ui/union/union-derive-eq.next.stderr +++ b/tests/ui/union/union-derive-eq.next.stderr @@ -7,7 +7,7 @@ LL | union U2 { LL | a: PartialEqNotEq, | ^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `PartialEqNotEq` | -note: required by a bound in `AssertParamIsEq` +note: required by a bound in `std::cmp::AssertParamIsEq` --> $SRC_DIR/core/src/cmp.rs:LL:COL help: consider annotating `PartialEqNotEq` with `#[derive(Eq)]` | From 40691d0ca6a20bae367533fb2b58320251b4ad17 Mon Sep 17 00:00:00 2001 From: tiif Date: Mon, 19 Jan 2026 01:46:08 +0000 Subject: [PATCH 0844/1061] Add myself to the review rotation --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index e51622f1e5a9..a25c2a0a388c 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1465,6 +1465,7 @@ compiler = [ "@oli-obk", "@petrochenkov", "@SparrowLii", + "@tiif", "@WaffleLapkin", "@wesleywiser", ] From 37135122179974e9073f4a885b70044cedfa3f80 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Sat, 17 Jan 2026 22:53:08 +0800 Subject: [PATCH 0845/1061] Parse ident with allowing recovery when trying to recover in diagnosing --- .../rustc_parse/src/parser/diagnostics.rs | 2 +- compiler/rustc_parse/src/parser/item.rs | 3 +- compiler/rustc_parse/src/parser/mod.rs | 2 +- .../kw-in-const-item-pos-recovery-149692.rs | 3 +- ...w-in-const-item-pos-recovery-149692.stderr | 19 ++++++-- .../macro/kw-in-item-pos-recovery-149692.rs | 9 ++-- .../kw-in-item-pos-recovery-149692.stderr | 48 +++++++++++++++---- .../macro/kw-in-item-pos-recovery-151238.rs | 13 +++++ .../kw-in-item-pos-recovery-151238.stderr | 25 ++++++++++ 9 files changed, 102 insertions(+), 22 deletions(-) create mode 100644 tests/ui/parser/macro/kw-in-item-pos-recovery-151238.rs create mode 100644 tests/ui/parser/macro/kw-in-item-pos-recovery-151238.stderr diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 2fd1d146b1f6..60e12fa05adf 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2264,7 +2264,7 @@ impl<'a> Parser<'a> { && self.look_ahead(1, |t| *t == token::Comma || *t == token::CloseParen) { // `fn foo(String s) {}` - let ident = self.parse_ident().unwrap(); + let ident = self.parse_ident_common(true).unwrap(); let span = pat.span.with_hi(ident.span.hi()); err.span_suggestion( diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index bc76418429aa..c7d09b834540 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -408,12 +408,11 @@ impl<'a> Parser<'a> { let insert_span = ident_span.shrink_to_lo(); let ident = if self.token.is_ident() - && self.token.is_non_reserved_ident() && (!is_const || self.look_ahead(1, |t| *t == token::OpenParen)) && self.look_ahead(1, |t| { matches!(t.kind, token::Lt | token::OpenBrace | token::OpenParen) }) { - self.parse_ident().unwrap() + self.parse_ident_common(true).unwrap() } else { return Ok(()); }; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index d6e99bc540f7..c39e8351f0bd 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -469,7 +469,7 @@ impl<'a> Parser<'a> { self.parse_ident_common(self.may_recover()) } - fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, Ident> { + pub(crate) fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, Ident> { let (ident, is_raw) = self.ident_or_err(recover)?; if is_raw == IdentIsRaw::No && ident.is_reserved() { diff --git a/tests/ui/parser/macro/kw-in-const-item-pos-recovery-149692.rs b/tests/ui/parser/macro/kw-in-const-item-pos-recovery-149692.rs index 58bb62bc4bf8..8619856cad67 100644 --- a/tests/ui/parser/macro/kw-in-const-item-pos-recovery-149692.rs +++ b/tests/ui/parser/macro/kw-in-const-item-pos-recovery-149692.rs @@ -6,6 +6,7 @@ macro_rules! m { } m!(const Self()); -//~^ ERROR expected one of `!` or `::`, found `(` +//~^ ERROR expected identifier, found keyword `Self` +//~^^ ERROR missing `fn` or `struct` for function or struct definition fn main() {} diff --git a/tests/ui/parser/macro/kw-in-const-item-pos-recovery-149692.stderr b/tests/ui/parser/macro/kw-in-const-item-pos-recovery-149692.stderr index f9b73109dbb4..d412c59c4372 100644 --- a/tests/ui/parser/macro/kw-in-const-item-pos-recovery-149692.stderr +++ b/tests/ui/parser/macro/kw-in-const-item-pos-recovery-149692.stderr @@ -1,11 +1,22 @@ -error: expected one of `!` or `::`, found `(` - --> $DIR/kw-in-const-item-pos-recovery-149692.rs:8:14 +error: expected identifier, found keyword `Self` + --> $DIR/kw-in-const-item-pos-recovery-149692.rs:8:10 + | +LL | m!(const Self()); + | ^^^^ expected identifier, found keyword + +error: missing `fn` or `struct` for function or struct definition + --> $DIR/kw-in-const-item-pos-recovery-149692.rs:8:10 | LL | (const $id:item()) => {} | -------- while parsing argument for this `item` macro fragment ... LL | m!(const Self()); - | ^ expected one of `!` or `::` + | ^^^^ + | +help: if you meant to call a macro, try + | +LL | m!(const Self!()); + | + -error: aborting due to 1 previous error +error: aborting due to 2 previous errors diff --git a/tests/ui/parser/macro/kw-in-item-pos-recovery-149692.rs b/tests/ui/parser/macro/kw-in-item-pos-recovery-149692.rs index 223864e33296..77372ced09c4 100644 --- a/tests/ui/parser/macro/kw-in-item-pos-recovery-149692.rs +++ b/tests/ui/parser/macro/kw-in-item-pos-recovery-149692.rs @@ -8,12 +8,15 @@ macro_rules! m { } m!(Self()); -//~^ ERROR expected one of `!` or `::`, found `(` +//~^ ERROR expected identifier, found keyword `Self` +//~^^ ERROR missing `fn` or `struct` for function or struct definition m!(Self{}); -//~^ ERROR expected one of `!` or `::`, found `{` +//~^ ERROR expected identifier, found keyword `Self` +//~^^ ERROR missing `enum` or `struct` for enum or struct definition m!(crate()); -//~^ ERROR expected one of `!` or `::`, found `(` +//~^ ERROR expected identifier, found keyword `crate` +//~^^ ERROR missing `fn` or `struct` for function or struct definition fn main() {} diff --git a/tests/ui/parser/macro/kw-in-item-pos-recovery-149692.stderr b/tests/ui/parser/macro/kw-in-item-pos-recovery-149692.stderr index a65214b0d1f9..39f3e2d3a9ea 100644 --- a/tests/ui/parser/macro/kw-in-item-pos-recovery-149692.stderr +++ b/tests/ui/parser/macro/kw-in-item-pos-recovery-149692.stderr @@ -1,29 +1,57 @@ -error: expected one of `!` or `::`, found `(` - --> $DIR/kw-in-item-pos-recovery-149692.rs:10:8 +error: expected identifier, found keyword `Self` + --> $DIR/kw-in-item-pos-recovery-149692.rs:10:4 + | +LL | m!(Self()); + | ^^^^ expected identifier, found keyword + +error: missing `fn` or `struct` for function or struct definition + --> $DIR/kw-in-item-pos-recovery-149692.rs:10:4 | LL | ($id:item()) => {} | -------- while parsing argument for this `item` macro fragment ... LL | m!(Self()); - | ^ expected one of `!` or `::` + | ^^^^ + | +help: if you meant to call a macro, try + | +LL | m!(Self!()); + | + -error: expected one of `!` or `::`, found `{` - --> $DIR/kw-in-item-pos-recovery-149692.rs:13:8 +error: expected identifier, found keyword `Self` + --> $DIR/kw-in-item-pos-recovery-149692.rs:14:4 + | +LL | m!(Self{}); + | ^^^^ expected identifier, found keyword + +error: missing `enum` or `struct` for enum or struct definition + --> $DIR/kw-in-item-pos-recovery-149692.rs:14:4 | LL | ($id:item()) => {} | -------- while parsing argument for this `item` macro fragment ... LL | m!(Self{}); - | ^ expected one of `!` or `::` + | ^^^^ -error: expected one of `!` or `::`, found `(` - --> $DIR/kw-in-item-pos-recovery-149692.rs:16:9 +error: expected identifier, found keyword `crate` + --> $DIR/kw-in-item-pos-recovery-149692.rs:18:4 + | +LL | m!(crate()); + | ^^^^^ expected identifier, found keyword + +error: missing `fn` or `struct` for function or struct definition + --> $DIR/kw-in-item-pos-recovery-149692.rs:18:4 | LL | ($id:item()) => {} | -------- while parsing argument for this `item` macro fragment ... LL | m!(crate()); - | ^ expected one of `!` or `::` + | ^^^^^ + | +help: if you meant to call a macro, try + | +LL | m!(crate!()); + | + -error: aborting due to 3 previous errors +error: aborting due to 6 previous errors diff --git a/tests/ui/parser/macro/kw-in-item-pos-recovery-151238.rs b/tests/ui/parser/macro/kw-in-item-pos-recovery-151238.rs new file mode 100644 index 000000000000..bd1785ba5b3c --- /dev/null +++ b/tests/ui/parser/macro/kw-in-item-pos-recovery-151238.rs @@ -0,0 +1,13 @@ +//@ edition: 2021 + +macro_rules! x { + ($ty : item) => {}; +} +x! { + trait MyTrait { fn bar(c self) } + //~^ ERROR expected identifier, found keyword `self` + //~^^ ERROR expected one of `:`, `@`, or `|`, found keyword `self` + //~^^^ ERROR expected one of `->`, `;`, `where`, or `{`, found `}` +} + +fn main() {} diff --git a/tests/ui/parser/macro/kw-in-item-pos-recovery-151238.stderr b/tests/ui/parser/macro/kw-in-item-pos-recovery-151238.stderr new file mode 100644 index 000000000000..81151edaf0c0 --- /dev/null +++ b/tests/ui/parser/macro/kw-in-item-pos-recovery-151238.stderr @@ -0,0 +1,25 @@ +error: expected identifier, found keyword `self` + --> $DIR/kw-in-item-pos-recovery-151238.rs:7:28 + | +LL | trait MyTrait { fn bar(c self) } + | ^^^^ expected identifier, found keyword + +error: expected one of `:`, `@`, or `|`, found keyword `self` + --> $DIR/kw-in-item-pos-recovery-151238.rs:7:28 + | +LL | trait MyTrait { fn bar(c self) } + | --^^^^ + | | | + | | expected one of `:`, `@`, or `|` + | help: declare the type after the parameter binding: `: ` + +error: expected one of `->`, `;`, `where`, or `{`, found `}` + --> $DIR/kw-in-item-pos-recovery-151238.rs:7:34 + | +LL | trait MyTrait { fn bar(c self) } + | --- ^ expected one of `->`, `;`, `where`, or `{` + | | + | while parsing this `fn` + +error: aborting due to 3 previous errors + From e519c686cfe9220609929e014642bf99eebb48c4 Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 19 Jan 2026 11:15:20 +0800 Subject: [PATCH 0846/1061] Deduplicate diagnostics for const trait supertraits --- .../traits/fulfillment_errors.rs | 31 +++++++++++++++++++ tests/ui/consts/issue-94675.rs | 1 - tests/ui/consts/issue-94675.stderr | 13 +------- tests/ui/traits/const-traits/call.rs | 1 - tests/ui/traits/const-traits/call.stderr | 11 +------ ...closure-const_trait_impl-ice-113381.stderr | 11 +------ ...-const-op-const-closure-non-const-outer.rs | 3 +- ...st-op-const-closure-non-const-outer.stderr | 15 ++------- 8 files changed, 39 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 00d06779e652..6872d038fb7f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1442,6 +1442,31 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.can_eq(param_env, goal.trait_ref, trait_assumption.trait_ref) } + fn can_match_host_effect( + &self, + param_env: ty::ParamEnv<'tcx>, + goal: ty::HostEffectPredicate<'tcx>, + assumption: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>, + ) -> bool { + let assumption = self.instantiate_binder_with_fresh_vars( + DUMMY_SP, + infer::BoundRegionConversionTime::HigherRankedType, + assumption, + ); + + assumption.constness.satisfies(goal.constness) + && self.can_eq(param_env, goal.trait_ref, assumption.trait_ref) + } + + fn as_host_effect_clause( + predicate: ty::Predicate<'tcx>, + ) -> Option>> { + predicate.as_clause().and_then(|clause| match clause.kind().skip_binder() { + ty::ClauseKind::HostEffect(pred) => Some(clause.kind().rebind(pred)), + _ => None, + }) + } + fn can_match_projection( &self, param_env: ty::ParamEnv<'tcx>, @@ -1484,6 +1509,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .filter_map(|implied| implied.as_trait_clause()) .any(|implied| self.can_match_trait(param_env, error, implied)) }) + } else if let Some(error) = Self::as_host_effect_clause(error.predicate) { + self.enter_forall(error, |error| { + elaborate(self.tcx, std::iter::once(cond.predicate)) + .filter_map(Self::as_host_effect_clause) + .any(|implied| self.can_match_host_effect(param_env, error, implied)) + }) } else if let Some(error) = error.predicate.as_projection_clause() { self.enter_forall(error, |error| { elaborate(self.tcx, std::iter::once(cond.predicate)) diff --git a/tests/ui/consts/issue-94675.rs b/tests/ui/consts/issue-94675.rs index f2ddc928d122..0553b676bc3e 100644 --- a/tests/ui/consts/issue-94675.rs +++ b/tests/ui/consts/issue-94675.rs @@ -10,7 +10,6 @@ impl<'a> Foo<'a> { const fn spam(&mut self, baz: &mut Vec) { self.bar[0] = baz.len(); //~^ ERROR: `Vec: [const] Index<_>` is not satisfied - //~| ERROR: `Vec: [const] Index` is not satisfied //~| ERROR: `Vec: [const] IndexMut` is not satisfied } } diff --git a/tests/ui/consts/issue-94675.stderr b/tests/ui/consts/issue-94675.stderr index 771f2a14c305..ab7a76a90e02 100644 --- a/tests/ui/consts/issue-94675.stderr +++ b/tests/ui/consts/issue-94675.stderr @@ -16,17 +16,6 @@ LL | self.bar[0] = baz.len(); note: trait `IndexMut` is implemented but not `const` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -error[E0277]: the trait bound `Vec: [const] Index` is not satisfied - --> $DIR/issue-94675.rs:11:9 - | -LL | self.bar[0] = baz.len(); - | ^^^^^^^^^^^ - | -note: trait `Index` is implemented but not `const` - --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -note: required by a bound in `std::ops::IndexMut::index_mut` - --> $SRC_DIR/core/src/ops/index.rs:LL:COL - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/call.rs b/tests/ui/traits/const-traits/call.rs index c36adc4248f0..360c08e1b7fe 100644 --- a/tests/ui/traits/const-traits/call.rs +++ b/tests/ui/traits/const-traits/call.rs @@ -6,7 +6,6 @@ const _: () = { assert!((const || true)()); //~^ ERROR }: [const] Fn()` is not satisfied - //~| ERROR }: [const] FnMut()` is not satisfied }; fn main() {} diff --git a/tests/ui/traits/const-traits/call.stderr b/tests/ui/traits/const-traits/call.stderr index b688746e2506..8e32cab6dfcf 100644 --- a/tests/ui/traits/const-traits/call.stderr +++ b/tests/ui/traits/const-traits/call.stderr @@ -4,15 +4,6 @@ error[E0277]: the trait bound `{closure@$DIR/call.rs:7:14: 7:22}: [const] Fn()` LL | assert!((const || true)()); | ^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `{closure@$DIR/call.rs:7:14: 7:22}: [const] FnMut()` is not satisfied - --> $DIR/call.rs:7:13 - | -LL | assert!((const || true)()); - | ^^^^^^^^^^^^^^^^^ - | -note: required by a bound in `call` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr b/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr index 90e87c724f54..dab3f14161fa 100644 --- a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr +++ b/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr @@ -4,15 +4,6 @@ error[E0277]: the trait bound `{closure@$DIR/const_closure-const_trait_impl-ice- LL | (const || (()).foo())(); | ^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `{closure@$DIR/const_closure-const_trait_impl-ice-113381.rs:15:6: 15:14}: [const] FnMut()` is not satisfied - --> $DIR/const_closure-const_trait_impl-ice-113381.rs:15:5 - | -LL | (const || (()).foo())(); - | ^^^^^^^^^^^^^^^^^^^^^^^ - | -note: required by a bound in `call` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs index ee4ff02f4c7c..de5bedf0ace7 100644 --- a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs +++ b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs @@ -10,7 +10,8 @@ impl Foo for () { } fn main() { + // #150052 deduplicate diagnostics for const trait supertraits + // so we only get one error here (const || { (()).foo() })(); //~^ ERROR: }: [const] Fn()` is not satisfied - //~| ERROR: }: [const] FnMut()` is not satisfied } diff --git a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr index 69d289537da1..efbedca1c7e7 100644 --- a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr +++ b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr @@ -1,18 +1,9 @@ -error[E0277]: the trait bound `{closure@$DIR/non-const-op-const-closure-non-const-outer.rs:13:6: 13:14}: [const] Fn()` is not satisfied - --> $DIR/non-const-op-const-closure-non-const-outer.rs:13:5 +error[E0277]: the trait bound `{closure@$DIR/non-const-op-const-closure-non-const-outer.rs:15:6: 15:14}: [const] Fn()` is not satisfied + --> $DIR/non-const-op-const-closure-non-const-outer.rs:15:5 | LL | (const || { (()).foo() })(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `{closure@$DIR/non-const-op-const-closure-non-const-outer.rs:13:6: 13:14}: [const] FnMut()` is not satisfied - --> $DIR/non-const-op-const-closure-non-const-outer.rs:13:5 - | -LL | (const || { (()).foo() })(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: required by a bound in `call` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. From 0895c4cbe6ff960b23626a538d1691d2ebf51311 Mon Sep 17 00:00:00 2001 From: Jamie Hill-Daniel Date: Mon, 19 Jan 2026 04:48:23 +0000 Subject: [PATCH 0847/1061] ci: Move lockfile updates to a script --- .github/workflows/dependencies.yml | 16 +++------------- src/tools/update-lockfile.sh | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 13 deletions(-) create mode 100755 src/tools/update-lockfile.sh diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml index 80ffd67e04e1..7c721c7abeaa 100644 --- a/.github/workflows/dependencies.yml +++ b/.github/workflows/dependencies.yml @@ -62,19 +62,9 @@ jobs: rustup toolchain install --no-self-update --profile minimal $TOOLCHAIN rustup default $TOOLCHAIN - - name: cargo update compiler & tools - # Remove first line that always just says "Updating crates.io index" - run: | - echo -e "\ncompiler & tools dependencies:" >> cargo_update.log - cargo update 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log - - name: cargo update library - run: | - echo -e "\nlibrary dependencies:" >> cargo_update.log - cargo update --manifest-path library/Cargo.toml 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log - - name: cargo update rustbook - run: | - echo -e "\nrustbook dependencies:" >> cargo_update.log - cargo update --manifest-path src/tools/rustbook/Cargo.toml 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log + - name: cargo update + run: ./src/tools/update-lockfile.sh + - name: upload Cargo.lock artifact for use in PR uses: actions/upload-artifact@v4 with: diff --git a/src/tools/update-lockfile.sh b/src/tools/update-lockfile.sh new file mode 100755 index 000000000000..a968d83d8152 --- /dev/null +++ b/src/tools/update-lockfile.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +# Updates the workspaces in `.`, `library` and `src/tools/rustbook` +# Logs are written to `cargo_update.log` +# Used as part of regular dependency bumps + +set -euo pipefail + +echo -e "\ncompiler & tools dependencies:" > cargo_update.log +# Remove first line that always just says "Updating crates.io index" +cargo update 2>&1 | sed '/crates.io index/d' | \ + tee -a cargo_update.log +echo -e "\nlibrary dependencies:" >> cargo_update.log +cargo update --manifest-path library/Cargo.toml 2>&1 | sed '/crates.io index/d' | \ + tee -a cargo_update.log +echo -e "\nrustbook dependencies:" >> cargo_update.log +cargo update --manifest-path src/tools/rustbook/Cargo.toml 2>&1 | sed '/crates.io index/d' | \ + tee -a cargo_update.log From 7ec34defe9e62a1a6946d3e700b5903d8dc89ece Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 19 Jan 2026 14:46:38 +1100 Subject: [PATCH 0848/1061] Temporarily re-export `assert_matches!` to reduce stabilization churn --- compiler/rustc_abi/src/extern_abi/tests.rs | 3 ++- compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs | 3 +-- compiler/rustc_borrowck/src/type_check/input_output.rs | 3 +-- compiler/rustc_builtin_macros/src/test.rs | 2 +- compiler/rustc_codegen_llvm/src/asm.rs | 3 +-- compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs | 2 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 2 +- compiler/rustc_codegen_ssa/src/back/write.rs | 2 +- compiler/rustc_codegen_ssa/src/traits/builder.rs | 2 +- compiler/rustc_const_eval/src/check_consts/check.rs | 2 +- compiler/rustc_const_eval/src/interpret/call.rs | 2 +- compiler/rustc_const_eval/src/interpret/cast.rs | 3 +-- compiler/rustc_const_eval/src/interpret/eval_context.rs | 3 +-- compiler/rustc_const_eval/src/interpret/intrinsics.rs | 3 +-- compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs | 3 ++- compiler/rustc_const_eval/src/interpret/memory.rs | 2 +- compiler/rustc_const_eval/src/interpret/operand.rs | 3 +-- compiler/rustc_const_eval/src/interpret/place.rs | 3 +-- compiler/rustc_data_structures/src/graph/scc/mod.rs | 2 +- compiler/rustc_data_structures/src/lib.rs | 5 +++++ compiler/rustc_errors/src/lib.rs | 3 +-- compiler/rustc_hir_analysis/src/collect.rs | 2 +- compiler/rustc_hir_analysis/src/collect/generics_of.rs | 2 +- compiler/rustc_hir_analysis/src/collect/predicates_of.rs | 3 +-- compiler/rustc_hir_analysis/src/delegation.rs | 3 +-- compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs | 2 +- compiler/rustc_hir_analysis/src/impl_wf_check.rs | 3 +-- compiler/rustc_hir_typeck/src/method/probe.rs | 2 +- compiler/rustc_infer/src/infer/outlives/verify.rs | 3 +-- compiler/rustc_infer/src/infer/snapshot/undo_log.rs | 3 +-- compiler/rustc_lint/src/impl_trait_overcaptures.rs | 2 +- compiler/rustc_middle/src/ty/consts/kind.rs | 3 +-- compiler/rustc_middle/src/ty/context.rs | 3 +-- compiler/rustc_middle/src/ty/instance.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/sty.rs | 2 +- compiler/rustc_mir_build/src/builder/coverageinfo.rs | 2 +- compiler/rustc_mir_build/src/builder/expr/as_place.rs | 2 +- compiler/rustc_mir_build/src/builder/matches/mod.rs | 2 +- compiler/rustc_mir_build/src/builder/matches/user_ty.rs | 2 +- compiler/rustc_mir_build/src/thir/pattern/mod.rs | 2 +- compiler/rustc_mir_build/src/thir/util.rs | 3 +-- compiler/rustc_mir_dataflow/src/impls/initialized.rs | 3 +-- compiler/rustc_mir_dataflow/src/value_analysis.rs | 2 +- compiler/rustc_mir_transform/src/dataflow_const_prop.rs | 2 +- compiler/rustc_mir_transform/src/inline.rs | 2 +- compiler/rustc_mir_transform/src/promote_consts.rs | 2 +- compiler/rustc_mir_transform/src/shim.rs | 2 +- compiler/rustc_parse/src/parser/mod.rs | 2 +- compiler/rustc_parse/src/parser/tests.rs | 2 +- compiler/rustc_query_system/src/dep_graph/graph.rs | 3 +-- compiler/rustc_resolve/src/late.rs | 2 +- compiler/rustc_symbol_mangling/src/export.rs | 3 +-- .../src/error_reporting/traits/suggestions.rs | 2 +- compiler/rustc_trait_selection/src/solve/inspect/analyse.rs | 3 +-- compiler/rustc_trait_selection/src/traits/select/mod.rs | 2 +- compiler/rustc_ty_utils/src/abi.rs | 2 +- compiler/rustc_ty_utils/src/layout/invariant.rs | 3 +-- 58 files changed, 64 insertions(+), 79 deletions(-) diff --git a/compiler/rustc_abi/src/extern_abi/tests.rs b/compiler/rustc_abi/src/extern_abi/tests.rs index fc546a6570f0..8b9353ccae97 100644 --- a/compiler/rustc_abi/src/extern_abi/tests.rs +++ b/compiler/rustc_abi/src/extern_abi/tests.rs @@ -1,6 +1,7 @@ -use std::assert_matches::assert_matches; use std::str::FromStr; +use rustc_data_structures::assert_matches; + use super::*; #[allow(non_snake_case)] diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 743a28822eb9..8f643d8f460f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -3,8 +3,7 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -use std::assert_matches::assert_matches; - +use rustc_data_structures::assert_matches; use rustc_errors::{Applicability, Diag, EmissionGuarantee}; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index eb31b5de05d2..f3b9dcc90a84 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -7,9 +7,8 @@ //! `RETURN_PLACE` the MIR arguments) are always fully normalized (and //! contain revealed `impl Trait` values). -use std::assert_matches::assert_matches; - use itertools::Itertools; +use rustc_data_structures::assert_matches; use rustc_hir as hir; use rustc_infer::infer::{BoundRegionConversionTime, RegionVariableOrigin}; use rustc_middle::mir::*; diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 6f14385d5d30..d5f774865a9e 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -1,12 +1,12 @@ //! The expansion from a test function to the appropriate test struct for libtest //! Ideally, this code would be in libtest but for efficiency and error messages it lives here. -use std::assert_matches::assert_matches; use std::iter; use rustc_ast::{self as ast, GenericParamKind, HasNodeId, attr, join_path_idents}; use rustc_ast_pretty::pprust; use rustc_attr_parsing::AttributeParser; +use rustc_data_structures::assert_matches; use rustc_errors::{Applicability, Diag, Level}; use rustc_expand::base::*; use rustc_hir::Attribute; diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index ee1b6d45e149..7f02518d6c0d 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -1,9 +1,8 @@ -use std::assert_matches::assert_matches; - use rustc_abi::{BackendRepr, Float, Integer, Primitive, Scalar}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_codegen_ssa::mir::operand::OperandValue; use rustc_codegen_ssa::traits::*; +use rustc_data_structures::assert_matches; use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::Instance; use rustc_middle::ty::layout::TyAndLayout; diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index a728f3ea1e66..b27b1a88f133 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -1,9 +1,9 @@ -use std::assert_matches::assert_matches; use std::sync::Arc; use itertools::Itertools; use rustc_abi::Align; use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, ConstCodegenMethods}; +use rustc_data_structures::assert_matches; use rustc_data_structures::fx::FxIndexMap; use rustc_index::IndexVec; use rustc_middle::ty::TyCtxt; diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index c6aae89f1e51..565db7d298bc 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1,4 +1,3 @@ -use std::assert_matches::assert_matches; use std::cmp::Ordering; use std::ffi::c_uint; use std::ptr; @@ -13,6 +12,7 @@ use rustc_codegen_ssa::errors::{ExpectedPointerMutability, InvalidMonomorphizati use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue}; use rustc_codegen_ssa::traits::*; +use rustc_data_structures::assert_matches; use rustc_hir::def_id::LOCAL_CRATE; use rustc_hir::{self as hir}; use rustc_middle::mir::BinOp; diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 3e36bd8552b1..53121fc6275b 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1,4 +1,3 @@ -use std::assert_matches::assert_matches; use std::marker::PhantomData; use std::panic::AssertUnwindSafe; use std::path::{Path, PathBuf}; @@ -8,6 +7,7 @@ use std::{fs, io, mem, str, thread}; use rustc_abi::Size; use rustc_ast::attr; +use rustc_data_structures::assert_matches; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::jobserver::{self, Acquired}; use rustc_data_structures::memmap::Mmap; diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 4f45c614e003..ba36188f05d1 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -1,7 +1,7 @@ -use std::assert_matches::assert_matches; use std::ops::Deref; use rustc_abi::{Align, Scalar, Size, WrappingRange}; +use rustc_data_structures::assert_matches; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::mir; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 3a85ca3760d2..95dbf42d4d44 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -1,11 +1,11 @@ //! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations. -use std::assert_matches::assert_matches; use std::borrow::Cow; use std::mem; use std::num::NonZero; use std::ops::Deref; +use rustc_data_structures::assert_matches; use rustc_errors::{Diag, ErrorGuaranteed}; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 94c6fd1b3238..9c8ca44c5e8f 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -1,10 +1,10 @@ //! Manages calling a concrete function (with known MIR body) with argument passing, //! and returning the return value to the caller. -use std::assert_matches::assert_matches; use std::borrow::Cow; use either::{Left, Right}; use rustc_abi::{self as abi, ExternAbi, FieldIdx, Integer, VariantIdx}; +use rustc_data_structures::assert_matches; use rustc_hir::def_id::DefId; use rustc_middle::ty::layout::{IntegerExt, TyAndLayout}; use rustc_middle::ty::{self, AdtDef, Instance, Ty, VariantDef}; diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 3485a5c625ba..43de2e7f078a 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -1,8 +1,7 @@ -use std::assert_matches::assert_matches; - use rustc_abi::{FieldIdx, Integer}; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_apfloat::{Float, FloatConvert}; +use rustc_data_structures::assert_matches; use rustc_middle::mir::CastKind; use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar}; use rustc_middle::ty::adjustment::PointerCoercion; diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index d23369caffa4..aeadf0257ea8 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -1,7 +1,6 @@ -use std::assert_matches::debug_assert_matches; - use either::{Left, Right}; use rustc_abi::{Align, HasDataLayout, Size, TargetDataLayout}; +use rustc_data_structures::debug_assert_matches; use rustc_errors::DiagCtxtHandle; use rustc_hir::def_id::DefId; use rustc_hir::limit::Limit; diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index fe1dd1b6eb35..e526f6120689 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -4,10 +4,9 @@ mod simd; -use std::assert_matches::assert_matches; - use rustc_abi::{FIRST_VARIANT, FieldIdx, HasDataLayout, Size, VariantIdx}; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; +use rustc_data_structures::assert_matches; use rustc_hir::def_id::CRATE_DEF_ID; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, read_target_uint, write_target_uint}; diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs index 33a115384a88..d7fe7801fb08 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs @@ -2,6 +2,7 @@ use either::Either; use rustc_abi::{BackendRepr, Endian}; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_apfloat::{Float, Round}; +use rustc_data_structures::assert_matches; use rustc_middle::mir::interpret::{InterpErrorKind, Pointer, UndefinedBehaviorInfo}; use rustc_middle::ty::{FloatTy, ScalarInt, SimdAlign}; use rustc_middle::{bug, err_ub_format, mir, span_bug, throw_unsup_format, ty}; @@ -10,7 +11,7 @@ use tracing::trace; use super::{ ImmTy, InterpCx, InterpResult, Machine, MinMax, MulAddType, OpTy, PlaceTy, Provenance, Scalar, - Size, TyAndLayout, assert_matches, interp_ok, throw_ub_format, + Size, TyAndLayout, interp_ok, throw_ub_format, }; use crate::interpret::Writeable; diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 862fe4779080..a6c8b28cce9f 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -6,7 +6,6 @@ //! integer. It is crucial that these operations call `check_align` *before* //! short-circuiting the empty case! -use std::assert_matches::assert_matches; use std::borrow::{Borrow, Cow}; use std::cell::Cell; use std::collections::VecDeque; @@ -14,6 +13,7 @@ use std::{fmt, ptr}; use rustc_abi::{Align, HasDataLayout, Size}; use rustc_ast::Mutability; +use rustc_data_structures::assert_matches; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_middle::mir::display_allocation; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 9a956259ba57..e8e77de8eb3e 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -1,11 +1,10 @@ //! Functions concerning immediate values and operands, and reading from operands. //! All high-level functions to read from memory work on operands as sources. -use std::assert_matches::assert_matches; - use either::{Either, Left, Right}; use rustc_abi as abi; use rustc_abi::{BackendRepr, HasDataLayout, Size}; +use rustc_data_structures::assert_matches; use rustc_hir::def::Namespace; use rustc_middle::mir::interpret::ScalarSizeMismatch; use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, TyAndLayout}; diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index a409c7fad417..d472c14253b5 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -2,10 +2,9 @@ //! into a place. //! All high-level functions to write to memory work on places as destinations. -use std::assert_matches::assert_matches; - use either::{Either, Left, Right}; use rustc_abi::{BackendRepr, HasDataLayout, Size}; +use rustc_data_structures::assert_matches; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::{bug, mir, span_bug}; diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs index 1882e6e835a4..91cbe3c533bb 100644 --- a/compiler/rustc_data_structures/src/graph/scc/mod.rs +++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs @@ -8,7 +8,6 @@ //! Typical examples would include: minimum element in SCC, maximum element //! reachable from it, etc. -use std::assert_matches::debug_assert_matches; use std::fmt::Debug; use std::marker::PhantomData; use std::ops::Range; @@ -16,6 +15,7 @@ use std::ops::Range; use rustc_index::{Idx, IndexSlice, IndexVec}; use tracing::{debug, instrument, trace}; +use crate::debug_assert_matches; use crate::fx::FxHashSet; use crate::graph::vec_graph::VecGraph; use crate::graph::{DirectedGraph, NumEdges, Successors}; diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index ff1dd41c82cc..8377213850b8 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -38,6 +38,11 @@ #![feature(unwrap_infallible)] // tidy-alphabetical-end +// Temporarily re-export `assert_matches!`, so that the rest of the compiler doesn't +// have to worry about it being moved to a different module in std during stabilization. +// FIXME(#151359): Remove this when `feature(assert_matches)` is stable in stage0. +// (This doesn't necessarily need to be fixed during the beta bump itself.) +pub use std::assert_matches::{assert_matches, debug_assert_matches}; use std::fmt; pub use atomic_ref::AtomicRef; diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 148368045f4f..ce40f3ae8bf8 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -23,7 +23,6 @@ extern crate self as rustc_errors; -use std::assert_matches::assert_matches; use std::backtrace::{Backtrace, BacktraceStatus}; use std::borrow::Cow; use std::cell::Cell; @@ -55,10 +54,10 @@ pub use diagnostic_impls::{ }; pub use emitter::ColorConfig; use emitter::{ConfusionType, DynEmitter, Emitter, detect_confusion_type, is_different}; -use rustc_data_structures::AtomicRef; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::stable_hasher::StableHasher; use rustc_data_structures::sync::{DynSend, Lock}; +use rustc_data_structures::{AtomicRef, assert_matches}; pub use rustc_error_messages::{ DiagArg, DiagArgFromDisplay, DiagArgName, DiagArgValue, DiagMessage, FluentBundle, IntoDiagArg, LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagMessage, diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 2c0253409387..9c0b638c1482 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -14,13 +14,13 @@ //! At present, however, we do run collection across all items in the //! crate as a kind of pass. This should eventually be factored away. -use std::assert_matches::assert_matches; use std::cell::Cell; use std::iter; use std::ops::Bound; use rustc_abi::{ExternAbi, Size}; use rustc_ast::Recovered; +use rustc_data_structures::assert_matches; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, E0228, ErrorGuaranteed, StashKey, struct_span_code_err, diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 3d2f0466cad0..511d513216eb 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -1,6 +1,6 @@ -use std::assert_matches::assert_matches; use std::ops::ControlFlow; +use rustc_data_structures::assert_matches; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor, VisitorExt}; diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 178c47b09c84..a2236b426305 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -1,6 +1,5 @@ -use std::assert_matches::assert_matches; - use hir::Node; +use rustc_data_structures::assert_matches; use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_hir::attrs::AttributeKind; diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs index cf0533c39e73..f64341d755f8 100644 --- a/compiler/rustc_hir_analysis/src/delegation.rs +++ b/compiler/rustc_hir_analysis/src/delegation.rs @@ -2,8 +2,7 @@ //! //! For more information about delegation design, see the tracking issue #118212. -use std::assert_matches::debug_assert_matches; - +use rustc_data_structures::debug_assert_matches; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 6e1e6c157a91..924967b65c19 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -19,10 +19,10 @@ mod dyn_trait; pub mod errors; pub mod generics; -use std::assert_matches::assert_matches; use std::slice; use rustc_ast::LitKind; +use rustc_data_structures::assert_matches; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index cadbc54c3410..f5c77c680000 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -8,9 +8,8 @@ //! specialization errors. These things can (and probably should) be //! fixed, but for the moment it's easier to do these checks early. -use std::assert_matches::debug_assert_matches; - use min_specialization::check_min_specialization; +use rustc_data_structures::debug_assert_matches; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_errors::codes::*; diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index beb0337d8c59..ed71ad2119c9 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1,8 +1,8 @@ -use std::assert_matches::debug_assert_matches; use std::cell::{Cell, RefCell}; use std::cmp::max; use std::ops::Deref; +use rustc_data_structures::debug_assert_matches; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sso::SsoHashSet; use rustc_errors::Applicability; diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index f67b99cb3f84..affeb01e6d05 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -1,5 +1,4 @@ -use std::assert_matches::assert_matches; - +use rustc_data_structures::assert_matches; use rustc_middle::ty::outlives::{Component, compute_alias_components_recursive}; use rustc_middle::ty::{self, OutlivesPredicate, Ty, TyCtxt}; use smallvec::smallvec; diff --git a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs index c859d64133c4..a6f324b70471 100644 --- a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs +++ b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs @@ -1,8 +1,7 @@ -use std::assert_matches::assert_matches; use std::marker::PhantomData; use rustc_data_structures::undo_log::{Rollback, UndoLogs}; -use rustc_data_structures::{snapshot_vec as sv, unify as ut}; +use rustc_data_structures::{assert_matches, snapshot_vec as sv, unify as ut}; use rustc_middle::ty::{self, OpaqueTypeKey, ProvisionalHiddenType}; use tracing::debug; diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index 2fc9d562dc56..f6c2e5946079 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -1,6 +1,6 @@ -use std::assert_matches::debug_assert_matches; use std::cell::LazyCell; +use rustc_data_structures::debug_assert_matches; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::unord::UnordSet; use rustc_errors::{LintDiagnostic, Subdiagnostic}; diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index b3436550e8e0..c9ccb9bd0b3e 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -1,5 +1,4 @@ -use std::assert_matches::assert_matches; - +use rustc_data_structures::assert_matches; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use super::Const; diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index e9fa3f14358e..a5aead9829f1 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -4,7 +4,6 @@ pub mod tls; -use std::assert_matches::debug_assert_matches; use std::borrow::{Borrow, Cow}; use std::cmp::Ordering; use std::env::VarError; @@ -17,7 +16,6 @@ use std::{fmt, iter, mem}; use rustc_abi::{ExternAbi, FieldIdx, Layout, LayoutData, TargetDataLayout, VariantIdx}; use rustc_ast as ast; -use rustc_data_structures::defer; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::intern::Interned; @@ -29,6 +27,7 @@ use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{ self, DynSend, DynSync, FreezeReadGuard, Lock, RwLock, WorkerLocal, }; +use rustc_data_structures::{debug_assert_matches, defer}; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, MultiSpan, }; diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index c27d47fcc0d8..0e9dd7dd169c 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -1,6 +1,6 @@ -use std::assert_matches::assert_matches; use std::fmt; +use rustc_data_structures::assert_matches; use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 8eee114ead02..ce713dcf42f5 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -11,7 +11,6 @@ #![allow(rustc::usage_of_ty_tykind)] -use std::assert_matches::assert_matches; use std::fmt::Debug; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; @@ -31,6 +30,7 @@ use rustc_ast::AttrVec; use rustc_ast::expand::typetree::{FncTree, Kind, Type, TypeTree}; use rustc_ast::node_id::NodeMap; pub use rustc_ast_ir::{Movability, Mutability, try_visit}; +use rustc_data_structures::assert_matches; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index c282f2211f65..34aca8adb4a0 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2,12 +2,12 @@ #![allow(rustc::usage_of_ty_tykind)] -use std::assert_matches::debug_assert_matches; use std::borrow::Cow; use std::ops::{ControlFlow, Range}; use hir::def::{CtorKind, DefKind}; use rustc_abi::{FIRST_VARIANT, FieldIdx, ScalableElt, VariantIdx}; +use rustc_data_structures::debug_assert_matches; use rustc_errors::{ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::LangItem; diff --git a/compiler/rustc_mir_build/src/builder/coverageinfo.rs b/compiler/rustc_mir_build/src/builder/coverageinfo.rs index 091b9dad5bc1..ae36b2fb7f38 100644 --- a/compiler/rustc_mir_build/src/builder/coverageinfo.rs +++ b/compiler/rustc_mir_build/src/builder/coverageinfo.rs @@ -1,6 +1,6 @@ -use std::assert_matches::assert_matches; use std::collections::hash_map::Entry; +use rustc_data_structures::assert_matches; use rustc_data_structures::fx::FxHashMap; use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, CoverageInfoHi, CoverageKind}; use rustc_middle::mir::{self, BasicBlock, SourceInfo, UnOp}; diff --git a/compiler/rustc_mir_build/src/builder/expr/as_place.rs b/compiler/rustc_mir_build/src/builder/expr/as_place.rs index 139c6da29d44..172dbf7c31b5 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs @@ -1,9 +1,9 @@ //! See docs in build/expr/mod.rs -use std::assert_matches::assert_matches; use std::iter; use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx}; +use rustc_data_structures::assert_matches; use rustc_hir::def_id::LocalDefId; use rustc_middle::hir::place::{Projection as HirProjection, ProjectionKind as HirProjectionKind}; use rustc_middle::mir::AssertKind::BoundsCheck; diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 11a181cfa8ce..2f9486c2d552 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -5,13 +5,13 @@ //! This also includes code for pattern bindings in `let` statements and //! function parameters. -use std::assert_matches::debug_assert_matches; use std::borrow::Borrow; use std::mem; use std::sync::Arc; use itertools::{Itertools, Position}; use rustc_abi::{FIRST_VARIANT, VariantIdx}; +use rustc_data_structures::debug_assert_matches; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::{BindingMode, ByRef, LangItem, LetStmt, LocalSource, Node}; diff --git a/compiler/rustc_mir_build/src/builder/matches/user_ty.rs b/compiler/rustc_mir_build/src/builder/matches/user_ty.rs index 2dcfd3772902..6ba5e360ef82 100644 --- a/compiler/rustc_mir_build/src/builder/matches/user_ty.rs +++ b/compiler/rustc_mir_build/src/builder/matches/user_ty.rs @@ -4,10 +4,10 @@ //! This avoids having to repeatedly clone a partly-built [`UserTypeProjections`] //! at every step of the traversal, which is what the previous code was doing. -use std::assert_matches::assert_matches; use std::iter; use rustc_abi::{FieldIdx, VariantIdx}; +use rustc_data_structures::assert_matches; use rustc_data_structures::smallvec::SmallVec; use rustc_middle::mir::{ProjectionElem, UserTypeProjection, UserTypeProjections}; use rustc_middle::ty::{AdtDef, UserTypeAnnotationIndex}; diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 650650cbaac9..d0abb6396145 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -4,11 +4,11 @@ mod check_match; mod const_to_pat; mod migration; -use std::assert_matches::assert_matches; use std::cmp::Ordering; use std::sync::Arc; use rustc_abi::{FieldIdx, Integer}; +use rustc_data_structures::assert_matches; use rustc_errors::codes::*; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; diff --git a/compiler/rustc_mir_build/src/thir/util.rs b/compiler/rustc_mir_build/src/thir/util.rs index 457957f5fce9..0093bb762110 100644 --- a/compiler/rustc_mir_build/src/thir/util.rs +++ b/compiler/rustc_mir_build/src/thir/util.rs @@ -1,5 +1,4 @@ -use std::assert_matches::assert_matches; - +use rustc_data_structures::assert_matches; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_middle::bug; diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index 9216106b6edd..6a0881ec2bcb 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -1,6 +1,5 @@ -use std::assert_matches::assert_matches; - use rustc_abi::VariantIdx; +use rustc_data_structures::assert_matches; use rustc_index::Idx; use rustc_index::bit_set::{DenseBitSet, MixedBitSet}; use rustc_middle::bug; diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index ac94ee5c8104..f102b7bb50f5 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -1,8 +1,8 @@ -use std::assert_matches::debug_assert_matches; use std::fmt::{Debug, Formatter}; use std::ops::Range; use rustc_abi::{FieldIdx, VariantIdx}; +use rustc_data_structures::debug_assert_matches; use rustc_data_structures::fx::{FxHashMap, FxIndexSet, StdEntry}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_index::IndexVec; diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 5254f60a1503..604f1da1a3ab 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -2,7 +2,6 @@ //! //! Currently, this pass only propagates scalar values. -use std::assert_matches::assert_matches; use std::cell::RefCell; use std::fmt::Formatter; @@ -11,6 +10,7 @@ use rustc_const_eval::const_eval::{DummyMachine, throw_machine_stop_str}; use rustc_const_eval::interpret::{ ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Projectable, interp_ok, }; +use rustc_data_structures::assert_matches; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::DefKind; use rustc_middle::bug; diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 1e9665f4337d..179ada36be75 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -1,10 +1,10 @@ //! Inlining pass for MIR functions. -use std::assert_matches::debug_assert_matches; use std::iter; use std::ops::{Range, RangeFrom}; use rustc_abi::{ExternAbi, FieldIdx}; +use rustc_data_structures::debug_assert_matches; use rustc_hir::attrs::{InlineAttr, OptimizeAttr}; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 11266ccc2832..2cc8e9d6739c 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -10,12 +10,12 @@ //! otherwise silence errors, if move analysis runs after promotion on broken //! MIR. -use std::assert_matches::assert_matches; use std::cell::Cell; use std::{cmp, iter, mem}; use either::{Left, Right}; use rustc_const_eval::check_consts::{ConstCx, qualifs}; +use rustc_data_structures::assert_matches; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_index::{IndexSlice, IndexVec}; diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 85e340c0a02a..cc1cb3d4f3ff 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -1,7 +1,7 @@ -use std::assert_matches::assert_matches; use std::{fmt, iter}; use rustc_abi::{ExternAbi, FIRST_VARIANT, FieldIdx, VariantIdx}; +use rustc_data_structures::assert_matches; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index d6e99bc540f7..c1ab8d76380a 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -16,7 +16,6 @@ mod ty; pub mod asm; pub mod cfg_select; -use std::assert_matches::debug_assert_matches; use std::{fmt, mem, slice}; use attr_wrapper::{AttrWrapper, UsePreAttrPos}; @@ -40,6 +39,7 @@ use rustc_ast::{ Mutability, Recovered, Safety, StrLit, Visibility, VisibilityKind, }; use rustc_ast_pretty::pprust; +use rustc_data_structures::debug_assert_matches; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, Diag, FatalError, MultiSpan, PResult}; use rustc_index::interval::IntervalSet; diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index 62e97c0c308c..2e1acca9e9af 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -1,5 +1,4 @@ #![allow(rustc::symbol_intern_string_literal)] -use std::assert_matches::assert_matches; use std::io::prelude::*; use std::iter::Peekable; use std::path::PathBuf; @@ -11,6 +10,7 @@ use rustc_ast::token::{self, Delimiter, Token}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_ast::{self as ast, PatKind, visit}; use rustc_ast_pretty::pprust::item_to_string; +use rustc_data_structures::assert_matches; use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter; use rustc_errors::emitter::{HumanEmitter, OutputTheme}; use rustc_errors::translation::Translator; diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 0b50d376b552..f32f3f78c04b 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -1,4 +1,3 @@ -use std::assert_matches::assert_matches; use std::fmt::Debug; use std::hash::Hash; use std::marker::PhantomData; @@ -7,12 +6,12 @@ use std::sync::atomic::{AtomicU32, Ordering}; use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::outline; use rustc_data_structures::profiling::QueryInvocationId; use rustc_data_structures::sharded::{self, ShardedHashMap}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{AtomicU64, Lock}; use rustc_data_structures::unord::UnordMap; +use rustc_data_structures::{assert_matches, outline}; use rustc_errors::DiagInner; use rustc_index::IndexVec; use rustc_macros::{Decodable, Encodable}; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 6557e1dea1a1..963bee369f6b 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -6,7 +6,6 @@ //! If you wonder why there's no `early.rs`, that's because it's split into three files - //! `build_reduced_graph.rs`, `macros.rs` and `imports.rs`. -use std::assert_matches::debug_assert_matches; use std::borrow::Cow; use std::collections::hash_map::Entry; use std::mem::{replace, swap, take}; @@ -16,6 +15,7 @@ use rustc_ast::visit::{ AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, try_visit, visit_opt, walk_list, }; use rustc_ast::*; +use rustc_data_structures::debug_assert_matches; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::codes::*; diff --git a/compiler/rustc_symbol_mangling/src/export.rs b/compiler/rustc_symbol_mangling/src/export.rs index 3896e06a627b..c99ba1d58f31 100644 --- a/compiler/rustc_symbol_mangling/src/export.rs +++ b/compiler/rustc_symbol_mangling/src/export.rs @@ -1,6 +1,5 @@ -use std::assert_matches::debug_assert_matches; - use rustc_abi::IntegerType; +use rustc_data_structures::debug_assert_matches; use rustc_data_structures::stable_hasher::StableHasher; use rustc_hashes::Hash128; use rustc_hir::def::DefKind; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index ef50dafec950..1c08b5e33142 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -1,12 +1,12 @@ // ignore-tidy-filelength -use std::assert_matches::debug_assert_matches; use std::borrow::Cow; use std::iter; use std::path::PathBuf; use itertools::{EitherOrBoth, Itertools}; use rustc_abi::ExternAbi; +use rustc_data_structures::debug_assert_matches; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::codes::*; diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 944d57bf95d1..ea8360c10b6f 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -9,8 +9,7 @@ //! coherence right now and was annoying to implement, so I am leaving it //! as is until we start using it for something else. -use std::assert_matches::assert_matches; - +use rustc_data_structures::assert_matches; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::Obligation; use rustc_macros::extension; diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index d6c9adfb2817..787dd4ea6254 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2,13 +2,13 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html#selection -use std::assert_matches::assert_matches; use std::cell::{Cell, RefCell}; use std::cmp; use std::fmt::{self, Display}; use std::ops::ControlFlow; use hir::def::DefKind; +use rustc_data_structures::assert_matches; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Diag, EmissionGuarantee}; diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index ad621c67772c..34c080c4938f 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -1,8 +1,8 @@ -use std::assert_matches::assert_matches; use std::iter; use rustc_abi::Primitive::Pointer; use rustc_abi::{BackendRepr, ExternAbi, PointerKind, Scalar, Size}; +use rustc_data_structures::assert_matches; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; use rustc_middle::bug; diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs index b013902f3fe3..97c98d0c2403 100644 --- a/compiler/rustc_ty_utils/src/layout/invariant.rs +++ b/compiler/rustc_ty_utils/src/layout/invariant.rs @@ -1,6 +1,5 @@ -use std::assert_matches::assert_matches; - use rustc_abi::{BackendRepr, FieldsShape, Scalar, Size, TagEncoding, Variants}; +use rustc_data_structures::assert_matches; use rustc_middle::bug; use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, TyAndLayout}; From 03b8b68073bd9273b9614830aaefe5b7f5d603c3 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Sun, 18 Jan 2026 20:30:48 +0100 Subject: [PATCH 0849/1061] Port `#[rustc_nounwind]` to attr parser --- .../src/attributes/rustc_internal.rs | 15 +++++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 5 +++-- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 4 +++- compiler/rustc_hir/src/attrs/data_structures.rs | 3 +++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 2 +- 6 files changed, 26 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 834b1d988cb4..f8ee011f559b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -320,3 +320,18 @@ impl NoArgsAttributeParser for RustcHasIncoherentInherentImplsParse ]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcHasIncoherentInherentImpls; } + +pub(crate) struct RustcNounwindParser; + +impl NoArgsAttributeParser for RustcNounwindParser { + const PATH: &[Symbol] = &[sym::rustc_nounwind]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::ForeignFn), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::TraitImpl)), + Allow(Target::Method(MethodKind::Trait { body: true })), + ]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNounwind; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 1a06f4edeaa6..e62dbc124eab 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -78,8 +78,8 @@ use crate::attributes::rustc_internal::{ RustcLintDiagnosticsParser, RustcLintOptDenyFieldAccessParser, RustcLintOptTyParser, RustcLintQueryInstabilityParser, RustcLintUntrackedQueryInformationParser, RustcMainParser, RustcMustImplementOneOfParser, RustcNeverReturnsNullPointerParser, - RustcNoImplicitAutorefsParser, RustcObjectLifetimeDefaultParser, RustcScalableVectorParser, - RustcSimdMonomorphizeLaneLimitParser, + RustcNoImplicitAutorefsParser, RustcNounwindParser, RustcObjectLifetimeDefaultParser, + RustcScalableVectorParser, RustcSimdMonomorphizeLaneLimitParser, }; use crate::attributes::semantics::MayDangleParser; use crate::attributes::stability::{ @@ -296,6 +296,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 1b0427e7e676..e29ba9c8725f 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -347,6 +347,9 @@ fn process_builtin_attrs( AttributeKind::RustcAllocatorZeroed => { codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED } + AttributeKind::RustcNounwind => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND + } _ => {} } } @@ -356,7 +359,6 @@ fn process_builtin_attrs( }; match name { - sym::rustc_nounwind => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND, sym::patchable_function_entry => { codegen_fn_attrs.patchable_function_entry = parse_patchable_function_entry(tcx, attr); diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 5cd508acc567..379ebf648f47 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -981,6 +981,9 @@ pub enum AttributeKind { /// Represents `#[rustc_no_implicit_autorefs]` RustcNoImplicitAutorefs, + /// Represents `#[rustc_nounwind]` + RustcNounwind, + /// Represents `#[rustc_object_lifetime_default]`. RustcObjectLifetimeDefault, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 19243c7d8468..44f040e5fdc8 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -122,6 +122,7 @@ impl AttributeKind { RustcMustImplementOneOf { .. } => No, RustcNeverReturnsNullPointer => Yes, RustcNoImplicitAutorefs => Yes, + RustcNounwind => No, RustcObjectLifetimeDefault => No, RustcPassIndirectlyInNonRusticAbis(..) => No, RustcReallocator => No, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 3a086ba5ff78..74edff7badba 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -322,6 +322,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcAllocatorZeroedVariant { .. } | AttributeKind::RustcDeallocator | AttributeKind::RustcReallocator + | AttributeKind::RustcNounwind ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); @@ -390,7 +391,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::rustc_partition_reused | sym::rustc_partition_codegened | sym::rustc_expected_cgu_reuse - | sym::rustc_nounwind // crate-level attrs, are checked below | sym::feature | sym::register_tool From 3e731f7e84301a898a36e46ee5e4845ff9bda98a Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Sun, 18 Jan 2026 20:41:29 +0100 Subject: [PATCH 0850/1061] Port `#[rustc_offload_kernel]` to attr parser --- .../rustc_attr_parsing/src/attributes/rustc_internal.rs | 9 +++++++++ compiler/rustc_attr_parsing/src/context.rs | 3 ++- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 6 +++--- compiler/rustc_hir/src/attrs/data_structures.rs | 3 +++ compiler/rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 1 + 6 files changed, 19 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index f8ee011f559b..51792b7aff72 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -335,3 +335,12 @@ impl NoArgsAttributeParser for RustcNounwindParser { ]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNounwind; } + +pub(crate) struct RustcOffloadKernelParser; + +impl NoArgsAttributeParser for RustcOffloadKernelParser { + const PATH: &[Symbol] = &[sym::rustc_offload_kernel]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcOffloadKernel; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index e62dbc124eab..0c882fee01c8 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -79,7 +79,7 @@ use crate::attributes::rustc_internal::{ RustcLintQueryInstabilityParser, RustcLintUntrackedQueryInformationParser, RustcMainParser, RustcMustImplementOneOfParser, RustcNeverReturnsNullPointerParser, RustcNoImplicitAutorefsParser, RustcNounwindParser, RustcObjectLifetimeDefaultParser, - RustcScalableVectorParser, RustcSimdMonomorphizeLaneLimitParser, + RustcOffloadKernelParser, RustcScalableVectorParser, RustcSimdMonomorphizeLaneLimitParser, }; use crate::attributes::semantics::MayDangleParser; use crate::attributes::stability::{ @@ -297,6 +297,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index e29ba9c8725f..e35d884b6711 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -350,6 +350,9 @@ fn process_builtin_attrs( AttributeKind::RustcNounwind => { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND } + AttributeKind::RustcOffloadKernel => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::OFFLOAD_KERNEL + } _ => {} } } @@ -363,9 +366,6 @@ fn process_builtin_attrs( codegen_fn_attrs.patchable_function_entry = parse_patchable_function_entry(tcx, attr); } - sym::rustc_offload_kernel => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::OFFLOAD_KERNEL - } _ => {} } } diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 379ebf648f47..314f36d6132d 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -987,6 +987,9 @@ pub enum AttributeKind { /// Represents `#[rustc_object_lifetime_default]`. RustcObjectLifetimeDefault, + /// Represents `#[rustc_offload_kernel]` + RustcOffloadKernel, + /// Represents `#[rustc_pass_indirectly_in_non_rustic_abis]` RustcPassIndirectlyInNonRusticAbis(Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 44f040e5fdc8..b55a5d0e29e1 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -124,6 +124,7 @@ impl AttributeKind { RustcNoImplicitAutorefs => Yes, RustcNounwind => No, RustcObjectLifetimeDefault => No, + RustcOffloadKernel => Yes, RustcPassIndirectlyInNonRusticAbis(..) => No, RustcReallocator => No, RustcScalableVector { .. } => Yes, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 74edff7badba..8074ae429892 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -323,6 +323,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcDeallocator | AttributeKind::RustcReallocator | AttributeKind::RustcNounwind + | AttributeKind::RustcOffloadKernel ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); From eeed3376e25905b6b1b42ee1fa1af2e75f4482f0 Mon Sep 17 00:00:00 2001 From: KaiTomotake Date: Mon, 19 Jan 2026 17:06:07 +0900 Subject: [PATCH 0851/1061] add test program A test for the issue where the variable meta is mistakenly treated as a reserved keyword. --- tests/ui/reserved/meta-is-not-reserved.rs | 7 +++++++ tests/ui/reserved/meta-is-not-reserved.stderr | 9 +++++++++ 2 files changed, 16 insertions(+) create mode 100644 tests/ui/reserved/meta-is-not-reserved.rs create mode 100644 tests/ui/reserved/meta-is-not-reserved.stderr diff --git a/tests/ui/reserved/meta-is-not-reserved.rs b/tests/ui/reserved/meta-is-not-reserved.rs new file mode 100644 index 000000000000..ceefe345ff0c --- /dev/null +++ b/tests/ui/reserved/meta-is-not-reserved.rs @@ -0,0 +1,7 @@ +// Regression test for +// A test for the issue where the variable meta is mistakenly treated as a reserved keyword. + +fn main() { + let xyz = meta; + //~^ ERROR cannot find value `meta` in this scope [E0425] +} diff --git a/tests/ui/reserved/meta-is-not-reserved.stderr b/tests/ui/reserved/meta-is-not-reserved.stderr new file mode 100644 index 000000000000..33f8fd82df85 --- /dev/null +++ b/tests/ui/reserved/meta-is-not-reserved.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `meta` in this scope + --> $DIR/meta-is-not-reserved.rs:5:15 + | +LL | let xyz = meta; + | ^^^^ not found in this scope + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0425`. From 67c45b739af089b9c8d96f0706c22b899a2ac324 Mon Sep 17 00:00:00 2001 From: JayanAXHF Date: Sat, 10 Jan 2026 01:37:51 +0530 Subject: [PATCH 0852/1061] feat: added syntax highlighting for code blocks in `rustc --explain` This commit adds a heuristics-based syntax highlighter for the `rustc --explain` command. It uses `rsutc_lexer`'s lexer to parse input in tokens, and matches on them to determine their color. --- Cargo.lock | 2 + compiler/rustc_driver_impl/Cargo.toml | 2 + compiler/rustc_driver_impl/src/highlighter.rs | 159 ++++++++++++++++++ compiler/rustc_driver_impl/src/lib.rs | 7 +- compiler/rustc_errors/src/markdown/mod.rs | 11 +- compiler/rustc_errors/src/markdown/term.rs | 41 +++-- .../src/markdown/tests/output.stdout | 10 +- .../rustc_errors/src/markdown/tests/term.rs | 2 +- tests/ui-fulldeps/explain_highlighter.rs | 29 ++++ .../explain_highlighter.run.stdout | 12 ++ 10 files changed, 249 insertions(+), 26 deletions(-) create mode 100644 compiler/rustc_driver_impl/src/highlighter.rs create mode 100644 tests/ui-fulldeps/explain_highlighter.rs create mode 100644 tests/ui-fulldeps/explain_highlighter.run.stdout diff --git a/Cargo.lock b/Cargo.lock index 470b38d5a91c..2d23541b4314 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3809,6 +3809,7 @@ dependencies = [ name = "rustc_driver_impl" version = "0.0.0" dependencies = [ + "anstyle", "ctrlc", "jiff", "libc", @@ -3834,6 +3835,7 @@ dependencies = [ "rustc_index", "rustc_infer", "rustc_interface", + "rustc_lexer", "rustc_lint", "rustc_log", "rustc_macros", diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 531b9e0c8ff7..c160240a18a7 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -5,6 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start +anstyle = "1.0.13" jiff = { version = "0.2.5", default-features = false, features = ["std"] } rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } @@ -28,6 +29,7 @@ rustc_incremental = { path = "../rustc_incremental" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } rustc_interface = { path = "../rustc_interface" } +rustc_lexer = { path = "../rustc_lexer" } rustc_lint = { path = "../rustc_lint" } rustc_log = { path = "../rustc_log" } rustc_macros = { path = "../rustc_macros" } diff --git a/compiler/rustc_driver_impl/src/highlighter.rs b/compiler/rustc_driver_impl/src/highlighter.rs new file mode 100644 index 000000000000..70b73cc29b72 --- /dev/null +++ b/compiler/rustc_driver_impl/src/highlighter.rs @@ -0,0 +1,159 @@ +//! This module provides a syntax highlighter for Rust code. +//! It is used by the `rustc --explain` command. +//! +//! The syntax highlighter uses `rustc_lexer`'s `tokenize` +//! function to parse the Rust code into a `Vec` of tokens. +//! The highlighter then highlights the tokens in the `Vec`, +//! and writes the highlighted output to the buffer. +use std::io::{self, Write}; + +use anstyle::{AnsiColor, Color, Effects, Style}; +use rustc_lexer::{LiteralKind, strip_shebang, tokenize}; + +const PRIMITIVE_TYPES: &'static [&str] = &[ + "i8", "i16", "i32", "i64", "i128", "isize", // signed integers + "u8", "u16", "u32", "u64", "u128", "usize", // unsigned integers + "f32", "f64", // floating point + "char", "bool", // others +]; + +const KEYWORDS: &'static [&str] = &[ + "static", "struct", "super", "trait", "true", "type", "unsafe", "use", "where", "while", "as", + "async", "await", "break", "const", "continue", "crate", "dyn", "else", "enum", "extern", + "false", "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", + "ref", +]; + +const STR_LITERAL_COLOR: AnsiColor = AnsiColor::Green; +const OTHER_LITERAL_COLOR: AnsiColor = AnsiColor::BrightRed; +const DERIVE_COLOR: AnsiColor = AnsiColor::BrightRed; +const KEYWORD_COLOR: AnsiColor = AnsiColor::BrightMagenta; +const TYPE_COLOR: AnsiColor = AnsiColor::Yellow; +const FUNCTION_COLOR: AnsiColor = AnsiColor::Blue; +const USE_COLOR: AnsiColor = AnsiColor::BrightMagenta; +const PRIMITIVE_TYPE_COLOR: AnsiColor = AnsiColor::Cyan; + +/// Highlight a Rust code string and write the highlighted +/// output to the buffer. It serves as a wrapper around +/// `Highlighter::highlight_rustc_lexer`. It is passed to +/// `write_anstream_buf` in the `lib.rs` file. +pub fn highlight(code: &str, buf: &mut Vec) -> io::Result<()> { + let mut highlighter = Highlighter::default(); + highlighter.highlight_rustc_lexer(code, buf) +} + +/// A syntax highlighter for Rust code +/// It is used by the `rustc --explain` command. +#[derive(Default)] +pub struct Highlighter { + /// Used to track if the previous token was a token + /// that warrants the next token to be colored differently + /// + /// For example, the keyword `fn` requires the next token + /// (the function name) to be colored differently. + prev_was_special: bool, + /// Used to track the length of tokens that have been + /// written so far. This is used to find the original + /// lexeme for a token from the code string. + len_accum: usize, +} + +impl Highlighter { + /// Create a new highlighter + pub fn new() -> Self { + Self::default() + } + + /// Highlight a Rust code string and write the highlighted + /// output to the buffer. + pub fn highlight_rustc_lexer(&mut self, code: &str, buf: &mut Vec) -> io::Result<()> { + use rustc_lexer::TokenKind; + + // Remove shebang from code string + let stripped_idx = strip_shebang(code).unwrap_or(0); + let stripped_code = &code[stripped_idx..]; + self.len_accum = stripped_idx; + let len_accum = &mut self.len_accum; + let tokens = tokenize(stripped_code, rustc_lexer::FrontmatterAllowed::No); + for token in tokens { + let len = token.len as usize; + // If the previous token was a special token, and this token is + // not a whitespace token, then it should be colored differently + let token_str = &code[*len_accum..*len_accum + len]; + if self.prev_was_special { + if token_str != " " { + self.prev_was_special = false; + } + let style = Style::new().fg_color(Some(Color::Ansi(AnsiColor::Blue))); + write!(buf, "{style}{token_str}{style:#}")?; + *len_accum += len; + continue; + } + match token.kind { + TokenKind::Ident => { + let mut style = Style::new(); + // Match if an identifier is a (well-known) keyword + if KEYWORDS.contains(&token_str) { + if token_str == "fn" { + self.prev_was_special = true; + } + style = style.fg_color(Some(Color::Ansi(KEYWORD_COLOR))); + } + // The `use` keyword is colored differently + if matches!(token_str, "use") { + style = style.fg_color(Some(Color::Ansi(USE_COLOR))); + } + // This heuristic test is to detect if the identifier is + // a function call. If it is, then the function identifier is + // colored differently. + if code[*len_accum..*len_accum + len + 1].ends_with('(') { + style = style.fg_color(Some(Color::Ansi(FUNCTION_COLOR))); + } + // The `derive` keyword is colored differently. + if token_str == "derive" { + style = style.fg_color(Some(Color::Ansi(DERIVE_COLOR))); + } + // This heuristic test is to detect if the identifier is + // a type. If it is, then the identifier is colored differently. + if matches!(token_str.chars().next().map(|c| c.is_uppercase()), Some(true)) { + style = style.fg_color(Some(Color::Ansi(TYPE_COLOR))); + } + // This if statement is to detect if the identifier is a primitive type. + if PRIMITIVE_TYPES.contains(&token_str) { + style = style.fg_color(Some(Color::Ansi(PRIMITIVE_TYPE_COLOR))); + } + write!(buf, "{style}{token_str}{style:#}")?; + } + + // Color literals + TokenKind::Literal { kind, suffix_start: _ } => { + // Strings -> Green + // Chars -> Green + // Raw strings -> Green + // C strings -> Green + // Byte Strings -> Green + // Other literals -> Bright Red (Orage-esque) + let style = match kind { + LiteralKind::Str { terminated: _ } + | LiteralKind::Char { terminated: _ } + | LiteralKind::RawStr { n_hashes: _ } + | LiteralKind::CStr { terminated: _ } => { + Style::new().fg_color(Some(Color::Ansi(STR_LITERAL_COLOR))) + } + _ => Style::new().fg_color(Some(Color::Ansi(OTHER_LITERAL_COLOR))), + }; + write!(buf, "{style}{token_str}{style:#}")?; + } + _ => { + // All other tokens are dimmed + let style = Style::new() + .fg_color(Some(Color::Ansi(AnsiColor::BrightWhite))) + .effects(Effects::DIMMED); + write!(buf, "{style}{token_str}{style:#}")?; + } + } + *len_accum += len; + } + Ok(()) + } +} diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 7820198f2dcf..045292338e58 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -86,6 +86,7 @@ pub mod args; pub mod pretty; #[macro_use] mod print; +pub mod highlighter; mod session_diagnostics; // Keep the OS parts of this `cfg` in sync with the `cfg` on the `libc` @@ -521,7 +522,11 @@ fn show_md_content_with_pager(content: &str, color: ColorConfig) { let mdstream = markdown::MdStream::parse_str(content); let bufwtr = markdown::create_stdout_bufwtr(); let mut mdbuf = Vec::new(); - if mdstream.write_anstream_buf(&mut mdbuf).is_ok() { Some((bufwtr, mdbuf)) } else { None } + if mdstream.write_anstream_buf(&mut mdbuf, Some(&highlighter::highlight)).is_ok() { + Some((bufwtr, mdbuf)) + } else { + None + } }; // Try to print via the pager, pretty output if possible. diff --git a/compiler/rustc_errors/src/markdown/mod.rs b/compiler/rustc_errors/src/markdown/mod.rs index 4f5e2328234d..9993407b05c0 100644 --- a/compiler/rustc_errors/src/markdown/mod.rs +++ b/compiler/rustc_errors/src/markdown/mod.rs @@ -18,9 +18,14 @@ impl<'a> MdStream<'a> { parse::entrypoint(s) } - /// Write formatted output to an anstream buffer - pub fn write_anstream_buf(&self, buf: &mut Vec) -> io::Result<()> { - term::entrypoint(self, buf) + /// Write formatted output to a stdout buffer, optionally with + /// a formatter for code blocks + pub fn write_anstream_buf( + &self, + buf: &mut Vec, + formatter: Option<&(dyn Fn(&str, &mut Vec) -> io::Result<()> + 'static)>, + ) -> io::Result<()> { + term::entrypoint(self, buf, formatter) } } diff --git a/compiler/rustc_errors/src/markdown/term.rs b/compiler/rustc_errors/src/markdown/term.rs index b0ce01548f00..b94cd06b30ef 100644 --- a/compiler/rustc_errors/src/markdown/term.rs +++ b/compiler/rustc_errors/src/markdown/term.rs @@ -12,29 +12,33 @@ thread_local! { static CURSOR: Cell = const { Cell::new(0) }; /// Width of the terminal static WIDTH: Cell = const { Cell::new(DEFAULT_COLUMN_WIDTH) }; + } -/// Print to terminal output to a buffer -pub(crate) fn entrypoint(stream: &MdStream<'_>, buf: &mut Vec) -> io::Result<()> { - #[cfg(not(test))] - if let Some((w, _)) = termize::dimensions() { - WIDTH.set(std::cmp::min(w, DEFAULT_COLUMN_WIDTH)); - } - write_stream(stream, buf, None, 0)?; +/// Print to the terminal output to a buffer +/// optionally with a formatter for code blocks +pub(crate) fn entrypoint( + stream: &MdStream<'_>, + buf: &mut Vec, + formatter: Option<&(dyn Fn(&str, &mut Vec) -> io::Result<()> + 'static)>, +) -> io::Result<()> { + write_stream(stream, buf, None, 0, formatter)?; buf.write_all(b"\n") } -/// Write the buffer, reset to the default style after each + +/// Write the buffer, reset to the default style after each, +/// optionally with a formatter for code blocks fn write_stream( MdStream(stream): &MdStream<'_>, buf: &mut Vec, + default: Option