From 6d2e82b254fef19f51a45cf92c62e2b8d3ce3c6c Mon Sep 17 00:00:00 2001 From: Lee ByeongJun Date: Tue, 12 Aug 2025 07:49:05 +0900 Subject: [PATCH 01/18] update rotate operation doc --- compiler/rustc_codegen_gcc/src/intrinsic/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index eb0a5336a1f13..82275d8833a44 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -493,9 +493,10 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc } sym::bitreverse => self.bit_reverse(width, args[0].immediate()), sym::rotate_left | sym::rotate_right => { - // TODO(antoyo): implement using algorithm from: + // Using optimized branchless algorithm from: // https://blog.regehr.org/archives/1063 - // for other platforms. + // This implementation uses the pattern (x<>(-n&(width-1))) + // which generates efficient code for other platforms. let is_left = name == sym::rotate_left; let val = args[0].immediate(); let raw_shift = args[1].immediate(); From f5a5f0ff03be6c3feb25440c675ce6bcb787ec23 Mon Sep 17 00:00:00 2001 From: yukang Date: Fri, 21 Nov 2025 20:34:35 +0800 Subject: [PATCH 02/18] use verbose for associated functions suggestion --- .../rustc_hir_typeck/src/method/suggest.rs | 2 +- tests/ui/issues/issue-4265.stderr | 10 ++-- tests/ui/methods/issue-3707.stderr | 10 ++-- tests/ui/suggestions/issue-102354.stderr | 10 ++-- tests/ui/suggestions/issue-103646.stderr | 10 ++-- .../suggest-assoc-fn-call-deref.stderr | 10 ++-- ...uggest-assoc-fn-call-for-impl-trait.stderr | 30 ++++++----- ...-fn-call-with-turbofish-placeholder.stderr | 10 ++-- ...n-call-with-turbofish-through-deref.stderr | 10 ++-- ...uggest-assoc-fn-call-with-turbofish.stderr | 50 +++++++++++-------- ...gest-assoc-fn-call-without-receiver.stderr | 40 +++++++++------ 11 files changed, 115 insertions(+), 77 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index a0d9e9a72386c..37661f93f0217 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2339,7 +2339,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { applicability = Applicability::HasPlaceholders; "(...)".to_owned() }; - err.span_suggestion( + err.span_suggestion_verbose( sugg_span, "use associated function syntax instead", format!("{ty_str}::{item_name}{args}"), diff --git a/tests/ui/issues/issue-4265.stderr b/tests/ui/issues/issue-4265.stderr index 23d00aaa44b54..d4a44c129a89e 100644 --- a/tests/ui/issues/issue-4265.stderr +++ b/tests/ui/issues/issue-4265.stderr @@ -14,10 +14,7 @@ LL | struct Foo { | ---------- method `bar` not found for this struct ... LL | Foo { baz: 0 }.bar(); - | ---------------^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `Foo::bar()` + | ^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `Foo` @@ -25,6 +22,11 @@ note: the candidate is defined in an impl for the type `Foo` | LL | fn bar() { | ^^^^^^^^ +help: use associated function syntax instead + | +LL - Foo { baz: 0 }.bar(); +LL + Foo::bar(); + | error: aborting due to 2 previous errors diff --git a/tests/ui/methods/issue-3707.stderr b/tests/ui/methods/issue-3707.stderr index b3d4dfe5aaa88..c163ccc81899a 100644 --- a/tests/ui/methods/issue-3707.stderr +++ b/tests/ui/methods/issue-3707.stderr @@ -2,10 +2,7 @@ error[E0599]: no method named `boom` found for reference `&Obj` in the current s --> $DIR/issue-3707.rs:10:14 | LL | self.boom(); - | -----^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `Obj::boom()` + | ^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `Obj` @@ -13,6 +10,11 @@ note: the candidate is defined in an impl for the type `Obj` | LL | pub fn boom() -> bool { | ^^^^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - self.boom(); +LL + Obj::boom(); + | error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/issue-102354.stderr b/tests/ui/suggestions/issue-102354.stderr index 8340d9340f9b2..9354ce3efe57d 100644 --- a/tests/ui/suggestions/issue-102354.stderr +++ b/tests/ui/suggestions/issue-102354.stderr @@ -2,10 +2,7 @@ error[E0599]: no method named `func` found for type `i32` in the current scope --> $DIR/issue-102354.rs:9:7 | LL | x.func(); - | --^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `i32::func()` + | ^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in the trait `Trait` @@ -13,6 +10,11 @@ note: the candidate is defined in the trait `Trait` | LL | fn func() {} | ^^^^^^^^^ +help: use associated function syntax instead + | +LL - x.func(); +LL + i32::func(); + | error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/issue-103646.stderr b/tests/ui/suggestions/issue-103646.stderr index 8d0e8652392d6..42505e13e7e68 100644 --- a/tests/ui/suggestions/issue-103646.stderr +++ b/tests/ui/suggestions/issue-103646.stderr @@ -4,10 +4,7 @@ error[E0599]: no method named `nya` found for type parameter `T` in the current LL | fn uwu(c: T) { | - method `nya` not found for this type parameter LL | c.nya(); - | --^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `T::nya()` + | ^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in the trait `Cat` @@ -15,6 +12,11 @@ note: the candidate is defined in the trait `Cat` | LL | fn nya() {} | ^^^^^^^^ +help: use associated function syntax instead + | +LL - c.nya(); +LL + T::nya(); + | error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-deref.stderr b/tests/ui/suggestions/suggest-assoc-fn-call-deref.stderr index a30b78692146b..2314ff378f641 100644 --- a/tests/ui/suggestions/suggest-assoc-fn-call-deref.stderr +++ b/tests/ui/suggestions/suggest-assoc-fn-call-deref.stderr @@ -2,10 +2,7 @@ error[E0599]: no method named `test` found for struct `Box>` in the cur --> $DIR/suggest-assoc-fn-call-deref.rs:13:7 | LL | x.test(); - | --^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `Foo::::test()` + | ^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `Foo` @@ -13,6 +10,11 @@ note: the candidate is defined in an impl for the type `Foo` | LL | fn test() -> i32 { 1 } | ^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - x.test(); +LL + Foo::::test(); + | error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.stderr b/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.stderr index 0df2b08d3be82..4ff4c50f17902 100644 --- a/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.stderr +++ b/tests/ui/suggestions/suggest-assoc-fn-call-for-impl-trait.stderr @@ -5,10 +5,7 @@ LL | struct A { | -------- method `foo` not found for this struct ... LL | _a.foo(); - | ---^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `A::foo(_a)` + | ^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in the trait `M` @@ -16,6 +13,11 @@ note: the candidate is defined in the trait `M` | LL | fn foo(_a: Self); | ^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - _a.foo(); +LL + A::foo(_a); + | error[E0599]: no method named `baz` found for struct `A` in the current scope --> $DIR/suggest-assoc-fn-call-for-impl-trait.rs:23:8 @@ -24,10 +26,7 @@ LL | struct A { | -------- method `baz` not found for this struct ... LL | _a.baz(0); - | ---^^^--- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `A::baz(0)` + | ^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in the trait `M` @@ -35,6 +34,11 @@ note: the candidate is defined in the trait `M` | LL | fn baz(_a: i32); | ^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - _a.baz(0); +LL + A::baz(0); + | error[E0599]: no method named `bar` found for struct `A` in the current scope --> $DIR/suggest-assoc-fn-call-for-impl-trait.rs:27:8 @@ -43,10 +47,7 @@ LL | struct A { | -------- method `bar` not found for this struct ... LL | _b.bar(); - | ---^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `A::bar(_b)` + | ^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in the trait `M` @@ -54,6 +55,11 @@ note: the candidate is defined in the trait `M` | LL | fn bar(_a: Self); | ^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - _b.bar(); +LL + A::bar(_b); + | error: aborting due to 3 previous errors diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish-placeholder.stderr b/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish-placeholder.stderr index 6e4c77deac50f..df8d80c4babfe 100644 --- a/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish-placeholder.stderr +++ b/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish-placeholder.stderr @@ -5,10 +5,7 @@ LL | struct GenericAssocMethod(T); | ---------------------------- method `default_hello` not found for this struct ... LL | x.default_hello(); - | --^^^^^^^^^^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `GenericAssocMethod::<_>::default_hello()` + | ^^^^^^^^^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `GenericAssocMethod` @@ -16,6 +13,11 @@ note: the candidate is defined in an impl for the type `GenericAssocMethod` | LL | fn default_hello() {} | ^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - x.default_hello(); +LL + GenericAssocMethod::<_>::default_hello(); + | error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr b/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr index 1bc2592944699..99d206764a17e 100644 --- a/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr +++ b/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr @@ -2,10 +2,7 @@ error[E0599]: no method named `hello` found for struct `RefMut<'_, HasAssocMetho --> $DIR/suggest-assoc-fn-call-with-turbofish-through-deref.rs:11:11 | LL | state.hello(); - | ------^^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `HasAssocMethod::hello()` + | ^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `HasAssocMethod` @@ -13,6 +10,11 @@ note: the candidate is defined in an impl for the type `HasAssocMethod` | LL | fn hello() {} | ^^^^^^^^^^ +help: use associated function syntax instead + | +LL - state.hello(); +LL + HasAssocMethod::hello(); + | error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr b/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr index 92b03fc77142c..56d6b9fcd143d 100644 --- a/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr +++ b/tests/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr @@ -5,10 +5,7 @@ LL | struct GenericAssocMethod(T); | ---------------------------- method `self_ty_ref_hello` not found for this struct ... LL | x.self_ty_ref_hello(); - | --^^^^^^^^^^^^^^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `GenericAssocMethod::<_>::self_ty_ref_hello(&x)` + | ^^^^^^^^^^^^^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `GenericAssocMethod` @@ -16,6 +13,11 @@ note: the candidate is defined in an impl for the type `GenericAssocMethod` | LL | fn self_ty_ref_hello(_: &Self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - x.self_ty_ref_hello(); +LL + GenericAssocMethod::<_>::self_ty_ref_hello(&x); + | error[E0599]: no method named `self_ty_hello` found for struct `GenericAssocMethod<{integer}>` in the current scope --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:16:7 @@ -24,10 +26,7 @@ LL | struct GenericAssocMethod(T); | ---------------------------- method `self_ty_hello` not found for this struct ... LL | x.self_ty_hello(); - | --^^^^^^^^^^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `GenericAssocMethod::<_>::self_ty_hello(x)` + | ^^^^^^^^^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `GenericAssocMethod` @@ -35,6 +34,11 @@ note: the candidate is defined in an impl for the type `GenericAssocMethod` | LL | fn self_ty_hello(_: Self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - x.self_ty_hello(); +LL + GenericAssocMethod::<_>::self_ty_hello(x); + | error[E0599]: no method named `default_hello` found for struct `GenericAssocMethod` in the current scope --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:20:7 @@ -43,10 +47,7 @@ LL | struct GenericAssocMethod(T); | ---------------------------- method `default_hello` not found for this struct ... LL | y.default_hello(); - | --^^^^^^^^^^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `GenericAssocMethod::::default_hello()` + | ^^^^^^^^^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `GenericAssocMethod` @@ -54,6 +55,11 @@ note: the candidate is defined in an impl for the type `GenericAssocMethod` | LL | fn default_hello() {} | ^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - y.default_hello(); +LL + GenericAssocMethod::::default_hello(); + | error[E0599]: no method named `self_ty_ref_hello` found for struct `GenericAssocMethod` in the current scope --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:22:7 @@ -62,10 +68,7 @@ LL | struct GenericAssocMethod(T); | ---------------------------- method `self_ty_ref_hello` not found for this struct ... LL | y.self_ty_ref_hello(); - | --^^^^^^^^^^^^^^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `GenericAssocMethod::::self_ty_ref_hello(&y)` + | ^^^^^^^^^^^^^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `GenericAssocMethod` @@ -73,6 +76,11 @@ note: the candidate is defined in an impl for the type `GenericAssocMethod` | LL | fn self_ty_ref_hello(_: &Self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - y.self_ty_ref_hello(); +LL + GenericAssocMethod::::self_ty_ref_hello(&y); + | error[E0599]: no method named `self_ty_hello` found for struct `GenericAssocMethod` in the current scope --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:24:7 @@ -81,10 +89,7 @@ LL | struct GenericAssocMethod(T); | ---------------------------- method `self_ty_hello` not found for this struct ... LL | y.self_ty_hello(); - | --^^^^^^^^^^^^^-- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `GenericAssocMethod::::self_ty_hello(y)` + | ^^^^^^^^^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `GenericAssocMethod` @@ -92,6 +97,11 @@ note: the candidate is defined in an impl for the type `GenericAssocMethod` | LL | fn self_ty_hello(_: Self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - y.self_ty_hello(); +LL + GenericAssocMethod::::self_ty_hello(y); + | error: aborting due to 5 previous errors diff --git a/tests/ui/suggestions/suggest-assoc-fn-call-without-receiver.stderr b/tests/ui/suggestions/suggest-assoc-fn-call-without-receiver.stderr index 793595784d937..a09cf41488df9 100644 --- a/tests/ui/suggestions/suggest-assoc-fn-call-without-receiver.stderr +++ b/tests/ui/suggestions/suggest-assoc-fn-call-without-receiver.stderr @@ -5,10 +5,7 @@ LL | struct A {} | -------- method `hello` not found for this struct ... LL | _a.hello(1); - | ---^^^^^--- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `A::hello(1)` + | ^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `A` @@ -16,6 +13,11 @@ note: the candidate is defined in an impl for the type `A` | LL | fn hello(_a: i32) {} | ^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - _a.hello(1); +LL + A::hello(1); + | error[E0599]: no method named `test` found for struct `A` in the current scope --> $DIR/suggest-assoc-fn-call-without-receiver.rs:22:8 @@ -24,10 +26,7 @@ LL | struct A {} | -------- method `test` not found for this struct ... LL | _a.test(1); - | ---^^^^--- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `A::test(_a, 1)` + | ^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `A` @@ -35,6 +34,11 @@ note: the candidate is defined in an impl for the type `A` | LL | fn test(_a: Self, _b: i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - _a.test(1); +LL + A::test(_a, 1); + | error[E0599]: no method named `hello` found for struct `B<&str>` in the current scope --> $DIR/suggest-assoc-fn-call-without-receiver.rs:26:8 @@ -43,10 +47,7 @@ LL | struct B { | ----------- method `hello` not found for this struct ... LL | _b.hello(1); - | ---^^^^^--- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `B::<&str>::hello(1)` + | ^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `B` @@ -54,6 +55,11 @@ note: the candidate is defined in an impl for the type `B` | LL | fn hello(_a: i32) {} | ^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - _b.hello(1); +LL + B::<&str>::hello(1); + | error[E0599]: no method named `test` found for struct `B<&str>` in the current scope --> $DIR/suggest-assoc-fn-call-without-receiver.rs:28:8 @@ -62,10 +68,7 @@ LL | struct B { | ----------- method `test` not found for this struct ... LL | _b.test(1); - | ---^^^^--- - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `B::<&str>::test(_b, 1)` + | ^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `B` @@ -73,6 +76,11 @@ note: the candidate is defined in an impl for the type `B` | LL | fn test(_a: Self, _b: i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - _b.test(1); +LL + B::<&str>::test(_b, 1); + | error: aborting due to 4 previous errors From e802180f416b1e30b70e605e4d950ea5e5564745 Mon Sep 17 00:00:00 2001 From: yukang Date: Fri, 21 Nov 2025 21:04:13 +0800 Subject: [PATCH 03/18] add suggestion for associated function --- compiler/rustc_hir_typeck/src/expr.rs | 34 +++++++++++++++ tests/ui/methods/assc-func-issue-149038.rs | 10 +++++ .../ui/methods/assc-func-issue-149038.stderr | 43 +++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 tests/ui/methods/assc-func-issue-149038.rs create mode 100644 tests/ui/methods/assc-func-issue-149038.stderr diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 658f9857e5e10..29eb1183953aa 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3369,6 +3369,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(within_macro_span, "due to this macro variable"); } + // Check if there is an associated function with the same name. + if let Some(def_id) = base_ty.peel_refs().ty_adt_def().map(|d| d.did()) { + for impl_def_id in self.tcx.inherent_impls(def_id) { + for item in self.tcx.associated_items(impl_def_id).in_definition_order() { + if let ExprKind::Field(base_expr, _) = expr.kind + && item.name() == field.name + && matches!(item.kind, ty::AssocKind::Fn { has_self: false, .. }) + { + err.span_label(field.span, "this is an associated function, not a method"); + err.note("found the following associated function; to be used as method, it must have a `self` parameter"); + let impl_ty = self.tcx.type_of(impl_def_id).instantiate_identity(); + err.span_note( + self.tcx.def_span(item.def_id), + format!("the candidate is defined in an impl for the type `{impl_ty}`"), + ); + + let ty_str = match base_ty.peel_refs().kind() { + ty::Adt(def, args) => self.tcx.def_path_str_with_args(def.did(), args), + _ => base_ty.peel_refs().to_string(), + }; + err.multipart_suggestion( + "use associated function syntax instead", + vec![ + (base_expr.span, ty_str), + (base_expr.span.between(field.span), "::".to_string()), + ], + Applicability::MaybeIncorrect, + ); + return err; + } + } + } + } + // try to add a suggestion in case the field is a nested field of a field of the Adt let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id(); let (ty, unwrap) = if let ty::Adt(def, args) = base_ty.kind() diff --git a/tests/ui/methods/assc-func-issue-149038.rs b/tests/ui/methods/assc-func-issue-149038.rs new file mode 100644 index 0000000000000..4fb4bd72fcc30 --- /dev/null +++ b/tests/ui/methods/assc-func-issue-149038.rs @@ -0,0 +1,10 @@ +struct S; +impl S { + fn foo() {} + fn bar(&self) { + self.foo(); //~ ERROR no method named `foo` found for reference `&S` in the current scope + let f: fn() = self.foo; //~ ERROR no field `foo` on type `&S` + } +} + +fn main() {} diff --git a/tests/ui/methods/assc-func-issue-149038.stderr b/tests/ui/methods/assc-func-issue-149038.stderr new file mode 100644 index 0000000000000..55b762bc0ee02 --- /dev/null +++ b/tests/ui/methods/assc-func-issue-149038.stderr @@ -0,0 +1,43 @@ +error[E0599]: no method named `foo` found for reference `&S` in the current scope + --> $DIR/assc-func-issue-149038.rs:5:14 + | +LL | self.foo(); + | ^^^ this is an associated function, not a method + | + = note: found the following associated functions; to be used as methods, functions must have a `self` parameter +note: the candidate is defined in an impl for the type `S` + --> $DIR/assc-func-issue-149038.rs:3:5 + | +LL | fn foo() {} + | ^^^^^^^^ +help: use associated function syntax instead + | +LL - self.foo(); +LL + S::foo(); + | + +error[E0609]: no field `foo` on type `&S` + --> $DIR/assc-func-issue-149038.rs:6:28 + | +LL | let f: fn() = self.foo; + | ^^^ + | | + | this is an associated function, not a method + | unknown field + | + = note: found the following associated function; to be used as method, it must have a `self` parameter +note: the candidate is defined in an impl for the type `S` + --> $DIR/assc-func-issue-149038.rs:3:5 + | +LL | fn foo() {} + | ^^^^^^^^ +help: use associated function syntax instead + | +LL - let f: fn() = self.foo; +LL + let f: fn() = S::foo; + | + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0599, E0609. +For more information about an error, try `rustc --explain E0599`. From 1b790cdcac1d0f156f312b59b318ae42eb84797c Mon Sep 17 00:00:00 2001 From: Andrew Zhogin Date: Thu, 11 Dec 2025 16:46:32 +0700 Subject: [PATCH 04/18] Weak for Arc pointer is marked as DynSend/DynSync --- compiler/rustc_data_structures/src/marker.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index 0ef3bb319ff80..72d5f004194a8 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -75,6 +75,7 @@ impl_dyn_send!( [std::sync::Mutex where T: ?Sized+ DynSend] [std::sync::mpsc::Sender where T: DynSend] [std::sync::Arc where T: ?Sized + DynSync + DynSend] + [std::sync::Weak where T: ?Sized + DynSync + DynSend] [std::sync::LazyLock where T: DynSend, F: DynSend] [std::collections::HashSet where K: DynSend, S: DynSend] [std::collections::HashMap where K: DynSend, V: DynSend, S: DynSend] @@ -157,6 +158,7 @@ impl_dyn_sync!( [std::sync::OnceLock where T: DynSend + DynSync] [std::sync::Mutex where T: ?Sized + DynSend] [std::sync::Arc where T: ?Sized + DynSync + DynSend] + [std::sync::Weak where T: ?Sized + DynSync + DynSend] [std::sync::LazyLock where T: DynSend + DynSync, F: DynSend] [std::collections::HashSet where K: DynSync, S: DynSync] [std::collections::HashMap where K: DynSync, V: DynSync, S: DynSync] From 04fedf71738c44e716b01480550787d99c47a254 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 12 Dec 2025 09:12:31 +0100 Subject: [PATCH 05/18] Remove unused code in `cfg_old` --- compiler/rustc_attr_parsing/messages.ftl | 10 - .../rustc_attr_parsing/src/attributes/cfg.rs | 22 +- .../src/attributes/cfg_old.rs | 210 ------------------ .../rustc_attr_parsing/src/attributes/mod.rs | 1 - .../src/attributes/stability.rs | 4 +- compiler/rustc_attr_parsing/src/lib.rs | 1 - .../src/session_diagnostics.rs | 37 +-- 7 files changed, 22 insertions(+), 263 deletions(-) delete mode 100644 compiler/rustc_attr_parsing/src/attributes/cfg_old.rs diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index f2642838b3c8c..deebc25c8259e 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -6,9 +6,6 @@ attr_parsing_bundle_needs_static = attr_parsing_cfg_attr_bad_delim = wrong `cfg_attr` delimiters -attr_parsing_cfg_predicate_identifier = - `cfg` predicate key must be an identifier - attr_parsing_deprecated_item_suggestion = suggestions on deprecated items are unstable .help = add `#![feature(deprecated_suggestion)]` to the crate root @@ -41,9 +38,6 @@ attr_parsing_empty_link_name = link name must not be empty .label = empty link name -attr_parsing_expected_one_cfg_pattern = - expected 1 cfg-pattern - attr_parsing_expected_single_version_literal = expected single version literal @@ -241,10 +235,6 @@ attr_parsing_unstable_cfg_target_compact = attr_parsing_unstable_feature_bound_incompatible_stability = item annotated with `#[unstable_feature_bound]` should not be stable .help = If this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]` -attr_parsing_unsupported_literal_cfg_boolean = - literal in `cfg` predicate value must be a boolean -attr_parsing_unsupported_literal_cfg_string = - literal in `cfg` predicate value must be a string attr_parsing_unsupported_literal_generic = unsupported literal attr_parsing_unsupported_literal_suggestion = diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 6ffe25098308a..93f4255309411 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -4,7 +4,9 @@ use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::DelimSpan; use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, ast, token}; use rustc_errors::{Applicability, PResult}; -use rustc_feature::{AttrSuggestionStyle, AttributeTemplate, Features, template}; +use rustc_feature::{ + AttrSuggestionStyle, AttributeTemplate, Features, GatedCfg, find_gated_cfg, template, +}; use rustc_hir::attrs::CfgEntry; use rustc_hir::lints::AttributeLintKind; use rustc_hir::{AttrPath, RustcVersion}; @@ -23,7 +25,7 @@ use crate::session_diagnostics::{ AttributeParseError, AttributeParseErrorReason, CfgAttrBadDelim, MetaBadDelimSugg, ParsedDescription, }; -use crate::{AttributeParser, fluent_generated, parse_version, session_diagnostics, try_gate_cfg}; +use crate::{AttributeParser, fluent_generated, parse_version, session_diagnostics}; pub const CFG_TEMPLATE: AttributeTemplate = template!( List: &["predicate"], @@ -410,3 +412,19 @@ fn parse_cfg_attr_internal<'a>( Ok((cfg_predicate, expanded_attrs)) } + +fn try_gate_cfg(name: Symbol, span: Span, sess: &Session, features: Option<&Features>) { + let gate = find_gated_cfg(|sym| sym == name); + if let (Some(feats), Some(gated_cfg)) = (features, gate) { + gate_cfg(gated_cfg, span, sess, feats); + } +} + +#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable +fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &Session, features: &Features) { + let (cfg, feature, has_feature) = gated_cfg; + if !has_feature(features) && !cfg_span.allows_unstable(*feature) { + let explain = format!("`cfg({cfg})` is experimental and subject to change"); + feature_err(sess, *feature, cfg_span, explain).emit(); + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs deleted file mode 100644 index acb234480d5dd..0000000000000 --- a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs +++ /dev/null @@ -1,210 +0,0 @@ -use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NodeId}; -use rustc_ast_pretty::pprust; -use rustc_feature::{Features, GatedCfg, find_gated_cfg}; -use rustc_hir::RustcVersion; -use rustc_session::Session; -use rustc_session::lint::{BuiltinLintDiag, Lint}; -use rustc_session::parse::feature_err; -use rustc_span::{Span, Symbol, sym}; - -use crate::session_diagnostics::{self, UnsupportedLiteralReason}; -use crate::{fluent_generated, parse_version}; - -/// Emitter of a builtin lint from `cfg_matches`. -/// -/// Used to support emitting a lint (currently on check-cfg), either: -/// - as an early buffered lint (in `rustc`) -/// - or has a "normal" lint from HIR (in `rustdoc`) -pub trait CfgMatchesLintEmitter { - fn emit_span_lint(&self, sess: &Session, lint: &'static Lint, sp: Span, diag: BuiltinLintDiag); -} - -impl CfgMatchesLintEmitter for NodeId { - fn emit_span_lint(&self, sess: &Session, lint: &'static Lint, sp: Span, diag: BuiltinLintDiag) { - sess.psess.buffer_lint(lint, sp, *self, diag); - } -} - -#[derive(Clone, Debug)] -pub struct Condition { - pub name: Symbol, - pub name_span: Span, - pub value: Option, - pub value_span: Option, - pub span: Span, -} - -pub fn try_gate_cfg(name: Symbol, span: Span, sess: &Session, features: Option<&Features>) { - let gate = find_gated_cfg(|sym| sym == name); - if let (Some(feats), Some(gated_cfg)) = (features, gate) { - gate_cfg(gated_cfg, span, sess, feats); - } -} - -#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable -fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &Session, features: &Features) { - let (cfg, feature, has_feature) = gated_cfg; - if !has_feature(features) && !cfg_span.allows_unstable(*feature) { - let explain = format!("`cfg({cfg})` is experimental and subject to change"); - feature_err(sess, *feature, cfg_span, explain).emit(); - } -} - -/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to -/// evaluate individual items. -pub fn eval_condition( - cfg: &MetaItemInner, - sess: &Session, - features: Option<&Features>, - eval: &mut impl FnMut(Condition) -> bool, -) -> bool { - let dcx = sess.dcx(); - - let cfg = match cfg { - MetaItemInner::MetaItem(meta_item) => meta_item, - MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => { - return *b; - } - _ => { - dcx.emit_err(session_diagnostics::UnsupportedLiteral { - span: cfg.span(), - reason: UnsupportedLiteralReason::CfgBoolean, - is_bytestr: false, - start_point_span: sess.source_map().start_point(cfg.span()), - }); - return false; - } - }; - - match &cfg.kind { - MetaItemKind::List(mis) if cfg.has_name(sym::version) => { - try_gate_cfg(sym::version, cfg.span, sess, features); - let (min_version, span) = match &mis[..] { - [MetaItemInner::Lit(MetaItemLit { kind: LitKind::Str(sym, ..), span, .. })] => { - (sym, span) - } - [ - MetaItemInner::Lit(MetaItemLit { span, .. }) - | MetaItemInner::MetaItem(MetaItem { span, .. }), - ] => { - dcx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: *span }); - return false; - } - [..] => { - dcx.emit_err(session_diagnostics::ExpectedSingleVersionLiteral { - span: cfg.span, - }); - return false; - } - }; - let Some(min_version) = parse_version(*min_version) else { - dcx.emit_warn(session_diagnostics::UnknownVersionLiteral { span: *span }); - return false; - }; - - // See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details - if sess.psess.assume_incomplete_release { - RustcVersion::current_overridable() > min_version - } else { - RustcVersion::current_overridable() >= min_version - } - } - MetaItemKind::List(mis) => { - for mi in mis.iter() { - if mi.meta_item_or_bool().is_none() { - dcx.emit_err(session_diagnostics::UnsupportedLiteral { - span: mi.span(), - reason: UnsupportedLiteralReason::Generic, - is_bytestr: false, - start_point_span: sess.source_map().start_point(mi.span()), - }); - return false; - } - } - - // The unwraps below may look dangerous, but we've already asserted - // that they won't fail with the loop above. - match cfg.name() { - Some(sym::any) => mis - .iter() - // We don't use any() here, because we want to evaluate all cfg condition - // as eval_condition can (and does) extra checks - .fold(false, |res, mi| res | eval_condition(mi, sess, features, eval)), - Some(sym::all) => mis - .iter() - // We don't use all() here, because we want to evaluate all cfg condition - // as eval_condition can (and does) extra checks - .fold(true, |res, mi| res & eval_condition(mi, sess, features, eval)), - Some(sym::not) => { - let [mi] = mis.as_slice() else { - dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span }); - return false; - }; - - !eval_condition(mi, sess, features, eval) - } - Some(sym::target) => { - if let Some(features) = features - && !features.cfg_target_compact() - { - feature_err( - sess, - sym::cfg_target_compact, - cfg.span, - fluent_generated::attr_parsing_unstable_cfg_target_compact, - ) - .emit(); - } - - mis.iter().fold(true, |res, mi| { - let Some(mut mi) = mi.meta_item().cloned() else { - dcx.emit_err(session_diagnostics::CfgPredicateIdentifier { - span: mi.span(), - }); - return false; - }; - - if let [seg, ..] = &mut mi.path.segments[..] { - seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name)); - } - - res & eval_condition(&MetaItemInner::MetaItem(mi), sess, features, eval) - }) - } - _ => { - dcx.emit_err(session_diagnostics::InvalidPredicate { - span: cfg.span, - predicate: pprust::path_to_string(&cfg.path), - }); - false - } - } - } - MetaItemKind::Word | MetaItemKind::NameValue(..) - if cfg.path.segments.len() != 1 - || cfg.path.segments[0].ident.is_path_segment_keyword() => - { - dcx.emit_err(session_diagnostics::CfgPredicateIdentifier { span: cfg.path.span }); - true - } - MetaItemKind::NameValue(lit) if !lit.kind.is_str() => { - dcx.emit_err(session_diagnostics::UnsupportedLiteral { - span: lit.span, - reason: UnsupportedLiteralReason::CfgString, - is_bytestr: lit.kind.is_bytestr(), - start_point_span: sess.source_map().start_point(lit.span), - }); - true - } - MetaItemKind::Word | MetaItemKind::NameValue(..) => { - let ident = cfg.ident().expect("multi-segment cfg predicate"); - eval(Condition { - name: ident.name, - name_span: ident.span, - value: cfg.value_str(), - value_span: cfg.name_value_literal_span(), - span: cfg.span, - }) - } - } -} diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 64bcb02b0b745..385003a359275 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -32,7 +32,6 @@ mod prelude; pub(crate) mod allow_unstable; pub(crate) mod body; pub(crate) mod cfg; -pub(crate) mod cfg_old; pub(crate) mod cfg_select; pub(crate) mod codegen_attrs; pub(crate) mod confusables; diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index b94e23477ffeb..b97095893b8e2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -8,7 +8,7 @@ use rustc_hir::{ use super::prelude::*; use super::util::parse_version; -use crate::session_diagnostics::{self, UnsupportedLiteralReason}; +use crate::session_diagnostics::{self}; macro_rules! reject_outside_std { ($cx: ident) => { @@ -304,7 +304,6 @@ pub(crate) fn parse_stability( let Some(param) = param.meta_item() else { cx.emit_err(session_diagnostics::UnsupportedLiteral { span: param_span, - reason: UnsupportedLiteralReason::Generic, is_bytestr: false, start_point_span: cx.sess().source_map().start_point(param_span), }); @@ -384,7 +383,6 @@ pub(crate) fn parse_unstability( let Some(param) = param.meta_item() else { cx.emit_err(session_diagnostics::UnsupportedLiteral { span: param.span(), - reason: UnsupportedLiteralReason::Generic, is_bytestr: false, start_point_span: cx.sess().source_map().start_point(param.span()), }); diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index cb02bb9d501fc..411b4dd75e661 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -107,7 +107,6 @@ pub mod validate_attr; pub use attributes::cfg::{ CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg, parse_cfg_attr, parse_cfg_entry, }; -pub use attributes::cfg_old::*; pub use attributes::cfg_select::*; pub use attributes::util::{is_builtin_attr, parse_version}; pub use context::{Early, Late, OmitDoc, ShouldEmit}; diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 7bb55d2a6de5b..df555a33f816b 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -12,19 +12,6 @@ use rustc_span::{Span, Symbol}; use crate::fluent_generated as fluent; -pub(crate) enum UnsupportedLiteralReason { - Generic, - CfgString, - CfgBoolean, -} - -#[derive(Diagnostic)] -#[diag(attr_parsing_expected_one_cfg_pattern, code = E0536)] -pub(crate) struct ExpectedOneCfgPattern { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(attr_parsing_invalid_predicate, code = E0537)] pub(crate) struct InvalidPredicate { @@ -234,28 +221,13 @@ pub(crate) struct InvalidReprHintNoValue { // FIXME(jdonszelmann): slowly phased out pub(crate) struct UnsupportedLiteral { pub span: Span, - pub reason: UnsupportedLiteralReason, pub is_bytestr: bool, pub start_point_span: Span, } impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { - let mut diag = Diag::new( - dcx, - level, - match self.reason { - UnsupportedLiteralReason::Generic => { - fluent::attr_parsing_unsupported_literal_generic - } - UnsupportedLiteralReason::CfgString => { - fluent::attr_parsing_unsupported_literal_cfg_string - } - UnsupportedLiteralReason::CfgBoolean => { - fluent::attr_parsing_unsupported_literal_cfg_boolean - } - }, - ); + let mut diag = Diag::new(dcx, level, fluent::attr_parsing_unsupported_literal_generic); diag.span(self.span); diag.code(E0565); if self.is_bytestr { @@ -375,13 +347,6 @@ pub(crate) struct RustcAllowedUnstablePairing { pub span: Span, } -#[derive(Diagnostic)] -#[diag(attr_parsing_cfg_predicate_identifier)] -pub(crate) struct CfgPredicateIdentifier { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(attr_parsing_deprecated_item_suggestion)] pub(crate) struct DeprecatedItemSuggestion { From acea7df0b4fdba04f94528f19ea1333cd68d2670 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 12 Dec 2025 09:24:49 +0100 Subject: [PATCH 06/18] Remove last remaining usages of `UnsupportedLiteral` --- compiler/rustc_attr_parsing/messages.ftl | 2 -- .../src/attributes/stability.rs | 12 ++------- .../src/session_diagnostics.rs | 25 ------------------- 3 files changed, 2 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index deebc25c8259e..61f816f0baf8f 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -235,8 +235,6 @@ attr_parsing_unstable_cfg_target_compact = attr_parsing_unstable_feature_bound_incompatible_stability = item annotated with `#[unstable_feature_bound]` should not be stable .help = If this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]` -attr_parsing_unsupported_literal_generic = - unsupported literal attr_parsing_unsupported_literal_suggestion = consider removing the prefix diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index b97095893b8e2..fede424c3af7d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -302,11 +302,7 @@ pub(crate) fn parse_stability( for param in list.mixed() { let param_span = param.span(); let Some(param) = param.meta_item() else { - cx.emit_err(session_diagnostics::UnsupportedLiteral { - span: param_span, - is_bytestr: false, - start_point_span: cx.sess().source_map().start_point(param_span), - }); + cx.unexpected_literal(param.span()); return None; }; @@ -381,11 +377,7 @@ pub(crate) fn parse_unstability( for param in list.mixed() { let Some(param) = param.meta_item() else { - cx.emit_err(session_diagnostics::UnsupportedLiteral { - span: param.span(), - is_bytestr: false, - start_point_span: cx.sess().source_map().start_point(param.span()), - }); + cx.unexpected_literal(param.span()); return None; }; diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index df555a33f816b..3adbe115b23b5 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -217,31 +217,6 @@ pub(crate) struct InvalidReprHintNoValue { pub name: Symbol, } -/// Error code: E0565 -// FIXME(jdonszelmann): slowly phased out -pub(crate) struct UnsupportedLiteral { - pub span: Span, - pub is_bytestr: bool, - pub start_point_span: Span, -} - -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral { - fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { - let mut diag = Diag::new(dcx, level, fluent::attr_parsing_unsupported_literal_generic); - diag.span(self.span); - diag.code(E0565); - if self.is_bytestr { - diag.span_suggestion( - self.start_point_span, - fluent::attr_parsing_unsupported_literal_suggestion, - "", - Applicability::MaybeIncorrect, - ); - } - diag - } -} - #[derive(Diagnostic)] #[diag(attr_parsing_invalid_repr_align_need_arg, code = E0589)] pub(crate) struct InvalidReprAlignNeedArg { From 3f63f521c1f611c2d68eaaf1fe5f9a3f08be3ed5 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 12 Dec 2025 22:06:07 +1100 Subject: [PATCH 07/18] Don't pass an unused `--color` to compiletest This flag was an artifact of compiletest's old libtest-based test executor, and currently doesn't influence compiletest's output at all. --- src/bootstrap/src/core/build_steps/test.rs | 1 - src/tools/compiletest/src/lib.rs | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index a699cd23fb607..f30641d71e839 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2401,7 +2401,6 @@ Please disable assertions with `rust.debug-assertions = false`. let git_config = builder.config.git_config(); cmd.arg("--nightly-branch").arg(git_config.nightly_branch); cmd.arg("--git-merge-commit-email").arg(git_config.git_merge_commit_email); - cmd.force_coloring_in_ci(); #[cfg(feature = "build-metrics")] builder.metrics.begin_test_suite( diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 1fa818df62dea..71dad36337932 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -136,8 +136,6 @@ fn parse_config(args: Vec) -> Config { ) .optflag("", "fail-fast", "stop as soon as possible after any test fails") .optopt("", "target", "the target to build for", "TARGET") - // FIXME: Should be removed once `bootstrap` will be updated to not use this option. - .optopt("", "color", "coloring: auto, always, never", "WHEN") .optopt("", "host", "the host to build for", "HOST") .optopt("", "cdb", "path to CDB to use for CDB debuginfo tests", "PATH") .optopt("", "gdb", "path to GDB to use for GDB debuginfo tests", "PATH") From ac5c70ad4d5d8f767237f5b3d28719fbc5d72bc8 Mon Sep 17 00:00:00 2001 From: Clara Engler Date: Tue, 11 Nov 2025 11:46:11 +0100 Subject: [PATCH 08/18] time: Implement SystemTime::{MIN, MAX} This commit introduces two new constants to SystemTime: `MIN` and `MAX`, whose value represent the maximum values for the respective data type, depending upon the platform. Technically, this value is already obtainable during runtime with the following algorithm: Use `SystemTime::UNIX_EPOCH` and call `checked_add` (or `checked_sub`) repeatedly with `Duration::new(0, 1)` on it, until it returns None. Mathematically speaking, this algorithm will terminate after a finite amount of steps, yet it is impractical to run it, as it takes practically forever. Besides, this commit also adds a unit test. Concrete implementation depending upon the platform is done in later commits. In the future, the hope of the authors lies within the creation of a `SystemTime::saturating_add` and `SystemTime::saturating_sub`, similar to the functions already present in `std::time::Duration`. However, for those, these constants are crucially required, thereby this should be seen as the initial step towards this direction. Below are platform specifc notes: # Hermit The HermitOS implementation is more or less identitcal to the Unix one. # sgx The implementation uses a `Duration` to store the Unix time, thereby implying `Duration::ZERO` and `Duration::MAX` as the limits. # solid The implementation uses a `time_t` to store the system time within a single value (i.e. no dual secs/nanosecs handling), thereby implying its `::MIN` and `::MAX` values as the respective boundaries. # UEFI UEFI has a weird way to store times, i.e. a very complicated struct. The standard proclaims "1900-01-01T00:00:00+0000" to be the lowest possible value and `MAX_UEFI_TIME` is already present for the upper limit. # Windows Windows is weird. The Win32 documentation makes no statement on a maximum value here. Next to this, there are two conflicting types: `SYSTEMTIME` and `FILETIME`. Rust's Standard Library uses `FILETIME`, whose limit will (probably) be `i64::MAX` packed into two integers. However, `SYSTEMTIME` has a lower-limit. # xous It is similar to sgx in the sense of using a `Duration`. # unsupported Unsupported platforms store a `SystemTime` in a `Duration`, just like sgx, thereby implying `Duration::ZERO` and `Duration::MAX` as the respective limits. --- library/std/src/sys/pal/hermit/time.rs | 8 +++ library/std/src/sys/pal/sgx/time.rs | 4 ++ library/std/src/sys/pal/solid/time.rs | 4 ++ library/std/src/sys/pal/uefi/time.rs | 17 ++++++ library/std/src/sys/pal/unix/time.rs | 11 ++++ library/std/src/sys/pal/unsupported/time.rs | 4 ++ library/std/src/sys/pal/windows/time.rs | 10 ++++ library/std/src/sys/pal/xous/time.rs | 4 ++ library/std/src/time.rs | 63 +++++++++++++++++++++ library/std/tests/time.rs | 19 +++++++ 10 files changed, 144 insertions(+) diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs index bd6fd5a3de428..53b1f9292b3d4 100644 --- a/library/std/src/sys/pal/hermit/time.rs +++ b/library/std/src/sys/pal/hermit/time.rs @@ -15,6 +15,10 @@ struct Timespec { } impl Timespec { + const MAX: Timespec = Self::new(i64::MAX, 1_000_000_000 - 1); + + const MIN: Timespec = Self::new(i64::MIN, 0); + const fn zero() -> Timespec { Timespec { t: timespec { tv_sec: 0, tv_nsec: 0 } } } @@ -209,6 +213,10 @@ pub struct SystemTime(Timespec); pub const UNIX_EPOCH: SystemTime = SystemTime(Timespec::zero()); impl SystemTime { + pub const MAX: SystemTime = SystemTime { t: Timespec::MAX }; + + pub const MIN: SystemTime = SystemTime { t: Timespec::MIN }; + pub fn new(tv_sec: i64, tv_nsec: i32) -> SystemTime { SystemTime(Timespec::new(tv_sec, tv_nsec)) } diff --git a/library/std/src/sys/pal/sgx/time.rs b/library/std/src/sys/pal/sgx/time.rs index db4cf2804bf13..a9a448226619e 100644 --- a/library/std/src/sys/pal/sgx/time.rs +++ b/library/std/src/sys/pal/sgx/time.rs @@ -28,6 +28,10 @@ impl Instant { } impl SystemTime { + pub const MAX: SystemTime = SystemTime(Duration::MAX); + + pub const MIN: SystemTime = SystemTime(Duration::ZERO); + pub fn now() -> SystemTime { SystemTime(usercalls::insecure_time()) } diff --git a/library/std/src/sys/pal/solid/time.rs b/library/std/src/sys/pal/solid/time.rs index c39d715c6a6f6..d5cf70f94c987 100644 --- a/library/std/src/sys/pal/solid/time.rs +++ b/library/std/src/sys/pal/solid/time.rs @@ -10,6 +10,10 @@ pub struct SystemTime(abi::time_t); pub const UNIX_EPOCH: SystemTime = SystemTime(0); impl SystemTime { + pub const MAX: SystemTime = SystemTime(abi::time_t::MAX); + + pub const MIN: SystemTime = SystemTime(abi::time_t::MIN); + pub fn now() -> SystemTime { let rtc = unsafe { let mut out = MaybeUninit::zeroed(); diff --git a/library/std/src/sys/pal/uefi/time.rs b/library/std/src/sys/pal/uefi/time.rs index 28dacbe3068a7..30df6d93d0eed 100644 --- a/library/std/src/sys/pal/uefi/time.rs +++ b/library/std/src/sys/pal/uefi/time.rs @@ -70,6 +70,23 @@ impl Instant { } impl SystemTime { + pub const MAX: SystemTime = MAX_UEFI_TIME; + + pub const MIN: SystemTime = SystemTime::from_uefi(r_efi::efi::Time { + year: 1900, + month: 1, + day: 1, + hour: 0, + minute: 0, + second: 0, + nanosecond: 0, + timezone: -1440, + daylight: 0, + pad1: 0, + pad2: 0, + }) + .unwrap(); + pub(crate) const fn from_uefi(t: r_efi::efi::Time) -> Option { match system_time_internal::from_uefi(&t) { Some(x) => Some(Self(x)), diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index 24f13853b96b3..1b3fbeee4d900 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -30,6 +30,10 @@ pub(crate) struct Timespec { } impl SystemTime { + pub const MAX: SystemTime = SystemTime { t: Timespec::MAX }; + + pub const MIN: SystemTime = SystemTime { t: Timespec::MIN }; + #[cfg_attr(any(target_os = "horizon", target_os = "hurd"), allow(unused))] pub fn new(tv_sec: i64, tv_nsec: i64) -> Result { Ok(SystemTime { t: Timespec::new(tv_sec, tv_nsec)? }) @@ -62,6 +66,13 @@ impl fmt::Debug for SystemTime { } impl Timespec { + const MAX: Timespec = unsafe { Self::new_unchecked(i64::MAX, 1_000_000_000 - 1) }; + + // As described below, on Apple OS, dates before epoch are represented differently. + // This is not an issue here however, because we are using tv_sec = i64::MIN, + // which will cause the compatibility wrapper to not be executed at all. + const MIN: Timespec = unsafe { Self::new_unchecked(i64::MIN, 0) }; + const unsafe fn new_unchecked(tv_sec: i64, tv_nsec: i64) -> Timespec { Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds::new_unchecked(tv_nsec as u32) } } } diff --git a/library/std/src/sys/pal/unsupported/time.rs b/library/std/src/sys/pal/unsupported/time.rs index 6d67b538a96bf..9bdd57268fd5b 100644 --- a/library/std/src/sys/pal/unsupported/time.rs +++ b/library/std/src/sys/pal/unsupported/time.rs @@ -27,6 +27,10 @@ impl Instant { } impl SystemTime { + pub const MAX: SystemTime = SystemTime(Duration::MAX); + + pub const MIN: SystemTime = SystemTime(Duration::ZERO); + pub fn now() -> SystemTime { panic!("time not implemented on this platform") } diff --git a/library/std/src/sys/pal/windows/time.rs b/library/std/src/sys/pal/windows/time.rs index 0d31b80e56afc..88f4d4cdbd615 100644 --- a/library/std/src/sys/pal/windows/time.rs +++ b/library/std/src/sys/pal/windows/time.rs @@ -64,6 +64,16 @@ impl Instant { } impl SystemTime { + pub const MAX: SystemTime = SystemTime { + t: c::FILETIME { + dwLowDateTime: (i64::MAX & 0xFFFFFFFF) as u32, + dwHighDateTime: (i64::MAX >> 32) as u32, + }, + }; + + pub const MIN: SystemTime = + SystemTime { t: c::FILETIME { dwLowDateTime: 0, dwHighDateTime: 0 } }; + pub fn now() -> SystemTime { unsafe { let mut t: SystemTime = mem::zeroed(); diff --git a/library/std/src/sys/pal/xous/time.rs b/library/std/src/sys/pal/xous/time.rs index ae8be81c0b7c5..1e7e48183e982 100644 --- a/library/std/src/sys/pal/xous/time.rs +++ b/library/std/src/sys/pal/xous/time.rs @@ -35,6 +35,10 @@ impl Instant { } impl SystemTime { + pub const MAX: SystemTime = SystemTime(Duration::MAX); + + pub const MIN: SystemTime = SystemTime(Duration::ZERO); + pub fn now() -> SystemTime { let result = blocking_scalar(systime_server(), GetUtcTimeMs.into()) .expect("failed to request utc time in ms"); diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 87aaf9091f1bc..0bda83af4dfb6 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -511,6 +511,69 @@ impl SystemTime { #[stable(feature = "assoc_unix_epoch", since = "1.28.0")] pub const UNIX_EPOCH: SystemTime = UNIX_EPOCH; + /// Represents the maximum value representable by [`SystemTime`] on this platform. + /// + /// This value differs a lot between platforms, but it is always the case + /// that any positive addition to [`SystemTime::MAX`] will fail. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(time_systemtime_limits)] + /// use std::time::{Duration, SystemTime}; + /// + /// // Adding zero will change nothing. + /// assert_eq!(SystemTime::MAX.checked_add(Duration::ZERO), Some(SystemTime::MAX)); + /// + /// // But adding just 1ns will already fail. + /// assert_eq!(SystemTime::MAX.checked_add(Duration::new(0, 1)), None); + /// + /// // Utilize this for saturating arithmetic to improve error handling. + /// // In this case, we will use a certificate with a timestamp in the + /// // future as a practical example. + /// let configured_offset = Duration::from_secs(60 * 60 * 24); + /// let valid_after = + /// SystemTime::now() + /// .checked_add(configured_offset) + /// .unwrap_or(SystemTime::MAX); + /// ``` + #[unstable(feature = "time_systemtime_limits", issue = "149067")] + pub const MAX: SystemTime = SystemTime(time::SystemTime::MAX); + + /// Represents the minimum value representable by [`SystemTime`] on this platform. + /// + /// This value differs a lot between platforms, but it is always the case + /// that any positive subtraction from [`SystemTime::MIN`] will fail. + /// + /// Depending on the platform, this may be either less than or equal to + /// [`SystemTime::UNIX_EPOCH`], depending on whether the operating system + /// supports the representation of timestamps before the Unix epoch or not. + /// However, it is always guaranteed that a [`SystemTime::UNIX_EPOCH`] fits + /// between a [`SystemTime::MIN`] and [`SystemTime::MAX`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(time_systemtime_limits)] + /// use std::time::{Duration, SystemTime}; + /// + /// // Subtracting zero will change nothing. + /// assert_eq!(SystemTime::MIN.checked_sub(Duration::ZERO), Some(SystemTime::MIN)); + /// + /// // But subtracting just 1ns will already fail. + /// assert_eq!(SystemTime::MIN.checked_sub(Duration::new(0, 1)), None); + /// + /// // Utilize this for saturating arithmetic to improve error handling. + /// // In this case, we will use a cache expiry as a practical example. + /// let configured_expiry = Duration::from_secs(60 * 3); + /// let expiry_threshold = + /// SystemTime::now() + /// .checked_sub(configured_expiry) + /// .unwrap_or(SystemTime::MIN); + /// ``` + #[unstable(feature = "time_systemtime_limits", issue = "149067")] + pub const MIN: SystemTime = SystemTime(time::SystemTime::MIN); + /// Returns the system time corresponding to "now". /// /// # Examples diff --git a/library/std/tests/time.rs b/library/std/tests/time.rs index be1948af91564..31cc7171fe52e 100644 --- a/library/std/tests/time.rs +++ b/library/std/tests/time.rs @@ -1,4 +1,5 @@ #![feature(duration_constants)] +#![feature(time_systemtime_limits)] use std::fmt::Debug; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; @@ -237,9 +238,27 @@ fn system_time_duration_since_max_range_on_unix() { let min = SystemTime::UNIX_EPOCH - (Duration::new(i64::MAX as u64 + 1, 0)); let max = SystemTime::UNIX_EPOCH + (Duration::new(i64::MAX as u64, 999_999_999)); + assert_eq!(min, SystemTime::MIN); + assert_eq!(max, SystemTime::MAX); + let delta_a = max.duration_since(min).expect("duration_since overflow"); let delta_b = min.duration_since(max).expect_err("duration_since overflow").duration(); assert_eq!(Duration::MAX, delta_a); assert_eq!(Duration::MAX, delta_b); } + +#[test] +fn system_time_max_min() { + // First, test everything with checked_* and Duration::ZERO. + assert_eq!(SystemTime::MAX.checked_add(Duration::ZERO), Some(SystemTime::MAX)); + assert_eq!(SystemTime::MAX.checked_sub(Duration::ZERO), Some(SystemTime::MAX)); + assert_eq!(SystemTime::MIN.checked_add(Duration::ZERO), Some(SystemTime::MIN)); + assert_eq!(SystemTime::MIN.checked_sub(Duration::ZERO), Some(SystemTime::MIN)); + + // Now do the same again with checked_* but try by ± a single nanosecond. + assert!(SystemTime::MAX.checked_add(Duration::new(0, 1)).is_none()); + assert!(SystemTime::MAX.checked_sub(Duration::new(0, 1)).is_some()); + assert!(SystemTime::MIN.checked_add(Duration::new(0, 1)).is_some()); + assert!(SystemTime::MIN.checked_sub(Duration::new(0, 1)).is_none()); +} From 0e7dc328942c05a98f2e49b65692d7e7e70ea9d7 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 12 Dec 2025 22:26:31 +1100 Subject: [PATCH 09/18] Inline `BootstrapCommand::force_coloring_in_ci` into its only call site This logic is cargo-specific anyway, so there is no need for it to be a generally-available helper method. --- src/bootstrap/src/core/builder/cargo.rs | 10 +++++++++- src/bootstrap/src/utils/exec.rs | 13 ------------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 2ca52c72e5ec7..5a6bade59a6a3 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -2,6 +2,8 @@ use std::env; use std::ffi::{OsStr, OsString}; use std::path::{Path, PathBuf}; +use build_helper::ci::CiEnv; + use super::{Builder, Kind}; use crate::core::build_steps::test; use crate::core::build_steps::tool::SourceType; @@ -1334,7 +1336,13 @@ impl Builder<'_> { // Try to use a sysroot-relative bindir, in case it was configured absolutely. cargo.env("RUSTC_INSTALL_BINDIR", self.config.bindir_relative()); - cargo.force_coloring_in_ci(); + if CiEnv::is_ci() { + // Tell cargo to use colored output for nicer logs in CI, even + // though CI isn't printing to a terminal. + // Also set an explicit `TERM=xterm` so that cargo doesn't warn + // about TERM not being set. + cargo.env("TERM", "xterm").args(["--color=always"]); + }; // When we build Rust dylibs they're all intended for intermediate // usage, so make sure we pass the -Cprefer-dynamic flag instead of diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index f875e6e1af75c..61b8b26dceaf4 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -21,7 +21,6 @@ use std::process::{ use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; -use build_helper::ci::CiEnv; use build_helper::drop_bomb::DropBomb; use build_helper::exit; @@ -390,18 +389,6 @@ impl<'a> BootstrapCommand { self.drop_bomb.get_created_location() } - /// If in a CI environment, forces the command to run with colors. - pub fn force_coloring_in_ci(&mut self) { - if CiEnv::is_ci() { - // Due to use of stamp/docker, the output stream of bootstrap is not - // a TTY in CI, so coloring is by-default turned off. - // The explicit `TERM=xterm` environment is needed for - // `--color always` to actually work. This env var was lost when - // compiling through the Makefile. Very strange. - self.env("TERM", "xterm").args(["--color", "always"]); - } - } - pub fn fingerprint(&self) -> CommandFingerprint { let command = &self.command; CommandFingerprint { From 93c3ac2868b6823c5fb7c0e1c98f8578fcfe3ad0 Mon Sep 17 00:00:00 2001 From: Jamie Cunliffe Date: Fri, 12 Dec 2025 13:25:21 +0000 Subject: [PATCH 10/18] `declare_lint_pass` for `INLINE_ALWAYS_MISMATCHING_TARGET_FEATURES` The `INLINE_ALWAYS_MISMATCHING_TARGET_FEATURES` lint was missing from this causing it to be an unknown lint when attempting to allow it. --- compiler/rustc_lint_defs/src/builtin.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index baecc14424ecf..99cce0c44b86d 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -48,6 +48,7 @@ declare_lint_pass! { ILL_FORMED_ATTRIBUTE_INPUT, INCOMPLETE_INCLUDE, INEFFECTIVE_UNSTABLE_TRAIT_IMPL, + INLINE_ALWAYS_MISMATCHING_TARGET_FEATURES, INLINE_NO_SANITIZE, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS, From 02bace8476c690a253f2dbdbe0f1fb75d402c8f6 Mon Sep 17 00:00:00 2001 From: Daria Sukhonina Date: Fri, 12 Dec 2025 16:35:48 +0300 Subject: [PATCH 11/18] Add a sanity check in case of any duplicate nodes --- compiler/rustc_query_system/src/dep_graph/graph.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index b2c72f19b78be..b85f226d108c6 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -1384,7 +1384,9 @@ impl DepNodeColorMap { #[inline] pub(super) fn insert_red(&self, index: SerializedDepNodeIndex) { - self.values[index].store(COMPRESSED_RED, Ordering::Release) + let value = self.values[index].swap(COMPRESSED_RED, Ordering::Release); + // Sanity check for duplicate nodes + assert_eq!(value, COMPRESSED_UNKNOWN, "trying to encode a dep node twice"); } } From 0ab4b8b9e0257a15fdf791950f48fa77dc0019b0 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 12 Dec 2025 12:21:15 +0100 Subject: [PATCH 12/18] Remove the E0536 error code --- compiler/rustc_error_codes/src/error_codes/E0536.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_error_codes/src/error_codes/E0536.md b/compiler/rustc_error_codes/src/error_codes/E0536.md index c1f43fa741cfa..7603be4fcc935 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0536.md +++ b/compiler/rustc_error_codes/src/error_codes/E0536.md @@ -1,3 +1,5 @@ +#### Note: this error code is no longer emitted by the compiler. + The `not` cfg-predicate was malformed. Erroneous code example (using `cargo doc`): From c7b5fb56950c3a7999fa9348096ee55d2773ace2 Mon Sep 17 00:00:00 2001 From: Daria Sukhonina Date: Fri, 12 Dec 2025 16:44:17 +0300 Subject: [PATCH 13/18] Also check in case it tries to mark red node as green --- compiler/rustc_query_system/src/dep_graph/graph.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index b85f226d108c6..8634274c3a751 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -1363,7 +1363,10 @@ impl DepNodeColorMap { Ordering::Relaxed, ) { Ok(_) => Ok(()), - Err(v) => Err(DepNodeIndex::from_u32(v)), + Err(v) => Err({ + assert_ne!(v, COMPRESSED_RED, "tried to mark a red node as green"); + DepNodeIndex::from_u32(v) + }), } } From 0748492e2bb7d48c4c548729b0593c470bc31155 Mon Sep 17 00:00:00 2001 From: delta17920 Date: Wed, 10 Dec 2025 18:17:03 +0000 Subject: [PATCH 14/18] Fix: Prevent macro-expanded extern crates from shadowing extern arguments --- compiler/rustc_resolve/src/ident.rs | 63 ++++++++++--------- compiler/rustc_resolve/src/imports.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 1 + .../ice-inconsistent-resolution-149821.rs | 17 +++++ .../ice-inconsistent-resolution-149821.stderr | 13 ++++ 5 files changed, 65 insertions(+), 31 deletions(-) create mode 100644 tests/ui/resolve/ice-inconsistent-resolution-149821.rs create mode 100644 tests/ui/resolve/ice-inconsistent-resolution-149821.stderr diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index e38d4370d5d25..5587fc91216ff 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -771,36 +771,39 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } else { None }; - // Skip ambiguity errors for extern flag bindings "overridden" - // by extern item bindings. - // FIXME: Remove with lang team approval. - let issue_145575_hack = Some(binding) == extern_prelude_flag_binding - && extern_prelude_item_binding.is_some() - && extern_prelude_item_binding != Some(innermost_binding); - if let Some(kind) = ambiguity_error_kind - && !issue_145575_hack - { - let misc = |f: Flags| { - if f.contains(Flags::MISC_SUGGEST_CRATE) { - AmbiguityErrorMisc::SuggestCrate - } else if f.contains(Flags::MISC_SUGGEST_SELF) { - AmbiguityErrorMisc::SuggestSelf - } else if f.contains(Flags::MISC_FROM_PRELUDE) { - AmbiguityErrorMisc::FromPrelude - } else { - AmbiguityErrorMisc::None - } - }; - self.ambiguity_errors.push(AmbiguityError { - kind, - ident: orig_ident, - b1: innermost_binding, - b2: binding, - warning: false, - misc1: misc(innermost_flags), - misc2: misc(flags), - }); - return true; + if let Some(kind) = ambiguity_error_kind { + // Skip ambiguity errors for extern flag bindings "overridden" + // by extern item bindings. + // FIXME: Remove with lang team approval. + let issue_145575_hack = Some(binding) == extern_prelude_flag_binding + && extern_prelude_item_binding.is_some() + && extern_prelude_item_binding != Some(innermost_binding); + + if issue_145575_hack { + self.issue_145575_hack_applied = true; + } else { + let misc = |f: Flags| { + if f.contains(Flags::MISC_SUGGEST_CRATE) { + AmbiguityErrorMisc::SuggestCrate + } else if f.contains(Flags::MISC_SUGGEST_SELF) { + AmbiguityErrorMisc::SuggestSelf + } else if f.contains(Flags::MISC_FROM_PRELUDE) { + AmbiguityErrorMisc::FromPrelude + } else { + AmbiguityErrorMisc::None + } + }; + self.ambiguity_errors.push(AmbiguityError { + kind, + ident: orig_ident, + b1: innermost_binding, + b2: binding, + warning: false, + misc1: misc(innermost_flags), + misc2: misc(flags), + }); + return true; + } } false diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 4ef87af560504..4e0f3db59821f 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1170,7 +1170,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return; } if let Some(initial_res) = initial_res { - if res != initial_res { + if res != initial_res && !this.issue_145575_hack_applied { span_bug!(import.span, "inconsistent resolution for an import"); } } else if this.privacy_errors.is_empty() { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 8132bf577d883..7e06b8511e30b 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1186,6 +1186,7 @@ pub struct Resolver<'ra, 'tcx> { privacy_errors: Vec> = Vec::new(), /// Ambiguity errors are delayed for deduplication. ambiguity_errors: Vec> = Vec::new(), + issue_145575_hack_applied: bool = false, /// `use` injections are delayed for better placement and deduplication. use_injections: Vec> = Vec::new(), /// Crate-local macro expanded `macro_export` referred to by a module-relative path. diff --git a/tests/ui/resolve/ice-inconsistent-resolution-149821.rs b/tests/ui/resolve/ice-inconsistent-resolution-149821.rs new file mode 100644 index 0000000000000..19b8a2f4330c4 --- /dev/null +++ b/tests/ui/resolve/ice-inconsistent-resolution-149821.rs @@ -0,0 +1,17 @@ +//@ edition: 2024 + +mod m { + use crate::*; + use core; +} + +macro_rules! define_other_core { + () => { + extern crate std as core; + //~^ ERROR macro-expanded `extern crate` items cannot shadow names passed with `--extern` + }; +} + +define_other_core! {} + +fn main() {} diff --git a/tests/ui/resolve/ice-inconsistent-resolution-149821.stderr b/tests/ui/resolve/ice-inconsistent-resolution-149821.stderr new file mode 100644 index 0000000000000..cd75a2f3e19b7 --- /dev/null +++ b/tests/ui/resolve/ice-inconsistent-resolution-149821.stderr @@ -0,0 +1,13 @@ +error: macro-expanded `extern crate` items cannot shadow names passed with `--extern` + --> $DIR/ice-inconsistent-resolution-149821.rs:10:9 + | +LL | extern crate std as core; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | define_other_core! {} + | --------------------- in this macro invocation + | + = note: this error originates in the macro `define_other_core` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + From 0a3fd242879bdd53747289db422c11a403333bcb Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Fri, 12 Dec 2025 20:34:54 +0300 Subject: [PATCH 15/18] Support attribute inheritance in delegation --- compiler/rustc_ast_lowering/src/delegation.rs | 156 +++++++++++++++--- compiler/rustc_middle/src/ty/mod.rs | 14 +- compiler/rustc_resolve/src/late.rs | 30 +++- tests/pretty/auxiliary/to-reuse-functions.rs | 14 ++ tests/pretty/delegation-inherit-attributes.pp | 61 +++++++ tests/pretty/delegation-inherit-attributes.rs | 56 +++++++ 6 files changed, 305 insertions(+), 26 deletions(-) create mode 100644 tests/pretty/auxiliary/to-reuse-functions.rs create mode 100644 tests/pretty/delegation-inherit-attributes.pp create mode 100644 tests/pretty/delegation-inherit-attributes.rs diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 0e7db7c9503cb..82bade8829a2f 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -43,13 +43,15 @@ use hir::def::{DefKind, PartialRes, Res}; use hir::{BodyId, HirId}; use rustc_abi::ExternAbi; use rustc_ast::*; +use rustc_attr_parsing::{AttributeParser, ShouldEmit}; use rustc_errors::ErrorGuaranteed; +use rustc_hir::Target; use rustc_hir::attrs::{AttributeKind, InlineAttr}; use rustc_hir::def_id::DefId; use rustc_middle::span_bug; -use rustc_middle::ty::{Asyncness, ResolverAstLowering}; +use rustc_middle::ty::{Asyncness, DelegationFnSigAttrs, ResolverAstLowering}; use rustc_span::symbol::kw; -use rustc_span::{Ident, Span, Symbol}; +use rustc_span::{DUMMY_SP, Ident, Span, Symbol}; use {rustc_ast as ast, rustc_hir as hir}; use super::{GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode}; @@ -62,6 +64,41 @@ pub(crate) struct DelegationResults<'hir> { pub generics: &'hir hir::Generics<'hir>, } +struct AttributeAdditionInfo { + pub equals: fn(&hir::Attribute) -> bool, + pub kind: AttributeAdditionKind, +} + +enum AttributeAdditionKind { + Default { factory: fn(Span) -> hir::Attribute }, + Inherit { flag: DelegationFnSigAttrs, factory: fn(Span, &hir::Attribute) -> hir::Attribute }, +} + +const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO; + +static ATTRIBUTES_ADDITIONS: &[AttributeAdditionInfo] = &[ + AttributeAdditionInfo { + equals: |a| matches!(a, hir::Attribute::Parsed(AttributeKind::MustUse { .. })), + kind: AttributeAdditionKind::Inherit { + factory: |span, original_attribute| { + let reason = match original_attribute { + hir::Attribute::Parsed(AttributeKind::MustUse { reason, .. }) => *reason, + _ => None, + }; + + hir::Attribute::Parsed(AttributeKind::MustUse { span, reason }) + }, + flag: DelegationFnSigAttrs::MUST_USE, + }, + }, + AttributeAdditionInfo { + equals: |a| matches!(a, hir::Attribute::Parsed(AttributeKind::Inline(..))), + kind: AttributeAdditionKind::Default { + factory: |span| hir::Attribute::Parsed(AttributeKind::Inline(InlineAttr::Hint, span)), + }, + }, +]; + impl<'hir> LoweringContext<'_, 'hir> { fn is_method(&self, def_id: DefId, span: Span) -> bool { match self.tcx.def_kind(def_id) { @@ -88,7 +125,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let sig_id = self.get_delegation_sig_id(item_id, delegation.id, span, is_in_trait_impl); match sig_id { Ok(sig_id) => { - self.add_inline_attribute_if_needed(span); + self.add_attributes_if_needed(span, sig_id); let is_method = self.is_method(sig_id, span); let (param_count, c_variadic) = self.param_count(sig_id); @@ -103,29 +140,100 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn add_inline_attribute_if_needed(&mut self, span: Span) { - const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO; - let create_inline_attr_slice = - || [hir::Attribute::Parsed(AttributeKind::Inline(InlineAttr::Hint, span))]; - - let new_attributes = match self.attrs.get(&PARENT_ID) { - Some(attrs) => { - // Check if reuse already specifies any inline attribute, if so, do nothing - if attrs - .iter() - .any(|a| matches!(a, hir::Attribute::Parsed(AttributeKind::Inline(..)))) + fn add_attributes_if_needed(&mut self, span: Span, sig_id: DefId) { + let new_attributes = self.create_new_attributes( + ATTRIBUTES_ADDITIONS, + span, + sig_id, + self.attrs.get(&PARENT_ID), + ); + + if new_attributes.is_empty() { + return; + } + + let new_arena_allocated_attributes = match self.attrs.get(&PARENT_ID) { + Some(existing_attrs) => self.arena.alloc_from_iter( + existing_attrs.iter().map(|a| a.clone()).chain(new_attributes.into_iter()), + ), + None => self.arena.alloc_from_iter(new_attributes.into_iter()), + }; + + self.attrs.insert(PARENT_ID, new_arena_allocated_attributes); + } + + fn create_new_attributes( + &self, + candidate_additions: &[AttributeAdditionInfo], + span: Span, + sig_id: DefId, + existing_attrs: Option<&&[hir::Attribute]>, + ) -> Vec { + let local_original_attributes = self.parse_local_original_attributes(sig_id); + + candidate_additions + .iter() + .filter_map(|addition_info| { + if let Some(existing_attrs) = existing_attrs + && existing_attrs + .iter() + .any(|existing_attr| (addition_info.equals)(existing_attr)) { - return; + return None; } - self.arena.alloc_from_iter( - attrs.into_iter().map(|a| a.clone()).chain(create_inline_attr_slice()), - ) - } - None => self.arena.alloc_from_iter(create_inline_attr_slice()), - }; + match addition_info.kind { + AttributeAdditionKind::Default { factory } => Some(factory(span)), + AttributeAdditionKind::Inherit { flag, factory } => { + let original_attribute = match sig_id.as_local() { + Some(local_id) => self + .resolver + .delegation_fn_sigs + .get(&local_id) + .is_some_and(|sig| sig.attrs_flags.contains(flag)) + .then(|| { + local_original_attributes + .as_ref() + .map(|attrs| { + attrs + .iter() + .find(|base_attr| (addition_info.equals)(base_attr)) + }) + .flatten() + }) + .flatten(), + None => self + .tcx + .get_all_attrs(sig_id) + .iter() + .find(|base_attr| (addition_info.equals)(base_attr)), + }; - self.attrs.insert(PARENT_ID, new_attributes); + original_attribute.map(|a| factory(span, a)) + } + } + }) + .collect::>() + } + + fn parse_local_original_attributes(&self, sig_id: DefId) -> Option> { + if let Some(local_id) = sig_id.as_local() + && let Some(info) = self.resolver.delegation_fn_sigs.get(&local_id) + && !info.to_inherit_attrs.is_empty() + { + Some(AttributeParser::parse_limited_all( + self.tcx.sess, + info.to_inherit_attrs.as_slice(), + None, + Target::Fn, + DUMMY_SP, + DUMMY_NODE_ID, + Some(self.tcx.features()), + ShouldEmit::Nothing, + )) + } else { + None + } } fn get_delegation_sig_id( @@ -220,7 +328,9 @@ impl<'hir> LoweringContext<'_, 'hir> { // We are not forwarding the attributes, as the delegation fn sigs are collected on the ast, // and here we need the hir attributes. let default_safety = - if sig.target_feature || self.tcx.def_kind(parent) == DefKind::ForeignMod { + if sig.attrs_flags.contains(DelegationFnSigAttrs::TARGET_FEATURE) + || self.tcx.def_kind(parent) == DefKind::ForeignMod + { hir::Safety::Unsafe } else { hir::Safety::Safe diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 6ca4949910f27..418335a893479 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -25,6 +25,7 @@ pub use generic_args::{GenericArgKind, TermKind, *}; pub use generics::*; pub use intrinsic::IntrinsicDef; use rustc_abi::{Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, VariantIdx}; +use rustc_ast::AttrVec; use rustc_ast::expand::typetree::{FncTree, Kind, Type, TypeTree}; use rustc_ast::node_id::NodeMap; pub use rustc_ast_ir::{Movability, Mutability, try_visit}; @@ -221,13 +222,24 @@ pub struct ResolverAstLowering { pub delegation_fn_sigs: LocalDefIdMap, } +bitflags::bitflags! { + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] + pub struct DelegationFnSigAttrs: u8 { + const TARGET_FEATURE = 1 << 0; + const MUST_USE = 1 << 1; + } +} + +pub const DELEGATION_INHERIT_ATTRS_START: DelegationFnSigAttrs = DelegationFnSigAttrs::MUST_USE; + #[derive(Debug)] pub struct DelegationFnSig { pub header: ast::FnHeader, pub param_count: usize, pub has_self: bool, pub c_variadic: bool, - pub target_feature: bool, + pub attrs_flags: DelegationFnSigAttrs, + pub to_inherit_attrs: AttrVec, } #[derive(Clone, Copy, Debug, HashStable)] diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index f1a03d5a06109..cc17ca9c026de 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -28,7 +28,9 @@ use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, Par use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::{MissingLifetimeKind, PrimTy, TraitCandidate}; use rustc_middle::middle::resolve_bound_vars::Set1; -use rustc_middle::ty::{AssocTag, DelegationFnSig, Visibility}; +use rustc_middle::ty::{ + AssocTag, DELEGATION_INHERIT_ATTRS_START, DelegationFnSig, DelegationFnSigAttrs, Visibility, +}; use rustc_middle::{bug, span_bug}; use rustc_session::config::{CrateType, ResolveDocLinks}; use rustc_session::lint; @@ -5294,13 +5296,37 @@ impl ItemInfoCollector<'_, '_, '_> { id: NodeId, attrs: &[Attribute], ) { + static NAMES_TO_FLAGS: &[(Symbol, DelegationFnSigAttrs)] = &[ + (sym::target_feature, DelegationFnSigAttrs::TARGET_FEATURE), + (sym::must_use, DelegationFnSigAttrs::MUST_USE), + ]; + + let mut to_inherit_attrs = AttrVec::new(); + let mut attrs_flags = DelegationFnSigAttrs::empty(); + + 'attrs_loop: for attr in attrs { + for &(name, flag) in NAMES_TO_FLAGS { + if attr.has_name(name) { + attrs_flags.set(flag, true); + + if flag.bits() >= DELEGATION_INHERIT_ATTRS_START.bits() { + to_inherit_attrs.push(attr.clone()); + } + + continue 'attrs_loop; + } + } + } + let sig = DelegationFnSig { header, param_count: decl.inputs.len(), has_self: decl.has_self(), c_variadic: decl.c_variadic(), - target_feature: attrs.iter().any(|attr| attr.has_name(sym::target_feature)), + attrs_flags, + to_inherit_attrs, }; + self.r.delegation_fn_sigs.insert(self.r.local_def_id(id), sig); } } diff --git a/tests/pretty/auxiliary/to-reuse-functions.rs b/tests/pretty/auxiliary/to-reuse-functions.rs new file mode 100644 index 0000000000000..55d6ecf035e34 --- /dev/null +++ b/tests/pretty/auxiliary/to-reuse-functions.rs @@ -0,0 +1,14 @@ +//@ edition:2021 + +#[must_use] +#[cold] +pub unsafe fn unsafe_fn_extern() -> usize { 1 } + +#[must_use = "extern_fn_extern: some reason"] +#[deprecated] +pub extern "C" fn extern_fn_extern() -> usize { 1 } + +pub const fn const_fn_extern() -> usize { 1 } + +#[must_use] +pub async fn async_fn_extern() { } diff --git a/tests/pretty/delegation-inherit-attributes.pp b/tests/pretty/delegation-inherit-attributes.pp new file mode 100644 index 0000000000000..772e177b88835 --- /dev/null +++ b/tests/pretty/delegation-inherit-attributes.pp @@ -0,0 +1,61 @@ +//@ edition:2021 +//@ aux-crate:to_reuse_functions=to-reuse-functions.rs +//@ pretty-mode:hir +//@ pretty-compare-only +//@ pp-exact:delegation-inherit-attributes.pp + +#![allow(incomplete_features)] +#![feature(fn_delegation)] +#[attr = MacroUse {arguments: UseAll}] +extern crate std; +#[prelude_import] +use std::prelude::rust_2021::*; + +extern crate to_reuse_functions; + +mod to_reuse { + #[attr = MustUse {reason: "foo: some reason"}] + #[attr = Cold] + fn foo(x: usize) -> usize { x } + + #[attr = MustUse] + #[attr = Cold] + fn foo_no_reason(x: usize) -> usize { x } + + #[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] + #[attr = Cold] + fn bar(x: usize) -> usize { x } +} + +#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] +#[attr = MustUse {reason: "foo: some reason"}] +#[attr = Inline(Hint)] +fn foo1(arg0: _) -> _ { to_reuse::foo(self + 1) } + +#[attr = MustUse] +#[attr = Inline(Hint)] +fn foo_no_reason(arg0: _) -> _ { to_reuse::foo_no_reason(self + 1) } + +#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] +#[attr = MustUse {reason: "some reason"}] +#[attr = Inline(Hint)] +fn foo2(arg0: _) -> _ { to_reuse::foo(self + 1) } + +#[attr = Inline(Hint)] +fn bar(arg0: _) -> _ { to_reuse::bar(arg0) } + +#[attr = MustUse] +#[attr = Inline(Hint)] +unsafe fn unsafe_fn_extern() -> _ { to_reuse_functions::unsafe_fn_extern() } +#[attr = MustUse {reason: "extern_fn_extern: some reason"}] +#[attr = Inline(Hint)] +extern "C" fn extern_fn_extern() + -> _ { to_reuse_functions::extern_fn_extern() } +#[attr = Inline(Hint)] +const fn const_fn_extern() -> _ { to_reuse_functions::const_fn_extern() } +#[attr = MustUse {reason: "some reason"}] +#[attr = Inline(Hint)] +async fn async_fn_extern() -> _ { to_reuse_functions::async_fn_extern() } + + +fn main() { } diff --git a/tests/pretty/delegation-inherit-attributes.rs b/tests/pretty/delegation-inherit-attributes.rs new file mode 100644 index 0000000000000..fe74b9a55a7d7 --- /dev/null +++ b/tests/pretty/delegation-inherit-attributes.rs @@ -0,0 +1,56 @@ +//@ edition:2021 +//@ aux-crate:to_reuse_functions=to-reuse-functions.rs +//@ pretty-mode:hir +//@ pretty-compare-only +//@ pp-exact:delegation-inherit-attributes.pp + +#![allow(incomplete_features)] +#![feature(fn_delegation)] + +extern crate to_reuse_functions; + +mod to_reuse { + #[must_use = "foo: some reason"] + #[cold] + pub fn foo(x: usize) -> usize { + x + } + + #[must_use] + #[cold] + pub fn foo_no_reason(x: usize) -> usize { + x + } + + #[cold] + #[deprecated] + pub fn bar(x: usize) -> usize { + x + } +} + +#[deprecated] +reuse to_reuse::foo as foo1 { + self + 1 +} + +reuse to_reuse::foo_no_reason { + self + 1 +} + +#[deprecated] +#[must_use = "some reason"] +reuse to_reuse::foo as foo2 { + self + 1 +} + +reuse to_reuse::bar; + +reuse to_reuse_functions::unsafe_fn_extern; +reuse to_reuse_functions::extern_fn_extern; +reuse to_reuse_functions::const_fn_extern; +#[must_use = "some reason"] +reuse to_reuse_functions::async_fn_extern; + + +fn main() {} From 146711fc249aec2272d565878e9139fa75f81288 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 9 Dec 2025 00:43:46 +0000 Subject: [PATCH 16/18] Use `let...else` instead of `match foo { ... _ => return };` and `if let ... else return` --- compiler/rustc_ast/src/ast.rs | 7 +- compiler/rustc_ast/src/attr/mod.rs | 19 ++- .../src/diagnostics/conflict_errors.rs | 7 +- .../src/diagnostics/explain_borrow.rs | 14 +-- .../rustc_borrowck/src/diagnostics/mod.rs | 14 +-- .../src/diagnostics/mutability_errors.rs | 9 +- .../src/diagnostics/region_errors.rs | 50 +++----- .../src/polonius/legacy/accesses.rs | 11 +- .../src/debuginfo/unwind.rs | 6 +- .../src/optimize/peephole.rs | 6 +- .../rustc_codegen_gcc/src/intrinsic/simd.rs | 31 +++-- compiler/rustc_codegen_llvm/src/intrinsic.rs | 5 +- .../rustc_codegen_ssa/src/codegen_attrs.rs | 5 +- compiler/rustc_expand/src/mbe/macro_rules.rs | 5 +- compiler/rustc_hir_analysis/src/collect.rs | 14 +-- .../src/collect/item_bounds.rs | 25 ++-- .../errors/wrong_number_of_generic_args.rs | 15 +-- .../src/hir_ty_lowering/errors.rs | 6 +- compiler/rustc_hir_typeck/src/callee.rs | 9 +- compiler/rustc_hir_typeck/src/demand.rs | 7 +- .../rustc_hir_typeck/src/expr_use_visitor.rs | 16 +-- .../src/fn_ctxt/adjust_fulfillment_errors.rs | 23 ++-- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 7 +- .../src/fn_ctxt/suggestions.rs | 20 ++- compiler/rustc_hir_typeck/src/inline_asm.rs | 7 +- .../rustc_hir_typeck/src/method/suggest.rs | 6 +- compiler/rustc_lint/src/builtin.rs | 7 +- ..._expr_fragment_specifier_2024_migration.rs | 6 +- compiler/rustc_middle/src/ty/diagnostics.rs | 9 +- compiler/rustc_middle/src/ty/mod.rs | 4 +- compiler/rustc_middle/src/ty/sty.rs | 15 +-- .../rustc_mir_dataflow/src/move_paths/mod.rs | 14 +-- .../rustc_mir_dataflow/src/value_analysis.rs | 7 +- compiler/rustc_mir_transform/src/gvn.rs | 45 ++++--- .../rustc_mir_transform/src/promote_consts.rs | 10 +- .../src/solve/eval_ctxt/mod.rs | 14 +-- .../src/solve/normalizes_to/mod.rs | 14 +-- .../src/solve/trait_goals.rs | 77 ++++++------ .../rustc_resolve/src/late/diagnostics.rs | 114 +++++++++--------- 39 files changed, 281 insertions(+), 399 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e348cc1ab2810..67152f5d24623 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1534,11 +1534,10 @@ impl Expr { // then type of result is trait object. // Otherwise we don't assume the result type. ExprKind::Binary(binop, lhs, rhs) if binop.node == BinOpKind::Add => { - if let (Some(lhs), Some(rhs)) = (lhs.to_bound(), rhs.to_bound()) { - TyKind::TraitObject(vec![lhs, rhs], TraitObjectSyntax::None) - } else { + let (Some(lhs), Some(rhs)) = (lhs.to_bound(), rhs.to_bound()) else { return None; - } + }; + TyKind::TraitObject(vec![lhs, rhs], TraitObjectSyntax::None) } ExprKind::Underscore => TyKind::Infer, diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index a5e630a09afe2..c53188a22aedd 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -447,20 +447,17 @@ impl MetaItem { thin_vec![PathSegment::path_root(span)] }; loop { - if let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) = + let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) = iter.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref() - { - segments.push(PathSegment::from_ident(Ident::new(name, span))); - } else { + else { return None; - } - if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) = - iter.peek() - { - iter.next(); - } else { + }; + segments.push(PathSegment::from_ident(Ident::new(name, span))); + let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) = iter.peek() + else { break; - } + }; + iter.next(); } let span = span.with_hi(segments.last().unwrap().ident.span.hi()); Path { span, segments, tokens: None } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 2999d1f2926cc..5cfe9db009bff 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -561,11 +561,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { VarDebugInfoContents::Place(ref p) => p == place, _ => false, }); - let arg_name = if let Some(var_info) = var_info { - var_info.name - } else { - return; - }; + let Some(var_info) = var_info else { return }; + let arg_name = var_info.name; struct MatchArgFinder { expr_span: Span, match_arg_span: Option, diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index bfdfa896cd2b9..8e18bf5577584 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -850,16 +850,10 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { // will only ever have one item at any given time, but by using a vector, we can pop from // it which simplifies the termination logic. let mut queue = vec![location]; - let mut target = - if let Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) = stmt { - if let Some(local) = place.as_local() { - local - } else { - return false; - } - } else { - return false; - }; + let Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) = stmt else { + return false; + }; + let Some(mut target) = place.as_local() else { return false }; debug!("was_captured_by_trait: target={:?} queue={:?}", target, queue); while let Some(current_location) = queue.pop() { diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index e13c1c712d8d7..e725b13434a1f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1124,16 +1124,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { use self::UseSpans::*; debug!("borrow_spans: use_span={:?} location={:?}", use_span, location); - let target = match self.body[location.block].statements.get(location.statement_index) { - Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) => { - if let Some(local) = place.as_local() { - local - } else { - return OtherUse(use_span); - } - } - _ => return OtherUse(use_span), + let Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) = + self.body[location.block].statements.get(location.statement_index) + else { + return OtherUse(use_span); }; + let Some(target) = place.as_local() else { return OtherUse(use_span) }; if self.body.local_kind(target) != LocalKind::Temp { // operands are always temporaries. diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 7d72de7efa4a1..e9039d4311b66 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -142,12 +142,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } else { item_msg = access_place_desc; let local_info = self.body.local_decls[local].local_info(); - if let LocalInfo::StaticRef { def_id, .. } = *local_info { - let static_name = &self.infcx.tcx.item_name(def_id); - reason = format!(", as `{static_name}` is an immutable static item"); - } else { + let LocalInfo::StaticRef { def_id, .. } = *local_info else { bug!("is_ref_to_static return true, but not ref to static?"); - } + }; + let static_name = &self.infcx.tcx.item_name(def_id); + reason = format!(", as `{static_name}` is an immutable static item"); } } PlaceRef { local, projection: [proj_base @ .., ProjectionElem::Deref] } => { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index f4bbdabf7f216..9c2b9139367a9 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -847,11 +847,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let fn_returns = self.infcx.tcx.return_type_impl_or_dyn_traits(suitable_region.scope); - let param = if let Some(param) = + let Some(param) = find_param_with_region(self.infcx.tcx, self.mir_def_id(), f, outlived_f) - { - param - } else { + else { return; }; @@ -930,37 +928,27 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let tcx = self.infcx.tcx; - let instance = if let ConstraintCategory::CallArgument(Some(func_ty)) = category { - let (fn_did, args) = match func_ty.kind() { - ty::FnDef(fn_did, args) => (fn_did, args), - _ => return, - }; - debug!(?fn_did, ?args); + let ConstraintCategory::CallArgument(Some(func_ty)) = category else { return }; + let ty::FnDef(fn_did, args) = func_ty.kind() else { return }; + debug!(?fn_did, ?args); - // Only suggest this on function calls, not closures - let ty = tcx.type_of(fn_did).instantiate_identity(); - debug!("ty: {:?}, ty.kind: {:?}", ty, ty.kind()); - if let ty::Closure(_, _) = ty.kind() { - return; - } - - if let Ok(Some(instance)) = ty::Instance::try_resolve( - tcx, - self.infcx.typing_env(self.infcx.param_env), - *fn_did, - self.infcx.resolve_vars_if_possible(args), - ) { - instance - } else { - return; - } - } else { + // Only suggest this on function calls, not closures + let ty = tcx.type_of(fn_did).instantiate_identity(); + debug!("ty: {:?}, ty.kind: {:?}", ty, ty.kind()); + if let ty::Closure(_, _) = ty.kind() { + return; + } + let Ok(Some(instance)) = ty::Instance::try_resolve( + tcx, + self.infcx.typing_env(self.infcx.param_env), + *fn_did, + self.infcx.resolve_vars_if_possible(args), + ) else { return; }; - let param = match find_param_with_region(tcx, self.mir_def_id(), f, o) { - Some(param) => param, - None => return, + let Some(param) = find_param_with_region(tcx, self.mir_def_id(), f, o) else { + return; }; debug!(?param); diff --git a/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs b/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs index edd7ca578b727..dc174775af2e5 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/accesses.rs @@ -67,12 +67,11 @@ impl<'a, 'tcx> Visitor<'tcx> for AccessFactsExtractor<'a, 'tcx> { match context { PlaceContext::NonMutatingUse(_) | PlaceContext::MutatingUse(MutatingUseContext::Borrow) => { - let path = match self.move_data.rev_lookup.find(place.as_ref()) { - LookupResult::Exact(path) | LookupResult::Parent(Some(path)) => path, - _ => { - // There's no path access to emit. - return; - } + let (LookupResult::Exact(path) | LookupResult::Parent(Some(path))) = + self.move_data.rev_lookup.find(place.as_ref()) + else { + // There's no path access to emit. + return; }; debug!("AccessFactsExtractor - emit path access ({path:?}, {location:?})"); self.facts.path_accessed_at_base.push((path, self.location_to_index(location))); diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs index ecaf88a26259e..33ffe4cc4e9c8 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs @@ -130,11 +130,9 @@ impl UnwindContext { return; } - let unwind_info = if let Some(unwind_info) = + let Some(unwind_info) = context.compiled_code().unwrap().create_unwind_info(module.isa()).unwrap() - { - unwind_info - } else { + else { return; }; diff --git a/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs b/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs index c93fe93521033..f38c1f96e6ed5 100644 --- a/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs +++ b/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs @@ -29,11 +29,7 @@ pub(crate) fn maybe_known_branch_taken( arg: Value, test_zero: bool, ) -> Option { - let arg_inst = if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) { - arg_inst - } else { - return None; - }; + let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) else { return None }; match bcx.func.dfg.insts[arg_inst] { InstructionData::UnaryImm { opcode: Opcode::Iconst, imm } => { diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index c7ed887b30d02..39b4bb3ebefab 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -774,24 +774,23 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( return Err(()); }}; } - let (elem_ty_str, elem_ty, cast_type) = if let ty::Float(ref f) = *in_elem.kind() { - let elem_ty = bx.cx.type_float_from_ty(*f); - match f.bit_width() { - 16 => ("", elem_ty, Some(bx.cx.double_type)), - 32 => ("f", elem_ty, None), - 64 => ("", elem_ty, None), - _ => { - return_error!(InvalidMonomorphization::FloatingPointVector { - span, - name, - f_ty: *f, - in_ty - }); - } - } - } else { + let ty::Float(ref f) = *in_elem.kind() else { return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty }); }; + let elem_ty = bx.cx.type_float_from_ty(*f); + let (elem_ty_str, elem_ty, cast_type) = match f.bit_width() { + 16 => ("", elem_ty, Some(bx.cx.double_type)), + 32 => ("f", elem_ty, None), + 64 => ("", elem_ty, None), + _ => { + return_error!(InvalidMonomorphization::FloatingPointVector { + span, + name, + f_ty: *f, + in_ty + }); + } + }; let vec_ty = bx.cx.type_vector(elem_ty, in_len); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 33541f7b695f8..e43bd8c2feef5 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1756,11 +1756,10 @@ fn generic_simd_intrinsic<'ll, 'tcx>( }}; } - let elem_ty = if let ty::Float(f) = in_elem.kind() { - bx.cx.type_float_from_ty(*f) - } else { + let ty::Float(f) = in_elem.kind() else { return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty }); }; + let elem_ty = bx.cx.type_float_from_ty(*f); let vec_ty = bx.type_vector(elem_ty, in_len); diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 0ab0cb0ef88a5..bfbe7bc20052e 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -721,11 +721,10 @@ pub fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option { }; // First read the ret symbol from the attribute - let ret_symbol = if let MetaItemInner::MetaItem(MetaItem { path: p1, .. }) = ret_activity { - p1.segments.first().unwrap().ident - } else { + let MetaItemInner::MetaItem(MetaItem { path: p1, .. }) = ret_activity else { span_bug!(attr.span(), "rustc_autodiff attribute must contain the return activity"); }; + let ret_symbol = p1.segments.first().unwrap().ident; // Then parse it into an actual DiffActivity let Ok(ret_activity) = DiffActivity::from_str(ret_symbol.as_str()) else { diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index c548cea537f40..8d2cc23f97639 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -788,11 +788,10 @@ pub fn compile_declarative_macro( let lhs_span = lhs_tt.span(); // Convert the lhs into `MatcherLoc` form, which is better for doing the // actual matching. - let lhs = if let mbe::TokenTree::Delimited(.., delimited) = lhs_tt { - mbe::macro_parser::compute_locs(&delimited.tts) - } else { + let mbe::TokenTree::Delimited(.., delimited) = lhs_tt else { return dummy_syn_ext(guar.unwrap()); }; + let lhs = mbe::macro_parser::compute_locs(&delimited.tts); if let Some(args) = args { let args_span = args.span(); let mbe::TokenTree::Delimited(.., delimited) = args else { diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 3cfcac5c72915..2e06684e0c7a8 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1551,15 +1551,15 @@ fn const_param_default<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, ) -> ty::EarlyBinder<'tcx, Const<'tcx>> { - let default_ct = match tcx.hir_node_by_def_id(def_id) { - hir::Node::GenericParam(hir::GenericParam { - kind: hir::GenericParamKind::Const { default: Some(ct), .. }, - .. - }) => ct, - _ => span_bug!( + let hir::Node::GenericParam(hir::GenericParam { + kind: hir::GenericParamKind::Const { default: Some(default_ct), .. }, + .. + }) = tcx.hir_node_by_def_id(def_id) + else { + span_bug!( tcx.def_span(def_id), "`const_param_default` expected a generic parameter with a constant" - ), + ) }; let icx = ItemCtxt::new(tcx, def_id); let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id); diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 6b51e31579616..7025f7ac84b02 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -188,29 +188,26 @@ fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>( for (param, var) in std::iter::zip(&generics.own_params, gat_vars) { let existing = match var.kind() { ty::GenericArgKind::Lifetime(re) => { - if let ty::RegionKind::ReBound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = + let ty::RegionKind::ReBound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = re.kind() - { - mapping.insert(bv.var, tcx.mk_param_from_def(param)) - } else { + else { return None; - } + }; + mapping.insert(bv.var, tcx.mk_param_from_def(param)) } ty::GenericArgKind::Type(ty) => { - if let ty::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = *ty.kind() { - mapping.insert(bv.var, tcx.mk_param_from_def(param)) - } else { + let ty::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = *ty.kind() else { return None; - } + }; + mapping.insert(bv.var, tcx.mk_param_from_def(param)) } ty::GenericArgKind::Const(ct) => { - if let ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = + let ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = ct.kind() - { - mapping.insert(bv.var, tcx.mk_param_from_def(param)) - } else { + else { return None; - } + }; + mapping.insert(bv.var, tcx.mk_param_from_def(param)) } }; diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs index 30324da3c6516..d835a7bbb8d29 100644 --- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs @@ -763,9 +763,8 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { &self, err: &mut Diag<'_, impl EmissionGuarantee>, ) { - let trait_ = match self.tcx.trait_of_assoc(self.def_id) { - Some(def_id) => def_id, - None => return, + let Some(trait_) = self.tcx.trait_of_assoc(self.def_id) else { + return; }; // Skip suggestion when the associated function is itself generic, it is unclear @@ -1077,15 +1076,11 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { /// Builds the `type defined here` message. fn show_definition(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { - let mut spans: MultiSpan = if let Some(def_span) = self.tcx.def_ident_span(self.def_id) { - if self.tcx.sess.source_map().is_span_accessible(def_span) { - def_span.into() - } else { - return; - } - } else { + let Some(def_span) = self.tcx.def_ident_span(self.def_id) else { return }; + if !self.tcx.sess.source_map().is_span_accessible(def_span) { return; }; + let mut spans: MultiSpan = def_span.into(); let msg = { let def_kind = self.tcx.def_descr(self.def_id); 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 600684d4f5147..5fc201db68e5d 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -1749,10 +1749,8 @@ fn generics_args_err_extend<'a>( GenericsArgsErrExtend::SelfTyAlias { def_id, span } => { let ty = tcx.at(span).type_of(def_id).instantiate_identity(); let span_of_impl = tcx.span_of_impl(def_id); - let def_id = match *ty.kind() { - ty::Adt(self_def, _) => self_def.did(), - _ => return, - }; + let ty::Adt(self_def, _) = *ty.kind() else { return }; + let def_id = self_def.did(); let type_name = tcx.item_name(def_id); let span_of_ty = tcx.def_ident_span(def_id); diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index f59fcab46661f..714c6a104a9e1 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -458,15 +458,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { // Actually need to unwrap one more layer of HIR to get to // the _real_ closure... - if let hir::Node::Expr(&hir::Expr { + let hir::Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }), .. }) = self.tcx.parent_hir_node(parent_hir_id) - { - fn_decl_span - } else { + else { return; - } + }; + fn_decl_span } else { return; }; diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index f1e74028f4ce7..3f214b4d2fccb 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -415,11 +415,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); Some(self.resolve_vars_if_possible(possible_rcvr_ty)) }); - if let Some(rcvr_ty) = possible_rcvr_ty { - rcvr_ty - } else { - return false; - } + let Some(rcvr_ty) = possible_rcvr_ty else { return false }; + rcvr_ty } }; diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 561230c193ce2..27b66d07f98e4 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -1561,19 +1561,15 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx base_place: PlaceWithHirId<'tcx>, ) -> Result, Cx::Error> { let base_curr_ty = base_place.place.ty(); - let deref_ty = match self + let Some(deref_ty) = self .cx .structurally_resolve_type(self.cx.tcx().hir_span(base_place.hir_id), base_curr_ty) .builtin_deref(true) - { - Some(ty) => ty, - None => { - debug!("explicit deref of non-derefable type: {:?}", base_curr_ty); - return Err(self.cx.report_bug( - self.cx.tcx().hir_span(node), - "explicit deref of non-derefable type", - )); - } + else { + debug!("explicit deref of non-derefable type: {:?}", base_curr_ty); + return Err(self + .cx + .report_bug(self.cx.tcx().hir_span(node), "explicit deref of non-derefable type")); }; let mut projections = base_place.place.projections; projections.push(Projection { kind: ProjectionKind::Deref, ty: deref_ty }); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index 854202c312705..5c04f2b5f63c4 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -48,33 +48,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let uninstantiated_pred = match flavor { - ClauseFlavor::Where => { + ClauseFlavor::Where if let Some(pred) = self .tcx .predicates_of(def_id) .instantiate_identity(self.tcx) .predicates .into_iter() - .nth(idx) - { - pred - } else { - return false; - } + .nth(idx) => + { + pred } - ClauseFlavor::Const => { + ClauseFlavor::Const if let Some((pred, _)) = self .tcx .const_conditions(def_id) .instantiate_identity(self.tcx) .into_iter() - .nth(idx) - { - pred.to_host_effect_clause(self.tcx, ty::BoundConstness::Maybe) - } else { - return false; - } + .nth(idx) => + { + pred.to_host_effect_clause(self.tcx, ty::BoundConstness::Maybe) } + _ => return false, }; let generics = self.tcx.generics_of(def_id); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 57da450d832cd..d04133ccee976 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1467,11 +1467,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => None, } }); - if let Some(new_def_id) = new_def_id { - def_id = new_def_id; - } else { - return; - } + let Some(new_def_id) = new_def_id else { return }; + def_id = new_def_id; } } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 1adcd91cc3ee2..d51b052e0d1bc 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1795,7 +1795,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(ty), hir::Path { segments: [segment], .. }, )) - | hir::ExprKind::Path(QPath::TypeRelative(ty, segment)) => { + | hir::ExprKind::Path(QPath::TypeRelative(ty, segment)) if let Some(self_ty) = self.typeck_results.borrow().node_type_opt(ty.hir_id) && let Ok(pick) = self.probe_for_name( Mode::Path, @@ -1805,12 +1805,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self_ty, expr.hir_id, ProbeScope::TraitsInScope, - ) - { - (pick.item, segment) - } else { - return false; - } + ) => + { + (pick.item, segment) } hir::ExprKind::Path(QPath::Resolved( None, @@ -1821,16 +1818,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if old_item_name != segment.ident.name { return false; } - if let Some(item) = self + let Some(item) = self .tcx .associated_items(self.tcx.parent(old_def_id)) .filter_by_name_unhygienic(capitalized_name) .next() - { - (*item, segment) - } else { + else { return false; - } + }; + (*item, segment) } _ => return false, }; diff --git a/compiler/rustc_hir_typeck/src/inline_asm.rs b/compiler/rustc_hir_typeck/src/inline_asm.rs index 6460bd72c7973..6626c3edb5466 100644 --- a/compiler/rustc_hir_typeck/src/inline_asm.rs +++ b/compiler/rustc_hir_typeck/src/inline_asm.rs @@ -121,13 +121,12 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { len, ) }; - if let Some(len) = len.try_to_target_usize(self.tcx()) { - (len, ty) - } else { + let Some(len) = len.try_to_target_usize(self.tcx()) else { return Err(NonAsmTypeReason::UnevaluatedSIMDArrayLength( field.did, len, )); - } + }; + (len, ty) } _ => (fields.len() as u64, elem_ty), }; diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 4b9ad345210dd..d31cd8569bb71 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -3543,10 +3543,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, return_type: Option>, ) { - let output_ty = match self.err_ctxt().get_impl_future_output_ty(ty) { - Some(output_ty) => self.resolve_vars_if_possible(output_ty), - _ => return, - }; + let Some(output_ty) = self.err_ctxt().get_impl_future_output_ty(ty) else { return }; + let output_ty = self.resolve_vars_if_possible(output_ty); let method_exists = self.method_exists_for_diagnostic(item_name, output_ty, call.hir_id, return_type); debug!("suggest_await_before_method: is_method_exist={}", method_exists); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 87b208923ddb9..810760e9f53e6 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1072,11 +1072,8 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes { cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, ) -> Option<(Ty<'tcx>, Ty<'tcx>)> { - let def = if let hir::ExprKind::Path(ref qpath) = expr.kind { - cx.qpath_res(qpath, expr.hir_id) - } else { - return None; - }; + let hir::ExprKind::Path(ref qpath) = expr.kind else { return None }; + let def = cx.qpath_res(qpath, expr.hir_id); if let Res::Def(DefKind::Fn, did) = def { if !def_id_is_transmute(cx, did) { return None; diff --git a/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs b/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs index f20605c914951..9220702c21f1d 100644 --- a/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs +++ b/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs @@ -120,10 +120,8 @@ impl Expr2024 { fn check_ident_token(&mut self, cx: &crate::EarlyContext<'_>, token: &Token) { debug!("check_ident_token: {:?}", token); - let (sym, edition) = match token.kind { - TokenKind::Ident(sym, _) => (sym, Edition::Edition2024), - _ => return, - }; + let TokenKind::Ident(sym, _) = token.kind else { return }; + let edition = Edition::Edition2024; debug!("token.span.edition(): {:?}", token.span.edition()); if token.span.edition() >= edition { diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 2e64fc290fcc2..279c34cb275d9 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -706,12 +706,9 @@ impl<'tcx> FallibleTypeFolder> for MakeSuggestableFolder<'tcx> { | Bound(_, _) | Placeholder(_) | Error(_) => { - if let Some(placeholder) = self.placeholder { - // We replace these with infer (which is passed in from an infcx). - placeholder - } else { - return Err(()); - } + let Some(placeholder) = self.placeholder else { return Err(()) }; + // We replace these with infer (which is passed in from an infcx). + placeholder } Alias(Opaque, AliasTy { def_id, .. }) => { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 6ca4949910f27..4e7e1da03e9f6 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2395,9 +2395,7 @@ fn typetree_from_ty_impl_inner<'tcx>( } if ty.is_ref() || ty.is_raw_ptr() || ty.is_box() { - let inner_ty = if let Some(inner) = ty.builtin_deref(true) { - inner - } else { + let Some(inner_ty) = ty.builtin_deref(true) else { return TypeTree::new(); }; diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 72573d96dc54f..852a0017687f2 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1528,18 +1528,13 @@ impl<'tcx> Ty<'tcx> { let mut cor_ty = self; let mut ty = cor_ty; loop { - if let ty::Coroutine(def_id, args) = ty.kind() { - cor_ty = ty; - f(ty); - if tcx.is_async_drop_in_place_coroutine(*def_id) { - ty = args.first().unwrap().expect_ty(); - continue; - } else { - return cor_ty; - } - } else { + let ty::Coroutine(def_id, args) = ty.kind() else { return cor_ty }; + cor_ty = ty; + f(ty); + if !tcx.is_async_drop_in_place_coroutine(*def_id) { return cor_ty; } + ty = args.first().unwrap().expect_ty(); } } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs index 6faef3e974a05..800d4e406cf09 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs @@ -100,11 +100,8 @@ impl<'tcx> MovePath<'tcx> { move_paths: &IndexSlice>, f: impl Fn(MovePathIndex) -> bool, ) -> Option { - let mut todo = if let Some(child) = self.first_child { - vec![child] - } else { - return None; - }; + let Some(child) = self.first_child else { return None }; + let mut todo = vec![child]; while let Some(mpi) = todo.pop() { if f(mpi) { @@ -331,11 +328,10 @@ impl<'tcx> MovePathLookup<'tcx> { MoveSubPathResult::Stop => None, }; - if let Some(&subpath) = subpath { - result = subpath; - } else { + let Some(&subpath) = subpath else { return LookupResult::Parent(Some(result)); - } + }; + result = subpath; } LookupResult::Exact(result) diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index b1ff7ffc60edd..daf304c1bf9df 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -721,11 +721,8 @@ impl<'tcx> Map<'tcx> { // Enum variant fields and enum discriminants alias each another. self.for_each_variant_sibling(index, sub, f); } - if let Some(sub) = sub { - index = sub - } else { - return; - } + let Some(sub) = sub else { return }; + index = sub; } self.for_each_value_inside(index, f); } diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index ebfeba5ad2252..92c74e7fc2763 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -590,31 +590,30 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { let fields = fields.iter().map(|&f| self.eval_to_const(f)).collect::>>()?; let variant = if ty.ty.is_enum() { Some(variant) } else { None }; - if matches!(ty.backend_repr, BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..)) - { - let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?; - let variant_dest = if let Some(variant) = variant { - self.ecx.project_downcast(&dest, variant).discard_err()? - } else { - dest.clone() - }; - for (field_index, op) in fields.into_iter().enumerate() { - let field_dest = self - .ecx - .project_field(&variant_dest, FieldIdx::from_usize(field_index)) - .discard_err()?; - self.ecx.copy_op(op, &field_dest).discard_err()?; - } - self.ecx - .write_discriminant(variant.unwrap_or(FIRST_VARIANT), &dest) - .discard_err()?; - self.ecx - .alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id()) - .discard_err()?; - dest.into() - } else { + let (BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..)) = ty.backend_repr + else { return None; + }; + let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?; + let variant_dest = if let Some(variant) = variant { + self.ecx.project_downcast(&dest, variant).discard_err()? + } else { + dest.clone() + }; + for (field_index, op) in fields.into_iter().enumerate() { + let field_dest = self + .ecx + .project_field(&variant_dest, FieldIdx::from_usize(field_index)) + .discard_err()?; + self.ecx.copy_op(op, &field_dest).discard_err()?; } + self.ecx + .write_discriminant(variant.unwrap_or(FIRST_VARIANT), &dest) + .discard_err()?; + self.ecx + .alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id()) + .discard_err()?; + dest.into() } Union(active_field, field) => { let field = self.eval_to_const(field)?; diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 6b0c331ff5415..7d631e96c32a7 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -410,14 +410,8 @@ impl<'tcx> Validator<'_, 'tcx> { // In theory, any zero-sized value could be borrowed // mutably without consequences. However, only &mut [] // is allowed right now. - if let ty::Array(_, len) = ty.kind() { - match len.try_to_target_usize(self.tcx) { - Some(0) => {} - _ => return Err(Unpromotable), - } - } else { - return Err(Unpromotable); - } + let ty::Array(_, len) = ty.kind() else { return Err(Unpromotable) }; + let Some(0) = len.try_to_target_usize(self.tcx) else { return Err(Unpromotable) }; } } 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 8d0a3ac94d5a3..1c79a2fd65de7 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 @@ -810,18 +810,16 @@ where pub(super) fn term_is_fully_unconstrained(&self, goal: Goal>) -> bool { let universe_of_term = match goal.predicate.term.kind() { ty::TermKind::Ty(ty) => { - if let ty::Infer(ty::TyVar(vid)) = ty.kind() { - self.delegate.universe_of_ty(vid).unwrap() - } else { + let ty::Infer(ty::TyVar(vid)) = ty.kind() else { return false; - } + }; + self.delegate.universe_of_ty(vid).unwrap() } ty::TermKind::Const(ct) => { - if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() { - self.delegate.universe_of_ct(vid).unwrap() - } else { + let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() else { return false; - } + }; + self.delegate.universe_of_ct(vid).unwrap() } }; diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index c65e0bb25897c..70c28421c57ea 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -445,17 +445,15 @@ where goal_kind: ty::ClosureKind, ) -> Result, NoSolution> { let cx = ecx.cx(); - let tupled_inputs_and_output = - match structural_traits::extract_tupled_inputs_and_output_from_callable( + let Some(tupled_inputs_and_output) = + structural_traits::extract_tupled_inputs_and_output_from_callable( cx, goal.predicate.self_ty(), goal_kind, - )? { - Some(tupled_inputs_and_output) => tupled_inputs_and_output, - None => { - return ecx.forced_ambiguity(MaybeCause::Ambiguity); - } - }; + )? + else { + return ecx.forced_ambiguity(MaybeCause::Ambiguity); + }; let (inputs, output) = ecx.instantiate_binder_with_infer(tupled_inputs_and_output); // A built-in `Fn` impl only holds if the output is sized. diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 168921655a394..651f073efb828 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -360,17 +360,15 @@ where } let cx = ecx.cx(); - let tupled_inputs_and_output = - match structural_traits::extract_tupled_inputs_and_output_from_callable( + let Some(tupled_inputs_and_output) = + structural_traits::extract_tupled_inputs_and_output_from_callable( cx, goal.predicate.self_ty(), goal_kind, - )? { - Some(a) => a, - None => { - return ecx.forced_ambiguity(MaybeCause::Ambiguity); - } - }; + )? + else { + return ecx.forced_ambiguity(MaybeCause::Ambiguity); + }; let (inputs, output) = ecx.instantiate_binder_with_infer(tupled_inputs_and_output); // A built-in `Fn` impl only holds if the output is sized. @@ -1409,42 +1407,39 @@ where let where_bounds: Vec<_> = candidates .extract_if(.., |c| matches!(c.source, CandidateSource::ParamEnv(_))) .collect(); - if let Some((response, info)) = self.try_merge_candidates(&where_bounds) { - match info { - // If there's an always applicable candidate, the result of all - // other candidates does not matter. This means we can ignore - // them when checking whether we've reached a fixpoint. - // - // We always prefer the first always applicable candidate, even if a - // later candidate is also always applicable and would result in fewer - // reruns. We could slightly improve this by e.g. searching for another - // always applicable candidate which doesn't depend on any cycle heads. - // - // NOTE: This is optimization is observable in case there is an always - // applicable global candidate and another non-global candidate which only - // applies because of a provisional result. I can't even think of a test - // case where this would occur and even then, this would not be unsound. - // Supporting this makes the code more involved, so I am just going to - // ignore this for now. - MergeCandidateInfo::AlwaysApplicable(i) => { - for (j, c) in where_bounds.into_iter().enumerate() { - if i != j { - self.ignore_candidate_head_usages(c.head_usages) - } + let Some((response, info)) = self.try_merge_candidates(&where_bounds) else { + return Ok((self.bail_with_ambiguity(&where_bounds), None)); + }; + match info { + // If there's an always applicable candidate, the result of all + // other candidates does not matter. This means we can ignore + // them when checking whether we've reached a fixpoint. + // + // We always prefer the first always applicable candidate, even if a + // later candidate is also always applicable and would result in fewer + // reruns. We could slightly improve this by e.g. searching for another + // always applicable candidate which doesn't depend on any cycle heads. + // + // NOTE: This is optimization is observable in case there is an always + // applicable global candidate and another non-global candidate which only + // applies because of a provisional result. I can't even think of a test + // case where this would occur and even then, this would not be unsound. + // Supporting this makes the code more involved, so I am just going to + // ignore this for now. + MergeCandidateInfo::AlwaysApplicable(i) => { + for (j, c) in where_bounds.into_iter().enumerate() { + if i != j { + self.ignore_candidate_head_usages(c.head_usages) } - // If a where-bound does not apply, we don't actually get a - // candidate for it. We manually track the head usages - // of all failed `ParamEnv` candidates instead. - self.ignore_candidate_head_usages( - failed_candidate_info.param_env_head_usages, - ); } - MergeCandidateInfo::EqualResponse => {} + // If a where-bound does not apply, we don't actually get a + // candidate for it. We manually track the head usages + // of all failed `ParamEnv` candidates instead. + self.ignore_candidate_head_usages(failed_candidate_info.param_env_head_usages); } - return Ok((response, Some(TraitGoalProvenVia::ParamEnv))); - } else { - return Ok((self.bail_with_ambiguity(&where_bounds), None)); - }; + MergeCandidateInfo::EqualResponse => {} + } + return Ok((response, Some(TraitGoalProvenVia::ParamEnv))); } // Next, prefer any alias bound (nested or otherwise). diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 069944b638c71..233a4c48862ac 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1537,86 +1537,80 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { /// Given `where ::Baz: String`, suggest `where T: Bar`. fn restrict_assoc_type_in_where_clause(&self, span: Span, err: &mut Diag<'_>) -> bool { // Detect that we are actually in a `where` predicate. - let (bounded_ty, bounds, where_span) = if let Some(ast::WherePredicate { + let Some(ast::WherePredicate { kind: ast::WherePredicateKind::BoundPredicate(ast::WhereBoundPredicate { bounded_ty, bound_generic_params, bounds, }), - span, + span: where_span, .. }) = self.diag_metadata.current_where_predicate - { - if !bound_generic_params.is_empty() { - return false; - } - (bounded_ty, bounds, span) - } else { + else { return false; }; + if !bound_generic_params.is_empty() { + return false; + } // Confirm that the target is an associated type. - let (ty, _, path) = if let ast::TyKind::Path(Some(qself), path) = &bounded_ty.kind { - // use this to verify that ident is a type param. - let Some(partial_res) = self.r.partial_res_map.get(&bounded_ty.id) else { - return false; - }; - if !matches!( - partial_res.full_res(), - Some(hir::def::Res::Def(hir::def::DefKind::AssocTy, _)) - ) { - return false; - } - (&qself.ty, qself.position, path) - } else { + let ast::TyKind::Path(Some(qself), path) = &bounded_ty.kind else { return false }; + // use this to verify that ident is a type param. + let Some(partial_res) = self.r.partial_res_map.get(&bounded_ty.id) else { return false }; + if !matches!( + partial_res.full_res(), + Some(hir::def::Res::Def(hir::def::DefKind::AssocTy, _)) + ) { return false; - }; + } - let peeled_ty = ty.peel_refs(); - if let ast::TyKind::Path(None, type_param_path) = &peeled_ty.kind { - // Confirm that the `SelfTy` is a type parameter. - let Some(partial_res) = self.r.partial_res_map.get(&peeled_ty.id) else { + let peeled_ty = qself.ty.peel_refs(); + let ast::TyKind::Path(None, type_param_path) = &peeled_ty.kind else { return false }; + // Confirm that the `SelfTy` is a type parameter. + let Some(partial_res) = self.r.partial_res_map.get(&peeled_ty.id) else { + return false; + }; + if !matches!( + partial_res.full_res(), + Some(hir::def::Res::Def(hir::def::DefKind::TyParam, _)) + ) { + return false; + } + let ([ast::PathSegment { args: None, .. }], [ast::GenericBound::Trait(poly_trait_ref)]) = + (&type_param_path.segments[..], &bounds[..]) + else { + return false; + }; + let [ast::PathSegment { ident, args: None, id }] = + &poly_trait_ref.trait_ref.path.segments[..] + else { + return false; + }; + if poly_trait_ref.modifiers != ast::TraitBoundModifiers::NONE { + return false; + } + if ident.span == span { + let Some(partial_res) = self.r.partial_res_map.get(&id) else { return false; }; - if !matches!( - partial_res.full_res(), - Some(hir::def::Res::Def(hir::def::DefKind::TyParam, _)) - ) { + if !matches!(partial_res.full_res(), Some(hir::def::Res::Def(..))) { return false; } - if let ( - [ast::PathSegment { args: None, .. }], - [ast::GenericBound::Trait(poly_trait_ref)], - ) = (&type_param_path.segments[..], &bounds[..]) - && let [ast::PathSegment { ident, args: None, id }] = - &poly_trait_ref.trait_ref.path.segments[..] - && poly_trait_ref.modifiers == ast::TraitBoundModifiers::NONE - { - if ident.span == span { - let Some(partial_res) = self.r.partial_res_map.get(&id) else { - return false; - }; - if !matches!(partial_res.full_res(), Some(hir::def::Res::Def(..))) { - return false; - } - let Some(new_where_bound_predicate) = - mk_where_bound_predicate(path, poly_trait_ref, ty) - else { - return false; - }; - err.span_suggestion_verbose( - *where_span, - format!("constrain the associated type to `{ident}`"), - where_bound_predicate_to_string(&new_where_bound_predicate), - Applicability::MaybeIncorrect, - ); - } - return true; - } + let Some(new_where_bound_predicate) = + mk_where_bound_predicate(path, poly_trait_ref, &qself.ty) + else { + return false; + }; + err.span_suggestion_verbose( + *where_span, + format!("constrain the associated type to `{ident}`"), + where_bound_predicate_to_string(&new_where_bound_predicate), + Applicability::MaybeIncorrect, + ); } - false + true } /// Check if the source is call expression and the first argument is `self`. If true, From a49c17538009294569a4658d61283823ab6adea6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 9 Dec 2025 00:54:18 +0000 Subject: [PATCH 17/18] `#![deny(clippy::manual_let_else)]` in some rustc modules --- compiler/rustc_ast/src/lib.rs | 1 + compiler/rustc_borrowck/src/lib.rs | 1 + compiler/rustc_const_eval/src/lib.rs | 1 + compiler/rustc_hir/src/lib.rs | 1 + compiler/rustc_hir_analysis/src/lib.rs | 1 + compiler/rustc_hir_typeck/src/lib.rs | 1 + compiler/rustc_lint/src/lib.rs | 1 + compiler/rustc_middle/src/lib.rs | 1 + compiler/rustc_next_trait_solver/src/lib.rs | 1 + compiler/rustc_resolve/src/lib.rs | 1 + 10 files changed, 10 insertions(+) diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index cbdc89f9deedc..10a8e181c840e 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -6,6 +6,7 @@ // tidy-alphabetical-start #![cfg_attr(bootstrap, feature(array_windows))] +#![deny(clippy::manual_let_else)] #![doc(test(attr(deny(warnings), allow(internal_features))))] #![feature(associated_type_defaults)] #![feature(box_patterns)] diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 8d61ffde116c5..d82357fca2d45 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2,6 +2,7 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![deny(clippy::manual_let_else)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(file_buffered)] diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 2fce4b8c0566e..6c74ed2a5121d 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -1,5 +1,6 @@ // tidy-alphabetical-start #![allow(rustc::diagnostic_outside_of_impl)] +#![deny(clippy::manual_let_else)] #![feature(array_try_map)] #![feature(assert_matches)] #![feature(box_patterns)] diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 7a5776f0d5a93..c27954b6d14e4 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -4,6 +4,7 @@ // tidy-alphabetical-start #![cfg_attr(bootstrap, feature(debug_closure_helpers))] +#![deny(clippy::manual_let_else)] #![feature(associated_type_defaults)] #![feature(closure_track_caller)] #![feature(const_default)] diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 538fb8c7df1ea..79c5fbab1ffa2 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -59,6 +59,7 @@ This API is completely unstable and subject to change. #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] #![cfg_attr(bootstrap, feature(debug_closure_helpers))] +#![deny(clippy::manual_let_else)] #![feature(assert_matches)] #![feature(gen_blocks)] #![feature(if_let_guard)] diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index d3ef1d63e8ba9..9ca5ddd494aeb 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -1,4 +1,5 @@ // tidy-alphabetical-start +#![deny(clippy::manual_let_else)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(if_let_guard)] diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 4e7a3e4051767..49929a0a9bc76 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -22,6 +22,7 @@ // tidy-alphabetical-start #![allow(internal_features)] #![cfg_attr(bootstrap, feature(array_windows))] +#![deny(clippy::manual_let_else)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(if_let_guard)] diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 5f62d44df6b61..ee3e89e57bd42 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -30,6 +30,7 @@ #![allow(rustc::direct_use_of_rustc_type_ir)] #![allow(rustc::untranslatable_diagnostic)] #![cfg_attr(bootstrap, feature(array_windows))] +#![deny(clippy::manual_let_else)] #![feature(allocator_api)] #![feature(assert_matches)] #![feature(associated_type_defaults)] diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs index 5fa29b7d9f813..117751810e29b 100644 --- a/compiler/rustc_next_trait_solver/src/lib.rs +++ b/compiler/rustc_next_trait_solver/src/lib.rs @@ -8,6 +8,7 @@ #![allow(rustc::direct_use_of_rustc_type_ir)] #![allow(rustc::usage_of_type_ir_inherent)] #![allow(rustc::usage_of_type_ir_traits)] +#![deny(clippy::manual_let_else)] // tidy-alphabetical-end pub mod canonical; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 0b4ec6956bd15..38cf83dc23f73 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -10,6 +10,7 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![deny(clippy::manual_let_else)] #![feature(arbitrary_self_types)] #![feature(assert_matches)] #![feature(box_patterns)] From 97c774215165b7422c2e6e18e52fc5d63f8669ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 12 Dec 2025 17:55:26 +0000 Subject: [PATCH 18/18] revert one change from rustc_next_trait_solver --- compiler/rustc_next_trait_solver/src/lib.rs | 1 - .../src/solve/eval_ctxt/mod.rs | 14 ++++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs index 117751810e29b..5fa29b7d9f813 100644 --- a/compiler/rustc_next_trait_solver/src/lib.rs +++ b/compiler/rustc_next_trait_solver/src/lib.rs @@ -8,7 +8,6 @@ #![allow(rustc::direct_use_of_rustc_type_ir)] #![allow(rustc::usage_of_type_ir_inherent)] #![allow(rustc::usage_of_type_ir_traits)] -#![deny(clippy::manual_let_else)] // tidy-alphabetical-end pub mod canonical; 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 1c79a2fd65de7..8d0a3ac94d5a3 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 @@ -810,16 +810,18 @@ where pub(super) fn term_is_fully_unconstrained(&self, goal: Goal>) -> bool { let universe_of_term = match goal.predicate.term.kind() { ty::TermKind::Ty(ty) => { - let ty::Infer(ty::TyVar(vid)) = ty.kind() else { + if let ty::Infer(ty::TyVar(vid)) = ty.kind() { + self.delegate.universe_of_ty(vid).unwrap() + } else { return false; - }; - self.delegate.universe_of_ty(vid).unwrap() + } } ty::TermKind::Const(ct) => { - let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() else { + if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() { + self.delegate.universe_of_ct(vid).unwrap() + } else { return false; - }; - self.delegate.universe_of_ct(vid).unwrap() + } } };