From 69f75dbd9240907f15b49d8079a529a3b4fa500d Mon Sep 17 00:00:00 2001 From: hizyyo Date: Sat, 5 Sep 2026 21:33:26 +0500 Subject: [PATCH 01/17] Move the foreign module #[link] ABI check to attribute parsing --- compiler/rustc_ast_lowering/src/lib.rs | 1 + .../src/attributes/allow_unstable.rs | 2 +- .../src/attributes/codegen_attrs.rs | 4 +- .../src/attributes/inline.rs | 2 +- .../src/attributes/link_attrs.rs | 19 ++++++-- .../src/attributes/lint_helpers.rs | 2 +- .../src/attributes/macro_attrs.rs | 2 +- .../rustc_attr_parsing/src/attributes/mod.rs | 8 ++-- compiler/rustc_attr_parsing/src/context.rs | 2 +- .../rustc_attr_parsing/src/diagnostics.rs | 7 +++ compiler/rustc_attr_parsing/src/interface.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 19 +------- compiler/rustc_passes/src/diagnostics.rs | 7 --- tests/ui/attributes/link-foreign-mod-abi.rs | 45 +++++++++++++++++++ tests/ui/attributes/link-invalid-abi.rs | 13 ++++++ tests/ui/attributes/link-invalid-abi.stderr | 24 ++++++++++ ...issue-43106-gating-of-builtin-attrs.stderr | 16 +++---- 17 files changed, 127 insertions(+), 48 deletions(-) create mode 100644 tests/ui/attributes/link-foreign-mod-abi.rs create mode 100644 tests/ui/attributes/link-invalid-abi.rs create mode 100644 tests/ui/attributes/link-invalid-abi.stderr diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 8513ee39855d0..efb434c921653 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -41,6 +41,7 @@ use std::mem; use std::sync::{Arc, LazyLock}; +use rustc_abi::ExternAbi; use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::node_id::NodeMap; use rustc_ast::visit::{self, Visitor}; diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index 667c2d0838a25..4a6e57b12233a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -26,7 +26,7 @@ impl CombineAttributeParser for AllowInternalUnstableParser { .zip(iter::repeat(cx.attr_span)) } - fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) { + fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { check_macro_only(cx, attr_span); } } diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index bff7d7ad81cb9..2553829f8c5ce 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -349,7 +349,7 @@ impl NoArgsAttributeParser for TrackCallerParser { const STABILITY: AttributeStability = AttributeStability::Stable; const CREATE: fn(Span) -> AttributeKind = AttributeKind::TrackCaller; - fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) { + fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { match cx.target { Target::Fn => { // `#[track_caller]` is not valid on weak lang items because they are called via @@ -571,7 +571,7 @@ impl CombineAttributeParser for TargetFeatureParser { parse_tf_attribute(cx, args) } - fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) { + fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { // `#[target_feature]` is incompatible with lang item functions, // except on WASM where calling target-feature functions is safe (see #84988). if !cx.sess().target.is_like_wasm && !cx.sess().opts.actually_rustdoc { diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index f3e305ea266a1..78a989fdfdba6 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -94,7 +94,7 @@ impl SingleAttributeParser for RustcForceInlineParser { )) } - fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) { + fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { let Some(inline_span) = find_attr!(cx.parsed_attrs, Inline(attr, span) if !matches!(attr, InlineAttr::Force { .. }) => span) else { return; diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index a00e5af00c2eb..e3e74971e99db 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -1,8 +1,10 @@ +use rustc_abi::ExternAbi; +use rustc_ast::ItemKind; use rustc_attr_ir::AttributeKind::{LinkName, LinkOrdinal, LinkSection}; use rustc_attr_ir::*; use rustc_errors::msg; use rustc_feature::{AttributeStability, Features}; -use rustc_lint_defs::builtin::ILL_FORMED_ATTRIBUTE_INPUT; +use rustc_lint_defs::builtin::{ILL_FORMED_ATTRIBUTE_INPUT, UNUSED_ATTRIBUTES}; use rustc_session::Session; use rustc_session::diagnostics::feature_err; use rustc_span::edition::Edition::Edition2024; @@ -17,7 +19,7 @@ use crate::attributes::cfg::parse_cfg_entry; use crate::diagnostics::{ AsNeededCompatibility, BothFfiConstAndPure, BundleNeedsStatic, EmptyLinkName, ExportSymbolsNeedsStatic, ImportNameTypeRaw, ImportNameTypeX86, IncompatibleWasmLink, - InvalidLinkModifier, InvalidMachoSection, InvalidMachoSectionReason, LinkFrameworkApple, + InvalidLinkModifier, InvalidMachoSection, InvalidMachoSectionReason, Link, LinkFrameworkApple, LinkOrdinalOutOfRange, LinkRequiresName, MultipleModifiers, NullOnLinkName, NullOnLinkSection, RawDylibOnlyWindows, WholeArchiveNeedsStatic, }; @@ -258,6 +260,17 @@ impl CombineAttributeParser for LinkParser { import_name_type, }) } + + fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { + let Some(item) = cx.target_item else { return }; + let ItemKind::ForeignMod(fm) = &item.kind else { return }; + let abi = fm.abi.map_or(ExternAbi::FALLBACK, |abi| { + abi.symbol_unescaped.as_str().parse().unwrap_or(ExternAbi::Rust) + }); + if matches!(abi, ExternAbi::Rust) { + cx.emit_lint(UNUSED_ATTRIBUTES, Link, attr_span); + } + } } impl LinkParser { @@ -584,7 +597,7 @@ impl NoArgsAttributeParser for FfiPureParser { const STABILITY: AttributeStability = unstable!(ffi_pure); const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure; - fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) { + fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { // `#[ffi_const]` functions cannot be `#[ffi_pure]`. if cx.all_attrs.iter().any(|a| a.word_is(sym::ffi_const)) { cx.emit_err(BothFfiConstAndPure { attr_span }); diff --git a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs index 4ead90af8d630..10e42ced30705 100644 --- a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs +++ b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs @@ -29,7 +29,7 @@ impl NoArgsAttributeParser for RustcPubTransparentParser { const STABILITY: AttributeStability = unstable!(rustc_attrs); const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPubTransparent; - fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) { + fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { // `#[rustc_pub_transparent]` may only be applied to `#[repr(transparent)]` types. let is_transparent = find_attr!( cx.parsed_attrs, diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index 92b61fe00b1b9..dde10225e652f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -136,7 +136,7 @@ impl NoArgsAttributeParser for AllowInternalUnsafeParser { const STABILITY: AttributeStability = unstable!(allow_internal_unsafe); const CREATE: fn(Span) -> AttributeKind = |span| AttributeKind::AllowInternalUnsafe(span); - fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) { + fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { check_macro_only(cx, attr_span); } } diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 242b4a73b06a6..8e47414f6c72a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -169,7 +169,7 @@ pub(crate) trait SingleAttributeParser: 'static { /// combinations. `attr_span` is the span of this attribute. /// /// Defaults to a no-op. - fn finalize_check(_cx: &FinalizeCheckContext<'_, '_>, _attr_span: Span) {} + fn finalize_check(_cx: &mut FinalizeCheckContext<'_, '_>, _attr_span: Span) {} } /// Use in combination with [`SingleAttributeParser`]. @@ -287,7 +287,7 @@ pub(crate) trait NoArgsAttributeParser: 'static { /// `attr_span` is the span of this attribute. /// /// Defaults to a no-op. - fn finalize_check(_cx: &FinalizeCheckContext<'_, '_>, _attr_span: Span) {} + fn finalize_check(_cx: &mut FinalizeCheckContext<'_, '_>, _attr_span: Span) {} } pub(crate) struct WithoutArgs(PhantomData); @@ -311,7 +311,7 @@ impl SingleAttributeParser for WithoutArgs { Some(T::CREATE(cx.attr_span)) } - fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) { + fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { T::finalize_check(cx, attr_span) } } @@ -355,7 +355,7 @@ pub(crate) trait CombineAttributeParser: 'static { /// `attr_span` is the span of the first attribute that was encountered. /// /// Defaults to a no-op. - fn finalize_check(_cx: &FinalizeCheckContext<'_, '_>, _attr_span: Span) {} + fn finalize_check(_cx: &mut FinalizeCheckContext<'_, '_>, _attr_span: Span) {} } /// Use in combination with [`CombineAttributeParser`]. diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 22a4a069b75c7..72839643b4dc3 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -102,7 +102,7 @@ pub(crate) type FinalizeFn = fn(&mut FinalizeContext<'_, '_>) -> FinalizeOutput; /// finalized, so it can inspect the fully parsed attributes via /// [`FinalizeCheckContext::parsed_attrs`]. The [`Span`] is the span of the attribute the /// check is associated with, used for diagnostics. -pub(crate) type FinalizeCheckFn = fn(&FinalizeCheckContext<'_, '_>, Span); +pub(crate) type FinalizeCheckFn = fn(&mut FinalizeCheckContext<'_, '_>, Span); /// The result of finalizing a single attribute parser. pub(crate) struct FinalizeOutput { diff --git a/compiler/rustc_attr_parsing/src/diagnostics.rs b/compiler/rustc_attr_parsing/src/diagnostics.rs index 44e405fcf5269..bf630c6bf91a0 100644 --- a/compiler/rustc_attr_parsing/src/diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/diagnostics.rs @@ -1825,6 +1825,13 @@ pub(crate) struct EmptyLinkName { pub span: Span, } +#[derive(Diagnostic)] +#[diag("attribute should be applied to an `extern` block with non-Rust ABI")] +#[warning( + "this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!" +)] +pub(crate) struct Link; + #[derive(Diagnostic)] #[diag("link kind `framework` is only supported on Apple targets", code = E0455)] pub(crate) struct LinkFrameworkApple { diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 48083683b6a7a..df89ffe57b9a0 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -512,7 +512,7 @@ impl<'sess> AttributeParser<'sess> { // inspect the fully parsed attributes via `FinalizeCheckContext::parsed_attrs`. for (check, attr_span) in deferred_checks { check( - &FinalizeCheckContext { + &mut FinalizeCheckContext { shared: SharedContext { cx: self, target_span, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 4926ec9872d3b..2c9a18239665e 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -8,7 +8,6 @@ use std::cell::Cell; use std::slice; -use rustc_abi::ExternAbi; use rustc_ast::MetaItemKind; use rustc_attr_ir::diagnostic::Directive; use rustc_attr_ir::lang_items::LangItem; @@ -208,7 +207,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } AttributeKind::Naked(..) => self.check_naked(hir_id, target), AttributeKind::MayDangle(attr_span) => self.check_may_dangle(hir_id, *attr_span), - AttributeKind::Link(_, attr_span) => self.check_link(hir_id, *attr_span, target), AttributeKind::MacroExport { span, .. } => { self.check_macro_export(hir_id, *span, target) } @@ -271,6 +269,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::InstructionSet(..) => (), AttributeKind::InstrumentFn(..) => (), AttributeKind::Lang(..) => (), + AttributeKind::Link(..) => (), AttributeKind::LinkName { .. } => (), AttributeKind::LinkOrdinal { .. } => (), AttributeKind::LinkSection { .. } => (), @@ -1100,22 +1099,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.dcx().emit_err(diagnostics::InvalidMayDangle { attr_span }); } - /// Checks if `#[link]` is applied to an item other than a foreign module. - fn check_link(&self, hir_id: HirId, attr_span: Span, target: Target) { - if target != Target::ForeignMod { - return; // Checked by attribute parser - } - - if let hir::Node::Item(item) = self.tcx.hir_node(hir_id) - && let Item { kind: ItemKind::ForeignMod { abi, .. }, .. } = item - && !matches!(abi, ExternAbi::Rust) - { - return; - } - - self.tcx.emit_node_span_lint(UNUSED_ATTRIBUTES, hir_id, attr_span, diagnostics::Link); - } - /// Checks if `#[rustc_legacy_const_generics]` is applied to a function and has a valid argument. fn check_rustc_legacy_const_generics( &self, diff --git a/compiler/rustc_passes/src/diagnostics.rs b/compiler/rustc_passes/src/diagnostics.rs index 59c1005885903..7c82811f99276 100644 --- a/compiler/rustc_passes/src/diagnostics.rs +++ b/compiler/rustc_passes/src/diagnostics.rs @@ -126,13 +126,6 @@ pub(crate) struct BothOptimizeNoneAndInline { pub inline_span: Span, } -#[derive(Diagnostic)] -#[diag("attribute should be applied to an `extern` block with non-Rust ABI")] -#[warning( - "this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!" -)] -pub(crate) struct Link; - #[derive(Diagnostic)] #[diag("#[rustc_legacy_const_generics] functions must only have const generics")] pub(crate) struct RustcLegacyConstGenericsOnly { diff --git a/tests/ui/attributes/link-foreign-mod-abi.rs b/tests/ui/attributes/link-foreign-mod-abi.rs new file mode 100644 index 0000000000000..83d0a2dd47f0b --- /dev/null +++ b/tests/ui/attributes/link-foreign-mod-abi.rs @@ -0,0 +1,45 @@ +//@ check-pass +//@ compile-flags: --crate-type=lib + +#![no_core] +#![feature(no_core, rust_cold_cc, rust_preserve_none_cc, rust_tail_cc, unboxed_closures)] +#![allow(missing_abi)] +#![deny(unfulfilled_lint_expectations, unused_attributes)] + +#[link(name = "omitted")] +extern {} + +#[link(name = "c")] +extern "C" {} + +#[link(name = "rust-call")] +extern "rust-call" {} + +#[link(name = "rust-cold")] +extern "rust-cold" {} + +#[link(name = "rust-preserve-none")] +extern "rust-preserve-none" {} + +#[link(name = "tail")] +extern "tail" {} + +#[cfg_attr(any(), link(name = "disabled"))] +extern "Rust" {} + +#[expect(unused_attributes)] +#[cfg_attr(all(), link(name = "enabled"))] +extern "Rust" {} + +#[allow(unused_attributes)] +#[link(name = "allowed")] +extern "Rust" {} + +#[expect(unused_attributes)] +#[link(name = "expected")] +extern "Rust" {} + +#[expect(unused_attributes)] +#[link(name = "first")] +#[link(name = "second")] +extern "Rust" {} diff --git a/tests/ui/attributes/link-invalid-abi.rs b/tests/ui/attributes/link-invalid-abi.rs new file mode 100644 index 0000000000000..49f91236c1a2b --- /dev/null +++ b/tests/ui/attributes/link-invalid-abi.rs @@ -0,0 +1,13 @@ +//@ check-fail +//@ compile-flags: --crate-type=lib + +#![no_core] +#![feature(no_core)] +#![warn(unused_attributes)] + +#[link(name = "first")] +//~^ WARN +//~| WARN +#[link(name = "second")] +extern "invalid" {} +//~^ ERROR diff --git a/tests/ui/attributes/link-invalid-abi.stderr b/tests/ui/attributes/link-invalid-abi.stderr new file mode 100644 index 0000000000000..add2ebcb7c186 --- /dev/null +++ b/tests/ui/attributes/link-invalid-abi.stderr @@ -0,0 +1,24 @@ +error[E0703]: invalid ABI: found `invalid` + --> $DIR/link-invalid-abi.rs:12:8 + | +LL | extern "invalid" {} + | ^^^^^^^^^ invalid ABI + | + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions + +warning: attribute should be applied to an `extern` block with non-Rust ABI + --> $DIR/link-invalid-abi.rs:8:1 + | +LL | #[link(name = "first")] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +note: the lint level is defined here + --> $DIR/link-invalid-abi.rs:6:9 + | +LL | #![warn(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0703`. 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 a677339551153..2d3b7658f9aae 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 @@ -207,14 +207,6 @@ note: the lint level is defined here LL | #![warn(unused_attributes, unknown_lints)] | ^^^^^^^^^^^^^^^^^ -warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:5 - | -LL | #[link(name = "x")] extern "Rust" {} - | ^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - warning: the `macro_use` attribute cannot be used on crates --> $DIR/issue-43106-gating-of-builtin-attrs.rs:45:4 | @@ -978,6 +970,14 @@ LL | #[link(name = "x")] impl S { } = help: the `link` attribute can only be applied to foreign modules = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +warning: attribute should be applied to an `extern` block with non-Rust ABI + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:5 + | +LL | #[link(name = "x")] extern "Rust" {} + | ^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + warning: the `must_use` attribute cannot be used on modules --> $DIR/issue-43106-gating-of-builtin-attrs.rs:749:3 | From 0c182d66b47f8203e551f0302022bcd9ea5c5277 Mon Sep 17 00:00:00 2001 From: hizyyo Date: Sat, 12 Sep 2026 16:00:46 +0500 Subject: [PATCH 02/17] Fix finalize_check signatures --- compiler/rustc_ast_lowering/src/lib.rs | 1 - compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index efb434c921653..8513ee39855d0 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -41,7 +41,6 @@ use std::mem; use std::sync::{Arc, LazyLock}; -use rustc_abi::ExternAbi; use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::node_id::NodeMap; use rustc_ast::visit::{self, Visitor}; diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs index 30fdadf95e4ce..2acba84956e67 100644 --- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -21,7 +21,7 @@ impl NoArgsAttributeParser for NonExhaustiveParser { const STABILITY: AttributeStability = AttributeStability::Stable; const CREATE: fn(Span) -> AttributeKind = AttributeKind::NonExhaustive; - fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) { + fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { if cx.target != Target::Struct { return; } From 89da8633dd9a996e633aae359cc100a009e98ae4 Mon Sep 17 00:00:00 2001 From: hizyyo Date: Sat, 19 Sep 2026 18:23:47 +0500 Subject: [PATCH 03/17] Address link attribute finalization invariants --- .../src/attributes/link_attrs.rs | 18 +++++++++++++++--- 1 file changed, 15 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 e3e74971e99db..f4d0fa35e3f47 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -262,10 +262,22 @@ impl CombineAttributeParser for LinkParser { } fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { - let Some(item) = cx.target_item else { return }; - let ItemKind::ForeignMod(fm) = &item.kind else { return }; + if cx.target != Target::ForeignMod { + return; + } + + let item = cx.target_item.expect("missing AST target item for Target::ForeignMod"); + let ItemKind::ForeignMod(fm) = &item.kind else { + panic!("expected foreign module AST target item for Target::ForeignMod"); + }; let abi = fm.abi.map_or(ExternAbi::FALLBACK, |abi| { - abi.symbol_unescaped.as_str().parse().unwrap_or(ExternAbi::Rust) + abi.symbol_unescaped.as_str().parse().unwrap_or_else(|_| { + cx.dcx().span_delayed_bug( + abi.span, + "LinkParser::finalize_check was unable to pre-detect the ABI, so it continues to use the recovery value solely to check for unused_attributes in the lint; a user error E0703 will be reported later in lower_abi", + ); + ExternAbi::Rust + }) }); if matches!(abi, ExternAbi::Rust) { cx.emit_lint(UNUSED_ATTRIBUTES, Link, attr_span); From 6846fe9a097dd8baf0af6113272159768cb56bb9 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 24 Sep 2026 00:38:00 +1000 Subject: [PATCH 04/17] Fix `Diverges` When it was added in PR 37412 it was a simple three-value lattice type implementing `PartialOrd`/`Ord`, and also implementing `BitAnd`/`BitOr` using `min`/`max`. This all made sense. Then in PR 64592 the `Always` variant got a span and a custom note added. This makes the meaning of all those operations much murkier. And the `is_always` method gained an alarming comment: > Enum comparison ignores the contents of fields, so we just fill them > in with garbage here. This is false! Enum comparison does use the contents of fields. This commit removes the `PartialOrd`/`Ord` impls and redoes `BitAnd`/`BitOr` in a way that preserves existing behaviour without relying on `span` and `custom_note` ordering. In the `Always`/`Always` case we now always use the fields from `self`; this is potentially different to the old behaviour but in practice no test outputs are affected, and at most some error messages might be slightly different. This helps with the next commit by removing some `Span` ordering operations. --- compiler/rustc_hir_typeck/src/diverges.rs | 29 ++++++++++++++++------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/diverges.rs b/compiler/rustc_hir_typeck/src/diverges.rs index 1a10e19d0a5e9..15ce40d417af2 100644 --- a/compiler/rustc_hir_typeck/src/diverges.rs +++ b/compiler/rustc_hir_typeck/src/diverges.rs @@ -1,13 +1,13 @@ -use std::{cmp, ops}; +use std::ops; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::Span; /// Tracks whether executing a node may exit normally (versus /// return/break/panic, which "diverge", leaving dead code in their /// wake). Tracked semi-automatically (through type variables marked /// as diverging), with some manual adjustments for control-flow /// primitives (approximating a CFG). -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub(crate) enum Diverges { /// Potentially unknown, some cases converge, /// others require a CFG to determine them. @@ -40,14 +40,28 @@ pub(crate) enum Diverges { impl ops::BitAnd for Diverges { type Output = Self; fn bitand(self, other: Self) -> Self { - cmp::min(self, other) + match (self, other) { + (x @ Self::Maybe, _) => x, + (_, x @ Self::Maybe) => x, + // Using `span`/`custom_note` from `self` seems to give better error messages. + (x @ Self::Always { .. }, Self::Always { .. }) => x, + (Self::WarnedAlways, x) => x, + (x, Self::WarnedAlways) => x, + } } } impl ops::BitOr for Diverges { type Output = Self; fn bitor(self, other: Self) -> Self { - cmp::max(self, other) + match (self, other) { + (x @ Self::WarnedAlways, _) => x, + (_, x @ Self::WarnedAlways) => x, + // Using `span`/`custom_note` from `self` seems to give better error messages. + (x @ Self::Always { .. }, Self::Always { .. }) => x, + (Self::Maybe, x) => x, + (x, Self::Maybe) => x, + } } } @@ -70,9 +84,6 @@ impl Diverges { } pub(super) fn is_always(self) -> bool { - // Enum comparison ignores the - // contents of fields, so we just - // fill them in with garbage here. - self >= Diverges::Always { span: DUMMY_SP, custom_note: None } + matches!(self, Diverges::WarnedAlways | Diverges::Always { .. }) } } From 0f125fae31e2edec291b23707f0ee9eed9753202 Mon Sep 17 00:00:00 2001 From: Paul Murphy Date: Thu, 24 Sep 2026 14:07:24 -0500 Subject: [PATCH 05/17] Ensure llvm worker threads have sufficient stack space The rustc driver sets the default stack size to 16MB, however worker threads spawned by the backend will use std's default stack size (usually 2MB). Pass through the stack size chosen by the driver to the backend, and explicitly request the stack size. --- compiler/rustc_codegen_ssa/src/back/write.rs | 23 ++++++++++++++++++-- compiler/rustc_interface/src/interface.rs | 3 +++ compiler/rustc_interface/src/util.rs | 2 +- compiler/rustc_session/src/config.rs | 5 +++++ compiler/rustc_session/src/options.rs | 1 + 5 files changed, 31 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 147e4c43c7103..6f74218fc4085 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -998,6 +998,7 @@ fn do_thin_lto( exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], needs_thin_lto: Vec>, + stack_size: usize, ) -> Vec { let _timer = prof.verbose_generic_activity("LLVM_thinlto"); @@ -1088,6 +1089,7 @@ fn do_thin_lto( Arc::clone(&tm_factory), coordinator_send.clone(), item, + stack_size, ); used_token_count += 1; } @@ -1280,6 +1282,8 @@ fn start_executing_work( None }; + let stack_size = sess.opts.recommended_stack_size; + let cgcx = CodegenContext { crate_types: tcx.crate_types().to_vec(), lto: sess.lto(), @@ -1542,6 +1546,7 @@ fn start_executing_work( coordinator_send.clone(), &mut llvm_start_time, item, + stack_size, ); } } @@ -1567,6 +1572,7 @@ fn start_executing_work( coordinator_send.clone(), &mut llvm_start_time, item, + stack_size, ); } else { // There is no unstarted work, so let the main thread @@ -1610,6 +1616,7 @@ fn start_executing_work( coordinator_send.clone(), &mut llvm_start_time, item, + stack_size, ); running_with_own_token += 1; } @@ -1778,6 +1785,7 @@ fn start_executing_work( &exported_symbols_for_lto, &[], needs_thin_lto, + stack_size, )); } else { if let Some(allocator_module) = allocator_module.take() { @@ -1873,6 +1881,7 @@ fn spawn_work<'a, B: WriteBackendMethods>( coordinator_send: Sender>, llvm_start_time: &mut Option>, work: WorkItem, + stack_size: usize, ) { if llvm_start_time.is_none() { *llvm_start_time = Some(prof.verbose_generic_activity("LLVM_passes")); @@ -1906,7 +1915,11 @@ fn spawn_work<'a, B: WriteBackendMethods>( }; drop(coordinator_send.send(msg)); }; - std::thread::Builder::new().name(name).spawn(f).expect("failed to spawn work thread"); + std::thread::Builder::new() + .name(name) + .stack_size(stack_size) + .spawn(f) + .expect("failed to spawn work thread"); } fn spawn_thin_lto_work( @@ -1916,6 +1929,7 @@ fn spawn_thin_lto_work( tm_factory: TargetMachineFactoryFn, coordinator_send: Sender, work: ThinLtoWorkItem, + stack_size: usize, ) { let cgcx = cgcx.clone(); let prof = prof.clone(); @@ -1948,7 +1962,11 @@ fn spawn_thin_lto_work( }; drop(coordinator_send.send(msg)); }; - std::thread::Builder::new().name(name).spawn(f).expect("failed to spawn work thread"); + std::thread::Builder::new() + .name(name) + .stack_size(stack_size) + .spawn(f) + .expect("failed to spawn work thread"); } enum SharedEmitterMessage { @@ -2189,6 +2207,7 @@ impl OngoingCodegen { &crate_info.exported_symbols_for_lto, &crate_info.each_linked_rlib_file_for_lto, needs_thin_lto, + sess.opts.recommended_stack_size, ), allocator_module: None, } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 3e73bdbf5985f..7a6a49f37278a 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -450,6 +450,9 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se config.using_internal_features, ); + // STACK_SIZE is setup in run_in_thread_pool_with_globals, before arriving here. + sess.opts.recommended_stack_size = *util::STACK_SIZE.get().unwrap(); + let target_config = codegen_backend.target_config(&sess); // Store all of the target features in the session. diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 912f13929a349..d58b7bfddfc6d 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -21,6 +21,7 @@ use rustc_metadata::{DylibError, EncodedMetadata, load_symbol_from_dylib}; use rustc_middle::dep_graph::WorkProductMap; use rustc_middle::ty::{CurrentGcx, TyCtxt}; use rustc_query_impl::{CollectActiveJobsKind, collect_active_query_jobs}; +pub use rustc_session::config::DEFAULT_STACK_SIZE; use rustc_session::config::{ Cfg, Jobs, OutFileName, OutputFilenames, OutputTypes, Sysroot, host_tuple, }; @@ -142,7 +143,6 @@ pub(crate) fn check_abi_required_features(sess: &Session) { } pub static STACK_SIZE: OnceLock = OnceLock::new(); -pub const DEFAULT_STACK_SIZE: usize = 17 * 1024 * 1024; fn init_stack_size(early_dcx: &EarlyDiagCtxt) -> usize { // Obey the environment setting or default diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 753a4ed0d779a..798dcaf969965 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -51,6 +51,9 @@ mod native_libs; mod print_request; pub mod sigpipe; +/// A recommended stack size for worker threads spawned within a session. +pub const DEFAULT_STACK_SIZE: usize = 17 * 1024 * 1024; + /// Special CPU name requesting the CPU of the current host. pub const NATIVE_CPU: &str = "native"; @@ -1516,6 +1519,7 @@ impl Default for Options { target_modifiers: BTreeMap::default(), mitigation_coverage_map: Default::default(), jobs: Jobs { frontend: None, backend: None, linker: LinkerJobs::Default }, + recommended_stack_size: DEFAULT_STACK_SIZE, } } } @@ -3074,6 +3078,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M target_modifiers: collected_options.target_modifiers, mitigation_coverage_map: collected_options.mitigations, jobs, + recommended_stack_size: DEFAULT_STACK_SIZE, } } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 13fc598d86bfa..5333bec0d58f4 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -438,6 +438,7 @@ top_level_options!( color: ColorConfig [UNTRACKED], verbose: bool [TRACKED_NO_CRATE_HASH], jobs: Jobs [UNTRACKED], + recommended_stack_size: usize [UNTRACKED], } ); From 999b4aaa959fc886e272249c63bd6cdc85a119bf Mon Sep 17 00:00:00 2001 From: Rachel Barker Date: Thu, 17 Sep 2026 16:57:10 +0100 Subject: [PATCH 06/17] Fix maximum read/write/send length on non-{Mac, Windows} platforms On most platforms, `send` takes a `size_t` length, but returns an `ssize_t` count of bytes written. This means that the actual limit is `ssize_t::MAX`, not `size_t::MAX`. QNX has a bug on top of this, where the returned length appears to be converted to a C `int` and back, resulting in the wrong return value if the length is >= 2^31 bytes. --- library/std/src/sys/fd/unix.rs | 16 ++++++---- .../std/src/sys/net/connection/socket/mod.rs | 24 +++++++++++--- .../src/sys/net/connection/socket/tests.rs | 31 +++++++++++++++---- .../src/sys/net/connection/socket/windows.rs | 2 +- 4 files changed, 55 insertions(+), 18 deletions(-) diff --git a/library/std/src/sys/fd/unix.rs b/library/std/src/sys/fd/unix.rs index aa84f6bc28023..6ebbc6afc1661 100644 --- a/library/std/src/sys/fd/unix.rs +++ b/library/std/src/sys/fd/unix.rs @@ -72,12 +72,16 @@ pub struct FileDesc(OwnedFd); // // On Apple targets however, apparently the 64-bit libc is either buggy or // intentionally showing odd behavior by rejecting any read with a size -// larger than INT_MAX. To handle both of these the read size is capped on -// both platforms. -const READ_LIMIT: usize = if cfg!(target_vendor = "apple") { - libc::c_int::MAX as usize -} else { - libc::ssize_t::MAX as usize +// larger than INT_MAX. +// +// Meanwhile on QNX, reads/writes/sends larger than INT_MAX return the wrong +// number of bytes written (eg, writing 2^31 bytes returns (2^64 - 2^31) instead +// of the correct byte count). +const READ_LIMIT: usize = cfg_select! { + any(target_vendor = "apple", target_os = "nto", target_os = "qnx") => { + libc::c_int::MAX as usize + } + _ => libc::ssize_t::MAX as usize, }; #[cfg(any( diff --git a/library/std/src/sys/net/connection/socket/mod.rs b/library/std/src/sys/net/connection/socket/mod.rs index 4e5de0209ad24..55db60fde694d 100644 --- a/library/std/src/sys/net/connection/socket/mod.rs +++ b/library/std/src/sys/net/connection/socket/mod.rs @@ -36,8 +36,26 @@ cfg_select! { use netc as c; +// Similarly to reads (see READ_LIMIT), the `send` syscall on most platforms +// takes a `size_t` length, but returns an `ssize_t` of bytes written. So the +// actual maximum number of bytes we can send in one call is SSIZE_MAX. +// +// On Apple targets however, apparently the 64-bit libc is either buggy or +// intentionally showing odd behavior by rejecting send calls with a size +// larger than INT_MAX. So cap the send size to INT_MAX. +// +// Meanwhile on QNX, reads/writes/sends larger than INT_MAX return the wrong +// number of bytes written (eg, writing 2^31 bytes returns (2^64 - 2^31) instead +// of the correct byte count). +// +// On Windows, the relevant syscall takes an `i32` (unlike for read/write!), +// so we need to clamp to i32::MAX. const MAX_SEND_LEN: usize = - if cfg!(target_vendor = "apple") { c_int::MAX as usize } else { ::MAX as usize }; + cfg_select! { + any(target_vendor = "apple", target_os = "nto", target_os = "qnx") => c_int::MAX as usize, + target_os = "windows" => i32::MAX as usize, + _ => libc::ssize_t::MAX as usize, + }; cfg_select! { any( @@ -717,8 +735,6 @@ impl UdpSocket { self.inner.peek_from(buf) } - // `MAX_SEND_LEN` is `usize::MAX` off Apple/Windows, where the guard is a no-op. - #[allow(clippy::absurd_extreme_comparisons)] pub fn send_to(&self, buf: &[u8], dst: &SocketAddr) -> io::Result { if buf.len() > MAX_SEND_LEN { return Err(io::Error::from_raw_os_error(c::EMSGSIZE)); @@ -872,8 +888,6 @@ impl UdpSocket { self.inner.peek(buf) } - // `MAX_SEND_LEN` is `usize::MAX` off Apple/Windows, where the guard is a no-op. - #[allow(clippy::absurd_extreme_comparisons)] pub fn send(&self, buf: &[u8]) -> io::Result { if buf.len() > MAX_SEND_LEN { return Err(io::Error::from_raw_os_error(c::EMSGSIZE)); diff --git a/library/std/src/sys/net/connection/socket/tests.rs b/library/std/src/sys/net/connection/socket/tests.rs index e6f02d7a93859..cc072420b754b 100644 --- a/library/std/src/sys/net/connection/socket/tests.rs +++ b/library/std/src/sys/net/connection/socket/tests.rs @@ -18,13 +18,32 @@ fn no_lookup_host_duplicates() { ); } -// #115325: on Apple, `send` rejects a length > `c_int::MAX` with `EINVAL`, so -// the clamp must not regress to the unbounded `wrlen_t::MAX`. +// On non-Windows platforms, the maximum valid length to pass into `send` is +// not the same as the maximum of the *type* used for the length. Ensure that +// the proper maximum is used, and that we do not regress to simply clamping to +// `wrlen_t::MAX` +// +// On Apple (per 115325), `send` takes a `size_t` length, but rejects any +// length > `c_int::MAX` with `EINVAL`. +// +// On QNX, `send` with length > `c_int::MAX` returns an incorrect count of bytes +// written. +// +// On Windows, `send` takes an `i32` length and returns an `i32`. +// +// On other platforms, `send` takes a `size_t` and returns an `ssize_t`, so +// sends larger then `ssize_t::MAX` will (maybe silently) return bad lengths. #[test] fn max_send_len_within_platform_limit() { - if cfg!(target_vendor = "apple") { - assert_eq!(MAX_SEND_LEN, c_int::MAX as usize); - } else { - assert_eq!(MAX_SEND_LEN, ::MAX as usize); + cfg_select! { + any(target_vendor = "apple", target_os = "nto", target_os = "qnx") => { + assert_eq!(MAX_SEND_LEN, c_int::MAX as usize); + } + target_os = "windows" => { + assert_eq!(MAX_SEND_LEN, i32::MAX as usize); + } + _ => { + assert_eq!(MAX_SEND_LEN, libc::ssize_t::MAX as usize); + } } } diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs index 8b98d0d31e507..e9d5336001fd8 100644 --- a/library/std/src/sys/net/connection/socket/windows.rs +++ b/library/std/src/sys/net/connection/socket/windows.rs @@ -309,7 +309,7 @@ impl Socket { ) -> io::Result<(usize, SocketAddr)> { let mut storage = unsafe { mem::zeroed::() }; let mut addrlen = size_of_val(&storage) as netc::socklen_t; - let length = cmp::min(buf.len(), ::MAX as usize) as wrlen_t; + let length = cmp::min(buf.len(), super::MAX_SEND_LEN) as wrlen_t; // On unix when a socket is shut down all further reads return 0, so we // do the same on windows to map a shut down socket to returning EOF. From 4326cf73a3a45bd95c47a576fb696dea793023eb Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 23 Sep 2026 22:15:02 +1000 Subject: [PATCH 07/17] Remove `PartialOrd`/`Ord` impls for `Span`/`SpanData` `Span` and `SpanData` encode four fields: `lo`/`hi`, `ctxt`, and `parent`. `ctxt` and `parent` have unorderable types. Both types ignore `ctxt` and `parent` for `PartialOrd`/`Ord`. But their `PartialEq`/`Eq` impls do *not* ignore those fields. This eq/ord inconsistency is a bug. It was introduced in #123165. The idea of ordering spans in general is dubious, because of `ctxt` and `parent`. But the idea of ordering spans just with `lo`/`hi` is fine. Therefore, this commit does the following. - Removes the `PartialOrd`/`Ord` impls for `Span`/`SpanData` - Adds a `Span::lo_hi` method which can be used in lots of places where span locations are involved in sorting. E.g. `xs.sort_by_key(|span| span.lo_hi())` - Adds `OrdSpan`, a newtype around `Span` that impls `PartialEq`/`Eq`/`PartialOrd`/`Ord` using `lo_hi`. This is for storing spans in ordered types like `BTreeMap`. Note also that some `sort`+`dedup` combinations might not remove all duplicates with the old eq/ord inconsistency. These now all do the right thing, which could affect some error messages, though in practice nothing in the test suite is affected. --- Cargo.lock | 1 - .../rustc_attr_parsing/src/attributes/repr.rs | 9 ++-- .../src/diagnostics/conflict_errors.rs | 6 +-- .../src/diagnostics/explain_borrow.rs | 4 +- .../rustc_borrowck/src/diagnostics/mod.rs | 2 +- .../src/diagnostics/move_errors.rs | 4 +- compiler/rustc_borrowck/src/type_check/mod.rs | 2 +- compiler/rustc_error_messages/src/lib.rs | 2 +- compiler/rustc_errors/src/diagnostic.rs | 2 +- compiler/rustc_hir_analysis/src/collect.rs | 2 +- .../src/hir_ty_lowering/errors.rs | 20 ++++----- compiler/rustc_hir_typeck/src/loops.rs | 19 +++++---- .../rustc_hir_typeck/src/method/suggest.rs | 31 +++++++------- compiler/rustc_hir_typeck/src/writeback.rs | 2 +- compiler/rustc_interface/src/passes.rs | 2 +- compiler/rustc_lint/src/builtin.rs | 4 +- compiler/rustc_lint/src/non_ascii_idents.rs | 10 ++--- compiler/rustc_middle/src/mono.rs | 10 ++--- compiler/rustc_middle/src/traits/mod.rs | 24 +++++------ .../rustc_mir_build/src/check_unsafety.rs | 2 +- .../src/thir/pattern/check_match.rs | 2 +- .../src/check_call_recursion.rs | 2 +- .../src/graph_checks/statics.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 2 +- .../src/handle_cycle_error.rs | 2 +- .../rustc_resolve/src/diagnostics/impls.rs | 12 +++--- compiler/rustc_resolve/src/ident.rs | 5 ++- compiler/rustc_resolve/src/imports.rs | 6 +-- .../rustc_resolve/src/late/diagnostics.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 4 +- compiler/rustc_span/Cargo.toml | 1 - compiler/rustc_span/src/lib.rs | 35 ++++++---------- compiler/rustc_span/src/span_encoding.rs | 41 +++++++++++++++++++ .../nice_region_error/static_impl_trait.rs | 9 ++-- .../src/error_reporting/infer/region.rs | 17 +++++--- src/librustdoc/clean/inline.rs | 2 +- src/librustdoc/html/macro_expansion.rs | 2 +- .../src/disallowed_script_idents.rs | 2 +- .../clippy/clippy_lints/src/format_args.rs | 4 +- .../clippy_lints/src/implicit_hasher.rs | 10 ++--- .../src/implied_bounds_in_impls.rs | 6 ++- .../src/macro_metavars_in_unsafe.rs | 6 +-- .../clippy/clippy_lints/src/macro_use.rs | 12 +++--- .../clippy_lints/src/methods/map_unwrap_or.rs | 2 +- .../src/methods/unnecessary_fold.rs | 2 +- .../src/multiple_unsafe_ops_per_block.rs | 2 +- .../clippy_lints/src/operators/cmp_owned.rs | 2 +- .../clippy/clippy_lints/src/useless_vec.rs | 9 ++-- src/tools/miri/src/shims/foreign_items.rs | 14 +++---- 49 files changed, 210 insertions(+), 165 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5f35ce252b78e..063ee6b9850b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4819,7 +4819,6 @@ version = "0.0.0" dependencies = [ "bitflags", "blake3", - "derive-where", "indexmap", "itoa", "md-5", diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 6115ed207d98c..bc4f9d20545fc 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -4,6 +4,7 @@ use rustc_attr_ir::IntType::{SignedInt, UnsignedInt}; use rustc_attr_ir::ReprAttr; use rustc_feature::AttributeStability; use rustc_session::diagnostics::feature_err; +use rustc_span::OrdSpan; use super::prelude::*; use crate::diagnostics; @@ -272,7 +273,7 @@ fn parse_alignment(node: &LitKind, cx: &AcceptContext<'_, '_>) -> Result); +pub(crate) struct RustcAlignParser(Option<(Align, OrdSpan)>); impl RustcAlignParser { const PATH: &[Symbol] = &[sym::rustc_align]; @@ -293,7 +294,7 @@ impl RustcAlignParser { }; match parse_alignment(&lit.kind, cx) { - Ok(literal) => self.0 = Ord::max(self.0, Some((literal, cx.attr_span))), + Ok(literal) => self.0 = Ord::max(self.0, Some((literal, OrdSpan(cx.attr_span)))), Err(message) => { cx.emit_err(diagnostics::InvalidAlignmentValue { span: lit.span, @@ -318,7 +319,7 @@ impl AttributeParser for RustcAlignParser { fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option { let (align, span) = self.0?; - Some(AttributeKind::RustcAlign { align, span }) + Some(AttributeKind::RustcAlign { align, span: span.0 }) } } @@ -342,6 +343,6 @@ impl AttributeParser for RustcAlignStaticParser { fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option { let (align, span) = self.0.0?; - Some(AttributeKind::RustcAlign { align, span }) + Some(AttributeKind::RustcAlign { align, span: span.0 }) } } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index f4b2ceb850666..132f074f9e0f9 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -893,7 +893,7 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { .errors .iter() .map(|error| error.span) - .any(|sp| span < sp && !sp.contains(span)) + .any(|sp| span.lo_hi() < sp.lo_hi() && !sp.contains(span)) }) { show_assign_sugg = true; if all_init_spans.iter().any(|init_span| !init_span.contains(span)) @@ -929,7 +929,7 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { let mut shown = false; let mut shown_condition_value = false; for error in visitor.errors { - if error.span < span && !error.span.overlaps(span) { + if error.span.lo_hi() < span.lo_hi() && !error.span.overlaps(span) { // When we have a case like `match-cfg-fake-edges.rs`, we don't want to mention // match arms coming after the primary span because they aren't relevant: // ``` @@ -950,7 +950,7 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { } if !shown { for sp in &reachable_spans { - if *sp < span && !sp.overlaps(span) { + if sp.lo_hi() < span.lo_hi() && !sp.overlaps(span) { err.span_label(*sp, "binding initialized here in some conditions"); } } diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index f431374de37ba..7537e2f9f1495 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -419,8 +419,8 @@ impl<'tcx> BorrowExplanation<'tcx> { _ => None, }) .collect::>(); - preds.sort(); - preds.dedup(); + preds.sort_by_key(|span| span.lo_hi()); + preds.dedup_by_key(|span| span.lo_hi()); if !preds.is_empty() { let s = if preds.len() == 1 { "" } else { "s" }; err.span_note( diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index c8abc2689ff7f..523db527d0cf9 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -123,7 +123,7 @@ impl<'diag, 'tcx> BorrowckDiagnosticsBuffer<'diag, 'tcx> { } if !self.buffered_diags.is_empty() { - self.buffered_diags.sort_by_key(|(sort_span, _)| *sort_span); + self.buffered_diags.sort_by_key(|(sort_span, _)| sort_span.lo_hi()); for (_, diag) in self.buffered_diags.drain(..) { diag.emit(); } diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index aa62d6aaa0751..4d65410455118 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -1206,8 +1206,8 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { suggestions.push((binding_span.shrink_to_lo(), msg, "ref ".to_string())); } } - suggestions.sort_unstable_by_key(|&(span, _, _)| span); - suggestions.dedup_by_key(|&mut (span, _, _)| span); + suggestions.sort_unstable_by_key(|&(span, _, _)| span.lo_hi()); + suggestions.dedup_by_key(|&mut (span, _, _)| span.lo_hi()); for (span, msg, suggestion) in suggestions { err.span_suggestion_verbose(span, msg, suggestion, Applicability::MachineApplicable); } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index a886187783b86..b3032662fb3e4 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -318,7 +318,7 @@ impl<'tcx> MirTypeckRegionConstraints<'tcx> { /// required to hold. Normally, this is at a particular point which /// created the obligation, but for constraints that the user gave, we /// want the constraint to hold at all points. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum Locations { /// Indicates that a type constraint should always be true. This /// is particularly important in the new borrowck analysis for diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index bedcfe998b638..cb3b43aafa155 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -101,7 +101,7 @@ impl MultiSpan { } pub fn from_spans(mut vec: Vec) -> MultiSpan { - vec.sort(); + vec.sort_by_key(|span| span.lo_hi()); MultiSpan { primary_spans: vec, span_labels: vec![], span_context: vec![] } } diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 9688f99abfebb..3f879b5f2effb 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -972,7 +972,7 @@ impl<'a> Diag<'a> { .map(|(span, snippet)| SubstitutionPart { snippet, span }) .collect::>(); - parts.sort_unstable_by_key(|part| part.span); + parts.sort_unstable_by_key(|part| part.span.lo_hi()); assert!(!parts.is_empty()); debug_assert_eq!( diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 8f693221b0fd2..66605e9de6ec0 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -240,7 +240,7 @@ fn bad_placeholder<'cx, 'tcx>( ) -> Diag<'cx> { let kind = if kind.ends_with('s') { format!("{kind}es") } else { format!("{kind}s") }; - spans.sort(); + spans.sort_by_key(|span| span.lo_hi()); cx.dcx().create_err(diagnostics::PlaceholderNotAllowedItemSignatures { spans, kind }) } 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 f2cf4743d76b6..de22c157ee5d1 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::{ }; use rustc_session::diagnostics::feature_err; use rustc_span::edit_distance::find_best_match_for_name; -use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, bug, kw, sym}; +use rustc_span::{BytePos, DUMMY_SP, Ident, OrdSpan, Span, Symbol, bug, kw, sym}; use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility; use rustc_trait_selection::traits::{ FulfillmentError, dyn_compatibility_violations_for_assoc_item, @@ -943,22 +943,22 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { return err.emit_err(); } - let mut bound_spans: SortedMap> = Default::default(); + let mut bound_spans: SortedMap> = Default::default(); let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| { let msg = format!("`{}`", if obligation.len() > 50 { quiet } else { obligation }); match self_ty.kind() { // Point at the type that couldn't satisfy the bound. - ty::Adt(def, _) => { - bound_spans.get_mut_or_insert_default(tcx.def_span(def.did())).push(msg) - } + ty::Adt(def, _) => bound_spans + .get_mut_or_insert_default(OrdSpan(tcx.def_span(def.did()))) + .push(msg), // Point at the trait object that couldn't satisfy the bound. ty::Dynamic(preds, _) => { for pred in preds.iter() { match pred.skip_binder() { ty::ExistentialPredicate::Trait(tr) => { bound_spans - .get_mut_or_insert_default(tcx.def_span(tr.def_id)) + .get_mut_or_insert_default(OrdSpan(tcx.def_span(tr.def_id))) .push(msg.clone()); } ty::ExistentialPredicate::Projection(_) @@ -969,7 +969,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Point at the closure that couldn't satisfy the bound. ty::Closure(def_id, _) => { bound_spans - .get_mut_or_insert_default(tcx.def_span(*def_id)) + .get_mut_or_insert_default(OrdSpan(tcx.def_span(*def_id))) .push(format!("`{quiet}`")); } _ => {} @@ -1034,7 +1034,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); for (span, mut bounds) in bound_spans { - if !tcx.sess.source_map().is_span_accessible(span) { + if !tcx.sess.source_map().is_span_accessible(span.0) { continue; } bounds.sort(); @@ -1045,7 +1045,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { [bounds @ .., last] => format!("doesn't satisfy {} or {last}", bounds.join(", ")), [] => unreachable!(), }; - err.span_label(span, msg); + err.span_label(span.0, msg); } add_def_label(&mut err); err.emit_err() @@ -1315,7 +1315,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); } } - suggestions.sort_by_key(|&(span, _)| span); + suggestions.sort_by_key(|&(span, _)| span.lo_hi()); // There are cases where one bound points to a span within another bound's span, like when // you have code like the following (#115019), so we skip providing a suggestion in those // cases to avoid having a malformed suggestion. diff --git a/compiler/rustc_hir_typeck/src/loops.rs b/compiler/rustc_hir_typeck/src/loops.rs index 3ce6c34176101..6b1354002c943 100644 --- a/compiler/rustc_hir_typeck/src/loops.rs +++ b/compiler/rustc_hir_typeck/src/loops.rs @@ -10,7 +10,7 @@ use rustc_hir::{Destination, Node, find_attr}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_span::hygiene::DesugaringKind; -use rustc_span::{BytePos, Span, span_bug}; +use rustc_span::{BytePos, OrdSpan, Span, span_bug}; use crate::diagnostics::{ BreakInsideClosure, BreakInsideCoroutine, BreakNonLoop, ConstContinueBadLabel, @@ -79,7 +79,7 @@ struct CheckLoopVisitor<'tcx> { // such as adding a label for an `if`. // e.g. `if 'foo: {}` would be incorrect. cx_stack: Vec, - block_breaks: BTreeMap, + block_breaks: BTreeMap, } pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<'tcx>) { @@ -377,12 +377,13 @@ impl<'hir> CheckLoopVisitor<'hir> { UnlabeledBlock { label_span, wrap_end } if br_cx_kind == BreakContextKind::Break && label_span.eq_ctxt(break_span) => { - let block = self.block_breaks.entry(label_span).or_insert_with(|| BlockInfo { - name: br_cx_kind.to_string(), - spans: vec![], - suggs: vec![], - wrap_end, - }); + let block = + self.block_breaks.entry(OrdSpan(label_span)).or_insert_with(|| BlockInfo { + name: br_cx_kind.to_string(), + spans: vec![], + suggs: vec![], + wrap_end, + }); block.spans.push(span); block.suggs.push(break_span); } @@ -423,7 +424,7 @@ impl<'hir> CheckLoopVisitor<'hir> { name: &block.name, is_break: true, suggestion: Some(OutsideLoopSuggestion { - block_span: *s, + block_span: s.0, break_spans: block.suggs.clone(), block_prefix: if block.wrap_end.is_some() { "{ 'block: " } else { "'block: " }, wrap_end: block.wrap_end, diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index e074ebf01bda4..615b755c39845 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -33,7 +33,7 @@ use rustc_middle::ty::print::{ use rustc_middle::ty::{self, GenericArgKind, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::def_id::DefIdSet; use rustc_span::{ - DUMMY_SP, ErrorGuaranteed, ExpnKind, FileName, Ident, MacroKind, Span, Symbol, bug, + DUMMY_SP, ErrorGuaranteed, ExpnKind, FileName, Ident, MacroKind, OrdSpan, Span, Symbol, bug, edit_distance, kw, sym, }; use rustc_trait_selection::error_reporting::traits::DefIdOrName; @@ -890,12 +890,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { source: SelfSource<'tcx>, unsatisfied_predicates: &UnsatisfiedPredicates<'tcx>, static_candidates: &[CandidateSource], - ) -> Result<(bool, bool, bool, bool, SortedMap>), ()> { + ) -> Result<(bool, bool, bool, bool, SortedMap>), ()> { let mut restrict_type_params = false; let mut suggested_derive = false; let mut unsatisfied_bounds = false; let mut custom_span_label = !static_candidates.is_empty(); - let mut bound_spans: SortedMap> = Default::default(); + let mut bound_spans: SortedMap> = Default::default(); let tcx = self.tcx; if item_ident.name == sym::count && self.is_slice_ty(rcvr_ty, span) { @@ -1137,7 +1137,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rcvr_ty: Ty<'tcx>, item_ident: Ident, item_kind: &str, - bound_spans: SortedMap>, + bound_spans: SortedMap>, unsatisfied_predicates: &UnsatisfiedPredicates<'tcx>, ) { let mut ty_span = match rcvr_ty.kind() { @@ -1179,6 +1179,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None }; for (span, mut bounds) in bound_spans { + let span = span.0; if !self.tcx.sess.source_map().is_span_accessible(span) { continue; } @@ -1715,7 +1716,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { suggested_derive: &mut bool, unsatisfied_bounds: &mut bool, custom_span_label: &mut bool, - bound_spans: &mut SortedMap>, + bound_spans: &mut SortedMap>, ) { let tcx = self.tcx; let rcvr_ty_str = self.tcx.short_string(rcvr_ty, err.long_ty_path()); @@ -1800,16 +1801,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let msg = format!("`{}`", if obligation.len() > 50 { quiet } else { obligation }); match self_ty.kind() { // Point at the type that couldn't satisfy the bound. - ty::Adt(def, _) => { - bound_spans.get_mut_or_insert_default(tcx.def_span(def.did())).push(msg) - } + ty::Adt(def, _) => bound_spans + .get_mut_or_insert_default(OrdSpan(tcx.def_span(def.did()))) + .push(msg), // Point at the trait object that couldn't satisfy the bound. ty::Dynamic(preds, _) => { for pred in preds.iter() { match pred.skip_binder() { ty::ExistentialPredicate::Trait(tr) => { bound_spans - .get_mut_or_insert_default(tcx.def_span(tr.def_id)) + .get_mut_or_insert_default(OrdSpan(tcx.def_span(tr.def_id))) .push(msg.clone()); } ty::ExistentialPredicate::Projection(_) @@ -1820,7 +1821,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Point at the closure that couldn't satisfy the bound. ty::Closure(def_id, _) => { bound_spans - .get_mut_or_insert_default(tcx.def_span(*def_id)) + .get_mut_or_insert_default(OrdSpan(tcx.def_span(*def_id))) .push(format!("`{quiet}`")); } _ => {} @@ -2030,7 +2031,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } let mut spanned_predicates: Vec<_> = spanned_predicates.into_iter().collect(); - spanned_predicates.sort_by_key(|(span, _)| *span); + spanned_predicates.sort_by_key(|(span, _)| span.lo_hi()); for (_, (primary_spans, span_labels, predicates)) in spanned_predicates { let mut tracker = TraitBoundDuplicateTracker::new(); let mut all_trait_bounds_for_rcvr = true; @@ -3572,7 +3573,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, trait_pred: ty::TraitClause<'tcx>, adt: ty::AdtDef<'tcx>, - ) -> Option> { + ) -> Option> { let diagnostic_name = self.tcx.get_diagnostic_name(trait_pred.def_id())?; let can_derive = match diagnostic_name { @@ -3610,7 +3611,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut derives = Vec::new(); let self_name = self_ty.to_string(); - let self_span = self.tcx.def_span(adt.did()); + let self_span = OrdSpan(self.tcx.def_span(adt.did())); for super_trait in supertraits(self.tcx, ty::Binder::dummy(trait_pred.trait_ref)) { if let Some(parent_diagnostic_name) = self.tcx.get_diagnostic_name(super_trait.def_id()) @@ -3628,7 +3629,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, err: &mut Diag<'_>, unsatisfied_predicates: &UnsatisfiedPredicates<'tcx>, - ) -> Vec<(String, Span, Symbol)> { + ) -> Vec<(String, OrdSpan, Symbol)> { let mut derives = Vec::new(); let mut traits = Vec::new(); for (pred, _, _) in unsatisfied_predicates { @@ -3692,7 +3693,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { continue; } } - derives_grouped.push((self_name, self_span, trait_name.to_string())); + derives_grouped.push((self_name, self_span.0, trait_name.to_string())); } for (self_name, self_span, traits) in &derives_grouped { diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 5ae65ad26f916..c19c25228fb42 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -499,7 +499,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } if !errors_buffer.is_empty() { - errors_buffer.sort_by_key(|diag| diag.span.primary_span()); + errors_buffer.sort_by_key(|diag| diag.span.primary_span().map(Span::lo_hi)); for err in errors_buffer { err.emit(); } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 610eb5fd099d2..f21888b1de5e0 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -434,7 +434,7 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) { // Gate identifiers containing invalid Unicode codepoints that were recovered during lexing. sess.psess.bad_unicode_identifiers.with_lock(|identifiers| { for (ident, mut spans) in identifiers.drain(..) { - spans.sort(); + spans.sort_by_key(|span| span.lo_hi()); if ident == sym::ferris { enum FerrisFix { SnakeCase, diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index bba993ee3f052..0688dcf2fcaf2 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2163,8 +2163,8 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { // Due to macros, there might be several predicates with the same span // and we only want to suggest removing them once. - lint_spans.sort_unstable(); - lint_spans.dedup(); + lint_spans.sort_unstable_by_key(|span| span.lo_hi()); + lint_spans.dedup_by_key(|span| span.lo_hi()); cx.emit_span_lint( EXPLICIT_OUTLIVES_REQUIREMENTS, diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs index 416b8717a7dc3..588a9e1130f76 100644 --- a/compiler/rustc_lint/src/non_ascii_idents.rs +++ b/compiler/rustc_lint/src/non_ascii_idents.rs @@ -2,7 +2,7 @@ use rustc_ast as ast; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::UnordMap; use rustc_lint_defs::{declare_lint, declare_lint_pass}; -use rustc_span::Symbol; +use rustc_span::{OrdSpan, Symbol}; use unicode_security::general_security_profile::IdentifierType; use crate::diagnostics::{ @@ -180,7 +180,7 @@ impl EarlyLintPass for NonAsciiIdents { // We will soon sort, so the initial order does not matter. #[allow(rustc::potential_query_instability)] let mut symbols: Vec<_> = symbols.iter().collect(); - symbols.sort_by_key(|k| k.1); + symbols.sort_by_key(|k| k.1.lo_hi()); for &(ref symbol, &sp) in symbols.iter() { let symbol_str = symbol.as_str(); if symbol_str.is_ascii() { @@ -342,7 +342,7 @@ impl EarlyLintPass for NonAsciiIdents { .collect::>(); // we're sorting the output here. - let mut lint_reports: BTreeMap<(Span, Vec), AugmentedScriptSet> = + let mut lint_reports: BTreeMap<(OrdSpan, Vec), AugmentedScriptSet> = BTreeMap::new(); // The end result is put in `lint_reports` which is sorted. @@ -368,7 +368,7 @@ impl EarlyLintPass for NonAsciiIdents { // We sort primitive chars here and can use unstable sort ch_list.sort_unstable(); ch_list.dedup(); - lint_reports.insert((sp, ch_list), augment_script_set); + lint_reports.insert((OrdSpan(sp), ch_list), augment_script_set); } for ((sp, ch_list), script_set) in lint_reports { @@ -382,7 +382,7 @@ impl EarlyLintPass for NonAsciiIdents { } cx.emit_span_lint( MIXED_SCRIPT_CONFUSABLES, - sp, + sp.0, MixedScriptConfusables { set: script_set.to_string(), includes }, ); } diff --git a/compiler/rustc_middle/src/mono.rs b/compiler/rustc_middle/src/mono.rs index a54ca4faf81ee..cf567fa1c8999 100644 --- a/compiler/rustc_middle/src/mono.rs +++ b/compiler/rustc_middle/src/mono.rs @@ -15,7 +15,7 @@ use rustc_hir::ItemId; use rustc_hir::def_id::{CrateNum, DefId, DefIdSet, LOCAL_CRATE}; use rustc_macros::{StableHash, TyDecodable, TyEncodable}; use rustc_session::config::OptLevel; -use rustc_span::{Span, Symbol}; +use rustc_span::{OrdSpan, Span, Symbol}; use rustc_target::spec::SymbolVisibility; use tracing::debug; @@ -528,7 +528,7 @@ impl<'tcx> CodegenUnit<'tcx> { // The codegen tests rely on items being process in the same order as // they appear in the file, so for local items, we sort by span first #[derive(PartialEq, Eq, PartialOrd, Ord)] - struct ItemSortKey<'tcx>(Option, SymbolName<'tcx>); + struct ItemSortKey<'tcx>(Option, SymbolName<'tcx>); // We only want to take HirIds of user-defines instances into account. // The others don't matter for the codegen tests and can even make item @@ -560,9 +560,9 @@ impl<'tcx> CodegenUnit<'tcx> { } fn item_sort_key<'tcx>(tcx: TyCtxt<'tcx>, item: MonoItem<'tcx>) -> ItemSortKey<'tcx> { ItemSortKey( - local_item_id(item) - .map(|def_id| tcx.def_span(def_id).find_ancestor_not_from_macro()) - .flatten(), + local_item_id(item).and_then(|def_id| { + tcx.def_span(def_id).find_ancestor_not_from_macro().map(OrdSpan) + }), item.symbol_name(tcx), ) } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 5520b059f5678..828a1ee79a06b 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -21,7 +21,7 @@ use rustc_macros::{ Decodable, Encodable, StableHash, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, }; use rustc_span::def_id::{CRATE_DEF_ID, LocalDefId}; -use rustc_span::{DUMMY_SP, Span, Symbol, sym}; +use rustc_span::{DUMMY_SP, OrdSpan, Span, Symbol, sym}; use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; @@ -863,15 +863,15 @@ impl DynCompatibilityViolation { | Self::SupertraitConst(_) => DynCompatibilityViolationSolution::None, Self::Method( name, - MethodViolation::StaticMethod(Some((add_self_sugg, make_sized_sugg))), + MethodViolation::StaticMethod(Some(((add_s, add_sp), (make_s, make_sp)))), _, ) => DynCompatibilityViolationSolution::AddSelfOrMakeSized { name: *name, - add_self_sugg: add_self_sugg.clone(), - make_sized_sugg: make_sized_sugg.clone(), + add_self_sugg: (add_s.clone(), OrdSpan(*add_sp)), + make_sized_sugg: (make_s.clone(), OrdSpan(*make_sp)), }, Self::Method(name, MethodViolation::UndispatchableReceiver(Some((span, lt))), _) => { - DynCompatibilityViolationSolution::ChangeToRefSelf(*name, *span, *lt) + DynCompatibilityViolationSolution::ChangeToRefSelf(*name, OrdSpan(*span), *lt) } Self::Method(name, ..) | Self::AssocConst(name, ..) | Self::GenericAssocTy(name, _) => { DynCompatibilityViolationSolution::MoveToAnotherTrait(*name) @@ -901,15 +901,15 @@ impl DynCompatibilityViolation { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum DynCompatibilityViolationSolution { None, AddSelfOrMakeSized { name: Symbol, - add_self_sugg: (String, Span), - make_sized_sugg: (String, Span), + add_self_sugg: (String, OrdSpan), + make_sized_sugg: (String, OrdSpan), }, - ChangeToRefSelf(Symbol, Span, Symbol), + ChangeToRefSelf(Symbol, OrdSpan, Symbol), MoveToAnotherTrait(Symbol), } @@ -923,7 +923,7 @@ impl DynCompatibilityViolationSolution { make_sized_sugg, } => { err.span_suggestion_verbose( - add_self_sugg.1, + add_self_sugg.1.0, format!( "consider turning `{name}` into a method by giving it a `&self` argument, \ so that it is accessible through the trait object's vtable", @@ -932,7 +932,7 @@ impl DynCompatibilityViolationSolution { Applicability::MaybeIncorrect, ); err.span_suggestion_verbose( - make_sized_sugg.1, + make_sized_sugg.1.0, format!( "alternatively, consider constraining `{name}` so it is explicitly marked \ as not applying to trait objects", @@ -943,7 +943,7 @@ impl DynCompatibilityViolationSolution { } DynCompatibilityViolationSolution::ChangeToRefSelf(name, span, lt) => { err.span_suggestion_verbose( - span, + span.0, format!("consider changing method `{name}`'s `self` parameter to be `&self`"), format!("&{lt}{}self", if lt != sym::empty { " " } else { "" }), Applicability::MachineApplicable, diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index e8cc5dc0edfd3..eebdabd4e7300 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -1104,7 +1104,7 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) { // Visit the body. visitor.visit_expr(&thir[expr]); - warnings.sort_by_key(|w| w.block_span); + warnings.sort_by_key(|w| w.block_span.lo_hi()); for UnusedUnsafeWarning { hir_id, block_span, enclosing_unsafe } in warnings { let block_span = tcx.sess.source_map().guess_head_span(block_span); tcx.emit_node_span_lint( 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 381ebdcc15037..8fa5a10a9100b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -412,7 +412,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { { let mut redundant_subpats = redundant_subpats.clone(); // Emit lints in the order in which they occur in the file. - redundant_subpats.sort_unstable_by_key(|(pat, _)| pat.data().span); + redundant_subpats.sort_unstable_by_key(|(pat, _)| pat.data().span.lo_hi()); for (pat, explanation) in redundant_subpats { report_unreachable_pattern(cx, arm.arm_data, pat, &explanation, None) } diff --git a/compiler/rustc_mir_transform/src/check_call_recursion.rs b/compiler/rustc_mir_transform/src/check_call_recursion.rs index 9627f8988f283..c90d230a19ffb 100644 --- a/compiler/rustc_mir_transform/src/check_call_recursion.rs +++ b/compiler/rustc_mir_transform/src/check_call_recursion.rs @@ -79,7 +79,7 @@ fn check_recursion<'tcx>( return; } - vis.reachable_recursive_calls.sort(); + vis.reachable_recursive_calls.sort_by_key(|span| span.lo_hi()); let sp = tcx.def_span(def_id); let hir_id = tcx.local_def_id_to_hir_id(def_id); diff --git a/compiler/rustc_monomorphize/src/graph_checks/statics.rs b/compiler/rustc_monomorphize/src/graph_checks/statics.rs index 4a6416843fded..e954077f27972 100644 --- a/compiler/rustc_monomorphize/src/graph_checks/statics.rs +++ b/compiler/rustc_monomorphize/src/graph_checks/statics.rs @@ -100,7 +100,7 @@ pub(super) fn check_static_initializers_are_acyclic<'tcx, 'a, 'b>( // 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()])); + nodes.sort_by_key(|node| tcx.def_span(statics[node.index()]).lo_hi()); let head_def = statics[nodes[0].index()]; let head_span = tcx.def_span(head_def); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 4926ec9872d3b..9d05a4d7ca89a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1210,7 +1210,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if !reprs.is_empty() { let sorted_reprs = { let mut to_sort = reprs.to_owned(); - to_sort.sort_unstable(); + to_sort.sort_unstable_by_key(|(attr, span)| (*attr, span.lo_hi())); to_sort }; diff --git a/compiler/rustc_query_impl/src/handle_cycle_error.rs b/compiler/rustc_query_impl/src/handle_cycle_error.rs index 83e95b9195580..3f70fc2a6b833 100644 --- a/compiler/rustc_query_impl/src/handle_cycle_error.rs +++ b/compiler/rustc_query_impl/src/handle_cycle_error.rs @@ -223,7 +223,7 @@ fn recursive_type_error( let start_index = item_and_field_ids .iter() .enumerate() - .min_by_key(|&(_, &(id, _))| tcx.def_span(id)) + .min_by_key(|&(_, &(id, _))| tcx.def_span(id).lo_hi()) .unwrap() .0; item_and_field_ids.rotate_left(start_index); diff --git a/compiler/rustc_resolve/src/diagnostics/impls.rs b/compiler/rustc_resolve/src/diagnostics/impls.rs index 331c948c66403..29802b0db0264 100644 --- a/compiler/rustc_resolve/src/diagnostics/impls.rs +++ b/compiler/rustc_resolve/src/diagnostics/impls.rs @@ -346,9 +346,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.lint_buffer.buffer_lint( MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, CRATE_NODE_ID, - span_use, + span_use.0, diagnostics::MacroExpandedMacroExportsAccessedByAbsolutePaths { - definition: span_def, + definition: span_def.0, }, ); } @@ -943,11 +943,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let BindingError { name, target, origin, could_be_path } = binding_error; let mut target_sp = target.iter().map(|pat| pat.span).collect::>(); - target_sp.sort(); - target_sp.dedup(); + target_sp.sort_by_key(|sp| sp.lo_hi()); + target_sp.dedup_by_key(|sp| sp.lo_hi()); let mut origin_sp = origin.iter().map(|(span, _)| *span).collect::>(); - origin_sp.sort(); - origin_sp.dedup(); + origin_sp.sort_by_key(|sp| sp.lo_hi()); + origin_sp.dedup_by_key(|sp| sp.lo_hi()); let msp = MultiSpan::from_spans(target_sp.clone()); let mut err = self.dcx().create_err(diagnostics::VariableIsNotBoundInAllPatterns { diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 9faedfeac571b..5b6bf203501f7 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -10,7 +10,7 @@ use rustc_middle::middle::resolve::PartialRes; use rustc_session::diagnostics::feature_err; use rustc_span::edition::Edition; use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext}; -use rustc_span::{Ident, Span, bug, kw, span_bug, sym}; +use rustc_span::{Ident, OrdSpan, Span, bug, kw, span_bug, sym}; use smallvec::SmallVec; use tracing::{debug, instrument}; @@ -1393,7 +1393,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && let DeclKind::Import { import, .. } = binding.kind && matches!(import.kind, ImportKind::MacroExport) { - self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); + self.macro_expanded_macro_export_errors + .insert((OrdSpan(path_span), OrdSpan(binding.span))); } self.record_use(ident, binding, used); diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index a19207d6fbacc..718b9e7305521 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -20,7 +20,7 @@ use rustc_middle::ty::Visibility; use rustc_session::diagnostics::feature_err; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::LocalExpnId; -use rustc_span::{Ident, Span, Symbol, kw, span_bug, sym}; +use rustc_span::{Ident, OrdSpan, Span, Symbol, kw, span_bug, sym}; use tracing::debug; use crate::Namespace::{self, *}; @@ -1757,7 +1757,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && !other_binding.is_ambiguity_recursive(); if is_redundant { redundant_span[ns] = - Some((other_binding.span, other_binding.is_import())); + Some((OrdSpan(other_binding.span), other_binding.is_import())); } } Err(_) => is_redundant = false, @@ -1777,7 +1777,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let ident = source; let subs = redundant_spans .into_iter() - .map(|(span, is_imported)| match (span.is_dummy(), is_imported) { + .map(|(OrdSpan(span), is_imported)| match (span.is_dummy(), is_imported) { (false, true) => { diagnostics::RedundantImportSub::ImportedHere { span, ident } } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 3dbb1b7fff662..f39cbc911edfe 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -113,7 +113,7 @@ fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, Str } /// Description of an elided lifetime. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] pub(super) struct MissingLifetime { /// Used to overwrite the resolution with the suggestion, to avoid cascading errors. pub id: NodeId, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index a913149733614..74ff5e3868e44 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -69,7 +69,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::{self, RegisteredTools, TyCtxt, TyCtxtFeed, Visibility}; use rustc_span::def_id::{LocalModId, ModId}; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency}; -use rustc_span::{DUMMY_SP, Ident, Span, Symbol, bug, kw, span_bug, sym}; +use rustc_span::{DUMMY_SP, Ident, OrdSpan, Span, Symbol, bug, kw, span_bug, sym}; use rustc_structures::CrateType; use smallvec::{SmallVec, smallvec}; use tracing::{debug, instrument}; @@ -1431,7 +1431,7 @@ pub struct Resolver<'ra, 'tcx> { /// Visibility path resolution failures are delayed until all modules are collected. delayed_vis_resolution_errors: Vec> = Vec::new(), /// Crate-local macro expanded `macro_export` referred to by a module-relative path. - macro_expanded_macro_export_errors: BTreeSet<(Span, Span)> = BTreeSet::new(), + macro_expanded_macro_export_errors: BTreeSet<(OrdSpan, OrdSpan)> = BTreeSet::new(), arenas: &'ra WorkerLocal>, dummy_decl: Decl<'ra>, diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index 7889e53315361..f8e5e2b48b5f0 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -7,7 +7,6 @@ edition = "2024" # tidy-alphabetical-start bitflags = "2.4.1" blake3 = "1.5.2" -derive-where = "1.2.7" indexmap = { version = "2.0.0" } itoa = "1.0" md5 = { package = "md-5", version = "0.10.0" } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 20950c1a5ff87..b03c70726f1b8 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -32,7 +32,6 @@ // this crate without this line making `rustc_span` available. extern crate self as rustc_span; -use derive_where::derive_where; use rustc_data_structures::stable_hash::StableHashCtxt; use rustc_data_structures::{AtomicRef, outline}; use rustc_macros::{Decodable, Encodable, StableHash}; @@ -60,7 +59,7 @@ pub mod def_id; use def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE, LocalDefId, StableCrateId}; pub mod edit_distance; mod span_encoding; -pub use span_encoding::{DUMMY_SP, Span}; +pub use span_encoding::{DUMMY_SP, OrdSpan, Span}; pub mod symbol; pub use symbol::{ @@ -74,7 +73,6 @@ pub mod profiling; pub mod macros; use std::borrow::Cow; -use std::cmp::{self, Ordering}; use std::fmt::Display; use std::hash::Hash; use std::io::{self, Read}; @@ -82,7 +80,7 @@ use std::ops::{Add, Range, Sub}; use std::path::{Path, PathBuf}; use std::str::FromStr; use std::sync::Arc; -use std::{fmt, iter}; +use std::{cmp, fmt, iter}; pub use macros::{bug, span_bug}; use md5::{Digest, Md5}; @@ -684,22 +682,20 @@ impl FileName { /// sent to other threads, but some pieces of performance infra run in a separate thread. /// Using `Span` is generally preferred. #[derive(Clone, Copy, Hash, PartialEq, Eq)] -#[derive_where(PartialOrd, Ord)] pub struct SpanData { pub lo: BytePos, pub hi: BytePos, /// Information about where the macro came from, if this piece of /// code was created by a macro expansion. - #[derive_where(skip)] - // `SyntaxContext` does not implement `Ord`. - // The other fields are enough to determine in-file order. pub ctxt: SyntaxContext, - #[derive_where(skip)] - // `LocalDefId` does not implement `Ord`. - // The other fields are enough to determine in-file order. pub parent: Option, } +// `SyntaxContext` and `LocalDefId` aren't orderable. See the equivalent negative impls for `Span` +// for more details. +impl !PartialOrd for SpanData {} +impl !Ord for SpanData {} + impl SpanData { #[inline] pub fn span(&self) -> Span { @@ -740,17 +736,6 @@ impl Default for SpanData { } } -impl PartialOrd for Span { - fn partial_cmp(&self, rhs: &Self) -> Option { - Some(self.cmp(rhs)) - } -} -impl Ord for Span { - fn cmp(&self, rhs: &Self) -> Ordering { - Ord::cmp(&self.data(), &rhs.data()) - } -} - impl Span { #[inline] pub fn lo(self) -> BytePos { @@ -773,6 +758,12 @@ impl Span { self.map_ctxt(|_| ctxt) } + #[inline] + pub fn lo_hi(self) -> (BytePos, BytePos) { + let data = self.data(); + (data.lo, data.hi) + } + #[inline] pub fn is_visible(self, sm: &SourceMap) -> bool { !self.is_dummy() && sm.is_span_accessible(self) diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index 64280d5ce4b5e..af6f219b4e58e 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -1,3 +1,6 @@ +use std::cmp::Ordering; +use std::hash::Hash; + use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::stable_hash::RawSpan; // This code is very hot and uses lots of arithmetic, avoid overflow checks for performance. @@ -85,6 +88,12 @@ pub struct Span { ctxt_or_parent_or_marker: u16, } +// `SyntaxContext` (`SpanData::ctxt`) and `LocalDefId` (within `SpanData::parent`) aren't orderable. +// If you want to order spans just on `lo`/`hi`, use explicit comparisons involving `Span::lo_hi`. +// Or you can wrap your span within `OrdSpan` which impls `PartialOrd`/`Ord` via `Span::lo_hi`. +impl !PartialOrd for Span {} +impl !Ord for Span {} + // Convenience structures for all span formats. #[derive(Clone, Copy)] struct InlineCtxt { @@ -456,6 +465,38 @@ impl Span { } } +/// Span wrapper that provides equality and ordering based only on the `lo`/`hi` fields. Exists +/// because `Span` doesn't impl `PartialOrd`/`Ord` due to the `ctxt` and `parent` fields being +/// unorderable. Useful when storing things in source code order, e.g. in a `BTreeMap`. +#[derive(Clone, Copy, Debug)] +pub struct OrdSpan(pub Span); + +impl PartialEq for OrdSpan { + fn eq(&self, rhs: &Self) -> bool { + // Ignores `ctxt` and `parent` because they are unorderable. + self.0.lo_hi() == rhs.0.lo_hi() + } +} + +impl Eq for OrdSpan {} + +impl PartialOrd for OrdSpan { + fn partial_cmp(&self, rhs: &Self) -> Option { + Some(self.cmp(rhs)) + } +} + +impl Ord for OrdSpan { + fn cmp(&self, rhs: &Self) -> Ordering { + // Ignores `ctxt` and `parent` because they are unorderable. + self.0.lo_hi().cmp(&rhs.0.lo_hi()) + } +} + +// `OrdSpan` is typically stored in types that rely on ordering, such as `BTreeMap` or `SortedMap`. +// Hashing shouldn't be necessary. +impl !Hash for OrdSpan {} + #[derive(Default)] pub(crate) struct SpanInterner { spans: FxIndexSet, diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs index 166c320cda28a..e79a05328f132 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs @@ -73,16 +73,17 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { if mention_influencer { spans.push(sup_origin.span()); } - // We dedup the spans *ignoring* expansion context. - spans.sort(); - spans.dedup_by_key(|span| (span.lo(), span.hi())); + // We sort and dedup the spans *ignoring* expansion context. + spans.sort_by_key(|span| span.lo_hi()); + spans.dedup_by_key(|span| span.lo_hi()); // We try to make the output have fewer overlapping spans if possible. let require_span = if sup_origin.span().overlaps(return_sp) { sup_origin.span() } else { return_sp }; let spans_empty = spans.is_empty(); - let require_as_note = spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp); + let require_as_note = + spans.iter().any(|sp| sp.overlaps(return_sp) || sp.lo_hi() > return_sp.lo_hi()); let bound = if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin { Some(*bound) } else { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index b9f70cea5f5ab..59ce72eef48fc 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -210,12 +210,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; // sort the errors by span, for better error message stability. - errors.sort_by_key(|u| match *u { - RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(), - RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(), - RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _, _) => rvo.span(), - RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(), - RegionResolutionError::CannotNormalize(_, ref sro) => sro.span(), + errors.sort_by_key(|u| { + match *u { + RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(), + RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(), + RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _, _) => rvo.span(), + RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => { + rvo.span() + } + RegionResolutionError::CannotNormalize(_, ref sro) => sro.span(), + } + .lo_hi() }); errors } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 2fbfae88918a0..b55c9acdf5b15 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -346,7 +346,7 @@ pub(super) fn build_function(cx: &mut DocContext<'_>, def_id: DefId) -> Box ExpandedCodeVisitor<'ast> { } fn compute_expanded(mut self) -> FxHashMap> { - self.expanded_codes.sort_unstable_by(|item1, item2| item1.span.cmp(&item2.span)); + self.expanded_codes.sort_unstable_by_key(|item| item.span.lo_hi()); let mut expanded: FxHashMap> = FxHashMap::default(); for ExpandedCodeInfo { span, code, original_span, .. } in self.expanded_codes { if let Ok(lines) = self.source_map.span_to_lines(span) diff --git a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs index 93f079f7351db..fe0e8c98b46e0 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs @@ -77,7 +77,7 @@ impl EarlyLintPass for DisallowedScriptIdents { // Sort by `Span` so that error messages make sense with respect to the // order of identifier locations in the code. let mut symbols: Vec<_> = symbols.iter().collect(); - symbols.sort_unstable_by_key(|k| k.1); + symbols.sort_unstable_by_key(|k| k.1.lo_hi()); for &(symbol, &span) in &symbols { // Note: `symbol.as_str()` is an expensive operation, thus should not be called diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs index 22be9d8367daa..a072e3dfff503 100644 --- a/src/tools/clippy/clippy_lints/src/format_args.rs +++ b/src/tools/clippy/clippy_lints/src/format_args.rs @@ -610,8 +610,8 @@ impl<'tcx> FormatArgsExpr<'_, 'tcx> { .any(|(span, _)| self.cx.sess().source_map().is_multiline(*span)); // Suggest removing each argument only once, for example in `format!("{0} {0}", arg)`. - fixes.sort_unstable_by_key(|(span, _)| *span); - fixes.dedup_by_key(|(span, _)| *span); + fixes.sort_unstable_by_key(|(span, _)| span.lo_hi()); + fixes.dedup_by_key(|(span, _)| span.lo_hi()); span_lint_and_then( self.cx, diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs index 02f8170fedc27..b511caf6b5299 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs @@ -9,7 +9,7 @@ use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass, declare_lint_pass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{Ty, TypeckResults}; -use rustc_span::Span; +use rustc_span::{OrdSpan, Span}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{IntoSpan as _, SpanExt as _, snippet, snippet_with_context}; @@ -94,7 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { format!("{}<{}, S>", target.type_name(), target.type_arguments()), ), ]; - suggestions.extend(vis.suggestions); + suggestions.extend(vis.suggestions.into_iter().map(|(span, s)| (span.0, s))); diag.multipart_suggestion( "add a type parameter for `BuildHasher`", @@ -295,7 +295,7 @@ struct ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> { cx: &'a LateContext<'tcx>, maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>, target: &'b ImplicitHasherType<'tcx>, - suggestions: BTreeMap, + suggestions: BTreeMap, } impl<'a, 'b, 'tcx> ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> { @@ -337,7 +337,7 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> { match method.ident.name { sym::new => { - self.suggestions.insert(e.span, format!("{container_name}::default()")); + self.suggestions.insert(OrdSpan(e.span), format!("{container_name}::default()")); }, sym::with_capacity => { let (arg_snippet, _) = snippet_with_context( @@ -350,7 +350,7 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> { &mut Applicability::MaybeIncorrect, ); self.suggestions.insert( - e.span, + OrdSpan(e.span), format!("{container_name}::with_capacity_and_hasher({arg_snippet}, Default::default())"), ); }, diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs index 73e430fa08d6b..8b6c99cc122c9 100644 --- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs +++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs @@ -1,3 +1,5 @@ +use std::cmp::max_by_key; + use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use rustc_errors::{Applicability, SuggestionStyle}; @@ -96,7 +98,9 @@ fn emit_lint( // `<>` needs to be added if there aren't yet any generic arguments or constraints let needs_angle_brackets = bound.args.is_empty() && bound.constraints.is_empty(); let insert_span = match (bound.args, bound.constraints) { - ([.., arg], [.., constraint]) => arg.span().max(constraint.span).shrink_to_hi(), + ([.., arg], [.., constraint]) => { + max_by_key(arg.span(), constraint.span, |span| span.lo_hi()).shrink_to_hi() + } ([.., arg], []) => arg.span().shrink_to_hi(), ([], [.., constraint]) => constraint.span.shrink_to_hi(), ([], []) => bound.span.shrink_to_hi(), diff --git a/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs b/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs index 8242c383140a6..82af5d67e6f23 100644 --- a/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs +++ b/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs @@ -7,7 +7,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_stmt}; use rustc_hir::{BlockCheckMode, Expr, ExprKind, HirId, Stmt, UnsafeSource}; use rustc_lint::{LateContext, LateLintPass, LintContext as _, impl_lint_pass}; -use rustc_span::{Span, SyntaxContext}; +use rustc_span::{OrdSpan, Span, SyntaxContext}; use std::collections::BTreeMap; use std::collections::btree_map::Entry; @@ -106,7 +106,7 @@ pub struct ExprMetavarsInUnsafe { /// } /// } /// ``` - metavar_expns: BTreeMap, + metavar_expns: BTreeMap, } impl ExprMetavarsInUnsafe { @@ -180,7 +180,7 @@ impl<'tcx> Visitor<'tcx> for BodyVisitor<'_, 'tcx> { } else if ctxt.is_root() && self.expn_depth > 0 { let unsafe_block = self.macro_unsafe_blocks.last().copied(); - match (self.lint.metavar_expns.entry(e.span), unsafe_block) { + match (self.lint.metavar_expns.entry(OrdSpan(e.span)), unsafe_block) { (Entry::Vacant(e), None) => { e.insert(MetavarState::ReferencedInSafe); }, diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs index 6f06e8665decc..9efc3b2edb515 100644 --- a/src/tools/clippy/clippy_lints/src/macro_use.rs +++ b/src/tools/clippy/clippy_lints/src/macro_use.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{self as hir, AmbigArg}; use rustc_lint::{LateContext, LateLintPass, LintContext as _, impl_lint_pass}; -use rustc_span::Span; +use rustc_span::{OrdSpan, Span}; use rustc_span::edition::Edition; use std::collections::BTreeMap; @@ -151,7 +151,7 @@ impl LateLintPass<'_> for MacroUseImports { if !check_dup.contains(&(*item).to_string()) { used.entry(( (*root).to_string(), - span, + OrdSpan(*span), hir_id.local_id, cx.tcx.def_path_hash(hir_id.owner.def_id.into()), )) @@ -175,7 +175,7 @@ impl LateLintPass<'_> for MacroUseImports { .collect::>(); used.entry(( (*root).to_string(), - span, + OrdSpan(*span), hir_id.local_id, cx.tcx.def_path_hash(hir_id.owner.def_id.into()), )) @@ -187,7 +187,7 @@ impl LateLintPass<'_> for MacroUseImports { let rest = rest.to_vec(); used.entry(( (*root).to_string(), - span, + OrdSpan(*span), hir_id.local_id, cx.tcx.def_path_hash(hir_id.owner.def_id.into()), )) @@ -215,11 +215,11 @@ impl LateLintPass<'_> for MacroUseImports { cx, MACRO_USE_IMPORTS, *hir_id, - *span, + span.0, "`macro_use` attributes are no longer needed in the Rust 2018 edition", |diag| { diag.span_suggestion( - *span, + span.0, "remove the attribute and import the macro directly, try", format!("use {import};"), Applicability::MaybeIncorrect, diff --git a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs index b58ceb263be22..7dfe8202a12d4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs @@ -187,7 +187,7 @@ impl<'tcx> Visitor<'tcx> for ReferenceVisitor<'_, 'tcx> { // 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 + if expr.span.lo_hi() < self.unwrap_or_span.lo_hi() && let ExprKind::Path(ref path) = expr.kind && let QPath::Resolved(_, path) = path && let Res::Local(local_id) = path.res diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs index edb1c9c53ded7..c7207bb4dd4bc 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs @@ -373,7 +373,7 @@ fn check_option_fold<'tcx>( // `.iter().fold(` -> `.as_ref().map_or(`, drop the accumulator // parameter, and substitute `init` for each use of the accumulator. - acc_uses.sort(); + acc_uses.sort_by_key(|span| span.lo_hi()); let mut parts = vec![ ( recv.span.with_lo(option_expr.span.hi()).with_hi(init.span.lo()), diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs index bf649ff5e249c..19c3abd2576f6 100644 --- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -122,7 +122,7 @@ impl<'tcx> UnsafeExprCollector<'tcx> { .into_iter() .map(|(span, msg)| (msg, span)) .collect::>(); - unsafe_ops.sort_unstable(); + unsafe_ops.sort_unstable_by_key(|(s, span)| (*s, span.lo_hi())); unsafe_ops } diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs index 968f6ad679b59..47708e8f02d19 100644 --- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs +++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs @@ -111,7 +111,7 @@ fn check_op(cx: &LateContext<'_>, outer: &Expr<'_>, expr: &Expr<'_>, other: &Exp } else { let span = expr.span.to(other.span); - let cmp_span = if other.span < expr.span { + let cmp_span = if other.span.lo_hi() < expr.span.lo_hi() { other.span.between(expr.span) } else { expr.span.between(other.span) diff --git a/src/tools/clippy/clippy_lints/src/useless_vec.rs b/src/tools/clippy/clippy_lints/src/useless_vec.rs index 3d2f47cee4670..0b526010d2cce 100644 --- a/src/tools/clippy/clippy_lints/src/useless_vec.rs +++ b/src/tools/clippy/clippy_lints/src/useless_vec.rs @@ -16,7 +16,7 @@ use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, LetStmt, Mutability, Node, Pa use rustc_lint::{LateContext, LateLintPass, impl_lint_pass}; use rustc_middle::ty; use rustc_middle::ty::layout::LayoutOf as _; -use rustc_span::{DesugaringKind, Span}; +use rustc_span::{DesugaringKind, OrdSpan, Span}; pub struct UselessVec { too_large_for_stack: u64, @@ -41,7 +41,7 @@ pub struct UselessVec { /// the first `vec![1, 2]` (which is shared with the other expn) to an array which indeed would /// work, we get a false positive warning on the `$v.push(3)` which really requires `$v` to /// be a vector. - span_to_state: BTreeMap, + span_to_state: BTreeMap, allow_in_test: bool, } @@ -223,7 +223,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { }, }; - if let Entry::Vacant(entry) = self.span_to_state.entry(vec_span) { + if let Entry::Vacant(entry) = self.span_to_state.entry(OrdSpan(vec_span)) { entry.insert(VecState::Change { suggest_ty, vec_snippet, @@ -232,7 +232,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { } }, VecToArray::Impossible => { - self.span_to_state.insert(vec_span, VecState::NoChange); + self.span_to_state.insert(OrdSpan(vec_span), VecState::NoChange); }, } } @@ -246,6 +246,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { expr_hir_id, } = state { + let span = span.0; span_lint_hir_and_then(cx, USELESS_VEC, expr_hir_id, span, "useless use of `vec!`", |diag| { let help_msg = format!("you can use {} directly", suggest_ty.desc()); // If the `vec!` macro contains comment, better not make the suggestion machine applicable as it diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 25c659f7b3ae9..5587fbbcaed1f 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -171,15 +171,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Make sure we are consistent wrt what is 'first' and 'second'. let original_span = - tcx.def_span(original.instance.def_id()).data(); - let span = tcx.def_span(def_id).data(); - if original_span < span { + tcx.def_span(original.instance.def_id()); + let span = tcx.def_span(def_id); + if original_span.lo_hi() < span.lo_hi() { throw_machine_stop!( TerminationInfo::MultipleSymbolDefinitions { link_name, - first: original_span, + first: original_span.data(), first_crate: tcx.crate_name(original.cnum), - second: span, + second: span.data(), second_crate: tcx.crate_name(cnum), } ); @@ -187,9 +187,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { throw_machine_stop!( TerminationInfo::MultipleSymbolDefinitions { link_name, - first: span, + first: span.data(), first_crate: tcx.crate_name(cnum), - second: original_span, + second: original_span.data(), second_crate: tcx.crate_name(original.cnum), } ); From 1b8ac4710bdf796e1b37d66024dbbec06f4e337b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 24 Sep 2026 18:48:08 +1000 Subject: [PATCH 08/17] Remove `Span::source_equal` It can be replaced with `Span::lo_hi` + `==`. --- .../src/diagnostics/conflict_errors.rs | 2 +- compiler/rustc_hir_typeck/src/demand.rs | 2 +- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 2 +- compiler/rustc_lint/src/non_fmt_panic.rs | 2 +- .../rustc_mir_transform/src/coverage/spans.rs | 4 ++-- compiler/rustc_span/src/lib.rs | 16 +++++----------- .../error_reporting/traits/fulfillment_errors.rs | 3 ++- 7 files changed, 13 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 132f074f9e0f9..ec751d6b3e199 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2544,7 +2544,7 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { if let hir::ExprKind::MethodCall(body_call, recv, ..) = ex.kind && body_call.ident.name == sym::next - && recv.span.source_equal(self.expr_span) + && recv.span.lo_hi() == self.expr_span.lo_hi() { self.body_expr = Some(ex); } diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 55eecef732aa4..efe3b4efc0ff1 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -734,7 +734,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match (parent, error) { (hir::Node::LetStmt(hir::LetStmt { ty: Some(ty), init: Some(init), .. }), _) - if init.hir_id == current_hir_id && !ty.span.source_equal(init.span) => + if init.hir_id == current_hir_id && ty.span.lo_hi() != init.span.lo_hi() => { // Point at `let` assignment type. err.span_label(ty.span, "expected due to this"); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 789d06722f897..29b1d5fe315e8 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -3311,7 +3311,7 @@ impl<'a, 'tcx> ArgsCtxt<'a, 'tcx> { // Sometimes macros mess up the spans, so do not normalize the // arg span to equal the error span, because that's less useful // than pointing out the arg expr in the wrong context. - if normalized_span.source_equal(self.call_metadata.error_span) { + if normalized_span.lo_hi() == self.call_metadata.error_span.lo_hi() { span } else { normalized_span diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index 6598110cbfa8f..6fd65af794ac6 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -367,5 +367,5 @@ fn is_arg_inside_call(arg: Span, call: Span) -> bool { // panic call in the source file, to avoid invalid suggestions when macros are involved. // We specifically check for the spans to not be identical, as that happens sometimes when // proc_macros lie about spans and apply the same span to all the tokens they produce. - call.contains(arg) && !call.source_equal(arg) + call.contains(arg) && call.lo_hi() != arg.lo_hi() } diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index ade8bb7865dda..9aa5f3b9f5ab2 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -50,7 +50,7 @@ pub(super) fn extract_refined_covspans<'tcx>( // Discard any spans not contained within the function body span. // Also discard any spans that fill the entire body, because they tend // to represent compiler-inserted code, e.g. implicitly returning `()`. - if !body_span.contains(covspan_span) || body_span.source_equal(covspan_span) { + if !body_span.contains(covspan_span) || body_span.lo_hi() == covspan_span.lo_hi() { return false; } @@ -91,7 +91,7 @@ pub(super) fn extract_refined_covspans<'tcx>( // preferring the one with the most-dominated BCB. // (Ideally we should try to preserve _all_ non-dominating BCBs, but that // requires a lot more complexity in the span refiner, for little benefit.) - covspans.dedup_by(|b, a| a.span.source_equal(b.span)); + covspans.dedup_by_key(|a| a.span.lo_hi()); // Sort the holes, and merge overlapping/adjacent holes. let mut holes = node.hole_spans.iter().copied().map(|span| Hole { span }).collect::>(); diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index b03c70726f1b8..ddec29eca6517 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -758,6 +758,10 @@ impl Span { self.map_ctxt(|_| ctxt) } + /// When to use this: + /// - Use it instead of `==` for span equality comparisons when either span could be generated + /// code and you only care that they point to the same bytes of source text. + /// - Use it (possibly via `OrdSpan`) for span ordering comparisons of any kind. #[inline] pub fn lo_hi(self) -> (BytePos, BytePos) { let data = self.data(); @@ -852,16 +856,6 @@ impl Span { span.lo <= other.hi && other.lo <= span.hi } - /// Returns `true` if the spans are equal with regards to the source text. - /// - /// Use this instead of `==` when either span could be generated code, - /// and you only care that they point to the same bytes of source text. - pub fn source_equal(self, other: Span) -> bool { - let span = self.data(); - let other = other.data(); - span.lo == other.lo && span.hi == other.hi - } - /// Returns `Some(span)`, where the start is trimmed by the end of `other`. pub fn trim_start(self, other: Span) -> Option { let span = self.data(); @@ -1075,7 +1069,7 @@ impl Span { } let expn_data = ctxt.outer_expn_data(); - let is_recursive = expn_data.call_site.source_equal(prev_span); + let is_recursive = expn_data.call_site.lo_hi() == prev_span.lo_hi(); prev_span = self; self = expn_data.call_site; 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 062b087413e4f..0da4b7d9030b4 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 @@ -1178,7 +1178,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { type Result = ControlFlow<&'v hir::Expr<'v>>; fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) -> Self::Result { if let hir::ExprKind::Match(expr, _arms, hir::MatchSource::TryDesugar(_)) = ex.kind - && ex.span.with_lo(ex.span.hi() - BytePos(1)).source_equal(self.search_span) + && ex.span.with_lo(ex.span.hi() - BytePos(1)).lo_hi() + == self.search_span.lo_hi() && let hir::ExprKind::Call(_, [expr, ..]) = expr.kind { ControlFlow::Break(expr) From 7c10734455ee9fd1cb197f3986687d37f0ef609f Mon Sep 17 00:00:00 2001 From: malezjaa Date: Wed, 16 Sep 2026 00:20:01 +0200 Subject: [PATCH 09/17] regression test for inherent associated const ICE --- .../ice-normalize-inherent-assoc-const.rs | 19 +++++++++++++++++++ .../ice-normalize-inherent-assoc-const.stderr | 15 +++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 tests/ui/associated-inherent-types/ice-normalize-inherent-assoc-const.rs create mode 100644 tests/ui/associated-inherent-types/ice-normalize-inherent-assoc-const.stderr diff --git a/tests/ui/associated-inherent-types/ice-normalize-inherent-assoc-const.rs b/tests/ui/associated-inherent-types/ice-normalize-inherent-assoc-const.rs new file mode 100644 index 0000000000000..843e33bae0d81 --- /dev/null +++ b/tests/ui/associated-inherent-types/ice-normalize-inherent-assoc-const.rs @@ -0,0 +1,19 @@ +//! Regression test for: https://github.com/rust-lang/rust/issues/142722. + +#![feature(trivial_bounds)] +#![feature(generic_const_exprs)] +#![feature(min_generic_const_args)] +#![feature(inherent_associated_types)] + +struct Foo; +impl Foo { + const ASSOC_C: usize = todo!(); + //~^ ERROR evaluation panicked: not yet implemented + fn foo() + where + [u8; Self::ASSOC_C]:, + { + } +} + +pub fn main() {} diff --git a/tests/ui/associated-inherent-types/ice-normalize-inherent-assoc-const.stderr b/tests/ui/associated-inherent-types/ice-normalize-inherent-assoc-const.stderr new file mode 100644 index 0000000000000..5ce8a67bc7810 --- /dev/null +++ b/tests/ui/associated-inherent-types/ice-normalize-inherent-assoc-const.stderr @@ -0,0 +1,15 @@ +error[E0080]: evaluation panicked: not yet implemented + --> $DIR/ice-normalize-inherent-assoc-const.rs:10:28 + | +LL | const ASSOC_C: usize = todo!(); + | ^^^^^^^ evaluation of `Foo::ASSOC_C` failed here + +note: erroneous constant encountered + --> $DIR/ice-normalize-inherent-assoc-const.rs:14:14 + | +LL | [u8; Self::ASSOC_C]:, + | ^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. From 01594298297ece4e1f671722da02ed8c0e445eef Mon Sep 17 00:00:00 2001 From: malezjaa Date: Mon, 28 Sep 2026 00:03:56 +0200 Subject: [PATCH 10/17] update feature name --- .../ice-normalize-inherent-assoc-const.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/associated-inherent-types/ice-normalize-inherent-assoc-const.rs b/tests/ui/associated-inherent-types/ice-normalize-inherent-assoc-const.rs index 843e33bae0d81..a7b430f85a9a2 100644 --- a/tests/ui/associated-inherent-types/ice-normalize-inherent-assoc-const.rs +++ b/tests/ui/associated-inherent-types/ice-normalize-inherent-assoc-const.rs @@ -2,7 +2,7 @@ #![feature(trivial_bounds)] #![feature(generic_const_exprs)] -#![feature(min_generic_const_args)] +#![feature(gca_min_const_items)] #![feature(inherent_associated_types)] struct Foo; From 54e09fa7055add9864144576412017d1560d4413 Mon Sep 17 00:00:00 2001 From: Adwin White Date: Fri, 18 Sep 2026 09:42:04 +0800 Subject: [PATCH 11/17] skip registering type outlives when non region infers exist --- .../eval_ctxt/solver_region_constraints.rs | 4 +++- .../rustc_next_trait_solver/src/solve/mod.rs | 21 +++++++++++-------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/solver_region_constraints.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/solver_region_constraints.rs index 10dd8585b09c4..5724834abf03c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/solver_region_constraints.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/solver_region_constraints.rs @@ -164,7 +164,9 @@ where Or::new_leaf(PlaceholderTyOutlives(Ty::new_placeholder(self.cx(), *p), r, ())) } Alias(_, alias) => self.destructure_alias_outlives(*alias, r), - UnresolvedInferenceVariable(_) => Or::new_ambig(()), + UnresolvedInferenceVariable(_) => { + panic!("Shouldn't destructure type outlives when ty vars exist") + } Param(_) => panic!("Params should have been canonicalized to placeholders"), EscapingAlias(components) => self.destructure_components(components, r), } diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 1d7d2dd75c316..dddc78373b1b5 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -92,15 +92,6 @@ where let ty::OutlivesClause(ty, lt) = goal.predicate; let ty = self.normalize(GoalSource::Misc, goal.param_env, ty::Unnormalized::new_wip(ty))?; - if self.cx().assumptions_on_binders() { - use rustc_type_ir::region_constraint::RegionConstraint; - - let constraint = self.destructure_type_outlives(ty, lt); - self.register_solver_region_constraint(RegionConstraint::new_from_or(constraint)); - } else { - self.register_ty_outlives(ty, lt); - } - // The normalized type can still contain non-rigid higher ranked aliases if their // normalization ends up with ambiguity. Or we have non-rigid aliases inside rigid ones. // Infer vars may be resolved to types/consts containing non-rigid aliases later. @@ -109,6 +100,18 @@ where if ty.has_non_region_infer() || ty.has_non_rigid_aliases() { self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) } else { + // We drop region constraints in ambiguous response so there's no need to add them in + // the ambiguous branch. Also this guarantees we don't have ty vars when destructuring + // type outlives. + if self.cx().assumptions_on_binders() { + use rustc_type_ir::region_constraint::RegionConstraint; + + let constraint = self.destructure_type_outlives(ty, lt); + self.register_solver_region_constraint(RegionConstraint::new_from_or(constraint)); + } else { + self.register_ty_outlives(ty, lt); + } + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } From 7809ec46cfd6927530cdf1da1e0c4515dd437ee5 Mon Sep 17 00:00:00 2001 From: Adwin White Date: Fri, 18 Sep 2026 10:23:32 +0800 Subject: [PATCH 12/17] remove `None` assumptions --- .../rustc_hir_analysis/src/check/wfcheck.rs | 2 +- compiler/rustc_infer/src/infer/context.rs | 6 ++-- compiler/rustc_infer/src/infer/mod.rs | 33 ++++++++----------- .../src/canonical/mod.rs | 2 +- .../src/placeholder.rs | 2 +- .../src/solve/eval_ctxt/mod.rs | 16 ++++++--- compiler/rustc_type_ir/src/infer_ctxt.rs | 4 +-- .../rustc_type_ir/src/region_constraint.rs | 33 ++++--------------- 8 files changed, 39 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 0a1787a23c893..4e1bb89b18e6a 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -2433,7 +2433,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { body.type_outlives, builder.freeze(), ); - self.infcx.insert_placeholder_assumptions(u, Some(assumptions)); + self.infcx.insert_placeholder_assumptions(u, assumptions); self.check_test_binder_body(body.value); let solver_region_constraint = self.infcx.get_solver_region_constraint(); let constraint = ty::region_constraint::eagerly_handle_placeholders_in_universe( diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 4d90e60736995..97f305f0699ca 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -49,7 +49,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { fn insert_placeholder_assumptions( &self, u: ty::UniverseIndex, - assumptions: Option>>, + assumptions: rustc_type_ir::region_constraint::Assumptions>, ) { self.insert_placeholder_assumptions(u, assumptions); } @@ -57,7 +57,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { fn get_placeholder_assumptions( &self, u: ty::UniverseIndex, - ) -> Option>> { + ) -> rustc_type_ir::region_constraint::Assumptions> { self.get_placeholder_assumptions(u) } @@ -189,7 +189,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { let u = self.universe(); self.placeholder_assumptions_for_next_solver .borrow_mut() - .insert(u, Some(rustc_type_ir::region_constraint::Assumptions::empty())); + .insert(u, rustc_type_ir::region_constraint::Assumptions::empty()); f(value) }) } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 267c36652656d..42c41164f7ad2 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -335,10 +335,7 @@ pub struct InferCtxt<'tcx> { // FIXME(-Zassumptions-on-binders): This and `universe` should probably be // in `InferCtxtInner` so they can participate in rollbacks and whatnot placeholder_assumptions_for_next_solver: RefCell< - FxIndexMap< - ty::UniverseIndex, - Option>>, - >, + FxIndexMap>>, >, next_trait_solver: bool, @@ -1579,28 +1576,26 @@ impl<'tcx> InferCtxt<'tcx> { pub fn insert_placeholder_assumptions( &self, u: ty::UniverseIndex, - assumptions: Option>>, + assumptions: rustc_type_ir::region_constraint::Assumptions>, ) { - if let Some(assumptions) = &assumptions { - assert!( - !assumptions.type_outlives.has_escaping_bound_vars(), - "assumptions has escaping bound vars, which is indicative of a bug in how assumptions are handled: {:?}", - assumptions.type_outlives - ); - assert!( - assumptions.region_outlives.base_edges().all(|r| !r.has_escaping_bound_vars()), - "assumptions has escaping bound vars, which is indicative of a bug in how assumptions are handled: {:?}", - assumptions.region_outlives - ); - } + assert!( + !assumptions.type_outlives.has_escaping_bound_vars(), + "assumptions has escaping bound vars, which is indicative of a bug in how assumptions are handled: {:?}", + assumptions.type_outlives + ); + assert!( + assumptions.region_outlives.base_edges().all(|r| !r.has_escaping_bound_vars()), + "assumptions has escaping bound vars, which is indicative of a bug in how assumptions are handled: {:?}", + assumptions.region_outlives + ); self.placeholder_assumptions_for_next_solver.borrow_mut().insert(u, assumptions); } pub fn get_placeholder_assumptions( &self, u: ty::UniverseIndex, - ) -> Option>> { - self.placeholder_assumptions_for_next_solver.borrow().get(&u).unwrap().as_ref().cloned() + ) -> rustc_type_ir::region_constraint::Assumptions> { + self.placeholder_assumptions_for_next_solver.borrow().get(&u).unwrap().clone() } pub fn get_solver_region_constraint(&self) -> SolverRegionConstraint<'tcx> { diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index 45ae4cadf519c..655ab64145db5 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -173,7 +173,7 @@ where // recreated universes here. delegate.insert_placeholder_assumptions( new_universe, - Some(rustc_type_ir::region_constraint::Assumptions::empty()), + rustc_type_ir::region_constraint::Assumptions::empty(), ); } } diff --git a/compiler/rustc_next_trait_solver/src/placeholder.rs b/compiler/rustc_next_trait_solver/src/placeholder.rs index c96aa90a10792..fdf702248196a 100644 --- a/compiler/rustc_next_trait_solver/src/placeholder.rs +++ b/compiler/rustc_next_trait_solver/src/placeholder.rs @@ -75,7 +75,7 @@ where // context to compute placeholder assumptions for the binders it enters. infcx.insert_placeholder_assumptions( *new, - Some(rustc_type_ir::region_constraint::Assumptions::empty()), + rustc_type_ir::region_constraint::Assumptions::empty(), ); } } 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 7397d43a48a00..58b3b1fdc49cb 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 @@ -1293,12 +1293,18 @@ where ) -> U { self.delegate.enter_forall_without_assumptions(value, |value| { let u = self.delegate.universe(); - let assumptions = if self.cx().assumptions_on_binders() { - self.region_assumptions_for_placeholders_in_universe(value.clone(), u, param_env) - } else { - None + if self.cx().assumptions_on_binders() { + if let Some(assumptions) = self.region_assumptions_for_placeholders_in_universe( + value.clone(), + u, + param_env, + ) { + self.delegate.insert_placeholder_assumptions(u, assumptions); + } else { + todo!("shoudl retun ambiguity") + } }; - self.delegate.insert_placeholder_assumptions(u, assumptions); + f(self, value) }) } diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 22ebedd9f7e3c..706d6229a840d 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -407,12 +407,12 @@ pub trait InferCtxtLike: Sized { fn insert_placeholder_assumptions( &self, u: ty::UniverseIndex, - assumptions: Option>, + assumptions: crate::region_constraint::Assumptions, ); fn get_placeholder_assumptions( &self, u: ty::UniverseIndex, - ) -> Option>; + ) -> crate::region_constraint::Assumptions; fn get_solver_region_constraint( &self, ) -> crate::region_constraint::RegionConstraint; diff --git a/compiler/rustc_type_ir/src/region_constraint.rs b/compiler/rustc_type_ir/src/region_constraint.rs index e13ecb5e9575e..0becd7a68ef2f 100644 --- a/compiler/rustc_type_ir/src/region_constraint.rs +++ b/compiler/rustc_type_ir/src/region_constraint.rs @@ -715,7 +715,7 @@ fn pull_region_outlives_constraints_out_of_universe< infcx: &Infcx, constraint: RegionConstraint, u: UniverseIndex, - assumptions: &Option>, + assumptions: &Assumptions, ) -> RegionConstraint { assert!(max_universe(infcx, constraint.clone()) <= u); @@ -745,14 +745,6 @@ fn pull_region_outlives_constraints_out_of_universe< continue; } - let assumptions = match assumptions { - Some(assumptions) => assumptions, - None => { - pulled_constraints.push(Or::new_ambig(())); - continue; - } - }; - // The constraint may already be entailed by the assumptions of the binder we are // leaving, e.g. `for<'a, 'b> where 'b: 'a { 'b: 'a }`. There is nothing to lift into // a smaller universe in that case, and looking for lower universe candidates would @@ -875,7 +867,7 @@ fn rewrite_type_outlives_constraints_in_universe_for_eager_placeholder_handling< infcx: &Infcx, constraint: RegionConstraint, u: UniverseIndex, - assumptions: &Option>, + assumptions: &Assumptions, ) -> RegionConstraint { use LeafRegionConstraint::*; @@ -920,7 +912,7 @@ fn rewrite_placeholder_ty_outlives_constraints_in_universe_for_eager_placeholder ty: I::Ty, region: Region, u: UniverseIndex, - assumptions: &Option>, + assumptions: &Assumptions, ) -> Or { use LeafRegionConstraint::*; @@ -931,11 +923,6 @@ fn rewrite_placeholder_ty_outlives_constraints_in_universe_for_eager_placeholder return Or::new_leaf(PlaceholderTyOutlives(ty, region, ())); } - let assumptions = match assumptions { - Some(assumptions) => assumptions, - None => return Or::new_ambig(()), - }; - let mut candidates = vec![]; // There could be `!T: 'region` assumptions in the env even if `!T` is in a @@ -966,7 +953,7 @@ fn rewrite_alias_ty_outlives_constraints_in_universe_for_eager_placeholder_handl infcx: &Infcx, bound_outlives: Binder, Region)>, u: UniverseIndex, - assumptions: &Option>, + assumptions: &Assumptions, ) -> Or { use LeafRegionConstraint::*; @@ -1016,14 +1003,6 @@ fn rewrite_alias_ty_outlives_constraints_in_universe_for_eager_placeholder_handl } } - let assumptions = match assumptions { - Some(assumptions) => assumptions, - None => { - candidates.push(Or::new_ambig(())); - return candidates.into_iter().fold(Or::new_false(), |acc, c| Or::build_or(acc, c)); - } - }; - // Actually look at the assumptions and matching our higher ranked alias outlives goal // against potentially higher ranked type outlives assumptions. candidates.push(alias_outlives_candidates_from_assumptions(infcx, bound_outlives, assumptions)); @@ -1274,14 +1253,14 @@ impl<'a, Infcx: InferCtxtLike, I: Interner> TypeRelation { self.infcx.enter_forall_with_empty_assumptions(a, |a| { let u = self.infcx.universe(); - self.infcx.insert_placeholder_assumptions(u, Some(Assumptions::empty())); + self.infcx.insert_placeholder_assumptions(u, Assumptions::empty()); let b = self.infcx.instantiate_binder_with_infer(b); self.relate(a, b) })?; self.infcx.enter_forall_with_empty_assumptions(b, |b| { let u = self.infcx.universe(); - self.infcx.insert_placeholder_assumptions(u, Some(Assumptions::empty())); + self.infcx.insert_placeholder_assumptions(u, Assumptions::empty()); let a = self.infcx.instantiate_binder_with_infer(a); self.relate(a, b) })?; From d1f102f5a65d4a3fecf2bd0533afecffa6189e42 Mon Sep 17 00:00:00 2001 From: Adwin White Date: Fri, 18 Sep 2026 12:00:13 +0800 Subject: [PATCH 13/17] force ambiguity when no assumptions --- compiler/rustc_infer/src/infer/context.rs | 6 ++++++ compiler/rustc_infer/src/infer/mod.rs | 9 ++++++++ .../src/solve/eval_ctxt/mod.rs | 16 +++++++------- .../eval_ctxt/solver_region_constraints.rs | 21 ++++++++++++++----- compiler/rustc_type_ir/src/infer_ctxt.rs | 2 ++ 5 files changed, 41 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 97f305f0699ca..38dab6ec4875d 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -1,4 +1,6 @@ //! Definition of `InferCtxtLike` from the librarified type layer. +use std::range::RangeInclusive; + use rustc_data_structures::sso::SsoHashMap; use rustc_hir::def_id::DefId; use rustc_middle::traits::ObligationCause; @@ -67,6 +69,10 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.get_solver_region_constraint().without_spans() } + fn has_placeholder_assumptions(&self, range: RangeInclusive) -> bool { + self.has_placeholder_assumptions(range) + } + fn overwrite_solver_region_constraint( &self, constraint: rustc_type_ir::region_constraint::RegionConstraint>, diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 42c41164f7ad2..e02cc9a7acd1f 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1,5 +1,6 @@ use std::cell::{Cell, RefCell}; use std::fmt; +use std::range::RangeInclusive; pub use at::DefineOpaqueTypes; use free_regions::RegionRelations; @@ -1598,6 +1599,14 @@ impl<'tcx> InferCtxt<'tcx> { self.placeholder_assumptions_for_next_solver.borrow().get(&u).unwrap().clone() } + pub fn has_placeholder_assumptions(&self, range: RangeInclusive) -> bool { + let assumptions = self.placeholder_assumptions_for_next_solver.borrow(); + // Walk around that `Step` trait is nightly only. + (range.start.index()..=range.last.index()) + .map(ty::UniverseIndex::from_usize) + .all(|u| assumptions.get(&u).is_some()) + } + pub fn get_solver_region_constraint(&self) -> SolverRegionConstraint<'tcx> { self.inner.borrow().solver_region_constraint_storage.get_constraint() } 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 58b3b1fdc49cb..8fc2a81ee4f52 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 @@ -1292,18 +1292,18 @@ where f: impl FnOnce(&mut Self, T) -> U, ) -> U { self.delegate.enter_forall_without_assumptions(value, |value| { + // Invariant: we shouldn't insert empty assumptions if assumptions computation fails. + // When handling placeholder constraints, we rely on vacancies to force ambiguity. let u = self.delegate.universe(); - if self.cx().assumptions_on_binders() { - if let Some(assumptions) = self.region_assumptions_for_placeholders_in_universe( + if self.cx().assumptions_on_binders() + && let Some(assumptions) = self.region_assumptions_for_placeholders_in_universe( value.clone(), u, param_env, - ) { - self.delegate.insert_placeholder_assumptions(u, assumptions); - } else { - todo!("shoudl retun ambiguity") - } - }; + ) + { + self.delegate.insert_placeholder_assumptions(u, assumptions); + } f(self, value) }) diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/solver_region_constraints.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/solver_region_constraints.rs index 5724834abf03c..d06675c25f904 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/solver_region_constraints.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/solver_region_constraints.rs @@ -115,12 +115,23 @@ where pub(super) fn eagerly_handle_placeholders(&mut self) -> Result { let constraint = self.delegate.get_solver_region_constraint(); - let smallest_universe = self.max_input_universe.index(); - let largest_universe = self.delegate.universe().index(); - debug!(?smallest_universe, largest_universe); + let smallest_universe = self.max_input_universe; + let largest_universe = self.delegate.universe(); + debug!("smallest_universe={smallest_universe:#?}, largest_universe={largest_universe:#?}"); + + // We rely on placeholder assumptions to evaluate region constraints with placeholders. + // But we can fail to compute assumptions due to unresolved type variables. In that case, + // we conservatively bail with ambiguity. + if !self + .delegate + .has_placeholder_assumptions(((smallest_universe + 1)..=largest_universe).into()) + { + return Ok(Certainty::AMBIGUOUS); + } - let constraint = ((smallest_universe + 1)..=largest_universe) - .map(|u| UniverseIndex::from_usize(u)) + // Walk around that `Step` trait is nightly only. + let constraint = ((smallest_universe.index() + 1)..=largest_universe.index()) + .map(UniverseIndex::from_usize) .rev() .fold(constraint, |constraint, u| { eagerly_handle_placeholders_in_universe(&**self.delegate, constraint, u) diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 706d6229a840d..d50f6521441d5 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -1,5 +1,6 @@ use core::fmt; use std::hash::{Hash, Hasher}; +use std::range::RangeInclusive; use derive_where::derive_where; #[cfg(feature = "nightly")] @@ -413,6 +414,7 @@ pub trait InferCtxtLike: Sized { &self, u: ty::UniverseIndex, ) -> crate::region_constraint::Assumptions; + fn has_placeholder_assumptions(&self, range: RangeInclusive) -> bool; fn get_solver_region_constraint( &self, ) -> crate::region_constraint::RegionConstraint; From c9016225be3d651a527d2d86e75834d38615d7e0 Mon Sep 17 00:00:00 2001 From: Adwin White Date: Fri, 18 Sep 2026 12:46:51 +0800 Subject: [PATCH 14/17] yeet `propagate_ambiguity` --- .../src/infer/outlives/obligations.rs | 2 - .../src/solve/eval_ctxt/mod.rs | 6 +-- .../eval_ctxt/solver_region_constraints.rs | 2 - .../rustc_type_ir/src/region_constraint.rs | 47 +------------------ 4 files changed, 2 insertions(+), 55 deletions(-) diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 14f534a3e7eb0..4b833da8eeb59 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -287,8 +287,6 @@ impl<'tcx> InferCtxt<'tcx> { &assumptions, ); debug!(?constraint); - let constraint = region_constraint::propagate_ambiguity(constraint); - debug!(?constraint); // FIXME(-Zassumptions-on-binders): actually implement OR as an OR for c in constraint.and_constraint.0.into_iter().chain( 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 8fc2a81ee4f52..4d74cbc339be3 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 @@ -5,7 +5,7 @@ use std::ops::ControlFlow; use rustc_macros::StableHash; use rustc_type_ir::data_structures::HashSet; use rustc_type_ir::inherent::*; -use rustc_type_ir::region_constraint::{self, RegionConstraint}; +use rustc_type_ir::region_constraint::RegionConstraint; use rustc_type_ir::relate::Relate; use rustc_type_ir::relate::solver_relating::RelateExt; use rustc_type_ir::search_graph::{ @@ -1678,10 +1678,6 @@ where let region_constraints = if self.cx().assumptions_on_binders() { ExternalRegionConstraints::NextGen(if let Certainty::Yes = certainty { let constraint = self.delegate.get_solver_region_constraint(); - debug_assert_eq!( - constraint, - region_constraint::propagate_ambiguity(constraint.clone()) - ); constraint } else { RegionConstraint::new_true() diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/solver_region_constraints.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/solver_region_constraints.rs index d06675c25f904..8a4d3fba99a39 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/solver_region_constraints.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/solver_region_constraints.rs @@ -8,7 +8,6 @@ use rustc_type_ir::outlives::{Component, push_outlives_components}; use rustc_type_ir::region_constraint::TransitiveRelationBuilder; use rustc_type_ir::region_constraint::{ And, Assumptions, LeafRegionConstraint, Or, eagerly_handle_placeholders_in_universe, - propagate_ambiguity, }; use rustc_type_ir::{ AliasTy, Binder, ClauseKind, Const, InferCtxtLike, Interner, Region, TypeVisitable, @@ -136,7 +135,6 @@ where .fold(constraint, |constraint, u| { eagerly_handle_placeholders_in_universe(&**self.delegate, constraint, u) }); - let constraint = propagate_ambiguity(constraint); debug!("final constraint={:?}", constraint); self.delegate.overwrite_solver_region_constraint(constraint.clone(), self.origin_span); diff --git a/compiler/rustc_type_ir/src/region_constraint.rs b/compiler/rustc_type_ir/src/region_constraint.rs index 0becd7a68ef2f..e1b1d157ff85f 100644 --- a/compiler/rustc_type_ir/src/region_constraint.rs +++ b/compiler/rustc_type_ir/src/region_constraint.rs @@ -558,8 +558,7 @@ pub fn eagerly_handle_placeholders_in_universe, I: Interne ) } -/// Force the whole constraint to be ambiguous if it contains ambiguities which could -/// have caused the constraint to be `false` if they had been `false` themselves. -/// -/// For example if we have `'a: 'b AND ambig` it's possible that if we had more inference -/// information we could have produced a better region constraint than `ambig`, and that -/// constraint may then have gone on to be false, at which point we would have `'a: 'b AND false` -/// causing the whole constraint to be `false`. -/// -/// If we're not careful we can wind up returning `'a: 'b AND ambig` from passing trait solver -/// goals and then upon rerunning wind up returning `NoSolution` which would be dubious :3 -/// -/// This is inherently conservative and this method should be called as little as possible as it -/// can cause us to get ambiguities instead of `NoSolution` (for example if `'a: 'b` is `false`), -/// which can affect coherence, candidate selection, etc. -/// -/// FIXME(-Zassumptions-on-binders): this method should probably be trait-solver internal as it only -/// matters at trait solver query boundaries. We currently call it in more than just that location -#[instrument(level = "debug", ret)] -pub fn propagate_ambiguity( - constraint: RegionConstraint, -) -> RegionConstraint { - if let Some(ambig) = constraint.and_constraint.0.iter().find(|c| c.is_ambig()) { - return RegionConstraint::new_leaf(ambig.clone()); - } - - for and in constraint.or_constraint.0.iter() { - // FIXME(-Zassumptions-on-binders): This is overly conservative. If we have: - // `'a: 'b OR ambig` we don't necessarily want to propagate ambiguity here - // as we might end up with `'a: 'b` being satisfied in which case we unnecessarily - // errored here. - // - // It's fine if the `ambig` wound up being `false` as that wouldn't cause a goal to - // become `NoSolution`, it would instead result in us returning the `'a: 'b` constraint - // by itself. - // - // `rust-lang/project-assumptions-on-binders#21` - if let Some(ambig) = and.0.iter().find(|c| c.is_ambig()) { - return RegionConstraint::new_leaf(ambig.clone()); - } - } - - constraint -} - /// Handles converting region outlives constraints involving placeholders from `u` into OR constraints /// involving regions from smaller universes with known relationships to the placeholder. For example: /// ```ignore (not rust) From 4d0e645b0f85ba6dfa6027f41d8487f929ee63e0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 28 Sep 2026 01:39:35 -0500 Subject: [PATCH 15/17] triagebot: Subscribe me to changes in test-float-parse --- triagebot.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 60098a038ea73..bad75dc51d740 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1185,6 +1185,10 @@ cc = ["@rust-lang/miri", "@RalfJung", "@oli-obk", "@lcnr"] message = "Some changes occurred in float parsing" cc = ["@tgross35"] +[mentions."src/tools/test-float-parse"] +message = "Some changes occurred in float parsing" +cc = ["@tgross35"] + [mentions."library/core/src/fmt/num.rs"] message = "Some changes occurred in integer formatting" cc = ["@tgross35"] From af8125b742e4414ce35960353810a1174326bbd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 23 Sep 2026 13:50:06 +0200 Subject: [PATCH 16/17] x perf takes database path --- src/bootstrap/src/core/build_steps/perf.rs | 21 +++++++++++++-- src/etc/completions/x.fish | 5 ++++ src/etc/completions/x.ps1 | 5 ++++ src/etc/completions/x.py.fish | 5 ++++ src/etc/completions/x.py.ps1 | 5 ++++ src/etc/completions/x.py.sh | 30 ++++++++++++++++++---- src/etc/completions/x.py.zsh | 5 ++++ src/etc/completions/x.sh | 30 ++++++++++++++++++---- src/etc/completions/x.zsh | 5 ++++ 9 files changed, 99 insertions(+), 12 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/perf.rs b/src/bootstrap/src/core/build_steps/perf.rs index 930f114f1a70e..e01ff61eb6f86 100644 --- a/src/bootstrap/src/core/build_steps/perf.rs +++ b/src/bootstrap/src/core/build_steps/perf.rs @@ -1,5 +1,6 @@ use std::env::consts::EXE_EXTENSION; use std::fmt::{Display, Formatter}; +use std::path::PathBuf; use crate::core::build_steps::compile::Sysroot; use crate::core::build_steps::tool::{RustcPerf, Rustdoc}; @@ -50,6 +51,9 @@ enum PerfCommand { /// The name of the modified artifact to be compared. modified: String, + + #[clap(long, global = true)] + database_path: Option, }, } @@ -87,6 +91,9 @@ struct SharedOpts { /// Select the profiles that should be benchmarked. #[clap(long, global = true, value_delimiter = ',', default_value = "Check,Debug,Opt")] profiles: Vec, + + #[clap(long, global = true)] + database_path: Option, } #[derive(Clone, Copy, Debug, PartialEq, clap::ValueEnum)] @@ -152,7 +159,17 @@ pub fn perf(builder: &Builder<'_>, args: &PerfArgs, trailing_args: &[String]) { // with compile-time benchmarks. cmd.current_dir(builder.src.join("src/tools/rustc-perf")); - let db_path = results_dir.join("results.db"); + let db_path = args + .cmd + .shared_opts() + .and_then(|i| i.database_path.as_ref()) + .or(if let PerfCommand::Compare { database_path: Some(path), .. } = &args.cmd { + Some(path) + } else { + None + }) + .map(|i| PathBuf::from(i.as_str())) + .unwrap_or_else(|| results_dir.join("results.db")); let is_profiling = match &args.cmd { PerfCommand::Eprintln { .. } @@ -214,7 +231,7 @@ Consider setting `rust.debuginfo-level = 1` in `bootstrap.toml`."#); cmd.args(trailing_args); cmd.run(builder); } - PerfCommand::Compare { base, modified } => { + PerfCommand::Compare { base, modified, database_path: _ } => { cmd.arg("bench_cmp"); cmd.arg("--db").arg(&db_path); cmd.arg(base).arg(modified); diff --git a/src/etc/completions/x.fish b/src/etc/completions/x.fish index 58c5e4255caf6..4ce38dd42033a 100644 --- a/src/etc/completions/x.fish +++ b/src/etc/completions/x.fish @@ -920,6 +920,7 @@ complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_fro complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l exclude -d 'Select the benchmarks matching a prefix in this comma-separated list that you don\'t want to run' -r complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l scenarios -d 'Select the scenarios that should be benchmarked' -r -f -a "{Full\t'',IncrFull\t'',IncrUnchanged\t'',IncrPatched\t''}" complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l profiles -d 'Select the profiles that should be benchmarked' -r -f -a "{Check\t'',Debug\t'',Doc\t'',DocJson\t'',Opt\t'',Clippy\t''}" +complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l database-path -r complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l build -d 'host target of the stage0 compiler' -r -f @@ -959,6 +960,7 @@ complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_fro complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l exclude -d 'Select the benchmarks matching a prefix in this comma-separated list that you don\'t want to run' -r complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l scenarios -d 'Select the scenarios that should be benchmarked' -r -f -a "{Full\t'',IncrFull\t'',IncrUnchanged\t'',IncrPatched\t''}" complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l profiles -d 'Select the profiles that should be benchmarked' -r -f -a "{Check\t'',Debug\t'',Doc\t'',DocJson\t'',Opt\t'',Clippy\t''}" +complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l database-path -r complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l build -d 'host target of the stage0 compiler' -r -f @@ -998,6 +1000,7 @@ complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_fro complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l exclude -d 'Select the benchmarks matching a prefix in this comma-separated list that you don\'t want to run' -r complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l scenarios -d 'Select the scenarios that should be benchmarked' -r -f -a "{Full\t'',IncrFull\t'',IncrUnchanged\t'',IncrPatched\t''}" complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l profiles -d 'Select the profiles that should be benchmarked' -r -f -a "{Check\t'',Debug\t'',Doc\t'',DocJson\t'',Opt\t'',Clippy\t''}" +complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l database-path -r complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l build -d 'host target of the stage0 compiler' -r -f @@ -1037,6 +1040,7 @@ complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_fro complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l exclude -d 'Select the benchmarks matching a prefix in this comma-separated list that you don\'t want to run' -r complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l scenarios -d 'Select the scenarios that should be benchmarked' -r -f -a "{Full\t'',IncrFull\t'',IncrUnchanged\t'',IncrPatched\t''}" complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l profiles -d 'Select the profiles that should be benchmarked' -r -f -a "{Check\t'',Debug\t'',Doc\t'',DocJson\t'',Opt\t'',Clippy\t''}" +complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l database-path -r complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l build -d 'host target of the stage0 compiler' -r -f @@ -1072,6 +1076,7 @@ complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_fro complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l skip-stage0-validation -d 'Skip stage0 compiler validation' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l database-path -r complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l build -d 'host target of the stage0 compiler' -r -f diff --git a/src/etc/completions/x.ps1 b/src/etc/completions/x.ps1 index bf7ed50a85b90..61a4d0d65de91 100644 --- a/src/etc/completions/x.ps1 +++ b/src/etc/completions/x.ps1 @@ -1093,6 +1093,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'Select the benchmarks matching a prefix in this comma-separated list that you don''t want to run') [CompletionResult]::new('--scenarios', '--scenarios', [CompletionResultType]::ParameterName, 'Select the scenarios that should be benchmarked') [CompletionResult]::new('--profiles', '--profiles', [CompletionResultType]::ParameterName, 'Select the profiles that should be benchmarked') + [CompletionResult]::new('--database-path', '--database-path', [CompletionResultType]::ParameterName, 'database-path') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') @@ -1140,6 +1141,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'Select the benchmarks matching a prefix in this comma-separated list that you don''t want to run') [CompletionResult]::new('--scenarios', '--scenarios', [CompletionResultType]::ParameterName, 'Select the scenarios that should be benchmarked') [CompletionResult]::new('--profiles', '--profiles', [CompletionResultType]::ParameterName, 'Select the profiles that should be benchmarked') + [CompletionResult]::new('--database-path', '--database-path', [CompletionResultType]::ParameterName, 'database-path') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') @@ -1187,6 +1189,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'Select the benchmarks matching a prefix in this comma-separated list that you don''t want to run') [CompletionResult]::new('--scenarios', '--scenarios', [CompletionResultType]::ParameterName, 'Select the scenarios that should be benchmarked') [CompletionResult]::new('--profiles', '--profiles', [CompletionResultType]::ParameterName, 'Select the profiles that should be benchmarked') + [CompletionResult]::new('--database-path', '--database-path', [CompletionResultType]::ParameterName, 'database-path') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') @@ -1234,6 +1237,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'Select the benchmarks matching a prefix in this comma-separated list that you don''t want to run') [CompletionResult]::new('--scenarios', '--scenarios', [CompletionResultType]::ParameterName, 'Select the scenarios that should be benchmarked') [CompletionResult]::new('--profiles', '--profiles', [CompletionResultType]::ParameterName, 'Select the profiles that should be benchmarked') + [CompletionResult]::new('--database-path', '--database-path', [CompletionResultType]::ParameterName, 'database-path') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') @@ -1277,6 +1281,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { break } 'x;perf;compare' { + [CompletionResult]::new('--database-path', '--database-path', [CompletionResultType]::ParameterName, 'database-path') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish index 292408fbe49f6..28b1767fc0e96 100644 --- a/src/etc/completions/x.py.fish +++ b/src/etc/completions/x.py.fish @@ -920,6 +920,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcomma complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l exclude -d 'Select the benchmarks matching a prefix in this comma-separated list that you don\'t want to run' -r complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l scenarios -d 'Select the scenarios that should be benchmarked' -r -f -a "{Full\t'',IncrFull\t'',IncrUnchanged\t'',IncrPatched\t''}" complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l profiles -d 'Select the profiles that should be benchmarked' -r -f -a "{Check\t'',Debug\t'',Doc\t'',DocJson\t'',Opt\t'',Clippy\t''}" +complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l database-path -r complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l build -d 'host target of the stage0 compiler' -r -f @@ -959,6 +960,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcomma complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l exclude -d 'Select the benchmarks matching a prefix in this comma-separated list that you don\'t want to run' -r complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l scenarios -d 'Select the scenarios that should be benchmarked' -r -f -a "{Full\t'',IncrFull\t'',IncrUnchanged\t'',IncrPatched\t''}" complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l profiles -d 'Select the profiles that should be benchmarked' -r -f -a "{Check\t'',Debug\t'',Doc\t'',DocJson\t'',Opt\t'',Clippy\t''}" +complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l database-path -r complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l build -d 'host target of the stage0 compiler' -r -f @@ -998,6 +1000,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcomma complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l exclude -d 'Select the benchmarks matching a prefix in this comma-separated list that you don\'t want to run' -r complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l scenarios -d 'Select the scenarios that should be benchmarked' -r -f -a "{Full\t'',IncrFull\t'',IncrUnchanged\t'',IncrPatched\t''}" complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l profiles -d 'Select the profiles that should be benchmarked' -r -f -a "{Check\t'',Debug\t'',Doc\t'',DocJson\t'',Opt\t'',Clippy\t''}" +complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l database-path -r complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l build -d 'host target of the stage0 compiler' -r -f @@ -1037,6 +1040,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcomma complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l exclude -d 'Select the benchmarks matching a prefix in this comma-separated list that you don\'t want to run' -r complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l scenarios -d 'Select the scenarios that should be benchmarked' -r -f -a "{Full\t'',IncrFull\t'',IncrUnchanged\t'',IncrPatched\t''}" complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l profiles -d 'Select the profiles that should be benchmarked' -r -f -a "{Check\t'',Debug\t'',Doc\t'',DocJson\t'',Opt\t'',Clippy\t''}" +complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l database-path -r complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l build -d 'host target of the stage0 compiler' -r -f @@ -1072,6 +1076,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcomma complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l skip-stage0-validation -d 'Skip stage0 compiler validation' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l database-path -r complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l build -d 'host target of the stage0 compiler' -r -f diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1 index 5ab4cab3a32a3..7178833189ac6 100644 --- a/src/etc/completions/x.py.ps1 +++ b/src/etc/completions/x.py.ps1 @@ -1093,6 +1093,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'Select the benchmarks matching a prefix in this comma-separated list that you don''t want to run') [CompletionResult]::new('--scenarios', '--scenarios', [CompletionResultType]::ParameterName, 'Select the scenarios that should be benchmarked') [CompletionResult]::new('--profiles', '--profiles', [CompletionResultType]::ParameterName, 'Select the profiles that should be benchmarked') + [CompletionResult]::new('--database-path', '--database-path', [CompletionResultType]::ParameterName, 'database-path') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') @@ -1140,6 +1141,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'Select the benchmarks matching a prefix in this comma-separated list that you don''t want to run') [CompletionResult]::new('--scenarios', '--scenarios', [CompletionResultType]::ParameterName, 'Select the scenarios that should be benchmarked') [CompletionResult]::new('--profiles', '--profiles', [CompletionResultType]::ParameterName, 'Select the profiles that should be benchmarked') + [CompletionResult]::new('--database-path', '--database-path', [CompletionResultType]::ParameterName, 'database-path') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') @@ -1187,6 +1189,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'Select the benchmarks matching a prefix in this comma-separated list that you don''t want to run') [CompletionResult]::new('--scenarios', '--scenarios', [CompletionResultType]::ParameterName, 'Select the scenarios that should be benchmarked') [CompletionResult]::new('--profiles', '--profiles', [CompletionResultType]::ParameterName, 'Select the profiles that should be benchmarked') + [CompletionResult]::new('--database-path', '--database-path', [CompletionResultType]::ParameterName, 'database-path') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') @@ -1234,6 +1237,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'Select the benchmarks matching a prefix in this comma-separated list that you don''t want to run') [CompletionResult]::new('--scenarios', '--scenarios', [CompletionResultType]::ParameterName, 'Select the scenarios that should be benchmarked') [CompletionResult]::new('--profiles', '--profiles', [CompletionResultType]::ParameterName, 'Select the profiles that should be benchmarked') + [CompletionResult]::new('--database-path', '--database-path', [CompletionResultType]::ParameterName, 'database-path') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') @@ -1277,6 +1281,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { break } 'x.py;perf;compare' { + [CompletionResult]::new('--database-path', '--database-path', [CompletionResultType]::ParameterName, 'database-path') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh index 0c449988b0461..f1b35e4cbc894 100644 --- a/src/etc/completions/x.py.sh +++ b/src/etc/completions/x.py.sh @@ -3094,7 +3094,7 @@ _x.py() { return 0 ;; x.py__perf__benchmark) - opts="-v -q -i -j -h --include --exclude --scenarios --profiles --verbose --quiet --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -q -i -j -h --include --exclude --scenarios --profiles --database-path --verbose --quiet --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3116,6 +3116,10 @@ _x.py() { COMPREPLY=($(compgen -W "Check Debug Doc DocJson Opt Clippy" -- "${cur}")) return 0 ;; + --database-path) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --config) local oldifs if [ -n "${IFS+x}" ]; then @@ -3292,7 +3296,7 @@ _x.py() { return 0 ;; x.py__perf__cachegrind) - opts="-v -q -i -j -h --include --exclude --scenarios --profiles --verbose --quiet --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -q -i -j -h --include --exclude --scenarios --profiles --database-path --verbose --quiet --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3314,6 +3318,10 @@ _x.py() { COMPREPLY=($(compgen -W "Check Debug Doc DocJson Opt Clippy" -- "${cur}")) return 0 ;; + --database-path) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --config) local oldifs if [ -n "${IFS+x}" ]; then @@ -3490,12 +3498,16 @@ _x.py() { return 0 ;; x.py__perf__compare) - opts="-v -q -i -j -h --verbose --quiet --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -q -i -j -h --database-path --verbose --quiet --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in + --database-path) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --config) local oldifs if [ -n "${IFS+x}" ]; then @@ -3676,7 +3688,7 @@ _x.py() { return 0 ;; x.py__perf__eprintln) - opts="-v -q -i -j -h --include --exclude --scenarios --profiles --verbose --quiet --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -q -i -j -h --include --exclude --scenarios --profiles --database-path --verbose --quiet --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3698,6 +3710,10 @@ _x.py() { COMPREPLY=($(compgen -W "Check Debug Doc DocJson Opt Clippy" -- "${cur}")) return 0 ;; + --database-path) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --config) local oldifs if [ -n "${IFS+x}" ]; then @@ -3874,7 +3890,7 @@ _x.py() { return 0 ;; x.py__perf__samply) - opts="-v -q -i -j -h --include --exclude --scenarios --profiles --verbose --quiet --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -q -i -j -h --include --exclude --scenarios --profiles --database-path --verbose --quiet --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3896,6 +3912,10 @@ _x.py() { COMPREPLY=($(compgen -W "Check Debug Doc DocJson Opt Clippy" -- "${cur}")) return 0 ;; + --database-path) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --config) local oldifs if [ -n "${IFS+x}" ]; then diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh index 9ee5843a5abd7..8376e44746052 100644 --- a/src/etc/completions/x.py.zsh +++ b/src/etc/completions/x.py.zsh @@ -1123,6 +1123,7 @@ _arguments "${_arguments_options[@]}" : \ '*--exclude=[Select the benchmarks matching a prefix in this comma-separated list that you don'\''t want to run]:EXCLUDE:_default' \ '*--scenarios=[Select the scenarios that should be benchmarked]:SCENARIOS:(Full IncrFull IncrUnchanged IncrPatched)' \ '*--profiles=[Select the profiles that should be benchmarked]:PROFILES:(Check Debug Doc DocJson Opt Clippy)' \ +'--database-path=[]:DATABASE_PATH:_default' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ '--build=[host target of the stage0 compiler]:BUILD:' \ @@ -1172,6 +1173,7 @@ _arguments "${_arguments_options[@]}" : \ '*--exclude=[Select the benchmarks matching a prefix in this comma-separated list that you don'\''t want to run]:EXCLUDE:_default' \ '*--scenarios=[Select the scenarios that should be benchmarked]:SCENARIOS:(Full IncrFull IncrUnchanged IncrPatched)' \ '*--profiles=[Select the profiles that should be benchmarked]:PROFILES:(Check Debug Doc DocJson Opt Clippy)' \ +'--database-path=[]:DATABASE_PATH:_default' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ '--build=[host target of the stage0 compiler]:BUILD:' \ @@ -1221,6 +1223,7 @@ _arguments "${_arguments_options[@]}" : \ '*--exclude=[Select the benchmarks matching a prefix in this comma-separated list that you don'\''t want to run]:EXCLUDE:_default' \ '*--scenarios=[Select the scenarios that should be benchmarked]:SCENARIOS:(Full IncrFull IncrUnchanged IncrPatched)' \ '*--profiles=[Select the profiles that should be benchmarked]:PROFILES:(Check Debug Doc DocJson Opt Clippy)' \ +'--database-path=[]:DATABASE_PATH:_default' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ '--build=[host target of the stage0 compiler]:BUILD:' \ @@ -1270,6 +1273,7 @@ _arguments "${_arguments_options[@]}" : \ '*--exclude=[Select the benchmarks matching a prefix in this comma-separated list that you don'\''t want to run]:EXCLUDE:_default' \ '*--scenarios=[Select the scenarios that should be benchmarked]:SCENARIOS:(Full IncrFull IncrUnchanged IncrPatched)' \ '*--profiles=[Select the profiles that should be benchmarked]:PROFILES:(Check Debug Doc DocJson Opt Clippy)' \ +'--database-path=[]:DATABASE_PATH:_default' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ '--build=[host target of the stage0 compiler]:BUILD:' \ @@ -1316,6 +1320,7 @@ _arguments "${_arguments_options[@]}" : \ ;; (compare) _arguments "${_arguments_options[@]}" : \ +'--database-path=[]:DATABASE_PATH:_default' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ '--build=[host target of the stage0 compiler]:BUILD:' \ diff --git a/src/etc/completions/x.sh b/src/etc/completions/x.sh index f8897cc5f5ec8..be81e2e743e7c 100644 --- a/src/etc/completions/x.sh +++ b/src/etc/completions/x.sh @@ -3094,7 +3094,7 @@ _x() { return 0 ;; x__perf__benchmark) - opts="-v -q -i -j -h --include --exclude --scenarios --profiles --verbose --quiet --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -q -i -j -h --include --exclude --scenarios --profiles --database-path --verbose --quiet --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3116,6 +3116,10 @@ _x() { COMPREPLY=($(compgen -W "Check Debug Doc DocJson Opt Clippy" -- "${cur}")) return 0 ;; + --database-path) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --config) local oldifs if [ -n "${IFS+x}" ]; then @@ -3292,7 +3296,7 @@ _x() { return 0 ;; x__perf__cachegrind) - opts="-v -q -i -j -h --include --exclude --scenarios --profiles --verbose --quiet --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -q -i -j -h --include --exclude --scenarios --profiles --database-path --verbose --quiet --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3314,6 +3318,10 @@ _x() { COMPREPLY=($(compgen -W "Check Debug Doc DocJson Opt Clippy" -- "${cur}")) return 0 ;; + --database-path) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --config) local oldifs if [ -n "${IFS+x}" ]; then @@ -3490,12 +3498,16 @@ _x() { return 0 ;; x__perf__compare) - opts="-v -q -i -j -h --verbose --quiet --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -q -i -j -h --database-path --verbose --quiet --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in + --database-path) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --config) local oldifs if [ -n "${IFS+x}" ]; then @@ -3676,7 +3688,7 @@ _x() { return 0 ;; x__perf__eprintln) - opts="-v -q -i -j -h --include --exclude --scenarios --profiles --verbose --quiet --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -q -i -j -h --include --exclude --scenarios --profiles --database-path --verbose --quiet --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3698,6 +3710,10 @@ _x() { COMPREPLY=($(compgen -W "Check Debug Doc DocJson Opt Clippy" -- "${cur}")) return 0 ;; + --database-path) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --config) local oldifs if [ -n "${IFS+x}" ]; then @@ -3874,7 +3890,7 @@ _x() { return 0 ;; x__perf__samply) - opts="-v -q -i -j -h --include --exclude --scenarios --profiles --verbose --quiet --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -q -i -j -h --include --exclude --scenarios --profiles --database-path --verbose --quiet --incremental --config --build-dir --build --host --target --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3896,6 +3912,10 @@ _x() { COMPREPLY=($(compgen -W "Check Debug Doc DocJson Opt Clippy" -- "${cur}")) return 0 ;; + --database-path) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --config) local oldifs if [ -n "${IFS+x}" ]; then diff --git a/src/etc/completions/x.zsh b/src/etc/completions/x.zsh index f61942a11da4a..3159859c1ea8e 100644 --- a/src/etc/completions/x.zsh +++ b/src/etc/completions/x.zsh @@ -1123,6 +1123,7 @@ _arguments "${_arguments_options[@]}" : \ '*--exclude=[Select the benchmarks matching a prefix in this comma-separated list that you don'\''t want to run]:EXCLUDE:_default' \ '*--scenarios=[Select the scenarios that should be benchmarked]:SCENARIOS:(Full IncrFull IncrUnchanged IncrPatched)' \ '*--profiles=[Select the profiles that should be benchmarked]:PROFILES:(Check Debug Doc DocJson Opt Clippy)' \ +'--database-path=[]:DATABASE_PATH:_default' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ '--build=[host target of the stage0 compiler]:BUILD:' \ @@ -1172,6 +1173,7 @@ _arguments "${_arguments_options[@]}" : \ '*--exclude=[Select the benchmarks matching a prefix in this comma-separated list that you don'\''t want to run]:EXCLUDE:_default' \ '*--scenarios=[Select the scenarios that should be benchmarked]:SCENARIOS:(Full IncrFull IncrUnchanged IncrPatched)' \ '*--profiles=[Select the profiles that should be benchmarked]:PROFILES:(Check Debug Doc DocJson Opt Clippy)' \ +'--database-path=[]:DATABASE_PATH:_default' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ '--build=[host target of the stage0 compiler]:BUILD:' \ @@ -1221,6 +1223,7 @@ _arguments "${_arguments_options[@]}" : \ '*--exclude=[Select the benchmarks matching a prefix in this comma-separated list that you don'\''t want to run]:EXCLUDE:_default' \ '*--scenarios=[Select the scenarios that should be benchmarked]:SCENARIOS:(Full IncrFull IncrUnchanged IncrPatched)' \ '*--profiles=[Select the profiles that should be benchmarked]:PROFILES:(Check Debug Doc DocJson Opt Clippy)' \ +'--database-path=[]:DATABASE_PATH:_default' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ '--build=[host target of the stage0 compiler]:BUILD:' \ @@ -1270,6 +1273,7 @@ _arguments "${_arguments_options[@]}" : \ '*--exclude=[Select the benchmarks matching a prefix in this comma-separated list that you don'\''t want to run]:EXCLUDE:_default' \ '*--scenarios=[Select the scenarios that should be benchmarked]:SCENARIOS:(Full IncrFull IncrUnchanged IncrPatched)' \ '*--profiles=[Select the profiles that should be benchmarked]:PROFILES:(Check Debug Doc DocJson Opt Clippy)' \ +'--database-path=[]:DATABASE_PATH:_default' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ '--build=[host target of the stage0 compiler]:BUILD:' \ @@ -1316,6 +1320,7 @@ _arguments "${_arguments_options[@]}" : \ ;; (compare) _arguments "${_arguments_options[@]}" : \ +'--database-path=[]:DATABASE_PATH:_default' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ '--build=[host target of the stage0 compiler]:BUILD:' \ From dce48c6b852d62db6819a2e830be41caed7ff16b Mon Sep 17 00:00:00 2001 From: Abhinav Srivastav Date: Mon, 28 Sep 2026 09:18:54 +0000 Subject: [PATCH 17/17] emit UnresolvedDelegationCallee for TypeRelativeDelegationRes::Error --- .../src/delegation/resolution.rs | 4 +- compiler/rustc_middle/src/middle/resolve.rs | 1 + tests/ui/delegation/bad-resolve.rs | 8 +++- tests/ui/delegation/bad-resolve.stderr | 42 +++++++++++++++++-- .../delegation-inherent-impl-issue-162774.rs | 18 ++++++++ ...legation-inherent-impl-issue-162774.stderr | 8 ++++ .../def-path-hash-collision-ice-153410.rs | 2 +- .../def-path-hash-collision-ice-153410.stderr | 8 +++- .../generics/synth-params-ice-143498.rs | 2 +- .../generics/synth-params-ice-143498.stderr | 8 +++- tests/ui/delegation/ice-issue-124342.rs | 2 +- tests/ui/delegation/ice-issue-124342.stderr | 8 +++- .../ice-line-bounds-issue-148732.rs | 2 +- .../ice-line-bounds-issue-148732.stderr | 8 +++- .../ice-non-fn-target-in-trait-impl.rs | 2 +- .../ice-non-fn-target-in-trait-impl.stderr | 8 +++- .../inherent-impls-non-local-crate.rs | 4 ++ .../inherent-impls-non-local-crate.stderr | 36 +++++++++++++--- .../ui/delegation/unused-import-ice-144594.rs | 2 +- .../unused-import-ice-144594.stderr | 8 +++- tests/ui/delegation/wrong-lifetime-rib.rs | 2 +- tests/ui/delegation/wrong-lifetime-rib.stderr | 8 +++- 22 files changed, 166 insertions(+), 25 deletions(-) create mode 100644 tests/ui/delegation/delegation-inherent-impl-issue-162774.rs create mode 100644 tests/ui/delegation/delegation-inherent-impl-issue-162774.stderr diff --git a/compiler/rustc_ast_lowering/src/delegation/resolution.rs b/compiler/rustc_ast_lowering/src/delegation/resolution.rs index 0e4992267b250..7678418c47e56 100644 --- a/compiler/rustc_ast_lowering/src/delegation/resolution.rs +++ b/compiler/rustc_ast_lowering/src/delegation/resolution.rs @@ -343,7 +343,9 @@ impl<'tcx> DelegationResolver<'_, 'tcx> { match tcx.resolve_type_relative_delegations(()).get(&def_id) { Some(res) => match *res { TypeRelativeDelegationRes::Ok(sig_id) => Ok(sig_id), - TypeRelativeDelegationRes::Error(err) => Err(err), + TypeRelativeDelegationRes::Error(_) => { + Err(tcx.dcx().emit_err(UnresolvedDelegationCallee { span })) + } TypeRelativeDelegationRes::Ambig(_) => { Err(tcx.dcx().emit_err(AmbiguousDelegationToInherentImpl { span })) } diff --git a/compiler/rustc_middle/src/middle/resolve.rs b/compiler/rustc_middle/src/middle/resolve.rs index 8267cde89ad27..fe8bc8a5f1537 100644 --- a/compiler/rustc_middle/src/middle/resolve.rs +++ b/compiler/rustc_middle/src/middle/resolve.rs @@ -291,6 +291,7 @@ pub struct DelegationInfo { } #[derive(Debug, StableHash)] +// FIXME(fn_delegation): replace with `Result`. pub enum TypeRelativeDelegationRes { Ok(DefId), Ambig(ErrorGuaranteed), diff --git a/tests/ui/delegation/bad-resolve.rs b/tests/ui/delegation/bad-resolve.rs index 0864776ab49fd..52da0f38017a0 100644 --- a/tests/ui/delegation/bad-resolve.rs +++ b/tests/ui/delegation/bad-resolve.rs @@ -43,7 +43,13 @@ impl Trait for S { mod prefix {} reuse unresolved_prefix::{a, b, c}; //~ ERROR cannot find module or crate `unresolved_prefix` +//~| ERROR failed to resolve delegation callee +//~| ERROR failed to resolve delegation callee +//~| ERROR failed to resolve delegation callee reuse prefix::{self, super, crate}; //~ ERROR `crate` in paths can only be used in start position -//~^ ERROR cannot find function `self` in module `prefix` +//~| ERROR failed to resolve delegation callee +//~| ERROR failed to resolve delegation callee +//~| ERROR cannot find function `self` in module `prefix` +//~| ERROR failed to resolve delegation callee fn main() {} diff --git a/tests/ui/delegation/bad-resolve.stderr b/tests/ui/delegation/bad-resolve.stderr index 9740442e4b9f3..9756a009ec9b9 100644 --- a/tests/ui/delegation/bad-resolve.stderr +++ b/tests/ui/delegation/bad-resolve.stderr @@ -72,13 +72,49 @@ LL | reuse foo { &self.0 } | ^^^ not found in this scope error[E0423]: cannot find function `self` in module `prefix` - --> $DIR/bad-resolve.rs:46:16 + --> $DIR/bad-resolve.rs:49:16 | LL | reuse prefix::{self, super, crate}; | ^^^^ not found in `prefix` | = note: a module named `prefix::self` exists in another namespace +error: failed to resolve delegation callee + --> $DIR/bad-resolve.rs:45:27 + | +LL | reuse unresolved_prefix::{a, b, c}; + | ^ + +error: failed to resolve delegation callee + --> $DIR/bad-resolve.rs:45:30 + | +LL | reuse unresolved_prefix::{a, b, c}; + | ^ + +error: failed to resolve delegation callee + --> $DIR/bad-resolve.rs:45:33 + | +LL | reuse unresolved_prefix::{a, b, c}; + | ^ + +error: failed to resolve delegation callee + --> $DIR/bad-resolve.rs:49:16 + | +LL | reuse prefix::{self, super, crate}; + | ^^^^ + +error: failed to resolve delegation callee + --> $DIR/bad-resolve.rs:49:22 + | +LL | reuse prefix::{self, super, crate}; + | ^^^^^ + +error: failed to resolve delegation callee + --> $DIR/bad-resolve.rs:49:29 + | +LL | reuse prefix::{self, super, crate}; + | ^^^^^ + error[E0186]: method `foo` has a `&self` declaration in the trait, but not in the impl --> $DIR/bad-resolve.rs:34:11 | @@ -152,12 +188,12 @@ LL | reuse unresolved_prefix::{a, b, c}; = help: you might be missing a crate named `unresolved_prefix` error[E0433]: `crate` in paths can only be used in start position - --> $DIR/bad-resolve.rs:46:29 + --> $DIR/bad-resolve.rs:49:29 | LL | reuse prefix::{self, super, crate}; | ^^^^^ can only be used in path start position -error: aborting due to 14 previous errors; 1 warning emitted +error: aborting due to 20 previous errors; 1 warning emitted Some errors have detailed explanations: E0038, E0046, E0186, E0324, E0407, E0423, E0425, E0433, E0575... For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/delegation/delegation-inherent-impl-issue-162774.rs b/tests/ui/delegation/delegation-inherent-impl-issue-162774.rs new file mode 100644 index 0000000000000..32432babd7b63 --- /dev/null +++ b/tests/ui/delegation/delegation-inherent-impl-issue-162774.rs @@ -0,0 +1,18 @@ +#![feature(fn_delegation)] + +trait Trait { + fn foo(&self) {} +} + +struct F; +impl Trait for F {} + +struct S(F); + +impl S { + reuse Trait::foo { self.0 } + reuse Self::foo::<> as bar { self } + //~^ ERROR failed to resolve delegation callee +} + +fn main() {} diff --git a/tests/ui/delegation/delegation-inherent-impl-issue-162774.stderr b/tests/ui/delegation/delegation-inherent-impl-issue-162774.stderr new file mode 100644 index 0000000000000..b2c0f53163470 --- /dev/null +++ b/tests/ui/delegation/delegation-inherent-impl-issue-162774.stderr @@ -0,0 +1,8 @@ +error: failed to resolve delegation callee + --> $DIR/delegation-inherent-impl-issue-162774.rs:14:17 + | +LL | reuse Self::foo::<> as bar { self } + | ^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/delegation/generics/def-path-hash-collision-ice-153410.rs b/tests/ui/delegation/generics/def-path-hash-collision-ice-153410.rs index a35386fa3720e..73c18e5690fd1 100644 --- a/tests/ui/delegation/generics/def-path-hash-collision-ice-153410.rs +++ b/tests/ui/delegation/generics/def-path-hash-collision-ice-153410.rs @@ -18,7 +18,7 @@ impl Iterator { //~^ ERROR: expected a type, found a trait [E0782] - reuse< < fn()>::Output>::Item as Iterator>::*; + reuse< < fn()>::Output>::Item as Iterator>::*; //~ ERROR failed to resolve delegation callee //~^ ERROR: cannot find method or associated constant `Item` in trait `Iterator` //~| ERROR: ambiguous associated type } diff --git a/tests/ui/delegation/generics/def-path-hash-collision-ice-153410.stderr b/tests/ui/delegation/generics/def-path-hash-collision-ice-153410.stderr index 99bb6ac7e66be..50eaca19144be 100644 --- a/tests/ui/delegation/generics/def-path-hash-collision-ice-153410.stderr +++ b/tests/ui/delegation/generics/def-path-hash-collision-ice-153410.stderr @@ -6,6 +6,12 @@ LL | reuse< < fn()>::Output>::Item as Iterator>::*; | = note: an associated type named `Iterator::Item` exists in another namespace +error: failed to resolve delegation callee + --> $DIR/def-path-hash-collision-ice-153410.rs:21:58 + | +LL | reuse< < fn()>::Output>::Item as Iterator>::*; + | ^ + error[E0782]: expected a type, found a trait --> $DIR/def-path-hash-collision-ice-153410.rs:19:6 | @@ -36,7 +42,7 @@ LL - reuse< < fn()>::Output>::Item as Iterator>::*; LL + reuse< < ::Output>::Item as Iterator>::*; | -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0223, E0575, E0782. For more information about an error, try `rustc --explain E0223`. diff --git a/tests/ui/delegation/generics/synth-params-ice-143498.rs b/tests/ui/delegation/generics/synth-params-ice-143498.rs index 366451ccdc012..2216f05f6c31f 100644 --- a/tests/ui/delegation/generics/synth-params-ice-143498.rs +++ b/tests/ui/delegation/generics/synth-params-ice-143498.rs @@ -18,7 +18,7 @@ impl X { //~^ ERROR: cannot find type `X` in this scope - reuse< std::fmt::Debug as Iterator >::*; + reuse< std::fmt::Debug as Iterator >::*; //~ ERROR failed to resolve delegation callee //~^ ERROR: cannot find method or associated constant `Item` in trait `Iterator` //~| ERROR: expected a type, found a trait } diff --git a/tests/ui/delegation/generics/synth-params-ice-143498.stderr b/tests/ui/delegation/generics/synth-params-ice-143498.stderr index 8db4a84d76c53..21c5e29ad8707 100644 --- a/tests/ui/delegation/generics/synth-params-ice-143498.stderr +++ b/tests/ui/delegation/generics/synth-params-ice-143498.stderr @@ -12,6 +12,12 @@ LL | reuse< std::fmt::Debug as Iterator >::*; | = note: an associated type named `Iterator::Item` exists in another namespace +error: failed to resolve delegation callee + --> $DIR/synth-params-ice-143498.rs:21:43 + | +LL | reuse< std::fmt::Debug as Iterator >::*; + | ^ + error[E0782]: expected a type, found a trait --> $DIR/synth-params-ice-143498.rs:21:12 | @@ -23,7 +29,7 @@ help: you can add the `dyn` keyword if you want a trait object LL | reuse< dyn std::fmt::Debug as Iterator >::*; | +++ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0425, E0575, E0782. For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/delegation/ice-issue-124342.rs b/tests/ui/delegation/ice-issue-124342.rs index b5e7d9386d33d..a882b1bd90e6b 100644 --- a/tests/ui/delegation/ice-issue-124342.rs +++ b/tests/ui/delegation/ice-issue-124342.rs @@ -3,7 +3,7 @@ mod to_reuse {} trait Trait { - reuse to_reuse::foo { foo } + reuse to_reuse::foo { foo } //~ ERROR failed to resolve delegation callee //~^ ERROR cannot find function `foo` in module `to_reuse` //~| ERROR cannot find value `foo` in this scope } diff --git a/tests/ui/delegation/ice-issue-124342.stderr b/tests/ui/delegation/ice-issue-124342.stderr index 19d75e494cafe..df2b2ea91f0bd 100644 --- a/tests/ui/delegation/ice-issue-124342.stderr +++ b/tests/ui/delegation/ice-issue-124342.stderr @@ -15,6 +15,12 @@ help: you might have meant to refer to the associated function LL | reuse to_reuse::foo { Self::foo } | ++++++ -error: aborting due to 2 previous errors +error: failed to resolve delegation callee + --> $DIR/ice-issue-124342.rs:6:21 + | +LL | reuse to_reuse::foo { foo } + | ^^^ + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/delegation/ice-line-bounds-issue-148732.rs b/tests/ui/delegation/ice-line-bounds-issue-148732.rs index 0123f0c8705b0..b8887f6ecbbf5 100644 --- a/tests/ui/delegation/ice-line-bounds-issue-148732.rs +++ b/tests/ui/delegation/ice-line-bounds-issue-148732.rs @@ -1,4 +1,4 @@ -reuse a as b { +reuse a as b { //~ ERROR failed to resolve delegation callee //~^ ERROR cannot find function `a` in this scope //~| ERROR functions delegation is not yet fully implemented dbg!(b); diff --git a/tests/ui/delegation/ice-line-bounds-issue-148732.stderr b/tests/ui/delegation/ice-line-bounds-issue-148732.stderr index eb93655beb60d..196f984626ce5 100644 --- a/tests/ui/delegation/ice-line-bounds-issue-148732.stderr +++ b/tests/ui/delegation/ice-line-bounds-issue-148732.stderr @@ -19,6 +19,12 @@ LL | | } = help: add `#![feature(fn_delegation)]` 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: failed to resolve delegation callee + --> $DIR/ice-line-bounds-issue-148732.rs:1:7 + | +LL | reuse a as b { + | ^ + error[E0277]: `fn() {b}` doesn't implement `Debug` --> $DIR/ice-line-bounds-issue-148732.rs:4:5 | @@ -30,7 +36,7 @@ LL | dbg!(b); | = help: use parentheses to call this function: `b()` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0277, E0425, E0658. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/delegation/ice-non-fn-target-in-trait-impl.rs b/tests/ui/delegation/ice-non-fn-target-in-trait-impl.rs index 7a61da79f3c8f..2dac22779c3da 100644 --- a/tests/ui/delegation/ice-non-fn-target-in-trait-impl.rs +++ b/tests/ui/delegation/ice-non-fn-target-in-trait-impl.rs @@ -10,7 +10,7 @@ trait Trait { } impl Trait for () { - reuse std::path::<> as bar; + reuse std::path::<> as bar; //~ ERROR failed to resolve delegation callee //~^ ERROR cannot find function `path` in crate `std` reuse core::<> as bar2; //~^ ERROR cannot find function `core` in this scope diff --git a/tests/ui/delegation/ice-non-fn-target-in-trait-impl.stderr b/tests/ui/delegation/ice-non-fn-target-in-trait-impl.stderr index e9eca6b35bb51..f543f823da157 100644 --- a/tests/ui/delegation/ice-non-fn-target-in-trait-impl.stderr +++ b/tests/ui/delegation/ice-non-fn-target-in-trait-impl.stderr @@ -14,6 +14,12 @@ LL | reuse core::<> as bar2; | = note: a crate named `core` exists in another namespace -error: aborting due to 2 previous errors +error: failed to resolve delegation callee + --> $DIR/ice-non-fn-target-in-trait-impl.rs:13:16 + | +LL | reuse std::path::<> as bar; + | ^^^^ + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0423`. diff --git a/tests/ui/delegation/inherent-impls-non-local-crate.rs b/tests/ui/delegation/inherent-impls-non-local-crate.rs index 27b8d387a7e63..865bdb877a8a1 100644 --- a/tests/ui/delegation/inherent-impls-non-local-crate.rs +++ b/tests/ui/delegation/inherent-impls-non-local-crate.rs @@ -6,13 +6,17 @@ reuse inherent_impl::S::foo; reuse inherent_impl::S::not_existing; //~^ ERROR: no associated function or constant named `not_existing` found for struct `S` in the current scope +//~| ERROR failed to resolve delegation callee reuse inherent_impl::S::TYPE; //~^ ERROR: no associated function or constant named `TYPE` found for struct `S` in the current scope +//~| ERROR failed to resolve delegation callee reuse inherent_impl::S::CONST; //~^ ERROR: expected function, found `usize` [E0618] +//~| ERROR failed to resolve delegation callee reuse inherent_impl::S::bar; //~^ ERROR: no associated function or constant named `bar` found for struct `S` in the current scope +//~| ERROR failed to resolve delegation callee reuse ::bar as trait_bar; diff --git a/tests/ui/delegation/inherent-impls-non-local-crate.stderr b/tests/ui/delegation/inherent-impls-non-local-crate.stderr index 31358b1d7144e..288f72427c376 100644 --- a/tests/ui/delegation/inherent-impls-non-local-crate.stderr +++ b/tests/ui/delegation/inherent-impls-non-local-crate.stderr @@ -1,5 +1,29 @@ +error: failed to resolve delegation callee + --> $DIR/inherent-impls-non-local-crate.rs:7:25 + | +LL | reuse inherent_impl::S::not_existing; + | ^^^^^^^^^^^^ + +error: failed to resolve delegation callee + --> $DIR/inherent-impls-non-local-crate.rs:10:25 + | +LL | reuse inherent_impl::S::TYPE; + | ^^^^ + +error: failed to resolve delegation callee + --> $DIR/inherent-impls-non-local-crate.rs:13:25 + | +LL | reuse inherent_impl::S::CONST; + | ^^^^^ + +error: failed to resolve delegation callee + --> $DIR/inherent-impls-non-local-crate.rs:17:25 + | +LL | reuse inherent_impl::S::bar; + | ^^^ + error: ambiguous delegation to inherent impl function - --> $DIR/inherent-impls-non-local-crate.rs:19:25 + --> $DIR/inherent-impls-non-local-crate.rs:23:25 | LL | reuse inherent_impl::X::foo as x_foo; | ^^^ @@ -11,19 +35,19 @@ LL | reuse inherent_impl::S::not_existing; | ^^^^^^^^^^^^ associated function or constant not found in `S` error[E0599]: no associated function or constant named `TYPE` found for struct `S` in the current scope - --> $DIR/inherent-impls-non-local-crate.rs:9:25 + --> $DIR/inherent-impls-non-local-crate.rs:10:25 | LL | reuse inherent_impl::S::TYPE; | ^^^^ associated function or constant not found in `S` error[E0618]: expected function, found `usize` - --> $DIR/inherent-impls-non-local-crate.rs:11:25 + --> $DIR/inherent-impls-non-local-crate.rs:13:25 | LL | reuse inherent_impl::S::CONST; | ^^^^^ call expression requires function error[E0599]: no associated function or constant named `bar` found for struct `S` in the current scope - --> $DIR/inherent-impls-non-local-crate.rs:14:25 + --> $DIR/inherent-impls-non-local-crate.rs:17:25 | LL | reuse inherent_impl::S::bar; | ^^^ associated function or constant not found in `S` @@ -35,7 +59,7 @@ LL + use inherent_impl::Trait; | error[E0034]: multiple applicable items in scope - --> $DIR/inherent-impls-non-local-crate.rs:19:25 + --> $DIR/inherent-impls-non-local-crate.rs:23:25 | LL | reuse inherent_impl::X::foo as x_foo; | ^^^ multiple `foo` found @@ -43,7 +67,7 @@ LL | reuse inherent_impl::X::foo as x_foo; = note: candidate #1 is defined in an impl for the type `X` = note: candidate #2 is defined in an impl for the type `X` -error: aborting due to 6 previous errors +error: aborting due to 10 previous errors Some errors have detailed explanations: E0034, E0599, E0618. For more information about an error, try `rustc --explain E0034`. diff --git a/tests/ui/delegation/unused-import-ice-144594.rs b/tests/ui/delegation/unused-import-ice-144594.rs index fca67c6ee0b81..f245b409c4999 100644 --- a/tests/ui/delegation/unused-import-ice-144594.rs +++ b/tests/ui/delegation/unused-import-ice-144594.rs @@ -1,6 +1,6 @@ #![feature(fn_delegation)] -reuse a as b { +reuse a as b { //~ ERROR failed to resolve delegation callee //~^ ERROR cannot find function `a` in this scope [E0425] || { use std::ops::Add; diff --git a/tests/ui/delegation/unused-import-ice-144594.stderr b/tests/ui/delegation/unused-import-ice-144594.stderr index f09313aac21f4..27440c0ff83ec 100644 --- a/tests/ui/delegation/unused-import-ice-144594.stderr +++ b/tests/ui/delegation/unused-import-ice-144594.stderr @@ -10,6 +10,12 @@ error[E0425]: cannot find value `x` in this scope LL | x.add | ^ not found in this scope -error: aborting due to 2 previous errors +error: failed to resolve delegation callee + --> $DIR/unused-import-ice-144594.rs:3:7 + | +LL | reuse a as b { + | ^ + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/delegation/wrong-lifetime-rib.rs b/tests/ui/delegation/wrong-lifetime-rib.rs index e9214b7c42260..ca14583eaa525 100644 --- a/tests/ui/delegation/wrong-lifetime-rib.rs +++ b/tests/ui/delegation/wrong-lifetime-rib.rs @@ -8,7 +8,7 @@ mod ice_156342 { impl Trait { //~^ ERROR: cannot define inherent `impl` for a type outside of the crate where the type is defined - reuse None::<&()>; + reuse None::<&()>; //~ ERROR failed to resolve delegation callee //~^ ERROR: expected function, found unit variant `None` } diff --git a/tests/ui/delegation/wrong-lifetime-rib.stderr b/tests/ui/delegation/wrong-lifetime-rib.stderr index ca759995fec42..447328f579df2 100644 --- a/tests/ui/delegation/wrong-lifetime-rib.stderr +++ b/tests/ui/delegation/wrong-lifetime-rib.stderr @@ -4,6 +4,12 @@ error[E0423]: expected function, found unit variant `None` LL | reuse None::<&()>; | ^^^^^^^^^^^ not a function +error: failed to resolve delegation callee + --> $DIR/wrong-lifetime-rib.rs:11:15 + | +LL | reuse None::<&()>; + | ^^^^ + error: inferred lifetimes are not allowed in delegations as we need to inherit signature --> $DIR/wrong-lifetime-rib.rs:17:18 | @@ -144,7 +150,7 @@ help: you can add the `dyn` keyword if you want a trait object LL | let _: &dyn X; | +++ -error: aborting due to 19 previous errors +error: aborting due to 20 previous errors Some errors have detailed explanations: E0116, E0223, E0423, E0782. For more information about an error, try `rustc --explain E0116`.