From fa63e12b7d556dfc4884541d75da182fd5df64ba Mon Sep 17 00:00:00 2001 From: Joao Roberto Date: Wed, 23 Sep 2026 10:54:49 -0300 Subject: [PATCH 01/49] Test mixed ambiguous ORs under assumptions on binders --- ...mixed-ambiguous-alias-outlives.fail.stderr | 20 +++++ .../mixed-ambiguous-alias-outlives.rs | 82 +++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 tests/ui/assumptions_on_binders/mixed-ambiguous-alias-outlives.fail.stderr create mode 100644 tests/ui/assumptions_on_binders/mixed-ambiguous-alias-outlives.rs diff --git a/tests/ui/assumptions_on_binders/mixed-ambiguous-alias-outlives.fail.stderr b/tests/ui/assumptions_on_binders/mixed-ambiguous-alias-outlives.fail.stderr new file mode 100644 index 0000000000000..b74bae2a7f964 --- /dev/null +++ b/tests/ui/assumptions_on_binders/mixed-ambiguous-alias-outlives.fail.stderr @@ -0,0 +1,20 @@ +error: unable to satisfy constraints involving placeholders due to unknown implied bounds + --> $DIR/mixed-ambiguous-alias-outlives.rs:32:9 + | +LL | forall<'a> { + | ^^^^^^ + +error: unable to satisfy constraints involving placeholders due to unknown implied bounds + --> $DIR/mixed-ambiguous-alias-outlives.rs:60:9 + | +LL | forall<'a> { + | ^^^^^^ + +error: unable to satisfy constraints involving placeholders due to unknown implied bounds + --> $DIR/mixed-ambiguous-alias-outlives.rs:72:9 + | +LL | forall<'a> { + | ^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/assumptions_on_binders/mixed-ambiguous-alias-outlives.rs b/tests/ui/assumptions_on_binders/mixed-ambiguous-alias-outlives.rs new file mode 100644 index 0000000000000..4fb0abba2aa24 --- /dev/null +++ b/tests/ui/assumptions_on_binders/mixed-ambiguous-alias-outlives.rs @@ -0,0 +1,82 @@ +//@ revisions: pass fail +//@[pass] check-pass +//@ compile-flags: -Zassumptions-on-binders -Znext-solver=globally + +#![feature(test_binder_constraints)] + +trait Project { + type Assoc; +} + +impl Project for T { + type Assoc = T; +} + +#[cfg(pass)] +core::test_binder_constraints! { + impl> { + forall<'a> { + or { + ambiguity, + for<> T::Assoc: 'a, + } + } + } +} + +// If the concrete candidate is rejected at the root, the ambiguous alternative must +// still cause an error rather than disappearing with the rejected candidate. +#[cfg(fail)] +core::test_binder_constraints! { + impl { + forall<'a> { + //[fail]~^ ERROR unable to satisfy constraints involving placeholders + or { + ambiguity, + for<> T::Assoc: 'a, + } + } + } +} + +// The order of the alternatives must not change whether the bound can be proved. +#[cfg(pass)] +core::test_binder_constraints! { + impl> { + forall<'a> { + or { + for<> T::Assoc: 'a, + ambiguity, + } + } + } +} + +// A required ambiguous constraint still makes the whole AND ambiguous, even when +// its sibling is known to hold. +#[cfg(fail)] +core::test_binder_constraints! { + impl> { + forall<'a> { + //[fail]~^ ERROR unable to satisfy constraints involving placeholders + ambiguity, + for<> T::Assoc: 'a, + } + } +} + +// Ambiguity shared by every OR alternative is still required after canonicalization. +#[cfg(fail)] +core::test_binder_constraints! { + impl { + forall<'a> { + //[fail]~^ ERROR unable to satisfy constraints involving placeholders + or { + ambiguity, + ambiguity, + } + } + } +} + +fn main() {} From ead34503f35a4b7c381c42f938f12e15b5b67444 Mon Sep 17 00:00:00 2001 From: Joao Roberto Date: Sat, 17 Oct 2026 15:56:14 -0300 Subject: [PATCH 02/49] Combine mixed ambiguous OR test cases --- .../mixed-ambiguous-alias-outlives.rs | 13 +++---------- ...stderr => mixed-ambiguous-alias-outlives.stderr} | 6 +++--- 2 files changed, 6 insertions(+), 13 deletions(-) rename tests/ui/assumptions_on_binders/{mixed-ambiguous-alias-outlives.fail.stderr => mixed-ambiguous-alias-outlives.stderr} (75%) diff --git a/tests/ui/assumptions_on_binders/mixed-ambiguous-alias-outlives.rs b/tests/ui/assumptions_on_binders/mixed-ambiguous-alias-outlives.rs index 4fb0abba2aa24..f09cd03273541 100644 --- a/tests/ui/assumptions_on_binders/mixed-ambiguous-alias-outlives.rs +++ b/tests/ui/assumptions_on_binders/mixed-ambiguous-alias-outlives.rs @@ -1,5 +1,3 @@ -//@ revisions: pass fail -//@[pass] check-pass //@ compile-flags: -Zassumptions-on-binders -Znext-solver=globally #![feature(test_binder_constraints)] @@ -12,7 +10,6 @@ impl Project for T { type Assoc = T; } -#[cfg(pass)] core::test_binder_constraints! { impl> { forall<'a> { @@ -26,11 +23,10 @@ core::test_binder_constraints! { // If the concrete candidate is rejected at the root, the ambiguous alternative must // still cause an error rather than disappearing with the rejected candidate. -#[cfg(fail)] core::test_binder_constraints! { impl { forall<'a> { - //[fail]~^ ERROR unable to satisfy constraints involving placeholders + //~^ ERROR unable to satisfy constraints involving placeholders or { ambiguity, for<> T::Assoc: 'a, @@ -40,7 +36,6 @@ core::test_binder_constraints! { } // The order of the alternatives must not change whether the bound can be proved. -#[cfg(pass)] core::test_binder_constraints! { impl> { forall<'a> { @@ -54,11 +49,10 @@ core::test_binder_constraints! { // A required ambiguous constraint still makes the whole AND ambiguous, even when // its sibling is known to hold. -#[cfg(fail)] core::test_binder_constraints! { impl> { forall<'a> { - //[fail]~^ ERROR unable to satisfy constraints involving placeholders + //~^ ERROR unable to satisfy constraints involving placeholders ambiguity, for<> T::Assoc: 'a, } @@ -66,11 +60,10 @@ core::test_binder_constraints! { } // Ambiguity shared by every OR alternative is still required after canonicalization. -#[cfg(fail)] core::test_binder_constraints! { impl { forall<'a> { - //[fail]~^ ERROR unable to satisfy constraints involving placeholders + //~^ ERROR unable to satisfy constraints involving placeholders or { ambiguity, ambiguity, diff --git a/tests/ui/assumptions_on_binders/mixed-ambiguous-alias-outlives.fail.stderr b/tests/ui/assumptions_on_binders/mixed-ambiguous-alias-outlives.stderr similarity index 75% rename from tests/ui/assumptions_on_binders/mixed-ambiguous-alias-outlives.fail.stderr rename to tests/ui/assumptions_on_binders/mixed-ambiguous-alias-outlives.stderr index b74bae2a7f964..c4df98380aa1b 100644 --- a/tests/ui/assumptions_on_binders/mixed-ambiguous-alias-outlives.fail.stderr +++ b/tests/ui/assumptions_on_binders/mixed-ambiguous-alias-outlives.stderr @@ -1,17 +1,17 @@ error: unable to satisfy constraints involving placeholders due to unknown implied bounds - --> $DIR/mixed-ambiguous-alias-outlives.rs:32:9 + --> $DIR/mixed-ambiguous-alias-outlives.rs:28:9 | LL | forall<'a> { | ^^^^^^ error: unable to satisfy constraints involving placeholders due to unknown implied bounds - --> $DIR/mixed-ambiguous-alias-outlives.rs:60:9 + --> $DIR/mixed-ambiguous-alias-outlives.rs:54:9 | LL | forall<'a> { | ^^^^^^ error: unable to satisfy constraints involving placeholders due to unknown implied bounds - --> $DIR/mixed-ambiguous-alias-outlives.rs:72:9 + --> $DIR/mixed-ambiguous-alias-outlives.rs:65:9 | LL | forall<'a> { | ^^^^^^ From 9a721b6e5cbc3a13f1288f6670f0a1c5740677bf Mon Sep 17 00:00:00 2001 From: Joao Roberto Date: Sat, 10 Oct 2026 13:00:58 -0300 Subject: [PATCH 03/49] Add region equality to the binder testing DSL --- compiler/rustc_ast/src/ast.rs | 9 +++++++++ compiler/rustc_ast/src/visit.rs | 1 + compiler/rustc_ast_lowering/src/item.rs | 9 ++++++++- compiler/rustc_hir/src/hir.rs | 1 + compiler/rustc_hir/src/intravisit.rs | 7 ++++++- .../rustc_hir_analysis/src/check/wfcheck.rs | 12 ++++++++++- compiler/rustc_hir_analysis/src/collect.rs | 20 +++++++++++++++++-- compiler/rustc_parse/src/parser/item.rs | 12 ++++++++++- 8 files changed, 65 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index c86d6366e0753..92c91283e5357 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -4099,11 +4099,20 @@ pub struct TestBinderBody { pub span: Span, pub foralls: ThinVec, pub exists: ThinVec, + pub region_equalities: Vec, pub constraints: Vec, /// These are not where clauses, but rather predicates within the body to be proven pub predicates: Vec, } +#[derive(Clone, Encodable, Decodable, Debug, Walkable)] +pub struct TestBinderRegionEquality { + #[visitable(extra = LifetimeCtxt::Bound)] + pub lhs: Lifetime, + #[visitable(extra = LifetimeCtxt::Bound)] + pub rhs: Lifetime, +} + #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct TestBinderForall { pub span: Span, diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index e4813b9588409..1f7aad264c0ec 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -559,6 +559,7 @@ macro_rules! common_visitor_and_walkers { StructExpr, StructRest, Term, + TestBinderRegionEquality, Trait, TraitBoundModifiers, TraitObjectSyntax, diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index abeafe2580171..5b63dfa7fde2b 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -2008,6 +2008,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let exists = self.arena.alloc_from_iter( body.exists.iter().map(|exists| self.lower_test_binder_exists(exists)), ); + let region_equalities = self.arena.alloc_from_iter(body.region_equalities.iter().map( + |TestBinderRegionEquality { lhs, rhs }| { + let lhs = self.lower_lifetime(lhs, LifetimeSource::Other, lhs.ident.into()); + let rhs = self.lower_lifetime(rhs, LifetimeSource::Other, rhs.ident.into()); + (lhs, rhs) + }, + )); let constraints = self.lower_test_binder_constraints_as_and(&body.constraints); let mut dedup_map = Default::default(); let predicates = self.arena.alloc_from_iter( @@ -2016,7 +2023,7 @@ impl<'hir> LoweringContext<'_, 'hir> { .map(|predicate| self.lower_where_predicate(predicate, &[], &mut dedup_map)), ); let span = self.lower_span(body.span); - hir::TestBinderBody { foralls, exists, constraints, predicates, span } + hir::TestBinderBody { span, foralls, exists, region_equalities, constraints, predicates } } fn lower_test_binder_forall( diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 4b27781086b02..5c7d434cd87b0 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4533,6 +4533,7 @@ pub struct TestBinderBody<'hir> { pub span: Span, pub foralls: &'hir [TestBinderForall<'hir>], pub exists: &'hir [TestBinderExists<'hir>], + pub region_equalities: &'hir [(&'hir Lifetime, &'hir Lifetime)], /// Constraints to be inserted directly into constraint storage to be proven pub constraints: TestBinderConstraint<'hir>, /// Constraints declared using `where` syntax, used via `register_obligation` diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 0fa40d0409854..f30dd8a707e27 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1600,9 +1600,14 @@ pub fn walk_test_binder_body<'v, V: Visitor<'v>>( visitor: &mut V, body: &'v TestBinderBody<'v>, ) -> V::Result { - let TestBinderBody { span: _, foralls, exists, constraints, predicates } = body; + let TestBinderBody { span: _, foralls, exists, region_equalities, constraints, predicates } = + body; walk_list!(visitor, visit_test_binder_forall, *foralls); walk_list!(visitor, visit_test_binder_exists, *exists); + for (lhs, rhs) in *region_equalities { + try_visit!(visitor.visit_lifetime(lhs)); + try_visit!(visitor.visit_lifetime(rhs)); + } try_visit!(visitor.visit_test_binder_constraint(&constraints)); walk_list!(visitor, visit_where_predicate, *predicates); V::Result::output() diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 9d8a133905301..75fc412ddbfa9 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -2380,7 +2380,16 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { #[instrument(level = "debug", skip(self))] pub(super) fn check_test_binder_body(&self, body: TestBinderBody<'tcx>) { - let TestBinderBody { span, foralls, exists, constraints, predicates } = body; + let TestBinderBody { span, foralls, exists, region_equalities, constraints, predicates } = + body; + for (equality, span) in region_equalities { + let cause = traits::ObligationCause::misc(span, self.body_def_id); + self.infcx.register_region_eq_constraint( + equality, + ty::VisibleForLeakCheck::Yes, + &cause, + ); + } if !predicates.is_empty() { for (predicate, span) in predicates { let cause = traits::ObligationCause::misc(span, self.body_def_id); @@ -2800,6 +2809,7 @@ pub(crate) struct TestBinderBody<'tcx> { pub span: Span, pub foralls: Vec>, pub exists: Vec>, + pub region_equalities: Vec<(ty::RegionEqPredicate<'tcx>, Span)>, /// Constraints to be inserted directly into constraint storage to be proven pub constraints: SolverRegionConstraint<'tcx>, /// Constraints declared using `where` syntax, used via `register_obligation` diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 7f181ef2e7e04..625542f6b9b2d 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -328,16 +328,32 @@ impl<'tcx> ItemCtxt<'tcx> { &self, item: &hir::TestBinderBody<'tcx>, ) -> TestBinderBody<'tcx> { - let hir::TestBinderBody { span, foralls, exists, constraints, predicates } = item; + let hir::TestBinderBody { + span, + foralls, + exists, + region_equalities, + constraints, + predicates, + } = item; let foralls = foralls.iter().map(|forall| self.lower_test_binder_forall(forall)).collect(); let exists = exists.iter().map(|exists| self.lower_test_binder_exists(exists)).collect(); + let region_equalities = region_equalities + .iter() + .map(|(lhs, rhs)| { + let span = lhs.ident.span.to(rhs.ident.span); + let lhs = self.lowerer().lower_lifetime(lhs, RegionInferReason::RegionPredicate); + let rhs = self.lowerer().lower_lifetime(rhs, RegionInferReason::RegionPredicate); + (ty::RegionEqPredicate(lhs, rhs), span) + }) + .collect(); let constraints = self.lower_test_binder_constraint(&constraints); let mut clauses = Default::default(); for predicate in *predicates { clauses_of::where_predicate_clauses(self, predicate, &mut clauses); } let predicates = clauses.into_iter().map(|(c, span)| (c.kind(), span)).collect(); - TestBinderBody { span: *span, foralls, exists, constraints, predicates } + TestBinderBody { span: *span, foralls, exists, region_equalities, constraints, predicates } } #[instrument(level = "debug", skip(self), ret)] diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 2011f8646346e..029bf168973ed 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2729,6 +2729,7 @@ impl<'a> Parser<'a> { pub fn parse_test_binder_body(&mut self) -> PResult<'a, TestBinderBody> { let mut foralls = ThinVec::new(); let mut exists = ThinVec::new(); + let mut region_equalities = Vec::new(); let mut constraints = Vec::new(); let mut predicates = Vec::new(); let mut span = self.token.span; @@ -2746,12 +2747,21 @@ impl<'a> Parser<'a> { exists.push(this.parse_test_binder_exists()?) } + _ if this.token.is_lifetime() && this.look_ahead(1, |t| t.kind == token::Eq) => { + let lhs = this.expect_lifetime(); + this.expect(exp!(Eq))?; + if !this.check_lifetime() { + this.unexpected()?; + } + let rhs = this.expect_lifetime(); + region_equalities.push(TestBinderRegionEquality { lhs, rhs }); + } _ => constraints.push(this.parse_test_binder_constraint()?), } Ok(()) })?; span = span.to(self.prev_token.span); - Ok(TestBinderBody { foralls, exists, constraints, predicates, span }) + Ok(TestBinderBody { foralls, exists, region_equalities, constraints, predicates, span }) } pub fn parse_test_binder_forall(&mut self) -> PResult<'a, TestBinderForall> { From 40295c384050d53820864382459e79472f8cb663 Mon Sep 17 00:00:00 2001 From: Joao Roberto Date: Sat, 10 Oct 2026 13:04:00 -0300 Subject: [PATCH 04/49] Resolve region variables before handling placeholders --- .../rustc_type_ir/src/region_constraint.rs | 1 + .../region-var-outlives-constraints.rs | 31 +++++++ .../region-var-outlives-constraints.stderr | 8 ++ .../resolve-region-vars.rs | 82 +++++++++++++++++++ 4 files changed, 122 insertions(+) create mode 100644 tests/ui/assumptions_on_binders/region-var-outlives-constraints.rs create mode 100644 tests/ui/assumptions_on_binders/region-var-outlives-constraints.stderr create mode 100644 tests/ui/assumptions_on_binders/resolve-region-vars.rs diff --git a/compiler/rustc_type_ir/src/region_constraint.rs b/compiler/rustc_type_ir/src/region_constraint.rs index 257d0a776403e..b5c774489ffb7 100644 --- a/compiler/rustc_type_ir/src/region_constraint.rs +++ b/compiler/rustc_type_ir/src/region_constraint.rs @@ -619,6 +619,7 @@ pub fn eagerly_handle_placeholders_in_universe RegionConstraint { assert!(u > UniverseIndex::ROOT, "eagerly handle placeholders called for root universe"); + let constraint = infcx.deeply_resolve_via_unification_table(constraint); let assumptions = infcx.get_placeholder_assumptions(u); // 1. rewrite type outlives constraints involving things from `u` into either region constraints diff --git a/tests/ui/assumptions_on_binders/region-var-outlives-constraints.rs b/tests/ui/assumptions_on_binders/region-var-outlives-constraints.rs new file mode 100644 index 0000000000000..303a9578fded5 --- /dev/null +++ b/tests/ui/assumptions_on_binders/region-var-outlives-constraints.rs @@ -0,0 +1,31 @@ +//@ compile-flags: -Zassumptions-on-binders -Znext-solver=globally + +#![feature(test_binder_constraints)] + +trait Trait<'a, 'b> { + type Assoc; +} + +core::test_binder_constraints! { + impl<'c, T> + where + for<'a, 'b> T: Trait<'a, 'b>, + { + forall<'a> + //~^ ERROR unable to satisfy constraints involving placeholders due to unknown implied bounds + where + for<'b> >::Assoc: 'c, + { + forall<'b> { + exists<'a2, 'b2, 'c2> { + 'a2: 'a, 'a: 'a2, + 'b2: 'b, 'b: 'b2, + 'c2: 'c, 'c: 'c2, + predicates >::Assoc: 'c2 + } + } expect { ambiguity } + } expect { ambiguity } + } +} + +fn main() {} diff --git a/tests/ui/assumptions_on_binders/region-var-outlives-constraints.stderr b/tests/ui/assumptions_on_binders/region-var-outlives-constraints.stderr new file mode 100644 index 0000000000000..cddec4ad9fd52 --- /dev/null +++ b/tests/ui/assumptions_on_binders/region-var-outlives-constraints.stderr @@ -0,0 +1,8 @@ +error: unable to satisfy constraints involving placeholders due to unknown implied bounds + --> $DIR/region-var-outlives-constraints.rs:14:9 + | +LL | forall<'a> + | ^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/assumptions_on_binders/resolve-region-vars.rs b/tests/ui/assumptions_on_binders/resolve-region-vars.rs new file mode 100644 index 0000000000000..3543a2f810e63 --- /dev/null +++ b/tests/ui/assumptions_on_binders/resolve-region-vars.rs @@ -0,0 +1,82 @@ +//@ check-pass +//@ compile-flags: -Zassumptions-on-binders -Znext-solver=globally + +#![feature(test_binder_constraints)] + +trait Trait<'a, 'b> { + type Assoc; +} + +core::test_binder_constraints! { + impl<'c, T> + where + for<'a, 'b> T: Trait<'a, 'b>, + { + forall<'a> + where + for<'b> >::Assoc: 'c, + { + forall<'b> { + predicates >::Assoc: 'c + } expect { + for<'b> >::Assoc: 'c + } + } expect { } + } +} + +core::test_binder_constraints! { + impl<'c, T> + where + for<'a, 'b> T: Trait<'a, 'b>, + { + forall<'a> + where + for<'b> >::Assoc: 'c, + { + forall<'b> { + exists<'a2, 'b2, 'c2> { + 'a2 = 'a, + 'b2 = 'b, + 'c2 = 'c, + or { + for<> >::Assoc: 'c2, + and { T: 'c2, 'a2: 'c2, 'b2: 'c2 } + } + } + } expect { + for<'b> >::Assoc: 'c + } + } expect { } + } +} + +core::test_binder_constraints! { + impl<'c, T> + where + for<'a, 'b> T: Trait<'a, 'b>, + { + forall<'a> + where + for<'b> >::Assoc: 'c, + { + forall<'b> { + exists<'a2, 'b2, 'c2> { + exists<'a3, 'b3, 'c3> { + 'a2 = 'a3, + 'b2 = 'b3, + 'c2 = 'c3, + 'a3 = 'a, + 'b3 = 'b, + 'c3 = 'c, + for<> >::Assoc: 'c3 + } + } + } expect { + for<'b> >::Assoc: 'c + } + } expect { } + } +} + +fn main() {} From 6d8cf48610f04f43edab2fa5ed6928edd2c7dc0d Mon Sep 17 00:00:00 2001 From: Joao Roberto Date: Mon, 12 Oct 2026 16:35:00 -0300 Subject: [PATCH 05/49] Remove obsolete region variable ambiguity control --- .../region-var-outlives-constraints.rs | 31 ------------------- .../region-var-outlives-constraints.stderr | 8 ----- 2 files changed, 39 deletions(-) delete mode 100644 tests/ui/assumptions_on_binders/region-var-outlives-constraints.rs delete mode 100644 tests/ui/assumptions_on_binders/region-var-outlives-constraints.stderr diff --git a/tests/ui/assumptions_on_binders/region-var-outlives-constraints.rs b/tests/ui/assumptions_on_binders/region-var-outlives-constraints.rs deleted file mode 100644 index 303a9578fded5..0000000000000 --- a/tests/ui/assumptions_on_binders/region-var-outlives-constraints.rs +++ /dev/null @@ -1,31 +0,0 @@ -//@ compile-flags: -Zassumptions-on-binders -Znext-solver=globally - -#![feature(test_binder_constraints)] - -trait Trait<'a, 'b> { - type Assoc; -} - -core::test_binder_constraints! { - impl<'c, T> - where - for<'a, 'b> T: Trait<'a, 'b>, - { - forall<'a> - //~^ ERROR unable to satisfy constraints involving placeholders due to unknown implied bounds - where - for<'b> >::Assoc: 'c, - { - forall<'b> { - exists<'a2, 'b2, 'c2> { - 'a2: 'a, 'a: 'a2, - 'b2: 'b, 'b: 'b2, - 'c2: 'c, 'c: 'c2, - predicates >::Assoc: 'c2 - } - } expect { ambiguity } - } expect { ambiguity } - } -} - -fn main() {} diff --git a/tests/ui/assumptions_on_binders/region-var-outlives-constraints.stderr b/tests/ui/assumptions_on_binders/region-var-outlives-constraints.stderr deleted file mode 100644 index cddec4ad9fd52..0000000000000 --- a/tests/ui/assumptions_on_binders/region-var-outlives-constraints.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: unable to satisfy constraints involving placeholders due to unknown implied bounds - --> $DIR/region-var-outlives-constraints.rs:14:9 - | -LL | forall<'a> - | ^^^^^^ - -error: aborting due to 1 previous error - From 74ef3f56b6d41398dc832cdec40948c26433ba6f Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 21 Oct 2026 15:42:14 +0200 Subject: [PATCH 06/49] move `ppcf128` to `core::num::imp` We run into the lang item being defined twice when running stdarch (so, `core_arch`) CI. Move the lang item into `core` proper. We run CI tests for the lang item in the main repo, so we should not touch it in stdarch anyway. This core definition is transparently wrapped in core_arch, so the methods and docs all remain there. --- library/core/src/num/imp/mod.rs | 3 +++ library/core/src/num/imp/ppcf128.rs | 13 +++++++++++++ library/stdarch/crates/core_arch/src/lib.rs | 8 ++++++-- library/stdarch/crates/core_arch/src/powerpc/mod.rs | 4 ++-- 4 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 library/core/src/num/imp/ppcf128.rs diff --git a/library/core/src/num/imp/mod.rs b/library/core/src/num/imp/mod.rs index 6fccfd1c238ed..e04f3cd93ba5f 100644 --- a/library/core/src/num/imp/mod.rs +++ b/library/core/src/num/imp/mod.rs @@ -11,6 +11,9 @@ pub mod diy_float; pub mod flt2dec; pub mod fmt; +// Public for core_arch. +pub mod ppcf128; + pub(crate) mod int_bits; pub(crate) mod int_log10; pub(crate) mod int_sqrt; diff --git a/library/core/src/num/imp/ppcf128.rs b/library/core/src/num/imp/ppcf128.rs new file mode 100644 index 0000000000000..04499e48cbd5d --- /dev/null +++ b/library/core/src/num/imp/ppcf128.rs @@ -0,0 +1,13 @@ +/// The IBM extended-precision (double-double) floating-point lang item. +/// +/// Here we define just the lang item, the public-facing type is defined +/// in core_arch. It transparently wraps this definition. +/// +/// The ppcf128 type should only be used on PowerPC targets, but is always defined +/// for the purpose of doc builds, specifically doc builds in the stdarch repo. +#[doc(hidden)] +#[cfg_attr(any(target_arch = "powerpc", target_arch = "powerpc64"), lang = "ppcf128")] +#[unstable(feature = "num_internals", issue = "none")] +#[allow(non_camel_case_types, dead_code)] +#[derive(Debug, Clone, Copy)] +pub struct ppcf128(u128); diff --git a/library/stdarch/crates/core_arch/src/lib.rs b/library/stdarch/crates/core_arch/src/lib.rs index 0c5daffaf05d9..c7e2d93b886a7 100644 --- a/library/stdarch/crates/core_arch/src/lib.rs +++ b/library/stdarch/crates/core_arch/src/lib.rs @@ -40,7 +40,11 @@ movrs_target_feature, clflushopt_target_feature, min_adt_const_params, - lang_items, + num_internals +)] +#![cfg_attr( + any(target_arch = "powerpc", target_arch = "powerpc64"), + feature(powerpc_ppcf128) )] #![cfg_attr( test, @@ -104,4 +108,4 @@ pub mod arch { } #[allow(unused_imports)] -use core::{array, cmp, convert, ffi, fmt, hint, intrinsics, marker, mem, ops, ptr, sync}; +use core::{array, cmp, convert, ffi, fmt, hint, intrinsics, marker, mem, num, ops, ptr, sync}; diff --git a/library/stdarch/crates/core_arch/src/powerpc/mod.rs b/library/stdarch/crates/core_arch/src/powerpc/mod.rs index e98a738e65ff4..57fcd17852157 100644 --- a/library/stdarch/crates/core_arch/src/powerpc/mod.rs +++ b/library/stdarch/crates/core_arch/src/powerpc/mod.rs @@ -4,7 +4,6 @@ pub(crate) mod macros; /// The IBM extended-precision (double-double) floating-point type. // FIXME(ppcf128) improve the docs. -#[lang = "ppcf128"] #[doc(alias = "__ibm128")] #[doc(alias = "doubledouble")] #[doc(alias = "f64f64")] @@ -12,7 +11,8 @@ pub(crate) mod macros; #[allow(non_camel_case_types)] #[doc(cfg(any(target_arch = "powerpc", target_arch = "powerpc64")))] #[derive(Clone, Copy)] -pub struct ppcf128(u128); +#[repr(transparent)] +pub struct ppcf128(crate::num::imp::ppcf128::ppcf128); #[unstable(feature = "powerpc_ppcf128", issue = "163323")] impl crate::fmt::Debug for ppcf128 { From 688479ddc1d669a965c0bb1ae2f2720483d7e396 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 24 Oct 2026 15:48:54 +0000 Subject: [PATCH 07/49] Add test for lifetime error involving field type with dyn Trait --- ...implicit-trait-object-static-obligation.rs | 101 ++++++++++++++++++ ...icit-trait-object-static-obligation.stderr | 66 ++++++++++++ 2 files changed, 167 insertions(+) create mode 100644 tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.rs create mode 100644 tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.stderr diff --git a/tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.rs b/tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.rs new file mode 100644 index 0000000000000..550c06cb739b3 --- /dev/null +++ b/tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.rs @@ -0,0 +1,101 @@ +// Detect. #78547. + +mod a { + pub struct Thing { + chars: Box>, + } + + impl Thing { + pub fn new(string: &str) -> Self { + Thing { + chars: Box::new(string.chars()), //~ ERROR: lifetime may not live long enough + } + } + } +} + +mod b { + pub struct Thing<'a> { + chars: Box + 'a>, + } + + impl Thing<'_> { + pub fn new(string: &str) -> Self { + Thing { //~ ERROR: lifetime may not live long enough + chars: Box::new(string.chars()), + } + } + } +} + +mod c { + pub struct Thing(Box>); + + impl Thing { + pub fn new(string: &str) -> Self { + Thing(Box::new(string.chars())) //~ ERROR: lifetime may not live long enough + } + } +} + +mod d { + pub enum Thing { + Foo(Box>), + } + + impl Thing { + pub fn new(string: &str) -> Self { + Thing::Foo(Box::new(string.chars())) //~ ERROR: lifetime may not live long enough + } + } +} + +mod e { + pub enum Thing { + Foo { + chars: Box>, + } + } + + impl Thing { + pub fn new(string: &str) -> Self { + Thing::Foo { + chars: Box::new(string.chars()), //~ ERROR: lifetime may not live long enough + } + } + } +} + +mod f { + pub struct Thing<'a> { + chars: Box>, + other: &'a (), + } + + impl Thing<'_> { + pub fn new(string: &str) -> Self { + Thing { + chars: Box::new(string.chars()), //~ ERROR: lifetime may not live long enough + other: &(), + } + } + } +} + +mod g { + pub struct Thing<'a> { + chars: Box>, + other: &'a (), + } + + impl<'a> Thing<'a> { + pub fn new(string: &str) -> Self { + Thing { + chars: Box::new(string.chars()), //~ ERROR: lifetime may not live long enough + other: &(), + } + } + } +} + +fn main() {} diff --git a/tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.stderr b/tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.stderr new file mode 100644 index 0000000000000..c2655e2db535d --- /dev/null +++ b/tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.stderr @@ -0,0 +1,66 @@ +error: lifetime may not live long enough + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:11:24 + | +LL | pub fn new(string: &str) -> Self { + | - let's call the lifetime of this reference `'1` +LL | Thing { +LL | chars: Box::new(string.chars()), + | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:24:13 + | +LL | pub fn new(string: &str) -> Self { + | - ---- return type is `b::Thing<'2>` + | | + | let's call the lifetime of this reference `'1` +LL | / Thing { +LL | | chars: Box::new(string.chars()), +LL | | } + | |_____________^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: lifetime may not live long enough + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:36:19 + | +LL | pub fn new(string: &str) -> Self { + | - let's call the lifetime of this reference `'1` +LL | Thing(Box::new(string.chars())) + | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:48:24 + | +LL | pub fn new(string: &str) -> Self { + | - let's call the lifetime of this reference `'1` +LL | Thing::Foo(Box::new(string.chars())) + | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:63:24 + | +LL | pub fn new(string: &str) -> Self { + | - let's call the lifetime of this reference `'1` +LL | Thing::Foo { +LL | chars: Box::new(string.chars()), + | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:78:24 + | +LL | pub fn new(string: &str) -> Self { + | - let's call the lifetime of this reference `'1` +LL | Thing { +LL | chars: Box::new(string.chars()), + | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:94:24 + | +LL | pub fn new(string: &str) -> Self { + | - let's call the lifetime of this reference `'1` +LL | Thing { +LL | chars: Box::new(string.chars()), + | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` + +error: aborting due to 7 previous errors + From 4c49bd96d89803bf4626f4b5690207084f4313d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 23 Oct 2026 00:23:55 +0000 Subject: [PATCH 08/49] Account for trait object with implicit `'static` lifetime in field type being returned ``` error: lifetime may not live long enough --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:11:24 | LL | pub fn new(string: &str) -> Self { | - let's call the lifetime of this reference `'1` LL | Thing { LL | chars: Box::new(string.chars()), | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` | note: this trait object introduces an implicit `'static` obligation --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:5:20 | LL | pub struct Thing { LL | chars: Box>, | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider introducing an explicit lifetime | LL ~ pub struct Thing<'a> { LL ~ chars: Box + 'a>, | ``` --- .../src/diagnostics/region_errors.rs | 162 +++++++++++++++++- compiler/rustc_middle/src/ty/diagnostics.rs | 2 +- ...icit-trait-object-static-obligation.stderr | 70 ++++++++ 3 files changed, 231 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 1130b89a67805..108476488a2eb 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -17,12 +17,13 @@ use rustc_middle::mir::{AnnotationSource, ConstraintCategory, ReturnConstraint}; use rustc_middle::ty::{ self, GenericArgs, Region, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitor, fold_regions, }; -use rustc_span::{Ident, Span, bug, kw}; +use rustc_span::{Ident, Span, Symbol, bug, kw}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::error_reporting::infer::nice_region_error::{ self, HirTraitObjectVisitor, NiceRegionError, TraitObjectVisitor, find_anon_type, find_param_with_region, suggest_adding_lifetime_params, }; +use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{Obligation, ObligationCtxt}; use tracing::{debug, instrument, trace}; @@ -947,7 +948,7 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { /// | is returning data with lifetime `'b` /// ``` fn report_general_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> Diag<'diag> { - let ErrorConstraintInfo { fr, outlived_fr, span, category, .. } = errci; + let ErrorConstraintInfo { fr, outlived_fr, span, category } = errci; let mir_def_name = self.infcx.tcx.def_descr(self.mir_def_id().to_def_id()); @@ -990,10 +991,167 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { self.suggest_adding_lifetime_params(&mut diag, *fr, *outlived_fr); self.suggest_move_on_borrowing_closure(&mut diag); self.suggest_deref_closure_return(&mut diag); + self.point_at_dyn_trait_in_field_def(&mut diag, *span, *outlived_fr); diag } + /// When a returned value has a field with a lifetime that isn't `'static`, and the requirement + /// comes from a `dyn Trait` with an implicit `'static` in the given field, point at the trait + /// object in the definition and suggest constraining it with a lifetime. + fn point_at_dyn_trait_in_field_def( + &self, + diag: &mut Diag<'_>, + span: Span, + outlived_fr: RegionVid, + ) { + let Some(outlived_f) = self.regioncx.to_error_region(outlived_fr) else { return }; + if outlived_f.kind() != ty::ReStatic { + return; + } + let Some(body_id) = self.infcx.tcx.hir_node_by_def_id(self.mir_def_id()).body_id() else { + return; + }; + let mut visitor = ReturnsVisitor::default(); + visitor.visit_body(&self.infcx.tcx.hir_body(body_id)); + if visitor.returns.is_empty() { + return; + } + + enum NameOrPos { + Name(Symbol), + Pos(usize), + } + + for ret in visitor.returns { + let (def_id, lit_field) = match ret.kind { + hir::ExprKind::Struct(hir::QPath::Resolved(_, path), fields, _tail) => { + let Def(_, def_id) = path.res else { continue }; + let Some(def_id) = def_id.as_local() else { continue }; + let Some(field) = fields.iter().find(|f| f.expr.span == span) else { continue }; + (def_id, NameOrPos::Name(field.ident.name)) + } + hir::ExprKind::Call(callee, args) + if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = callee.kind => + { + let Def(_, def_id) = path.res else { continue }; + let Some(def_id) = def_id.as_local() else { continue }; + let Some((pos, _)) = args.iter().enumerate().find(|(_, a)| a.span == span) + else { + continue; + }; + (def_id, NameOrPos::Pos(pos)) + } + _ => continue, + }; + let (def_spans, fields, generics) = match self.infcx.tcx.hir_node_by_def_id(def_id) { + hir::Node::Item(item) => match item.kind { + hir::ItemKind::Struct(name, generics, data) => { + let (hir::VariantData::Struct { fields, .. } + | hir::VariantData::Tuple(fields, ..)) = data + else { + continue; + }; + (vec![name.span], fields, generics) + } + _ => continue, + }, + hir::Node::Variant(variant) => { + let hir::VariantData::Struct { fields, .. } = variant.data else { continue }; + let parent = self.infcx.tcx.parent(def_id.into()); + let mut def_spans = vec![self.infcx.tcx.def_span(parent).shrink_to_lo()]; + let generics = if let DefKind::Variant = self.infcx.tcx.def_kind(parent) { + let parent = self.infcx.tcx.parent(parent); + def_spans.push(self.infcx.tcx.def_span(parent).shrink_to_lo()); + self.infcx + .tcx + .hir_get_generics(parent.expect_local()) + .expect("item with no generics?") + } else { + self.infcx + .tcx + .hir_get_generics(parent.expect_local()) + .expect("item with no generics?") + }; + (def_spans, fields, generics) + } + hir::Node::Ctor(data) => { + let hir::VariantData::Tuple(fields, ..) = data else { continue }; + let parent = self.infcx.tcx.parent(def_id.into()); + let mut def_spans = vec![self.infcx.tcx.def_span(parent).shrink_to_lo()]; + let generics = if let DefKind::Variant = self.infcx.tcx.def_kind(parent) { + let parent = self.infcx.tcx.parent(parent); + def_spans.push(self.infcx.tcx.def_span(parent).shrink_to_lo()); + self.infcx + .tcx + .hir_get_generics(parent.expect_local()) + .expect("item with no generics?") + } else { + self.infcx + .tcx + .hir_get_generics(parent.expect_local()) + .expect("item with no generics?") + }; + (def_spans, *fields, generics) + } + _ => continue, + }; + + let Some((_, f)) = fields.iter().enumerate().find(|(i, f)| match lit_field { + NameOrPos::Name(name) => f.ident.name == name, + NameOrPos::Pos(pos) => *i == pos, + }) else { + continue; + }; + + let mut v = ty::TraitObjectVisitor(vec![]); + v.visit_ty_unambig(f.ty); + let mut span: MultiSpan = v.0.iter().map(|x| x.span).collect::>().into(); + // Display the item and variant lines. + for def_span in def_spans { + span.push_span_context(def_span); + } + // Display the field's line (even if different to its type's). + span.push_span_context(f.ident.span); + // Display the type's start line (even if different to its type's). + span.push_span_context(f.ty.span.shrink_to_lo()); + let (these, s, introduce) = if v.0.len() == 1 { + ("this", "", "introduces") + } else { + ("these", "s", "introduce") + }; + diag.span_note( + span, + format!("{these} trait object{s} {introduce} an implicit `'static` obligation"), + ); + let suggestion_param_name = generics + .params + .iter() + .filter(|p| matches!(p.kind, hir::GenericParamKind::Lifetime { .. })) + .map(|p| p.name.ident().name) + .find(|i| *i != kw::UnderscoreLifetime); + if let Some(name) = suggestion_param_name { + let msg = "consider using an explicit lifetime"; + let mut sugg = vec![]; + for ty in v.0 { + sugg.push((ty.span.shrink_to_hi(), format!(" + {name}"))); + } + diag.multipart_suggestion(msg, sugg, Applicability::MachineApplicable); + } else { + let msg = "consider introducing an explicit lifetime"; + let mut sugg = vec![match generics.span_for_lifetime_suggestion() { + Some(span) => (span, "'a, ".to_string()), + None => (generics.span, "<'a>".to_string()), + }]; + for ty in v.0 { + sugg.push((ty.span.shrink_to_hi(), " + 'a".to_string())); + } + diag.multipart_suggestion(msg, sugg, Applicability::MachineApplicable); + } + return; + } + } + /// Adds a suggestion to errors where an `impl Trait` is returned. /// /// ```text diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index df1daac366c53..b3159384b951d 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -578,7 +578,7 @@ pub fn suggest_constraining_type_params<'a>( } /// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for. -pub(crate) struct TraitObjectVisitor<'tcx>(pub(crate) Vec<&'tcx hir::Ty<'tcx>>); +pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>); impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> { fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) { diff --git a/tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.stderr b/tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.stderr index c2655e2db535d..cd62df85d13db 100644 --- a/tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.stderr +++ b/tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.stderr @@ -6,6 +6,18 @@ LL | pub fn new(string: &str) -> Self { LL | Thing { LL | chars: Box::new(string.chars()), | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` + | +note: this trait object introduces an implicit `'static` obligation + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:5:20 + | +LL | pub struct Thing { +LL | chars: Box>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider introducing an explicit lifetime + | +LL ~ pub struct Thing<'a> { +LL ~ chars: Box + 'a>, + | error: lifetime may not live long enough --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:24:13 @@ -26,6 +38,16 @@ LL | pub fn new(string: &str) -> Self { | - let's call the lifetime of this reference `'1` LL | Thing(Box::new(string.chars())) | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` + | +note: this trait object introduces an implicit `'static` obligation + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:32:26 + | +LL | pub struct Thing(Box>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider introducing an explicit lifetime + | +LL | pub struct Thing<'a>(Box + 'a>); + | ++++ ++++ error: lifetime may not live long enough --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:48:24 @@ -34,6 +56,18 @@ LL | pub fn new(string: &str) -> Self { | - let's call the lifetime of this reference `'1` LL | Thing::Foo(Box::new(string.chars())) | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` + | +note: this trait object introduces an implicit `'static` obligation + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:43:17 + | +LL | pub enum Thing { +LL | Foo(Box>), + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider introducing an explicit lifetime + | +LL ~ pub enum Thing<'a> { +LL ~ Foo(Box + 'a>), + | error: lifetime may not live long enough --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:63:24 @@ -43,6 +77,20 @@ LL | pub fn new(string: &str) -> Self { LL | Thing::Foo { LL | chars: Box::new(string.chars()), | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` + | +note: this trait object introduces an implicit `'static` obligation + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:56:24 + | +LL | pub enum Thing { +LL | Foo { +LL | chars: Box>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider introducing an explicit lifetime + | +LL ~ pub enum Thing<'a> { +LL | Foo { +LL ~ chars: Box + 'a>, + | error: lifetime may not live long enough --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:78:24 @@ -52,6 +100,17 @@ LL | pub fn new(string: &str) -> Self { LL | Thing { LL | chars: Box::new(string.chars()), | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` + | +note: this trait object introduces an implicit `'static` obligation + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:71:20 + | +LL | pub struct Thing<'a> { +LL | chars: Box>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider using an explicit lifetime + | +LL | chars: Box + 'a>, + | ++++ error: lifetime may not live long enough --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:94:24 @@ -61,6 +120,17 @@ LL | pub fn new(string: &str) -> Self { LL | Thing { LL | chars: Box::new(string.chars()), | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` + | +note: this trait object introduces an implicit `'static` obligation + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:87:20 + | +LL | pub struct Thing<'a> { +LL | chars: Box>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider using an explicit lifetime + | +LL | chars: Box + 'a>, + | ++++ error: aborting due to 7 previous errors From f4f657b52f7d2291e74c5bfcc5dac1da028ec73c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 23 Oct 2026 17:05:16 +0000 Subject: [PATCH 09/49] Account for lifetime mismatch introduced in sub-expression of field and add test for multiple `dyn Trait`s ``` error: lifetime may not live long enough --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:126:25 | LL | pub fn new(string: &str) -> Self { | - let's call the lifetime of this reference `'1` LL | Thing { LL | chars: (Box::new(string.chars()), Box::new(string.chars())), | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` | note: these `dyn Trait`s introduce an implicit `'static` obligation --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:120:21 | LL | pub struct Thing { LL | chars: (Box>, Box>), | ^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider introducing an explicit lifetime | LL ~ pub struct Thing<'a> { LL ~ chars: (Box + 'a>, Box + 'a>), | ``` --- .../src/diagnostics/region_errors.rs | 9 ++- ...implicit-trait-object-static-obligation.rs | 50 ++++++++++++ ...icit-trait-object-static-obligation.stderr | 77 +++++++++++++++++-- 3 files changed, 126 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 108476488a2eb..9bb60d47ac849 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -1028,7 +1028,9 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { hir::ExprKind::Struct(hir::QPath::Resolved(_, path), fields, _tail) => { let Def(_, def_id) = path.res else { continue }; let Some(def_id) = def_id.as_local() else { continue }; - let Some(field) = fields.iter().find(|f| f.expr.span == span) else { continue }; + let Some(field) = fields.iter().find(|f| f.expr.span.contains(span)) else { + continue; + }; (def_id, NameOrPos::Name(field.ident.name)) } hir::ExprKind::Call(callee, args) @@ -1036,7 +1038,8 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { { let Def(_, def_id) = path.res else { continue }; let Some(def_id) = def_id.as_local() else { continue }; - let Some((pos, _)) = args.iter().enumerate().find(|(_, a)| a.span == span) + let Some((pos, _)) = + args.iter().enumerate().find(|(_, a)| a.span.contains(span)) else { continue; }; @@ -1122,7 +1125,7 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { }; diag.span_note( span, - format!("{these} trait object{s} {introduce} an implicit `'static` obligation"), + format!("{these} `dyn Trait`{s} {introduce} an implicit `'static` obligation"), ); let suggestion_param_name = generics .params diff --git a/tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.rs b/tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.rs index 550c06cb739b3..a524b085c0928 100644 --- a/tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.rs +++ b/tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.rs @@ -98,4 +98,54 @@ mod g { } } +mod h { + pub struct Thing { + chars: Box>, + other_chars: Box>, + } + + impl Thing { + pub fn new(string: &str) -> Self { + Thing { + chars: Box::new(string.chars()), //~ ERROR: lifetime may not live long enough + other_chars: Box::new(string.chars()), + } + } + } +} + +mod i { + // Explicit check for more than one `dyn Trait` introducing the `'static` lifetime + pub struct Thing { + chars: (Box>, Box>), + } + + impl Thing { + pub fn new(string: &str) -> Self { + Thing { + chars: (Box::new(string.chars()), Box::new(string.chars())), //~ ERROR: lifetime may not live long enough + } + } + } +} + +mod j { + pub struct Thing { + chars: Box>, + } + + impl Thing { + pub fn new(string: &str) -> Self { + if true { + return Thing { + chars: Box::new(string.chars()), //~ ERROR: lifetime may not live long enough + }; + } + Thing { + chars: Box::new(string.chars()), + } + } + } +} + fn main() {} diff --git a/tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.stderr b/tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.stderr index cd62df85d13db..d1f23d72b4382 100644 --- a/tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.stderr +++ b/tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.stderr @@ -7,7 +7,7 @@ LL | Thing { LL | chars: Box::new(string.chars()), | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` | -note: this trait object introduces an implicit `'static` obligation +note: this `dyn Trait` introduces an implicit `'static` obligation --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:5:20 | LL | pub struct Thing { @@ -39,7 +39,7 @@ LL | pub fn new(string: &str) -> Self { LL | Thing(Box::new(string.chars())) | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` | -note: this trait object introduces an implicit `'static` obligation +note: this `dyn Trait` introduces an implicit `'static` obligation --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:32:26 | LL | pub struct Thing(Box>); @@ -57,7 +57,7 @@ LL | pub fn new(string: &str) -> Self { LL | Thing::Foo(Box::new(string.chars())) | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` | -note: this trait object introduces an implicit `'static` obligation +note: this `dyn Trait` introduces an implicit `'static` obligation --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:43:17 | LL | pub enum Thing { @@ -78,7 +78,7 @@ LL | Thing::Foo { LL | chars: Box::new(string.chars()), | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` | -note: this trait object introduces an implicit `'static` obligation +note: this `dyn Trait` introduces an implicit `'static` obligation --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:56:24 | LL | pub enum Thing { @@ -101,7 +101,7 @@ LL | Thing { LL | chars: Box::new(string.chars()), | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` | -note: this trait object introduces an implicit `'static` obligation +note: this `dyn Trait` introduces an implicit `'static` obligation --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:71:20 | LL | pub struct Thing<'a> { @@ -121,7 +121,7 @@ LL | Thing { LL | chars: Box::new(string.chars()), | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` | -note: this trait object introduces an implicit `'static` obligation +note: this `dyn Trait` introduces an implicit `'static` obligation --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:87:20 | LL | pub struct Thing<'a> { @@ -132,5 +132,68 @@ help: consider using an explicit lifetime LL | chars: Box + 'a>, | ++++ -error: aborting due to 7 previous errors +error: lifetime may not live long enough + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:110:24 + | +LL | pub fn new(string: &str) -> Self { + | - let's call the lifetime of this reference `'1` +LL | Thing { +LL | chars: Box::new(string.chars()), + | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` + | +note: this `dyn Trait` introduces an implicit `'static` obligation + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:103:20 + | +LL | pub struct Thing { +LL | chars: Box>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider introducing an explicit lifetime + | +LL ~ pub struct Thing<'a> { +LL ~ chars: Box + 'a>, + | + +error: lifetime may not live long enough + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:126:25 + | +LL | pub fn new(string: &str) -> Self { + | - let's call the lifetime of this reference `'1` +LL | Thing { +LL | chars: (Box::new(string.chars()), Box::new(string.chars())), + | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` + | +note: these `dyn Trait`s introduce an implicit `'static` obligation + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:120:21 + | +LL | pub struct Thing { +LL | chars: (Box>, Box>), + | ^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider introducing an explicit lifetime + | +LL ~ pub struct Thing<'a> { +LL ~ chars: (Box + 'a>, Box + 'a>), + | + +error: lifetime may not live long enough + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:141:28 + | +LL | pub fn new(string: &str) -> Self { + | - let's call the lifetime of this reference `'1` +... +LL | chars: Box::new(string.chars()), + | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` + | +note: this `dyn Trait` introduces an implicit `'static` obligation + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:134:20 + | +LL | pub struct Thing { +LL | chars: Box>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider introducing an explicit lifetime + | +LL ~ pub struct Thing<'a> { +LL ~ chars: Box + 'a>, + | + +error: aborting due to 10 previous errors From 3574f1d11b648f78a267bb4338038f2fc4debeba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 24 Oct 2026 16:49:59 +0000 Subject: [PATCH 10/49] Point at introduction of unmet lifetime ``` error: lifetime may not live long enough --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:24:13 | LL | impl Thing<'_> { | -- lifetime `'2` introduced here LL | pub fn new(string: &str) -> Self { | - ---- return type is `b::Thing<'2>` | | | let's call the lifetime of this reference `'1` LL | / Thing { LL | | chars: Box::new(string.chars()), LL | | } | |_____________^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` ``` ``` error: lifetime may not live long enough --> $DIR/issue-52742.rs:12:9 | LL | impl Foo<'_, '_> { | -- lifetime `'2` introduced here LL | fn take_bar(&mut self, b: Bar<'_>) { | --------- - -- lifetime `'1` introduced here | | | | | has type `Bar<'1>` | has type `&mut Foo<'_, '2>` LL | self.y = b.z | ^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` ``` --- .../src/diagnostics/region_name.rs | 39 ++++++++++--- .../regionck-2.stderr | 5 +- ...atched-arg-and-hir-arg-issue-126385.stderr | 2 + tests/ui/c-variadic/variadic-ffi-4.stderr | 20 ++++--- ...t-lifetime-in-assoc-type-projection.stderr | 10 ++-- .../ex2b-push-no-existing-names.stderr | 6 +- ...oth-anon-regions-both-are-structs-2.stderr | 6 +- ...oth-anon-regions-both-are-structs-3.stderr | 6 +- ...-both-anon-regions-both-are-structs.stderr | 6 +- ...3-both-anon-regions-one-is-struct-2.stderr | 5 +- ...3-both-anon-regions-one-is-struct-3.stderr | 5 +- ...3-both-anon-regions-one-is-struct-4.stderr | 5 +- ...ex3-both-anon-regions-one-is-struct.stderr | 5 +- ...eport-when-borrow-and-drop-conflict.stderr | 12 +++- tests/ui/nll/issue-52742.stderr | 7 ++- tests/ui/nll/issue-55394.stderr | 2 + tests/ui/nll/type-alias-free-regions.stderr | 8 ++- ...ect-lifetime-default-from-box-error.stderr | 4 +- .../regions-infer-paramd-indirect.stderr | 4 +- ...implicit-trait-object-static-obligation.rs | 29 ++++++++++ ...icit-trait-object-static-obligation.stderr | 56 ++++++++++++------- ...ry_self_types_pin_lifetime_mismatch.stderr | 5 +- .../ui/static/static-reference-to-fn-2.stderr | 12 +++- 23 files changed, 186 insertions(+), 73 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 1d1c9c0baef51..99203fe0ebf18 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -61,11 +61,11 @@ pub(crate) enum RegionNameHighlight { MatchedAdtAndSegment(Span), /// The anonymous region corresponds to a region where the type annotation is completely missing /// from the code, e.g. in a closure arguments `|x| { ... }`, where `x` is a reference. - CannotMatchHirTy(Span, Symbol), + CannotMatchHirTy(Span, Symbol, Option), /// The anonymous region corresponds to a region where the type annotation is completely missing /// from the code, and *even if* we print out the full name of the type, the region name won't /// be included. This currently occurs for opaque types like `impl Future`. - Occluded(Span, Symbol), + Occluded(Span, Symbol, Option), } impl RegionName { @@ -98,8 +98,8 @@ impl RegionName { | RegionNameSource::AnonRegionFromOutput(ref highlight, _) => match *highlight { RegionNameHighlight::MatchedHirTy(span) | RegionNameHighlight::MatchedAdtAndSegment(span) - | RegionNameHighlight::CannotMatchHirTy(span, _) - | RegionNameHighlight::Occluded(span, _) => Some(span), + | RegionNameHighlight::CannotMatchHirTy(span, _, _) + | RegionNameHighlight::Occluded(span, _, _) => Some(span), }, } } @@ -120,8 +120,12 @@ impl RegionName { RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::CannotMatchHirTy( span, type_name, + lt_span, )) => { diag.span_label(*span, format!("has type `{type_name}`")); + if let Some(span) = lt_span { + diag.span_label(*span, format!("lifetime `{self}` introduced here")); + } } RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::MatchedHirTy(span)) | RegionNameSource::AnonRegionFromOutput(RegionNameHighlight::MatchedHirTy(span), _) @@ -143,14 +147,18 @@ impl RegionName { RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::Occluded( span, type_name, + lt_span, )) => { diag.span_label( *span, format!("lifetime `{self}` appears in the type `{type_name}`"), ); + if let Some(span) = lt_span { + diag.span_label(*span, format!("lifetime `{self}` introduced here")); + } } RegionNameSource::AnonRegionFromOutput( - RegionNameHighlight::Occluded(span, type_name), + RegionNameHighlight::Occluded(span, type_name, lt_span), mir_description, ) => { diag.span_label( @@ -159,6 +167,9 @@ impl RegionName { "return type{mir_description} `{type_name}` contains a lifetime `{self}`" ), ); + if let Some(span) = lt_span { + diag.span_label(*span, format!("lifetime `{self}` introduced here")); + } } RegionNameSource::AnonRegionFromUpvar(span, upvar_name) => { diag.span_label( @@ -167,10 +178,13 @@ impl RegionName { ); } RegionNameSource::AnonRegionFromOutput( - RegionNameHighlight::CannotMatchHirTy(span, type_name), + RegionNameHighlight::CannotMatchHirTy(span, type_name, lt_span), mir_description, ) => { diag.span_label(*span, format!("return type{mir_description} is `{type_name}`")); + if let Some(span) = lt_span { + diag.span_label(*span, format!("lifetime `{self}` introduced here")); + } } RegionNameSource::AnonRegionFromYieldTy(span, type_name) => { diag.span_label(*span, format!("yield type is {type_name}")); @@ -576,11 +590,18 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { "highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}", type_name, needle_fr ); + let lt_span = if let Some(needle) = self.regioncx.to_error_region(needle_fr) + && let Some(def_id) = needle.opt_param_def_id(self.infcx.tcx, self.mir_def_id().into()) + { + Some(self.infcx.tcx.def_span(def_id)) + } else { + None + }; if type_name.contains(&format!("'{counter}")) { // Only add a label if we can confirm that a region was labelled. - RegionNameHighlight::CannotMatchHirTy(span, Symbol::intern(&type_name)) + RegionNameHighlight::CannotMatchHirTy(span, Symbol::intern(&type_name), lt_span) } else { - RegionNameHighlight::Occluded(span, Symbol::intern(&type_name)) + RegionNameHighlight::Occluded(span, Symbol::intern(&type_name), lt_span) } } @@ -1111,7 +1132,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { Some(RegionName { name: region_name, source: RegionNameSource::AnonRegionFromArgument( - RegionNameHighlight::CannotMatchHirTy(arg_span, arg_name?), + RegionNameHighlight::CannotMatchHirTy(arg_span, arg_name?, None), ), }) } else { diff --git a/tests/ui/associated-inherent-types/regionck-2.stderr b/tests/ui/associated-inherent-types/regionck-2.stderr index 82f5c6a72c008..491bebce26d02 100644 --- a/tests/ui/associated-inherent-types/regionck-2.stderr +++ b/tests/ui/associated-inherent-types/regionck-2.stderr @@ -17,8 +17,9 @@ error: lifetime may not live long enough --> $DIR/regionck-2.rs:12:1 | LL | fn test(_: Lexer::Cursor) {} - | ^^^^^^^^-^^^^^^^^^^^^^^^^ - | | | + | ^^^^^^^^-^^-----^^^^^^^^^ + | | | | + | | | lifetime `'1` introduced here | | has type `Lexer<'1>::Cursor` | requires that `'1` must outlive `'static` diff --git a/tests/ui/borrowck/unmatched-arg-and-hir-arg-issue-126385.stderr b/tests/ui/borrowck/unmatched-arg-and-hir-arg-issue-126385.stderr index dc19178732ba2..e1468963069d8 100644 --- a/tests/ui/borrowck/unmatched-arg-and-hir-arg-issue-126385.stderr +++ b/tests/ui/borrowck/unmatched-arg-and-hir-arg-issue-126385.stderr @@ -23,6 +23,8 @@ LL + pub fn f(field: &[u32]) -> MyStruct { error: lifetime may not live long enough --> $DIR/unmatched-arg-and-hir-arg-issue-126385.rs:10:9 | +LL | impl MyStruct<'_> { + | -- lifetime `'2` introduced here LL | pub fn f(field: &[u32]) -> Self { | - --------- return type is `MyStruct<'2>` | | diff --git a/tests/ui/c-variadic/variadic-ffi-4.stderr b/tests/ui/c-variadic/variadic-ffi-4.stderr index a92a5fd4bf61d..64dff4320b93f 100644 --- a/tests/ui/c-variadic/variadic-ffi-4.stderr +++ b/tests/ui/c-variadic/variadic-ffi-4.stderr @@ -20,8 +20,9 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:16:5 | LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaList, mut ap1: ...) { - | ------- ------- has type `VaList<'1>` - | | + | ------- ------ ------- has type `VaList<'1>` + | | | + | | lifetime `'2` introduced here | has type `&mut VaList<'2>` LL | *ap0 = ap1; | ^^^^ assignment requires that `'1` must outlive `'2` @@ -30,8 +31,9 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:21:5 | LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) { - | ------- ------- has type `VaList<'2>` - | | + | ------- ------ ------- has type `VaList<'2>` + | | | + | | lifetime `'1` introduced here | has type `&mut VaList<'1>` LL | ap0 = &mut ap1; | ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` @@ -44,8 +46,9 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:21:5 | LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) { - | ------- ------- has type `VaList<'2>` - | | + | ------- ------ ------- has type `VaList<'2>` + | | | + | | lifetime `'1` introduced here | has type `&mut VaList<'1>` LL | ap0 = &mut ap1; | ^^^^^^^^^^^^^^ assignment requires that `'2` must outlive `'1` @@ -74,8 +77,9 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:28:5 | LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaList, mut ap1: ...) { - | ------- ------- has type `VaList<'1>` - | | + | ------- ------ ------- has type `VaList<'1>` + | | | + | | lifetime `'2` introduced here | has type `&mut VaList<'2>` LL | *ap0 = ap1.clone(); | ^^^^ assignment requires that `'1` must outlive `'2` diff --git a/tests/ui/lifetimes/implicit-lifetime-in-assoc-type-projection.stderr b/tests/ui/lifetimes/implicit-lifetime-in-assoc-type-projection.stderr index 7c06ffd7c1e48..3c912864dfd20 100644 --- a/tests/ui/lifetimes/implicit-lifetime-in-assoc-type-projection.stderr +++ b/tests/ui/lifetimes/implicit-lifetime-in-assoc-type-projection.stderr @@ -29,8 +29,9 @@ LL | impl<'a> Publisher<'a> for MyStruct<'a> { | -- lifetime `'a` defined here LL | type Output = u64; LL | fn subscribe(&mut self, t : Box::Output> + 'a>) { - | ^^^^^^^^^^^^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | | + | ^^^^^^^^^^^^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------^^^^^^^^^^^^^^^^^ + | | | | + | | | lifetime `'1` introduced here | | has type `Box as Publisher<'1>>::Output>>` | requires that `'a` must outlive `'1` @@ -41,8 +42,9 @@ LL | impl<'a> Publisher<'a> for MyStruct<'a> { | -- lifetime `'a` defined here LL | type Output = u64; LL | fn subscribe(&mut self, t : Box::Output> + 'a>) { - | ^^^^^^^^^^^^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | | + | ^^^^^^^^^^^^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------^^^^^^^^^^^^^^^^^ + | | | | + | | | lifetime `'1` introduced here | | has type `Box as Publisher<'1>>::Output>>` | requires that `'1` must outlive `'a` diff --git a/tests/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.stderr b/tests/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.stderr index a187cb755dd56..a28f884b6389d 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.stderr @@ -2,8 +2,10 @@ error: lifetime may not live long enough --> $DIR/ex2b-push-no-existing-names.rs:6:5 | LL | fn foo(x: &mut Vec>, y: Ref) { - | - - has type `Ref<'1, i32>` - | | + | - - - - lifetime `'1` introduced here + | | | | + | | | has type `Ref<'1, i32>` + | | lifetime `'2` introduced here | has type `&mut Vec>` LL | x.push(y); | ^^^^^^^^^ argument requires that `'1` must outlive `'2` diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.stderr index f8ad923cce8a5..d25414bb5d797 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.stderr @@ -2,8 +2,10 @@ error: lifetime may not live long enough --> $DIR/ex3-both-anon-regions-both-are-structs-2.rs:7:5 | LL | fn foo(mut x: Ref, y: Ref) { - | ----- - has type `Ref<'_, '1>` - | | + | ----- --- - --- lifetime `'1` introduced here + | | | | + | | | has type `Ref<'_, '1>` + | | lifetime `'2` introduced here | has type `Ref<'_, '2>` LL | x.b = y.b; | ^^^^^^^^^ assignment requires that `'1` must outlive `'2` diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.stderr index a1149779d2c6d..d6da2c15f88cb 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.stderr @@ -2,8 +2,10 @@ error: lifetime may not live long enough --> $DIR/ex3-both-anon-regions-both-are-structs-3.rs:7:5 | LL | fn foo(mut x: Ref) { - | ----- - | | + | ----- --- + | | | + | | lifetime `'1` introduced here + | | lifetime `'2` introduced here | has type `Ref<'_, '1>` | has type `Ref<'2, '_>` LL | x.a = x.b; diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr index 264673ff3e82c..de47669b144b8 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr @@ -2,8 +2,10 @@ error: lifetime may not live long enough --> $DIR/ex3-both-anon-regions-both-are-structs.rs:6:5 | LL | fn foo(mut x: Vec, y: Ref) { - | ----- - has type `Ref<'1>` - | | + | ----- --- - --- lifetime `'1` introduced here + | | | | + | | | has type `Ref<'1>` + | | lifetime `'2` introduced here | has type `Vec>` LL | x.push(y); | ^^^^^^^^^ argument requires that `'1` must outlive `'2` diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr index 29bf7e62985a3..d33ed7e7c0b0e 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr @@ -2,8 +2,9 @@ error: lifetime may not live long enough --> $DIR/ex3-both-anon-regions-one-is-struct-2.rs:4:5 | LL | fn foo(mut x: Ref, y: &u32) { - | ----- - let's call the lifetime of this reference `'2` - | | + | ----- --- - let's call the lifetime of this reference `'2` + | | | + | | lifetime `'1` introduced here | has type `Ref<'_, '1>` LL | y = x.b; | ^^^^^^^ assignment requires that `'1` must outlive `'2` diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.stderr index d9c7530b64c57..ef9e5eedd27bd 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.stderr @@ -2,8 +2,9 @@ error: lifetime may not live long enough --> $DIR/ex3-both-anon-regions-one-is-struct-3.rs:4:5 | LL | fn foo(mut y: Ref, x: &u32) { - | ----- - let's call the lifetime of this reference `'1` - | | + | ----- --- - let's call the lifetime of this reference `'1` + | | | + | | lifetime `'2` introduced here | has type `Ref<'_, '2>` LL | y.b = x; | ^^^^^^^ assignment requires that `'1` must outlive `'2` diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr index 02c0658ff1730..279450766c636 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr @@ -2,8 +2,9 @@ error: lifetime may not live long enough --> $DIR/ex3-both-anon-regions-one-is-struct-4.rs:10:5 | LL | fn bar(foo: &mut Foo) { - | --- - let's call the lifetime of this reference `'1` - | | + | --- - --- lifetime `'2` introduced here + | | | + | | let's call the lifetime of this reference `'1` | has type `&mut Foo<'2>` LL | foo.modify(); | ^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct.stderr index ef28ddeacc5e2..65605846d79f8 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct.stderr @@ -2,8 +2,9 @@ error: lifetime may not live long enough --> $DIR/ex3-both-anon-regions-one-is-struct.rs:7:5 | LL | fn foo(mut x: Ref, y: &u32) { - | ----- - let's call the lifetime of this reference `'1` - | | + | ----- --- - let's call the lifetime of this reference `'1` + | | | + | | lifetime `'2` introduced here | has type `Ref<'_, '2>` LL | x.b = y; | ^^^^^^^ assignment requires that `'1` must outlive `'2` diff --git a/tests/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr b/tests/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr index 7f9cbc3c30a92..3f1bb892393e1 100644 --- a/tests/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr +++ b/tests/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr @@ -2,7 +2,9 @@ error[E0713]: borrow may still be in use when destructor runs --> $DIR/issue-52059-report-when-borrow-and-drop-conflict.rs:11:5 | LL | fn finish_1(s: S) -> &mut String { - | - has type `S<'1>` + | - - lifetime `'1` introduced here + | | + | has type `S<'1>` LL | s.url | ^^^^^ returning this value requires that `*s.url` is borrowed for `'1` LL | } @@ -12,7 +14,9 @@ error[E0713]: borrow may still be in use when destructor runs --> $DIR/issue-52059-report-when-borrow-and-drop-conflict.rs:16:13 | LL | fn finish_2(s: S) -> &mut String { - | - has type `S<'1>` + | - - lifetime `'1` introduced here + | | + | has type `S<'1>` LL | let p = &mut *s.url; p | ^^^^^^^^^^^ - returning this value requires that `*s.url` is borrowed for `'1` LL | } @@ -22,7 +26,9 @@ error[E0713]: borrow may still be in use when destructor runs --> $DIR/issue-52059-report-when-borrow-and-drop-conflict.rs:21:21 | LL | fn finish_3(s: S) -> &mut String { - | - has type `S<'1>` + | - - lifetime `'1` introduced here + | | + | has type `S<'1>` LL | let p: &mut _ = s.url; p | ^^^^^ - returning this value requires that `*s.url` is borrowed for `'1` LL | } diff --git a/tests/ui/nll/issue-52742.stderr b/tests/ui/nll/issue-52742.stderr index 8c09e542c05cc..3ddfddc2ffc98 100644 --- a/tests/ui/nll/issue-52742.stderr +++ b/tests/ui/nll/issue-52742.stderr @@ -1,9 +1,12 @@ error: lifetime may not live long enough --> $DIR/issue-52742.rs:12:9 | +LL | impl Foo<'_, '_> { + | -- lifetime `'2` introduced here LL | fn take_bar(&mut self, b: Bar<'_>) { - | --------- - has type `Bar<'1>` - | | + | --------- - -- lifetime `'1` introduced here + | | | + | | has type `Bar<'1>` | has type `&mut Foo<'_, '2>` LL | self.y = b.z | ^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` diff --git a/tests/ui/nll/issue-55394.stderr b/tests/ui/nll/issue-55394.stderr index 03382b668aa53..36fef319047b5 100644 --- a/tests/ui/nll/issue-55394.stderr +++ b/tests/ui/nll/issue-55394.stderr @@ -1,6 +1,8 @@ error: lifetime may not live long enough --> $DIR/issue-55394.rs:9:9 | +LL | impl Foo<'_> { + | -- lifetime `'2` introduced here LL | fn new(bar: &mut Bar) -> Self { | - ---- return type is `Foo<'2>` | | diff --git a/tests/ui/nll/type-alias-free-regions.stderr b/tests/ui/nll/type-alias-free-regions.stderr index 45fd5a2f1d657..d0a6454a3dac7 100644 --- a/tests/ui/nll/type-alias-free-regions.stderr +++ b/tests/ui/nll/type-alias-free-regions.stderr @@ -4,7 +4,9 @@ error: lifetime may not live long enough LL | impl<'a> FromBox<'a> for C<'a> { | -- lifetime `'a` defined here LL | fn from_box(b: Box) -> Self { - | - has type `Box>` + | - - lifetime `'1` introduced here + | | + | has type `Box>` LL | C { f: b } | ^^^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1` @@ -14,7 +16,9 @@ error: lifetime may not live long enough LL | impl<'a> FromTuple<'a> for C<'a> { | -- lifetime `'a` defined here LL | fn from_tuple(b: (B,)) -> Self { - | - has type `(Box<&'1 isize>,)` + | - - lifetime `'1` introduced here + | | + | has type `(Box<&'1 isize>,)` LL | C { f: Box::new(b.0) } | ^^^^^^^^^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1` diff --git a/tests/ui/object-lifetime/object-lifetime-default-from-box-error.stderr b/tests/ui/object-lifetime/object-lifetime-default-from-box-error.stderr index 05eb611081a41..5e9166bb9c1dc 100644 --- a/tests/ui/object-lifetime/object-lifetime-default-from-box-error.stderr +++ b/tests/ui/object-lifetime/object-lifetime-default-from-box-error.stderr @@ -2,7 +2,9 @@ error: lifetime may not live long enough --> $DIR/object-lifetime-default-from-box-error.rs:18:5 | LL | fn load(ss: &mut SomeStruct) -> Box { - | -- has type `&mut SomeStruct<'1>` + | -- ---------- lifetime `'1` introduced here + | | + | has type `&mut SomeStruct<'1>` ... LL | ss.r | ^^^^ returning this value requires that `'1` must outlive `'static` diff --git a/tests/ui/regions/regions-infer-paramd-indirect.stderr b/tests/ui/regions/regions-infer-paramd-indirect.stderr index 4a1cd111936e1..639858b553239 100644 --- a/tests/ui/regions/regions-infer-paramd-indirect.stderr +++ b/tests/ui/regions/regions-infer-paramd-indirect.stderr @@ -5,7 +5,9 @@ LL | impl<'a> SetF<'a> for C<'a> { | -- lifetime `'a` defined here ... LL | fn set_f_bad(&mut self, b: Box) { - | - has type `Box>` + | - - lifetime `'1` introduced here + | | + | has type `Box>` LL | self.f = b; | ^^^^^^ assignment requires that `'1` must outlive `'a` diff --git a/tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.rs b/tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.rs index a524b085c0928..b6e9eeaa3e0b1 100644 --- a/tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.rs +++ b/tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.rs @@ -1,6 +1,9 @@ // Detect. #78547. mod a { + // Originally reported case, where `dyn Trait` had implicit `'static` requirement. + // We ensure we point at `dyn Iterator` and we should be suggesting to add a named + // lifetime to `Thing`. pub struct Thing { chars: Box>, } @@ -15,6 +18,9 @@ mod a { } mod b { + // Similar to above, but the `dyn Trait` has an explicit named bound on the type, but an + // implicit one in the `impl`. + // We ensure we point at `impl Thing<'_>` as introducing the unmet lifetime in `-> Self`. pub struct Thing<'a> { chars: Box + 'a>, } @@ -29,6 +35,7 @@ mod b { } mod c { + // Ensure that we are handling tuple-structs. pub struct Thing(Box>); impl Thing { @@ -39,6 +46,7 @@ mod c { } mod d { + // Ensure that we are handling tuple enum variants. pub enum Thing { Foo(Box>), } @@ -51,6 +59,7 @@ mod d { } mod e { + // Ensure that we are handling struct enum variants. pub enum Thing { Foo { chars: Box>, @@ -99,6 +108,8 @@ mod g { } mod h { + // Multiple lifetime failures on the same expression. We currently only talk about the first + // field's lifetime failure, and point at the first field in the definition. pub struct Thing { chars: Box>, other_chars: Box>, @@ -130,6 +141,7 @@ mod i { } mod j { + // Multiple returned values with the same problem. We currently ignore the second incident. pub struct Thing { chars: Box>, } @@ -148,4 +160,21 @@ mod j { } } +mod k { + // Similar to `b`, but with a named lifetime in the `impl`. We flat out tell people to use the + // exisitng named lifetime in `fn new(&str)`. + pub struct Thing<'a> { + chars: Box + 'a>, + } + + impl<'a> Thing<'a> { + pub fn new(string: &str) -> Self { + Thing { //~ ERROR: explicit lifetime required in the type of `string` + chars: Box::new(string.chars()), + } + } + } +} + + fn main() {} diff --git a/tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.stderr b/tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.stderr index d1f23d72b4382..666eb8334959f 100644 --- a/tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.stderr +++ b/tests/ui/regions/return-expr-with-implicit-trait-object-static-obligation.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:11:24 + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:14:24 | LL | pub fn new(string: &str) -> Self { | - let's call the lifetime of this reference `'1` @@ -8,7 +8,7 @@ LL | chars: Box::new(string.chars()), | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` | note: this `dyn Trait` introduces an implicit `'static` obligation - --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:5:20 + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:8:20 | LL | pub struct Thing { LL | chars: Box>, @@ -20,8 +20,10 @@ LL ~ chars: Box + 'a>, | error: lifetime may not live long enough - --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:24:13 + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:30:13 | +LL | impl Thing<'_> { + | -- lifetime `'2` introduced here LL | pub fn new(string: &str) -> Self { | - ---- return type is `b::Thing<'2>` | | @@ -32,7 +34,7 @@ LL | | } | |_____________^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough - --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:36:19 + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:43:19 | LL | pub fn new(string: &str) -> Self { | - let's call the lifetime of this reference `'1` @@ -40,7 +42,7 @@ LL | Thing(Box::new(string.chars())) | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` | note: this `dyn Trait` introduces an implicit `'static` obligation - --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:32:26 + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:39:26 | LL | pub struct Thing(Box>); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -50,7 +52,7 @@ LL | pub struct Thing<'a>(Box + 'a>); | ++++ ++++ error: lifetime may not live long enough - --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:48:24 + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:56:24 | LL | pub fn new(string: &str) -> Self { | - let's call the lifetime of this reference `'1` @@ -58,7 +60,7 @@ LL | Thing::Foo(Box::new(string.chars())) | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` | note: this `dyn Trait` introduces an implicit `'static` obligation - --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:43:17 + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:51:17 | LL | pub enum Thing { LL | Foo(Box>), @@ -70,7 +72,7 @@ LL ~ Foo(Box + 'a>), | error: lifetime may not live long enough - --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:63:24 + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:72:24 | LL | pub fn new(string: &str) -> Self { | - let's call the lifetime of this reference `'1` @@ -79,7 +81,7 @@ LL | chars: Box::new(string.chars()), | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` | note: this `dyn Trait` introduces an implicit `'static` obligation - --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:56:24 + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:65:24 | LL | pub enum Thing { LL | Foo { @@ -93,7 +95,7 @@ LL ~ chars: Box + 'a>, | error: lifetime may not live long enough - --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:78:24 + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:87:24 | LL | pub fn new(string: &str) -> Self { | - let's call the lifetime of this reference `'1` @@ -102,7 +104,7 @@ LL | chars: Box::new(string.chars()), | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` | note: this `dyn Trait` introduces an implicit `'static` obligation - --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:71:20 + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:80:20 | LL | pub struct Thing<'a> { LL | chars: Box>, @@ -113,7 +115,7 @@ LL | chars: Box + 'a>, | ++++ error: lifetime may not live long enough - --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:94:24 + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:103:24 | LL | pub fn new(string: &str) -> Self { | - let's call the lifetime of this reference `'1` @@ -122,7 +124,7 @@ LL | chars: Box::new(string.chars()), | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` | note: this `dyn Trait` introduces an implicit `'static` obligation - --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:87:20 + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:96:20 | LL | pub struct Thing<'a> { LL | chars: Box>, @@ -133,7 +135,7 @@ LL | chars: Box + 'a>, | ++++ error: lifetime may not live long enough - --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:110:24 + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:121:24 | LL | pub fn new(string: &str) -> Self { | - let's call the lifetime of this reference `'1` @@ -142,7 +144,7 @@ LL | chars: Box::new(string.chars()), | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` | note: this `dyn Trait` introduces an implicit `'static` obligation - --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:103:20 + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:114:20 | LL | pub struct Thing { LL | chars: Box>, @@ -154,7 +156,7 @@ LL ~ chars: Box + 'a>, | error: lifetime may not live long enough - --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:126:25 + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:137:25 | LL | pub fn new(string: &str) -> Self { | - let's call the lifetime of this reference `'1` @@ -163,7 +165,7 @@ LL | chars: (Box::new(string.chars()), Box::new(string.chars())) | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` | note: these `dyn Trait`s introduce an implicit `'static` obligation - --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:120:21 + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:131:21 | LL | pub struct Thing { LL | chars: (Box>, Box>), @@ -175,7 +177,7 @@ LL ~ chars: (Box + 'a>, Box $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:141:28 + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:153:28 | LL | pub fn new(string: &str) -> Self { | - let's call the lifetime of this reference `'1` @@ -184,7 +186,7 @@ LL | chars: Box::new(string.chars()), | ^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'1` must outlive `'static` | note: this `dyn Trait` introduces an implicit `'static` obligation - --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:134:20 + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:146:20 | LL | pub struct Thing { LL | chars: Box>, @@ -195,5 +197,19 @@ LL ~ pub struct Thing<'a> { LL ~ chars: Box + 'a>, | -error: aborting due to 10 previous errors +error[E0621]: explicit lifetime required in the type of `string` + --> $DIR/return-expr-with-implicit-trait-object-static-obligation.rs:172:13 + | +LL | / Thing { +LL | | chars: Box::new(string.chars()), +LL | | } + | |_____________^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `string` + | +LL | pub fn new(string: &'a str) -> Self { + | ++ + +error: aborting due to 11 previous errors +For more information about this error, try `rustc --explain E0621`. diff --git a/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr b/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr index 57527dd31df35..b76ffa0606c2a 100644 --- a/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr +++ b/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr @@ -32,8 +32,9 @@ error: lifetime may not live long enough --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:21:9 | LL | fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { - | -- ---- has type `Pin<&'1 Foo>` - | | + | -- ---- - lifetime `'1` introduced here + | | | + | | has type `Pin<&'1 Foo>` | lifetime `'a` defined here LL | arg | ^^^ method was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a` diff --git a/tests/ui/static/static-reference-to-fn-2.stderr b/tests/ui/static/static-reference-to-fn-2.stderr index 133d8ec2e1e51..ae80c8a7bd136 100644 --- a/tests/ui/static/static-reference-to-fn-2.stderr +++ b/tests/ui/static/static-reference-to-fn-2.stderr @@ -2,7 +2,9 @@ error[E0716]: temporary value dropped while borrowed --> $DIR/static-reference-to-fn-2.rs:18:22 | LL | fn state1(self_: &mut StateMachineIter) -> Option<&'static str> { - | ----- has type `&mut StateMachineIter<'1>` + | ----- ---------------- lifetime `'1` introduced here + | | + | has type `&mut StateMachineIter<'1>` LL | self_.statefn = &id(state2 as StateMachineFunc); | -----------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement | | | @@ -13,7 +15,9 @@ error[E0716]: temporary value dropped while borrowed --> $DIR/static-reference-to-fn-2.rs:24:22 | LL | fn state2(self_: &mut StateMachineIter) -> Option<(&'static str)> { - | ----- has type `&mut StateMachineIter<'1>` + | ----- ---------------- lifetime `'1` introduced here + | | + | has type `&mut StateMachineIter<'1>` LL | self_.statefn = &id(state3 as StateMachineFunc); | -----------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement | | | @@ -24,7 +28,9 @@ error[E0716]: temporary value dropped while borrowed --> $DIR/static-reference-to-fn-2.rs:30:22 | LL | fn state3(self_: &mut StateMachineIter) -> Option<(&'static str)> { - | ----- has type `&mut StateMachineIter<'1>` + | ----- ---------------- lifetime `'1` introduced here + | | + | has type `&mut StateMachineIter<'1>` LL | self_.statefn = &id(finished as StateMachineFunc); | -----------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement | | | From 23148c1ca2b89992b62ab4f5b3a14cbc8bd7d94a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 21 Oct 2026 17:12:05 +0000 Subject: [PATCH 11/49] Point at `impl` through which associated function is provided When encountering a type mismatch in arguments of a call expr of an associated function, point not only at the `trait` but also the `impl`. ``` error[E0308]: mismatched types --> tests/ui/fn_traits/point-at-impl-in-call-argument-type-error.rs:9:21 | 9 | let b = B::from(a); //~ ERROR: mismatched types | ------- ^ expected `B`, found `A` | | | arguments to this function are incorrect | note: associated function defined here --> library/core/src/convert/mod.rs:594:8 | 588 | pub const trait From: Sized { ... 594 | fn from(value: T) -> Self; | ^^^^ note: associated function provided through this `impl` --> library/core/src/convert/mod.rs:787:1 | 787 | const impl From for T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ``` --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 35 ++++++++++++++++--- .../ui/delegation/delegation-first-arg.stderr | 5 +++ tests/ui/delegation/explicit-paths.stderr | 5 +++ .../inherent-impls-recursive-cycle.stderr | 5 +++ .../self-coercion-static-free.stderr | 30 ++++++++++++++++ .../self-mapping-arguments-errors.stderr | 5 +++ .../ui/delegation/self-mapping-output.stderr | 20 +++++++++++ .../unused-target-expr-in-glob-or-list.stderr | 10 ++++++ ...int-at-impl-in-call-argument-type-error.rs | 12 +++++++ ...at-impl-in-call-argument-type-error.stderr | 16 +++++++++ tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr | 12 +++++++ 11 files changed, 151 insertions(+), 4 deletions(-) create mode 100644 tests/ui/fn_traits/point-at-impl-in-call-argument-type-error.rs create mode 100644 tests/ui/fn_traits/point-at-impl-in-call-argument-type-error.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index a9809d552a2be..5483e807d4318 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -41,9 +41,8 @@ use crate::diagnostics::{ExprParenthesesNeeded, SuggestPtrNullMut, SuggestRawMut use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx}; use crate::gather_locals::Declaration; use crate::inline_asm::InlineAsmCtxt; -use crate::method::probe::IsSuggestion; -use crate::method::probe::Mode::MethodCall; use crate::method::probe::ProbeScope::TraitsInScope; +use crate::method::probe::{IsSuggestion, Mode}; use crate::{ BreakableCtxt, Diverges, Expectation, FnCtxt, GatherLocalsVisitor, LoweredTy, Needs, TupleArgumentsFlag, diagnostics, struct_span_code_err, @@ -1914,9 +1913,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let def_kind = self.tcx.def_kind(def_id); if let DefKind::AssocFn = def_kind { - spans.push_span_context(self.tcx.def_span(self.tcx.parent(def_id)).shrink_to_lo()); + let parent_def_id = self.tcx.parent(def_id); + spans.push_span_context(self.tcx.def_span(parent_def_id).shrink_to_lo()); } err.span_note(spans, format!("{} defined here", self.tcx.def_descr(def_id))); + if let DefKind::AssocFn = def_kind + && !is_method + && let parent_def_id = self.tcx.parent(def_id) + && let Some(callee_ty) = callee_ty + && let ty::FnDef(_def_id, args) = callee_ty.kind() + && let DefKind::Trait = self.tcx.def_kind(parent_def_id) + && let Ok(Some(traits::ImplSource::UserDefined(x))) = self.probe(|_| { + let trait_ref = ty::TraitRef::new( + self.tcx, + parent_def_id, + args.skip_binder() + .truncate_to(self.tcx, self.tcx.generics_of(parent_def_id)), + ); + let obligation = traits::Obligation::new( + self.tcx, + traits::ObligationCause::dummy(), + self.param_env, + trait_ref, + ); + SelectionContext::new(self).select(&obligation) + }) + { + err.span_note( + self.tcx.def_span(x.impl_def_id), + format!("{} provided through this `impl`", self.tcx.def_descr(def_id)), + ); + } if let DefKind::Fn | DefKind::AssocFn = def_kind && let ty::Param(_) = self.tcx.fn_sig(def_id).instantiate_identity().skip_binder().output().kind() @@ -3430,7 +3457,7 @@ impl<'a, 'tcx> ArgsCtxt<'a, 'tcx> { if let Some(callee_ty) = self.call_ctxt.callee_ty && let Ok(Some(assoc)) = self.call_ctxt.fn_ctxt.probe_op( call_name.span, - MethodCall, + Mode::MethodCall, Some(call_name), None, IsSuggestion(true), diff --git a/tests/ui/delegation/delegation-first-arg.stderr b/tests/ui/delegation/delegation-first-arg.stderr index 7fd37e3f8f92e..f59f7ea97aca2 100644 --- a/tests/ui/delegation/delegation-first-arg.stderr +++ b/tests/ui/delegation/delegation-first-arg.stderr @@ -74,6 +74,11 @@ LL | trait Trait: Sized { ... LL | fn static_empty() {} | ^^^^^^^^^^^^ +note: associated function provided through this `impl` + --> $DIR/delegation-first-arg.rs:13:1 + | +LL | impl Trait for S {} + | ^^^^^^^^^^^^^^^^ help: remove the extra argument | LL - reuse ::static_empty { self.0 } diff --git a/tests/ui/delegation/explicit-paths.stderr b/tests/ui/delegation/explicit-paths.stderr index 1995b7a639f1f..2d2d42b79ed43 100644 --- a/tests/ui/delegation/explicit-paths.stderr +++ b/tests/ui/delegation/explicit-paths.stderr @@ -52,6 +52,11 @@ note: method defined here LL | trait Trait { LL | fn foo1(&self, x: i32) -> i32 { x } | ^^^^ ----- +note: method provided through this `impl` + --> $DIR/explicit-paths.rs:10:1 + | +LL | impl Trait for F {} + | ^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `S2: Trait` is not satisfied --> $DIR/explicit-paths.rs:73:16 diff --git a/tests/ui/delegation/inherent-impls-recursive-cycle.stderr b/tests/ui/delegation/inherent-impls-recursive-cycle.stderr index 943f70f55fc6e..bae8ba7f616cb 100644 --- a/tests/ui/delegation/inherent-impls-recursive-cycle.stderr +++ b/tests/ui/delegation/inherent-impls-recursive-cycle.stderr @@ -124,6 +124,11 @@ note: associated function defined here LL | trait Trait1 { LL | reuse trait_foo_reused as foo; | ^^^ +note: associated function provided through this `impl` + --> $DIR/inherent-impls-recursive-cycle.rs:33:1 + | +LL | impl Trait1 for S3 { + | ^^^^^^^^^^^^^^^^^^ help: remove the extra argument | LL - reuse ::foo { S3 } diff --git a/tests/ui/delegation/self-coercion-static-free.stderr b/tests/ui/delegation/self-coercion-static-free.stderr index 35d69da3a3f6d..66543acd080c6 100644 --- a/tests/ui/delegation/self-coercion-static-free.stderr +++ b/tests/ui/delegation/self-coercion-static-free.stderr @@ -26,6 +26,11 @@ LL | pub trait Trait: Sized { ... LL | fn static_value(_: Self) -> i32 { 1 } | ^^^^^^^^^^^^ ------- +note: associated function provided through this `impl` + --> $DIR/self-coercion-static-free.rs:17:1 + | +LL | impl Trait for F {} + | ^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/self-coercion-static-free.rs:22:40 @@ -45,6 +50,11 @@ LL | pub trait Trait: Sized { ... LL | fn static_mut_ref(_: &mut Self) -> i32 { 2 } | ^^^^^^^^^^^^^^ ------------ +note: associated function provided through this `impl` + --> $DIR/self-coercion-static-free.rs:17:1 + | +LL | impl Trait for F {} + | ^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/self-coercion-static-free.rs:22:56 @@ -64,6 +74,11 @@ LL | pub trait Trait: Sized { ... LL | fn static_ref(_: &Self) -> i32 { 3 } | ^^^^^^^^^^ -------- +note: associated function provided through this `impl` + --> $DIR/self-coercion-static-free.rs:17:1 + | +LL | impl Trait for F {} + | ^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/self-coercion-static-free.rs:35:26 @@ -81,6 +96,11 @@ LL | pub trait Trait: Sized { ... LL | fn static_value(_: Self) -> i32 { 1 } | ^^^^^^^^^^^^ ------- +note: associated function provided through this `impl` + --> $DIR/self-coercion-static-free.rs:17:1 + | +LL | impl Trait for F {} + | ^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/self-coercion-static-free.rs:35:40 @@ -100,6 +120,11 @@ LL | pub trait Trait: Sized { ... LL | fn static_mut_ref(_: &mut Self) -> i32 { 2 } | ^^^^^^^^^^^^^^ ------------ +note: associated function provided through this `impl` + --> $DIR/self-coercion-static-free.rs:17:1 + | +LL | impl Trait for F {} + | ^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/self-coercion-static-free.rs:35:56 @@ -119,6 +144,11 @@ LL | pub trait Trait: Sized { ... LL | fn static_ref(_: &Self) -> i32 { 3 } | ^^^^^^^^^^ -------- +note: associated function provided through this `impl` + --> $DIR/self-coercion-static-free.rs:17:1 + | +LL | impl Trait for F {} + | ^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/self-coercion-static-free.rs:52:43 diff --git a/tests/ui/delegation/self-mapping-arguments-errors.stderr b/tests/ui/delegation/self-mapping-arguments-errors.stderr index d63dae2478464..032561ddd8816 100644 --- a/tests/ui/delegation/self-mapping-arguments-errors.stderr +++ b/tests/ui/delegation/self-mapping-arguments-errors.stderr @@ -113,6 +113,11 @@ note: method defined here LL | trait MyAdd { LL | fn add(self, other: Box) -> Self; | ^^^ ----- +note: method provided through this `impl` + --> $DIR/self-mapping-arguments-errors.rs:37:5 + | +LL | impl MyAdd for usize { + | ^^^^^^^^^^^^^^^^^^^^ help: store this in the heap by calling `Box::new` | LL | reuse impl MyAdd for W { Box::new(self.0) } diff --git a/tests/ui/delegation/self-mapping-output.stderr b/tests/ui/delegation/self-mapping-output.stderr index 4b184f1a57446..16d72442dc4af 100644 --- a/tests/ui/delegation/self-mapping-output.stderr +++ b/tests/ui/delegation/self-mapping-output.stderr @@ -241,6 +241,11 @@ note: method defined here LL | trait Trait { LL | fn method(&self) -> Self; | ^^^^^^ ---- +note: method provided through this `impl` + --> $DIR/self-mapping-output.rs:238:5 + | +LL | impl Trait for F { + | ^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/self-mapping-output.rs:251:29 @@ -271,6 +276,11 @@ LL | trait Trait { ... LL | fn raw_S(&self) -> S { S } | ^^^^^ ----- +note: method provided through this `impl` + --> $DIR/self-mapping-output.rs:238:5 + | +LL | impl Trait for F { + | ^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/self-mapping-output.rs:263:38 @@ -289,6 +299,11 @@ note: method defined here LL | trait Trait { LL | fn method(&self) -> Self; | ^^^^^^ ---- +note: method provided through this `impl` + --> $DIR/self-mapping-output.rs:238:5 + | +LL | impl Trait for F { + | ^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/self-mapping-output.rs:263:29 @@ -319,6 +334,11 @@ LL | trait Trait { ... LL | fn raw_S(&self) -> S { S } | ^^^^^ ----- +note: method provided through this `impl` + --> $DIR/self-mapping-output.rs:238:5 + | +LL | impl Trait for F { + | ^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/self-mapping-output.rs:296:31 diff --git a/tests/ui/delegation/unused-target-expr-in-glob-or-list.stderr b/tests/ui/delegation/unused-target-expr-in-glob-or-list.stderr index 330e536f81840..21d9586d2f58e 100644 --- a/tests/ui/delegation/unused-target-expr-in-glob-or-list.stderr +++ b/tests/ui/delegation/unused-target-expr-in-glob-or-list.stderr @@ -225,6 +225,11 @@ note: associated function defined here LL | pub trait Trait: Sized { LL | fn static_self() -> F { F } | ^^^^^^^^^^^ +note: associated function provided through this `impl` + --> $DIR/unused-target-expr-in-glob-or-list.rs:14:1 + | +LL | impl Trait for F {} + | ^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/unused-target-expr-in-glob-or-list.rs:107:37 @@ -290,6 +295,11 @@ note: associated function defined here LL | pub trait Trait: Sized { LL | fn static_self() -> F { F } | ^^^^^^^^^^^ +note: associated function provided through this `impl` + --> $DIR/unused-target-expr-in-glob-or-list.rs:14:1 + | +LL | impl Trait for F {} + | ^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/unused-target-expr-in-glob-or-list.rs:127:33 diff --git a/tests/ui/fn_traits/point-at-impl-in-call-argument-type-error.rs b/tests/ui/fn_traits/point-at-impl-in-call-argument-type-error.rs new file mode 100644 index 0000000000000..160c0c36c1f05 --- /dev/null +++ b/tests/ui/fn_traits/point-at-impl-in-call-argument-type-error.rs @@ -0,0 +1,12 @@ +// Point at blanket `impl`, which might help the user figure out that `B::from` can only convert to +// `B`. Issue #104712. + +struct A; +struct B; + +fn foo() { + let a = A; + let b = B::from(a); //~ ERROR: mismatched types +} + +fn main() {} diff --git a/tests/ui/fn_traits/point-at-impl-in-call-argument-type-error.stderr b/tests/ui/fn_traits/point-at-impl-in-call-argument-type-error.stderr new file mode 100644 index 0000000000000..855b5561ee7b0 --- /dev/null +++ b/tests/ui/fn_traits/point-at-impl-in-call-argument-type-error.stderr @@ -0,0 +1,16 @@ +error[E0308]: mismatched types + --> $DIR/point-at-impl-in-call-argument-type-error.rs:9:21 + | +LL | let b = B::from(a); + | ------- ^ expected `B`, found `A` + | | + | arguments to this function are incorrect + | +note: associated function defined here + --> $SRC_DIR/core/src/convert/mod.rs:LL:COL +note: associated function provided through this `impl` + --> $SRC_DIR/core/src/convert/mod.rs:LL:COL + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr index dbbee54c185bf..15894a0c09c6e 100644 --- a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr +++ b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr @@ -40,6 +40,12 @@ LL | >::add(1u32, 2); | this argument influences the return type of `add` note: method defined here --> $SRC_DIR/core/src/ops/arith.rs:LL:COL +note: method provided through this `impl` + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL + | + = note: in this macro invocation + = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) help: change the type of the numeric literal from `u32` to `i32` | LL - >::add(1u32, 2); @@ -63,6 +69,12 @@ LL | >::add(1, 2u32); | this argument influences the return type of `add` note: method defined here --> $SRC_DIR/core/src/ops/arith.rs:LL:COL +note: method provided through this `impl` + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL + | + = note: in this macro invocation + = note: this error originates in the macro `add_impl` (in Nightly builds, run with -Z macro-backtrace for more info) help: change the type of the numeric literal from `u32` to `i32` | LL - >::add(1, 2u32); From 84b9cfd76b1b3fb0d0fb993903ba59bdac7dc444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 24 Oct 2026 21:32:08 +0000 Subject: [PATCH 12/49] Account for blanket impls in message when pointing at one --- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 17 ++++++++++++++--- ...t-at-impl-in-call-argument-type-error.stderr | 2 +- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 5483e807d4318..69ffd02466589 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1,3 +1,4 @@ +// ignore-tidy-file-filelength use std::ops::Deref; use std::{fmt, iter}; @@ -1923,7 +1924,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let Some(callee_ty) = callee_ty && let ty::FnDef(_def_id, args) = callee_ty.kind() && let DefKind::Trait = self.tcx.def_kind(parent_def_id) - && let Ok(Some(traits::ImplSource::UserDefined(x))) = self.probe(|_| { + && let Ok(Some(traits::ImplSource::UserDefined(pick))) = self.probe(|_| { let trait_ref = ty::TraitRef::new( self.tcx, parent_def_id, @@ -1940,8 +1941,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) { err.span_note( - self.tcx.def_span(x.impl_def_id), - format!("{} provided through this `impl`", self.tcx.def_descr(def_id)), + self.tcx.def_span(pick.impl_def_id), + format!( + "{} provided through this {}`impl`", + self.tcx.def_descr(def_id), + if let ty::Param(_) = + self.tcx.type_of(pick.impl_def_id).skip_binder().kind() + { + "blanket " + } else { + "" + }, + ), ); } if let DefKind::Fn | DefKind::AssocFn = def_kind diff --git a/tests/ui/fn_traits/point-at-impl-in-call-argument-type-error.stderr b/tests/ui/fn_traits/point-at-impl-in-call-argument-type-error.stderr index 855b5561ee7b0..8af4873ca71ed 100644 --- a/tests/ui/fn_traits/point-at-impl-in-call-argument-type-error.stderr +++ b/tests/ui/fn_traits/point-at-impl-in-call-argument-type-error.stderr @@ -8,7 +8,7 @@ LL | let b = B::from(a); | note: associated function defined here --> $SRC_DIR/core/src/convert/mod.rs:LL:COL -note: associated function provided through this `impl` +note: associated function provided through this blanket `impl` --> $SRC_DIR/core/src/convert/mod.rs:LL:COL error: aborting due to 1 previous error From 178c4e1cb91fd3381be61910bf5c5f8f64b14a2b Mon Sep 17 00:00:00 2001 From: Yash Aggarwal <68061195+yashaggarwal85d@users.noreply.github.com> Date: Sun, 25 Oct 2026 07:07:46 +0000 Subject: [PATCH 13/49] Add regression tests for reborrow of non-Copy fields --- .../reborrow-generic-mut-field-aliasing.rs | 18 ++++++++++++++++++ .../reborrow-generic-mut-field-aliasing.stderr | 13 +++++++++++++ .../reborrow-non-copy-field-double-use.rs | 16 ++++++++++++++++ .../reborrow-non-copy-field-double-use.stderr | 9 +++++++++ 4 files changed, 56 insertions(+) create mode 100644 tests/ui/reborrow/reborrow-generic-mut-field-aliasing.rs create mode 100644 tests/ui/reborrow/reborrow-generic-mut-field-aliasing.stderr create mode 100644 tests/ui/reborrow/reborrow-non-copy-field-double-use.rs create mode 100644 tests/ui/reborrow/reborrow-non-copy-field-double-use.stderr diff --git a/tests/ui/reborrow/reborrow-generic-mut-field-aliasing.rs b/tests/ui/reborrow/reborrow-generic-mut-field-aliasing.rs new file mode 100644 index 0000000000000..c214e895ce428 --- /dev/null +++ b/tests/ui/reborrow/reborrow-generic-mut-field-aliasing.rs @@ -0,0 +1,18 @@ +#![feature(reborrow)] + +struct Wrap<'a, T>(&'a (), T); + +impl<'a> std::marker::Reborrow for Wrap<'a, &'static mut i32> {} + +fn get<'a, 'b>(x: Wrap<'a, &'b mut i32>) -> &'b mut i32 { + x.1 +} + +fn main() { + let mut x = 1; + let thing = Wrap(&(), &mut x); + let y = get(thing); + let z = get(thing); //~ ERROR cannot borrow `thing` as mutable more than once at a time + *y = 2; + *z = 3; +} diff --git a/tests/ui/reborrow/reborrow-generic-mut-field-aliasing.stderr b/tests/ui/reborrow/reborrow-generic-mut-field-aliasing.stderr new file mode 100644 index 0000000000000..a8d84ff29c015 --- /dev/null +++ b/tests/ui/reborrow/reborrow-generic-mut-field-aliasing.stderr @@ -0,0 +1,13 @@ +error[E0499]: cannot borrow `thing` as mutable more than once at a time + --> $DIR/reborrow-generic-mut-field-aliasing.rs:15:17 + | +LL | let y = get(thing); + | ----- first mutable borrow occurs here +LL | let z = get(thing); + | ^^^^^ second mutable borrow occurs here +LL | *y = 2; + | ------ first borrow later used here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/reborrow/reborrow-non-copy-field-double-use.rs b/tests/ui/reborrow/reborrow-non-copy-field-double-use.rs new file mode 100644 index 0000000000000..b3623774df975 --- /dev/null +++ b/tests/ui/reborrow/reborrow-non-copy-field-double-use.rs @@ -0,0 +1,16 @@ +#![feature(reborrow)] + +struct Wrap<'a>(&'a mut (), String); +//~^ ERROR the trait bound `String: Copy` is not satisfied + +impl<'a> std::marker::Reborrow for Wrap<'a> {} + +fn get(x: Wrap<'_>) -> String { + x.1 +} + +fn main() { + let x = Wrap(&mut (), String::from("a")); + let _y = get(x); + let _z = get(x); +} diff --git a/tests/ui/reborrow/reborrow-non-copy-field-double-use.stderr b/tests/ui/reborrow/reborrow-non-copy-field-double-use.stderr new file mode 100644 index 0000000000000..1eb1606930699 --- /dev/null +++ b/tests/ui/reborrow/reborrow-non-copy-field-double-use.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `String: Copy` is not satisfied + --> $DIR/reborrow-non-copy-field-double-use.rs:3:29 + | +LL | struct Wrap<'a>(&'a mut (), String); + | ^^^^^^ the trait `Copy` is not implemented for `String` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. From 9931a0d091eb81265fc3d397715b0d5280a3f0fe Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 15 Sep 2026 14:14:20 +0200 Subject: [PATCH 14/49] Enable `--generate-link-to-definition` rustdoc option on std docs --- library/std/src/lib.rs | 13 ++ library/std/src/os/darwin/fs.rs | 94 ++++++-- library/std/src/os/linux/process.rs | 36 ++- library/std/src/os/wasi/fs.rs | 24 +- library/std/src/os/windows/ffi.rs | 8 +- library/std/src/os/windows/fs.rs | 108 ++++++--- library/std/src/os/windows/io/handle.rs | 124 ++++++---- library/std/src/os/windows/io/raw.rs | 92 +++++--- library/std/src/os/windows/io/socket.rs | 106 +++++---- library/std/src/os/windows/net/addr.rs | 26 ++- library/std/src/os/windows/net/listener.rs | 16 +- library/std/src/os/windows/net/stream.rs | 40 +++- library/std/src/os/windows/process.rs | 256 +++++++++++++-------- library/std/src/os/windows/thread.rs | 8 +- library/std/src/sys/process/unix/unix.rs | 12 +- src/bootstrap/src/core/build_steps/doc.rs | 9 +- 16 files changed, 648 insertions(+), 324 deletions(-) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 8ed3a46bf3189..69bdc3256a9b7 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -449,6 +449,19 @@ since = "1.90.0" )] +// Macro used when rendering with `rustdoc` to replace code with `loop {}`. +#[allow(unused_macros)] +macro_rules! no_code { + ($($code:tt)*) => { + #[cfg(not(doc))] + { + $($code)* + } + #[cfg(doc)] + loop {} + } +} + // The Rust prelude // The compiler expects the prelude definition to be defined before its use statement. pub mod prelude; diff --git a/library/std/src/os/darwin/fs.rs b/library/std/src/os/darwin/fs.rs index b41391f19dccf..5349892dbd1c1 100644 --- a/library/std/src/os/darwin/fs.rs +++ b/library/std/src/os/darwin/fs.rs @@ -89,70 +89,114 @@ impl MetadataExt for Metadata { #[allow(deprecated)] #[cfg(any(doc, target_os = "macos", target_os = "ios"))] fn as_raw_stat(&self) -> &super::raw::stat { - unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const super::raw::stat) } + no_code! { + unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const super::raw::stat) } + } } fn st_dev(&self) -> u64 { - self.as_inner().as_inner().st_dev as u64 + no_code! { + self.as_inner().as_inner().st_dev as u64 + } } fn st_ino(&self) -> u64 { - self.as_inner().as_inner().st_ino as u64 + no_code! { + self.as_inner().as_inner().st_ino as u64 + } } fn st_mode(&self) -> u32 { - self.as_inner().as_inner().st_mode as u32 + no_code! { + self.as_inner().as_inner().st_mode as u32 + } } fn st_nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink as u64 + no_code! { + self.as_inner().as_inner().st_nlink as u64 + } } fn st_uid(&self) -> u32 { - self.as_inner().as_inner().st_uid as u32 + no_code! { + self.as_inner().as_inner().st_uid as u32 + } } fn st_gid(&self) -> u32 { - self.as_inner().as_inner().st_gid as u32 + no_code! { + self.as_inner().as_inner().st_gid as u32 + } } fn st_rdev(&self) -> u64 { - self.as_inner().as_inner().st_rdev as u64 + no_code! { + self.as_inner().as_inner().st_rdev as u64 + } } fn st_size(&self) -> u64 { - self.as_inner().as_inner().st_size as u64 + no_code! { + self.as_inner().as_inner().st_size as u64 + } } fn st_atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 + no_code! { + self.as_inner().as_inner().st_atime as i64 + } } fn st_atime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_atime_nsec as i64 + no_code! { + self.as_inner().as_inner().st_atime_nsec as i64 + } } fn st_mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 + no_code! { + self.as_inner().as_inner().st_mtime as i64 + } } fn st_mtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_mtime_nsec as i64 + no_code! { + self.as_inner().as_inner().st_mtime_nsec as i64 + } } fn st_ctime(&self) -> i64 { - self.as_inner().as_inner().st_ctime as i64 + no_code! { + self.as_inner().as_inner().st_ctime as i64 + } } fn st_ctime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_ctime_nsec as i64 + no_code! { + self.as_inner().as_inner().st_ctime_nsec as i64 + } } fn st_birthtime(&self) -> i64 { - self.as_inner().as_inner().st_birthtime as i64 + no_code! { + self.as_inner().as_inner().st_birthtime as i64 + } } fn st_birthtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_birthtime_nsec as i64 + no_code! { + self.as_inner().as_inner().st_birthtime_nsec as i64 + } } fn st_blksize(&self) -> u64 { - self.as_inner().as_inner().st_blksize as u64 + no_code! { + self.as_inner().as_inner().st_blksize as u64 + } } fn st_blocks(&self) -> u64 { - self.as_inner().as_inner().st_blocks as u64 + no_code! { + self.as_inner().as_inner().st_blocks as u64 + } } fn st_gen(&self) -> u32 { - self.as_inner().as_inner().st_gen as u32 + no_code! { + self.as_inner().as_inner().st_gen as u32 + } } fn st_flags(&self) -> u32 { - self.as_inner().as_inner().st_flags as u32 + no_code! { + self.as_inner().as_inner().st_flags as u32 + } } fn st_lspare(&self) -> u32 { - self.as_inner().as_inner().st_lspare as u32 + no_code! { + self.as_inner().as_inner().st_lspare as u32 + } } #[cfg(target_os = "macos")] fn st_qspare(&self) -> [u64; 2] { @@ -172,7 +216,9 @@ pub impl(self) trait FileTimesExt { #[stable(feature = "file_set_times", since = "1.75.0")] impl FileTimesExt for fs::FileTimes { fn set_created(mut self, t: SystemTime) -> Self { - self.as_inner_mut().set_created(t.into_inner()); - self + no_code! { + self.as_inner_mut().set_created(t.into_inner()); + self + } } } diff --git a/library/std/src/os/linux/process.rs b/library/std/src/os/linux/process.rs index e0ddaa85cb82e..26f2057b6d942 100644 --- a/library/std/src/os/linux/process.rs +++ b/library/std/src/os/linux/process.rs @@ -62,7 +62,9 @@ impl PidFd { /// /// [`Child::kill`]: process::Child::kill pub fn kill(&self) -> Result<()> { - self.inner.kill() + no_code! { + self.inner.kill() + } } /// Waits for the child to exit completely, returning the status that it exited with. @@ -75,7 +77,9 @@ impl PidFd { /// /// [`Child::wait`]: process::Child::wait pub fn wait(&self) -> Result { - self.inner.wait().map(FromInner::from_inner) + no_code! { + self.inner.wait().map(FromInner::from_inner) + } } /// Attempts to collect the exit status of the child if it has already exited. @@ -85,7 +89,9 @@ impl PidFd { /// /// [`Child::try_wait`]: process::Child::try_wait pub fn try_wait(&self) -> Result> { - Ok(self.inner.try_wait()?.map(FromInner::from_inner)) + no_code! { + Ok(self.inner.try_wait()?.map(FromInner::from_inner)) + } } } @@ -111,37 +117,49 @@ impl IntoInner for PidFd { impl AsRawFd for PidFd { #[inline] fn as_raw_fd(&self) -> RawFd { - self.as_inner().as_inner().as_raw_fd() + no_code! { + self.as_inner().as_inner().as_raw_fd() + } } } impl FromRawFd for PidFd { unsafe fn from_raw_fd(fd: RawFd) -> Self { - Self::from_inner(InnerPidFd::from_raw_fd(fd)) + no_code! { + Self::from_inner(InnerPidFd::from_raw_fd(fd)) + } } } impl IntoRawFd for PidFd { fn into_raw_fd(self) -> RawFd { - self.into_inner().into_inner().into_raw_fd() + no_code! { + self.into_inner().into_inner().into_raw_fd() + } } } impl AsFd for PidFd { fn as_fd(&self) -> BorrowedFd<'_> { - self.as_inner().as_inner().as_fd() + no_code! { + self.as_inner().as_inner().as_fd() + } } } impl From for PidFd { fn from(fd: OwnedFd) -> Self { - Self::from_inner(InnerPidFd::from_inner(FileDesc::from_inner(fd))) + no_code! { + Self::from_inner(InnerPidFd::from_inner(FileDesc::from_inner(fd))) + } } } impl From for OwnedFd { fn from(pid_fd: PidFd) -> Self { - pid_fd.into_inner().into_inner().into_inner() + no_code! { + pid_fd.into_inner().into_inner().into_inner() + } } } diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs index 369e5d4b0fb9d..96a18ff934ff0 100644 --- a/library/std/src/os/wasi/fs.rs +++ b/library/std/src/os/wasi/fs.rs @@ -334,13 +334,19 @@ pub trait MetadataExt { impl MetadataExt for fs::Metadata { fn dev(&self) -> u64 { - self.as_inner().as_inner().st_dev + no_code! { + self.as_inner().as_inner().st_dev + } } fn ino(&self) -> u64 { - self.as_inner().as_inner().st_ino + no_code! { + self.as_inner().as_inner().st_ino + } } fn nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink + no_code! { + self.as_inner().as_inner().st_nlink + } } } @@ -359,13 +365,19 @@ pub trait FileTypeExt { impl FileTypeExt for fs::FileType { fn is_block_device(&self) -> bool { - self.as_inner().is(libc::S_IFBLK) + no_code! { + self.as_inner().is(libc::S_IFBLK) + } } fn is_char_device(&self) -> bool { - self.as_inner().is(libc::S_IFCHR) + no_code! { + self.as_inner().is(libc::S_IFCHR) + } } fn is_socket(&self) -> bool { - self.as_inner().is(libc::S_IFSOCK) + no_code! { + self.as_inner().is(libc::S_IFSOCK) + } } } diff --git a/library/std/src/os/windows/ffi.rs b/library/std/src/os/windows/ffi.rs index b27a116f60388..d21dace2346ce 100644 --- a/library/std/src/os/windows/ffi.rs +++ b/library/std/src/os/windows/ffi.rs @@ -89,7 +89,9 @@ pub impl(self) trait OsStringExt { #[stable(feature = "rust1", since = "1.0.0")] impl OsStringExt for OsString { fn from_wide(wide: &[u16]) -> OsString { - FromInner::from_inner(Buf { inner: Wtf8Buf::from_wide(wide) }) + no_code! { + FromInner::from_inner(Buf { inner: Wtf8Buf::from_wide(wide) }) + } } } @@ -126,7 +128,9 @@ pub impl(self) trait OsStrExt { impl OsStrExt for OsStr { #[inline] fn encode_wide(&self) -> EncodeWide<'_> { - EncodeWide { inner: self.as_inner().inner.encode_wide() } + no_code! { + EncodeWide { inner: self.as_inner().inner.encode_wide() } + } } } diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs index 865cc90e83156..ec60272e8c89d 100644 --- a/library/std/src/os/windows/fs.rs +++ b/library/std/src/os/windows/fs.rs @@ -494,28 +494,38 @@ pub trait OpenOptionsExt { #[stable(feature = "open_options_ext", since = "1.10.0")] impl OpenOptionsExt for OpenOptions { fn access_mode(&mut self, access: u32) -> &mut OpenOptions { - self.as_inner_mut().access_mode(access); - self + no_code! { + self.as_inner_mut().access_mode(access); + self + } } fn share_mode(&mut self, share: u32) -> &mut OpenOptions { - self.as_inner_mut().share_mode(share); - self + no_code! { + self.as_inner_mut().share_mode(share); + self + } } fn custom_flags(&mut self, flags: u32) -> &mut OpenOptions { - self.as_inner_mut().custom_flags(flags); - self + no_code! { + self.as_inner_mut().custom_flags(flags); + self + } } fn attributes(&mut self, attributes: u32) -> &mut OpenOptions { - self.as_inner_mut().attributes(attributes); - self + no_code! { + self.as_inner_mut().attributes(attributes); + self + } } fn security_qos_flags(&mut self, flags: u32) -> &mut OpenOptions { - self.as_inner_mut().security_qos_flags(flags); - self + no_code! { + self.as_inner_mut().security_qos_flags(flags); + self + } } } @@ -537,13 +547,17 @@ pub impl(self) trait OpenOptionsExt2 { #[unstable(feature = "windows_freeze_file_times", issue = "149715")] impl OpenOptionsExt2 for OpenOptions { fn freeze_last_access_time(&mut self, freeze: bool) -> &mut Self { - self.as_inner_mut().freeze_last_access_time(freeze); - self + no_code! { + self.as_inner_mut().freeze_last_access_time(freeze); + self + } } fn freeze_last_write_time(&mut self, freeze: bool) -> &mut Self { - self.as_inner_mut().freeze_last_write_time(freeze); - self + no_code! { + self.as_inner_mut().freeze_last_write_time(freeze); + self + } } } @@ -595,7 +609,9 @@ pub impl(self) trait PermissionsExt { #[unstable(feature = "windows_permissions_ext", issue = "152956")] impl PermissionsExt for fs::Permissions { fn file_attributes(&self) -> u32 { - self.as_inner().file_attributes() + no_code! { + self.as_inner().file_attributes() + } } fn set_file_attributes(&mut self, mask: u32) { @@ -806,31 +822,49 @@ pub trait MetadataExt { #[stable(feature = "metadata_ext", since = "1.1.0")] impl MetadataExt for Metadata { fn file_attributes(&self) -> u32 { - self.as_inner().attrs() + no_code! { + self.as_inner().attrs() + } } fn creation_time(&self) -> u64 { - self.as_inner().created_u64() + no_code! { + self.as_inner().created_u64() + } } fn last_access_time(&self) -> u64 { - self.as_inner().accessed_u64() + no_code! { + self.as_inner().accessed_u64() + } } fn last_write_time(&self) -> u64 { - self.as_inner().modified_u64() + no_code! { + self.as_inner().modified_u64() + } } fn file_size(&self) -> u64 { - self.as_inner().size() + no_code! { + self.as_inner().size() + } } fn volume_serial_number(&self) -> Option { - self.as_inner().volume_serial_number() + no_code! { + self.as_inner().volume_serial_number() + } } fn number_of_links(&self) -> Option { - self.as_inner().number_of_links() + no_code! { + self.as_inner().number_of_links() + } } fn file_index(&self) -> Option { - self.as_inner().file_index() + no_code! { + self.as_inner().file_index() + } } fn change_time(&self) -> Option { - self.as_inner().changed_u64() + no_code! { + self.as_inner().changed_u64() + } } } @@ -850,10 +884,14 @@ pub impl(self) trait FileTypeExt { #[stable(feature = "windows_file_type_ext", since = "1.64.0")] impl FileTypeExt for fs::FileType { fn is_symlink_dir(&self) -> bool { - self.as_inner().is_symlink_dir() + no_code! { + self.as_inner().is_symlink_dir() + } } fn is_symlink_file(&self) -> bool { - self.as_inner().is_symlink_file() + no_code! { + self.as_inner().is_symlink_file() + } } } @@ -868,8 +906,10 @@ pub impl(self) trait FileTimesExt { #[stable(feature = "file_set_times", since = "1.75.0")] impl FileTimesExt for fs::FileTimes { fn set_created(mut self, t: SystemTime) -> Self { - self.as_inner_mut().set_created(t.into_inner()); - self + no_code! { + self.as_inner_mut().set_created(t.into_inner()); + self + } } } @@ -912,7 +952,9 @@ impl FileTimesExt for fs::FileTimes { #[stable(feature = "symlink", since = "1.1.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "fs_symlink_file")] pub fn symlink_file, Q: AsRef>(original: P, link: Q) -> io::Result<()> { - sys::fs::symlink_inner(original.as_ref(), link.as_ref(), false) + no_code! { + sys::fs::symlink_inner(original.as_ref(), link.as_ref(), false) + } } /// Creates a new symlink to a directory on the filesystem. @@ -954,7 +996,9 @@ pub fn symlink_file, Q: AsRef>(original: P, link: Q) -> io: #[stable(feature = "symlink", since = "1.1.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "fs_symlink_dir")] pub fn symlink_dir, Q: AsRef>(original: P, link: Q) -> io::Result<()> { - sys::fs::symlink_inner(original.as_ref(), link.as_ref(), true) + no_code! { + sys::fs::symlink_inner(original.as_ref(), link.as_ref(), true) + } } /// Creates a junction point. @@ -966,5 +1010,7 @@ pub fn symlink_dir, Q: AsRef>(original: P, link: Q) -> io:: /// If either path is not a local file path then this will fail. #[unstable(feature = "junction_point", issue = "121709")] pub fn junction_point, Q: AsRef>(original: P, link: Q) -> io::Result<()> { - sys::fs::junction_point(original.as_ref(), link.as_ref()) + no_code! { + sys::fs::junction_point(original.as_ref(), link.as_ref()) + } } diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index ec20baf2bf2ce..96db1c06318b9 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -194,9 +194,11 @@ impl TryFrom for OwnedHandle { impl Drop for HandleOrNull { #[inline] fn drop(&mut self) { - if self.is_valid() { - unsafe { - let _ = sys::c::CloseHandle(self.0); + no_code! { + if self.is_valid() { + unsafe { + let _ = sys::c::CloseHandle(self.0); + } } } } @@ -216,7 +218,9 @@ impl BorrowedHandle<'_> { /// object as the existing `BorrowedHandle` instance. #[stable(feature = "io_safety", since = "1.63.0")] pub fn try_clone_to_owned(&self) -> io::Result { - self.duplicate(0, false, sys::c::DUPLICATE_SAME_ACCESS) + no_code! { + self.duplicate(0, false, sys::c::DUPLICATE_SAME_ACCESS) + } } pub(crate) fn duplicate( @@ -225,30 +229,32 @@ impl BorrowedHandle<'_> { inherit: bool, options: u32, ) -> io::Result { - let handle = self.as_raw_handle(); - - // `Stdin`, `Stdout`, and `Stderr` can all hold null handles, such as - // in a process with a detached console. `DuplicateHandle` would fail - // if we passed it a null handle, but we can treat null as a valid - // handle which doesn't do any I/O, and allow it to be duplicated. - if handle.is_null() { - return unsafe { Ok(OwnedHandle::from_raw_handle(handle)) }; - } + no_code! { + let handle = self.as_raw_handle(); + + // `Stdin`, `Stdout`, and `Stderr` can all hold null handles, such as + // in a process with a detached console. `DuplicateHandle` would fail + // if we passed it a null handle, but we can treat null as a valid + // handle which doesn't do any I/O, and allow it to be duplicated. + if handle.is_null() { + return unsafe { Ok(OwnedHandle::from_raw_handle(handle)) }; + } - let mut ret = ptr::null_mut(); - cvt(unsafe { - let cur_proc = sys::c::GetCurrentProcess(); - sys::c::DuplicateHandle( - cur_proc, - handle, - cur_proc, - &mut ret, - access, - inherit as sys::c::BOOL, - options, - ) - })?; - unsafe { Ok(OwnedHandle::from_raw_handle(ret)) } + let mut ret = ptr::null_mut(); + cvt(unsafe { + let cur_proc = sys::c::GetCurrentProcess(); + sys::c::DuplicateHandle( + cur_proc, + handle, + cur_proc, + &mut ret, + access, + inherit as sys::c::BOOL, + options, + ) + })?; + unsafe { Ok(OwnedHandle::from_raw_handle(ret)) } + } } } @@ -272,9 +278,11 @@ impl TryFrom for OwnedHandle { impl Drop for HandleOrInvalid { #[inline] fn drop(&mut self) { - if self.is_valid() { - unsafe { - let _ = sys::c::CloseHandle(self.0); + no_code! { + if self.is_valid() { + unsafe { + let _ = sys::c::CloseHandle(self.0); + } } } } @@ -492,7 +500,9 @@ impl AsHandle for &mut T { impl AsHandle for crate::sync::Arc { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - (**self).as_handle() + no_code! { + (**self).as_handle() + } } } @@ -500,7 +510,9 @@ impl AsHandle for crate::sync::Arc { impl AsHandle for crate::rc::Rc { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - (**self).as_handle() + no_code! { + (**self).as_handle() + } } } @@ -508,7 +520,9 @@ impl AsHandle for crate::rc::Rc { impl AsHandle for crate::rc::UniqueRc { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - (**self).as_handle() + no_code! { + (**self).as_handle() + } } } @@ -516,7 +530,9 @@ impl AsHandle for crate::rc::UniqueRc { impl AsHandle for Box { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - (**self).as_handle() + no_code! { + (**self).as_handle() + } } } @@ -543,7 +559,9 @@ impl AsHandle for OwnedHandle { impl AsHandle for fs::File { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - self.as_inner().as_handle() + no_code! { + self.as_inner().as_handle() + } } } @@ -552,7 +570,9 @@ impl From for OwnedHandle { /// Takes ownership of a [`File`](fs::File)'s underlying file handle. #[inline] fn from(file: fs::File) -> OwnedHandle { - file.into_inner().into_inner().into_inner() + no_code! { + file.into_inner().into_inner().into_inner() + } } } @@ -561,7 +581,9 @@ impl From for fs::File { /// Returns a [`File`](fs::File) that takes ownership of the given handle. #[inline] fn from(owned: OwnedHandle) -> Self { - Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned))) + no_code! { + Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned))) + } } } @@ -676,28 +698,36 @@ impl AsHandle for crate::thread::JoinHandle { impl From> for OwnedHandle { #[inline] fn from(join_handle: crate::thread::JoinHandle) -> OwnedHandle { - join_handle.into_inner().into_handle().into_inner() + no_code! { + join_handle.into_inner().into_handle().into_inner() + } } } #[stable(feature = "anonymous_pipe", since = "1.87.0")] impl AsHandle for io::PipeReader { fn as_handle(&self) -> BorrowedHandle<'_> { - self.0.as_handle() + no_code! { + self.0.as_handle() + } } } #[stable(feature = "anonymous_pipe", since = "1.87.0")] impl From for OwnedHandle { fn from(pipe: io::PipeReader) -> Self { - pipe.into_inner().into_inner() + no_code! { + pipe.into_inner().into_inner() + } } } #[stable(feature = "anonymous_pipe", since = "1.87.0")] impl AsHandle for io::PipeWriter { fn as_handle(&self) -> BorrowedHandle<'_> { - self.0.as_handle() + no_code! { + self.0.as_handle() + } } } @@ -747,20 +777,26 @@ unsafe_impl_handle_asrefs!(crate::fs::File, io::PipeWriter, io::PipeReader,); #[stable(feature = "anonymous_pipe", since = "1.87.0")] impl From for OwnedHandle { fn from(pipe: io::PipeWriter) -> Self { - pipe.into_inner().into_inner() + no_code! { + pipe.into_inner().into_inner() + } } } #[stable(feature = "anonymous_pipe", since = "1.87.0")] impl From for io::PipeReader { fn from(owned_handle: OwnedHandle) -> Self { - Self::from_inner(FromInner::from_inner(owned_handle)) + no_code! { + Self::from_inner(FromInner::from_inner(owned_handle)) + } } } #[stable(feature = "anonymous_pipe", since = "1.87.0")] impl From for io::PipeWriter { fn from(owned_handle: OwnedHandle) -> Self { - Self::from_inner(FromInner::from_inner(owned_handle)) + no_code! { + Self::from_inner(FromInner::from_inner(owned_handle)) + } } } diff --git a/library/std/src/os/windows/io/raw.rs b/library/std/src/os/windows/io/raw.rs index d050c28832517..bd1601fc5c5fd 100644 --- a/library/std/src/os/windows/io/raw.rs +++ b/library/std/src/os/windows/io/raw.rs @@ -94,7 +94,9 @@ pub trait IntoRawHandle { impl AsRawHandle for fs::File { #[inline] fn as_raw_handle(&self) -> RawHandle { - self.as_inner().as_raw_handle() as RawHandle + no_code! { + self.as_inner().as_raw_handle() as RawHandle + } } } @@ -156,11 +158,13 @@ pub(super) fn stdio_handle(raw: RawHandle) -> RawHandle { impl FromRawHandle for fs::File { #[inline] unsafe fn from_raw_handle(handle: RawHandle) -> fs::File { - unsafe { - let handle = handle as sys::c::HANDLE; - fs::File::from_inner(sys::fs::File::from_inner(FromInner::from_inner( - OwnedHandle::from_raw_handle(handle), - ))) + no_code! { + unsafe { + let handle = handle as sys::c::HANDLE; + fs::File::from_inner(sys::fs::File::from_inner(FromInner::from_inner( + OwnedHandle::from_raw_handle(handle), + ))) + } } } } @@ -169,7 +173,9 @@ impl FromRawHandle for fs::File { impl IntoRawHandle for fs::File { #[inline] fn into_raw_handle(self) -> RawHandle { - self.into_inner().into_raw_handle() as *mut _ + no_code! { + self.into_inner().into_raw_handle() as *mut _ + } } } @@ -238,21 +244,27 @@ pub trait IntoRawSocket { impl AsRawSocket for net::TcpStream { #[inline] fn as_raw_socket(&self) -> RawSocket { - self.as_inner().socket().as_raw_socket() + no_code! { + self.as_inner().socket().as_raw_socket() + } } } #[stable(feature = "rust1", since = "1.0.0")] impl AsRawSocket for net::TcpListener { #[inline] fn as_raw_socket(&self) -> RawSocket { - self.as_inner().socket().as_raw_socket() + no_code! { + self.as_inner().socket().as_raw_socket() + } } } #[stable(feature = "rust1", since = "1.0.0")] impl AsRawSocket for net::UdpSocket { #[inline] fn as_raw_socket(&self) -> RawSocket { - self.as_inner().socket().as_raw_socket() + no_code! { + self.as_inner().socket().as_raw_socket() + } } } @@ -260,9 +272,11 @@ impl AsRawSocket for net::UdpSocket { impl FromRawSocket for net::TcpStream { #[inline] unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream { - unsafe { - let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); - net::TcpStream::from_inner(sys::net::TcpStream::from_inner(sock)) + no_code! { + unsafe { + let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); + net::TcpStream::from_inner(sys::net::TcpStream::from_inner(sock)) + } } } } @@ -270,9 +284,11 @@ impl FromRawSocket for net::TcpStream { impl FromRawSocket for net::TcpListener { #[inline] unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener { - unsafe { - let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); - net::TcpListener::from_inner(sys::net::TcpListener::from_inner(sock)) + no_code! { + unsafe { + let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); + net::TcpListener::from_inner(sys::net::TcpListener::from_inner(sock)) + } } } } @@ -280,9 +296,11 @@ impl FromRawSocket for net::TcpListener { impl FromRawSocket for net::UdpSocket { #[inline] unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket { - unsafe { - let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); - net::UdpSocket::from_inner(sys::net::UdpSocket::from_inner(sock)) + no_code! { + unsafe { + let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); + net::UdpSocket::from_inner(sys::net::UdpSocket::from_inner(sock)) + } } } } @@ -291,7 +309,9 @@ impl FromRawSocket for net::UdpSocket { impl IntoRawSocket for net::TcpStream { #[inline] fn into_raw_socket(self) -> RawSocket { - self.into_inner().into_socket().into_inner().into_raw_socket() + no_code! { + self.into_inner().into_socket().into_inner().into_raw_socket() + } } } @@ -299,7 +319,9 @@ impl IntoRawSocket for net::TcpStream { impl IntoRawSocket for net::TcpListener { #[inline] fn into_raw_socket(self) -> RawSocket { - self.into_inner().into_socket().into_inner().into_raw_socket() + no_code! { + self.into_inner().into_socket().into_inner().into_raw_socket() + } } } @@ -307,48 +329,62 @@ impl IntoRawSocket for net::TcpListener { impl IntoRawSocket for net::UdpSocket { #[inline] fn into_raw_socket(self) -> RawSocket { - self.into_inner().into_socket().into_inner().into_raw_socket() + no_code! { + self.into_inner().into_socket().into_inner().into_raw_socket() + } } } #[stable(feature = "anonymous_pipe", since = "1.87.0")] impl AsRawHandle for io::PipeReader { fn as_raw_handle(&self) -> RawHandle { - self.0.as_raw_handle() + no_code! { + self.0.as_raw_handle() + } } } #[stable(feature = "anonymous_pipe", since = "1.87.0")] impl FromRawHandle for io::PipeReader { unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { - unsafe { Self::from_inner(FromRawHandle::from_raw_handle(raw_handle)) } + no_code! { + unsafe { Self::from_inner(FromRawHandle::from_raw_handle(raw_handle)) } + } } } #[stable(feature = "anonymous_pipe", since = "1.87.0")] impl IntoRawHandle for io::PipeReader { fn into_raw_handle(self) -> RawHandle { - self.0.into_raw_handle() + no_code! { + self.0.into_raw_handle() + } } } #[stable(feature = "anonymous_pipe", since = "1.87.0")] impl AsRawHandle for io::PipeWriter { fn as_raw_handle(&self) -> RawHandle { - self.0.as_raw_handle() + no_code! { + self.0.as_raw_handle() + } } } #[stable(feature = "anonymous_pipe", since = "1.87.0")] impl FromRawHandle for io::PipeWriter { unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { - unsafe { Self::from_inner(FromRawHandle::from_raw_handle(raw_handle)) } + no_code! { + unsafe { Self::from_inner(FromRawHandle::from_raw_handle(raw_handle)) } + } } } #[stable(feature = "anonymous_pipe", since = "1.87.0")] impl IntoRawHandle for io::PipeWriter { fn into_raw_handle(self) -> RawHandle { - self.0.into_raw_handle() + no_code! { + self.0.into_raw_handle() + } } } diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index d625a9ac52730..dd4476bac4bd0 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -79,14 +79,16 @@ impl OwnedSocket { #[allow(implicit_provenance_casts)] #[cfg(not(target_vendor = "uwp"))] pub(crate) fn set_no_inherit(&self) -> io::Result<()> { - cvt(unsafe { - sys::c::SetHandleInformation( - self.as_raw_socket() as sys::c::HANDLE, - sys::c::HANDLE_FLAG_INHERIT, - 0, - ) - }) - .map(drop) + no_code! { + cvt(unsafe { + sys::c::SetHandleInformation( + self.as_raw_socket() as sys::c::HANDLE, + sys::c::HANDLE_FLAG_INHERIT, + 0, + ) + }) + .map(drop) + } } #[cfg(target_vendor = "uwp")] @@ -100,35 +102,16 @@ impl BorrowedSocket<'_> { /// object as the existing `BorrowedSocket` instance. #[stable(feature = "io_safety", since = "1.63.0")] pub fn try_clone_to_owned(&self) -> io::Result { - let mut info = unsafe { mem::zeroed::() }; - let result = unsafe { - sys::c::WSADuplicateSocketW( - self.as_raw_socket() as sys::c::SOCKET, - sys::c::GetCurrentProcessId(), - &mut info, - ) - }; - sys::net::cvt(result)?; - let socket = unsafe { - sys::c::WSASocketW( - info.iAddressFamily, - info.iSocketType, - info.iProtocol, - &info, - 0, - sys::c::WSA_FLAG_OVERLAPPED | sys::c::WSA_FLAG_NO_HANDLE_INHERIT, - ) - }; - - if socket != sys::c::INVALID_SOCKET { - unsafe { Ok(OwnedSocket::from_raw_socket(socket as RawSocket)) } - } else { - let error = unsafe { sys::c::WSAGetLastError() }; - - if error != sys::c::WSAEPROTOTYPE && error != sys::c::WSAEINVAL { - return Err(io::Error::from_raw_os_error(error)); - } - + no_code! { + let mut info = unsafe { mem::zeroed::() }; + let result = unsafe { + sys::c::WSADuplicateSocketW( + self.as_raw_socket() as sys::c::SOCKET, + sys::c::GetCurrentProcessId(), + &mut info, + ) + }; + sys::net::cvt(result)?; let socket = unsafe { sys::c::WSASocketW( info.iAddressFamily, @@ -136,18 +119,39 @@ impl BorrowedSocket<'_> { info.iProtocol, &info, 0, - sys::c::WSA_FLAG_OVERLAPPED, + sys::c::WSA_FLAG_OVERLAPPED | sys::c::WSA_FLAG_NO_HANDLE_INHERIT, ) }; - if socket == sys::c::INVALID_SOCKET { - return Err(last_error()); - } - - unsafe { - let socket = OwnedSocket::from_raw_socket(socket as RawSocket); - socket.set_no_inherit()?; - Ok(socket) + if socket != sys::c::INVALID_SOCKET { + unsafe { Ok(OwnedSocket::from_raw_socket(socket as RawSocket)) } + } else { + let error = unsafe { sys::c::WSAGetLastError() }; + + if error != sys::c::WSAEPROTOTYPE && error != sys::c::WSAEINVAL { + return Err(io::Error::from_raw_os_error(error)); + } + + let socket = unsafe { + sys::c::WSASocketW( + info.iAddressFamily, + info.iSocketType, + info.iProtocol, + &info, + 0, + sys::c::WSA_FLAG_OVERLAPPED, + ) + }; + + if socket == sys::c::INVALID_SOCKET { + return Err(last_error()); + } + + unsafe { + let socket = OwnedSocket::from_raw_socket(socket as RawSocket); + socket.set_no_inherit()?; + Ok(socket) + } } } } @@ -155,7 +159,9 @@ impl BorrowedSocket<'_> { /// Returns the last error from the Windows socket interface. fn last_error() -> io::Error { - io::Error::from_raw_os_error(unsafe { sys::c::WSAGetLastError() }) + no_code! { + io::Error::from_raw_os_error(unsafe { sys::c::WSAGetLastError() }) + } } #[stable(feature = "io_safety", since = "1.63.0")] @@ -195,8 +201,10 @@ impl FromRawSocket for OwnedSocket { impl Drop for OwnedSocket { #[inline] fn drop(&mut self) { - unsafe { - let _ = sys::c::closesocket(self.socket.as_inner() as sys::c::SOCKET); + no_code! { + unsafe { + let _ = sys::c::closesocket(self.socket.as_inner() as sys::c::SOCKET); + } } } } diff --git a/library/std/src/os/windows/net/addr.rs b/library/std/src/os/windows/net/addr.rs index 5f6b93e56e723..614579762573c 100644 --- a/library/std/src/os/windows/net/addr.rs +++ b/library/std/src/os/windows/net/addr.rs @@ -131,20 +131,24 @@ impl SocketAddr { where P: AsRef, { - sockaddr_un(path.as_ref()).map(|(addr, len)| SocketAddr { addr, len: len as _ }) + no_code! { + sockaddr_un(path.as_ref()).map(|(addr, len)| SocketAddr { addr, len: len as _ }) + } } fn address(&self) -> AddressKind<'_> { - let len = self.len as usize - SUN_PATH_OFFSET; - let path = unsafe { mem::transmute::<&[i8], &[u8]>(&self.addr.sun_path) }; + no_code! { + let len = self.len as usize - SUN_PATH_OFFSET; + let path = unsafe { mem::transmute::<&[i8], &[u8]>(&self.addr.sun_path) }; - if len == 0 { - AddressKind::Unnamed - } else if self.addr.sun_path[0] == 0 { - AddressKind::Abstract(ByteStr::from_bytes(&path[1..len])) - } else { - AddressKind::Pathname(unsafe { - OsStr::from_encoded_bytes_unchecked(&path[..len - 1]).as_ref() - }) + if len == 0 { + AddressKind::Unnamed + } else if self.addr.sun_path[0] == 0 { + AddressKind::Abstract(ByteStr::from_bytes(&path[1..len])) + } else { + AddressKind::Pathname(unsafe { + OsStr::from_encoded_bytes_unchecked(&path[..len - 1]).as_ref() + }) + } } } diff --git a/library/std/src/os/windows/net/listener.rs b/library/std/src/os/windows/net/listener.rs index 19f5254e08bf9..5749747b3adee 100644 --- a/library/std/src/os/windows/net/listener.rs +++ b/library/std/src/os/windows/net/listener.rs @@ -164,7 +164,9 @@ impl UnixListener { /// } /// ``` pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { getsockname(self.0.as_raw(), addr, len) }) + no_code! { + SocketAddr::new(|addr, len| unsafe { getsockname(self.0.as_raw(), addr, len) }) + } } /// Creates a new independently owned handle to the underlying socket. @@ -326,21 +328,27 @@ impl<'a> Iterator for Incoming<'a> { impl AsRawSocket for UnixListener { #[inline] fn as_raw_socket(&self) -> RawSocket { - self.0.as_raw_socket() + no_code! { + self.0.as_raw_socket() + } } } impl FromRawSocket for UnixListener { #[inline] unsafe fn from_raw_socket(sock: RawSocket) -> Self { - UnixListener(unsafe { Socket::from_raw_socket(sock) }) + no_code! { + UnixListener(unsafe { Socket::from_raw_socket(sock) }) + } } } impl IntoRawSocket for UnixListener { #[inline] fn into_raw_socket(self) -> RawSocket { - self.0.into_raw_socket() + no_code! { + self.0.into_raw_socket() + } } } diff --git a/library/std/src/os/windows/net/stream.rs b/library/std/src/os/windows/net/stream.rs index c0f32e75411e9..1df01b8b527d5 100644 --- a/library/std/src/os/windows/net/stream.rs +++ b/library/std/src/os/windows/net/stream.rs @@ -127,7 +127,9 @@ impl UnixStream { /// } /// ``` pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { getsockname(self.0.as_raw(), addr, len) }) + no_code! { + SocketAddr::new(|addr, len| unsafe { getsockname(self.0.as_raw(), addr, len) }) + } } /// Returns the socket address of the remote half of this connection. @@ -146,7 +148,9 @@ impl UnixStream { /// } /// ``` pub fn peer_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { getpeername(self.0.as_raw(), addr, len) }) + no_code! { + SocketAddr::new(|addr, len| unsafe { getpeername(self.0.as_raw(), addr, len) }) + } } /// Returns the read timeout of this socket. @@ -167,7 +171,9 @@ impl UnixStream { /// } /// ``` pub fn read_timeout(&self) -> io::Result> { - self.0.timeout(SO_RCVTIMEO) + no_code! { + self.0.timeout(SO_RCVTIMEO) + } } /// Moves the socket into or out of nonblocking mode. @@ -231,7 +237,9 @@ impl UnixStream { /// } /// ``` pub fn set_read_timeout(&self, dur: Option) -> io::Result<()> { - self.0.set_timeout(dur, SO_RCVTIMEO) + no_code! { + self.0.set_timeout(dur, SO_RCVTIMEO) + } } /// Sets the write timeout for the socket. @@ -277,7 +285,9 @@ impl UnixStream { /// } /// ``` pub fn set_write_timeout(&self, dur: Option) -> io::Result<()> { - self.0.set_timeout(dur, SO_SNDTIMEO) + no_code! { + self.0.set_timeout(dur, SO_SNDTIMEO) + } } /// Shuts down the read, write, or both halves of this connection. @@ -368,7 +378,9 @@ impl UnixStream { /// } /// ``` pub fn write_timeout(&self) -> io::Result> { - self.0.timeout(SO_SNDTIMEO) + no_code! { + self.0.timeout(SO_SNDTIMEO) + } } } @@ -413,26 +425,34 @@ impl<'a> io::Write for &'a UnixStream { impl AsSocket for UnixStream { #[inline] fn as_socket(&self) -> BorrowedSocket<'_> { - self.0.as_socket() + no_code! { + self.0.as_socket() + } } } impl AsRawSocket for UnixStream { #[inline] fn as_raw_socket(&self) -> RawSocket { - self.0.as_raw_socket() + no_code! { + self.0.as_raw_socket() + } } } impl FromRawSocket for UnixStream { #[inline] unsafe fn from_raw_socket(sock: RawSocket) -> Self { - unsafe { UnixStream(Socket::from_raw_socket(sock)) } + no_code! { + unsafe { UnixStream(Socket::from_raw_socket(sock)) } + } } } impl IntoRawSocket for UnixStream { fn into_raw_socket(self) -> RawSocket { - self.0.into_raw_socket() + no_code! { + self.0.into_raw_socket() + } } } diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs index f4b60f2ed8eca..568bd45f01da3 100644 --- a/library/std/src/os/windows/process.rs +++ b/library/std/src/os/windows/process.rs @@ -15,9 +15,11 @@ use crate::{io, marker, process, ptr, sys}; #[stable(feature = "process_extensions", since = "1.2.0")] impl FromRawHandle for process::Stdio { unsafe fn from_raw_handle(handle: RawHandle) -> process::Stdio { - let handle = unsafe { sys::handle::Handle::from_raw_handle(handle as *mut _) }; - let io = sys::process::Stdio::Handle(handle); - process::Stdio::from_inner(io) + no_code! { + let handle = unsafe { sys::handle::Handle::from_raw_handle(handle as *mut _) }; + let io = sys::process::Stdio::Handle(handle); + process::Stdio::from_inner(io) + } } } @@ -26,9 +28,11 @@ impl From for process::Stdio { /// Takes ownership of a handle and returns a [`Stdio`](process::Stdio) /// that can attach a stream to it. fn from(handle: OwnedHandle) -> process::Stdio { - let handle = sys::handle::Handle::from_inner(handle); - let io = sys::process::Stdio::Handle(handle); - process::Stdio::from_inner(io) + no_code! { + let handle = sys::handle::Handle::from_inner(handle); + let io = sys::process::Stdio::Handle(handle); + process::Stdio::from_inner(io) + } } } @@ -36,7 +40,9 @@ impl From for process::Stdio { impl AsRawHandle for process::Child { #[inline] fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().as_raw_handle() as *mut _ + no_code! { + self.as_inner().handle().as_raw_handle() as *mut _ + } } } @@ -44,14 +50,18 @@ impl AsRawHandle for process::Child { impl AsHandle for process::Child { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - self.as_inner().handle().as_handle() + no_code! { + self.as_inner().handle().as_handle() + } } } #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for process::Child { fn into_raw_handle(self) -> RawHandle { - self.into_inner().into_handle().into_raw_handle() as *mut _ + no_code! { + self.into_inner().into_handle().into_raw_handle() as *mut _ + } } } @@ -59,7 +69,9 @@ impl IntoRawHandle for process::Child { impl From for OwnedHandle { /// Takes ownership of a [`Child`](process::Child)'s process handle. fn from(child: process::Child) -> OwnedHandle { - child.into_inner().into_handle().into_inner() + no_code! { + child.into_inner().into_handle().into_inner() + } } } @@ -67,7 +79,9 @@ impl From for OwnedHandle { impl AsRawHandle for process::ChildStdin { #[inline] fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().as_raw_handle() as *mut _ + no_code! { + self.as_inner().handle().as_raw_handle() as *mut _ + } } } @@ -75,7 +89,9 @@ impl AsRawHandle for process::ChildStdin { impl AsRawHandle for process::ChildStdout { #[inline] fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().as_raw_handle() as *mut _ + no_code! { + self.as_inner().handle().as_raw_handle() as *mut _ + } } } @@ -83,28 +99,36 @@ impl AsRawHandle for process::ChildStdout { impl AsRawHandle for process::ChildStderr { #[inline] fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().as_raw_handle() as *mut _ + no_code! { + self.as_inner().handle().as_raw_handle() as *mut _ + } } } #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for process::ChildStdin { fn into_raw_handle(self) -> RawHandle { - self.into_inner().into_handle().into_raw_handle() as *mut _ + no_code! { + self.into_inner().into_handle().into_raw_handle() as *mut _ + } } } #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for process::ChildStdout { fn into_raw_handle(self) -> RawHandle { - self.into_inner().into_handle().into_raw_handle() as *mut _ + no_code! { + self.into_inner().into_handle().into_raw_handle() as *mut _ + } } } #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for process::ChildStderr { fn into_raw_handle(self) -> RawHandle { - self.into_inner().into_handle().into_raw_handle() as *mut _ + no_code! { + self.into_inner().into_handle().into_raw_handle() as *mut _ + } } } @@ -115,9 +139,11 @@ impl IntoRawHandle for process::ChildStderr { #[stable(feature = "child_stream_from_fd", since = "1.74.0")] impl From for process::ChildStdin { fn from(handle: OwnedHandle) -> process::ChildStdin { - let handle = sys::handle::Handle::from_inner(handle); - let pipe = sys::process::ChildPipe::from_inner(handle); - process::ChildStdin::from_inner(pipe) + no_code! { + let handle = sys::handle::Handle::from_inner(handle); + let pipe = sys::process::ChildPipe::from_inner(handle); + process::ChildStdin::from_inner(pipe) + } } } @@ -128,9 +154,11 @@ impl From for process::ChildStdin { #[stable(feature = "child_stream_from_fd", since = "1.74.0")] impl From for process::ChildStdout { fn from(handle: OwnedHandle) -> process::ChildStdout { - let handle = sys::handle::Handle::from_inner(handle); - let pipe = sys::process::ChildPipe::from_inner(handle); - process::ChildStdout::from_inner(pipe) + no_code! { + let handle = sys::handle::Handle::from_inner(handle); + let pipe = sys::process::ChildPipe::from_inner(handle); + process::ChildStdout::from_inner(pipe) + } } } @@ -141,9 +169,11 @@ impl From for process::ChildStdout { #[stable(feature = "child_stream_from_fd", since = "1.74.0")] impl From for process::ChildStderr { fn from(handle: OwnedHandle) -> process::ChildStderr { - let handle = sys::handle::Handle::from_inner(handle); - let pipe = sys::process::ChildPipe::from_inner(handle); - process::ChildStderr::from_inner(pipe) + no_code! { + let handle = sys::handle::Handle::from_inner(handle); + let pipe = sys::process::ChildPipe::from_inner(handle); + process::ChildStderr::from_inner(pipe) + } } } @@ -159,7 +189,9 @@ pub impl(self) trait ExitStatusExt { #[stable(feature = "exit_status_from", since = "1.12.0")] impl ExitStatusExt for process::ExitStatus { fn from_raw(raw: u32) -> Self { - process::ExitStatus::from_inner(From::from(raw)) + no_code! { + process::ExitStatus::from_inner(From::from(raw)) + } } } @@ -391,28 +423,38 @@ pub impl(self) trait CommandExt { #[stable(feature = "windows_process_extensions", since = "1.16.0")] impl CommandExt for process::Command { fn creation_flags(&mut self, flags: u32) -> &mut process::Command { - self.as_inner_mut().creation_flags(flags); - self + no_code! { + self.as_inner_mut().creation_flags(flags); + self + } } fn desktop>(&mut self, desktop: S) -> &mut process::Command { - self.as_inner_mut().desktop(desktop.as_ref()); - self + no_code! { + self.as_inner_mut().desktop(desktop.as_ref()); + self + } } fn show_window(&mut self, cmd_show: u16) -> &mut process::Command { - self.as_inner_mut().show_window(Some(cmd_show)); - self + no_code! { + self.as_inner_mut().show_window(Some(cmd_show)); + self + } } fn force_quotes(&mut self, enabled: bool) -> &mut process::Command { - self.as_inner_mut().force_quotes(enabled); - self + no_code! { + self.as_inner_mut().force_quotes(enabled); + self + } } fn raw_arg>(&mut self, raw_text: S) -> &mut process::Command { - self.as_inner_mut().raw_arg(raw_text.as_ref()); - self + no_code! { + self.as_inner_mut().raw_arg(raw_text.as_ref()); + self + } } fn async_pipes(&mut self, always_async: bool) -> &mut process::Command { @@ -428,29 +470,39 @@ impl CommandExt for process::Command { &mut self, attribute_list: &ProcThreadAttributeList<'_>, ) -> io::Result { - self.as_inner_mut() - .spawn_with_attributes(sys::process::Stdio::Inherit, true, Some(attribute_list)) - .map(process::Child::from_inner) + no_code! { + self.as_inner_mut() + .spawn_with_attributes(sys::process::Stdio::Inherit, true, Some(attribute_list)) + .map(process::Child::from_inner) + } } fn startupinfo_fullscreen(&mut self, enabled: bool) -> &mut process::Command { - self.as_inner_mut().startupinfo_fullscreen(enabled); - self + no_code! { + self.as_inner_mut().startupinfo_fullscreen(enabled); + self + } } fn startupinfo_untrusted_source(&mut self, enabled: bool) -> &mut process::Command { - self.as_inner_mut().startupinfo_untrusted_source(enabled); - self + no_code! { + self.as_inner_mut().startupinfo_untrusted_source(enabled); + self + } } fn startupinfo_force_feedback(&mut self, enabled: Option) -> &mut process::Command { - self.as_inner_mut().startupinfo_force_feedback(enabled); - self + no_code! { + self.as_inner_mut().startupinfo_force_feedback(enabled); + self + } } fn inherit_handles(&mut self, inherit_handles: bool) -> &mut process::Command { - self.as_inner_mut().inherit_handles(inherit_handles); - self + no_code! { + self.as_inner_mut().inherit_handles(inherit_handles); + self + } } } @@ -464,7 +516,9 @@ pub impl(self) trait ChildExt { #[stable(feature = "windows_process_extensions_main_thread_handle", since = "1.100.0")] impl ChildExt for process::Child { fn main_thread_handle(&self) -> BorrowedHandle<'_> { - self.handle.main_thread_handle() + no_code! { + self.handle.main_thread_handle() + } } } @@ -484,7 +538,9 @@ pub impl(self) trait ExitCodeExt { #[stable(feature = "windows_process_exit_code_from", since = "CURRENT_RUSTC_VERSION")] impl ExitCodeExt for process::ExitCode { fn from_raw(raw: u32) -> Self { - process::ExitCode::from_inner(From::from(raw)) + no_code! { + process::ExitCode::from_inner(From::from(raw)) + } } } @@ -521,9 +577,11 @@ impl<'a> Drop for ProcThreadAttributeList<'a> { /// /// [1]: fn drop(&mut self) { - let lp_attribute_list = - self.attribute_list.as_mut_ptr().cast::(); - unsafe { sys::c::DeleteProcThreadAttributeList(lp_attribute_list) } + no_code! { + let lp_attribute_list = + self.attribute_list.as_mut_ptr().cast::(); + unsafe { sys::c::DeleteProcThreadAttributeList(lp_attribute_list) } + } } } @@ -667,58 +725,60 @@ impl<'a> ProcThreadAttributeListBuilder<'a> { /// Returns an error if the maximum number of attributes is exceeded /// or if there is an I/O error during initialization. pub fn finish(&self) -> io::Result> { - // To initialize our ProcThreadAttributeList, we need to determine - // how many bytes to allocate for it. The Windows API simplifies this - // process by allowing us to call `InitializeProcThreadAttributeList` - // with a null pointer to retrieve the required size. - let mut required_size = 0; - let Ok(attribute_count) = self.attributes.len().try_into() else { - return Err(io::const_error!( - io::ErrorKind::InvalidInput, - "maximum number of ProcThreadAttributes exceeded", - )); - }; - unsafe { - sys::c::InitializeProcThreadAttributeList( - ptr::null_mut(), - attribute_count, - 0, - &mut required_size, - ) - }; - - let mut attribute_list = vec![MaybeUninit::uninit(); required_size].into_boxed_slice(); - - // Once we've allocated the necessary memory, it's safe to invoke - // `InitializeProcThreadAttributeList` to properly initialize the list. - sys::cvt(unsafe { - sys::c::InitializeProcThreadAttributeList( - attribute_list.as_mut_ptr().cast::(), - attribute_count, - 0, - &mut required_size, - ) - })?; - - // # Add our attributes to the buffer. - // It's theoretically possible for the attribute count to exceed a u32 - // value. Therefore, we ensure that we don't add more attributes than - // the buffer was initialized for. - for (&attribute, value) in self.attributes.iter().take(attribute_count as usize) { + no_code! { + // To initialize our ProcThreadAttributeList, we need to determine + // how many bytes to allocate for it. The Windows API simplifies this + // process by allowing us to call `InitializeProcThreadAttributeList` + // with a null pointer to retrieve the required size. + let mut required_size = 0; + let Ok(attribute_count) = self.attributes.len().try_into() else { + return Err(io::const_error!( + io::ErrorKind::InvalidInput, + "maximum number of ProcThreadAttributes exceeded", + )); + }; + unsafe { + sys::c::InitializeProcThreadAttributeList( + ptr::null_mut(), + attribute_count, + 0, + &mut required_size, + ) + }; + + let mut attribute_list = vec![MaybeUninit::uninit(); required_size].into_boxed_slice(); + + // Once we've allocated the necessary memory, it's safe to invoke + // `InitializeProcThreadAttributeList` to properly initialize the list. sys::cvt(unsafe { - sys::c::UpdateProcThreadAttribute( + sys::c::InitializeProcThreadAttributeList( attribute_list.as_mut_ptr().cast::(), + attribute_count, 0, - attribute, - value.ptr, - value.size, - ptr::null_mut(), - ptr::null_mut(), + &mut required_size, ) })?; - } - Ok(ProcThreadAttributeList { attribute_list, _lifetime_marker: marker::PhantomData }) + // # Add our attributes to the buffer. + // It's theoretically possible for the attribute count to exceed a u32 + // value. Therefore, we ensure that we don't add more attributes than + // the buffer was initialized for. + for (&attribute, value) in self.attributes.iter().take(attribute_count as usize) { + sys::cvt(unsafe { + sys::c::UpdateProcThreadAttribute( + attribute_list.as_mut_ptr().cast::(), + 0, + attribute, + value.ptr, + value.size, + ptr::null_mut(), + ptr::null_mut(), + ) + })?; + } + + Ok(ProcThreadAttributeList { attribute_list, _lifetime_marker: marker::PhantomData }) + } } } diff --git a/library/std/src/os/windows/thread.rs b/library/std/src/os/windows/thread.rs index 1cdee44de4b72..137afc6af1a4c 100644 --- a/library/std/src/os/windows/thread.rs +++ b/library/std/src/os/windows/thread.rs @@ -12,7 +12,9 @@ use crate::thread; impl AsRawHandle for thread::JoinHandle { #[inline] fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().as_raw_handle() as *mut _ + no_code! { + self.as_inner().handle().as_raw_handle() as *mut _ + } } } @@ -20,6 +22,8 @@ impl AsRawHandle for thread::JoinHandle { impl IntoRawHandle for thread::JoinHandle { #[inline] fn into_raw_handle(self) -> RawHandle { - self.into_inner().into_handle().into_raw_handle() as *mut _ + no_code! { + self.into_inner().into_handle().into_raw_handle() as *mut _ + } } } diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs index ab02c05ea49a9..8d83bcf7e54bc 100644 --- a/library/std/src/sys/process/unix/unix.rs +++ b/library/std/src/sys/process/unix/unix.rs @@ -1320,11 +1320,13 @@ mod linux_child_ext { } fn into_pidfd(mut self) -> Result { - self.handle - .pidfd - .take() - .map(>::from_inner) - .ok_or_else(|| self) + no_code! { + self.handle + .pidfd + .take() + .map(>::from_inner) + .ok_or_else(|| self) + } } } } diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 34e9b354bddb2..ebc1a0fd3da89 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -710,7 +710,14 @@ impl CommandLineStep for Std { .expect("non-utf8 paths are unsupported"); let mut extra_args = match self.format { DocumentationFormat::Html => { - vec!["--markdown-css", "rust.css", "--markdown-no-toc", "--index-page", &index_page] + vec![ + "--markdown-css", + "rust.css", + "--markdown-no-toc", + "--index-page", + &index_page, + "--generate-link-to-definition", + ] } DocumentationFormat::Json => vec![], }; From b648b01ce91093a8f8d4d3d2ded14a3111f21f68 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 14 Oct 2026 22:28:26 +0200 Subject: [PATCH 15/49] Create new builtin rustc macro `rustdoc_skip_body` and replace the `std::no_code` macro --- compiler/rustc_builtin_macros/src/lib.rs | 2 + .../src/rustdoc_skip_body.rs | 93 ++++++ compiler/rustc_span/src/symbol.rs | 1 + library/std/src/lib.rs | 13 - library/std/src/macros.rs | 13 + library/std/src/os/darwin/fs.rs | 118 +++---- library/std/src/os/linux/process.rs | 46 ++- library/std/src/os/wasi/fs.rs | 31 +- library/std/src/os/windows/ffi.rs | 11 +- library/std/src/os/windows/fs.rs | 132 ++++---- library/std/src/os/windows/io/handle.rs | 143 ++++----- library/std/src/os/windows/io/raw.rs | 111 +++---- library/std/src/os/windows/io/socket.rs | 111 ++++--- library/std/src/os/windows/net/addr.rs | 30 +- library/std/src/os/windows/net/listener.rs | 22 +- library/std/src/os/windows/net/stream.rs | 52 ++-- library/std/src/os/windows/process.rs | 287 ++++++++---------- library/std/src/os/windows/thread.rs | 11 +- library/std/src/sys/process/unix/unix.rs | 14 +- 19 files changed, 601 insertions(+), 640 deletions(-) create mode 100644 compiler/rustc_builtin_macros/src/rustdoc_skip_body.rs diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 4c3b42eaa0b22..aaaf67e34af4e 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -46,6 +46,7 @@ mod iter; mod log_syntax; mod offload; mod pattern_type; +mod rustdoc_skip_body; mod source_util; mod test; mod test_binder_constraints; @@ -125,6 +126,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { eii_shared_macro: eii::eii_shared_macro, global_allocator: global_allocator::expand, offload_kernel: offload::expand_kernel, + rustdoc_skip_body: rustdoc_skip_body::expand, test: test::expand_test, test_case: test::expand_test_case, unsafe_eii: eii::unsafe_eii, diff --git a/compiler/rustc_builtin_macros/src/rustdoc_skip_body.rs b/compiler/rustc_builtin_macros/src/rustdoc_skip_body.rs new file mode 100644 index 0000000000000..7649fc7d72fe0 --- /dev/null +++ b/compiler/rustc_builtin_macros/src/rustdoc_skip_body.rs @@ -0,0 +1,93 @@ +//! The expansion from a function when the code would not compile with rustdoc: so if `cfg(doc)`, +//! expands to a `loop {}`. + +use rustc_ast::token::{self, Delimiter, IdentKind}; +use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; +use rustc_ast::{ + AssocItemKind, AttrArgs, AttrItem, Attribute, DelimArgs, ExprKind, Fn, ItemKind, MetaItem, + Safety, +}; +use rustc_expand::base::*; +use rustc_span::{Ident, Span, sym}; +use thin_vec::ThinVec; + +pub(crate) fn expand( + cx: &mut ExtCtxt<'_>, + attr_path_sp: Span, + meta_item: &MetaItem, + mut item: Annotatable, +) -> Vec { + if !meta_item.is_word() { + cx.dcx().struct_span_err(attr_path_sp, "`rustdoc_skip_body` doesn't take arguments").emit(); + } + let mut is_expected_item = false; + match item { + Annotatable::Item(ref mut item) => { + if let ItemKind::Fn(ref mut fn_) = item.kind { + expand_macro(cx, attr_path_sp, fn_); + is_expected_item = true; + } + } + Annotatable::AssocItem(ref mut item, _) => { + if let AssocItemKind::Fn(ref mut fn_) = item.kind { + expand_macro(cx, attr_path_sp, fn_); + is_expected_item = true; + } + } + _ => {} + } + if !is_expected_item { + cx.dcx() + .struct_span_err(attr_path_sp, "`rustdoc_skip_body` can only be used on functions") + .emit(); + } + vec![item] +} + +fn cfg_not_doc(cx: &mut ExtCtxt<'_>, sp: Span) -> Attribute { + // `not(doc)` + let not_doc = TokenStream::new(vec![ + TokenTree::token_alone(token::Ident(sym::not, IdentKind::Normal), sp), + TokenTree::Delimited( + DelimSpan::from_single(sp), + DelimSpacing::new(Spacing::JointHidden, Spacing::Alone), + Delimiter::Parenthesis, + TokenStream::token_alone(token::Ident(sym::doc, IdentKind::Normal), sp), + ), + ]); + + cx.attr_nested( + AttrItem { + unsafety: Safety::Default, + path: cx.path_ident(sp, Ident::new(sym::cfg, sp)), + args: AttrArgs::Delimited(DelimArgs { + dspan: DelimSpan::from_single(sp), + delim: Delimiter::Parenthesis, + tokens: not_doc, + }), + span: sp, + }, + sp, + ) +} + +fn expand_macro(cx: &mut ExtCtxt<'_>, sp: Span, fn_: &mut Fn) { + let Some(old_body) = fn_.body.take() else { + // No body... Well, no possibility to not compile I guess so all good. + return; + }; + let mut old_body = cx.expr_block(old_body); + // We add on the function's body `#[cfg(not(doc))]`. + old_body.attrs.push(cfg_not_doc(cx, sp)); + + // We create the `#[cfg(doc)] loop {}` "block". + let mut loop_expr = cx.expr(sp, ExprKind::Loop(cx.block(sp, ThinVec::new()), None, sp)); + loop_expr.attrs.push(cx.attr_nested_word(sym::cfg, sym::doc, sp)); + + let mut stmts = ThinVec::new(); + stmts.push(cx.stmt_expr(loop_expr)); + stmts.push(cx.stmt_expr(old_body)); + + // We create a new function body containing both blocks. + fn_.body = Some(cx.block(sp, stmts)); +} diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 89deeb44cf1b2..fc46005938b69 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1913,6 +1913,7 @@ symbols! { rustdoc, rustdoc_internals, rustdoc_missing_doc_code_examples, + rustdoc_skip_body, rustfmt, rvalue_static_promotion, rvector, diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 69bdc3256a9b7..8ed3a46bf3189 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -449,19 +449,6 @@ since = "1.90.0" )] -// Macro used when rendering with `rustdoc` to replace code with `loop {}`. -#[allow(unused_macros)] -macro_rules! no_code { - ($($code:tt)*) => { - #[cfg(not(doc))] - { - $($code)* - } - #[cfg(doc)] - loop {} - } -} - // The Rust prelude // The compiler expects the prelude definition to be defined before its use statement. pub mod prelude; diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index ea574fc4146e7..7dcdd2c6246b1 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -461,3 +461,16 @@ macro_rules! hash_map { map }} } + +/// Attribute macro to replace a function's body with `loop {}` under rustdoc. +/// +/// This allows target-specific functions to be documented on other targets, +/// even when their bodies reference items unavailable on the target used to +/// build the documentation. Use this with `#[cfg(any(doc, ...))]` to include +/// such functions in documentation builds. +/// +/// The function's signature must still be valid on the documentation target. +#[rustc_builtin_macro] +pub(crate) macro rustdoc_skip_body($item:item) { + /* compiler built-in */ +} diff --git a/library/std/src/os/darwin/fs.rs b/library/std/src/os/darwin/fs.rs index 5349892dbd1c1..ece59e96c7819 100644 --- a/library/std/src/os/darwin/fs.rs +++ b/library/std/src/os/darwin/fs.rs @@ -4,6 +4,7 @@ #![stable(feature = "metadata_ext", since = "1.1.0")] use crate::fs::{self, Metadata}; +use crate::macros::rustdoc_skip_body; use crate::sys::{AsInner, AsInnerMut, IntoInner}; use crate::time::SystemTime; @@ -88,115 +89,93 @@ pub trait MetadataExt { impl MetadataExt for Metadata { #[allow(deprecated)] #[cfg(any(doc, target_os = "macos", target_os = "ios"))] + #[rustdoc_skip_body] fn as_raw_stat(&self) -> &super::raw::stat { - no_code! { - unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const super::raw::stat) } - } + unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const super::raw::stat) } } + #[rustdoc_skip_body] fn st_dev(&self) -> u64 { - no_code! { - self.as_inner().as_inner().st_dev as u64 - } + self.as_inner().as_inner().st_dev as u64 } + #[rustdoc_skip_body] fn st_ino(&self) -> u64 { - no_code! { - self.as_inner().as_inner().st_ino as u64 - } + self.as_inner().as_inner().st_ino as u64 } + #[rustdoc_skip_body] fn st_mode(&self) -> u32 { - no_code! { - self.as_inner().as_inner().st_mode as u32 - } + self.as_inner().as_inner().st_mode as u32 } + #[rustdoc_skip_body] fn st_nlink(&self) -> u64 { - no_code! { - self.as_inner().as_inner().st_nlink as u64 - } + self.as_inner().as_inner().st_nlink as u64 } + #[rustdoc_skip_body] fn st_uid(&self) -> u32 { - no_code! { - self.as_inner().as_inner().st_uid as u32 - } + self.as_inner().as_inner().st_uid as u32 } + #[rustdoc_skip_body] fn st_gid(&self) -> u32 { - no_code! { - self.as_inner().as_inner().st_gid as u32 - } + self.as_inner().as_inner().st_gid as u32 } + #[rustdoc_skip_body] fn st_rdev(&self) -> u64 { - no_code! { - self.as_inner().as_inner().st_rdev as u64 - } + self.as_inner().as_inner().st_rdev as u64 } + #[rustdoc_skip_body] fn st_size(&self) -> u64 { - no_code! { - self.as_inner().as_inner().st_size as u64 - } + self.as_inner().as_inner().st_size as u64 } + #[rustdoc_skip_body] fn st_atime(&self) -> i64 { - no_code! { - self.as_inner().as_inner().st_atime as i64 - } + self.as_inner().as_inner().st_atime as i64 } + #[rustdoc_skip_body] fn st_atime_nsec(&self) -> i64 { - no_code! { - self.as_inner().as_inner().st_atime_nsec as i64 - } + self.as_inner().as_inner().st_atime_nsec as i64 } + #[rustdoc_skip_body] fn st_mtime(&self) -> i64 { - no_code! { - self.as_inner().as_inner().st_mtime as i64 - } + self.as_inner().as_inner().st_mtime as i64 } + #[rustdoc_skip_body] fn st_mtime_nsec(&self) -> i64 { - no_code! { - self.as_inner().as_inner().st_mtime_nsec as i64 - } + self.as_inner().as_inner().st_mtime_nsec as i64 } + #[rustdoc_skip_body] fn st_ctime(&self) -> i64 { - no_code! { - self.as_inner().as_inner().st_ctime as i64 - } + self.as_inner().as_inner().st_ctime as i64 } + #[rustdoc_skip_body] fn st_ctime_nsec(&self) -> i64 { - no_code! { - self.as_inner().as_inner().st_ctime_nsec as i64 - } + self.as_inner().as_inner().st_ctime_nsec as i64 } + #[rustdoc_skip_body] fn st_birthtime(&self) -> i64 { - no_code! { - self.as_inner().as_inner().st_birthtime as i64 - } + self.as_inner().as_inner().st_birthtime as i64 } + #[rustdoc_skip_body] fn st_birthtime_nsec(&self) -> i64 { - no_code! { - self.as_inner().as_inner().st_birthtime_nsec as i64 - } + self.as_inner().as_inner().st_birthtime_nsec as i64 } + #[rustdoc_skip_body] fn st_blksize(&self) -> u64 { - no_code! { - self.as_inner().as_inner().st_blksize as u64 - } + self.as_inner().as_inner().st_blksize as u64 } + #[rustdoc_skip_body] fn st_blocks(&self) -> u64 { - no_code! { - self.as_inner().as_inner().st_blocks as u64 - } + self.as_inner().as_inner().st_blocks as u64 } + #[rustdoc_skip_body] fn st_gen(&self) -> u32 { - no_code! { - self.as_inner().as_inner().st_gen as u32 - } + self.as_inner().as_inner().st_gen as u32 } + #[rustdoc_skip_body] fn st_flags(&self) -> u32 { - no_code! { - self.as_inner().as_inner().st_flags as u32 - } + self.as_inner().as_inner().st_flags as u32 } + #[rustdoc_skip_body] fn st_lspare(&self) -> u32 { - no_code! { - self.as_inner().as_inner().st_lspare as u32 - } + self.as_inner().as_inner().st_lspare as u32 } #[cfg(target_os = "macos")] fn st_qspare(&self) -> [u64; 2] { @@ -215,10 +194,9 @@ pub impl(self) trait FileTimesExt { #[stable(feature = "file_set_times", since = "1.75.0")] impl FileTimesExt for fs::FileTimes { + #[rustdoc_skip_body] fn set_created(mut self, t: SystemTime) -> Self { - no_code! { - self.as_inner_mut().set_created(t.into_inner()); - self - } + self.as_inner_mut().set_created(t.into_inner()); + self } } diff --git a/library/std/src/os/linux/process.rs b/library/std/src/os/linux/process.rs index 26f2057b6d942..26a4ab4b4c603 100644 --- a/library/std/src/os/linux/process.rs +++ b/library/std/src/os/linux/process.rs @@ -5,6 +5,7 @@ #![unstable(feature = "linux_pidfd", issue = "82971")] use crate::io::Result; +use crate::macros::rustdoc_skip_body; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::process::{self, ExitStatus}; use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner}; @@ -61,10 +62,9 @@ impl PidFd { /// races. But doing so will return an Error. /// /// [`Child::kill`]: process::Child::kill + #[rustdoc_skip_body] pub fn kill(&self) -> Result<()> { - no_code! { - self.inner.kill() - } + self.inner.kill() } /// Waits for the child to exit completely, returning the status that it exited with. @@ -76,10 +76,9 @@ impl PidFd { /// will return an Error. /// /// [`Child::wait`]: process::Child::wait + #[rustdoc_skip_body] pub fn wait(&self) -> Result { - no_code! { - self.inner.wait().map(FromInner::from_inner) - } + self.inner.wait().map(FromInner::from_inner) } /// Attempts to collect the exit status of the child if it has already exited. @@ -88,10 +87,9 @@ impl PidFd { /// to reap a child will return an ExitStatus, further attempts will return an Error. /// /// [`Child::try_wait`]: process::Child::try_wait + #[rustdoc_skip_body] pub fn try_wait(&self) -> Result> { - no_code! { - Ok(self.inner.try_wait()?.map(FromInner::from_inner)) - } + Ok(self.inner.try_wait()?.map(FromInner::from_inner)) } } @@ -116,50 +114,44 @@ impl IntoInner for PidFd { impl AsRawFd for PidFd { #[inline] + #[rustdoc_skip_body] fn as_raw_fd(&self) -> RawFd { - no_code! { - self.as_inner().as_inner().as_raw_fd() - } + self.as_inner().as_inner().as_raw_fd() } } impl FromRawFd for PidFd { + #[rustdoc_skip_body] unsafe fn from_raw_fd(fd: RawFd) -> Self { - no_code! { - Self::from_inner(InnerPidFd::from_raw_fd(fd)) - } + Self::from_inner(InnerPidFd::from_raw_fd(fd)) } } impl IntoRawFd for PidFd { + #[rustdoc_skip_body] fn into_raw_fd(self) -> RawFd { - no_code! { - self.into_inner().into_inner().into_raw_fd() - } + self.into_inner().into_inner().into_raw_fd() } } impl AsFd for PidFd { + #[rustdoc_skip_body] fn as_fd(&self) -> BorrowedFd<'_> { - no_code! { - self.as_inner().as_inner().as_fd() - } + self.as_inner().as_inner().as_fd() } } impl From for PidFd { + #[rustdoc_skip_body] fn from(fd: OwnedFd) -> Self { - no_code! { - Self::from_inner(InnerPidFd::from_inner(FileDesc::from_inner(fd))) - } + Self::from_inner(InnerPidFd::from_inner(FileDesc::from_inner(fd))) } } impl From for OwnedFd { + #[rustdoc_skip_body] fn from(pid_fd: PidFd) -> Self { - no_code! { - pid_fd.into_inner().into_inner().into_inner() - } + pid_fd.into_inner().into_inner().into_inner() } } diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs index 96a18ff934ff0..811ab7ea8480b 100644 --- a/library/std/src/os/wasi/fs.rs +++ b/library/std/src/os/wasi/fs.rs @@ -12,6 +12,7 @@ use io::{Read, Write}; use crate::ffi::OsStr; use crate::fs::{self, File, OpenOptions}; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; +use crate::macros::rustdoc_skip_body; #[cfg(target_env = "p1")] use crate::os::fd::AsRawFd; use crate::path::Path; @@ -333,20 +334,17 @@ pub trait MetadataExt { } impl MetadataExt for fs::Metadata { + #[rustdoc_skip_body] fn dev(&self) -> u64 { - no_code! { - self.as_inner().as_inner().st_dev - } + self.as_inner().as_inner().st_dev } + #[rustdoc_skip_body] fn ino(&self) -> u64 { - no_code! { - self.as_inner().as_inner().st_ino - } + self.as_inner().as_inner().st_ino } + #[rustdoc_skip_body] fn nlink(&self) -> u64 { - no_code! { - self.as_inner().as_inner().st_nlink - } + self.as_inner().as_inner().st_nlink } } @@ -364,20 +362,17 @@ pub trait FileTypeExt { } impl FileTypeExt for fs::FileType { + #[rustdoc_skip_body] fn is_block_device(&self) -> bool { - no_code! { - self.as_inner().is(libc::S_IFBLK) - } + self.as_inner().is(libc::S_IFBLK) } + #[rustdoc_skip_body] fn is_char_device(&self) -> bool { - no_code! { - self.as_inner().is(libc::S_IFCHR) - } + self.as_inner().is(libc::S_IFCHR) } + #[rustdoc_skip_body] fn is_socket(&self) -> bool { - no_code! { - self.as_inner().is(libc::S_IFSOCK) - } + self.as_inner().is(libc::S_IFSOCK) } } diff --git a/library/std/src/os/windows/ffi.rs b/library/std/src/os/windows/ffi.rs index d21dace2346ce..a4c6f1ad7df42 100644 --- a/library/std/src/os/windows/ffi.rs +++ b/library/std/src/os/windows/ffi.rs @@ -58,6 +58,7 @@ use alloc::wtf8::Wtf8Buf; use crate::ffi::{OsStr, OsString}; use crate::fmt; use crate::iter::FusedIterator; +use crate::macros::rustdoc_skip_body; use crate::sys::os_str::Buf; use crate::sys::{AsInner, FromInner}; @@ -88,10 +89,9 @@ pub impl(self) trait OsStringExt { #[stable(feature = "rust1", since = "1.0.0")] impl OsStringExt for OsString { + #[rustdoc_skip_body] fn from_wide(wide: &[u16]) -> OsString { - no_code! { - FromInner::from_inner(Buf { inner: Wtf8Buf::from_wide(wide) }) - } + FromInner::from_inner(Buf { inner: Wtf8Buf::from_wide(wide) }) } } @@ -127,10 +127,9 @@ pub impl(self) trait OsStrExt { #[stable(feature = "rust1", since = "1.0.0")] impl OsStrExt for OsStr { #[inline] + #[rustdoc_skip_body] fn encode_wide(&self) -> EncodeWide<'_> { - no_code! { - EncodeWide { inner: self.as_inner().inner.encode_wide() } - } + EncodeWide { inner: self.as_inner().inner.encode_wide() } } } diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs index ec60272e8c89d..d931dd2476039 100644 --- a/library/std/src/os/windows/fs.rs +++ b/library/std/src/os/windows/fs.rs @@ -6,6 +6,7 @@ use crate::fs::{self, Metadata, OpenOptions, Permissions}; use crate::io::BorrowedCursor; +use crate::macros::rustdoc_skip_body; use crate::path::Path; use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner}; use crate::time::SystemTime; @@ -493,39 +494,34 @@ pub trait OpenOptionsExt { #[stable(feature = "open_options_ext", since = "1.10.0")] impl OpenOptionsExt for OpenOptions { + #[rustdoc_skip_body] fn access_mode(&mut self, access: u32) -> &mut OpenOptions { - no_code! { - self.as_inner_mut().access_mode(access); - self - } + self.as_inner_mut().access_mode(access); + self } + #[rustdoc_skip_body] fn share_mode(&mut self, share: u32) -> &mut OpenOptions { - no_code! { - self.as_inner_mut().share_mode(share); - self - } + self.as_inner_mut().share_mode(share); + self } + #[rustdoc_skip_body] fn custom_flags(&mut self, flags: u32) -> &mut OpenOptions { - no_code! { - self.as_inner_mut().custom_flags(flags); - self - } + self.as_inner_mut().custom_flags(flags); + self } + #[rustdoc_skip_body] fn attributes(&mut self, attributes: u32) -> &mut OpenOptions { - no_code! { - self.as_inner_mut().attributes(attributes); - self - } + self.as_inner_mut().attributes(attributes); + self } + #[rustdoc_skip_body] fn security_qos_flags(&mut self, flags: u32) -> &mut OpenOptions { - no_code! { - self.as_inner_mut().security_qos_flags(flags); - self - } + self.as_inner_mut().security_qos_flags(flags); + self } } @@ -546,18 +542,16 @@ pub impl(self) trait OpenOptionsExt2 { #[unstable(feature = "windows_freeze_file_times", issue = "149715")] impl OpenOptionsExt2 for OpenOptions { + #[rustdoc_skip_body] fn freeze_last_access_time(&mut self, freeze: bool) -> &mut Self { - no_code! { - self.as_inner_mut().freeze_last_access_time(freeze); - self - } + self.as_inner_mut().freeze_last_access_time(freeze); + self } + #[rustdoc_skip_body] fn freeze_last_write_time(&mut self, freeze: bool) -> &mut Self { - no_code! { - self.as_inner_mut().freeze_last_write_time(freeze); - self - } + self.as_inner_mut().freeze_last_write_time(freeze); + self } } @@ -608,10 +602,9 @@ pub impl(self) trait PermissionsExt { #[unstable(feature = "windows_permissions_ext", issue = "152956")] impl PermissionsExt for fs::Permissions { + #[rustdoc_skip_body] fn file_attributes(&self) -> u32 { - no_code! { - self.as_inner().file_attributes() - } + self.as_inner().file_attributes() } fn set_file_attributes(&mut self, mask: u32) { @@ -821,50 +814,41 @@ pub trait MetadataExt { #[stable(feature = "metadata_ext", since = "1.1.0")] impl MetadataExt for Metadata { + #[rustdoc_skip_body] fn file_attributes(&self) -> u32 { - no_code! { - self.as_inner().attrs() - } + self.as_inner().attrs() } + #[rustdoc_skip_body] fn creation_time(&self) -> u64 { - no_code! { - self.as_inner().created_u64() - } + self.as_inner().created_u64() } + #[rustdoc_skip_body] fn last_access_time(&self) -> u64 { - no_code! { - self.as_inner().accessed_u64() - } + self.as_inner().accessed_u64() } + #[rustdoc_skip_body] fn last_write_time(&self) -> u64 { - no_code! { - self.as_inner().modified_u64() - } + self.as_inner().modified_u64() } + #[rustdoc_skip_body] fn file_size(&self) -> u64 { - no_code! { - self.as_inner().size() - } + self.as_inner().size() } + #[rustdoc_skip_body] fn volume_serial_number(&self) -> Option { - no_code! { - self.as_inner().volume_serial_number() - } + self.as_inner().volume_serial_number() } + #[rustdoc_skip_body] fn number_of_links(&self) -> Option { - no_code! { - self.as_inner().number_of_links() - } + self.as_inner().number_of_links() } + #[rustdoc_skip_body] fn file_index(&self) -> Option { - no_code! { - self.as_inner().file_index() - } + self.as_inner().file_index() } + #[rustdoc_skip_body] fn change_time(&self) -> Option { - no_code! { - self.as_inner().changed_u64() - } + self.as_inner().changed_u64() } } @@ -883,15 +867,13 @@ pub impl(self) trait FileTypeExt { #[stable(feature = "windows_file_type_ext", since = "1.64.0")] impl FileTypeExt for fs::FileType { + #[rustdoc_skip_body] fn is_symlink_dir(&self) -> bool { - no_code! { - self.as_inner().is_symlink_dir() - } + self.as_inner().is_symlink_dir() } + #[rustdoc_skip_body] fn is_symlink_file(&self) -> bool { - no_code! { - self.as_inner().is_symlink_file() - } + self.as_inner().is_symlink_file() } } @@ -905,11 +887,10 @@ pub impl(self) trait FileTimesExt { #[stable(feature = "file_set_times", since = "1.75.0")] impl FileTimesExt for fs::FileTimes { + #[rustdoc_skip_body] fn set_created(mut self, t: SystemTime) -> Self { - no_code! { - self.as_inner_mut().set_created(t.into_inner()); - self - } + self.as_inner_mut().set_created(t.into_inner()); + self } } @@ -951,10 +932,9 @@ impl FileTimesExt for fs::FileTimes { #[doc(alias = "CreateSymbolicLink", alias = "CreateSymbolicLinkW")] #[stable(feature = "symlink", since = "1.1.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "fs_symlink_file")] +#[rustdoc_skip_body] pub fn symlink_file, Q: AsRef>(original: P, link: Q) -> io::Result<()> { - no_code! { - sys::fs::symlink_inner(original.as_ref(), link.as_ref(), false) - } + sys::fs::symlink_inner(original.as_ref(), link.as_ref(), false) } /// Creates a new symlink to a directory on the filesystem. @@ -995,10 +975,9 @@ pub fn symlink_file, Q: AsRef>(original: P, link: Q) -> io: #[doc(alias = "CreateSymbolicLink", alias = "CreateSymbolicLinkW")] #[stable(feature = "symlink", since = "1.1.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "fs_symlink_dir")] +#[rustdoc_skip_body] pub fn symlink_dir, Q: AsRef>(original: P, link: Q) -> io::Result<()> { - no_code! { - sys::fs::symlink_inner(original.as_ref(), link.as_ref(), true) - } + sys::fs::symlink_inner(original.as_ref(), link.as_ref(), true) } /// Creates a junction point. @@ -1009,8 +988,7 @@ pub fn symlink_dir, Q: AsRef>(original: P, link: Q) -> io:: /// /// If either path is not a local file path then this will fail. #[unstable(feature = "junction_point", issue = "121709")] +#[rustdoc_skip_body] pub fn junction_point, Q: AsRef>(original: P, link: Q) -> io::Result<()> { - no_code! { - sys::fs::junction_point(original.as_ref(), link.as_ref()) - } + sys::fs::junction_point(original.as_ref(), link.as_ref()) } diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 96db1c06318b9..90d9770cc6203 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -4,6 +4,7 @@ use super::raw::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle}; use crate::alloc::Allocator; +use crate::macros::rustdoc_skip_body; use crate::marker::PhantomData; use crate::mem::ManuallyDrop; use crate::sys::{AsInner, FromInner, IntoInner, cvt}; @@ -193,12 +194,11 @@ impl TryFrom for OwnedHandle { #[stable(feature = "io_safety", since = "1.63.0")] impl Drop for HandleOrNull { #[inline] + #[rustdoc_skip_body] fn drop(&mut self) { - no_code! { - if self.is_valid() { - unsafe { - let _ = sys::c::CloseHandle(self.0); - } + if self.is_valid() { + unsafe { + let _ = sys::c::CloseHandle(self.0); } } } @@ -217,44 +217,42 @@ impl BorrowedHandle<'_> { /// Creates a new `OwnedHandle` instance that shares the same underlying /// object as the existing `BorrowedHandle` instance. #[stable(feature = "io_safety", since = "1.63.0")] + #[rustdoc_skip_body] pub fn try_clone_to_owned(&self) -> io::Result { - no_code! { - self.duplicate(0, false, sys::c::DUPLICATE_SAME_ACCESS) - } + self.duplicate(0, false, sys::c::DUPLICATE_SAME_ACCESS) } + #[rustdoc_skip_body] pub(crate) fn duplicate( &self, access: u32, inherit: bool, options: u32, ) -> io::Result { - no_code! { - let handle = self.as_raw_handle(); - - // `Stdin`, `Stdout`, and `Stderr` can all hold null handles, such as - // in a process with a detached console. `DuplicateHandle` would fail - // if we passed it a null handle, but we can treat null as a valid - // handle which doesn't do any I/O, and allow it to be duplicated. - if handle.is_null() { - return unsafe { Ok(OwnedHandle::from_raw_handle(handle)) }; - } - - let mut ret = ptr::null_mut(); - cvt(unsafe { - let cur_proc = sys::c::GetCurrentProcess(); - sys::c::DuplicateHandle( - cur_proc, - handle, - cur_proc, - &mut ret, - access, - inherit as sys::c::BOOL, - options, - ) - })?; - unsafe { Ok(OwnedHandle::from_raw_handle(ret)) } + let handle = self.as_raw_handle(); + + // `Stdin`, `Stdout`, and `Stderr` can all hold null handles, such as + // in a process with a detached console. `DuplicateHandle` would fail + // if we passed it a null handle, but we can treat null as a valid + // handle which doesn't do any I/O, and allow it to be duplicated. + if handle.is_null() { + return unsafe { Ok(OwnedHandle::from_raw_handle(handle)) }; } + + let mut ret = ptr::null_mut(); + cvt(unsafe { + let cur_proc = sys::c::GetCurrentProcess(); + sys::c::DuplicateHandle( + cur_proc, + handle, + cur_proc, + &mut ret, + access, + inherit as sys::c::BOOL, + options, + ) + })?; + unsafe { Ok(OwnedHandle::from_raw_handle(ret)) } } } @@ -277,12 +275,11 @@ impl TryFrom for OwnedHandle { #[stable(feature = "io_safety", since = "1.63.0")] impl Drop for HandleOrInvalid { #[inline] + #[rustdoc_skip_body] fn drop(&mut self) { - no_code! { - if self.is_valid() { - unsafe { - let _ = sys::c::CloseHandle(self.0); - } + if self.is_valid() { + unsafe { + let _ = sys::c::CloseHandle(self.0); } } } @@ -499,40 +496,36 @@ impl AsHandle for &mut T { /// ``` impl AsHandle for crate::sync::Arc { #[inline] + #[rustdoc_skip_body] fn as_handle(&self) -> BorrowedHandle<'_> { - no_code! { - (**self).as_handle() - } + (**self).as_handle() } } #[stable(feature = "as_windows_ptrs", since = "1.71.0")] impl AsHandle for crate::rc::Rc { #[inline] + #[rustdoc_skip_body] fn as_handle(&self) -> BorrowedHandle<'_> { - no_code! { - (**self).as_handle() - } + (**self).as_handle() } } #[unstable(feature = "unique_rc_arc", issue = "112566")] impl AsHandle for crate::rc::UniqueRc { #[inline] + #[rustdoc_skip_body] fn as_handle(&self) -> BorrowedHandle<'_> { - no_code! { - (**self).as_handle() - } + (**self).as_handle() } } #[stable(feature = "as_windows_ptrs", since = "1.71.0")] impl AsHandle for Box { #[inline] + #[rustdoc_skip_body] fn as_handle(&self) -> BorrowedHandle<'_> { - no_code! { - (**self).as_handle() - } + (**self).as_handle() } } @@ -558,10 +551,9 @@ impl AsHandle for OwnedHandle { #[stable(feature = "io_safety", since = "1.63.0")] impl AsHandle for fs::File { #[inline] + #[rustdoc_skip_body] fn as_handle(&self) -> BorrowedHandle<'_> { - no_code! { - self.as_inner().as_handle() - } + self.as_inner().as_handle() } } @@ -569,10 +561,9 @@ impl AsHandle for fs::File { impl From for OwnedHandle { /// Takes ownership of a [`File`](fs::File)'s underlying file handle. #[inline] + #[rustdoc_skip_body] fn from(file: fs::File) -> OwnedHandle { - no_code! { - file.into_inner().into_inner().into_inner() - } + file.into_inner().into_inner().into_inner() } } @@ -580,10 +571,9 @@ impl From for OwnedHandle { impl From for fs::File { /// Returns a [`File`](fs::File) that takes ownership of the given handle. #[inline] + #[rustdoc_skip_body] fn from(owned: OwnedHandle) -> Self { - no_code! { - Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned))) - } + Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned))) } } @@ -697,37 +687,33 @@ impl AsHandle for crate::thread::JoinHandle { #[stable(feature = "io_safety", since = "1.63.0")] impl From> for OwnedHandle { #[inline] + #[rustdoc_skip_body] fn from(join_handle: crate::thread::JoinHandle) -> OwnedHandle { - no_code! { - join_handle.into_inner().into_handle().into_inner() - } + join_handle.into_inner().into_handle().into_inner() } } #[stable(feature = "anonymous_pipe", since = "1.87.0")] impl AsHandle for io::PipeReader { + #[rustdoc_skip_body] fn as_handle(&self) -> BorrowedHandle<'_> { - no_code! { - self.0.as_handle() - } + self.0.as_handle() } } #[stable(feature = "anonymous_pipe", since = "1.87.0")] impl From for OwnedHandle { + #[rustdoc_skip_body] fn from(pipe: io::PipeReader) -> Self { - no_code! { - pipe.into_inner().into_inner() - } + pipe.into_inner().into_inner() } } #[stable(feature = "anonymous_pipe", since = "1.87.0")] impl AsHandle for io::PipeWriter { + #[rustdoc_skip_body] fn as_handle(&self) -> BorrowedHandle<'_> { - no_code! { - self.0.as_handle() - } + self.0.as_handle() } } @@ -776,27 +762,24 @@ unsafe_impl_handle_asrefs!(crate::fs::File, io::PipeWriter, io::PipeReader,); #[stable(feature = "anonymous_pipe", since = "1.87.0")] impl From for OwnedHandle { + #[rustdoc_skip_body] fn from(pipe: io::PipeWriter) -> Self { - no_code! { - pipe.into_inner().into_inner() - } + pipe.into_inner().into_inner() } } #[stable(feature = "anonymous_pipe", since = "1.87.0")] impl From for io::PipeReader { + #[rustdoc_skip_body] fn from(owned_handle: OwnedHandle) -> Self { - no_code! { - Self::from_inner(FromInner::from_inner(owned_handle)) - } + Self::from_inner(FromInner::from_inner(owned_handle)) } } #[stable(feature = "anonymous_pipe", since = "1.87.0")] impl From for io::PipeWriter { + #[rustdoc_skip_body] fn from(owned_handle: OwnedHandle) -> Self { - no_code! { - Self::from_inner(FromInner::from_inner(owned_handle)) - } + Self::from_inner(FromInner::from_inner(owned_handle)) } } diff --git a/library/std/src/os/windows/io/raw.rs b/library/std/src/os/windows/io/raw.rs index bd1601fc5c5fd..0bd74c76490b1 100644 --- a/library/std/src/os/windows/io/raw.rs +++ b/library/std/src/os/windows/io/raw.rs @@ -2,6 +2,7 @@ #![stable(feature = "rust1", since = "1.0.0")] +use crate::macros::rustdoc_skip_body; #[cfg(doc)] use crate::os::windows::io::{AsHandle, AsSocket}; use crate::os::windows::io::{OwnedHandle, OwnedSocket}; @@ -93,10 +94,9 @@ pub trait IntoRawHandle { #[stable(feature = "rust1", since = "1.0.0")] impl AsRawHandle for fs::File { #[inline] + #[rustdoc_skip_body] fn as_raw_handle(&self) -> RawHandle { - no_code! { - self.as_inner().as_raw_handle() as RawHandle - } + self.as_inner().as_raw_handle() as RawHandle } } @@ -157,14 +157,13 @@ pub(super) fn stdio_handle(raw: RawHandle) -> RawHandle { #[stable(feature = "from_raw_os", since = "1.1.0")] impl FromRawHandle for fs::File { #[inline] + #[rustdoc_skip_body] unsafe fn from_raw_handle(handle: RawHandle) -> fs::File { - no_code! { - unsafe { - let handle = handle as sys::c::HANDLE; - fs::File::from_inner(sys::fs::File::from_inner(FromInner::from_inner( - OwnedHandle::from_raw_handle(handle), - ))) - } + unsafe { + let handle = handle as sys::c::HANDLE; + fs::File::from_inner(sys::fs::File::from_inner(FromInner::from_inner( + OwnedHandle::from_raw_handle(handle), + ))) } } } @@ -172,10 +171,9 @@ impl FromRawHandle for fs::File { #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for fs::File { #[inline] + #[rustdoc_skip_body] fn into_raw_handle(self) -> RawHandle { - no_code! { - self.into_inner().into_raw_handle() as *mut _ - } + self.into_inner().into_raw_handle() as *mut _ } } @@ -243,64 +241,58 @@ pub trait IntoRawSocket { #[stable(feature = "rust1", since = "1.0.0")] impl AsRawSocket for net::TcpStream { #[inline] + #[rustdoc_skip_body] fn as_raw_socket(&self) -> RawSocket { - no_code! { - self.as_inner().socket().as_raw_socket() - } + self.as_inner().socket().as_raw_socket() } } #[stable(feature = "rust1", since = "1.0.0")] impl AsRawSocket for net::TcpListener { #[inline] + #[rustdoc_skip_body] fn as_raw_socket(&self) -> RawSocket { - no_code! { - self.as_inner().socket().as_raw_socket() - } + self.as_inner().socket().as_raw_socket() } } #[stable(feature = "rust1", since = "1.0.0")] impl AsRawSocket for net::UdpSocket { #[inline] + #[rustdoc_skip_body] fn as_raw_socket(&self) -> RawSocket { - no_code! { - self.as_inner().socket().as_raw_socket() - } + self.as_inner().socket().as_raw_socket() } } #[stable(feature = "from_raw_os", since = "1.1.0")] impl FromRawSocket for net::TcpStream { #[inline] + #[rustdoc_skip_body] unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream { - no_code! { - unsafe { - let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); - net::TcpStream::from_inner(sys::net::TcpStream::from_inner(sock)) - } + unsafe { + let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); + net::TcpStream::from_inner(sys::net::TcpStream::from_inner(sock)) } } } #[stable(feature = "from_raw_os", since = "1.1.0")] impl FromRawSocket for net::TcpListener { #[inline] + #[rustdoc_skip_body] unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener { - no_code! { - unsafe { - let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); - net::TcpListener::from_inner(sys::net::TcpListener::from_inner(sock)) - } + unsafe { + let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); + net::TcpListener::from_inner(sys::net::TcpListener::from_inner(sock)) } } } #[stable(feature = "from_raw_os", since = "1.1.0")] impl FromRawSocket for net::UdpSocket { #[inline] + #[rustdoc_skip_body] unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket { - no_code! { - unsafe { - let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); - net::UdpSocket::from_inner(sys::net::UdpSocket::from_inner(sock)) - } + unsafe { + let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); + net::UdpSocket::from_inner(sys::net::UdpSocket::from_inner(sock)) } } } @@ -308,83 +300,74 @@ impl FromRawSocket for net::UdpSocket { #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawSocket for net::TcpStream { #[inline] + #[rustdoc_skip_body] fn into_raw_socket(self) -> RawSocket { - no_code! { - self.into_inner().into_socket().into_inner().into_raw_socket() - } + self.into_inner().into_socket().into_inner().into_raw_socket() } } #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawSocket for net::TcpListener { #[inline] + #[rustdoc_skip_body] fn into_raw_socket(self) -> RawSocket { - no_code! { - self.into_inner().into_socket().into_inner().into_raw_socket() - } + self.into_inner().into_socket().into_inner().into_raw_socket() } } #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawSocket for net::UdpSocket { #[inline] + #[rustdoc_skip_body] fn into_raw_socket(self) -> RawSocket { - no_code! { - self.into_inner().into_socket().into_inner().into_raw_socket() - } + self.into_inner().into_socket().into_inner().into_raw_socket() } } #[stable(feature = "anonymous_pipe", since = "1.87.0")] impl AsRawHandle for io::PipeReader { + #[rustdoc_skip_body] fn as_raw_handle(&self) -> RawHandle { - no_code! { - self.0.as_raw_handle() - } + self.0.as_raw_handle() } } #[stable(feature = "anonymous_pipe", since = "1.87.0")] impl FromRawHandle for io::PipeReader { + #[rustdoc_skip_body] unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { - no_code! { - unsafe { Self::from_inner(FromRawHandle::from_raw_handle(raw_handle)) } - } + unsafe { Self::from_inner(FromRawHandle::from_raw_handle(raw_handle)) } } } #[stable(feature = "anonymous_pipe", since = "1.87.0")] impl IntoRawHandle for io::PipeReader { + #[rustdoc_skip_body] fn into_raw_handle(self) -> RawHandle { - no_code! { - self.0.into_raw_handle() - } + self.0.into_raw_handle() } } #[stable(feature = "anonymous_pipe", since = "1.87.0")] impl AsRawHandle for io::PipeWriter { + #[rustdoc_skip_body] fn as_raw_handle(&self) -> RawHandle { - no_code! { - self.0.as_raw_handle() - } + self.0.as_raw_handle() } } #[stable(feature = "anonymous_pipe", since = "1.87.0")] impl FromRawHandle for io::PipeWriter { + #[rustdoc_skip_body] unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { - no_code! { - unsafe { Self::from_inner(FromRawHandle::from_raw_handle(raw_handle)) } - } + unsafe { Self::from_inner(FromRawHandle::from_raw_handle(raw_handle)) } } } #[stable(feature = "anonymous_pipe", since = "1.87.0")] impl IntoRawHandle for io::PipeWriter { + #[rustdoc_skip_body] fn into_raw_handle(self) -> RawHandle { - no_code! { - self.0.into_raw_handle() - } + self.0.into_raw_handle() } } diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index dd4476bac4bd0..24038e3dd5624 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -4,6 +4,7 @@ use super::raw::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket}; use crate::alloc::Allocator; +use crate::macros::rustdoc_skip_body; use crate::marker::PhantomData; use crate::mem::{self, ManuallyDrop}; #[cfg(not(target_vendor = "uwp"))] @@ -78,17 +79,16 @@ impl OwnedSocket { // FIXME(strict_provenance_magic): we defined RawSocket to be a u64 ;-; #[allow(implicit_provenance_casts)] #[cfg(not(target_vendor = "uwp"))] + #[rustdoc_skip_body] pub(crate) fn set_no_inherit(&self) -> io::Result<()> { - no_code! { - cvt(unsafe { - sys::c::SetHandleInformation( - self.as_raw_socket() as sys::c::HANDLE, - sys::c::HANDLE_FLAG_INHERIT, - 0, - ) - }) - .map(drop) - } + cvt(unsafe { + sys::c::SetHandleInformation( + self.as_raw_socket() as sys::c::HANDLE, + sys::c::HANDLE_FLAG_INHERIT, + 0, + ) + }) + .map(drop) } #[cfg(target_vendor = "uwp")] @@ -101,17 +101,37 @@ impl BorrowedSocket<'_> { /// Creates a new `OwnedSocket` instance that shares the same underlying /// object as the existing `BorrowedSocket` instance. #[stable(feature = "io_safety", since = "1.63.0")] + #[rustdoc_skip_body] pub fn try_clone_to_owned(&self) -> io::Result { - no_code! { - let mut info = unsafe { mem::zeroed::() }; - let result = unsafe { - sys::c::WSADuplicateSocketW( - self.as_raw_socket() as sys::c::SOCKET, - sys::c::GetCurrentProcessId(), - &mut info, - ) - }; - sys::net::cvt(result)?; + let mut info = unsafe { mem::zeroed::() }; + let result = unsafe { + sys::c::WSADuplicateSocketW( + self.as_raw_socket() as sys::c::SOCKET, + sys::c::GetCurrentProcessId(), + &mut info, + ) + }; + sys::net::cvt(result)?; + let socket = unsafe { + sys::c::WSASocketW( + info.iAddressFamily, + info.iSocketType, + info.iProtocol, + &info, + 0, + sys::c::WSA_FLAG_OVERLAPPED | sys::c::WSA_FLAG_NO_HANDLE_INHERIT, + ) + }; + + if socket != sys::c::INVALID_SOCKET { + unsafe { Ok(OwnedSocket::from_raw_socket(socket as RawSocket)) } + } else { + let error = unsafe { sys::c::WSAGetLastError() }; + + if error != sys::c::WSAEPROTOTYPE && error != sys::c::WSAEINVAL { + return Err(io::Error::from_raw_os_error(error)); + } + let socket = unsafe { sys::c::WSASocketW( info.iAddressFamily, @@ -119,49 +139,27 @@ impl BorrowedSocket<'_> { info.iProtocol, &info, 0, - sys::c::WSA_FLAG_OVERLAPPED | sys::c::WSA_FLAG_NO_HANDLE_INHERIT, + sys::c::WSA_FLAG_OVERLAPPED, ) }; - if socket != sys::c::INVALID_SOCKET { - unsafe { Ok(OwnedSocket::from_raw_socket(socket as RawSocket)) } - } else { - let error = unsafe { sys::c::WSAGetLastError() }; - - if error != sys::c::WSAEPROTOTYPE && error != sys::c::WSAEINVAL { - return Err(io::Error::from_raw_os_error(error)); - } - - let socket = unsafe { - sys::c::WSASocketW( - info.iAddressFamily, - info.iSocketType, - info.iProtocol, - &info, - 0, - sys::c::WSA_FLAG_OVERLAPPED, - ) - }; - - if socket == sys::c::INVALID_SOCKET { - return Err(last_error()); - } - - unsafe { - let socket = OwnedSocket::from_raw_socket(socket as RawSocket); - socket.set_no_inherit()?; - Ok(socket) - } + if socket == sys::c::INVALID_SOCKET { + return Err(last_error()); + } + + unsafe { + let socket = OwnedSocket::from_raw_socket(socket as RawSocket); + socket.set_no_inherit()?; + Ok(socket) } } } } /// Returns the last error from the Windows socket interface. +#[rustdoc_skip_body] fn last_error() -> io::Error { - no_code! { - io::Error::from_raw_os_error(unsafe { sys::c::WSAGetLastError() }) - } + io::Error::from_raw_os_error(unsafe { sys::c::WSAGetLastError() }) } #[stable(feature = "io_safety", since = "1.63.0")] @@ -200,11 +198,10 @@ impl FromRawSocket for OwnedSocket { #[stable(feature = "io_safety", since = "1.63.0")] impl Drop for OwnedSocket { #[inline] + #[rustdoc_skip_body] fn drop(&mut self) { - no_code! { - unsafe { - let _ = sys::c::closesocket(self.socket.as_inner() as sys::c::SOCKET); - } + unsafe { + let _ = sys::c::closesocket(self.socket.as_inner() as sys::c::SOCKET); } } } diff --git a/library/std/src/os/windows/net/addr.rs b/library/std/src/os/windows/net/addr.rs index 614579762573c..7ab856ae6ba44 100644 --- a/library/std/src/os/windows/net/addr.rs +++ b/library/std/src/os/windows/net/addr.rs @@ -1,6 +1,7 @@ #![unstable(feature = "windows_unix_domain_sockets", issue = "150487")] use crate::byte_str::ByteStr; use crate::ffi::OsStr; +use crate::macros::rustdoc_skip_body; use crate::path::Path; #[cfg(not(doc))] use crate::sys::c::{AF_UNIX, SOCKADDR, SOCKADDR_UN}; @@ -127,28 +128,27 @@ impl SocketAddr { /// /// assert!(SocketAddr::from_pathname("/path/with/\0/bytes").is_err()); /// ``` + #[rustdoc_skip_body] pub fn from_pathname

(path: P) -> io::Result where P: AsRef, { - no_code! { - sockaddr_un(path.as_ref()).map(|(addr, len)| SocketAddr { addr, len: len as _ }) - } + sockaddr_un(path.as_ref()).map(|(addr, len)| SocketAddr { addr, len: len as _ }) } + + #[rustdoc_skip_body] fn address(&self) -> AddressKind<'_> { - no_code! { - let len = self.len as usize - SUN_PATH_OFFSET; - let path = unsafe { mem::transmute::<&[i8], &[u8]>(&self.addr.sun_path) }; + let len = self.len as usize - SUN_PATH_OFFSET; + let path = unsafe { mem::transmute::<&[i8], &[u8]>(&self.addr.sun_path) }; - if len == 0 { - AddressKind::Unnamed - } else if self.addr.sun_path[0] == 0 { - AddressKind::Abstract(ByteStr::from_bytes(&path[1..len])) - } else { - AddressKind::Pathname(unsafe { - OsStr::from_encoded_bytes_unchecked(&path[..len - 1]).as_ref() - }) - } + if len == 0 { + AddressKind::Unnamed + } else if self.addr.sun_path[0] == 0 { + AddressKind::Abstract(ByteStr::from_bytes(&path[1..len])) + } else { + AddressKind::Pathname(unsafe { + OsStr::from_encoded_bytes_unchecked(&path[..len - 1]).as_ref() + }) } } diff --git a/library/std/src/os/windows/net/listener.rs b/library/std/src/os/windows/net/listener.rs index 5749747b3adee..d3b9b50c17293 100644 --- a/library/std/src/os/windows/net/listener.rs +++ b/library/std/src/os/windows/net/listener.rs @@ -1,4 +1,6 @@ #![unstable(feature = "windows_unix_domain_sockets", issue = "150487")] + +use crate::macros::rustdoc_skip_body; use crate::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket}; use crate::os::windows::net::{SocketAddr, UnixStream}; use crate::path::Path; @@ -163,10 +165,9 @@ impl UnixListener { /// Ok(()) /// } /// ``` + #[rustdoc_skip_body] pub fn local_addr(&self) -> io::Result { - no_code! { - SocketAddr::new(|addr, len| unsafe { getsockname(self.0.as_raw(), addr, len) }) - } + SocketAddr::new(|addr, len| unsafe { getsockname(self.0.as_raw(), addr, len) }) } /// Creates a new independently owned handle to the underlying socket. @@ -327,28 +328,25 @@ impl<'a> Iterator for Incoming<'a> { impl AsRawSocket for UnixListener { #[inline] + #[rustdoc_skip_body] fn as_raw_socket(&self) -> RawSocket { - no_code! { - self.0.as_raw_socket() - } + self.0.as_raw_socket() } } impl FromRawSocket for UnixListener { #[inline] + #[rustdoc_skip_body] unsafe fn from_raw_socket(sock: RawSocket) -> Self { - no_code! { - UnixListener(unsafe { Socket::from_raw_socket(sock) }) - } + UnixListener(unsafe { Socket::from_raw_socket(sock) }) } } impl IntoRawSocket for UnixListener { #[inline] + #[rustdoc_skip_body] fn into_raw_socket(self) -> RawSocket { - no_code! { - self.0.into_raw_socket() - } + self.0.into_raw_socket() } } diff --git a/library/std/src/os/windows/net/stream.rs b/library/std/src/os/windows/net/stream.rs index 1df01b8b527d5..9a3360bfb565c 100644 --- a/library/std/src/os/windows/net/stream.rs +++ b/library/std/src/os/windows/net/stream.rs @@ -1,4 +1,6 @@ #![unstable(feature = "windows_unix_domain_sockets", issue = "150487")] + +use crate::macros::rustdoc_skip_body; use crate::net::Shutdown; use crate::os::windows::io::{ AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, RawSocket, @@ -126,10 +128,9 @@ impl UnixStream { /// Ok(()) /// } /// ``` + #[rustdoc_skip_body] pub fn local_addr(&self) -> io::Result { - no_code! { - SocketAddr::new(|addr, len| unsafe { getsockname(self.0.as_raw(), addr, len) }) - } + SocketAddr::new(|addr, len| unsafe { getsockname(self.0.as_raw(), addr, len) }) } /// Returns the socket address of the remote half of this connection. @@ -147,10 +148,9 @@ impl UnixStream { /// Ok(()) /// } /// ``` + #[rustdoc_skip_body] pub fn peer_addr(&self) -> io::Result { - no_code! { - SocketAddr::new(|addr, len| unsafe { getpeername(self.0.as_raw(), addr, len) }) - } + SocketAddr::new(|addr, len| unsafe { getpeername(self.0.as_raw(), addr, len) }) } /// Returns the read timeout of this socket. @@ -170,10 +170,9 @@ impl UnixStream { /// Ok(()) /// } /// ``` + #[rustdoc_skip_body] pub fn read_timeout(&self) -> io::Result> { - no_code! { - self.0.timeout(SO_RCVTIMEO) - } + self.0.timeout(SO_RCVTIMEO) } /// Moves the socket into or out of nonblocking mode. @@ -236,10 +235,9 @@ impl UnixStream { /// Ok(()) /// } /// ``` + #[rustdoc_skip_body] pub fn set_read_timeout(&self, dur: Option) -> io::Result<()> { - no_code! { - self.0.set_timeout(dur, SO_RCVTIMEO) - } + self.0.set_timeout(dur, SO_RCVTIMEO) } /// Sets the write timeout for the socket. @@ -284,10 +282,9 @@ impl UnixStream { /// Ok(()) /// } /// ``` + #[rustdoc_skip_body] pub fn set_write_timeout(&self, dur: Option) -> io::Result<()> { - no_code! { - self.0.set_timeout(dur, SO_SNDTIMEO) - } + self.0.set_timeout(dur, SO_SNDTIMEO) } /// Shuts down the read, write, or both halves of this connection. @@ -377,10 +374,9 @@ impl UnixStream { /// Ok(()) /// } /// ``` + #[rustdoc_skip_body] pub fn write_timeout(&self) -> io::Result> { - no_code! { - self.0.timeout(SO_SNDTIMEO) - } + self.0.timeout(SO_SNDTIMEO) } } @@ -424,35 +420,31 @@ impl<'a> io::Write for &'a UnixStream { impl AsSocket for UnixStream { #[inline] + #[rustdoc_skip_body] fn as_socket(&self) -> BorrowedSocket<'_> { - no_code! { - self.0.as_socket() - } + self.0.as_socket() } } impl AsRawSocket for UnixStream { #[inline] + #[rustdoc_skip_body] fn as_raw_socket(&self) -> RawSocket { - no_code! { - self.0.as_raw_socket() - } + self.0.as_raw_socket() } } impl FromRawSocket for UnixStream { #[inline] + #[rustdoc_skip_body] unsafe fn from_raw_socket(sock: RawSocket) -> Self { - no_code! { - unsafe { UnixStream(Socket::from_raw_socket(sock)) } - } + unsafe { UnixStream(Socket::from_raw_socket(sock)) } } } impl IntoRawSocket for UnixStream { + #[rustdoc_skip_body] fn into_raw_socket(self) -> RawSocket { - no_code! { - self.0.into_raw_socket() - } + self.0.into_raw_socket() } } diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs index 568bd45f01da3..5065026b21a46 100644 --- a/library/std/src/os/windows/process.rs +++ b/library/std/src/os/windows/process.rs @@ -5,6 +5,7 @@ #![stable(feature = "process_extensions", since = "1.2.0")] use crate::ffi::{OsStr, c_void}; +use crate::macros::rustdoc_skip_body; use crate::mem::MaybeUninit; use crate::os::windows::io::{ AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle, @@ -14,12 +15,11 @@ use crate::{io, marker, process, ptr, sys}; #[stable(feature = "process_extensions", since = "1.2.0")] impl FromRawHandle for process::Stdio { + #[rustdoc_skip_body] unsafe fn from_raw_handle(handle: RawHandle) -> process::Stdio { - no_code! { - let handle = unsafe { sys::handle::Handle::from_raw_handle(handle as *mut _) }; - let io = sys::process::Stdio::Handle(handle); - process::Stdio::from_inner(io) - } + let handle = unsafe { sys::handle::Handle::from_raw_handle(handle as *mut _) }; + let io = sys::process::Stdio::Handle(handle); + process::Stdio::from_inner(io) } } @@ -27,108 +27,97 @@ impl FromRawHandle for process::Stdio { impl From for process::Stdio { /// Takes ownership of a handle and returns a [`Stdio`](process::Stdio) /// that can attach a stream to it. + #[rustdoc_skip_body] fn from(handle: OwnedHandle) -> process::Stdio { - no_code! { - let handle = sys::handle::Handle::from_inner(handle); - let io = sys::process::Stdio::Handle(handle); - process::Stdio::from_inner(io) - } + let handle = sys::handle::Handle::from_inner(handle); + let io = sys::process::Stdio::Handle(handle); + process::Stdio::from_inner(io) } } #[stable(feature = "process_extensions", since = "1.2.0")] impl AsRawHandle for process::Child { #[inline] + #[rustdoc_skip_body] fn as_raw_handle(&self) -> RawHandle { - no_code! { - self.as_inner().handle().as_raw_handle() as *mut _ - } + self.as_inner().handle().as_raw_handle() as *mut _ } } #[stable(feature = "io_safety", since = "1.63.0")] impl AsHandle for process::Child { #[inline] + #[rustdoc_skip_body] fn as_handle(&self) -> BorrowedHandle<'_> { - no_code! { - self.as_inner().handle().as_handle() - } + self.as_inner().handle().as_handle() } } #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for process::Child { + #[rustdoc_skip_body] fn into_raw_handle(self) -> RawHandle { - no_code! { - self.into_inner().into_handle().into_raw_handle() as *mut _ - } + self.into_inner().into_handle().into_raw_handle() as *mut _ } } #[stable(feature = "io_safety", since = "1.63.0")] impl From for OwnedHandle { /// Takes ownership of a [`Child`](process::Child)'s process handle. + #[rustdoc_skip_body] fn from(child: process::Child) -> OwnedHandle { - no_code! { - child.into_inner().into_handle().into_inner() - } + child.into_inner().into_handle().into_inner() } } #[stable(feature = "process_extensions", since = "1.2.0")] impl AsRawHandle for process::ChildStdin { #[inline] + #[rustdoc_skip_body] fn as_raw_handle(&self) -> RawHandle { - no_code! { - self.as_inner().handle().as_raw_handle() as *mut _ - } + self.as_inner().handle().as_raw_handle() as *mut _ } } #[stable(feature = "process_extensions", since = "1.2.0")] impl AsRawHandle for process::ChildStdout { #[inline] + #[rustdoc_skip_body] fn as_raw_handle(&self) -> RawHandle { - no_code! { - self.as_inner().handle().as_raw_handle() as *mut _ - } + self.as_inner().handle().as_raw_handle() as *mut _ } } #[stable(feature = "process_extensions", since = "1.2.0")] impl AsRawHandle for process::ChildStderr { #[inline] + #[rustdoc_skip_body] fn as_raw_handle(&self) -> RawHandle { - no_code! { - self.as_inner().handle().as_raw_handle() as *mut _ - } + self.as_inner().handle().as_raw_handle() as *mut _ } } #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for process::ChildStdin { + #[rustdoc_skip_body] fn into_raw_handle(self) -> RawHandle { - no_code! { - self.into_inner().into_handle().into_raw_handle() as *mut _ - } + self.into_inner().into_handle().into_raw_handle() as *mut _ } } #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for process::ChildStdout { + #[rustdoc_skip_body] fn into_raw_handle(self) -> RawHandle { - no_code! { - self.into_inner().into_handle().into_raw_handle() as *mut _ - } + self.into_inner().into_handle().into_raw_handle() as *mut _ } } #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for process::ChildStderr { + #[rustdoc_skip_body] fn into_raw_handle(self) -> RawHandle { - no_code! { - self.into_inner().into_handle().into_raw_handle() as *mut _ - } + self.into_inner().into_handle().into_raw_handle() as *mut _ } } @@ -138,12 +127,11 @@ impl IntoRawHandle for process::ChildStderr { /// writing from and to it is implemented using asynchronous APIs. #[stable(feature = "child_stream_from_fd", since = "1.74.0")] impl From for process::ChildStdin { + #[rustdoc_skip_body] fn from(handle: OwnedHandle) -> process::ChildStdin { - no_code! { - let handle = sys::handle::Handle::from_inner(handle); - let pipe = sys::process::ChildPipe::from_inner(handle); - process::ChildStdin::from_inner(pipe) - } + let handle = sys::handle::Handle::from_inner(handle); + let pipe = sys::process::ChildPipe::from_inner(handle); + process::ChildStdin::from_inner(pipe) } } @@ -153,12 +141,11 @@ impl From for process::ChildStdin { /// writing from and to it is implemented using asynchronous APIs. #[stable(feature = "child_stream_from_fd", since = "1.74.0")] impl From for process::ChildStdout { + #[rustdoc_skip_body] fn from(handle: OwnedHandle) -> process::ChildStdout { - no_code! { - let handle = sys::handle::Handle::from_inner(handle); - let pipe = sys::process::ChildPipe::from_inner(handle); - process::ChildStdout::from_inner(pipe) - } + let handle = sys::handle::Handle::from_inner(handle); + let pipe = sys::process::ChildPipe::from_inner(handle); + process::ChildStdout::from_inner(pipe) } } @@ -168,12 +155,11 @@ impl From for process::ChildStdout { /// writing from and to it is implemented using asynchronous APIs. #[stable(feature = "child_stream_from_fd", since = "1.74.0")] impl From for process::ChildStderr { + #[rustdoc_skip_body] fn from(handle: OwnedHandle) -> process::ChildStderr { - no_code! { - let handle = sys::handle::Handle::from_inner(handle); - let pipe = sys::process::ChildPipe::from_inner(handle); - process::ChildStderr::from_inner(pipe) - } + let handle = sys::handle::Handle::from_inner(handle); + let pipe = sys::process::ChildPipe::from_inner(handle); + process::ChildStderr::from_inner(pipe) } } @@ -188,10 +174,9 @@ pub impl(self) trait ExitStatusExt { #[stable(feature = "exit_status_from", since = "1.12.0")] impl ExitStatusExt for process::ExitStatus { + #[rustdoc_skip_body] fn from_raw(raw: u32) -> Self { - no_code! { - process::ExitStatus::from_inner(From::from(raw)) - } + process::ExitStatus::from_inner(From::from(raw)) } } @@ -422,39 +407,34 @@ pub impl(self) trait CommandExt { #[stable(feature = "windows_process_extensions", since = "1.16.0")] impl CommandExt for process::Command { + #[rustdoc_skip_body] fn creation_flags(&mut self, flags: u32) -> &mut process::Command { - no_code! { - self.as_inner_mut().creation_flags(flags); - self - } + self.as_inner_mut().creation_flags(flags); + self } + #[rustdoc_skip_body] fn desktop>(&mut self, desktop: S) -> &mut process::Command { - no_code! { - self.as_inner_mut().desktop(desktop.as_ref()); - self - } + self.as_inner_mut().desktop(desktop.as_ref()); + self } + #[rustdoc_skip_body] fn show_window(&mut self, cmd_show: u16) -> &mut process::Command { - no_code! { - self.as_inner_mut().show_window(Some(cmd_show)); - self - } + self.as_inner_mut().show_window(Some(cmd_show)); + self } + #[rustdoc_skip_body] fn force_quotes(&mut self, enabled: bool) -> &mut process::Command { - no_code! { - self.as_inner_mut().force_quotes(enabled); - self - } + self.as_inner_mut().force_quotes(enabled); + self } + #[rustdoc_skip_body] fn raw_arg>(&mut self, raw_text: S) -> &mut process::Command { - no_code! { - self.as_inner_mut().raw_arg(raw_text.as_ref()); - self - } + self.as_inner_mut().raw_arg(raw_text.as_ref()); + self } fn async_pipes(&mut self, always_async: bool) -> &mut process::Command { @@ -466,43 +446,38 @@ impl CommandExt for process::Command { self } + #[rustdoc_skip_body] fn spawn_with_attributes( &mut self, attribute_list: &ProcThreadAttributeList<'_>, ) -> io::Result { - no_code! { - self.as_inner_mut() - .spawn_with_attributes(sys::process::Stdio::Inherit, true, Some(attribute_list)) - .map(process::Child::from_inner) - } + self.as_inner_mut() + .spawn_with_attributes(sys::process::Stdio::Inherit, true, Some(attribute_list)) + .map(process::Child::from_inner) } + #[rustdoc_skip_body] fn startupinfo_fullscreen(&mut self, enabled: bool) -> &mut process::Command { - no_code! { - self.as_inner_mut().startupinfo_fullscreen(enabled); - self - } + self.as_inner_mut().startupinfo_fullscreen(enabled); + self } + #[rustdoc_skip_body] fn startupinfo_untrusted_source(&mut self, enabled: bool) -> &mut process::Command { - no_code! { - self.as_inner_mut().startupinfo_untrusted_source(enabled); - self - } + self.as_inner_mut().startupinfo_untrusted_source(enabled); + self } + #[rustdoc_skip_body] fn startupinfo_force_feedback(&mut self, enabled: Option) -> &mut process::Command { - no_code! { - self.as_inner_mut().startupinfo_force_feedback(enabled); - self - } + self.as_inner_mut().startupinfo_force_feedback(enabled); + self } + #[rustdoc_skip_body] fn inherit_handles(&mut self, inherit_handles: bool) -> &mut process::Command { - no_code! { - self.as_inner_mut().inherit_handles(inherit_handles); - self - } + self.as_inner_mut().inherit_handles(inherit_handles); + self } } @@ -515,10 +490,9 @@ pub impl(self) trait ChildExt { #[stable(feature = "windows_process_extensions_main_thread_handle", since = "1.100.0")] impl ChildExt for process::Child { + #[rustdoc_skip_body] fn main_thread_handle(&self) -> BorrowedHandle<'_> { - no_code! { - self.handle.main_thread_handle() - } + self.handle.main_thread_handle() } } @@ -537,10 +511,9 @@ pub impl(self) trait ExitCodeExt { #[stable(feature = "windows_process_exit_code_from", since = "CURRENT_RUSTC_VERSION")] impl ExitCodeExt for process::ExitCode { + #[rustdoc_skip_body] fn from_raw(raw: u32) -> Self { - no_code! { - process::ExitCode::from_inner(From::from(raw)) - } + process::ExitCode::from_inner(From::from(raw)) } } @@ -576,12 +549,11 @@ impl<'a> Drop for ProcThreadAttributeList<'a> { /// underlying attribute list. /// /// [1]: + #[rustdoc_skip_body] fn drop(&mut self) { - no_code! { - let lp_attribute_list = - self.attribute_list.as_mut_ptr().cast::(); - unsafe { sys::c::DeleteProcThreadAttributeList(lp_attribute_list) } - } + let lp_attribute_list = + self.attribute_list.as_mut_ptr().cast::(); + unsafe { sys::c::DeleteProcThreadAttributeList(lp_attribute_list) } } } @@ -724,61 +696,60 @@ impl<'a> ProcThreadAttributeListBuilder<'a> { /// /// Returns an error if the maximum number of attributes is exceeded /// or if there is an I/O error during initialization. + #[rustdoc_skip_body] pub fn finish(&self) -> io::Result> { - no_code! { - // To initialize our ProcThreadAttributeList, we need to determine - // how many bytes to allocate for it. The Windows API simplifies this - // process by allowing us to call `InitializeProcThreadAttributeList` - // with a null pointer to retrieve the required size. - let mut required_size = 0; - let Ok(attribute_count) = self.attributes.len().try_into() else { - return Err(io::const_error!( - io::ErrorKind::InvalidInput, - "maximum number of ProcThreadAttributes exceeded", - )); - }; - unsafe { - sys::c::InitializeProcThreadAttributeList( - ptr::null_mut(), - attribute_count, - 0, - &mut required_size, - ) - }; - - let mut attribute_list = vec![MaybeUninit::uninit(); required_size].into_boxed_slice(); - - // Once we've allocated the necessary memory, it's safe to invoke - // `InitializeProcThreadAttributeList` to properly initialize the list. + // To initialize our ProcThreadAttributeList, we need to determine + // how many bytes to allocate for it. The Windows API simplifies this + // process by allowing us to call `InitializeProcThreadAttributeList` + // with a null pointer to retrieve the required size. + let mut required_size = 0; + let Ok(attribute_count) = self.attributes.len().try_into() else { + return Err(io::const_error!( + io::ErrorKind::InvalidInput, + "maximum number of ProcThreadAttributes exceeded", + )); + }; + unsafe { + sys::c::InitializeProcThreadAttributeList( + ptr::null_mut(), + attribute_count, + 0, + &mut required_size, + ) + }; + + let mut attribute_list = vec![MaybeUninit::uninit(); required_size].into_boxed_slice(); + + // Once we've allocated the necessary memory, it's safe to invoke + // `InitializeProcThreadAttributeList` to properly initialize the list. + sys::cvt(unsafe { + sys::c::InitializeProcThreadAttributeList( + attribute_list.as_mut_ptr().cast::(), + attribute_count, + 0, + &mut required_size, + ) + })?; + + // # Add our attributes to the buffer. + // It's theoretically possible for the attribute count to exceed a u32 + // value. Therefore, we ensure that we don't add more attributes than + // the buffer was initialized for. + for (&attribute, value) in self.attributes.iter().take(attribute_count as usize) { sys::cvt(unsafe { - sys::c::InitializeProcThreadAttributeList( + sys::c::UpdateProcThreadAttribute( attribute_list.as_mut_ptr().cast::(), - attribute_count, 0, - &mut required_size, + attribute, + value.ptr, + value.size, + ptr::null_mut(), + ptr::null_mut(), ) })?; - - // # Add our attributes to the buffer. - // It's theoretically possible for the attribute count to exceed a u32 - // value. Therefore, we ensure that we don't add more attributes than - // the buffer was initialized for. - for (&attribute, value) in self.attributes.iter().take(attribute_count as usize) { - sys::cvt(unsafe { - sys::c::UpdateProcThreadAttribute( - attribute_list.as_mut_ptr().cast::(), - 0, - attribute, - value.ptr, - value.size, - ptr::null_mut(), - ptr::null_mut(), - ) - })?; - } - - Ok(ProcThreadAttributeList { attribute_list, _lifetime_marker: marker::PhantomData }) } + + Ok(ProcThreadAttributeList { attribute_list, _lifetime_marker: marker::PhantomData }) } } diff --git a/library/std/src/os/windows/thread.rs b/library/std/src/os/windows/thread.rs index 137afc6af1a4c..b53bd72f5d3e1 100644 --- a/library/std/src/os/windows/thread.rs +++ b/library/std/src/os/windows/thread.rs @@ -4,6 +4,7 @@ #![stable(feature = "thread_extensions", since = "1.9.0")] +use crate::macros::rustdoc_skip_body; use crate::os::windows::io::{AsRawHandle, IntoRawHandle, RawHandle}; use crate::sys::{AsInner, IntoInner}; use crate::thread; @@ -11,19 +12,17 @@ use crate::thread; #[stable(feature = "thread_extensions", since = "1.9.0")] impl AsRawHandle for thread::JoinHandle { #[inline] + #[rustdoc_skip_body] fn as_raw_handle(&self) -> RawHandle { - no_code! { - self.as_inner().handle().as_raw_handle() as *mut _ - } + self.as_inner().handle().as_raw_handle() as *mut _ } } #[stable(feature = "thread_extensions", since = "1.9.0")] impl IntoRawHandle for thread::JoinHandle { #[inline] + #[rustdoc_skip_body] fn into_raw_handle(self) -> RawHandle { - no_code! { - self.into_inner().into_handle().into_raw_handle() as *mut _ - } + self.into_inner().into_handle().into_raw_handle() as *mut _ } } diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs index 8d83bcf7e54bc..d1262ba3e2e6e 100644 --- a/library/std/src/sys/process/unix/unix.rs +++ b/library/std/src/sys/process/unix/unix.rs @@ -1304,6 +1304,7 @@ impl ExitStatusError { #[cfg(target_os = "linux")] mod linux_child_ext { use crate::io::ErrorKind; + use crate::macros::rustdoc_skip_body; use crate::os::linux::process as os; use crate::sys::{FromInner, process as imp}; use crate::{io, mem}; @@ -1319,14 +1320,13 @@ mod linux_child_ext { .ok_or_else(|| io::const_error!(ErrorKind::Uncategorized, "no pidfd was created.")) } + #[rustdoc_skip_body] fn into_pidfd(mut self) -> Result { - no_code! { - self.handle - .pidfd - .take() - .map(>::from_inner) - .ok_or_else(|| self) - } + self.handle + .pidfd + .take() + .map(>::from_inner) + .ok_or_else(|| self) } } } From df368be14964ca7280784ab4c508359cf8fc44c9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 24 Oct 2026 23:23:00 +0200 Subject: [PATCH 16/49] Disable `unused_macros` check on `rustdoc_skip_body` --- library/std/src/macros.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index 7dcdd2c6246b1..15ff7afa45818 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -471,6 +471,7 @@ macro_rules! hash_map { /// /// The function's signature must still be valid on the documentation target. #[rustc_builtin_macro] +#[allow(unused_macros)] pub(crate) macro rustdoc_skip_body($item:item) { /* compiler built-in */ } From badf74d846057e6cccf6f82048771ba78a0664bb Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Wed, 9 Sep 2026 00:17:36 +0800 Subject: [PATCH 17/49] move check_naked() from check_attr.rs to codegen_attrs.rs Signed-off-by: Richard Tjokroutomo --- compiler/rustc_ast/src/ast.rs | 19 ++++++++ .../src/attributes/codegen_attrs.rs | 46 +++++++++++++++++++ compiler/rustc_passes/src/check_attr.rs | 1 + 3 files changed, 66 insertions(+) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 53df848459e32..c178092b39995 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3949,6 +3949,25 @@ impl Extern { Extern::Implicit(span) | Extern::Explicit(_, span) => Some(span), } } + + /// An ABI "like Rust" + /// + /// These ABIs are fully controlled by the Rust compiler, which means they + /// - support unwinding with `-Cpanic=unwind`, unlike `extern "C"` + /// - often diverge from the C ABI + /// - are subject to change between compiler versions + pub fn is_rustic_abi(self) -> bool { + match self { + Extern::None => true, + Extern::Implicit(_) => false, + Extern::Explicit(name, _) => { + matches!( + name.symbol_unescaped.as_str(), + "Rust" | "rust-call" | "rust-cold" | "rust-preserve-none" | "rust-tail" + ) + } + } + } } /// A function header. diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index bd30983cd69d4..e147d785e5460 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -1,3 +1,4 @@ +use rustc_ast::ItemKind; use rustc_attr_ir::{ CoverageAttrKind, InstrumentFnAttr, OptimizeAttr, RtsanSetting, UsedBy, find_attr, }; @@ -8,6 +9,7 @@ use rustc_structures::SanitizerSet; use super::prelude::*; use crate::attributes::AttributeSafety; +use crate::context::FinalizeCheckFn; use crate::diagnostics::{ EmptyExportName, EmptySection, NakedFunctionIncompatibleAttribute, NullOnExport, NullOnObjcClass, NullOnObjcSelector, NullOnSection, ObjcClassExpectedStringLiteral, @@ -327,6 +329,50 @@ impl AttributeParser for NakedParser { Some(AttributeKind::Naked(span)) } + + fn deferred_finalize_check(&self) -> Option<(FinalizeCheckFn, Span)> { + Some(( + |cx, _| match cx.target { + Target::Fn + | Target::Method( + MethodKind::Trait { body: true } | MethodKind::TraitImpl | MethodKind::Inherent, + ) => { + let Some(item) = cx.target_item else { + return; + }; + + let ItemKind::Fn(fn_item) = &item.kind else { + return; + }; + + let fn_sig = &fn_item.sig; + let abi = fn_sig.header.ext; + + if abi.is_rustic_abi() && !cx.features().naked_functions_rustic_abi() { + let abi_type = match abi { + rustc_ast::ast::Extern::None => "Rust".into(), + rustc_ast::ast::Extern::Explicit(name, _) => { + name.symbol_unescaped.to_string() + } + rustc_ast::ast::Extern::Implicit(_) => unreachable!(), + }; + feature_err( + cx.sess(), + sym::naked_functions_rustic_abi, + fn_sig.span, + format!( + "`#[naked]` is currently unstable on `extern \"{}\"` functions", + abi_type + ), + ) + .emit(); + } + } + _ => {} + }, + self.span?, + )) + } } pub(crate) struct TrackCallerParser; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ab951a2cc1ce9..58d595914b528 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -270,6 +270,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::MoveSizeLimit { .. } => (), AttributeKind::MustNotSupend { .. } => (), AttributeKind::MustUse { .. } => (), + AttributeKind::Naked(..) => (), AttributeKind::NeedsAllocator => (), AttributeKind::NeedsPanicRuntime => (), AttributeKind::NoBuiltins => (), From 2a5584dcb007699f9a68e1acd86346114ffc7500 Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Fri, 11 Sep 2026 21:45:10 +0800 Subject: [PATCH 18/49] also consider associate item Signed-off-by: Richard Tjokroutomo --- compiler/rustc_ast_lowering/src/block.rs | 2 +- compiler/rustc_ast_lowering/src/expr.rs | 17 ++++--- .../rustc_ast_lowering/src/expr/closure.rs | 2 +- compiler/rustc_ast_lowering/src/item.rs | 20 ++++++--- compiler/rustc_ast_lowering/src/lib.rs | 20 ++++++--- compiler/rustc_ast_lowering/src/pat.rs | 2 +- .../src/attributes/codegen_attrs.rs | 45 ++++++++++++++++--- compiler/rustc_attr_parsing/src/context.rs | 4 ++ compiler/rustc_attr_parsing/src/interface.rs | 3 ++ compiler/rustc_passes/src/check_attr.rs | 27 ----------- compiler/rustc_resolve/src/def_collector.rs | 1 + 11 files changed, 90 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index b2cb1718b86a3..4e1b36c01f5af 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -104,7 +104,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }; let span = self.lower_span(l.span); let source = hir::LocalSource::Normal; - self.lower_attrs(hir_id, &l.attrs, l.span, Target::Statement); + self.lower_attrs(hir_id, &l.attrs, l.span, Target::Statement, None); self.arena.alloc(hir::LetStmt { hir_id, super_, ty, pat, init, els, span, source }) } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index c10ad4b2a398c..0839cdb7df579 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -231,7 +231,14 @@ impl<'hir> LoweringContext<'_, 'hir> { let old_attrs = self.curr_owner.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]); let new_attrs = self - .lower_attrs_vec(&e.attrs, e.span, ex.hir_id, Target::from_expr(e), None) + .lower_attrs_vec( + &e.attrs, + e.span, + ex.hir_id, + Target::from_expr(e), + None, + None, + ) .into_iter() .chain(old_attrs.iter().cloned()); let new_attrs = &*self.arena.alloc_from_iter(new_attrs); @@ -255,7 +262,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } let expr_hir_id = self.lower_node_id(e.id); - self.lower_attrs(expr_hir_id, &e.attrs, e.span, Target::from_expr(e)); + self.lower_attrs(expr_hir_id, &e.attrs, e.span, Target::from_expr(e), None); let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), @@ -795,7 +802,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let guard = arm.guard.as_ref().map(|guard| self.lower_expr(&guard.cond)); let hir_id = self.next_id(); let span = self.lower_span(arm.span); - self.lower_attrs(hir_id, &arm.attrs, arm.span, Target::Arm); + self.lower_attrs(hir_id, &arm.attrs, arm.span, Target::Arm, None); let is_never_pattern = pat.is_never_pattern(); // We need to lower the body even if it's unneeded for never pattern in match, // ensure that we can get HirId for DefId if need (issue #137708). @@ -1659,7 +1666,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> { let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField); + self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField, None); hir::ExprField { hir_id, ident: self.lower_ident(f.ident), @@ -1926,7 +1933,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // // Also, add the attributes to the outer returned expr node. let expr = self.expr_drop_temps_mut(for_span, match_expr); - self.lower_attrs(expr.hir_id, &e.attrs, e.span, Target::from_expr(e)); + self.lower_attrs(expr.hir_id, &e.attrs, e.span, Target::from_expr(e), None); expr } diff --git a/compiler/rustc_ast_lowering/src/expr/closure.rs b/compiler/rustc_ast_lowering/src/expr/closure.rs index 5924d53dd11e4..c1fd17362cd09 100644 --- a/compiler/rustc_ast_lowering/src/expr/closure.rs +++ b/compiler/rustc_ast_lowering/src/expr/closure.rs @@ -20,7 +20,7 @@ impl<'hir> LoweringContext<'_, 'hir> { closure: &Closure, ) -> hir::Expr<'hir> { let expr_hir_id = self.lower_node_id(e.id); - let attrs = self.lower_attrs(expr_hir_id, &e.attrs, e.span, Target::from_expr(e)); + let attrs = self.lower_attrs(expr_hir_id, &e.attrs, e.span, Target::from_expr(e), None); match closure.coroutine_marker { Some(coroutine_marker) => self.lower_expr_coroutine_closure_with_move_exprs( diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 296b0887f6002..47ab15b82d5ef 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -166,6 +166,7 @@ impl<'hir> LoweringContext<'_, 'hir> { i.span, Target::from_ast_item(i), Some(i), + None, &extra_hir_attributes, ); @@ -614,8 +615,13 @@ impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> { let owner_id = self.curr_owner.owner_id(); let hir_id: HirId = owner_id.into(); - let attrs = - self.lower_attrs(hir_id, &i.attrs, i.span, Target::from_foreign_item_kind(&i.kind)); + let attrs = self.lower_attrs( + hir_id, + &i.attrs, + i.span, + Target::from_foreign_item_kind(&i.kind), + None, + ); let (ident, kind) = match &i.kind { ForeignItemKind::Fn(Fn { sig, ident, generics, define_opaque, .. }) => { let fdec = &sig.decl; @@ -693,7 +699,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.dcx().span_fatal(v.span, "unnamed enum variants are not yet implemented"); } let hir_id = self.lower_node_id(v.id); - self.lower_attrs(hir_id, &v.attrs, v.span, Target::Variant); + self.lower_attrs(hir_id, &v.attrs, v.span, Target::Variant, None); hir::Variant { hir_id, def_id: self.local_def_id(v.id), @@ -780,7 +786,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let ty = self.lower_ty_alloc(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy)); let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span, Target::Field); + self.lower_attrs(hir_id, &f.attrs, f.span, Target::Field, None); hir::FieldDef { span: self.lower_span(f.span), hir_id, @@ -808,6 +814,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_assoc_item_kind(&i.kind, AssocCtxt::Trait), + Some(i), ); let (ident, generics, kind, has_value) = match &i.kind { @@ -1070,6 +1077,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_assoc_item_kind(&i.kind, AssocCtxt::Impl { of_trait: is_in_trait_impl }), + Some(i), ); let (ident, (generics, kind)) = match &i.kind { @@ -1238,7 +1246,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_param(&mut self, param: &Param) -> hir::Param<'hir> { let hir_id = self.lower_node_id(param.id); - self.lower_attrs(hir_id, ¶m.attrs, param.span, Target::Param); + self.lower_attrs(hir_id, ¶m.attrs, param.span, Target::Param, None); hir::Param { hir_id, pat: self.lower_pat(¶m.pat), @@ -1948,7 +1956,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::WherePredicate<'hir> { let hir_id = self.lower_node_id(pred.id); let span = self.lower_span(pred.span); - self.lower_attrs(hir_id, &pred.attrs, span, Target::WherePredicate); + self.lower_attrs(hir_id, &pred.attrs, span, Target::WherePredicate, None); let kind = self.arena.alloc(match &pred.kind { WherePredicateKind::BoundPredicate(WhereBoundPredicate { bound_generic_params, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index c68fcb18427c5..efd69eab11686 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1149,8 +1149,9 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: &[Attribute], target_span: Span, target: Target, + target_assoc_item: Option<&ast::AssocItem>, ) -> &'hir [rustc_attr_ir::Attribute] { - self.lower_attrs_with_extra(id, attrs, target_span, target, None, &[]) + self.lower_attrs_with_extra(id, attrs, target_span, target, None, target_assoc_item, &[]) } fn lower_attrs_with_extra( @@ -1160,13 +1161,20 @@ impl<'hir> LoweringContext<'_, 'hir> { target_span: Span, target: Target, target_item: Option<&ast::Item>, + target_assoc_item: Option<&ast::AssocItem>, extra_hir_attributes: &[rustc_attr_ir::Attribute], ) -> &'hir [rustc_attr_ir::Attribute] { if attrs.is_empty() && extra_hir_attributes.is_empty() { &[] } else { - let mut lowered_attrs = - self.lower_attrs_vec(attrs, self.lower_span(target_span), id, target, target_item); + let mut lowered_attrs = self.lower_attrs_vec( + attrs, + self.lower_span(target_span), + id, + target, + target_item, + target_assoc_item, + ); lowered_attrs.extend(extra_hir_attributes.iter().cloned()); assert_eq!(id.owner, self.curr_owner.owner_id()); @@ -1194,6 +1202,7 @@ impl<'hir> LoweringContext<'_, 'hir> { target_hir_id: HirId, target: Target, target_item: Option<&ast::Item>, + target_assoc_item: Option<&ast::AssocItem>, ) -> Vec { let l = self.span_lowerer(); self.attribute_parser.parse_attribute_list( @@ -1201,6 +1210,7 @@ impl<'hir> LoweringContext<'_, 'hir> { target_span, target, target_item, + target_assoc_item, |s| l.lower(s), |lint_id, span, kind| { self.curr_owner.delayed_lints.push(DelayedLint { @@ -2328,7 +2338,7 @@ impl<'hir> LoweringContext<'_, 'hir> { colon_span: param.colon_span.map(|s| self.lower_span(s)), source, }; - self.lower_attrs(hir_id, param_attrs, param_span, Target::from(¶m)); + self.lower_attrs(hir_id, param_attrs, param_span, Target::from(¶m), None); param } @@ -2932,7 +2942,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // FIXME(mgca): This might result in lowering attributes that // then go unused as the `Target::ExprField` is not actually // corresponding to `Node::ExprField`. - self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField); + self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField, None); let expr = self.lower_expr_to_const_arg_direct(&f.expr, None); hir::ConstArgExprField { diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index df3d7b1a3c0a6..c7a7f81a5b4d7 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -92,7 +92,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let fs = self.arena.alloc_from_iter(fields.iter().map(|f| { let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span, Target::PatField); + self.lower_attrs(hir_id, &f.attrs, f.span, Target::PatField, None); hir::PatField { hir_id, diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index e147d785e5460..a6a9e85cfabcb 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -1,4 +1,4 @@ -use rustc_ast::ItemKind; +use rustc_ast::{AssocItemKind, ItemKind}; use rustc_attr_ir::{ CoverageAttrKind, InstrumentFnAttr, OptimizeAttr, RtsanSetting, UsedBy, find_attr, }; @@ -333,16 +333,47 @@ impl AttributeParser for NakedParser { fn deferred_finalize_check(&self) -> Option<(FinalizeCheckFn, Span)> { Some(( |cx, _| match cx.target { - Target::Fn - | Target::Method( - MethodKind::Trait { body: true } | MethodKind::TraitImpl | MethodKind::Inherent, - ) => { + Target::Fn => { let Some(item) = cx.target_item else { - return; + panic!("expected struct AST target item for {:?}", cx.target); }; let ItemKind::Fn(fn_item) = &item.kind else { - return; + panic!("expected struct AST target item for {:?}", cx.target); + }; + + let fn_sig = &fn_item.sig; + let abi = fn_sig.header.ext; + + if abi.is_rustic_abi() && !cx.features().naked_functions_rustic_abi() { + let abi_type = match abi { + rustc_ast::ast::Extern::None => "Rust".into(), + rustc_ast::ast::Extern::Explicit(name, _) => { + name.symbol_unescaped.to_string() + } + rustc_ast::ast::Extern::Implicit(_) => unreachable!(), + }; + feature_err( + cx.sess(), + sym::naked_functions_rustic_abi, + fn_sig.span, + format!( + "`#[naked]` is currently unstable on `extern \"{}\"` functions", + abi_type + ), + ) + .emit(); + } + } + Target::Method( + MethodKind::Trait { body: true } | MethodKind::TraitImpl | MethodKind::Inherent, + ) => { + let Some(assoc_item) = cx.target_assoc_item else { + panic!("expected struct AST target associated item for {:?}", cx.target); + }; + + let AssocItemKind::Fn(fn_item) = &assoc_item.kind else { + panic!("expected struct AST target associated item for {:?}", cx.target); }; let fn_sig = &fn_item.sig; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index f5e1868364355..1eaa36c5bc1b8 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -867,6 +867,10 @@ pub(crate) struct FinalizeCheckContext<'p, 'sess> { /// The AST item these attributes were applied to, when the target is an item. /// Used by `finalize_check` to inspect item structure that is not encoded in [`Target`]. pub(crate) target_item: Option<&'p rustc_ast::ast::Item>, + + /// The AST associated item these attributes were applied to, when the target is an associated item. + /// Used by `finalize_check` to inspect associated item structure that is not encoded in [`Target`]. + pub(crate) target_assoc_item: Option<&'p rustc_ast::ast::AssocItem>, } impl<'p, 'sess: 'p> Deref for FinalizeCheckContext<'p, 'sess> { diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 6895dda06cb6a..d95680981e67b 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -163,6 +163,7 @@ impl<'sess> AttributeParser<'sess> { target_span, target, None, + None, std::convert::identity, |lint_id, span, kind| { sess.psess.dyn_buffer_lint_sess(lint_id.lint, span, target_node_id, kind.0) @@ -320,6 +321,7 @@ impl<'sess> AttributeParser<'sess> { target_span: Span, target: Target, target_item: Option<&ast::Item>, + target_assoc_item: Option<&ast::AssocItem>, lower_span: impl Copy + Fn(Span) -> Span, mut emit_lint: impl FnMut(LintId, MultiSpan, EmitAttribute), ) -> Vec { @@ -520,6 +522,7 @@ impl<'sess> AttributeParser<'sess> { all_attrs: &attr_paths, parsed_attrs: &attributes, target_item, + target_assoc_item, }, attr_span, ); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 58d595914b528..4c658dd946283 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -195,7 +195,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::RustcAllowConstFnUnstable(_, first_span) => { self.check_rustc_allow_const_fn_unstable(hir_id, *first_span, span, target) } - AttributeKind::Naked(..) => self.check_naked(hir_id, target), AttributeKind::MayDangle(attr_span) => self.check_may_dangle(hir_id, *attr_span), AttributeKind::Doc(attr) => self.check_doc_attrs(attr, hir_id, target), AttributeKind::EiiImpl(eii_impl) => self.check_eii_impl(eii_impl), @@ -732,32 +731,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks if `#[naked]` is applied to a function definition. - fn check_naked(&self, hir_id: HirId, target: Target) { - match target { - Target::Fn - | Target::Method( - MethodKind::Trait { body: true } | MethodKind::TraitImpl | MethodKind::Inherent, - ) => { - let fn_sig = self.tcx.hir_node(hir_id).fn_sig().unwrap(); - let abi = fn_sig.header.abi; - if abi.is_rustic_abi() && !self.tcx.features().naked_functions_rustic_abi() { - feature_err( - &self.tcx.sess, - sym::naked_functions_rustic_abi, - fn_sig.span, - format!( - "`#[naked]` is currently unstable on `extern \"{}\"` functions", - abi.as_str() - ), - ) - .emit(); - } - } - _ => {} - } - } - fn check_doc_alias_value(&self, span: Span, hir_id: HirId, target: Target, alias: Symbol) { if let Some(location) = match target { Target::AssocTy(_) => { diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 1b0045d4e02f3..e024efdab0e4a 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -184,6 +184,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { i.span, Target::MacroDef, None, + None, std::convert::identity, |_lint_id, _span, _kind| { // FIXME(jdonszelmann): emit lints here properly From 94bf10ca9c953f9162530354aec52706e1a5fd56 Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Sat, 12 Sep 2026 21:55:29 +0800 Subject: [PATCH 19/49] wrap target_item & target_assoc_item into an enum Signed-off-by: Richard Tjokroutomo --- compiler/rustc_ast/src/ast.rs | 6 ++ compiler/rustc_ast_lowering/src/expr.rs | 9 +-- compiler/rustc_ast_lowering/src/item.rs | 7 +-- compiler/rustc_ast_lowering/src/lib.rs | 16 ++--- .../src/attributes/codegen_attrs.rs | 59 ++++++------------- .../src/attributes/non_exhaustive.rs | 29 +++++---- compiler/rustc_attr_parsing/src/context.rs | 9 +-- compiler/rustc_attr_parsing/src/interface.rs | 7 +-- compiler/rustc_resolve/src/def_collector.rs | 1 - 9 files changed, 56 insertions(+), 87 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index c178092b39995..a4916c402808a 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3872,6 +3872,12 @@ impl VariantData { } } +#[derive(Clone, Copy, Debug)] +pub enum AstItemKind<'a> { + Item(&'a Item), + AssocItem(&'a Item), +} + /// An item definition. #[derive(Clone, Encodable, Decodable, Debug)] pub struct Item { diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 0839cdb7df579..62c6b8adb85eb 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -231,14 +231,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let old_attrs = self.curr_owner.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]); let new_attrs = self - .lower_attrs_vec( - &e.attrs, - e.span, - ex.hir_id, - Target::from_expr(e), - None, - None, - ) + .lower_attrs_vec(&e.attrs, e.span, ex.hir_id, Target::from_expr(e), None) .into_iter() .chain(old_attrs.iter().cloned()); let new_attrs = &*self.arena.alloc_from_iter(new_attrs); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 47ab15b82d5ef..3a628e7b4b298 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -165,8 +165,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_ast_item(i), - Some(i), - None, + Some(ast::AstItemKind::Item(i)), &extra_hir_attributes, ); @@ -814,7 +813,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_assoc_item_kind(&i.kind, AssocCtxt::Trait), - Some(i), + Some(ast::AstItemKind::AssocItem(i)), ); let (ident, generics, kind, has_value) = match &i.kind { @@ -1077,7 +1076,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_assoc_item_kind(&i.kind, AssocCtxt::Impl { of_trait: is_in_trait_impl }), - Some(i), + Some(ast::AstItemKind::AssocItem(i)), ); let (ident, (generics, kind)) = match &i.kind { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index efd69eab11686..76d8fa7d05d02 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1149,9 +1149,9 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: &[Attribute], target_span: Span, target: Target, - target_assoc_item: Option<&ast::AssocItem>, + ast_target_item: Option>, ) -> &'hir [rustc_attr_ir::Attribute] { - self.lower_attrs_with_extra(id, attrs, target_span, target, None, target_assoc_item, &[]) + self.lower_attrs_with_extra(id, attrs, target_span, target, ast_target_item, &[]) } fn lower_attrs_with_extra( @@ -1160,8 +1160,7 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: &[Attribute], target_span: Span, target: Target, - target_item: Option<&ast::Item>, - target_assoc_item: Option<&ast::AssocItem>, + ast_target_item: Option>, extra_hir_attributes: &[rustc_attr_ir::Attribute], ) -> &'hir [rustc_attr_ir::Attribute] { if attrs.is_empty() && extra_hir_attributes.is_empty() { @@ -1172,8 +1171,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_span(target_span), id, target, - target_item, - target_assoc_item, + ast_target_item, ); lowered_attrs.extend(extra_hir_attributes.iter().cloned()); @@ -1201,16 +1199,14 @@ impl<'hir> LoweringContext<'_, 'hir> { target_span: Span, target_hir_id: HirId, target: Target, - target_item: Option<&ast::Item>, - target_assoc_item: Option<&ast::AssocItem>, + ast_target_item: Option>, ) -> Vec { let l = self.span_lowerer(); self.attribute_parser.parse_attribute_list( attrs, target_span, target, - target_item, - target_assoc_item, + ast_target_item, |s| l.lower(s), |lint_id, span, kind| { self.curr_owner.delayed_lints.push(DelayedLint { diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index a6a9e85cfabcb..f1c7e5268c655 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -333,50 +333,29 @@ impl AttributeParser for NakedParser { fn deferred_finalize_check(&self) -> Option<(FinalizeCheckFn, Span)> { Some(( |cx, _| match cx.target { - Target::Fn => { - let Some(item) = cx.target_item else { - panic!("expected struct AST target item for {:?}", cx.target); - }; - - let ItemKind::Fn(fn_item) = &item.kind else { - panic!("expected struct AST target item for {:?}", cx.target); - }; - - let fn_sig = &fn_item.sig; - let abi = fn_sig.header.ext; - - if abi.is_rustic_abi() && !cx.features().naked_functions_rustic_abi() { - let abi_type = match abi { - rustc_ast::ast::Extern::None => "Rust".into(), - rustc_ast::ast::Extern::Explicit(name, _) => { - name.symbol_unescaped.to_string() - } - rustc_ast::ast::Extern::Implicit(_) => unreachable!(), - }; - feature_err( - cx.sess(), - sym::naked_functions_rustic_abi, - fn_sig.span, - format!( - "`#[naked]` is currently unstable on `extern \"{}\"` functions", - abi_type - ), - ) - .emit(); - } - } - Target::Method( + Target::Fn + | Target::Method( MethodKind::Trait { body: true } | MethodKind::TraitImpl | MethodKind::Inherent, ) => { - let Some(assoc_item) = cx.target_assoc_item else { - panic!("expected struct AST target associated item for {:?}", cx.target); - }; - - let AssocItemKind::Fn(fn_item) = &assoc_item.kind else { - panic!("expected struct AST target associated item for {:?}", cx.target); + let fn_sig = match cx.ast_target_item { + Some(rustc_ast::ast::AstItemKind::Item(ast_item)) => { + let ItemKind::Fn(fn_item) = &ast_item.kind else { + panic!("expected struct AST target item for {:?}", ast_item); + }; + &fn_item.sig + } + Some(rustc_ast::ast::AstItemKind::AssocItem(assoc_item)) => { + let AssocItemKind::Fn(fn_item) = &assoc_item.kind else { + panic!( + "expected struct AST target associated item for {:?}", + assoc_item + ); + }; + &fn_item.sig + } + _ => panic!("expected enum AST target kind for {:?}", cx.ast_target_item), }; - let fn_sig = &fn_item.sig; let abi = fn_sig.header.ext; if abi.is_rustic_abi() && !cx.features().naked_functions_rustic_abi() { diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs index 2acba84956e67..75c8e68868948 100644 --- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -1,4 +1,4 @@ -use rustc_ast::{ItemKind, VariantData}; +use rustc_ast::{AstItemKind, ItemKind, VariantData}; use rustc_feature::AttributeStability; use super::prelude::*; @@ -26,17 +26,22 @@ impl NoArgsAttributeParser for NonExhaustiveParser { return; } - let item = cx.target_item.expect("missing AST target item for Target::Struct"); - let ItemKind::Struct(_, _, data) = &item.kind else { - panic!("expected struct AST target item for Target::Struct"); - }; - if let VariantData::Struct { fields, .. } = data - && fields.iter().any(|f| f.default_value().is_some()) - { - cx.emit_err(NonExhaustiveWithDefaultFieldValues { - attr_span, - defn_span: cx.target_span, - }); + let item = cx.ast_target_item.expect("missing AST target item for Target::Struct"); + match item { + AstItemKind::Item(ast_item) => { + let ItemKind::Struct(_, _, data) = &ast_item.kind else { + panic!("expected struct AST target item for Target::Struct"); + }; + if let VariantData::Struct { fields, .. } = data + && fields.iter().any(|f| f.default_value().is_some()) + { + cx.emit_err(NonExhaustiveWithDefaultFieldValues { + attr_span, + defn_span: cx.target_span, + }); + } + } + _ => {} } } } diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 1eaa36c5bc1b8..c82783844eb39 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -864,13 +864,8 @@ pub(crate) struct FinalizeCheckContext<'p, 'sess> { /// Unlike [`all_attrs`](Self::all_attrs), this contains the fully parsed attributes. pub(crate) parsed_attrs: &'p [Attribute], - /// The AST item these attributes were applied to, when the target is an item. - /// Used by `finalize_check` to inspect item structure that is not encoded in [`Target`]. - pub(crate) target_item: Option<&'p rustc_ast::ast::Item>, - - /// The AST associated item these attributes were applied to, when the target is an associated item. - /// Used by `finalize_check` to inspect associated item structure that is not encoded in [`Target`]. - pub(crate) target_assoc_item: Option<&'p rustc_ast::ast::AssocItem>, + /// The AST item these attributes were applied to. + pub(crate) ast_target_item: Option>, } impl<'p, 'sess: 'p> Deref for FinalizeCheckContext<'p, 'sess> { diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index d95680981e67b..c30d3d9eddd9e 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -163,7 +163,6 @@ impl<'sess> AttributeParser<'sess> { target_span, target, None, - None, std::convert::identity, |lint_id, span, kind| { sess.psess.dyn_buffer_lint_sess(lint_id.lint, span, target_node_id, kind.0) @@ -320,8 +319,7 @@ impl<'sess> AttributeParser<'sess> { attrs: &[ast::Attribute], target_span: Span, target: Target, - target_item: Option<&ast::Item>, - target_assoc_item: Option<&ast::AssocItem>, + ast_target_item: Option>, lower_span: impl Copy + Fn(Span) -> Span, mut emit_lint: impl FnMut(LintId, MultiSpan, EmitAttribute), ) -> Vec { @@ -521,8 +519,7 @@ impl<'sess> AttributeParser<'sess> { }, all_attrs: &attr_paths, parsed_attrs: &attributes, - target_item, - target_assoc_item, + ast_target_item, }, attr_span, ); diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index e024efdab0e4a..1b0045d4e02f3 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -184,7 +184,6 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { i.span, Target::MacroDef, None, - None, std::convert::identity, |_lint_id, _span, _kind| { // FIXME(jdonszelmann): emit lints here properly From 4d28e20af526a0e6dfa315e84d09da6019756032 Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Sun, 13 Sep 2026 09:28:08 +0800 Subject: [PATCH 20/49] addressing review comments Signed-off-by: Richard Tjokroutomo --- compiler/rustc_ast/src/ast.rs | 25 --------- compiler/rustc_ast_lowering/src/item.rs | 7 +-- compiler/rustc_ast_lowering/src/lib.rs | 20 +++---- compiler/rustc_attr_ir/src/target.rs | 53 ++++++++++++++++++- .../src/attributes/codegen_attrs.rs | 35 +++--------- .../src/attributes/non_exhaustive.rs | 6 +-- compiler/rustc_attr_parsing/src/context.rs | 2 +- compiler/rustc_attr_parsing/src/interface.rs | 4 +- 8 files changed, 78 insertions(+), 74 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index a4916c402808a..53df848459e32 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3872,12 +3872,6 @@ impl VariantData { } } -#[derive(Clone, Copy, Debug)] -pub enum AstItemKind<'a> { - Item(&'a Item), - AssocItem(&'a Item), -} - /// An item definition. #[derive(Clone, Encodable, Decodable, Debug)] pub struct Item { @@ -3955,25 +3949,6 @@ impl Extern { Extern::Implicit(span) | Extern::Explicit(_, span) => Some(span), } } - - /// An ABI "like Rust" - /// - /// These ABIs are fully controlled by the Rust compiler, which means they - /// - support unwinding with `-Cpanic=unwind`, unlike `extern "C"` - /// - often diverge from the C ABI - /// - are subject to change between compiler versions - pub fn is_rustic_abi(self) -> bool { - match self { - Extern::None => true, - Extern::Implicit(_) => false, - Extern::Explicit(name, _) => { - matches!( - name.symbol_unescaped.as_str(), - "Rust" | "rust-call" | "rust-cold" | "rust-preserve-none" | "rust-tail" - ) - } - } - } } /// A function header. diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 3a628e7b4b298..d86b016b016a8 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1,6 +1,7 @@ use rustc_abi::ExternAbi; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; +use rustc_attr_ir::target::AstTarget; use rustc_attr_ir::target::Target; use rustc_attr_ir::{AttributeKind, EiiImplResolution, find_attr}; use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err}; @@ -165,7 +166,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_ast_item(i), - Some(ast::AstItemKind::Item(i)), + Some(AstTarget::Item(i)), &extra_hir_attributes, ); @@ -813,7 +814,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_assoc_item_kind(&i.kind, AssocCtxt::Trait), - Some(ast::AstItemKind::AssocItem(i)), + Some(AstTarget::AssocItem(i)), ); let (ident, generics, kind, has_value) = match &i.kind { @@ -1076,7 +1077,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_assoc_item_kind(&i.kind, AssocCtxt::Impl { of_trait: is_in_trait_impl }), - Some(ast::AstItemKind::AssocItem(i)), + Some(AstTarget::AssocItem(i)), ); let (ident, (generics, kind)) = match &i.kind { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 76d8fa7d05d02..0ac58ee911ab0 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -48,6 +48,7 @@ use rustc_ast::{self as ast, *}; use rustc_attr_ir::find_attr; use rustc_attr_ir::lang_items::LangItem; use rustc_attr_ir::target::Target; +use rustc_attr_ir::target::AstTarget; use rustc_attr_parsing::{AttributeParser, Recovery, ShouldEmit}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sorted_map::SortedMap; @@ -1149,9 +1150,9 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: &[Attribute], target_span: Span, target: Target, - ast_target_item: Option>, + ast_target: Option>, ) -> &'hir [rustc_attr_ir::Attribute] { - self.lower_attrs_with_extra(id, attrs, target_span, target, ast_target_item, &[]) + self.lower_attrs_with_extra(id, attrs, target_span, target, ast_target, &[]) } fn lower_attrs_with_extra( @@ -1160,19 +1161,14 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: &[Attribute], target_span: Span, target: Target, - ast_target_item: Option>, + ast_target: Option>, extra_hir_attributes: &[rustc_attr_ir::Attribute], ) -> &'hir [rustc_attr_ir::Attribute] { if attrs.is_empty() && extra_hir_attributes.is_empty() { &[] } else { - let mut lowered_attrs = self.lower_attrs_vec( - attrs, - self.lower_span(target_span), - id, - target, - ast_target_item, - ); + let mut lowered_attrs = + self.lower_attrs_vec(attrs, self.lower_span(target_span), id, target, ast_target); lowered_attrs.extend(extra_hir_attributes.iter().cloned()); assert_eq!(id.owner, self.curr_owner.owner_id()); @@ -1199,14 +1195,14 @@ impl<'hir> LoweringContext<'_, 'hir> { target_span: Span, target_hir_id: HirId, target: Target, - ast_target_item: Option>, + ast_target: Option>, ) -> Vec { let l = self.span_lowerer(); self.attribute_parser.parse_attribute_list( attrs, target_span, target, - ast_target_item, + ast_target, |s| l.lower(s), |lint_id, span, kind| { self.curr_owner.delayed_lints.push(DelayedLint { diff --git a/compiler/rustc_attr_ir/src/target.rs b/compiler/rustc_attr_ir/src/target.rs index c41e78c4a96e0..57875d915e047 100644 --- a/compiler/rustc_attr_ir/src/target.rs +++ b/compiler/rustc_attr_ir/src/target.rs @@ -2,10 +2,19 @@ use std::fmt::{self, Display}; +use rustc_abi::ExternAbi; pub use rustc_ast::visit::AssocCtxt; -use rustc_ast::{AssocItemKind, ForeignItemKind, ast}; +use rustc_ast::{AssocItemKind, ForeignItemKind, Item, ast}; use rustc_macros::StableHash; +// This enum lists all possible types of AST items. +// FIXME: Currently, this enum only lists `Item` and `AssocItem`, but in the future, be exhaustive. +#[derive(Clone, Copy, Debug)] +pub enum AstTarget<'a> { + Item(&'a Item), + AssocItem(&'a Item), +} + #[derive(Copy, Clone, PartialEq, Debug, Eq, StableHash)] pub enum MethodKind { /// Method in a `trait Trait` block @@ -65,6 +74,48 @@ pub enum Target { Break, } +impl AstTarget<'_> { + pub fn get_abi(&self) -> Option { + let ext = match self { + AstTarget::Item(item) => { + let ast::ItemKind::Fn(fn_item) = &item.kind else { + return None; + }; + fn_item.sig.header.ext + } + AstTarget::AssocItem(assoc_item) => { + let ast::AssocItemKind::Fn(fn_item) = &assoc_item.kind else { + return None; + }; + fn_item.sig.header.ext + } + }; + + match ext { + ast::Extern::None => Some(ExternAbi::Rust), + ast::Extern::Implicit(_) => Some(ExternAbi::FALLBACK), + ast::Extern::Explicit(abi, _) => Some(abi.symbol_unescaped.as_str().parse().ok()?), + } + } + + pub fn get_fn_sig(&self) -> Option<&rustc_ast::ast::FnSig> { + match self { + AstTarget::Item(item) => { + let ast::ItemKind::Fn(fn_item) = &item.kind else { + return None; + }; + Some(&fn_item.sig) + } + AstTarget::AssocItem(assoc_item) => { + let ast::AssocItemKind::Fn(fn_item) = &assoc_item.kind else { + return None; + }; + Some(&fn_item.sig) + } + } + } +} + impl Display for Target { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", Self::name(*self)) diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index f1c7e5268c655..88bfa2177c24f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -1,4 +1,3 @@ -use rustc_ast::{AssocItemKind, ItemKind}; use rustc_attr_ir::{ CoverageAttrKind, InstrumentFnAttr, OptimizeAttr, RtsanSetting, UsedBy, find_attr, }; @@ -337,42 +336,24 @@ impl AttributeParser for NakedParser { | Target::Method( MethodKind::Trait { body: true } | MethodKind::TraitImpl | MethodKind::Inherent, ) => { - let fn_sig = match cx.ast_target_item { - Some(rustc_ast::ast::AstItemKind::Item(ast_item)) => { - let ItemKind::Fn(fn_item) = &ast_item.kind else { - panic!("expected struct AST target item for {:?}", ast_item); - }; - &fn_item.sig - } - Some(rustc_ast::ast::AstItemKind::AssocItem(assoc_item)) => { - let AssocItemKind::Fn(fn_item) = &assoc_item.kind else { - panic!( - "expected struct AST target associated item for {:?}", - assoc_item - ); - }; - &fn_item.sig - } - _ => panic!("expected enum AST target kind for {:?}", cx.ast_target_item), + let Some(ast_target) = cx.ast_target else { + panic!("missing AST target for {:?}", cx.target); }; - let abi = fn_sig.header.ext; + let fn_sig = + ast_target.get_fn_sig().expect("missing fn signature for AST target"); + let Some(abi) = ast_target.get_abi() else { + return; + }; if abi.is_rustic_abi() && !cx.features().naked_functions_rustic_abi() { - let abi_type = match abi { - rustc_ast::ast::Extern::None => "Rust".into(), - rustc_ast::ast::Extern::Explicit(name, _) => { - name.symbol_unescaped.to_string() - } - rustc_ast::ast::Extern::Implicit(_) => unreachable!(), - }; feature_err( cx.sess(), sym::naked_functions_rustic_abi, fn_sig.span, format!( "`#[naked]` is currently unstable on `extern \"{}\"` functions", - abi_type + abi.as_str() ), ) .emit(); diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs index 75c8e68868948..3c8afaefa3953 100644 --- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -1,4 +1,4 @@ -use rustc_ast::{AstItemKind, ItemKind, VariantData}; +use rustc_ast::{ItemKind, VariantData}; use rustc_feature::AttributeStability; use super::prelude::*; @@ -26,9 +26,9 @@ impl NoArgsAttributeParser for NonExhaustiveParser { return; } - let item = cx.ast_target_item.expect("missing AST target item for Target::Struct"); + let item = cx.ast_target.expect("missing AST target item for Target::Struct"); match item { - AstItemKind::Item(ast_item) => { + rustc_attr_ir::target::AstTarget::Item(ast_item) => { let ItemKind::Struct(_, _, data) = &ast_item.kind else { panic!("expected struct AST target item for Target::Struct"); }; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index c82783844eb39..ba45048f4a435 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -865,7 +865,7 @@ pub(crate) struct FinalizeCheckContext<'p, 'sess> { pub(crate) parsed_attrs: &'p [Attribute], /// The AST item these attributes were applied to. - pub(crate) ast_target_item: Option>, + pub(crate) ast_target: Option>, } impl<'p, 'sess: 'p> Deref for FinalizeCheckContext<'p, 'sess> { diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index c30d3d9eddd9e..a33784d066df4 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -319,7 +319,7 @@ impl<'sess> AttributeParser<'sess> { attrs: &[ast::Attribute], target_span: Span, target: Target, - ast_target_item: Option>, + ast_target: Option>, lower_span: impl Copy + Fn(Span) -> Span, mut emit_lint: impl FnMut(LintId, MultiSpan, EmitAttribute), ) -> Vec { @@ -519,7 +519,7 @@ impl<'sess> AttributeParser<'sess> { }, all_attrs: &attr_paths, parsed_attrs: &attributes, - ast_target_item, + ast_target, }, attr_span, ); From f69f5a97a191470bb2473f5fdda329d188157e68 Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Tue, 15 Sep 2026 13:31:59 +0800 Subject: [PATCH 21/49] exhaust all possible types of AST Target (obtained from grepping all functions calling lower_attrs() Signed-off-by: Richard Tjokroutomo --- compiler/rustc_ast_lowering/src/block.rs | 8 +++- compiler/rustc_ast_lowering/src/expr.rs | 18 ++++++--- .../rustc_ast_lowering/src/expr/closure.rs | 8 +++- compiler/rustc_ast_lowering/src/item.rs | 25 +++++++----- compiler/rustc_ast_lowering/src/lib.rs | 37 +++++++++++++----- compiler/rustc_ast_lowering/src/pat.rs | 8 +++- compiler/rustc_attr_ir/src/target.rs | 38 +++++++++++++++++-- .../src/attributes/codegen_attrs.rs | 8 +--- .../src/attributes/non_exhaustive.rs | 3 +- compiler/rustc_attr_parsing/src/context.rs | 2 +- compiler/rustc_attr_parsing/src/interface.rs | 4 +- compiler/rustc_resolve/src/def_collector.rs | 2 +- 12 files changed, 117 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 4e1b36c01f5af..0ebc9c1533b2f 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -104,7 +104,13 @@ impl<'hir> LoweringContext<'_, 'hir> { }; let span = self.lower_span(l.span); let source = hir::LocalSource::Normal; - self.lower_attrs(hir_id, &l.attrs, l.span, Target::Statement, None); + self.lower_attrs( + hir_id, + &l.attrs, + l.span, + Target::Statement, + rustc_attr_ir::target::AstTarget::Local(l), + ); self.arena.alloc(hir::LetStmt { hir_id, super_, ty, pat, init, els, span, source }) } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 62c6b8adb85eb..55a39a6a5497a 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -6,7 +6,7 @@ use rustc_ast::node_id::NodeMap; use rustc_ast::visit::{Visitor, walk_expr}; use rustc_ast::*; use rustc_attr_ir::lang_items::LangItem; -use rustc_attr_ir::target::Target; +use rustc_attr_ir::target::{AstTarget, Target}; use rustc_errors::msg; use rustc_hir as hir; use rustc_hir::HirId; @@ -231,7 +231,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let old_attrs = self.curr_owner.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]); let new_attrs = self - .lower_attrs_vec(&e.attrs, e.span, ex.hir_id, Target::from_expr(e), None) + .lower_attrs_vec( + &e.attrs, + e.span, + ex.hir_id, + Target::from_expr(e), + AstTarget::None, + ) .into_iter() .chain(old_attrs.iter().cloned()); let new_attrs = &*self.arena.alloc_from_iter(new_attrs); @@ -255,7 +261,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } let expr_hir_id = self.lower_node_id(e.id); - self.lower_attrs(expr_hir_id, &e.attrs, e.span, Target::from_expr(e), None); + self.lower_attrs(expr_hir_id, &e.attrs, e.span, Target::from_expr(e), AstTarget::Expr(e)); let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), @@ -795,7 +801,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let guard = arm.guard.as_ref().map(|guard| self.lower_expr(&guard.cond)); let hir_id = self.next_id(); let span = self.lower_span(arm.span); - self.lower_attrs(hir_id, &arm.attrs, arm.span, Target::Arm, None); + self.lower_attrs(hir_id, &arm.attrs, arm.span, Target::Arm, AstTarget::Arm(arm)); let is_never_pattern = pat.is_never_pattern(); // We need to lower the body even if it's unneeded for never pattern in match, // ensure that we can get HirId for DefId if need (issue #137708). @@ -1659,7 +1665,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> { let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField, None); + self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField, AstTarget::ExprField(f)); hir::ExprField { hir_id, ident: self.lower_ident(f.ident), @@ -1926,7 +1932,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // // Also, add the attributes to the outer returned expr node. let expr = self.expr_drop_temps_mut(for_span, match_expr); - self.lower_attrs(expr.hir_id, &e.attrs, e.span, Target::from_expr(e), None); + self.lower_attrs(expr.hir_id, &e.attrs, e.span, Target::from_expr(e), AstTarget::Expr(e)); expr } diff --git a/compiler/rustc_ast_lowering/src/expr/closure.rs b/compiler/rustc_ast_lowering/src/expr/closure.rs index c1fd17362cd09..99ac5d1743731 100644 --- a/compiler/rustc_ast_lowering/src/expr/closure.rs +++ b/compiler/rustc_ast_lowering/src/expr/closure.rs @@ -20,7 +20,13 @@ impl<'hir> LoweringContext<'_, 'hir> { closure: &Closure, ) -> hir::Expr<'hir> { let expr_hir_id = self.lower_node_id(e.id); - let attrs = self.lower_attrs(expr_hir_id, &e.attrs, e.span, Target::from_expr(e), None); + let attrs = self.lower_attrs( + expr_hir_id, + &e.attrs, + e.span, + Target::from_expr(e), + rustc_attr_ir::target::AstTarget::Closure(closure), + ); match closure.coroutine_marker { Some(coroutine_marker) => self.lower_expr_coroutine_closure_with_move_exprs( diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index d86b016b016a8..115a8df73c9a5 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1,8 +1,7 @@ use rustc_abi::ExternAbi; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; -use rustc_attr_ir::target::AstTarget; -use rustc_attr_ir::target::Target; +use rustc_attr_ir::target::{AstTarget, Target}; use rustc_attr_ir::{AttributeKind, EiiImplResolution, find_attr}; use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err}; use rustc_hir::def::{DefKind, Res}; @@ -166,7 +165,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_ast_item(i), - Some(AstTarget::Item(i)), + AstTarget::Item(i), &extra_hir_attributes, ); @@ -620,7 +619,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_foreign_item_kind(&i.kind), - None, + AstTarget::ForeignItem(i), ); let (ident, kind) = match &i.kind { ForeignItemKind::Fn(Fn { sig, ident, generics, define_opaque, .. }) => { @@ -699,7 +698,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.dcx().span_fatal(v.span, "unnamed enum variants are not yet implemented"); } let hir_id = self.lower_node_id(v.id); - self.lower_attrs(hir_id, &v.attrs, v.span, Target::Variant, None); + self.lower_attrs(hir_id, &v.attrs, v.span, Target::Variant, AstTarget::Variant(v)); hir::Variant { hir_id, def_id: self.local_def_id(v.id), @@ -786,7 +785,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let ty = self.lower_ty_alloc(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy)); let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span, Target::Field, None); + self.lower_attrs(hir_id, &f.attrs, f.span, Target::Field, AstTarget::FieldDef(f)); hir::FieldDef { span: self.lower_span(f.span), hir_id, @@ -814,7 +813,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_assoc_item_kind(&i.kind, AssocCtxt::Trait), - Some(AstTarget::AssocItem(i)), + AstTarget::AssocItem(i), ); let (ident, generics, kind, has_value) = match &i.kind { @@ -1077,7 +1076,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_assoc_item_kind(&i.kind, AssocCtxt::Impl { of_trait: is_in_trait_impl }), - Some(AstTarget::AssocItem(i)), + AstTarget::AssocItem(i), ); let (ident, (generics, kind)) = match &i.kind { @@ -1246,7 +1245,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_param(&mut self, param: &Param) -> hir::Param<'hir> { let hir_id = self.lower_node_id(param.id); - self.lower_attrs(hir_id, ¶m.attrs, param.span, Target::Param, None); + self.lower_attrs(hir_id, ¶m.attrs, param.span, Target::Param, AstTarget::Param(param)); hir::Param { hir_id, pat: self.lower_pat(¶m.pat), @@ -1956,7 +1955,13 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::WherePredicate<'hir> { let hir_id = self.lower_node_id(pred.id); let span = self.lower_span(pred.span); - self.lower_attrs(hir_id, &pred.attrs, span, Target::WherePredicate, None); + self.lower_attrs( + hir_id, + &pred.attrs, + span, + Target::WherePredicate, + AstTarget::WherePredicate(pred), + ); let kind = self.arena.alloc(match &pred.kind { WherePredicateKind::BoundPredicate(WhereBoundPredicate { bound_generic_params, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 0ac58ee911ab0..7bb0b044d3e79 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -47,8 +47,7 @@ use rustc_ast::visit::{self, Visitor}; use rustc_ast::{self as ast, *}; use rustc_attr_ir::find_attr; use rustc_attr_ir::lang_items::LangItem; -use rustc_attr_ir::target::Target; -use rustc_attr_ir::target::AstTarget; +use rustc_attr_ir::target::{AstTarget, Target}; use rustc_attr_parsing::{AttributeParser, Recovery, ShouldEmit}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sorted_map::SortedMap; @@ -763,7 +762,13 @@ fn lower_to_hir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::MaybeOwner<'_> { AstOwner::Crate(c) => with_lctx(tcx, &*resolver, CRATE_NODE_ID, |lctx| { debug_assert_eq!(lctx.curr_owner.owner_id(), CRATE_OWNER_ID); let module = lctx.lower_mod(&c.items, &c.spans); - lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs, c.spans.inner_span, Target::Crate); + lctx.lower_attrs( + hir::CRATE_HIR_ID, + &c.attrs, + c.spans.inner_span, + Target::Crate, + AstTarget::Crate(c), + ); hir::OwnerNode::Crate(module) }), AstOwner::Item(item) => { @@ -1150,7 +1155,7 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: &[Attribute], target_span: Span, target: Target, - ast_target: Option>, + ast_target: AstTarget<'_>, ) -> &'hir [rustc_attr_ir::Attribute] { self.lower_attrs_with_extra(id, attrs, target_span, target, ast_target, &[]) } @@ -1161,7 +1166,7 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: &[Attribute], target_span: Span, target: Target, - ast_target: Option>, + ast_target: AstTarget<'_>, extra_hir_attributes: &[rustc_attr_ir::Attribute], ) -> &'hir [rustc_attr_ir::Attribute] { if attrs.is_empty() && extra_hir_attributes.is_empty() { @@ -1195,7 +1200,7 @@ impl<'hir> LoweringContext<'_, 'hir> { target_span: Span, target_hir_id: HirId, target: Target, - ast_target: Option>, + ast_target: AstTarget<'_>, ) -> Vec { let l = self.span_lowerer(); self.attribute_parser.parse_attribute_list( @@ -2320,7 +2325,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let hir_id = self.lower_node_id(param.id); let param_attrs = ¶m.attrs; let param_span = param.span(); - let param = hir::GenericParam { + let param_hir = hir::GenericParam { hir_id, def_id: self.local_def_id(param.id), name, @@ -2330,8 +2335,14 @@ impl<'hir> LoweringContext<'_, 'hir> { colon_span: param.colon_span.map(|s| self.lower_span(s)), source, }; - self.lower_attrs(hir_id, param_attrs, param_span, Target::from(¶m), None); - param + self.lower_attrs( + hir_id, + param_attrs, + param_span, + Target::from(¶m_hir), + AstTarget::GenericParam(param), + ); + param_hir } fn lower_generic_param_kind( @@ -2934,7 +2945,13 @@ impl<'hir> LoweringContext<'_, 'hir> { // FIXME(mgca): This might result in lowering attributes that // then go unused as the `Target::ExprField` is not actually // corresponding to `Node::ExprField`. - self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField, None); + self.lower_attrs( + hir_id, + &f.attrs, + f.span, + Target::ExprField, + AstTarget::Expr(expr), + ); let expr = self.lower_expr_to_const_arg_direct(&f.expr, None); hir::ConstArgExprField { diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index c7a7f81a5b4d7..2f2c5d7747269 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -92,7 +92,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let fs = self.arena.alloc_from_iter(fields.iter().map(|f| { let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span, Target::PatField, None); + self.lower_attrs( + hir_id, + &f.attrs, + f.span, + Target::PatField, + rustc_attr_ir::target::AstTarget::Pat(pattern), + ); hir::PatField { hir_id, diff --git a/compiler/rustc_attr_ir/src/target.rs b/compiler/rustc_attr_ir/src/target.rs index 57875d915e047..1ebe105203b14 100644 --- a/compiler/rustc_attr_ir/src/target.rs +++ b/compiler/rustc_attr_ir/src/target.rs @@ -4,15 +4,33 @@ use std::fmt::{self, Display}; use rustc_abi::ExternAbi; pub use rustc_ast::visit::AssocCtxt; -use rustc_ast::{AssocItemKind, ForeignItemKind, Item, ast}; +use rustc_ast::{ + Arm, AssocItemKind, Closure, Crate, Expr, ExprField, FieldDef, ForeignItemKind, GenericParam, + Item, Local, Param, Pat, Variant, WherePredicate, ast, +}; use rustc_macros::StableHash; // This enum lists all possible types of AST items. -// FIXME: Currently, this enum only lists `Item` and `AssocItem`, but in the future, be exhaustive. #[derive(Clone, Copy, Debug)] pub enum AstTarget<'a> { - Item(&'a Item), AssocItem(&'a Item), + ForeignItem(&'a Item), + Item(&'a Item), + + Arm(&'a Arm), + Closure(&'a Closure), + Crate(&'a Crate), + Expr(&'a Expr), + ExprField(&'a ExprField), + FieldDef(&'a FieldDef), + GenericParam(&'a GenericParam), + Local(&'a Local), + Param(&'a Param), + Pat(&'a Pat), + Variant(&'a Variant), + WherePredicate(&'a WherePredicate), + + None, // Used when it is not possible to get detailed information about the target. } #[derive(Copy, Clone, PartialEq, Debug, Eq, StableHash)] @@ -89,6 +107,13 @@ impl AstTarget<'_> { }; fn_item.sig.header.ext } + AstTarget::ForeignItem(foreign_item) => { + let ast::ForeignItemKind::Fn(fn_item) = &foreign_item.kind else { + return None; + }; + fn_item.sig.header.ext + } + _ => return None, }; match ext { @@ -112,6 +137,13 @@ impl AstTarget<'_> { }; Some(&fn_item.sig) } + AstTarget::ForeignItem(foreign_item) => { + let ast::ForeignItemKind::Fn(fn_item) = &foreign_item.kind else { + return None; + }; + Some(&fn_item.sig) + } + _ => None, } } } diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 88bfa2177c24f..f5dffe1291368 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -336,13 +336,9 @@ impl AttributeParser for NakedParser { | Target::Method( MethodKind::Trait { body: true } | MethodKind::TraitImpl | MethodKind::Inherent, ) => { - let Some(ast_target) = cx.ast_target else { - panic!("missing AST target for {:?}", cx.target); - }; - let fn_sig = - ast_target.get_fn_sig().expect("missing fn signature for AST target"); - let Some(abi) = ast_target.get_abi() else { + cx.ast_target.get_fn_sig().expect("missing fn signature for AST target"); + let Some(abi) = cx.ast_target.get_abi() else { return; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs index 3c8afaefa3953..d85c37953103d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -26,8 +26,7 @@ impl NoArgsAttributeParser for NonExhaustiveParser { return; } - let item = cx.ast_target.expect("missing AST target item for Target::Struct"); - match item { + match cx.ast_target { rustc_attr_ir::target::AstTarget::Item(ast_item) => { let ItemKind::Struct(_, _, data) = &ast_item.kind else { panic!("expected struct AST target item for Target::Struct"); diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index ba45048f4a435..172973633af4e 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -865,7 +865,7 @@ pub(crate) struct FinalizeCheckContext<'p, 'sess> { pub(crate) parsed_attrs: &'p [Attribute], /// The AST item these attributes were applied to. - pub(crate) ast_target: Option>, + pub(crate) ast_target: rustc_attr_ir::target::AstTarget<'p>, } impl<'p, 'sess: 'p> Deref for FinalizeCheckContext<'p, 'sess> { diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index a33784d066df4..36543a0623027 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -162,7 +162,7 @@ impl<'sess> AttributeParser<'sess> { attrs, target_span, target, - None, + rustc_attr_ir::target::AstTarget::None, std::convert::identity, |lint_id, span, kind| { sess.psess.dyn_buffer_lint_sess(lint_id.lint, span, target_node_id, kind.0) @@ -319,7 +319,7 @@ impl<'sess> AttributeParser<'sess> { attrs: &[ast::Attribute], target_span: Span, target: Target, - ast_target: Option>, + ast_target: rustc_attr_ir::target::AstTarget<'_>, lower_span: impl Copy + Fn(Span) -> Span, mut emit_lint: impl FnMut(LintId, MultiSpan, EmitAttribute), ) -> Vec { diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 1b0045d4e02f3..ef848822b32df 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -183,7 +183,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { &i.attrs, i.span, Target::MacroDef, - None, + rustc_attr_ir::target::AstTarget::Item(i), std::convert::identity, |_lint_id, _span, _kind| { // FIXME(jdonszelmann): emit lints here properly From 436ac66526c53ce2e8cb0ae720586a7acce11a78 Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Sun, 27 Sep 2026 10:29:57 +0800 Subject: [PATCH 22/49] addressing comments & fixing code after 0929 rebase Signed-off-by: Richard Tjokroutomo --- compiler/rustc_ast_lowering/src/item.rs | 8 +-- compiler/rustc_attr_ir/src/target.rs | 55 +++++-------------- .../src/attributes/codegen_attrs.rs | 3 +- .../src/attributes/link_attrs.rs | 37 ++++++------- .../src/attributes/non_exhaustive.rs | 7 +-- compiler/rustc_resolve/src/def_collector.rs | 2 +- 6 files changed, 40 insertions(+), 72 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 115a8df73c9a5..cb2b7f1f46db6 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -165,7 +165,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_ast_item(i), - AstTarget::Item(i), + AstTarget::Item(&i.kind), &extra_hir_attributes, ); @@ -619,7 +619,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_foreign_item_kind(&i.kind), - AstTarget::ForeignItem(i), + AstTarget::ForeignItem(&i.kind), ); let (ident, kind) = match &i.kind { ForeignItemKind::Fn(Fn { sig, ident, generics, define_opaque, .. }) => { @@ -813,7 +813,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_assoc_item_kind(&i.kind, AssocCtxt::Trait), - AstTarget::AssocItem(i), + AstTarget::AssocItem(&i.kind), ); let (ident, generics, kind, has_value) = match &i.kind { @@ -1076,7 +1076,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_assoc_item_kind(&i.kind, AssocCtxt::Impl { of_trait: is_in_trait_impl }), - AstTarget::AssocItem(i), + AstTarget::AssocItem(&i.kind), ); let (ident, (generics, kind)) = match &i.kind { diff --git a/compiler/rustc_attr_ir/src/target.rs b/compiler/rustc_attr_ir/src/target.rs index 1ebe105203b14..7be670b20b2ca 100644 --- a/compiler/rustc_attr_ir/src/target.rs +++ b/compiler/rustc_attr_ir/src/target.rs @@ -6,16 +6,16 @@ use rustc_abi::ExternAbi; pub use rustc_ast::visit::AssocCtxt; use rustc_ast::{ Arm, AssocItemKind, Closure, Crate, Expr, ExprField, FieldDef, ForeignItemKind, GenericParam, - Item, Local, Param, Pat, Variant, WherePredicate, ast, + ItemKind, Local, Param, Pat, Variant, WherePredicate, ast, }; use rustc_macros::StableHash; -// This enum lists all possible types of AST items. +/// This enum lists all possible types of AST items. #[derive(Clone, Copy, Debug)] pub enum AstTarget<'a> { - AssocItem(&'a Item), - ForeignItem(&'a Item), - Item(&'a Item), + AssocItem(&'a AssocItemKind), + ForeignItem(&'a ForeignItemKind), + Item(&'a ItemKind), Arm(&'a Arm), Closure(&'a Closure), @@ -30,7 +30,8 @@ pub enum AstTarget<'a> { Variant(&'a Variant), WherePredicate(&'a WherePredicate), - None, // Used when it is not possible to get detailed information about the target. + /// Used when it is not possible to get detailed information about the target. + None, } #[derive(Copy, Clone, PartialEq, Debug, Eq, StableHash)] @@ -95,24 +96,9 @@ pub enum Target { impl AstTarget<'_> { pub fn get_abi(&self) -> Option { let ext = match self { - AstTarget::Item(item) => { - let ast::ItemKind::Fn(fn_item) = &item.kind else { - return None; - }; - fn_item.sig.header.ext - } - AstTarget::AssocItem(assoc_item) => { - let ast::AssocItemKind::Fn(fn_item) = &assoc_item.kind else { - return None; - }; - fn_item.sig.header.ext - } - AstTarget::ForeignItem(foreign_item) => { - let ast::ForeignItemKind::Fn(fn_item) = &foreign_item.kind else { - return None; - }; - fn_item.sig.header.ext - } + AstTarget::Item(ast::ItemKind::Fn(fn_item)) => fn_item.sig.header.ext, + AstTarget::AssocItem(ast::AssocItemKind::Fn(fn_item)) => fn_item.sig.header.ext, + AstTarget::ForeignItem(ast::ForeignItemKind::Fn(fn_item)) => fn_item.sig.header.ext, _ => return None, }; @@ -125,24 +111,9 @@ impl AstTarget<'_> { pub fn get_fn_sig(&self) -> Option<&rustc_ast::ast::FnSig> { match self { - AstTarget::Item(item) => { - let ast::ItemKind::Fn(fn_item) = &item.kind else { - return None; - }; - Some(&fn_item.sig) - } - AstTarget::AssocItem(assoc_item) => { - let ast::AssocItemKind::Fn(fn_item) = &assoc_item.kind else { - return None; - }; - Some(&fn_item.sig) - } - AstTarget::ForeignItem(foreign_item) => { - let ast::ForeignItemKind::Fn(fn_item) = &foreign_item.kind else { - return None; - }; - Some(&fn_item.sig) - } + AstTarget::Item(ast::ItemKind::Fn(fn_item)) => Some(&fn_item.sig), + AstTarget::AssocItem(ast::AssocItemKind::Fn(fn_item)) => Some(&fn_item.sig), + AstTarget::ForeignItem(ast::ForeignItemKind::Fn(fn_item)) => Some(&fn_item.sig), _ => None, } } diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index f5dffe1291368..992fcfcc556ae 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -348,8 +348,7 @@ impl AttributeParser for NakedParser { sym::naked_functions_rustic_abi, fn_sig.span, format!( - "`#[naked]` is currently unstable on `extern \"{}\"` functions", - abi.as_str() + "`#[naked]` is currently unstable on `extern {abi}` functions", ), ) .emit(); diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index ed911a63eb7fe..ba9f6be111f47 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -262,25 +262,24 @@ impl CombineAttributeParser for LinkParser { } fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { - if cx.target != Target::ForeignMod { - return; - } - - let item = cx.target_item.expect("missing AST target item for Target::ForeignMod"); - let ItemKind::ForeignMod(fm) = &item.kind else { - panic!("expected foreign module AST target item for Target::ForeignMod"); - }; - let abi = fm.abi.map_or(ExternAbi::FALLBACK, |abi| { - abi.symbol_unescaped.as_str().parse().unwrap_or_else(|_| { - cx.dcx().span_delayed_bug( - abi.span, - "LinkParser::finalize_check was unable to pre-detect the ABI, so it continues to use the recovery value solely to check for unused_attributes in the lint; a user error E0703 will be reported later in lower_abi", - ); - ExternAbi::Rust - }) - }); - if matches!(abi, ExternAbi::Rust) { - cx.emit_lint(UNUSED_ATTRIBUTES, Link, attr_span); + match cx.ast_target { + rustc_attr_ir::target::AstTarget::Item(ast_item) + if let ItemKind::ForeignMod(fm) = &ast_item => + { + let abi = fm.abi.map_or(ExternAbi::FALLBACK, |abi| { + abi.symbol_unescaped.as_str().parse().unwrap_or_else(|_| { + cx.dcx().span_delayed_bug( + abi.span, + "LinkParser::finalize_check was unable to pre-detect the ABI, so it continues to use the recovery value solely to check for unused_attributes in the lint; a user error E0703 will be reported later in lower_abi", + ); + ExternAbi::Rust + }) + }); + if matches!(abi, ExternAbi::Rust) { + cx.emit_lint(UNUSED_ATTRIBUTES, Link, attr_span); + } + } + _ => {} } } } diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs index d85c37953103d..1a3db27763577 100644 --- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -27,10 +27,9 @@ impl NoArgsAttributeParser for NonExhaustiveParser { } match cx.ast_target { - rustc_attr_ir::target::AstTarget::Item(ast_item) => { - let ItemKind::Struct(_, _, data) = &ast_item.kind else { - panic!("expected struct AST target item for Target::Struct"); - }; + rustc_attr_ir::target::AstTarget::Item(ast_item) + if let ItemKind::Struct(_, _, data) = &ast_item => + { if let VariantData::Struct { fields, .. } = data && fields.iter().any(|f| f.default_value().is_some()) { diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index ef848822b32df..1caa032871e38 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -183,7 +183,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { &i.attrs, i.span, Target::MacroDef, - rustc_attr_ir::target::AstTarget::Item(i), + rustc_attr_ir::target::AstTarget::Item(&i.kind), std::convert::identity, |_lint_id, _span, _kind| { // FIXME(jdonszelmann): emit lints here properly From 030e2e7a0b26384f4cde04f4ab6117b1d2f88eb8 Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Thu, 1 Oct 2026 15:42:45 +0800 Subject: [PATCH 23/49] make AstTarget map 1-1 with Target Signed-off-by: Richard Tjokroutomo --- compiler/rustc_ast_lowering/src/block.rs | 2 +- compiler/rustc_ast_lowering/src/expr.rs | 28 ++- .../rustc_ast_lowering/src/expr/closure.rs | 2 +- compiler/rustc_ast_lowering/src/item.rs | 22 +- compiler/rustc_ast_lowering/src/lib.rs | 6 +- compiler/rustc_ast_lowering/src/pat.rs | 2 +- compiler/rustc_attr_ir/src/target.rs | 216 ++++++++++++++++-- .../src/attributes/codegen_attrs.rs | 3 + .../src/attributes/link_attrs.rs | 5 +- .../src/attributes/macro_attrs.rs | 20 +- .../src/attributes/non_exhaustive.rs | 5 +- compiler/rustc_attr_parsing/src/interface.rs | 2 +- compiler/rustc_resolve/src/def_collector.rs | 2 +- 13 files changed, 256 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 0ebc9c1533b2f..cffd17bc16cee 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -109,7 +109,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &l.attrs, l.span, Target::Statement, - rustc_attr_ir::target::AstTarget::Local(l), + rustc_attr_ir::target::AstTarget::Local(Some(l)), ); self.arena.alloc(hir::LetStmt { hir_id, super_, ty, pat, init, els, span, source }) } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 55a39a6a5497a..941f54dc259c4 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -236,7 +236,7 @@ impl<'hir> LoweringContext<'_, 'hir> { e.span, ex.hir_id, Target::from_expr(e), - AstTarget::None, + AstTarget::from(Target::from_expr(e)), ) .into_iter() .chain(old_attrs.iter().cloned()); @@ -261,7 +261,13 @@ impl<'hir> LoweringContext<'_, 'hir> { } let expr_hir_id = self.lower_node_id(e.id); - self.lower_attrs(expr_hir_id, &e.attrs, e.span, Target::from_expr(e), AstTarget::Expr(e)); + self.lower_attrs( + expr_hir_id, + &e.attrs, + e.span, + Target::from_expr(e), + AstTarget::Expression(Some(e)), + ); let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), @@ -801,7 +807,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let guard = arm.guard.as_ref().map(|guard| self.lower_expr(&guard.cond)); let hir_id = self.next_id(); let span = self.lower_span(arm.span); - self.lower_attrs(hir_id, &arm.attrs, arm.span, Target::Arm, AstTarget::Arm(arm)); + self.lower_attrs(hir_id, &arm.attrs, arm.span, Target::Arm, AstTarget::Arm(Some(arm))); let is_never_pattern = pat.is_never_pattern(); // We need to lower the body even if it's unneeded for never pattern in match, // ensure that we can get HirId for DefId if need (issue #137708). @@ -1665,7 +1671,13 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> { let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField, AstTarget::ExprField(f)); + self.lower_attrs( + hir_id, + &f.attrs, + f.span, + Target::ExprField, + AstTarget::ExprField(Some(f)), + ); hir::ExprField { hir_id, ident: self.lower_ident(f.ident), @@ -1932,7 +1944,13 @@ impl<'hir> LoweringContext<'_, 'hir> { // // Also, add the attributes to the outer returned expr node. let expr = self.expr_drop_temps_mut(for_span, match_expr); - self.lower_attrs(expr.hir_id, &e.attrs, e.span, Target::from_expr(e), AstTarget::Expr(e)); + self.lower_attrs( + expr.hir_id, + &e.attrs, + e.span, + Target::from_expr(e), + AstTarget::Expression(Some(e)), + ); expr } diff --git a/compiler/rustc_ast_lowering/src/expr/closure.rs b/compiler/rustc_ast_lowering/src/expr/closure.rs index 99ac5d1743731..4d948db3c38b5 100644 --- a/compiler/rustc_ast_lowering/src/expr/closure.rs +++ b/compiler/rustc_ast_lowering/src/expr/closure.rs @@ -25,7 +25,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &e.attrs, e.span, Target::from_expr(e), - rustc_attr_ir::target::AstTarget::Closure(closure), + rustc_attr_ir::target::AstTarget::Closure(Some(closure)), ); match closure.coroutine_marker { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index cb2b7f1f46db6..4ac1187d19a44 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -165,7 +165,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_ast_item(i), - AstTarget::Item(&i.kind), + AstTarget::from_ast_item(&i.kind), &extra_hir_attributes, ); @@ -619,7 +619,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_foreign_item_kind(&i.kind), - AstTarget::ForeignItem(&i.kind), + AstTarget::from_foreign_item_kind(&i.kind), ); let (ident, kind) = match &i.kind { ForeignItemKind::Fn(Fn { sig, ident, generics, define_opaque, .. }) => { @@ -698,7 +698,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.dcx().span_fatal(v.span, "unnamed enum variants are not yet implemented"); } let hir_id = self.lower_node_id(v.id); - self.lower_attrs(hir_id, &v.attrs, v.span, Target::Variant, AstTarget::Variant(v)); + self.lower_attrs(hir_id, &v.attrs, v.span, Target::Variant, AstTarget::Variant(Some(v))); hir::Variant { hir_id, def_id: self.local_def_id(v.id), @@ -785,7 +785,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let ty = self.lower_ty_alloc(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy)); let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span, Target::Field, AstTarget::FieldDef(f)); + self.lower_attrs(hir_id, &f.attrs, f.span, Target::Field, AstTarget::Field(Some(f))); hir::FieldDef { span: self.lower_span(f.span), hir_id, @@ -813,7 +813,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_assoc_item_kind(&i.kind, AssocCtxt::Trait), - AstTarget::AssocItem(&i.kind), + AstTarget::from_assoc_item_kind(&i.kind), ); let (ident, generics, kind, has_value) = match &i.kind { @@ -1076,7 +1076,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_assoc_item_kind(&i.kind, AssocCtxt::Impl { of_trait: is_in_trait_impl }), - AstTarget::AssocItem(&i.kind), + AstTarget::from_assoc_item_kind(&i.kind), ); let (ident, (generics, kind)) = match &i.kind { @@ -1245,7 +1245,13 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_param(&mut self, param: &Param) -> hir::Param<'hir> { let hir_id = self.lower_node_id(param.id); - self.lower_attrs(hir_id, ¶m.attrs, param.span, Target::Param, AstTarget::Param(param)); + self.lower_attrs( + hir_id, + ¶m.attrs, + param.span, + Target::Param, + AstTarget::Param(Some(param)), + ); hir::Param { hir_id, pat: self.lower_pat(¶m.pat), @@ -1960,7 +1966,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &pred.attrs, span, Target::WherePredicate, - AstTarget::WherePredicate(pred), + AstTarget::WherePredicate(Some(pred)), ); let kind = self.arena.alloc(match &pred.kind { WherePredicateKind::BoundPredicate(WhereBoundPredicate { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 7bb0b044d3e79..2b575ddc0ed84 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -767,7 +767,7 @@ fn lower_to_hir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::MaybeOwner<'_> { &c.attrs, c.spans.inner_span, Target::Crate, - AstTarget::Crate(c), + AstTarget::Crate(Some(c)), ); hir::OwnerNode::Crate(module) }), @@ -2340,7 +2340,7 @@ impl<'hir> LoweringContext<'_, 'hir> { param_attrs, param_span, Target::from(¶m_hir), - AstTarget::GenericParam(param), + AstTarget::GenericParam(Some(param)), ); param_hir } @@ -2950,7 +2950,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &f.attrs, f.span, Target::ExprField, - AstTarget::Expr(expr), + AstTarget::Expression(Some(expr)), ); let expr = self.lower_expr_to_const_arg_direct(&f.expr, None); diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 2f2c5d7747269..d854b4db64d37 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -97,7 +97,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &f.attrs, f.span, Target::PatField, - rustc_attr_ir::target::AstTarget::Pat(pattern), + rustc_attr_ir::target::AstTarget::Pat(Some(pattern)), ); hir::PatField { diff --git a/compiler/rustc_attr_ir/src/target.rs b/compiler/rustc_attr_ir/src/target.rs index 7be670b20b2ca..6216de0c5eaf0 100644 --- a/compiler/rustc_attr_ir/src/target.rs +++ b/compiler/rustc_attr_ir/src/target.rs @@ -5,33 +5,82 @@ use std::fmt::{self, Display}; use rustc_abi::ExternAbi; pub use rustc_ast::visit::AssocCtxt; use rustc_ast::{ - Arm, AssocItemKind, Closure, Crate, Expr, ExprField, FieldDef, ForeignItemKind, GenericParam, - ItemKind, Local, Param, Pat, Variant, WherePredicate, ast, + Arm, AssocItemKind, Closure, Crate, Expr, ExprField, FieldDef, ForLoop, ForeignItemKind, + GenericParam, ItemKind, Local, Param, Pat, PatField, Stmt, Variant, WherePredicate, ast, }; use rustc_macros::StableHash; /// This enum lists all possible types of AST items. #[derive(Clone, Copy, Debug)] pub enum AstTarget<'a> { + // Target types that may correspond to different kinds of items. + Delegation { target: Option>, mac: bool }, + MacroCall(Option>), + + // Target types that correspond exclusively to `AssocItem` kind. Mapping is obtained from `Target::from_assoc_item_kind`. + AssocConst(Option<&'a AssocItemKind>), + Method(Option<&'a AssocItemKind>), + AssocTy(Option<&'a AssocItemKind>), + + // Target types that correspond exclusively to `ForeignItem` kind. Mapping is obtained from `Target::from_foreign_item_kind`. + ForeignStatic(Option<&'a ForeignItemKind>), + ForeignFn(Option<&'a ForeignItemKind>), + ForeignTy(Option<&'a ForeignItemKind>), + + // Target types that correspond exclusively to `Item` kind. Mapping is obtained from `Target::from_ast_item`. + ExternCrate(Option<&'a ItemKind>), + Use(Option<&'a ItemKind>), + Static(Option<&'a ItemKind>), + Const(Option<&'a ItemKind>), + Fn(Option<&'a ItemKind>), + Mod(Option<&'a ItemKind>), + ForeignMod(Option<&'a ItemKind>), + GlobalAsm(Option<&'a ItemKind>), + TyAlias(Option<&'a ItemKind>), + Enum(Option<&'a ItemKind>), + Struct(Option<&'a ItemKind>), + Union(Option<&'a ItemKind>), + Trait(Option<&'a ItemKind>), + TraitAlias(Option<&'a ItemKind>), + Impl { item: Option<&'a ItemKind>, of_trait: bool }, + MacroDef(Option<&'a ItemKind>), + + // Target types that correspond exclusively to `Expr` kind. Mapping is obtained from `Target::from_expr`. + Closure(Option<&'a Closure>), + Expression(Option<&'a Expr>), + ForLoop(Option<&'a ForLoop>), + Loop, + While, + Break, + + Arm(Option<&'a Arm>), + ConstParam(Option<&'a GenericParam>), + Crate(Option<&'a Crate>), + ExprField(Option<&'a ExprField>), + Field(Option<&'a FieldDef>), + GenericParam(Option<&'a GenericParam>), + LifetimeParam(Option<&'a GenericParam>), + Local(Option<&'a Local>), + Param(Option<&'a Param>), + Pat(Option<&'a Pat>), + PatField(Option<&'a PatField>), + Statement(Option<&'a Stmt>), + TypeParam(Option<&'a GenericParam>), + Variant(Option<&'a Variant>), + WherePredicate(Option<&'a WherePredicate>), +} + +#[derive(Clone, Copy, Debug)] +pub enum DelegationAstTarget<'a> { AssocItem(&'a AssocItemKind), - ForeignItem(&'a ForeignItemKind), Item(&'a ItemKind), +} - Arm(&'a Arm), - Closure(&'a Closure), - Crate(&'a Crate), - Expr(&'a Expr), - ExprField(&'a ExprField), - FieldDef(&'a FieldDef), - GenericParam(&'a GenericParam), - Local(&'a Local), - Param(&'a Param), - Pat(&'a Pat), - Variant(&'a Variant), - WherePredicate(&'a WherePredicate), - - /// Used when it is not possible to get detailed information about the target. - None, +#[derive(Clone, Copy, Debug)] +pub enum MacroCallAstTarget<'a> { + AssocItem(&'a AssocItemKind), + ForeignItem(&'a ForeignItemKind), + Item(&'a ItemKind), } #[derive(Copy, Clone, PartialEq, Debug, Eq, StableHash)] @@ -47,6 +96,8 @@ pub enum MethodKind { Inherent, } +// FIXME(rtjkro): `AstTarget` has nearly one-to-one mapping with `Target`, barring the extra fields from `AssocConst`, `Method`, and `AssocTy`. +// In the future, remove `Target` and use `AstTarget` instead. #[derive(Copy, Clone, PartialEq, Debug, Eq, StableHash)] pub enum Target { ExternCrate, @@ -93,12 +144,12 @@ pub enum Target { Break, } -impl AstTarget<'_> { +impl<'a> AstTarget<'a> { pub fn get_abi(&self) -> Option { let ext = match self { - AstTarget::Item(ast::ItemKind::Fn(fn_item)) => fn_item.sig.header.ext, - AstTarget::AssocItem(ast::AssocItemKind::Fn(fn_item)) => fn_item.sig.header.ext, - AstTarget::ForeignItem(ast::ForeignItemKind::Fn(fn_item)) => fn_item.sig.header.ext, + AstTarget::Method(Some(ast::AssocItemKind::Fn(fn_item))) => fn_item.sig.header.ext, + AstTarget::Fn(Some(ast::ItemKind::Fn(fn_item))) => fn_item.sig.header.ext, + AstTarget::ForeignFn(Some(ast::ForeignItemKind::Fn(fn_item))) => fn_item.sig.header.ext, _ => return None, }; @@ -111,12 +162,127 @@ impl AstTarget<'_> { pub fn get_fn_sig(&self) -> Option<&rustc_ast::ast::FnSig> { match self { - AstTarget::Item(ast::ItemKind::Fn(fn_item)) => Some(&fn_item.sig), - AstTarget::AssocItem(ast::AssocItemKind::Fn(fn_item)) => Some(&fn_item.sig), - AstTarget::ForeignItem(ast::ForeignItemKind::Fn(fn_item)) => Some(&fn_item.sig), + AstTarget::Method(Some(ast::AssocItemKind::Fn(fn_item))) => Some(&fn_item.sig), + AstTarget::Fn(Some(ast::ItemKind::Fn(fn_item))) => Some(&fn_item.sig), + AstTarget::ForeignFn(Some(ast::ForeignItemKind::Fn(fn_item))) => Some(&fn_item.sig), _ => None, } } + + pub fn from_foreign_item_kind(kind: &'a ast::ForeignItemKind) -> Self { + match kind { + ForeignItemKind::Static(_) => AstTarget::ForeignStatic(Some(kind)), + ForeignItemKind::Fn(_) => AstTarget::ForeignFn(Some(kind)), + ForeignItemKind::TyAlias(_) => AstTarget::ForeignTy(Some(kind)), + ForeignItemKind::MacCall(_) => { + AstTarget::MacroCall(Some(MacroCallAstTarget::ForeignItem(kind))) + } + } + } + + pub fn from_assoc_item_kind(kind: &'a ast::AssocItemKind) -> Self { + match kind { + AssocItemKind::Const(_) => AstTarget::AssocConst(Some(kind)), + AssocItemKind::Fn(_) => AstTarget::Method(Some(kind)), + AssocItemKind::Type(_) => AstTarget::AssocTy(Some(kind)), + AssocItemKind::Delegation(_) => AstTarget::Delegation { + target: Some(DelegationAstTarget::AssocItem(kind)), + mac: false, + }, + AssocItemKind::DelegationMac(_) => AstTarget::Delegation { + target: Some(DelegationAstTarget::AssocItem(kind)), + mac: true, + }, + AssocItemKind::MacCall(_) => { + AstTarget::MacroCall(Some(MacroCallAstTarget::AssocItem(kind))) + } + } + } + + pub fn from_ast_item(kind: &'a ast::ItemKind) -> Self { + match kind { + ast::ItemKind::ExternCrate(..) => AstTarget::ExternCrate(Some(kind)), + ast::ItemKind::Use(..) => AstTarget::Use(Some(kind)), + ast::ItemKind::Static { .. } => AstTarget::Static(Some(kind)), + ast::ItemKind::Const(..) => AstTarget::Const(Some(kind)), + ast::ItemKind::ConstBlock(..) => AstTarget::Const(Some(kind)), + ast::ItemKind::Fn { .. } => AstTarget::Fn(Some(kind)), + ast::ItemKind::Mod(..) => AstTarget::Mod(Some(kind)), + ast::ItemKind::ForeignMod { .. } => AstTarget::ForeignMod(Some(kind)), + ast::ItemKind::GlobalAsm { .. } => AstTarget::GlobalAsm(Some(kind)), + ast::ItemKind::TyAlias(..) => AstTarget::TyAlias(Some(kind)), + ast::ItemKind::Enum(..) => AstTarget::Enum(Some(kind)), + ast::ItemKind::Struct(..) => AstTarget::Struct(Some(kind)), + ast::ItemKind::Union(..) => AstTarget::Union(Some(kind)), + ast::ItemKind::Trait(..) => AstTarget::Trait(Some(kind)), + ast::ItemKind::TraitAlias(..) => AstTarget::TraitAlias(Some(kind)), + ast::ItemKind::Impl(i) => { + AstTarget::Impl { item: Some(kind), of_trait: i.of_trait.is_some() } + } + ast::ItemKind::MacCall(..) => { + AstTarget::MacroCall(Some(MacroCallAstTarget::Item(kind))) + } + ast::ItemKind::MacroDef(..) => AstTarget::MacroDef(Some(kind)), + ast::ItemKind::Delegation(..) => { + AstTarget::Delegation { target: Some(DelegationAstTarget::Item(kind)), mac: false } + } + ast::ItemKind::DelegationMac(..) => { + AstTarget::Delegation { target: Some(DelegationAstTarget::Item(kind)), mac: true } + } + ast::ItemKind::TestBinderConstraints(..) => { + AstTarget::MacroCall(Some(MacroCallAstTarget::Item(kind))) + } + } + } +} + +impl<'a> From for AstTarget<'a> { + fn from(target: Target) -> Self { + match target { + Target::ExternCrate => AstTarget::ExternCrate(None), + Target::Use => AstTarget::Use(None), + Target::Static => AstTarget::Static(None), + Target::Const => AstTarget::Const(None), + Target::Fn => AstTarget::Fn(None), + Target::Closure => AstTarget::Closure(None), + Target::Mod => AstTarget::Mod(None), + Target::ForeignMod => AstTarget::ForeignMod(None), + Target::GlobalAsm => AstTarget::GlobalAsm(None), + Target::TyAlias => AstTarget::TyAlias(None), + Target::Enum => AstTarget::Enum(None), + Target::Variant => AstTarget::Variant(None), + Target::Struct => AstTarget::Struct(None), + Target::Field => AstTarget::Field(None), + Target::Union => AstTarget::Union(None), + Target::Trait => AstTarget::Trait(None), + Target::TraitAlias => AstTarget::TraitAlias(None), + Target::Impl { of_trait } => AstTarget::Impl { item: None, of_trait }, + Target::Expression => AstTarget::Expression(None), + Target::Statement => AstTarget::Statement(None), + Target::Arm => AstTarget::Arm(None), + Target::AssocConst(_assoc_ctxt) => AstTarget::AssocConst(None), + Target::Method(_method_kind) => AstTarget::Method(None), + Target::AssocTy(_assoc_ctxt) => AstTarget::AssocTy(None), + Target::ForeignFn => AstTarget::ForeignFn(None), + Target::ForeignStatic => AstTarget::ForeignStatic(None), + Target::ForeignTy => AstTarget::ForeignTy(None), + Target::LifetimeParam => AstTarget::LifetimeParam(None), + Target::TypeParam => AstTarget::TypeParam(None), + Target::ConstParam => AstTarget::ConstParam(None), + Target::MacroDef => AstTarget::MacroDef(None), + Target::Param => AstTarget::Param(None), + Target::PatField => AstTarget::PatField(None), + Target::ExprField => AstTarget::ExprField(None), + Target::WherePredicate => AstTarget::WherePredicate(None), + Target::MacroCall => AstTarget::MacroCall(None), + Target::Crate => AstTarget::Crate(None), + Target::Delegation { mac } => AstTarget::Delegation { target: None, mac }, + Target::ForLoop => AstTarget::ForLoop(None), + Target::While => AstTarget::While, + Target::Loop => AstTarget::Loop, + Target::Break => AstTarget::Break, + } + } } impl Display for Target { diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 992fcfcc556ae..0adc5751373b6 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -330,6 +330,9 @@ impl AttributeParser for NakedParser { } fn deferred_finalize_check(&self) -> Option<(FinalizeCheckFn, Span)> { + // FIXME(rtjkro): Currently, we're enum matching on `cx.target` instead of `cx.ast_target` + // because `AstTarget::Method` doesn't contain `MethodKind` yet. In the future, when this field is available to `AstTarget::Method`, + // update this check to use `cx.ast_target` instead of `cx.target`. Some(( |cx, _| match cx.target { Target::Fn diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index ba9f6be111f47..a122713ce1930 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -263,8 +263,9 @@ impl CombineAttributeParser for LinkParser { fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { match cx.ast_target { - rustc_attr_ir::target::AstTarget::Item(ast_item) - if let ItemKind::ForeignMod(fm) = &ast_item => + rustc_attr_ir::target::AstTarget::ForeignMod(ast_item) + if let ItemKind::ForeignMod(fm) = + &ast_item.expect("missing AST target item for astTarget::ForeignMod") => { let abi = fm.abi.map_or(ExternAbi::FALLBACK, |abi| { abi.symbol_unescaped.as_str().parse().unwrap_or_else(|_| { diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index 8bb5e6b7fc270..5e2e0db135961 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -1,4 +1,5 @@ use rustc_ast::ItemKind; +use rustc_attr_ir::target::AstTarget; use rustc_attr_ir::{MacroUseArgs, find_attr}; use rustc_feature::AttributeStability; use rustc_lint_defs::builtin::{INVALID_MACRO_EXPORT_ARGUMENTS, UNUSED_ATTRIBUTES}; @@ -181,15 +182,16 @@ impl SingleAttributeParser for MacroExportParser { } fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { - if cx.target != Target::MacroDef { - return; - } - - let item = cx.target_item.unwrap(); - if let ItemKind::MacroDef(_, macro_def) = &item.kind - && !macro_def.macro_rules - { - cx.emit_lint(UNUSED_ATTRIBUTES, MacroExport::OnDeclMacro, attr_span); + match cx.ast_target { + AstTarget::MacroDef(item_kind) => { + if let ItemKind::MacroDef(_, macro_def) = + item_kind.expect("AstTarget::MacroDef should always have an ItemKind::MacroDef") + && !macro_def.macro_rules + { + cx.emit_lint(UNUSED_ATTRIBUTES, MacroExport::OnDeclMacro, attr_span); + } + } + _ => {} } } } diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs index 1a3db27763577..c4ff1f220f581 100644 --- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -27,8 +27,9 @@ impl NoArgsAttributeParser for NonExhaustiveParser { } match cx.ast_target { - rustc_attr_ir::target::AstTarget::Item(ast_item) - if let ItemKind::Struct(_, _, data) = &ast_item => + rustc_attr_ir::target::AstTarget::Struct(ast_item) + if let ItemKind::Struct(_, _, data) = + &ast_item.expect("missing AST target item for AstTarget::Struct") => { if let VariantData::Struct { fields, .. } = data && fields.iter().any(|f| f.default_value().is_some()) diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 36543a0623027..90a2cd04caade 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -162,7 +162,7 @@ impl<'sess> AttributeParser<'sess> { attrs, target_span, target, - rustc_attr_ir::target::AstTarget::None, + rustc_attr_ir::target::AstTarget::from(target), std::convert::identity, |lint_id, span, kind| { sess.psess.dyn_buffer_lint_sess(lint_id.lint, span, target_node_id, kind.0) diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 1caa032871e38..1b4e95c13399c 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -183,7 +183,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { &i.attrs, i.span, Target::MacroDef, - rustc_attr_ir::target::AstTarget::Item(&i.kind), + rustc_attr_ir::target::AstTarget::from_ast_item(&i.kind), std::convert::identity, |_lint_id, _span, _kind| { // FIXME(jdonszelmann): emit lints here properly From d3fd3f27d3d21fbfdd74c3358e1828abe15d3b17 Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Mon, 5 Oct 2026 22:51:29 +0800 Subject: [PATCH 24/49] remove options Signed-off-by: Richard Tjokroutomo --- compiler/rustc_ast_lowering/src/block.rs | 2 +- compiler/rustc_ast_lowering/src/expr.rs | 16 +- .../rustc_ast_lowering/src/expr/closure.rs | 2 +- compiler/rustc_ast_lowering/src/item.rs | 14 +- compiler/rustc_ast_lowering/src/lib.rs | 14 +- compiler/rustc_ast_lowering/src/pat.rs | 2 +- compiler/rustc_attr_ir/src/target.rs | 222 +++++++----------- .../src/attributes/link_attrs.rs | 3 +- .../src/attributes/macro_attrs.rs | 3 +- .../src/attributes/non_exhaustive.rs | 3 +- compiler/rustc_attr_parsing/src/interface.rs | 2 +- 11 files changed, 111 insertions(+), 172 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index cffd17bc16cee..0ebc9c1533b2f 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -109,7 +109,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &l.attrs, l.span, Target::Statement, - rustc_attr_ir::target::AstTarget::Local(Some(l)), + rustc_attr_ir::target::AstTarget::Local(l), ); self.arena.alloc(hir::LetStmt { hir_id, super_, ty, pat, init, els, span, source }) } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 941f54dc259c4..648cf6b30ca2e 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -236,7 +236,7 @@ impl<'hir> LoweringContext<'_, 'hir> { e.span, ex.hir_id, Target::from_expr(e), - AstTarget::from(Target::from_expr(e)), + AstTarget::Expression(e), ) .into_iter() .chain(old_attrs.iter().cloned()); @@ -266,7 +266,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &e.attrs, e.span, Target::from_expr(e), - AstTarget::Expression(Some(e)), + AstTarget::Expression(e), ); let kind = match &e.kind { @@ -807,7 +807,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let guard = arm.guard.as_ref().map(|guard| self.lower_expr(&guard.cond)); let hir_id = self.next_id(); let span = self.lower_span(arm.span); - self.lower_attrs(hir_id, &arm.attrs, arm.span, Target::Arm, AstTarget::Arm(Some(arm))); + self.lower_attrs(hir_id, &arm.attrs, arm.span, Target::Arm, AstTarget::Arm(arm)); let is_never_pattern = pat.is_never_pattern(); // We need to lower the body even if it's unneeded for never pattern in match, // ensure that we can get HirId for DefId if need (issue #137708). @@ -1671,13 +1671,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> { let hir_id = self.lower_node_id(f.id); - self.lower_attrs( - hir_id, - &f.attrs, - f.span, - Target::ExprField, - AstTarget::ExprField(Some(f)), - ); + self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField, AstTarget::ExprField(f)); hir::ExprField { hir_id, ident: self.lower_ident(f.ident), @@ -1949,7 +1943,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &e.attrs, e.span, Target::from_expr(e), - AstTarget::Expression(Some(e)), + AstTarget::Expression(e), ); expr } diff --git a/compiler/rustc_ast_lowering/src/expr/closure.rs b/compiler/rustc_ast_lowering/src/expr/closure.rs index 4d948db3c38b5..99ac5d1743731 100644 --- a/compiler/rustc_ast_lowering/src/expr/closure.rs +++ b/compiler/rustc_ast_lowering/src/expr/closure.rs @@ -25,7 +25,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &e.attrs, e.span, Target::from_expr(e), - rustc_attr_ir::target::AstTarget::Closure(Some(closure)), + rustc_attr_ir::target::AstTarget::Closure(closure), ); match closure.coroutine_marker { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 4ac1187d19a44..0cea675ff8a56 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -698,7 +698,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.dcx().span_fatal(v.span, "unnamed enum variants are not yet implemented"); } let hir_id = self.lower_node_id(v.id); - self.lower_attrs(hir_id, &v.attrs, v.span, Target::Variant, AstTarget::Variant(Some(v))); + self.lower_attrs(hir_id, &v.attrs, v.span, Target::Variant, AstTarget::Variant(v)); hir::Variant { hir_id, def_id: self.local_def_id(v.id), @@ -785,7 +785,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let ty = self.lower_ty_alloc(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy)); let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span, Target::Field, AstTarget::Field(Some(f))); + self.lower_attrs(hir_id, &f.attrs, f.span, Target::Field, AstTarget::Field(f)); hir::FieldDef { span: self.lower_span(f.span), hir_id, @@ -1245,13 +1245,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_param(&mut self, param: &Param) -> hir::Param<'hir> { let hir_id = self.lower_node_id(param.id); - self.lower_attrs( - hir_id, - ¶m.attrs, - param.span, - Target::Param, - AstTarget::Param(Some(param)), - ); + self.lower_attrs(hir_id, ¶m.attrs, param.span, Target::Param, AstTarget::Param(param)); hir::Param { hir_id, pat: self.lower_pat(¶m.pat), @@ -1966,7 +1960,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &pred.attrs, span, Target::WherePredicate, - AstTarget::WherePredicate(Some(pred)), + AstTarget::WherePredicate(pred), ); let kind = self.arena.alloc(match &pred.kind { WherePredicateKind::BoundPredicate(WhereBoundPredicate { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 2b575ddc0ed84..ace9b0937880f 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -767,7 +767,7 @@ fn lower_to_hir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::MaybeOwner<'_> { &c.attrs, c.spans.inner_span, Target::Crate, - AstTarget::Crate(Some(c)), + AstTarget::Crate(c), ); hir::OwnerNode::Crate(module) }), @@ -2008,7 +2008,13 @@ impl<'hir> LoweringContext<'_, 'hir> { // FIXME This uses `fn_hir_id`, which is not correct, it should use the parameter hir id instead // The parameter is currently not lowered for functions without bodies, so there is no place to store the lowered hir id // This should be fixed by storing function parameters in the `hir::FnSig` instead of `hir::Body` - self.lower_attrs(fn_hir_id, ¶m.attrs, param.span, Target::Param); + self.lower_attrs( + fn_hir_id, + ¶m.attrs, + param.span, + Target::Param, + AstTarget::None, + ); } let itctx = match kind { FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait => { @@ -2340,7 +2346,7 @@ impl<'hir> LoweringContext<'_, 'hir> { param_attrs, param_span, Target::from(¶m_hir), - AstTarget::GenericParam(Some(param)), + AstTarget::GenericParam(param), ); param_hir } @@ -2950,7 +2956,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &f.attrs, f.span, Target::ExprField, - AstTarget::Expression(Some(expr)), + AstTarget::Expression(expr), ); let expr = self.lower_expr_to_const_arg_direct(&f.expr, None); diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index d854b4db64d37..2f2c5d7747269 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -97,7 +97,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &f.attrs, f.span, Target::PatField, - rustc_attr_ir::target::AstTarget::Pat(Some(pattern)), + rustc_attr_ir::target::AstTarget::Pat(pattern), ); hir::PatField { diff --git a/compiler/rustc_attr_ir/src/target.rs b/compiler/rustc_attr_ir/src/target.rs index 6216de0c5eaf0..831a86dd7296a 100644 --- a/compiler/rustc_attr_ir/src/target.rs +++ b/compiler/rustc_attr_ir/src/target.rs @@ -14,60 +14,63 @@ use rustc_macros::StableHash; #[derive(Clone, Copy, Debug)] pub enum AstTarget<'a> { // Target types that may correspond to different kinds of items. - Delegation { target: Option>, mac: bool }, - MacroCall(Option>), + Delegation { target: DelegationAstTarget<'a>, mac: bool }, + MacroCall(MacroCallAstTarget<'a>), // Target types that correspond exclusively to `AssocItem` kind. Mapping is obtained from `Target::from_assoc_item_kind`. - AssocConst(Option<&'a AssocItemKind>), - Method(Option<&'a AssocItemKind>), - AssocTy(Option<&'a AssocItemKind>), + AssocConst(&'a AssocItemKind), + Method(&'a AssocItemKind), + AssocTy(&'a AssocItemKind), // Target types that correspond exclusively to `ForeignItem` kind. Mapping is obtained from `Target::from_foreign_item_kind`. - ForeignStatic(Option<&'a ForeignItemKind>), - ForeignFn(Option<&'a ForeignItemKind>), - ForeignTy(Option<&'a ForeignItemKind>), + ForeignStatic(&'a ForeignItemKind), + ForeignFn(&'a ForeignItemKind), + ForeignTy(&'a ForeignItemKind), // Target types that correspond exclusively to `Item` kind. Mapping is obtained from `Target::from_ast_item`. - ExternCrate(Option<&'a ItemKind>), - Use(Option<&'a ItemKind>), - Static(Option<&'a ItemKind>), - Const(Option<&'a ItemKind>), - Fn(Option<&'a ItemKind>), - Mod(Option<&'a ItemKind>), - ForeignMod(Option<&'a ItemKind>), - GlobalAsm(Option<&'a ItemKind>), - TyAlias(Option<&'a ItemKind>), - Enum(Option<&'a ItemKind>), - Struct(Option<&'a ItemKind>), - Union(Option<&'a ItemKind>), - Trait(Option<&'a ItemKind>), - TraitAlias(Option<&'a ItemKind>), - Impl { item: Option<&'a ItemKind>, of_trait: bool }, - MacroDef(Option<&'a ItemKind>), + ExternCrate(&'a ItemKind), + Use(&'a ItemKind), + Static(&'a ItemKind), + Const(&'a ItemKind), + Fn(&'a ItemKind), + Mod(&'a ItemKind), + ForeignMod(&'a ItemKind), + GlobalAsm(&'a ItemKind), + TyAlias(&'a ItemKind), + Enum(&'a ItemKind), + Struct(&'a ItemKind), + Union(&'a ItemKind), + Trait(&'a ItemKind), + TraitAlias(&'a ItemKind), + Impl { item: &'a ItemKind, of_trait: bool }, + MacroDef(&'a ItemKind), // Target types that correspond exclusively to `Expr` kind. Mapping is obtained from `Target::from_expr`. - Closure(Option<&'a Closure>), - Expression(Option<&'a Expr>), - ForLoop(Option<&'a ForLoop>), + Closure(&'a Closure), + Expression(&'a Expr), + ForLoop(&'a ForLoop), Loop, While, Break, - Arm(Option<&'a Arm>), - ConstParam(Option<&'a GenericParam>), - Crate(Option<&'a Crate>), - ExprField(Option<&'a ExprField>), - Field(Option<&'a FieldDef>), - GenericParam(Option<&'a GenericParam>), - LifetimeParam(Option<&'a GenericParam>), - Local(Option<&'a Local>), - Param(Option<&'a Param>), - Pat(Option<&'a Pat>), - PatField(Option<&'a PatField>), - Statement(Option<&'a Stmt>), - TypeParam(Option<&'a GenericParam>), - Variant(Option<&'a Variant>), - WherePredicate(Option<&'a WherePredicate>), + Arm(&'a Arm), + ConstParam(&'a GenericParam), + Crate(&'a Crate), + ExprField(&'a ExprField), + Field(&'a FieldDef), + GenericParam(&'a GenericParam), + LifetimeParam(&'a GenericParam), + Local(&'a Local), + Param(&'a Param), + Pat(&'a Pat), + PatField(&'a PatField), + Statement(&'a Stmt), + TypeParam(&'a GenericParam), + Variant(&'a Variant), + WherePredicate(&'a WherePredicate), + + // Only reserved for cases when it is not possible to obtain detailed Ast Target + None, } #[derive(Clone, Copy, Debug)] @@ -147,9 +150,9 @@ pub enum Target { impl<'a> AstTarget<'a> { pub fn get_abi(&self) -> Option { let ext = match self { - AstTarget::Method(Some(ast::AssocItemKind::Fn(fn_item))) => fn_item.sig.header.ext, - AstTarget::Fn(Some(ast::ItemKind::Fn(fn_item))) => fn_item.sig.header.ext, - AstTarget::ForeignFn(Some(ast::ForeignItemKind::Fn(fn_item))) => fn_item.sig.header.ext, + AstTarget::Method(ast::AssocItemKind::Fn(fn_item)) => fn_item.sig.header.ext, + AstTarget::Fn(ast::ItemKind::Fn(fn_item)) => fn_item.sig.header.ext, + AstTarget::ForeignFn(ast::ForeignItemKind::Fn(fn_item)) => fn_item.sig.header.ext, _ => return None, }; @@ -162,129 +165,74 @@ impl<'a> AstTarget<'a> { pub fn get_fn_sig(&self) -> Option<&rustc_ast::ast::FnSig> { match self { - AstTarget::Method(Some(ast::AssocItemKind::Fn(fn_item))) => Some(&fn_item.sig), - AstTarget::Fn(Some(ast::ItemKind::Fn(fn_item))) => Some(&fn_item.sig), - AstTarget::ForeignFn(Some(ast::ForeignItemKind::Fn(fn_item))) => Some(&fn_item.sig), + AstTarget::Method(ast::AssocItemKind::Fn(fn_item)) => Some(&fn_item.sig), + AstTarget::Fn(ast::ItemKind::Fn(fn_item)) => Some(&fn_item.sig), + AstTarget::ForeignFn(ast::ForeignItemKind::Fn(fn_item)) => Some(&fn_item.sig), _ => None, } } pub fn from_foreign_item_kind(kind: &'a ast::ForeignItemKind) -> Self { match kind { - ForeignItemKind::Static(_) => AstTarget::ForeignStatic(Some(kind)), - ForeignItemKind::Fn(_) => AstTarget::ForeignFn(Some(kind)), - ForeignItemKind::TyAlias(_) => AstTarget::ForeignTy(Some(kind)), + ForeignItemKind::Static(_) => AstTarget::ForeignStatic(kind), + ForeignItemKind::Fn(_) => AstTarget::ForeignFn(kind), + ForeignItemKind::TyAlias(_) => AstTarget::ForeignTy(kind), ForeignItemKind::MacCall(_) => { - AstTarget::MacroCall(Some(MacroCallAstTarget::ForeignItem(kind))) + AstTarget::MacroCall(MacroCallAstTarget::ForeignItem(kind)) } } } pub fn from_assoc_item_kind(kind: &'a ast::AssocItemKind) -> Self { match kind { - AssocItemKind::Const(_) => AstTarget::AssocConst(Some(kind)), - AssocItemKind::Fn(_) => AstTarget::Method(Some(kind)), - AssocItemKind::Type(_) => AstTarget::AssocTy(Some(kind)), - AssocItemKind::Delegation(_) => AstTarget::Delegation { - target: Some(DelegationAstTarget::AssocItem(kind)), - mac: false, - }, - AssocItemKind::DelegationMac(_) => AstTarget::Delegation { - target: Some(DelegationAstTarget::AssocItem(kind)), - mac: true, - }, - AssocItemKind::MacCall(_) => { - AstTarget::MacroCall(Some(MacroCallAstTarget::AssocItem(kind))) + AssocItemKind::Const(_) => AstTarget::AssocConst(kind), + AssocItemKind::Fn(_) => AstTarget::Method(kind), + AssocItemKind::Type(_) => AstTarget::AssocTy(kind), + AssocItemKind::Delegation(_) => { + AstTarget::Delegation { target: DelegationAstTarget::AssocItem(kind), mac: false } } + AssocItemKind::DelegationMac(_) => { + AstTarget::Delegation { target: DelegationAstTarget::AssocItem(kind), mac: true } + } + AssocItemKind::MacCall(_) => AstTarget::MacroCall(MacroCallAstTarget::AssocItem(kind)), } } pub fn from_ast_item(kind: &'a ast::ItemKind) -> Self { match kind { - ast::ItemKind::ExternCrate(..) => AstTarget::ExternCrate(Some(kind)), - ast::ItemKind::Use(..) => AstTarget::Use(Some(kind)), - ast::ItemKind::Static { .. } => AstTarget::Static(Some(kind)), - ast::ItemKind::Const(..) => AstTarget::Const(Some(kind)), - ast::ItemKind::ConstBlock(..) => AstTarget::Const(Some(kind)), - ast::ItemKind::Fn { .. } => AstTarget::Fn(Some(kind)), - ast::ItemKind::Mod(..) => AstTarget::Mod(Some(kind)), - ast::ItemKind::ForeignMod { .. } => AstTarget::ForeignMod(Some(kind)), - ast::ItemKind::GlobalAsm { .. } => AstTarget::GlobalAsm(Some(kind)), - ast::ItemKind::TyAlias(..) => AstTarget::TyAlias(Some(kind)), - ast::ItemKind::Enum(..) => AstTarget::Enum(Some(kind)), - ast::ItemKind::Struct(..) => AstTarget::Struct(Some(kind)), - ast::ItemKind::Union(..) => AstTarget::Union(Some(kind)), - ast::ItemKind::Trait(..) => AstTarget::Trait(Some(kind)), - ast::ItemKind::TraitAlias(..) => AstTarget::TraitAlias(Some(kind)), + ast::ItemKind::ExternCrate(..) => AstTarget::ExternCrate(kind), + ast::ItemKind::Use(..) => AstTarget::Use(kind), + ast::ItemKind::Static { .. } => AstTarget::Static(kind), + ast::ItemKind::Const(..) => AstTarget::Const(kind), + ast::ItemKind::ConstBlock(..) => AstTarget::Const(kind), + ast::ItemKind::Fn { .. } => AstTarget::Fn(kind), + ast::ItemKind::Mod(..) => AstTarget::Mod(kind), + ast::ItemKind::ForeignMod { .. } => AstTarget::ForeignMod(kind), + ast::ItemKind::GlobalAsm { .. } => AstTarget::GlobalAsm(kind), + ast::ItemKind::TyAlias(..) => AstTarget::TyAlias(kind), + ast::ItemKind::Enum(..) => AstTarget::Enum(kind), + ast::ItemKind::Struct(..) => AstTarget::Struct(kind), + ast::ItemKind::Union(..) => AstTarget::Union(kind), + ast::ItemKind::Trait(..) => AstTarget::Trait(kind), + ast::ItemKind::TraitAlias(..) => AstTarget::TraitAlias(kind), ast::ItemKind::Impl(i) => { - AstTarget::Impl { item: Some(kind), of_trait: i.of_trait.is_some() } - } - ast::ItemKind::MacCall(..) => { - AstTarget::MacroCall(Some(MacroCallAstTarget::Item(kind))) + AstTarget::Impl { item: kind, of_trait: i.of_trait.is_some() } } - ast::ItemKind::MacroDef(..) => AstTarget::MacroDef(Some(kind)), + ast::ItemKind::MacCall(..) => AstTarget::MacroCall(MacroCallAstTarget::Item(kind)), + ast::ItemKind::MacroDef(..) => AstTarget::MacroDef(kind), ast::ItemKind::Delegation(..) => { - AstTarget::Delegation { target: Some(DelegationAstTarget::Item(kind)), mac: false } + AstTarget::Delegation { target: DelegationAstTarget::Item(kind), mac: false } } ast::ItemKind::DelegationMac(..) => { - AstTarget::Delegation { target: Some(DelegationAstTarget::Item(kind)), mac: true } + AstTarget::Delegation { target: DelegationAstTarget::Item(kind), mac: true } } ast::ItemKind::TestBinderConstraints(..) => { - AstTarget::MacroCall(Some(MacroCallAstTarget::Item(kind))) + AstTarget::MacroCall(MacroCallAstTarget::Item(kind)) } } } } -impl<'a> From for AstTarget<'a> { - fn from(target: Target) -> Self { - match target { - Target::ExternCrate => AstTarget::ExternCrate(None), - Target::Use => AstTarget::Use(None), - Target::Static => AstTarget::Static(None), - Target::Const => AstTarget::Const(None), - Target::Fn => AstTarget::Fn(None), - Target::Closure => AstTarget::Closure(None), - Target::Mod => AstTarget::Mod(None), - Target::ForeignMod => AstTarget::ForeignMod(None), - Target::GlobalAsm => AstTarget::GlobalAsm(None), - Target::TyAlias => AstTarget::TyAlias(None), - Target::Enum => AstTarget::Enum(None), - Target::Variant => AstTarget::Variant(None), - Target::Struct => AstTarget::Struct(None), - Target::Field => AstTarget::Field(None), - Target::Union => AstTarget::Union(None), - Target::Trait => AstTarget::Trait(None), - Target::TraitAlias => AstTarget::TraitAlias(None), - Target::Impl { of_trait } => AstTarget::Impl { item: None, of_trait }, - Target::Expression => AstTarget::Expression(None), - Target::Statement => AstTarget::Statement(None), - Target::Arm => AstTarget::Arm(None), - Target::AssocConst(_assoc_ctxt) => AstTarget::AssocConst(None), - Target::Method(_method_kind) => AstTarget::Method(None), - Target::AssocTy(_assoc_ctxt) => AstTarget::AssocTy(None), - Target::ForeignFn => AstTarget::ForeignFn(None), - Target::ForeignStatic => AstTarget::ForeignStatic(None), - Target::ForeignTy => AstTarget::ForeignTy(None), - Target::LifetimeParam => AstTarget::LifetimeParam(None), - Target::TypeParam => AstTarget::TypeParam(None), - Target::ConstParam => AstTarget::ConstParam(None), - Target::MacroDef => AstTarget::MacroDef(None), - Target::Param => AstTarget::Param(None), - Target::PatField => AstTarget::PatField(None), - Target::ExprField => AstTarget::ExprField(None), - Target::WherePredicate => AstTarget::WherePredicate(None), - Target::MacroCall => AstTarget::MacroCall(None), - Target::Crate => AstTarget::Crate(None), - Target::Delegation { mac } => AstTarget::Delegation { target: None, mac }, - Target::ForLoop => AstTarget::ForLoop(None), - Target::While => AstTarget::While, - Target::Loop => AstTarget::Loop, - Target::Break => AstTarget::Break, - } - } -} - impl Display for Target { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", Self::name(*self)) diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index a122713ce1930..baf0496ef7a36 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -264,8 +264,7 @@ impl CombineAttributeParser for LinkParser { fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { match cx.ast_target { rustc_attr_ir::target::AstTarget::ForeignMod(ast_item) - if let ItemKind::ForeignMod(fm) = - &ast_item.expect("missing AST target item for astTarget::ForeignMod") => + if let ItemKind::ForeignMod(fm) = &ast_item => { let abi = fm.abi.map_or(ExternAbi::FALLBACK, |abi| { abi.symbol_unescaped.as_str().parse().unwrap_or_else(|_| { diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index 5e2e0db135961..335fc16c6105b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -184,8 +184,7 @@ impl SingleAttributeParser for MacroExportParser { fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { match cx.ast_target { AstTarget::MacroDef(item_kind) => { - if let ItemKind::MacroDef(_, macro_def) = - item_kind.expect("AstTarget::MacroDef should always have an ItemKind::MacroDef") + if let ItemKind::MacroDef(_, macro_def) = item_kind && !macro_def.macro_rules { cx.emit_lint(UNUSED_ATTRIBUTES, MacroExport::OnDeclMacro, attr_span); diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs index c4ff1f220f581..09fd2d46bc0bb 100644 --- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -28,8 +28,7 @@ impl NoArgsAttributeParser for NonExhaustiveParser { match cx.ast_target { rustc_attr_ir::target::AstTarget::Struct(ast_item) - if let ItemKind::Struct(_, _, data) = - &ast_item.expect("missing AST target item for AstTarget::Struct") => + if let ItemKind::Struct(_, _, data) = &ast_item => { if let VariantData::Struct { fields, .. } = data && fields.iter().any(|f| f.default_value().is_some()) diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 90a2cd04caade..36543a0623027 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -162,7 +162,7 @@ impl<'sess> AttributeParser<'sess> { attrs, target_span, target, - rustc_attr_ir::target::AstTarget::from(target), + rustc_attr_ir::target::AstTarget::None, std::convert::identity, |lint_id, span, kind| { sess.psess.dyn_buffer_lint_sess(lint_id.lint, span, target_node_id, kind.0) From b516dbb93426c61d115685c3a93ded82654d7896 Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Tue, 6 Oct 2026 10:32:09 +0800 Subject: [PATCH 25/49] rebase latest changes & addressing latest comments Signed-off-by: Richard Tjokroutomo --- compiler/rustc_ast_lowering/src/block.rs | 2 +- .../rustc_attr_parsing/src/attributes/rustc_internal.rs | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 0ebc9c1533b2f..e55dd4992270c 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -109,7 +109,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &l.attrs, l.span, Target::Statement, - rustc_attr_ir::target::AstTarget::Local(l), + rustc_attr_ir::target::AstTarget::None, ); self.arena.alloc(hir::LetStmt { hir_id, super_, ty, pat, init, els, span, source }) } diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 52422a85041a4..76e00e16abd9d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -171,12 +171,11 @@ impl SingleAttributeParser for RustcLegacyConstGenericsParser { } fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { - if cx.target != Target::Fn { - // Invalid targets are already diagnosed by target checking. + let rustc_attr_ir::target::AstTarget::Fn(item_kind) = cx.ast_target else { return; - } - let item = cx.target_item.expect("missing AST target item for Target::Fn"); - let ItemKind::Fn(function) = &item.kind else { + }; + + let ItemKind::Fn(function) = item_kind else { panic!("expected fn AST target item for Target::Fn"); }; let index_list = rustc_attr_ir::find_attr!(cx.parsed_attrs, RustcLegacyConstGenerics { fn_indexes, .. } => fn_indexes) From 49577d56d2fbd7e98171e6ef5849baf18b8dae06 Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Wed, 7 Oct 2026 20:36:38 +0800 Subject: [PATCH 26/49] some tidy ups Signed-off-by: Richard Tjokroutomo --- compiler/rustc_ast_lowering/src/block.rs | 6 +-- compiler/rustc_ast_lowering/src/lib.rs | 4 +- compiler/rustc_attr_ir/src/target.rs | 45 +++++-------------- .../src/attributes/link_attrs.rs | 21 ++++----- .../src/attributes/macro_attrs.rs | 17 ++++--- .../src/attributes/non_exhaustive.rs | 29 ++++++------ 6 files changed, 47 insertions(+), 75 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index e55dd4992270c..52f92a96c8ce3 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -37,7 +37,7 @@ impl<'hir> LoweringContext<'_, 'hir> { match &s.kind { StmtKind::Let(local) => { let hir_id = self.lower_node_id(s.id); - let local = self.lower_local(local); + let local = self.lower_local(local, &s); self.alias_attrs(hir_id, local.hir_id); let kind = hir::StmtKind::Let(local); let span = self.lower_span(s.span); @@ -88,7 +88,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn lower_local(&mut self, l: &Local) -> &'hir hir::LetStmt<'hir> { + fn lower_local(&mut self, l: &Local, s: &Stmt) -> &'hir hir::LetStmt<'hir> { // Let statements are allowed to have impl trait in bindings. let super_ = l.super_.map(|span| self.lower_span(span)); let ty = l.ty.as_ref().map(|t| { @@ -109,7 +109,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &l.attrs, l.span, Target::Statement, - rustc_attr_ir::target::AstTarget::None, + rustc_attr_ir::target::AstTarget::Statement(s), ); self.arena.alloc(hir::LetStmt { hir_id, super_, ty, pat, init, els, span, source }) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index ace9b0937880f..2cec93937594d 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2013,7 +2013,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ¶m.attrs, param.span, Target::Param, - AstTarget::None, + AstTarget::Param(param), ); } let itctx = match kind { @@ -2956,7 +2956,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &f.attrs, f.span, Target::ExprField, - AstTarget::Expression(expr), + AstTarget::ExprField(f), ); let expr = self.lower_expr_to_const_arg_direct(&f.expr, None); diff --git a/compiler/rustc_attr_ir/src/target.rs b/compiler/rustc_attr_ir/src/target.rs index 831a86dd7296a..d1be4b38aaea9 100644 --- a/compiler/rustc_attr_ir/src/target.rs +++ b/compiler/rustc_attr_ir/src/target.rs @@ -14,8 +14,8 @@ use rustc_macros::StableHash; #[derive(Clone, Copy, Debug)] pub enum AstTarget<'a> { // Target types that may correspond to different kinds of items. - Delegation { target: DelegationAstTarget<'a>, mac: bool }, - MacroCall(MacroCallAstTarget<'a>), + Delegation, + MacroCall, // Target types that correspond exclusively to `AssocItem` kind. Mapping is obtained from `Target::from_assoc_item_kind`. AssocConst(&'a AssocItemKind), @@ -73,19 +73,6 @@ pub enum AstTarget<'a> { None, } -#[derive(Clone, Copy, Debug)] -pub enum DelegationAstTarget<'a> { - AssocItem(&'a AssocItemKind), - Item(&'a ItemKind), -} - -#[derive(Clone, Copy, Debug)] -pub enum MacroCallAstTarget<'a> { - AssocItem(&'a AssocItemKind), - ForeignItem(&'a ForeignItemKind), - Item(&'a ItemKind), -} - #[derive(Copy, Clone, PartialEq, Debug, Eq, StableHash)] pub enum MethodKind { /// Method in a `trait Trait` block @@ -177,9 +164,7 @@ impl<'a> AstTarget<'a> { ForeignItemKind::Static(_) => AstTarget::ForeignStatic(kind), ForeignItemKind::Fn(_) => AstTarget::ForeignFn(kind), ForeignItemKind::TyAlias(_) => AstTarget::ForeignTy(kind), - ForeignItemKind::MacCall(_) => { - AstTarget::MacroCall(MacroCallAstTarget::ForeignItem(kind)) - } + ForeignItemKind::MacCall(_) => AstTarget::MacroCall, } } @@ -188,13 +173,9 @@ impl<'a> AstTarget<'a> { AssocItemKind::Const(_) => AstTarget::AssocConst(kind), AssocItemKind::Fn(_) => AstTarget::Method(kind), AssocItemKind::Type(_) => AstTarget::AssocTy(kind), - AssocItemKind::Delegation(_) => { - AstTarget::Delegation { target: DelegationAstTarget::AssocItem(kind), mac: false } - } - AssocItemKind::DelegationMac(_) => { - AstTarget::Delegation { target: DelegationAstTarget::AssocItem(kind), mac: true } - } - AssocItemKind::MacCall(_) => AstTarget::MacroCall(MacroCallAstTarget::AssocItem(kind)), + AssocItemKind::Delegation(_) => AstTarget::Delegation, + AssocItemKind::DelegationMac(_) => AstTarget::Delegation, + AssocItemKind::MacCall(_) => AstTarget::MacroCall, } } @@ -218,17 +199,11 @@ impl<'a> AstTarget<'a> { ast::ItemKind::Impl(i) => { AstTarget::Impl { item: kind, of_trait: i.of_trait.is_some() } } - ast::ItemKind::MacCall(..) => AstTarget::MacroCall(MacroCallAstTarget::Item(kind)), + ast::ItemKind::MacCall(..) => AstTarget::MacroCall, ast::ItemKind::MacroDef(..) => AstTarget::MacroDef(kind), - ast::ItemKind::Delegation(..) => { - AstTarget::Delegation { target: DelegationAstTarget::Item(kind), mac: false } - } - ast::ItemKind::DelegationMac(..) => { - AstTarget::Delegation { target: DelegationAstTarget::Item(kind), mac: true } - } - ast::ItemKind::TestBinderConstraints(..) => { - AstTarget::MacroCall(MacroCallAstTarget::Item(kind)) - } + ast::ItemKind::Delegation(..) => AstTarget::Delegation, + ast::ItemKind::DelegationMac(..) => AstTarget::Delegation, + ast::ItemKind::TestBinderConstraints(..) => AstTarget::MacroCall, } } } diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index baf0496ef7a36..bb6e9eca5820a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -262,11 +262,15 @@ impl CombineAttributeParser for LinkParser { } fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { - match cx.ast_target { - rustc_attr_ir::target::AstTarget::ForeignMod(ast_item) - if let ItemKind::ForeignMod(fm) = &ast_item => - { - let abi = fm.abi.map_or(ExternAbi::FALLBACK, |abi| { + let rustc_attr_ir::target::AstTarget::ForeignMod(ast_item) = cx.ast_target else { + return; + }; + + let ItemKind::ForeignMod(fm) = &ast_item else { + panic!("expected field ForeignMod for AstTarget::ForeignMod"); + }; + + let abi = fm.abi.map_or(ExternAbi::FALLBACK, |abi| { abi.symbol_unescaped.as_str().parse().unwrap_or_else(|_| { cx.dcx().span_delayed_bug( abi.span, @@ -275,11 +279,8 @@ impl CombineAttributeParser for LinkParser { ExternAbi::Rust }) }); - if matches!(abi, ExternAbi::Rust) { - cx.emit_lint(UNUSED_ATTRIBUTES, Link, attr_span); - } - } - _ => {} + if matches!(abi, ExternAbi::Rust) { + cx.emit_lint(UNUSED_ATTRIBUTES, Link, attr_span); } } } diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index 335fc16c6105b..252a9f5e379bc 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -182,15 +182,14 @@ impl SingleAttributeParser for MacroExportParser { } fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { - match cx.ast_target { - AstTarget::MacroDef(item_kind) => { - if let ItemKind::MacroDef(_, macro_def) = item_kind - && !macro_def.macro_rules - { - cx.emit_lint(UNUSED_ATTRIBUTES, MacroExport::OnDeclMacro, attr_span); - } - } - _ => {} + let AstTarget::MacroDef(item_kind) = cx.ast_target else { + return; + }; + + if let ItemKind::MacroDef(_, macro_def) = item_kind + && !macro_def.macro_rules + { + cx.emit_lint(UNUSED_ATTRIBUTES, MacroExport::OnDeclMacro, attr_span); } } } diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs index 09fd2d46bc0bb..3c4a77b3bb673 100644 --- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -22,24 +22,21 @@ impl NoArgsAttributeParser for NonExhaustiveParser { const CREATE: fn(Span) -> AttributeKind = AttributeKind::NonExhaustive; fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { - if cx.target != Target::Struct { + let rustc_attr_ir::target::AstTarget::Struct(ast_item) = cx.ast_target else { return; - } + }; + + let ItemKind::Struct(_, _, data) = ast_item else { + panic!("expected struct AST target item for AstTarget::Struct"); + }; - match cx.ast_target { - rustc_attr_ir::target::AstTarget::Struct(ast_item) - if let ItemKind::Struct(_, _, data) = &ast_item => - { - if let VariantData::Struct { fields, .. } = data - && fields.iter().any(|f| f.default_value().is_some()) - { - cx.emit_err(NonExhaustiveWithDefaultFieldValues { - attr_span, - defn_span: cx.target_span, - }); - } - } - _ => {} + if let VariantData::Struct { fields, .. } = data + && fields.iter().any(|f| f.default_value().is_some()) + { + cx.emit_err(NonExhaustiveWithDefaultFieldValues { + attr_span, + defn_span: cx.target_span, + }); } } } From 2c481cc0c925b41e406dca8a7bfd214f243a5a04 Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Wed, 7 Oct 2026 22:37:19 +0800 Subject: [PATCH 27/49] remove Item, AsocItem, & ForeignItem Signed-off-by: Richard Tjokroutomo --- compiler/rustc_attr_ir/src/target.rs | 119 ++++++++++-------- .../src/attributes/link_attrs.rs | 7 +- .../src/attributes/macro_attrs.rs | 7 +- .../src/attributes/non_exhaustive.rs | 8 +- .../src/attributes/rustc_internal.rs | 7 +- 5 files changed, 72 insertions(+), 76 deletions(-) diff --git a/compiler/rustc_attr_ir/src/target.rs b/compiler/rustc_attr_ir/src/target.rs index d1be4b38aaea9..a6ad343bd2785 100644 --- a/compiler/rustc_attr_ir/src/target.rs +++ b/compiler/rustc_attr_ir/src/target.rs @@ -5,10 +5,13 @@ use std::fmt::{self, Display}; use rustc_abi::ExternAbi; pub use rustc_ast::visit::AssocCtxt; use rustc_ast::{ - Arm, AssocItemKind, Closure, Crate, Expr, ExprField, FieldDef, ForLoop, ForeignItemKind, - GenericParam, ItemKind, Local, Param, Pat, PatField, Stmt, Variant, WherePredicate, ast, + Arm, AssocItemKind, Closure, ConstBlockItem, ConstItem, Crate, EnumDef, Expr, ExprField, + FieldDef, Fn, ForLoop, ForeignItemKind, ForeignMod, GenericParam, Generics, Impl, InlineAsm, + Local, MacroDef, ModKind, Param, Pat, PatField, Safety, StaticItem, Stmt, Trait, TraitAlias, + TyAlias, UseTree, Variant, VariantData, WherePredicate, ast, }; use rustc_macros::StableHash; +use rustc_span::{Ident, Symbol}; /// This enum lists all possible types of AST items. #[derive(Clone, Copy, Debug)] @@ -18,32 +21,32 @@ pub enum AstTarget<'a> { MacroCall, // Target types that correspond exclusively to `AssocItem` kind. Mapping is obtained from `Target::from_assoc_item_kind`. - AssocConst(&'a AssocItemKind), - Method(&'a AssocItemKind), - AssocTy(&'a AssocItemKind), + AssocConst(&'a ConstItem), + Method(&'a Fn), + AssocTy(&'a TyAlias), // Target types that correspond exclusively to `ForeignItem` kind. Mapping is obtained from `Target::from_foreign_item_kind`. - ForeignStatic(&'a ForeignItemKind), - ForeignFn(&'a ForeignItemKind), - ForeignTy(&'a ForeignItemKind), + ForeignStatic(&'a StaticItem), + ForeignFn(&'a Fn), + ForeignTy(&'a TyAlias), // Target types that correspond exclusively to `Item` kind. Mapping is obtained from `Target::from_ast_item`. - ExternCrate(&'a ItemKind), - Use(&'a ItemKind), - Static(&'a ItemKind), - Const(&'a ItemKind), - Fn(&'a ItemKind), - Mod(&'a ItemKind), - ForeignMod(&'a ItemKind), - GlobalAsm(&'a ItemKind), - TyAlias(&'a ItemKind), - Enum(&'a ItemKind), - Struct(&'a ItemKind), - Union(&'a ItemKind), - Trait(&'a ItemKind), - TraitAlias(&'a ItemKind), - Impl { item: &'a ItemKind, of_trait: bool }, - MacroDef(&'a ItemKind), + ExternCrate(&'a Option, &'a Ident), + Use(&'a UseTree), + Static(&'a StaticItem), + Const(ConstTypeAstTarget<'a>), + Fn(&'a Fn), + Mod(&'a Safety, &'a Ident, &'a ModKind), + ForeignMod(&'a ForeignMod), + GlobalAsm(&'a InlineAsm), + TyAlias(&'a TyAlias), + Enum(&'a Ident, &'a Generics, &'a EnumDef), + Struct(&'a Ident, &'a Generics, &'a VariantData), + Union(&'a Ident, &'a Generics, &'a VariantData), + Trait(&'a Trait), + TraitAlias(&'a TraitAlias), + Impl(&'a Impl), + MacroDef(&'a Ident, &'a MacroDef), // Target types that correspond exclusively to `Expr` kind. Mapping is obtained from `Target::from_expr`. Closure(&'a Closure), @@ -73,6 +76,12 @@ pub enum AstTarget<'a> { None, } +#[derive(Clone, Copy, Debug)] +pub enum ConstTypeAstTarget<'a> { + ConstItem(&'a ConstItem), + ConstBlockItem(&'a ConstBlockItem), +} + #[derive(Copy, Clone, PartialEq, Debug, Eq, StableHash)] pub enum MethodKind { /// Method in a `trait Trait` block @@ -137,9 +146,9 @@ pub enum Target { impl<'a> AstTarget<'a> { pub fn get_abi(&self) -> Option { let ext = match self { - AstTarget::Method(ast::AssocItemKind::Fn(fn_item)) => fn_item.sig.header.ext, - AstTarget::Fn(ast::ItemKind::Fn(fn_item)) => fn_item.sig.header.ext, - AstTarget::ForeignFn(ast::ForeignItemKind::Fn(fn_item)) => fn_item.sig.header.ext, + AstTarget::Method(fn_item) => fn_item.sig.header.ext, + AstTarget::Fn(fn_item) => fn_item.sig.header.ext, + AstTarget::ForeignFn(fn_item) => fn_item.sig.header.ext, _ => return None, }; @@ -152,27 +161,27 @@ impl<'a> AstTarget<'a> { pub fn get_fn_sig(&self) -> Option<&rustc_ast::ast::FnSig> { match self { - AstTarget::Method(ast::AssocItemKind::Fn(fn_item)) => Some(&fn_item.sig), - AstTarget::Fn(ast::ItemKind::Fn(fn_item)) => Some(&fn_item.sig), - AstTarget::ForeignFn(ast::ForeignItemKind::Fn(fn_item)) => Some(&fn_item.sig), + AstTarget::Method(fn_item) => Some(&fn_item.sig), + AstTarget::Fn(fn_item) => Some(&fn_item.sig), + AstTarget::ForeignFn(fn_item) => Some(&fn_item.sig), _ => None, } } pub fn from_foreign_item_kind(kind: &'a ast::ForeignItemKind) -> Self { match kind { - ForeignItemKind::Static(_) => AstTarget::ForeignStatic(kind), - ForeignItemKind::Fn(_) => AstTarget::ForeignFn(kind), - ForeignItemKind::TyAlias(_) => AstTarget::ForeignTy(kind), + ForeignItemKind::Static(static_item) => AstTarget::ForeignStatic(static_item), + ForeignItemKind::Fn(f) => AstTarget::ForeignFn(f), + ForeignItemKind::TyAlias(ty_alias) => AstTarget::ForeignTy(ty_alias), ForeignItemKind::MacCall(_) => AstTarget::MacroCall, } } pub fn from_assoc_item_kind(kind: &'a ast::AssocItemKind) -> Self { match kind { - AssocItemKind::Const(_) => AstTarget::AssocConst(kind), - AssocItemKind::Fn(_) => AstTarget::Method(kind), - AssocItemKind::Type(_) => AstTarget::AssocTy(kind), + AssocItemKind::Const(const_item) => AstTarget::AssocConst(const_item), + AssocItemKind::Fn(f) => AstTarget::Method(f), + AssocItemKind::Type(type_alias) => AstTarget::AssocTy(type_alias), AssocItemKind::Delegation(_) => AstTarget::Delegation, AssocItemKind::DelegationMac(_) => AstTarget::Delegation, AssocItemKind::MacCall(_) => AstTarget::MacroCall, @@ -181,26 +190,28 @@ impl<'a> AstTarget<'a> { pub fn from_ast_item(kind: &'a ast::ItemKind) -> Self { match kind { - ast::ItemKind::ExternCrate(..) => AstTarget::ExternCrate(kind), - ast::ItemKind::Use(..) => AstTarget::Use(kind), - ast::ItemKind::Static { .. } => AstTarget::Static(kind), - ast::ItemKind::Const(..) => AstTarget::Const(kind), - ast::ItemKind::ConstBlock(..) => AstTarget::Const(kind), - ast::ItemKind::Fn { .. } => AstTarget::Fn(kind), - ast::ItemKind::Mod(..) => AstTarget::Mod(kind), - ast::ItemKind::ForeignMod { .. } => AstTarget::ForeignMod(kind), - ast::ItemKind::GlobalAsm { .. } => AstTarget::GlobalAsm(kind), - ast::ItemKind::TyAlias(..) => AstTarget::TyAlias(kind), - ast::ItemKind::Enum(..) => AstTarget::Enum(kind), - ast::ItemKind::Struct(..) => AstTarget::Struct(kind), - ast::ItemKind::Union(..) => AstTarget::Union(kind), - ast::ItemKind::Trait(..) => AstTarget::Trait(kind), - ast::ItemKind::TraitAlias(..) => AstTarget::TraitAlias(kind), - ast::ItemKind::Impl(i) => { - AstTarget::Impl { item: kind, of_trait: i.of_trait.is_some() } + ast::ItemKind::ExternCrate(symbol, ident) => AstTarget::ExternCrate(symbol, ident), + ast::ItemKind::Use(use_tree) => AstTarget::Use(use_tree), + ast::ItemKind::Static(static_item) => AstTarget::Static(static_item), + ast::ItemKind::Const(const_item) => { + AstTarget::Const(ConstTypeAstTarget::ConstItem(const_item)) + } + ast::ItemKind::ConstBlock(const_block_item) => { + AstTarget::Const(ConstTypeAstTarget::ConstBlockItem(const_block_item)) } + ast::ItemKind::Fn(f) => AstTarget::Fn(f), + ast::ItemKind::Mod(s, i, mk) => AstTarget::Mod(s, i, mk), + ast::ItemKind::ForeignMod(foreign_mod) => AstTarget::ForeignMod(foreign_mod), + ast::ItemKind::GlobalAsm(inline_asm) => AstTarget::GlobalAsm(inline_asm), + ast::ItemKind::TyAlias(ty_alias) => AstTarget::TyAlias(ty_alias), + ast::ItemKind::Enum(i, g, ed) => AstTarget::Enum(i, g, ed), + ast::ItemKind::Struct(i, g, vd) => AstTarget::Struct(i, g, vd), + ast::ItemKind::Union(i, g, vd) => AstTarget::Union(i, g, vd), + ast::ItemKind::Trait(trait_kind) => AstTarget::Trait(trait_kind), + ast::ItemKind::TraitAlias(trait_alias) => AstTarget::TraitAlias(trait_alias), + ast::ItemKind::Impl(i) => AstTarget::Impl(i), ast::ItemKind::MacCall(..) => AstTarget::MacroCall, - ast::ItemKind::MacroDef(..) => AstTarget::MacroDef(kind), + ast::ItemKind::MacroDef(ident, macro_def) => AstTarget::MacroDef(ident, macro_def), ast::ItemKind::Delegation(..) => AstTarget::Delegation, ast::ItemKind::DelegationMac(..) => AstTarget::Delegation, ast::ItemKind::TestBinderConstraints(..) => AstTarget::MacroCall, diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index bb6e9eca5820a..40ca63e2a4da7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -1,5 +1,4 @@ use rustc_abi::ExternAbi; -use rustc_ast::ItemKind; use rustc_attr_ir::AttributeKind::{LinkName, LinkOrdinal, LinkSection}; use rustc_attr_ir::*; use rustc_errors::msg; @@ -262,14 +261,10 @@ impl CombineAttributeParser for LinkParser { } fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { - let rustc_attr_ir::target::AstTarget::ForeignMod(ast_item) = cx.ast_target else { + let rustc_attr_ir::target::AstTarget::ForeignMod(fm) = cx.ast_target else { return; }; - let ItemKind::ForeignMod(fm) = &ast_item else { - panic!("expected field ForeignMod for AstTarget::ForeignMod"); - }; - let abi = fm.abi.map_or(ExternAbi::FALLBACK, |abi| { abi.symbol_unescaped.as_str().parse().unwrap_or_else(|_| { cx.dcx().span_delayed_bug( diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index 252a9f5e379bc..8a0c31400b100 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -1,4 +1,3 @@ -use rustc_ast::ItemKind; use rustc_attr_ir::target::AstTarget; use rustc_attr_ir::{MacroUseArgs, find_attr}; use rustc_feature::AttributeStability; @@ -182,13 +181,11 @@ impl SingleAttributeParser for MacroExportParser { } fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { - let AstTarget::MacroDef(item_kind) = cx.ast_target else { + let AstTarget::MacroDef(_, macro_def) = cx.ast_target else { return; }; - if let ItemKind::MacroDef(_, macro_def) = item_kind - && !macro_def.macro_rules - { + if !macro_def.macro_rules { cx.emit_lint(UNUSED_ATTRIBUTES, MacroExport::OnDeclMacro, attr_span); } } diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs index 3c4a77b3bb673..ea670a70083a7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -1,4 +1,4 @@ -use rustc_ast::{ItemKind, VariantData}; +use rustc_ast::VariantData; use rustc_feature::AttributeStability; use super::prelude::*; @@ -22,14 +22,10 @@ impl NoArgsAttributeParser for NonExhaustiveParser { const CREATE: fn(Span) -> AttributeKind = AttributeKind::NonExhaustive; fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { - let rustc_attr_ir::target::AstTarget::Struct(ast_item) = cx.ast_target else { + let rustc_attr_ir::target::AstTarget::Struct(_, _, data) = cx.ast_target else { return; }; - let ItemKind::Struct(_, _, data) = ast_item else { - panic!("expected struct AST target item for AstTarget::Struct"); - }; - if let VariantData::Struct { fields, .. } = data && fields.iter().any(|f| f.default_value().is_some()) { diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 76e00e16abd9d..5554d84e7a455 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use rustc_ast::{GenericParamKind, ItemKind, LitIntType, LitKind, MetaItemLit}; +use rustc_ast::{GenericParamKind, LitIntType, LitKind, MetaItemLit}; use rustc_attr_ir::lang_items::LangItem; use rustc_attr_ir::{ BorrowckGraphvizFormatKind, CguFields, CguKind, RustcAssertVarianceKind, RustcCleanAttribute, @@ -171,13 +171,10 @@ impl SingleAttributeParser for RustcLegacyConstGenericsParser { } fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { - let rustc_attr_ir::target::AstTarget::Fn(item_kind) = cx.ast_target else { + let rustc_attr_ir::target::AstTarget::Fn(function) = cx.ast_target else { return; }; - let ItemKind::Fn(function) = item_kind else { - panic!("expected fn AST target item for Target::Fn"); - }; let index_list = rustc_attr_ir::find_attr!(cx.parsed_attrs, RustcLegacyConstGenerics { fn_indexes, .. } => fn_indexes) .expect("missing parsed RustcLegacyConstGenerics attribute in finalize_check"); let generics = &function.generics; From f8072010bdb3dc03bd4ef4abceb2af6c3a35a3c3 Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Wed, 7 Oct 2026 23:19:36 +0800 Subject: [PATCH 28/49] pass AstTarget::Expression too Signed-off-by: Richard Tjokroutomo --- compiler/rustc_ast_lowering/src/block.rs | 10 +---- compiler/rustc_ast_lowering/src/contract.rs | 38 +++++++++++++------ compiler/rustc_ast_lowering/src/expr.rs | 19 ++++++---- .../rustc_ast_lowering/src/expr/closure.rs | 4 +- compiler/rustc_ast_lowering/src/pat.rs | 4 +- .../src/attributes/link_attrs.rs | 16 ++++---- .../src/attributes/non_exhaustive.rs | 3 +- .../src/attributes/rustc_internal.rs | 3 +- compiler/rustc_attr_parsing/src/interface.rs | 4 +- compiler/rustc_resolve/src/def_collector.rs | 4 +- 10 files changed, 60 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 52f92a96c8ce3..dbed9093fc29b 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -1,5 +1,5 @@ use rustc_ast::{Block, BlockCheckMode, Local, LocalKind, Stmt, StmtKind}; -use rustc_attr_ir::target::Target; +use rustc_attr_ir::target::{AstTarget, Target}; use rustc_hir as hir; use rustc_span::sym; use smallvec::SmallVec; @@ -104,13 +104,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }; let span = self.lower_span(l.span); let source = hir::LocalSource::Normal; - self.lower_attrs( - hir_id, - &l.attrs, - l.span, - Target::Statement, - rustc_attr_ir::target::AstTarget::Statement(s), - ); + self.lower_attrs(hir_id, &l.attrs, l.span, Target::Statement, AstTarget::Statement(s)); self.arena.alloc(hir::LetStmt { hir_id, super_, ty, pat, init, els, span, source }) } diff --git a/compiler/rustc_ast_lowering/src/contract.rs b/compiler/rustc_ast_lowering/src/contract.rs index 9ceec41533d8e..5c7cbf6f79305 100644 --- a/compiler/rustc_ast_lowering/src/contract.rs +++ b/compiler/rustc_ast_lowering/src/contract.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use rustc_attr_ir::lang_items::LangItem; +use rustc_attr_ir::target::{AstTarget, Target}; use rustc_span::sym; use crate::LoweringContext; @@ -60,8 +61,12 @@ impl<'hir> LoweringContext<'_, 'hir> { postcond_checker, ); - let wrapped_body = - self.wrap_body_with_contract_check(body, contract_check, postcond_checker.span); + let wrapped_body = self.wrap_body_with_contract_check( + body, + contract_check, + postcond_checker.span, + ens, + ); self.expr_block(wrapped_body) } (None, Some(ens)) => { @@ -90,8 +95,12 @@ impl<'hir> LoweringContext<'_, 'hir> { let contract_check = self.lower_contract_check_with_postcond(contract_decls, None, postcond_checker); - let wrapped_body = - self.wrap_body_with_contract_check(body, contract_check, postcond_checker.span); + let wrapped_body = self.wrap_body_with_contract_check( + body, + contract_check, + postcond_checker.span, + ens, + ); self.expr_block(wrapped_body) } (Some(req), None) => { @@ -236,6 +245,7 @@ impl<'hir> LoweringContext<'_, 'hir> { body: impl FnOnce(&mut Self) -> rustc_hir::Expr<'hir>, contract_check: &'hir rustc_hir::Expr<'hir>, postcond_span: rustc_span::Span, + ast_expr: &rustc_ast::Expr, ) -> &'hir rustc_hir::Block<'hir> { let check_ident: rustc_span::Ident = rustc_span::Ident::new(sym::__ensures_checker, postcond_span); @@ -264,7 +274,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let body = self.arena.alloc(body(self)); // Finally, inject an ensures check on the implicit return of the body. - let body = self.inject_ensures_check(body, postcond_span, check_ident, check_hir_id); + let body = + self.inject_ensures_check(body, postcond_span, check_ident, check_hir_id, ast_expr); // Flatten the body into precond, then postcond, then wrapped body. let wrapped_body = self.block_all( @@ -280,14 +291,16 @@ impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn checked_return( &mut self, opt_expr: Option<&'hir rustc_hir::Expr<'hir>>, + ast_expr: &rustc_ast::Expr, ) -> rustc_hir::ExprKind<'hir> { - let checked_ret = - if let Some((check_span, check_ident, check_hir_id)) = self.contract_ensures { - let expr = opt_expr.unwrap_or_else(|| self.expr_unit(check_span)); - Some(self.inject_ensures_check(expr, check_span, check_ident, check_hir_id)) - } else { - opt_expr - }; + let checked_ret = if let Some((check_span, check_ident, check_hir_id)) = + self.contract_ensures + { + let expr = opt_expr.unwrap_or_else(|| self.expr_unit(check_span)); + Some(self.inject_ensures_check(expr, check_span, check_ident, check_hir_id, ast_expr)) + } else { + opt_expr + }; rustc_hir::ExprKind::Ret(checked_ret) } @@ -298,6 +311,7 @@ impl<'hir> LoweringContext<'_, 'hir> { span: rustc_span::Span, cond_ident: rustc_span::Ident, cond_hir_id: rustc_hir::HirId, + ast_expr: &rustc_ast::Expr, ) -> &'hir rustc_hir::Expr<'hir> { // { // let ret = { body }; diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 648cf6b30ca2e..7ab08ebade496 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -492,11 +492,11 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::Continue(opt_label) => { hir::ExprKind::Continue(self.lower_jump_destination(e.id, *opt_label)) } - ExprKind::Ret(e) => { - let expr = e.as_ref().map(|x| self.lower_expr(x)); - self.checked_return(expr) + ExprKind::Ret(box_e) => { + let expr = box_e.as_ref().map(|x| self.lower_expr(x)); + self.checked_return(expr, e) } - ExprKind::Yeet(sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref()), + ExprKind::Yeet(sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref(), e), ExprKind::Become(sub_expr) => { let sub_expr = self.lower_expr(sub_expr); hir::ExprKind::Become(sub_expr) @@ -2027,7 +2027,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ), )) } else { - let ret_expr = self.checked_return(Some(from_residual_expr)); + let ret_expr = self.checked_return(Some(from_residual_expr), sub_expr); self.arena.alloc(self.expr(try_span, ret_expr)) }; @@ -2051,7 +2051,12 @@ impl<'hir> LoweringContext<'_, 'hir> { /// ``` /// But to simplify this, there's a `from_yeet` lang item function which /// handles the combined `FromResidual::from_residual(Yeet(residual))`. - fn lower_expr_yeet(&mut self, span: Span, sub_expr: Option<&Expr>) -> hir::ExprKind<'hir> { + fn lower_expr_yeet( + &mut self, + span: Span, + sub_expr: Option<&Expr>, + ast_expr: &rustc_ast::Expr, + ) -> hir::ExprKind<'hir> { // The expression (if present) or `()` otherwise. let (yeeted_span, yeeted_expr) = if let Some(sub_expr) = sub_expr { (sub_expr.span, self.lower_expr(sub_expr)) @@ -2079,7 +2084,7 @@ impl<'hir> LoweringContext<'_, 'hir> { Some(from_yeet_expr), ) } - TryBlockScope::Function => self.checked_return(Some(from_yeet_expr)), + TryBlockScope::Function => self.checked_return(Some(from_yeet_expr), ast_expr), } } diff --git a/compiler/rustc_ast_lowering/src/expr/closure.rs b/compiler/rustc_ast_lowering/src/expr/closure.rs index 99ac5d1743731..808248db3204e 100644 --- a/compiler/rustc_ast_lowering/src/expr/closure.rs +++ b/compiler/rustc_ast_lowering/src/expr/closure.rs @@ -1,6 +1,6 @@ use rustc_ast::*; use rustc_attr_ir::find_attr; -use rustc_attr_ir::target::Target; +use rustc_attr_ir::target::{AstTarget, Target}; use rustc_hir as hir; use rustc_hir::HirId; use rustc_span::{Span, span_bug}; @@ -25,7 +25,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &e.attrs, e.span, Target::from_expr(e), - rustc_attr_ir::target::AstTarget::Closure(closure), + AstTarget::Closure(closure), ); match closure.coroutine_marker { diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 2f2c5d7747269..cce1b7039e7b2 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use rustc_ast::*; use rustc_attr_ir::lang_items::LangItem; -use rustc_attr_ir::target::Target; +use rustc_attr_ir::target::{AstTarget, Target}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_span::{DesugaringKind, Ident, Span, Spanned, respan, span_bug}; @@ -97,7 +97,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &f.attrs, f.span, Target::PatField, - rustc_attr_ir::target::AstTarget::Pat(pattern), + AstTarget::Pat(pattern), ); hir::PatField { diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 40ca63e2a4da7..09a82c6e7db0e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -266,14 +266,14 @@ impl CombineAttributeParser for LinkParser { }; let abi = fm.abi.map_or(ExternAbi::FALLBACK, |abi| { - abi.symbol_unescaped.as_str().parse().unwrap_or_else(|_| { - cx.dcx().span_delayed_bug( - abi.span, - "LinkParser::finalize_check was unable to pre-detect the ABI, so it continues to use the recovery value solely to check for unused_attributes in the lint; a user error E0703 will be reported later in lower_abi", - ); - ExternAbi::Rust - }) - }); + abi.symbol_unescaped.as_str().parse().unwrap_or_else(|_| { + cx.dcx().span_delayed_bug( + abi.span, + "LinkParser::finalize_check was unable to pre-detect the ABI, so it continues to use the recovery value solely to check for unused_attributes in the lint; a user error E0703 will be reported later in lower_abi", + ); + ExternAbi::Rust + }) + }); if matches!(abi, ExternAbi::Rust) { cx.emit_lint(UNUSED_ATTRIBUTES, Link, attr_span); } diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs index ea670a70083a7..6611041e0c4aa 100644 --- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -1,4 +1,5 @@ use rustc_ast::VariantData; +use rustc_attr_ir::target::AstTarget; use rustc_feature::AttributeStability; use super::prelude::*; @@ -22,7 +23,7 @@ impl NoArgsAttributeParser for NonExhaustiveParser { const CREATE: fn(Span) -> AttributeKind = AttributeKind::NonExhaustive; fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { - let rustc_attr_ir::target::AstTarget::Struct(_, _, data) = cx.ast_target else { + let AstTarget::Struct(_, _, data) = cx.ast_target else { return; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 5554d84e7a455..0ed85596c5bc0 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -2,6 +2,7 @@ use std::path::PathBuf; use rustc_ast::{GenericParamKind, LitIntType, LitKind, MetaItemLit}; use rustc_attr_ir::lang_items::LangItem; +use rustc_attr_ir::target::AstTarget; use rustc_attr_ir::{ BorrowckGraphvizFormatKind, CguFields, CguKind, RustcAssertVarianceKind, RustcCleanAttribute, RustcCleanQueries, RustcMirKind, @@ -171,7 +172,7 @@ impl SingleAttributeParser for RustcLegacyConstGenericsParser { } fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { - let rustc_attr_ir::target::AstTarget::Fn(function) = cx.ast_target else { + let AstTarget::Fn(function) = cx.ast_target else { return; }; diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 36543a0623027..77184105f7a8f 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -6,7 +6,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use rustc_ast as ast; use rustc_ast::token::DocFragmentKind; use rustc_ast::{AttrStyle, CRATE_NODE_ID, NodeId, Safety}; -use rustc_attr_ir::target::Target; +use rustc_attr_ir::target::{AstTarget, Target}; use rustc_attr_ir::{AttrArgs, AttrItem, AttrPath, Attribute, AttributeKind, HashIgnoredAttrId}; use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level, MultiSpan}; @@ -162,7 +162,7 @@ impl<'sess> AttributeParser<'sess> { attrs, target_span, target, - rustc_attr_ir::target::AstTarget::None, + AstTarget::None, std::convert::identity, |lint_id, span, kind| { sess.psess.dyn_buffer_lint_sess(lint_id.lint, span, target_node_id, kind.0) diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 1b4e95c13399c..474615c9a7672 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -2,7 +2,7 @@ use std::mem; use rustc_ast::visit::FnKind; use rustc_ast::*; -use rustc_attr_ir::target::Target; +use rustc_attr_ir::target::{AstTarget, Target}; use rustc_attr_parsing::{AttributeParser, ShouldEmit}; use rustc_expand::expand::AstFragment; use rustc_hir as hir; @@ -183,7 +183,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { &i.attrs, i.span, Target::MacroDef, - rustc_attr_ir::target::AstTarget::from_ast_item(&i.kind), + AstTarget::from_ast_item(&i.kind), std::convert::identity, |_lint_id, _span, _kind| { // FIXME(jdonszelmann): emit lints here properly From d2c019a05f31ffaadc3bee6f9614d3bdf7b6a543 Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Fri, 9 Oct 2026 23:10:37 +0800 Subject: [PATCH 29/49] remove unused AstTarget types & some tidy ups Signed-off-by: Richard Tjokroutomo --- compiler/rustc_attr_ir/src/target.rs | 15 +++------------ .../src/attributes/link_attrs.rs | 7 ++++--- .../src/attributes/non_exhaustive.rs | 1 - .../src/attributes/rustc_internal.rs | 1 - compiler/rustc_attr_parsing/src/interface.rs | 2 +- 5 files changed, 8 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_attr_ir/src/target.rs b/compiler/rustc_attr_ir/src/target.rs index a6ad343bd2785..180f03f60fc85 100644 --- a/compiler/rustc_attr_ir/src/target.rs +++ b/compiler/rustc_attr_ir/src/target.rs @@ -6,9 +6,9 @@ use rustc_abi::ExternAbi; pub use rustc_ast::visit::AssocCtxt; use rustc_ast::{ Arm, AssocItemKind, Closure, ConstBlockItem, ConstItem, Crate, EnumDef, Expr, ExprField, - FieldDef, Fn, ForLoop, ForeignItemKind, ForeignMod, GenericParam, Generics, Impl, InlineAsm, - Local, MacroDef, ModKind, Param, Pat, PatField, Safety, StaticItem, Stmt, Trait, TraitAlias, - TyAlias, UseTree, Variant, VariantData, WherePredicate, ast, + FieldDef, Fn, ForeignItemKind, ForeignMod, GenericParam, Generics, Impl, InlineAsm, MacroDef, + ModKind, Param, Pat, Safety, StaticItem, Stmt, Trait, TraitAlias, TyAlias, UseTree, Variant, + VariantData, WherePredicate, ast, }; use rustc_macros::StableHash; use rustc_span::{Ident, Symbol}; @@ -51,24 +51,15 @@ pub enum AstTarget<'a> { // Target types that correspond exclusively to `Expr` kind. Mapping is obtained from `Target::from_expr`. Closure(&'a Closure), Expression(&'a Expr), - ForLoop(&'a ForLoop), - Loop, - While, - Break, Arm(&'a Arm), - ConstParam(&'a GenericParam), Crate(&'a Crate), ExprField(&'a ExprField), Field(&'a FieldDef), GenericParam(&'a GenericParam), - LifetimeParam(&'a GenericParam), - Local(&'a Local), Param(&'a Param), Pat(&'a Pat), - PatField(&'a PatField), Statement(&'a Stmt), - TypeParam(&'a GenericParam), Variant(&'a Variant), WherePredicate(&'a WherePredicate), diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 09a82c6e7db0e..d5b2f7accb621 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -1,5 +1,6 @@ use rustc_abi::ExternAbi; use rustc_attr_ir::AttributeKind::{LinkName, LinkOrdinal, LinkSection}; +use rustc_attr_ir::target::AstTarget; use rustc_attr_ir::*; use rustc_errors::msg; use rustc_feature::{AttributeStability, Features}; @@ -261,7 +262,7 @@ impl CombineAttributeParser for LinkParser { } fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { - let rustc_attr_ir::target::AstTarget::ForeignMod(fm) = cx.ast_target else { + let AstTarget::ForeignMod(fm) = cx.ast_target else { return; }; @@ -272,8 +273,8 @@ impl CombineAttributeParser for LinkParser { "LinkParser::finalize_check was unable to pre-detect the ABI, so it continues to use the recovery value solely to check for unused_attributes in the lint; a user error E0703 will be reported later in lower_abi", ); ExternAbi::Rust - }) - }); + }) + }); if matches!(abi, ExternAbi::Rust) { cx.emit_lint(UNUSED_ATTRIBUTES, Link, attr_span); } diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs index 6611041e0c4aa..c2f8875e440e7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -26,7 +26,6 @@ impl NoArgsAttributeParser for NonExhaustiveParser { let AstTarget::Struct(_, _, data) = cx.ast_target else { return; }; - if let VariantData::Struct { fields, .. } = data && fields.iter().any(|f| f.default_value().is_some()) { diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 0ed85596c5bc0..e8bdce0df5b95 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -175,7 +175,6 @@ impl SingleAttributeParser for RustcLegacyConstGenericsParser { let AstTarget::Fn(function) = cx.ast_target else { return; }; - let index_list = rustc_attr_ir::find_attr!(cx.parsed_attrs, RustcLegacyConstGenerics { fn_indexes, .. } => fn_indexes) .expect("missing parsed RustcLegacyConstGenerics attribute in finalize_check"); let generics = &function.generics; diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 77184105f7a8f..e2f56541e70db 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -319,7 +319,7 @@ impl<'sess> AttributeParser<'sess> { attrs: &[ast::Attribute], target_span: Span, target: Target, - ast_target: rustc_attr_ir::target::AstTarget<'_>, + ast_target: AstTarget<'_>, lower_span: impl Copy + Fn(Span) -> Span, mut emit_lint: impl FnMut(LintId, MultiSpan, EmitAttribute), ) -> Vec { From 3c451a5cab0999533dc16dda43e230dbcaf82ee9 Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Sat, 17 Oct 2026 10:57:33 +0800 Subject: [PATCH 30/49] latest rebase & some mods involving genericparams Signed-off-by: Richard Tjokroutomo --- compiler/rustc_ast_lowering/src/lib.rs | 21 ++++++++++++++++++++- compiler/rustc_passes/src/check_attr.rs | 1 - 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 2cec93937594d..76da5a3306b58 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2000,7 +2000,26 @@ impl<'hir> LoweringContext<'_, 'hir> { colon_span: None, source: hir::GenericParamSource::Generics, }; - self.lower_attrs(hir_id, ¶m.attrs, param.span, Target::from(&generic_param)); + let ast_generic_param = ast::GenericParam { + id: param.id, + ident, + attrs: param.attrs.clone(), + bounds: Default::default(), + is_placeholder: false, + kind: ast::GenericParamKind::Const { + ty: param.ty.clone(), + span: param.span, + default: None, + }, + colon_span: None, + }; + self.lower_attrs( + hir_id, + ¶m.attrs, + param.span, + Target::from(&generic_param), + AstTarget::GenericParam(&ast_generic_param), + ); self.curr_owner.const_defs.push(generic_param); return None; } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 4c658dd946283..c59425feb3173 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -38,7 +38,6 @@ use rustc_middle::query::Providers; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, TyCtxt, TypingMode, Unnormalized, Variance}; -use rustc_session::diagnostics::feature_err; use rustc_span::edition::Edition; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, bug, kw, span_bug, sym}; use rustc_structures::CrateType; From 6c8618c3b53289b27a87bc71bdc43767a54143c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 24 Oct 2026 16:42:27 +0200 Subject: [PATCH 31/49] Replace `insta` with `expect-test` in bootstrap --- src/bootstrap/Cargo.lock | 47 ++++++------------- src/bootstrap/Cargo.toml | 2 +- src/bootstrap/src/core/build_steps/test.rs | 7 ++- .../src/core/builder/cli_paths/tests.rs | 19 +++++--- src/bootstrap/src/core/builder/tests.rs | 4 +- 5 files changed, 32 insertions(+), 47 deletions(-) diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index c5f9a4288c632..4d72f562a0bc6 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -48,9 +48,9 @@ dependencies = [ "clap", "clap_complete", "cmake", + "expect-test", "home", "ignore", - "insta", "junction", "libc", "object", @@ -175,17 +175,6 @@ dependencies = [ "cc", ] -[[package]] -name = "console" -version = "0.16.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87" -dependencies = [ - "encode_unicode", - "libc", - "windows-sys", -] - [[package]] name = "cpufeatures" version = "0.2.15" @@ -241,10 +230,10 @@ dependencies = [ ] [[package]] -name = "encode_unicode" -version = "1.0.0" +name = "dissimilar" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" +checksum = "aeda16ab4059c5fd2a83f2b9c9e9c981327b18aa8e3b313f7e6563799d4f093e" [[package]] name = "errno" @@ -256,6 +245,16 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "expect-test" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63af43ff4431e848fb47472a920f14fa71c24de13255a5692e93d4e90302acb0" +dependencies = [ + "dissimilar", + "once_cell", +] + [[package]] name = "fastrand" version = "2.3.0" @@ -345,18 +344,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "insta" -version = "1.47.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4a6248eb93a4401ed2f37dfe8ea592d3cf05b7cf4f8efa867b6895af7e094e" -dependencies = [ - "console", - "once_cell", - "similar", - "tempfile", -] - [[package]] name = "itoa" version = "1.0.11" @@ -682,12 +669,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "similar" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" - [[package]] name = "smallvec" version = "1.13.2" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 4dcf87e3290a2..fa744c895477f 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -89,7 +89,7 @@ features = [ ] [dev-dependencies] -insta = "1.43" +expect-test = "1" # We care a lot about bootstrap's compile times, so don't include debuginfo for # dependencies, only bootstrap itself. diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 70a97c8b87826..081f469069de9 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -4177,10 +4177,9 @@ impl CommandLineStep for Bootstrap { .env("RUSTC_BOOTSTRAP", "1"); if builder.config.cmd.bless() { - // Tell `insta` to automatically bless any failing `.snap` files. - // Unlike compiletest blessing, the tests might still report failure. - // Does not bless inline snapshots. - cargo.env("INSTA_UPDATE", "always"); + // Tell `expect-test` to automatically bless any failing `.snap` files + // and inline snapshots. + cargo.env("UPDATE_EXPECT", "1"); } run_cargo_test(cargo, &[], &[], None, host, builder, record_failed_tests); diff --git a/src/bootstrap/src/core/builder/cli_paths/tests.rs b/src/bootstrap/src/core/builder/cli_paths/tests.rs index a6754e063caf4..5dd888b3fda4c 100644 --- a/src/bootstrap/src/core/builder/cli_paths/tests.rs +++ b/src/bootstrap/src/core/builder/cli_paths/tests.rs @@ -1,5 +1,5 @@ use std::collections::{BTreeSet, HashSet}; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex}; use crate::core::builder::{Builder, CommandLineStepDescription}; @@ -59,12 +59,17 @@ fn render_steps_for_cli_args(args_str: &str) -> String { } fn snapshot_test_inner(name: &str, args_str: &str) { - let mut settings = insta::Settings::clone_current(); - // Use the test name as the snapshot filename, not its whole fully-qualified name. - settings.set_prepend_module_to_snapshot(false); - settings.bind(|| { - insta::assert_snapshot!(name, render_steps_for_cli_args(args_str), args_str); - }); + let name = Path::new("snapshots").join(format!("{name}.snap")); + let steps = render_steps_for_cli_args(args_str); + let file = file!(); + let content = format!( + r"--- +source: {file} +expression: {args_str} +--- +{steps}" + ); + expect_test::expect_file![name].assert_eq(&content); } /// Keep the snapshots directory tidy by forbidding `.snap` files that don't diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index ecdb057fd43b7..b8ea63437130c 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -358,8 +358,8 @@ fn any_debug() { assert_eq!(x.downcast_ref::(), Some(&MyStruct { x: 7 })); } -/// These tests use insta for snapshot testing. -/// See bootstrap's README on how to bless the snapshots. +/// These tests use expect-test for snapshot testing. +/// Run `x test bootstrap --bless` to update them. mod snapshot { use crate::core::build_steps::test; use crate::core::builder::tests::{RenderConfig, TEST_TRIPLE_1, TEST_TRIPLE_2, host_target}; From 7ed5fb8e4661cca0af8ce521fb69447b9c24fc6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 24 Oct 2026 16:42:30 +0200 Subject: [PATCH 32/49] Update snapshots --- .../builder/cli_paths/snapshots/x_fmt.snap | 1 - .../builder/cli_paths/snapshots/x_run.snap | 1 - .../x_test_rustdoc_skip_rustdoc.snap | 1 - src/bootstrap/src/core/builder/tests.rs | 3430 ++++++++--------- 4 files changed, 1598 insertions(+), 1835 deletions(-) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_fmt.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_fmt.snap index d7a99d45bfa70..48169a9210079 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_fmt.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_fmt.snap @@ -2,4 +2,3 @@ source: src/bootstrap/src/core/builder/cli_paths/tests.rs expression: fmt --- - diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_run.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_run.snap index fb4968b51c147..a20f552e1d26a 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_run.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_run.snap @@ -2,4 +2,3 @@ source: src/bootstrap/src/core/builder/cli_paths/tests.rs expression: run --- - diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_rustdoc_skip_rustdoc.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_rustdoc_skip_rustdoc.snap index f7e480936ebb7..321dda12654e9 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_rustdoc_skip_rustdoc.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_rustdoc_skip_rustdoc.snap @@ -2,4 +2,3 @@ source: src/bootstrap/src/core/builder/cli_paths/tests.rs expression: test rustdoc --skip=rustdoc --- - diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index b8ea63437130c..544c47602136a 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -374,80 +374,67 @@ mod snapshot { #[test] fn build_default() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("build") - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustdoc 1 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustdoc 1 "#]] + .assert_eq(&ctx.config("build").render_steps()); } #[test] fn build_cross_compile() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("build") + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> rustc 2 + [build] rustc 2 -> std 2 + [build] rustc 1 -> std 1 + [build] rustc 2 -> std 2 + [build] rustdoc 2 + [build] llvm + [build] rustc 1 -> rustc 2 + [build] rustdoc 2 "#]] + .assert_eq( + &ctx.config("build") // Cross-compilation fails on stage 1, as we don't have a stage0 std available // for non-host targets. .stage(2) .hosts(&[&host_target(), TEST_TRIPLE_1]) .targets(&[&host_target(), TEST_TRIPLE_1]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 1 -> rustc 2 - [build] rustc 2 -> std 2 - [build] rustc 1 -> std 1 - [build] rustc 2 -> std 2 - [build] rustdoc 2 - [build] llvm - [build] rustc 1 -> rustc 2 - [build] rustdoc 2 - "); + .render_steps(), + ); } #[test] fn build_with_empty_host() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx - .config("build") - .hosts(&[]) - .targets(&[TEST_TRIPLE_1]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - " - ); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 "#]] + .assert_eq(&ctx.config("build").hosts(&[]).targets(&[TEST_TRIPLE_1]).render_steps()); } #[test] fn build_compiler_no_explicit_stage() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("build") - .path("compiler") - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 "#]] + .assert_eq(&ctx.config("build").path("compiler").render_steps()); } #[test] fn build_rustc_no_explicit_stage() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("build") - .path("rustc") - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 "#]] + .assert_eq(&ctx.config("build").path("rustc").render_steps()); } #[test] @@ -460,174 +447,158 @@ mod snapshot { #[test] fn build_compiler_stage_1() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("build") - .path("compiler") - .stage(1) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 "#]] + .assert_eq(&ctx.config("build").path("compiler").stage(1).render_steps()); } #[test] fn build_compiler_stage_2() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("build") - .path("compiler") - .stage(2) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 1 -> rustc 2 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> rustc 2 "#]] + .assert_eq(&ctx.config("build").path("compiler").stage(2).render_steps()); } #[test] fn build_compiler_stage_3() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("build") - .path("compiler") - .stage(3) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 1 -> rustc 2 - [build] rustc 2 -> std 2 - [build] rustc 2 -> rustc 3 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> rustc 2 + [build] rustc 2 -> std 2 + [build] rustc 2 -> rustc 3 "#]] + .assert_eq(&ctx.config("build").path("compiler").stage(3).render_steps()); } #[test] fn build_compiler_stage_3_cross() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("build") - .path("compiler") - .hosts(&[TEST_TRIPLE_1]) - .stage(3) - .render_steps(), @r" - [build] llvm - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 1 -> rustc 2 - [build] rustc 1 -> std 1 - [build] rustc 2 -> std 2 - [build] rustc 2 -> std 2 - [build] rustc 2 -> rustc 3 - "); + expect_test::expect![[r#" + [build] llvm + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> rustc 2 + [build] rustc 1 -> std 1 + [build] rustc 2 -> std 2 + [build] rustc 2 -> std 2 + [build] rustc 2 -> rustc 3 "#]] + .assert_eq( + &ctx.config("build").path("compiler").hosts(&[TEST_TRIPLE_1]).stage(3).render_steps(), + ); } #[test] fn build_compiler_stage_3_full_bootstrap() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("build") + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> rustc 2 + [build] rustc 2 -> std 2 + [build] rustc 2 -> rustc 3 "#]] + .assert_eq( + &ctx.config("build") .path("compiler") .stage(3) .args(&["--set", "build.full-bootstrap=true"]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 1 -> rustc 2 - [build] rustc 2 -> std 2 - [build] rustc 2 -> rustc 3 - "); + .render_steps(), + ); } #[test] fn build_compiler_stage_3_cross_full_bootstrap() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("build") + expect_test::expect![[r#" + [build] llvm + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> rustc 2 + [build] rustc 2 -> std 2 + [build] rustc 2 -> std 2 + [build] rustc 2 -> rustc 3 "#]] + .assert_eq( + &ctx.config("build") .path("compiler") .stage(3) .hosts(&[TEST_TRIPLE_1]) .args(&["--set", "build.full-bootstrap=true"]) - .render_steps(), @r" - [build] llvm - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 1 -> rustc 2 - [build] rustc 2 -> std 2 - [build] rustc 2 -> std 2 - [build] rustc 2 -> rustc 3 - "); + .render_steps(), + ); } #[test] fn build_compiler_codegen_backend() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx - .config("build") + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 0 -> rustc_codegen_cranelift 1 + [build] rustc 1 -> std 1 + [build] rustdoc 1 "#]] + .assert_eq( + &ctx.config("build") .args(&["--set", "rust.codegen-backends=['llvm', 'cranelift']"]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 0 -> rustc_codegen_cranelift 1 - [build] rustc 1 -> std 1 - [build] rustdoc 1 - " + .render_steps(), ); } #[test] fn build_compiler_tools() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx - .config("build") + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 0 -> LldWrapper 1 + [build] rustc 0 -> LlvmBitcodeLinker 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> rustc 2 + [build] rustc 1 -> LldWrapper 2 + [build] rustc 1 -> LlvmBitcodeLinker 2 + [build] rustc 2 -> std 2 + [build] rustdoc 2 "#]] + .assert_eq( + &ctx.config("build") .stage(2) .args(&["--set", "rust.lld=true", "--set", "rust.llvm-bitcode-linker=true"]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 0 -> LldWrapper 1 - [build] rustc 0 -> LlvmBitcodeLinker 1 - [build] rustc 1 -> std 1 - [build] rustc 1 -> rustc 2 - [build] rustc 1 -> LldWrapper 2 - [build] rustc 1 -> LlvmBitcodeLinker 2 - [build] rustc 2 -> std 2 - [build] rustdoc 2 - " + .render_steps(), ); } #[test] fn build_compiler_tools_cross() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx - .config("build") + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 0 -> LldWrapper 1 + [build] rustc 0 -> LlvmBitcodeLinker 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> rustc 2 + [build] rustc 1 -> LldWrapper 2 + [build] rustc 1 -> LlvmBitcodeLinker 2 + [build] rustc 1 -> std 1 + [build] rustc 2 -> std 2 + [build] llvm + [build] rustc 1 -> rustc 2 + [build] rustc 1 -> LldWrapper 2 + [build] rustc 1 -> LlvmBitcodeLinker 2 + [build] rustdoc 2 "#]] + .assert_eq( + &ctx.config("build") .stage(2) .args(&["--set", "rust.lld=true", "--set", "rust.llvm-bitcode-linker=true"]) .hosts(&[TEST_TRIPLE_1]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 0 -> LldWrapper 1 - [build] rustc 0 -> LlvmBitcodeLinker 1 - [build] rustc 1 -> std 1 - [build] rustc 1 -> rustc 2 - [build] rustc 1 -> LldWrapper 2 - [build] rustc 1 -> LlvmBitcodeLinker 2 - [build] rustc 1 -> std 1 - [build] rustc 2 -> std 2 - [build] llvm - [build] rustc 1 -> rustc 2 - [build] rustc 1 -> LldWrapper 2 - [build] rustc 1 -> LlvmBitcodeLinker 2 - [build] rustdoc 2 - " + .render_steps(), ); } @@ -637,14 +608,11 @@ mod snapshot { [(host_target(), DefaultLinuxLinkerOverride::SelfContainedLldCc)].into(), || { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("build") - .path("compiler") - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 0 -> LldWrapper 1 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 0 -> LldWrapper 1 "#]] + .assert_eq(&ctx.config("build").path("compiler").render_steps()); }, ); } @@ -655,14 +623,15 @@ mod snapshot { [(host_target(), DefaultLinuxLinkerOverride::SelfContainedLldCc)].into(), || { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("build") - .path("compiler") - .args(&["--set", "rust.lld=false"]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 "#]] + .assert_eq( + &ctx.config("build") + .path("compiler") + .args(&["--set", "rust.lld=false"]) + .render_steps(), + ); }, ); } @@ -670,14 +639,11 @@ mod snapshot { #[test] fn build_library_no_explicit_stage() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("build") - .path("library") - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 "#]] + .assert_eq(&ctx.config("build").path("library").render_steps()); } #[test] @@ -690,56 +656,46 @@ mod snapshot { #[test] fn build_library_stage_0_local_rebuild() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("build") + expect_test::expect![["[build] rustc 0 -> std 0 "]].assert_eq( + &ctx.config("build") .path("library") .stage(0) .targets(&[TEST_TRIPLE_1]) .args(&["--set", "build.local-rebuild=true"]) - .render_steps(), @"[build] rustc 0 -> std 0 "); + .render_steps(), + ); } #[test] fn build_library_stage_1() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("build") - .path("library") - .stage(1) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 "#]] + .assert_eq(&ctx.config("build").path("library").stage(1).render_steps()); } #[test] fn build_library_stage_2() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("build") - .path("library") - .stage(2) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 1 -> rustc 2 - [build] rustc 2 -> std 2 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> rustc 2 + [build] rustc 2 -> std 2 "#]] + .assert_eq(&ctx.config("build").path("library").stage(2).render_steps()); } #[test] fn build_miri_no_explicit_stage() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("build") - .path("miri") - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 0 -> miri 1 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 0 -> miri 1 "#]] + .assert_eq(&ctx.config("build").path("miri").render_steps()); } #[test] @@ -752,53 +708,40 @@ mod snapshot { #[test] fn build_miri_stage_1() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("build") - .path("miri") - .stage(1) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 0 -> miri 1 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 0 -> miri 1 "#]] + .assert_eq(&ctx.config("build").path("miri").stage(1).render_steps()); } #[test] fn build_miri_stage_2() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("build") - .path("miri") - .stage(2) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 1 -> rustc 2 - [build] rustc 1 -> miri 2 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> rustc 2 + [build] rustc 1 -> miri 2 "#]] + .assert_eq(&ctx.config("build").path("miri").stage(2).render_steps()); } #[test] fn build_error_index() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("build") - .path("error_index_generator") - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 0 -> error-index 1 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 0 -> error-index 1 "#]] + .assert_eq(&ctx.config("build").path("error_index_generator").render_steps()); } #[test] fn build_bootstrap_tool_no_explicit_stage() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("build") - .path("opt-dist") - .render_steps(), @"[build] rustc 0 -> OptimizedDist 1 "); + expect_test::expect![["[build] rustc 0 -> OptimizedDist 1 "]] + .assert_eq(&ctx.config("build").path("opt-dist").render_steps()); } #[test] @@ -811,21 +754,15 @@ mod snapshot { #[test] fn build_bootstrap_tool_stage_1() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("build") - .path("opt-dist") - .stage(1) - .render_steps(), @"[build] rustc 0 -> OptimizedDist 1 "); + expect_test::expect![["[build] rustc 0 -> OptimizedDist 1 "]] + .assert_eq(&ctx.config("build").path("opt-dist").stage(1).render_steps()); } #[test] fn build_bootstrap_tool_stage_2() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("build") - .path("opt-dist") - .stage(2) - .render_steps(), @"[build] rustc 0 -> OptimizedDist 1 "); + expect_test::expect![["[build] rustc 0 -> OptimizedDist 1 "]] + .assert_eq(&ctx.config("build").path("opt-dist").stage(2).render_steps()); } #[test] @@ -839,95 +776,81 @@ mod snapshot { #[test] fn alias_and_path_for_library() { let ctx = TestCtx::new(); - insta::assert_snapshot!(ctx.config("build") - .paths(&["library", "core"]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - "); - - insta::assert_snapshot!(ctx.config("build") - .paths(&["std"]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - "); - - insta::assert_snapshot!(ctx.config("build") - .paths(&["core"]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - "); - - insta::assert_snapshot!(ctx.config("build") - .paths(&["alloc"]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - "); - - insta::assert_snapshot!(ctx.config("doc") + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 "#]] + .assert_eq(&ctx.config("build").paths(&["library", "core"]).render_steps()); + + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 "#]] + .assert_eq(&ctx.config("build").paths(&["std"]).render_steps()); + + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 "#]] + .assert_eq(&ctx.config("build").paths(&["core"]).render_steps()); + + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 "#]] + .assert_eq(&ctx.config("build").paths(&["alloc"]).render_steps()); + + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustdoc 1 + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind]"#]].assert_eq(&ctx.config("doc") .paths(&["library", "core"]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustdoc 1 - [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] - "); + .render_steps()); } #[test] fn build_all() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("build") + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> rustc 2 + [build] llvm + [build] rustc 1 -> std 1 + [build] rustc 1 -> rustc 2 + [build] rustc 2 -> std 2 + [build] rustc 2 -> std 2 + [build] rustc 1 -> std 1 + [build] rustc 2 -> std 2 "#]] + .assert_eq( + &ctx.config("build") .stage(2) .paths(&["compiler/rustc", "library"]) .hosts(&[&host_target(), TEST_TRIPLE_1]) .targets(&[&host_target(), TEST_TRIPLE_1, TEST_TRIPLE_2]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 1 -> rustc 2 - [build] llvm - [build] rustc 1 -> std 1 - [build] rustc 1 -> rustc 2 - [build] rustc 2 -> std 2 - [build] rustc 2 -> std 2 - [build] rustc 1 -> std 1 - [build] rustc 2 -> std 2 - "); + .render_steps(), + ); } #[test] fn build_cargo() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("build") - .paths(&["cargo"]) - .render_steps(), @"[build] rustc 0 -> cargo 1 "); + expect_test::expect![["[build] rustc 0 -> cargo 1 "]] + .assert_eq(&ctx.config("build").paths(&["cargo"]).render_steps()); } #[test] fn build_cargo_cross() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("build") - .paths(&["cargo"]) - .hosts(&[TEST_TRIPLE_1]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 1 -> std 1 - [build] rustc 1 -> cargo 2 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> cargo 2 "#]] + .assert_eq(&ctx.config("build").paths(&["cargo"]).hosts(&[TEST_TRIPLE_1]).render_steps()); } #[test] @@ -941,475 +864,457 @@ mod snapshot { let ctx = TestCtx::new(); // Note that stdlib is uplifted, that is why `[dist] rustc 1 -> std ` is in // the output. - insta::assert_snapshot!( - ctx - .config("dist") - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 0 -> UnstableBookGen 1 - [build] rustc 0 -> Rustbook 1 - [doc] unstable-book (book) - [doc] book (book) - [doc] book/first-edition (book) - [doc] book/second-edition (book) - [doc] book/2018-edition (book) - [build] rustdoc 1 - [doc] rustc 1 -> standalone 2 - [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] - [build] rustc 1 -> rustc 2 - [build] rustc 1 -> error-index 2 - [doc] rustc 1 -> error-index 2 - [doc] nomicon (book) - [doc] rustc 1 -> reference (book) 2 - [doc] rustdoc (book) - [doc] rust-by-example (book) - [build] rustc 0 -> LintDocs 1 - [doc] rustc (book) - [doc] cargo (book) - [doc] clippy (book) - [doc] embedded-book (book) - [doc] edition-guide (book) - [doc] style-guide (book) - [doc] rustc 1 -> releases 2 - [build] rustc 0 -> RustInstaller 1 - [dist] docs - [doc] rustc 1 -> std 1 crates=[] - [dist] rustc 1 -> json-docs 2 - [dist] mingw - [build] rustdoc 2 - [build] rustc 0 -> GenerateCopyright 1 - [dist] rustc - [dist] rustc 1 -> std 1 - [dist] rustc 1 -> rustc-dev 2 - [dist] src <> - [dist] reproducible-artifacts - " - ); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 0 -> UnstableBookGen 1 + [build] rustc 0 -> Rustbook 1 + [doc] unstable-book (book) + [doc] book (book) + [doc] book/first-edition (book) + [doc] book/second-edition (book) + [doc] book/2018-edition (book) + [build] rustdoc 1 + [doc] rustc 1 -> standalone 2 + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] + [build] rustc 1 -> rustc 2 + [build] rustc 1 -> error-index 2 + [doc] rustc 1 -> error-index 2 + [doc] nomicon (book) + [doc] rustc 1 -> reference (book) 2 + [doc] rustdoc (book) + [doc] rust-by-example (book) + [build] rustc 0 -> LintDocs 1 + [doc] rustc (book) + [doc] cargo (book) + [doc] clippy (book) + [doc] embedded-book (book) + [doc] edition-guide (book) + [doc] style-guide (book) + [doc] rustc 1 -> releases 2 + [build] rustc 0 -> RustInstaller 1 + [dist] docs + [doc] rustc 1 -> std 1 crates=[] + [dist] rustc 1 -> json-docs 2 + [dist] mingw + [build] rustdoc 2 + [build] rustc 0 -> GenerateCopyright 1 + [dist] rustc + [dist] rustc 1 -> std 1 + [dist] rustc 1 -> rustc-dev 2 + [dist] src <> + [dist] reproducible-artifacts "#]].assert_eq(&ctx + .config("dist") + .render_steps()); } #[test] fn dist_extended() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("dist") - .args(&[ - "--set", - "build.extended=true", - "--set", - "rust.llvm-bitcode-linker=true", - "--set", - "rust.lld=true", - ]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 0 -> LldWrapper 1 - [build] rustc 0 -> WasmComponentLd 1 - [build] rustc 0 -> LlvmBitcodeLinker 1 - [build] rustc 1 -> std 1 - [build] rustc 0 -> UnstableBookGen 1 - [build] rustc 0 -> Rustbook 1 - [doc] unstable-book (book) - [doc] book (book) - [doc] book/first-edition (book) - [doc] book/second-edition (book) - [doc] book/2018-edition (book) - [build] rustdoc 1 - [doc] rustc 1 -> standalone 2 - [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] - [build] rustc 1 -> rustc 2 - [build] rustc 1 -> LldWrapper 2 - [build] rustc 1 -> WasmComponentLd 2 - [build] rustc 1 -> LlvmBitcodeLinker 2 - [build] rustc 1 -> error-index 2 - [doc] rustc 1 -> error-index 2 - [doc] nomicon (book) - [doc] rustc 1 -> reference (book) 2 - [doc] rustdoc (book) - [doc] rust-by-example (book) - [build] rustc 0 -> LintDocs 1 - [doc] rustc (book) - [doc] cargo (book) - [doc] clippy (book) - [doc] embedded-book (book) - [doc] edition-guide (book) - [doc] style-guide (book) - [doc] rustc 1 -> releases 2 - [build] rustc 0 -> RustInstaller 1 - [dist] docs - [doc] rustc 1 -> std 1 crates=[] - [dist] rustc 1 -> json-docs 2 - [dist] mingw - [build] rustdoc 2 - [build] rustc 1 -> rust-analyzer-proc-macro-srv 2 - [build] rustc 0 -> GenerateCopyright 1 - [dist] rustc - [dist] rustc 1 -> std 1 - [dist] rustc 1 -> rustc-dev 2 - [dist] rustc 1 -> analysis 2 - [dist] src <> - [build] rustc 1 -> cargo 2 - [dist] rustc 1 -> cargo 2 - [build] rustc 1 -> rust-analyzer 2 - [dist] rustc 1 -> rust-analyzer 2 - [build] rustc 1 -> rustfmt 2 - [build] rustc 1 -> cargo-fmt 2 - [dist] rustc 1 -> rustfmt 2 - [build] rustc 1 -> clippy-driver 2 - [build] rustc 1 -> cargo-clippy 2 - [dist] rustc 1 -> clippy 2 - [build] rustc 1 -> miri 2 - [build] rustc 1 -> cargo-miri 2 - [dist] rustc 1 -> miri 2 - [doc] rustc 2 -> std 2 crates=[] - [dist] rustc 2 -> json-docs 3 - [dist] rustc 1 -> extended 2 - [dist] reproducible-artifacts - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 0 -> LldWrapper 1 + [build] rustc 0 -> WasmComponentLd 1 + [build] rustc 0 -> LlvmBitcodeLinker 1 + [build] rustc 1 -> std 1 + [build] rustc 0 -> UnstableBookGen 1 + [build] rustc 0 -> Rustbook 1 + [doc] unstable-book (book) + [doc] book (book) + [doc] book/first-edition (book) + [doc] book/second-edition (book) + [doc] book/2018-edition (book) + [build] rustdoc 1 + [doc] rustc 1 -> standalone 2 + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] + [build] rustc 1 -> rustc 2 + [build] rustc 1 -> LldWrapper 2 + [build] rustc 1 -> WasmComponentLd 2 + [build] rustc 1 -> LlvmBitcodeLinker 2 + [build] rustc 1 -> error-index 2 + [doc] rustc 1 -> error-index 2 + [doc] nomicon (book) + [doc] rustc 1 -> reference (book) 2 + [doc] rustdoc (book) + [doc] rust-by-example (book) + [build] rustc 0 -> LintDocs 1 + [doc] rustc (book) + [doc] cargo (book) + [doc] clippy (book) + [doc] embedded-book (book) + [doc] edition-guide (book) + [doc] style-guide (book) + [doc] rustc 1 -> releases 2 + [build] rustc 0 -> RustInstaller 1 + [dist] docs + [doc] rustc 1 -> std 1 crates=[] + [dist] rustc 1 -> json-docs 2 + [dist] mingw + [build] rustdoc 2 + [build] rustc 1 -> rust-analyzer-proc-macro-srv 2 + [build] rustc 0 -> GenerateCopyright 1 + [dist] rustc + [dist] rustc 1 -> std 1 + [dist] rustc 1 -> rustc-dev 2 + [dist] rustc 1 -> analysis 2 + [dist] src <> + [build] rustc 1 -> cargo 2 + [dist] rustc 1 -> cargo 2 + [build] rustc 1 -> rust-analyzer 2 + [dist] rustc 1 -> rust-analyzer 2 + [build] rustc 1 -> rustfmt 2 + [build] rustc 1 -> cargo-fmt 2 + [dist] rustc 1 -> rustfmt 2 + [build] rustc 1 -> clippy-driver 2 + [build] rustc 1 -> cargo-clippy 2 + [dist] rustc 1 -> clippy 2 + [build] rustc 1 -> miri 2 + [build] rustc 1 -> cargo-miri 2 + [dist] rustc 1 -> miri 2 + [doc] rustc 2 -> std 2 crates=[] + [dist] rustc 2 -> json-docs 3 + [dist] rustc 1 -> extended 2 + [dist] reproducible-artifacts "#]].assert_eq(&ctx.config("dist") + .args(&[ + "--set", + "build.extended=true", + "--set", + "rust.llvm-bitcode-linker=true", + "--set", + "rust.lld=true", + ]) + .render_steps()); } #[test] fn dist_with_targets() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx - .config("dist") - .hosts(&[&host_target()]) - .targets(&[&host_target(), TEST_TRIPLE_1]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 0 -> UnstableBookGen 1 - [build] rustc 0 -> Rustbook 1 - [doc] unstable-book (book) - [build] rustc 1 -> std 1 - [doc] unstable-book (book) - [doc] book (book) - [doc] book/first-edition (book) - [doc] book/second-edition (book) - [doc] book/2018-edition (book) - [doc] book (book) - [doc] book/first-edition (book) - [doc] book/second-edition (book) - [doc] book/2018-edition (book) - [build] rustdoc 1 - [doc] rustc 1 -> standalone 2 - [doc] rustc 1 -> standalone 2 - [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] - [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] - [build] rustc 1 -> rustc 2 - [build] rustc 1 -> error-index 2 - [doc] rustc 1 -> error-index 2 - [doc] nomicon (book) - [doc] nomicon (book) - [doc] rustc 1 -> reference (book) 2 - [doc] rustc 1 -> reference (book) 2 - [doc] rustdoc (book) - [doc] rustdoc (book) - [doc] rust-by-example (book) - [doc] rust-by-example (book) - [build] rustc 0 -> LintDocs 1 - [doc] rustc (book) - [doc] cargo (book) - [doc] cargo (book) - [doc] clippy (book) - [doc] clippy (book) - [doc] embedded-book (book) - [doc] embedded-book (book) - [doc] edition-guide (book) - [doc] edition-guide (book) - [doc] style-guide (book) - [doc] style-guide (book) - [doc] rustc 1 -> releases 2 - [doc] rustc 1 -> releases 2 - [build] rustc 0 -> RustInstaller 1 - [dist] docs - [dist] docs - [doc] rustc 1 -> std 1 crates=[] - [dist] rustc 1 -> json-docs 2 - [doc] rustc 1 -> std 1 crates=[] - [dist] rustc 1 -> json-docs 2 - [dist] mingw - [dist] mingw - [build] rustdoc 2 - [build] rustc 0 -> GenerateCopyright 1 - [dist] rustc - [dist] rustc 1 -> std 1 - [dist] rustc 1 -> std 1 - [dist] rustc 1 -> rustc-dev 2 - [dist] src <> - [dist] reproducible-artifacts - " - ); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 0 -> UnstableBookGen 1 + [build] rustc 0 -> Rustbook 1 + [doc] unstable-book (book) + [build] rustc 1 -> std 1 + [doc] unstable-book (book) + [doc] book (book) + [doc] book/first-edition (book) + [doc] book/second-edition (book) + [doc] book/2018-edition (book) + [doc] book (book) + [doc] book/first-edition (book) + [doc] book/second-edition (book) + [doc] book/2018-edition (book) + [build] rustdoc 1 + [doc] rustc 1 -> standalone 2 + [doc] rustc 1 -> standalone 2 + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] + [build] rustc 1 -> rustc 2 + [build] rustc 1 -> error-index 2 + [doc] rustc 1 -> error-index 2 + [doc] nomicon (book) + [doc] nomicon (book) + [doc] rustc 1 -> reference (book) 2 + [doc] rustc 1 -> reference (book) 2 + [doc] rustdoc (book) + [doc] rustdoc (book) + [doc] rust-by-example (book) + [doc] rust-by-example (book) + [build] rustc 0 -> LintDocs 1 + [doc] rustc (book) + [doc] cargo (book) + [doc] cargo (book) + [doc] clippy (book) + [doc] clippy (book) + [doc] embedded-book (book) + [doc] embedded-book (book) + [doc] edition-guide (book) + [doc] edition-guide (book) + [doc] style-guide (book) + [doc] style-guide (book) + [doc] rustc 1 -> releases 2 + [doc] rustc 1 -> releases 2 + [build] rustc 0 -> RustInstaller 1 + [dist] docs + [dist] docs + [doc] rustc 1 -> std 1 crates=[] + [dist] rustc 1 -> json-docs 2 + [doc] rustc 1 -> std 1 crates=[] + [dist] rustc 1 -> json-docs 2 + [dist] mingw + [dist] mingw + [build] rustdoc 2 + [build] rustc 0 -> GenerateCopyright 1 + [dist] rustc + [dist] rustc 1 -> std 1 + [dist] rustc 1 -> std 1 + [dist] rustc 1 -> rustc-dev 2 + [dist] src <> + [dist] reproducible-artifacts "#]].assert_eq(&ctx + .config("dist") + .hosts(&[&host_target()]) + .targets(&[&host_target(), TEST_TRIPLE_1]) + .render_steps()); } #[test] fn dist_with_hosts() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx - .config("dist") - .hosts(&[&host_target(), TEST_TRIPLE_1]) - .targets(&[&host_target()]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 0 -> UnstableBookGen 1 - [build] rustc 0 -> Rustbook 1 - [doc] unstable-book (book) - [build] rustc 1 -> std 1 - [doc] book (book) - [doc] book/first-edition (book) - [doc] book/second-edition (book) - [doc] book/2018-edition (book) - [build] rustdoc 1 - [doc] rustc 1 -> standalone 2 - [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] - [build] rustc 1 -> rustc 2 - [build] rustc 1 -> error-index 2 - [doc] rustc 1 -> error-index 2 - [build] llvm - [build] rustc 1 -> rustc 2 - [build] rustc 1 -> error-index 2 - [doc] rustc 1 -> error-index 2 - [doc] nomicon (book) - [doc] rustc 1 -> reference (book) 2 - [doc] rustdoc (book) - [doc] rust-by-example (book) - [build] rustc 0 -> LintDocs 1 - [doc] rustc (book) - [doc] rustc (book) - [doc] cargo (book) - [doc] clippy (book) - [doc] embedded-book (book) - [doc] edition-guide (book) - [doc] style-guide (book) - [doc] rustc 1 -> releases 2 - [build] rustc 0 -> RustInstaller 1 - [dist] docs - [doc] rustc 1 -> std 1 crates=[] - [dist] rustc 1 -> json-docs 2 - [dist] mingw - [build] rustdoc 2 - [build] rustc 0 -> GenerateCopyright 1 - [dist] rustc - [build] rustdoc 2 - [dist] rustc - [dist] rustc 1 -> std 1 - [dist] rustc 1 -> rustc-dev 2 - [dist] rustc 1 -> rustc-dev 2 - [dist] src <> - [dist] reproducible-artifacts - [dist] reproducible-artifacts - " - ); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 0 -> UnstableBookGen 1 + [build] rustc 0 -> Rustbook 1 + [doc] unstable-book (book) + [build] rustc 1 -> std 1 + [doc] book (book) + [doc] book/first-edition (book) + [doc] book/second-edition (book) + [doc] book/2018-edition (book) + [build] rustdoc 1 + [doc] rustc 1 -> standalone 2 + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] + [build] rustc 1 -> rustc 2 + [build] rustc 1 -> error-index 2 + [doc] rustc 1 -> error-index 2 + [build] llvm + [build] rustc 1 -> rustc 2 + [build] rustc 1 -> error-index 2 + [doc] rustc 1 -> error-index 2 + [doc] nomicon (book) + [doc] rustc 1 -> reference (book) 2 + [doc] rustdoc (book) + [doc] rust-by-example (book) + [build] rustc 0 -> LintDocs 1 + [doc] rustc (book) + [doc] rustc (book) + [doc] cargo (book) + [doc] clippy (book) + [doc] embedded-book (book) + [doc] edition-guide (book) + [doc] style-guide (book) + [doc] rustc 1 -> releases 2 + [build] rustc 0 -> RustInstaller 1 + [dist] docs + [doc] rustc 1 -> std 1 crates=[] + [dist] rustc 1 -> json-docs 2 + [dist] mingw + [build] rustdoc 2 + [build] rustc 0 -> GenerateCopyright 1 + [dist] rustc + [build] rustdoc 2 + [dist] rustc + [dist] rustc 1 -> std 1 + [dist] rustc 1 -> rustc-dev 2 + [dist] rustc 1 -> rustc-dev 2 + [dist] src <> + [dist] reproducible-artifacts + [dist] reproducible-artifacts "#]].assert_eq(&ctx + .config("dist") + .hosts(&[&host_target(), TEST_TRIPLE_1]) + .targets(&[&host_target()]) + .render_steps()); } #[test] fn dist_with_targets_and_hosts() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx - .config("dist") - .hosts(&[&host_target(), TEST_TRIPLE_1]) - .targets(&[&host_target(), TEST_TRIPLE_1]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 0 -> UnstableBookGen 1 - [build] rustc 0 -> Rustbook 1 - [doc] unstable-book (book) - [build] rustc 1 -> std 1 - [doc] unstable-book (book) - [doc] book (book) - [doc] book/first-edition (book) - [doc] book/second-edition (book) - [doc] book/2018-edition (book) - [doc] book (book) - [doc] book/first-edition (book) - [doc] book/second-edition (book) - [doc] book/2018-edition (book) - [build] rustdoc 1 - [doc] rustc 1 -> standalone 2 - [doc] rustc 1 -> standalone 2 - [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] - [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] - [build] rustc 1 -> rustc 2 - [build] rustc 1 -> error-index 2 - [doc] rustc 1 -> error-index 2 - [build] llvm - [build] rustc 1 -> rustc 2 - [build] rustc 1 -> error-index 2 - [doc] rustc 1 -> error-index 2 - [doc] nomicon (book) - [doc] nomicon (book) - [doc] rustc 1 -> reference (book) 2 - [doc] rustc 1 -> reference (book) 2 - [doc] rustdoc (book) - [doc] rustdoc (book) - [doc] rust-by-example (book) - [doc] rust-by-example (book) - [build] rustc 0 -> LintDocs 1 - [doc] rustc (book) - [doc] rustc (book) - [doc] cargo (book) - [doc] cargo (book) - [doc] clippy (book) - [doc] clippy (book) - [doc] embedded-book (book) - [doc] embedded-book (book) - [doc] edition-guide (book) - [doc] edition-guide (book) - [doc] style-guide (book) - [doc] style-guide (book) - [doc] rustc 1 -> releases 2 - [doc] rustc 1 -> releases 2 - [build] rustc 0 -> RustInstaller 1 - [dist] docs - [dist] docs - [doc] rustc 1 -> std 1 crates=[] - [dist] rustc 1 -> json-docs 2 - [doc] rustc 1 -> std 1 crates=[] - [dist] rustc 1 -> json-docs 2 - [dist] mingw - [dist] mingw - [build] rustdoc 2 - [build] rustc 0 -> GenerateCopyright 1 - [dist] rustc - [build] rustdoc 2 - [dist] rustc - [dist] rustc 1 -> std 1 - [dist] rustc 1 -> std 1 - [dist] rustc 1 -> rustc-dev 2 - [dist] rustc 1 -> rustc-dev 2 - [dist] src <> - [dist] reproducible-artifacts - [dist] reproducible-artifacts - " - ); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 0 -> UnstableBookGen 1 + [build] rustc 0 -> Rustbook 1 + [doc] unstable-book (book) + [build] rustc 1 -> std 1 + [doc] unstable-book (book) + [doc] book (book) + [doc] book/first-edition (book) + [doc] book/second-edition (book) + [doc] book/2018-edition (book) + [doc] book (book) + [doc] book/first-edition (book) + [doc] book/second-edition (book) + [doc] book/2018-edition (book) + [build] rustdoc 1 + [doc] rustc 1 -> standalone 2 + [doc] rustc 1 -> standalone 2 + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] + [build] rustc 1 -> rustc 2 + [build] rustc 1 -> error-index 2 + [doc] rustc 1 -> error-index 2 + [build] llvm + [build] rustc 1 -> rustc 2 + [build] rustc 1 -> error-index 2 + [doc] rustc 1 -> error-index 2 + [doc] nomicon (book) + [doc] nomicon (book) + [doc] rustc 1 -> reference (book) 2 + [doc] rustc 1 -> reference (book) 2 + [doc] rustdoc (book) + [doc] rustdoc (book) + [doc] rust-by-example (book) + [doc] rust-by-example (book) + [build] rustc 0 -> LintDocs 1 + [doc] rustc (book) + [doc] rustc (book) + [doc] cargo (book) + [doc] cargo (book) + [doc] clippy (book) + [doc] clippy (book) + [doc] embedded-book (book) + [doc] embedded-book (book) + [doc] edition-guide (book) + [doc] edition-guide (book) + [doc] style-guide (book) + [doc] style-guide (book) + [doc] rustc 1 -> releases 2 + [doc] rustc 1 -> releases 2 + [build] rustc 0 -> RustInstaller 1 + [dist] docs + [dist] docs + [doc] rustc 1 -> std 1 crates=[] + [dist] rustc 1 -> json-docs 2 + [doc] rustc 1 -> std 1 crates=[] + [dist] rustc 1 -> json-docs 2 + [dist] mingw + [dist] mingw + [build] rustdoc 2 + [build] rustc 0 -> GenerateCopyright 1 + [dist] rustc + [build] rustdoc 2 + [dist] rustc + [dist] rustc 1 -> std 1 + [dist] rustc 1 -> std 1 + [dist] rustc 1 -> rustc-dev 2 + [dist] rustc 1 -> rustc-dev 2 + [dist] src <> + [dist] reproducible-artifacts + [dist] reproducible-artifacts "#]].assert_eq(&ctx + .config("dist") + .hosts(&[&host_target(), TEST_TRIPLE_1]) + .targets(&[&host_target(), TEST_TRIPLE_1]) + .render_steps()); } #[test] fn dist_with_empty_host() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx - .config("dist") - .hosts(&[]) - .targets(&[TEST_TRIPLE_1]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 0 -> UnstableBookGen 1 - [build] rustc 0 -> Rustbook 1 - [doc] unstable-book (book) - [doc] book (book) - [doc] book/first-edition (book) - [doc] book/second-edition (book) - [doc] book/2018-edition (book) - [build] rustc 1 -> std 1 - [build] rustdoc 1 - [doc] rustc 1 -> standalone 2 - [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] - [doc] nomicon (book) - [doc] rustc 1 -> reference (book) 2 - [doc] rustdoc (book) - [doc] rust-by-example (book) - [doc] cargo (book) - [doc] clippy (book) - [doc] embedded-book (book) - [doc] edition-guide (book) - [doc] style-guide (book) - [doc] rustc 1 -> releases 2 - [build] rustc 0 -> RustInstaller 1 - [dist] docs - [doc] rustc 1 -> std 1 crates=[] - [dist] rustc 1 -> json-docs 2 - [dist] mingw - [dist] rustc 1 -> std 1 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 0 -> UnstableBookGen 1 + [build] rustc 0 -> Rustbook 1 + [doc] unstable-book (book) + [doc] book (book) + [doc] book/first-edition (book) + [doc] book/second-edition (book) + [doc] book/2018-edition (book) + [build] rustc 1 -> std 1 + [build] rustdoc 1 + [doc] rustc 1 -> standalone 2 + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] + [doc] nomicon (book) + [doc] rustc 1 -> reference (book) 2 + [doc] rustdoc (book) + [doc] rust-by-example (book) + [doc] cargo (book) + [doc] clippy (book) + [doc] embedded-book (book) + [doc] edition-guide (book) + [doc] style-guide (book) + [doc] rustc 1 -> releases 2 + [build] rustc 0 -> RustInstaller 1 + [dist] docs + [doc] rustc 1 -> std 1 crates=[] + [dist] rustc 1 -> json-docs 2 + [dist] mingw + [dist] rustc 1 -> std 1 "#]].assert_eq(&ctx + .config("dist") + .hosts(&[]) + .targets(&[TEST_TRIPLE_1]) + .render_steps()); } #[test] fn dist_all_cross_extended() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx - .config("dist") - .hosts(&[TEST_TRIPLE_1]) - .targets(&[TEST_TRIPLE_1]) - .args(&["--set", "rust.channel=nightly", "--set", "build.extended=true"]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 0 -> WasmComponentLd 1 - [build] rustc 1 -> std 1 - [build] rustc 0 -> UnstableBookGen 1 - [build] rustc 0 -> Rustbook 1 - [doc] unstable-book (book) - [doc] book (book) - [doc] book/first-edition (book) - [doc] book/second-edition (book) - [doc] book/2018-edition (book) - [build] rustc 1 -> std 1 - [build] rustdoc 1 - [doc] rustc 1 -> standalone 2 - [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] - [build] llvm - [build] rustc 1 -> rustc 2 - [build] rustc 1 -> WasmComponentLd 2 - [build] rustc 1 -> error-index 2 - [doc] rustc 1 -> error-index 2 - [doc] nomicon (book) - [doc] rustc 1 -> reference (book) 2 - [doc] rustdoc (book) - [doc] rust-by-example (book) - [build] rustc 0 -> LintDocs 1 - [doc] rustc (book) - [doc] cargo (book) - [doc] clippy (book) - [doc] embedded-book (book) - [doc] edition-guide (book) - [doc] style-guide (book) - [doc] rustc 1 -> releases 2 - [build] rustc 0 -> RustInstaller 1 - [dist] docs - [doc] rustc 1 -> std 1 crates=[] - [dist] rustc 1 -> json-docs 2 - [dist] mingw - [build] rustdoc 2 - [build] rustc 1 -> rust-analyzer-proc-macro-srv 2 - [build] rustc 0 -> GenerateCopyright 1 - [dist] rustc - [dist] rustc 1 -> std 1 - [dist] rustc 1 -> rustc-dev 2 - [dist] rustc 1 -> analysis 2 - [dist] src <> - [build] rustc 1 -> cargo 2 - [dist] rustc 1 -> cargo 2 - [build] rustc 1 -> rust-analyzer 2 - [dist] rustc 1 -> rust-analyzer 2 - [build] rustc 1 -> rustfmt 2 - [build] rustc 1 -> cargo-fmt 2 - [dist] rustc 1 -> rustfmt 2 - [build] rustc 1 -> clippy-driver 2 - [build] rustc 1 -> cargo-clippy 2 - [dist] rustc 1 -> clippy 2 - [build] rustc 1 -> miri 2 - [build] rustc 1 -> cargo-miri 2 - [dist] rustc 1 -> miri 2 - [build] rustc 1 -> LlvmBitcodeLinker 2 - [doc] rustc 2 -> std 2 crates=[] - [dist] rustc 2 -> json-docs 3 - [dist] rustc 1 -> extended 2 - [dist] reproducible-artifacts - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 0 -> WasmComponentLd 1 + [build] rustc 1 -> std 1 + [build] rustc 0 -> UnstableBookGen 1 + [build] rustc 0 -> Rustbook 1 + [doc] unstable-book (book) + [doc] book (book) + [doc] book/first-edition (book) + [doc] book/second-edition (book) + [doc] book/2018-edition (book) + [build] rustc 1 -> std 1 + [build] rustdoc 1 + [doc] rustc 1 -> standalone 2 + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] + [build] llvm + [build] rustc 1 -> rustc 2 + [build] rustc 1 -> WasmComponentLd 2 + [build] rustc 1 -> error-index 2 + [doc] rustc 1 -> error-index 2 + [doc] nomicon (book) + [doc] rustc 1 -> reference (book) 2 + [doc] rustdoc (book) + [doc] rust-by-example (book) + [build] rustc 0 -> LintDocs 1 + [doc] rustc (book) + [doc] cargo (book) + [doc] clippy (book) + [doc] embedded-book (book) + [doc] edition-guide (book) + [doc] style-guide (book) + [doc] rustc 1 -> releases 2 + [build] rustc 0 -> RustInstaller 1 + [dist] docs + [doc] rustc 1 -> std 1 crates=[] + [dist] rustc 1 -> json-docs 2 + [dist] mingw + [build] rustdoc 2 + [build] rustc 1 -> rust-analyzer-proc-macro-srv 2 + [build] rustc 0 -> GenerateCopyright 1 + [dist] rustc + [dist] rustc 1 -> std 1 + [dist] rustc 1 -> rustc-dev 2 + [dist] rustc 1 -> analysis 2 + [dist] src <> + [build] rustc 1 -> cargo 2 + [dist] rustc 1 -> cargo 2 + [build] rustc 1 -> rust-analyzer 2 + [dist] rustc 1 -> rust-analyzer 2 + [build] rustc 1 -> rustfmt 2 + [build] rustc 1 -> cargo-fmt 2 + [dist] rustc 1 -> rustfmt 2 + [build] rustc 1 -> clippy-driver 2 + [build] rustc 1 -> cargo-clippy 2 + [dist] rustc 1 -> clippy 2 + [build] rustc 1 -> miri 2 + [build] rustc 1 -> cargo-miri 2 + [dist] rustc 1 -> miri 2 + [build] rustc 1 -> LlvmBitcodeLinker 2 + [doc] rustc 2 -> std 2 crates=[] + [dist] rustc 2 -> json-docs 3 + [dist] rustc 1 -> extended 2 + [dist] reproducible-artifacts "#]].assert_eq(&ctx + .config("dist") + .hosts(&[TEST_TRIPLE_1]) + .targets(&[TEST_TRIPLE_1]) + .args(&["--set", "rust.channel=nightly", "--set", "build.extended=true"]) + .render_steps()); } /// Simulates e.g. the powerpc64 builder, which is fully cross-compiled from x64, but it does @@ -1441,43 +1346,42 @@ mod snapshot { && *m.target.triple == host_target() }); - insta::assert_snapshot!( - steps.render(), @r" - [dist] mingw - [build] llvm - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 0 -> WasmComponentLd 1 - [build] rustc 1 -> std 1 - [build] rustc 1 -> std 1 - [build] rustc 1 -> rustc 2 - [build] rustc 1 -> WasmComponentLd 2 - [build] rustdoc 2 - [build] rustc 1 -> rust-analyzer-proc-macro-srv 2 - [build] rustc 0 -> GenerateCopyright 1 - [build] rustc 0 -> RustInstaller 1 - [dist] rustc - [dist] rustc 1 -> std 1 - [dist] rustc 1 -> rustc-dev 2 - [dist] rustc 1 -> analysis 2 - [dist] src <> - [build] rustc 1 -> cargo 2 - [dist] rustc 1 -> cargo 2 - [build] rustc 1 -> rust-analyzer 2 - [dist] rustc 1 -> rust-analyzer 2 - [build] rustc 1 -> rustfmt 2 - [build] rustc 1 -> cargo-fmt 2 - [dist] rustc 1 -> rustfmt 2 - [build] rustc 1 -> clippy-driver 2 - [build] rustc 1 -> cargo-clippy 2 - [dist] rustc 1 -> clippy 2 - [build] rustc 1 -> miri 2 - [build] rustc 1 -> cargo-miri 2 - [dist] rustc 1 -> miri 2 - [build] rustc 1 -> LlvmBitcodeLinker 2 - [dist] rustc 1 -> extended 2 - [dist] reproducible-artifacts - "); + expect_test::expect![[r#" + [dist] mingw + [build] llvm + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 0 -> WasmComponentLd 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> rustc 2 + [build] rustc 1 -> WasmComponentLd 2 + [build] rustdoc 2 + [build] rustc 1 -> rust-analyzer-proc-macro-srv 2 + [build] rustc 0 -> GenerateCopyright 1 + [build] rustc 0 -> RustInstaller 1 + [dist] rustc + [dist] rustc 1 -> std 1 + [dist] rustc 1 -> rustc-dev 2 + [dist] rustc 1 -> analysis 2 + [dist] src <> + [build] rustc 1 -> cargo 2 + [dist] rustc 1 -> cargo 2 + [build] rustc 1 -> rust-analyzer 2 + [dist] rustc 1 -> rust-analyzer 2 + [build] rustc 1 -> rustfmt 2 + [build] rustc 1 -> cargo-fmt 2 + [dist] rustc 1 -> rustfmt 2 + [build] rustc 1 -> clippy-driver 2 + [build] rustc 1 -> cargo-clippy 2 + [dist] rustc 1 -> clippy 2 + [build] rustc 1 -> miri 2 + [build] rustc 1 -> cargo-miri 2 + [dist] rustc 1 -> miri 2 + [build] rustc 1 -> LlvmBitcodeLinker 2 + [dist] rustc 1 -> extended 2 + [dist] reproducible-artifacts "#]] + .assert_eq(&steps.render()); } /// Enable dist cranelift tarball by default with `x dist` if cranelift is enabled in @@ -1485,131 +1389,118 @@ mod snapshot { #[test] fn dist_cranelift_by_default() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx - .config("dist") - .args(&["--set", "rust.codegen-backends=['llvm', 'cranelift']"]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 0 -> rustc_codegen_cranelift 1 - [build] rustc 1 -> std 1 - [build] rustc 0 -> UnstableBookGen 1 - [build] rustc 0 -> Rustbook 1 - [doc] unstable-book (book) - [doc] book (book) - [doc] book/first-edition (book) - [doc] book/second-edition (book) - [doc] book/2018-edition (book) - [build] rustdoc 1 - [doc] rustc 1 -> standalone 2 - [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] - [build] rustc 1 -> rustc 2 - [build] rustc 1 -> rustc_codegen_cranelift 2 - [build] rustc 1 -> error-index 2 - [doc] rustc 1 -> error-index 2 - [doc] nomicon (book) - [doc] rustc 1 -> reference (book) 2 - [doc] rustdoc (book) - [doc] rust-by-example (book) - [build] rustc 0 -> LintDocs 1 - [doc] rustc (book) - [doc] cargo (book) - [doc] clippy (book) - [doc] embedded-book (book) - [doc] edition-guide (book) - [doc] style-guide (book) - [doc] rustc 1 -> releases 2 - [build] rustc 0 -> RustInstaller 1 - [dist] docs - [doc] rustc 1 -> std 1 crates=[] - [dist] rustc 1 -> json-docs 2 - [dist] mingw - [build] rustdoc 2 - [build] rustc 0 -> GenerateCopyright 1 - [dist] rustc - [dist] rustc 1 -> rustc_codegen_cranelift 2 - [dist] rustc 1 -> std 1 - [dist] rustc 1 -> rustc-dev 2 - [dist] src <> - [dist] reproducible-artifacts - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 0 -> rustc_codegen_cranelift 1 + [build] rustc 1 -> std 1 + [build] rustc 0 -> UnstableBookGen 1 + [build] rustc 0 -> Rustbook 1 + [doc] unstable-book (book) + [doc] book (book) + [doc] book/first-edition (book) + [doc] book/second-edition (book) + [doc] book/2018-edition (book) + [build] rustdoc 1 + [doc] rustc 1 -> standalone 2 + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] + [build] rustc 1 -> rustc 2 + [build] rustc 1 -> rustc_codegen_cranelift 2 + [build] rustc 1 -> error-index 2 + [doc] rustc 1 -> error-index 2 + [doc] nomicon (book) + [doc] rustc 1 -> reference (book) 2 + [doc] rustdoc (book) + [doc] rust-by-example (book) + [build] rustc 0 -> LintDocs 1 + [doc] rustc (book) + [doc] cargo (book) + [doc] clippy (book) + [doc] embedded-book (book) + [doc] edition-guide (book) + [doc] style-guide (book) + [doc] rustc 1 -> releases 2 + [build] rustc 0 -> RustInstaller 1 + [dist] docs + [doc] rustc 1 -> std 1 crates=[] + [dist] rustc 1 -> json-docs 2 + [dist] mingw + [build] rustdoc 2 + [build] rustc 0 -> GenerateCopyright 1 + [dist] rustc + [dist] rustc 1 -> rustc_codegen_cranelift 2 + [dist] rustc 1 -> std 1 + [dist] rustc 1 -> rustc-dev 2 + [dist] src <> + [dist] reproducible-artifacts "#]].assert_eq(&ctx + .config("dist") + .args(&["--set", "rust.codegen-backends=['llvm', 'cranelift']"]) + .render_steps()); } #[test] fn dist_bootstrap() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx - .config("dist") - .path("bootstrap") - .render_steps(), @r" - [build] rustc 0 -> RustInstaller 1 - [dist] bootstrap - "); + expect_test::expect![[r#" + [build] rustc 0 -> RustInstaller 1 + [dist] bootstrap "#]] + .assert_eq(&ctx.config("dist").path("bootstrap").render_steps()); } #[test] fn dist_library_stage_0_local_rebuild() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("dist") + expect_test::expect![[r#" + [build] rustc 0 -> std 0 + [build] rustc 0 -> RustInstaller 1 + [dist] rustc 0 -> std 0 "#]] + .assert_eq( + &ctx.config("dist") .path("rust-std") .stage(0) .targets(&[TEST_TRIPLE_1]) .args(&["--set", "build.local-rebuild=true"]) - .render_steps(), @r" - [build] rustc 0 -> std 0 - [build] rustc 0 -> RustInstaller 1 - [dist] rustc 0 -> std 0 - "); + .render_steps(), + ); } #[test] fn dist_rustc_docs() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx - .config("dist") - .path("rustc-docs") - .render_steps(), @" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustdoc 1 - [doc] rustc 1 -> rustc 2 - [build] rustc 1 -> rustc 2 - [doc] rustc 1 -> Rustdoc 2 - [doc] rustc 1 -> Rustfmt 2 - [doc] rustc 1 -> Clippy 2 - [doc] rustc 1 -> Miri 2 - [doc] rustc 1 -> Cargo 2 - [doc] rustc 1 -> Tidy 2 - [doc] rustc 1 -> Bootstrap 2 - [doc] rustc 1 -> BuildHelper 2 - [doc] rustc 1 -> Compiletest 2 - [doc] rustc 1 -> RunMakeSupport 2 - [doc] rustc 1 -> CompilerWithTools 2 - [build] rustc 0 -> RustInstaller 1 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustdoc 1 + [doc] rustc 1 -> rustc 2 + [build] rustc 1 -> rustc 2 + [doc] rustc 1 -> Rustdoc 2 + [doc] rustc 1 -> Rustfmt 2 + [doc] rustc 1 -> Clippy 2 + [doc] rustc 1 -> Miri 2 + [doc] rustc 1 -> Cargo 2 + [doc] rustc 1 -> Tidy 2 + [doc] rustc 1 -> Bootstrap 2 + [doc] rustc 1 -> BuildHelper 2 + [doc] rustc 1 -> Compiletest 2 + [doc] rustc 1 -> RunMakeSupport 2 + [doc] rustc 1 -> CompilerWithTools 2 + [build] rustc 0 -> RustInstaller 1 "#]] + .assert_eq(&ctx.config("dist").path("rustc-docs").render_steps()); } #[test] fn check_compiler_no_explicit_stage() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("check") - .path("compiler") - .render_steps(), @"[check] rustc 0 -> rustc 1 (78 crates)"); + expect_test::expect![["[check] rustc 0 -> rustc 1 (78 crates)"]] + .assert_eq(&ctx.config("check").path("compiler").render_steps()); } #[test] fn check_rustc_no_explicit_stage() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("check") - .path("rustc") - .render_steps(), @"[check] rustc 0 -> rustc 1 (1 crates)"); + expect_test::expect![["[check] rustc 0 -> rustc 1 (1 crates)"]] + .assert_eq(&ctx.config("check").path("rustc").render_steps()); } #[test] @@ -1622,66 +1513,54 @@ mod snapshot { #[test] fn check_compiler_stage_1() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("check") - .path("compiler") - .stage(1) - .render_steps(), @"[check] rustc 0 -> rustc 1 (78 crates)"); + expect_test::expect![["[check] rustc 0 -> rustc 1 (78 crates)"]] + .assert_eq(&ctx.config("check").path("compiler").stage(1).render_steps()); } #[test] fn check_compiler_stage_2() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("check") - .path("compiler") - .stage(2) - .render_steps(), @" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [check] rustc 1 -> rustc 2 (78 crates) - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [check] rustc 1 -> rustc 2 (78 crates)"#]] + .assert_eq(&ctx.config("check").path("compiler").stage(2).render_steps()); } #[test] fn check_cross_compile() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("check") - .targets(&[TEST_TRIPLE_1]) - .hosts(&[TEST_TRIPLE_1]) - .render_steps(), @" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [check] rustc 1 -> std 1 - [check] rustc 1 -> rustc 2 (78 crates) - [check] rustc 1 -> rustc 2 - [check] rustc 1 -> Rustdoc 2 - [check] rustc 1 -> rustc_codegen_cranelift 2 - [check] rustc 1 -> rustc_codegen_gcc 2 - [check] rustc 1 -> Clippy 2 - [check] rustc 1 -> Miri 2 - [check] rustc 1 -> CargoMiri 2 - [check] rustc 1 -> Rustfmt 2 - [check] rustc 1 -> RustAnalyzer 2 - [check] rustc 1 -> TestFloatParse 2 - [check] rustc 1 -> std 1 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [check] rustc 1 -> std 1 + [check] rustc 1 -> rustc 2 (78 crates) + [check] rustc 1 -> rustc 2 + [check] rustc 1 -> Rustdoc 2 + [check] rustc 1 -> rustc_codegen_cranelift 2 + [check] rustc 1 -> rustc_codegen_gcc 2 + [check] rustc 1 -> Clippy 2 + [check] rustc 1 -> Miri 2 + [check] rustc 1 -> CargoMiri 2 + [check] rustc 1 -> Rustfmt 2 + [check] rustc 1 -> RustAnalyzer 2 + [check] rustc 1 -> TestFloatParse 2 + [check] rustc 1 -> std 1 "#]] + .assert_eq( + &ctx.config("check").targets(&[TEST_TRIPLE_1]).hosts(&[TEST_TRIPLE_1]).render_steps(), + ); } #[test] fn check_library_no_explicit_stage() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("check") - .path("library") - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [check] rustc 1 -> std 1 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [check] rustc 1 -> std 1 "#]] + .assert_eq(&ctx.config("check").path("library").render_steps()); } #[test] @@ -1694,46 +1573,39 @@ mod snapshot { #[test] fn check_library_stage_1() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("check") - .path("library") - .stage(1) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [check] rustc 1 -> std 1 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [check] rustc 1 -> std 1 "#]] + .assert_eq(&ctx.config("check").path("library").stage(1).render_steps()); } #[test] fn check_library_stage_2() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("check") - .path("library") - .stage(2) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 1 -> rustc 2 - [check] rustc 2 -> std 2 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> rustc 2 + [check] rustc 2 -> std 2 "#]] + .assert_eq(&ctx.config("check").path("library").stage(2).render_steps()); } #[test] fn check_library_cross_compile() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("check") + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [check] rustc 1 -> std 1 + [check] rustc 1 -> std 1 "#]] + .assert_eq( + &ctx.config("check") .paths(&["core", "alloc", "std"]) .targets(&[TEST_TRIPLE_1, TEST_TRIPLE_2]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [check] rustc 1 -> std 1 - [check] rustc 1 -> std 1 - "); + .render_steps(), + ); } /// Make sure that we don't check library when download-rustc is disabled @@ -1742,29 +1614,21 @@ mod snapshot { fn check_library_skip_without_download_rustc() { let ctx = TestCtx::new(); let args = ["--set", "rust.download-rustc=false", "--skip-std-check-if-no-download-rustc"]; - insta::assert_snapshot!( - ctx.config("check") - .paths(&["library"]) - .args(&args) - .render_steps(), @""); + expect_test::expect![[""]] + .assert_eq(&ctx.config("check").paths(&["library"]).args(&args).render_steps()); - insta::assert_snapshot!( - ctx.config("check") - .paths(&["library", "compiler"]) - .args(&args) - .render_steps(), @"[check] rustc 0 -> rustc 1 (78 crates)"); + expect_test::expect![["[check] rustc 0 -> rustc 1 (78 crates)"]].assert_eq( + &ctx.config("check").paths(&["library", "compiler"]).args(&args).render_steps(), + ); } #[test] fn check_miri_no_explicit_stage() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("check") - .path("miri") - .render_steps(), @r" - [check] rustc 0 -> rustc 1 - [check] rustc 0 -> Miri 1 - "); + expect_test::expect![[r#" + [check] rustc 0 -> rustc 1 + [check] rustc 0 -> Miri 1 "#]] + .assert_eq(&ctx.config("check").path("miri").render_steps()); } #[test] @@ -1777,72 +1641,54 @@ mod snapshot { #[test] fn check_miri_stage_1() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("check") - .path("miri") - .stage(1) - .render_steps(), @r" - [check] rustc 0 -> rustc 1 - [check] rustc 0 -> Miri 1 - "); + expect_test::expect![[r#" + [check] rustc 0 -> rustc 1 + [check] rustc 0 -> Miri 1 "#]] + .assert_eq(&ctx.config("check").path("miri").stage(1).render_steps()); } #[test] fn check_miri_stage_2() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("check") - .path("miri") - .stage(2) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [check] rustc 1 -> rustc 2 - [check] rustc 1 -> Miri 2 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [check] rustc 1 -> rustc 2 + [check] rustc 1 -> Miri 2 "#]] + .assert_eq(&ctx.config("check").path("miri").stage(2).render_steps()); } #[test] fn check_compiletest() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("check") - .path("compiletest") - .render_steps(), @"[check] rustc 0 -> Compiletest 1 "); + expect_test::expect![["[check] rustc 0 -> Compiletest 1 "]] + .assert_eq(&ctx.config("check").path("compiletest").render_steps()); } #[test] fn check_codegen() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("check") - .path("rustc_codegen_cranelift") - .render_steps(), @r" - [check] rustc 0 -> rustc 1 - [check] rustc 0 -> rustc_codegen_cranelift 1 - "); + expect_test::expect![[r#" + [check] rustc 0 -> rustc 1 + [check] rustc 0 -> rustc_codegen_cranelift 1 "#]] + .assert_eq(&ctx.config("check").path("rustc_codegen_cranelift").render_steps()); } #[test] fn check_rust_analyzer() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("check") - .path("rust-analyzer") - .render_steps(), @r" - [check] rustc 0 -> rustc 1 - [check] rustc 0 -> RustAnalyzer 1 - "); + expect_test::expect![[r#" + [check] rustc 0 -> rustc 1 + [check] rustc 0 -> RustAnalyzer 1 "#]] + .assert_eq(&ctx.config("check").path("rust-analyzer").render_steps()); } #[test] fn check_bootstrap_tool() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("check") - .path("run-make-support") - .render_steps(), @"[check] rustc 0 -> RunMakeSupport 1 "); + expect_test::expect![["[check] rustc 0 -> RunMakeSupport 1 "]] + .assert_eq(&ctx.config("check").path("run-make-support").render_steps()); } fn prepare_test_config(ctx: &TestCtx) -> ConfigBuilder { @@ -1860,305 +1706,310 @@ mod snapshot { #[test] fn test_all_stage_1() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - prepare_test_config(&ctx) - .render_steps(), @" - [build] rustc 0 -> Tidy 1 - [test] tidy <> - [build] rustdoc 0 - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 0 -> Compiletest 1 - [test] compiletest-ui 1 - [test] compiletest-crashes 1 - [build] rustc 0 -> CoverageDump 1 - [test] compiletest-coverage 1 - [test] compiletest-coverage 1 - [build] rustc 1 -> std 1 - [test] compiletest-mir-opt 1 - [test] compiletest-codegen-llvm 1 - [test] compiletest-codegen-units 1 - [test] compiletest-assembly-gcc 1 - [test] compiletest-assembly-llvm 1 - [test] compiletest-incremental 1 - [test] compiletest-debuginfo 1 - [test] compiletest-ui-fulldeps 1 - [build] rustdoc 1 - [test] compiletest-rustdoc-html 1 - [test] compiletest-coverage-run-rustdoc 1 - [test] compiletest-pretty 1 - [build] rustc 1 -> std 1 - [build] rustc 0 -> std 0 - [test] rustc 0 -> CrateLibrustc 1 - [build] rustc 1 -> rustc 2 - [test] crate-bootstrap src/tools/coverage-dump - [test] crate-bootstrap src/tools/jsondoclint - [test] crate-bootstrap src/tools/replace-version-placeholder - [test] crate-bootstrap tidyselftest - [build] rustc 0 -> UnstableBookGen 1 - [build] rustc 0 -> Rustbook 1 - [doc] unstable-book (book) - [doc] book (book) - [doc] book/first-edition (book) - [doc] book/second-edition (book) - [doc] book/2018-edition (book) - [doc] rustc 0 -> standalone 1 - [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] - [build] rustc 0 -> error-index 1 - [doc] rustc 0 -> error-index 1 - [doc] nomicon (book) - [doc] rustc 1 -> reference (book) 2 - [doc] rustdoc (book) - [doc] rust-by-example (book) - [build] rustc 0 -> LintDocs 1 - [doc] rustc (book) - [doc] cargo (book) - [doc] clippy (book) - [doc] embedded-book (book) - [doc] edition-guide (book) - [doc] style-guide (book) - [doc] rustc 0 -> releases 1 - [build] rustc 0 -> Linkchecker 1 - [test] link-check - [test] tier-check - [test] rustc 0 -> rust-analyzer 1 - [build] rustc 0 -> RustdocTheme 1 - [test] rustdoc-theme 1 - [test] compiletest-rustdoc-ui 1 - [build] rustc 0 -> JsonDocCk 1 - [build] rustc 0 -> JsonDocLint 1 - [test] compiletest-rustdoc-json 1 - [doc] rustc 0 -> rustc 1 - [build] rustc 0 -> HtmlChecker 1 - [test] html-check - [test] test-float-parse - [build] rustc 0 -> RunMakeSupport 1 - [test] compiletest-run-make 1 - [build] rustc 0 -> cargo 1 - [test] compiletest-run-make-cargo 1 - [test] intrinsic-test - "); + expect_test::expect![[r#" + [build] rustc 0 -> Tidy 1 + [test] tidy <> + [build] rustdoc 0 + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 0 -> Compiletest 1 + [test] compiletest-ui 1 + [test] compiletest-crashes 1 + [build] rustc 0 -> CoverageDump 1 + [test] compiletest-coverage 1 + [test] compiletest-coverage 1 + [build] rustc 1 -> std 1 + [test] compiletest-mir-opt 1 + [test] compiletest-codegen-llvm 1 + [test] compiletest-codegen-units 1 + [test] compiletest-assembly-gcc 1 + [test] compiletest-assembly-llvm 1 + [test] compiletest-incremental 1 + [test] compiletest-debuginfo 1 + [test] compiletest-ui-fulldeps 1 + [build] rustdoc 1 + [test] compiletest-rustdoc-html 1 + [test] compiletest-coverage-run-rustdoc 1 + [test] compiletest-pretty 1 + [build] rustc 1 -> std 1 + [build] rustc 0 -> std 0 + [test] rustc 0 -> CrateLibrustc 1 + [build] rustc 1 -> rustc 2 + [test] crate-bootstrap src/tools/coverage-dump + [test] crate-bootstrap src/tools/jsondoclint + [test] crate-bootstrap src/tools/replace-version-placeholder + [test] crate-bootstrap tidyselftest + [build] rustc 0 -> UnstableBookGen 1 + [build] rustc 0 -> Rustbook 1 + [doc] unstable-book (book) + [doc] book (book) + [doc] book/first-edition (book) + [doc] book/second-edition (book) + [doc] book/2018-edition (book) + [doc] rustc 0 -> standalone 1 + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] + [build] rustc 0 -> error-index 1 + [doc] rustc 0 -> error-index 1 + [doc] nomicon (book) + [doc] rustc 1 -> reference (book) 2 + [doc] rustdoc (book) + [doc] rust-by-example (book) + [build] rustc 0 -> LintDocs 1 + [doc] rustc (book) + [doc] cargo (book) + [doc] clippy (book) + [doc] embedded-book (book) + [doc] edition-guide (book) + [doc] style-guide (book) + [doc] rustc 0 -> releases 1 + [build] rustc 0 -> Linkchecker 1 + [test] link-check + [test] tier-check + [test] rustc 0 -> rust-analyzer 1 + [build] rustc 0 -> RustdocTheme 1 + [test] rustdoc-theme 1 + [test] compiletest-rustdoc-ui 1 + [build] rustc 0 -> JsonDocCk 1 + [build] rustc 0 -> JsonDocLint 1 + [test] compiletest-rustdoc-json 1 + [doc] rustc 0 -> rustc 1 + [build] rustc 0 -> HtmlChecker 1 + [test] html-check + [test] test-float-parse + [build] rustc 0 -> RunMakeSupport 1 + [test] compiletest-run-make 1 + [build] rustc 0 -> cargo 1 + [test] compiletest-run-make-cargo 1 + [test] intrinsic-test "#]].assert_eq(&prepare_test_config(&ctx) + .render_steps()); } #[test] fn test_compiletest_self_test() { let ctx = TestCtx::new(); let steps = ctx.config("test").arg("compiletest").render_steps(); - insta::assert_snapshot!(steps, @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustdoc 0 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustdoc 0 "#]] + .assert_eq(&steps); } #[test] fn test_compiletest_suites_stage1() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("test") - .args(&["ui", "ui-fulldeps", "run-make", "rustdoc-html", "rustdoc-gui", "incremental"]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 0 -> Compiletest 1 - [test] compiletest-ui 1 - [test] compiletest-ui-fulldeps 1 - [build] rustc 0 -> RunMakeSupport 1 - [build] rustdoc 1 - [test] compiletest-run-make 1 - [test] compiletest-rustdoc-html 1 - [build] rustc 0 -> RustdocGUITest 1 - [test] rustdoc-gui 1 - [test] compiletest-incremental 1 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 0 -> Compiletest 1 + [test] compiletest-ui 1 + [test] compiletest-ui-fulldeps 1 + [build] rustc 0 -> RunMakeSupport 1 + [build] rustdoc 1 + [test] compiletest-run-make 1 + [test] compiletest-rustdoc-html 1 + [build] rustc 0 -> RustdocGUITest 1 + [test] rustdoc-gui 1 + [test] compiletest-incremental 1 "#]] + .assert_eq( + &ctx.config("test") + .args(&[ + "ui", + "ui-fulldeps", + "run-make", + "rustdoc-html", + "rustdoc-gui", + "incremental", + ]) + .render_steps(), + ); } #[test] fn test_compiletest_suites_stage2() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("test") - .args(&["ui", "ui-fulldeps", "run-make", "rustdoc-html", "rustdoc-gui", "incremental"]) + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> rustc 2 + [build] rustc 2 -> std 2 + [build] rustc 0 -> Compiletest 1 + [test] compiletest-ui 2 + [build] rustc 2 -> rustc 3 + [test] compiletest-ui-fulldeps 2 + [build] rustc 0 -> RunMakeSupport 1 + [build] rustdoc 2 + [test] compiletest-run-make 2 + [test] compiletest-rustdoc-html 2 + [build] rustc 0 -> RustdocGUITest 1 + [test] rustdoc-gui 2 + [test] compiletest-incremental 2 "#]] + .assert_eq( + &ctx.config("test") + .args(&[ + "ui", + "ui-fulldeps", + "run-make", + "rustdoc-html", + "rustdoc-gui", + "incremental", + ]) .stage(2) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 1 -> rustc 2 - [build] rustc 2 -> std 2 - [build] rustc 0 -> Compiletest 1 - [test] compiletest-ui 2 - [build] rustc 2 -> rustc 3 - [test] compiletest-ui-fulldeps 2 - [build] rustc 0 -> RunMakeSupport 1 - [build] rustdoc 2 - [test] compiletest-run-make 2 - [test] compiletest-rustdoc-html 2 - [build] rustc 0 -> RustdocGUITest 1 - [test] rustdoc-gui 2 - [test] compiletest-incremental 2 - "); + .render_steps(), + ); } #[test] fn test_compiletest_suites_stage2_cross() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("test") + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> rustc 2 + [build] rustc 2 -> std 2 + [build] rustc 0 -> Compiletest 1 + [build] rustc 1 -> std 1 + [build] rustc 2 -> std 2 + [test] compiletest-ui 2 + [build] llvm + [build] rustc 2 -> rustc 3 + [test] compiletest-ui-fulldeps 2 + [build] rustc 0 -> RunMakeSupport 1 + [build] rustdoc 2 + [test] compiletest-run-make 2 + [build] rustc 1 -> rustc 2 + [build] rustdoc 1 + [build] rustc 2 -> std 2 + [build] rustdoc 2 + [build] rustc 0 -> RustdocGUITest 1 + [test] rustdoc-gui 2 + [test] compiletest-incremental 2 "#]] + .assert_eq( + &ctx.config("test") .hosts(&[TEST_TRIPLE_1]) .targets(&[TEST_TRIPLE_1]) .args(&["ui", "ui-fulldeps", "run-make", "rustdoc", "rustdoc-gui", "incremental"]) .stage(2) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 1 -> rustc 2 - [build] rustc 2 -> std 2 - [build] rustc 0 -> Compiletest 1 - [build] rustc 1 -> std 1 - [build] rustc 2 -> std 2 - [test] compiletest-ui 2 - [build] llvm - [build] rustc 2 -> rustc 3 - [test] compiletest-ui-fulldeps 2 - [build] rustc 0 -> RunMakeSupport 1 - [build] rustdoc 2 - [test] compiletest-run-make 2 - [build] rustc 1 -> rustc 2 - [build] rustdoc 1 - [build] rustc 2 -> std 2 - [build] rustdoc 2 - [build] rustc 0 -> RustdocGUITest 1 - [test] rustdoc-gui 2 - [test] compiletest-incremental 2 - "); + .render_steps(), + ); } #[test] fn test_all_stage_2() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - prepare_test_config(&ctx) - .stage(2) - .render_steps(), @" - [build] rustc 0 -> Tidy 1 - [test] tidy <> - [build] rustdoc 0 - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 1 -> rustc 2 - [build] rustc 2 -> std 2 - [build] rustc 0 -> Compiletest 1 - [test] compiletest-ui 2 - [test] compiletest-crashes 2 - [build] rustc 0 -> CoverageDump 1 - [test] compiletest-coverage 2 - [test] compiletest-coverage 2 - [build] rustc 2 -> std 2 - [test] compiletest-mir-opt 2 - [test] compiletest-codegen-llvm 2 - [test] compiletest-codegen-units 2 - [test] compiletest-assembly-gcc 2 - [test] compiletest-assembly-llvm 2 - [test] compiletest-incremental 2 - [test] compiletest-debuginfo 2 - [build] rustc 2 -> rustc 3 - [test] compiletest-ui-fulldeps 2 - [build] rustdoc 2 - [test] compiletest-rustdoc-html 2 - [test] compiletest-coverage-run-rustdoc 2 - [test] compiletest-pretty 2 - [build] rustc 2 -> std 2 - [build] rustc 1 -> std 1 - [build] rustdoc 1 - [test] rustc 1 -> CrateLibrustc 2 - [test] crate-bootstrap src/tools/coverage-dump - [test] crate-bootstrap src/tools/jsondoclint - [test] crate-bootstrap src/tools/replace-version-placeholder - [test] crate-bootstrap tidyselftest - [build] rustc 0 -> UnstableBookGen 1 - [build] rustc 0 -> Rustbook 1 - [doc] unstable-book (book) - [doc] book (book) - [doc] book/first-edition (book) - [doc] book/second-edition (book) - [doc] book/2018-edition (book) - [doc] rustc 1 -> standalone 2 - [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] - [build] rustc 1 -> error-index 2 - [doc] rustc 1 -> error-index 2 - [doc] nomicon (book) - [doc] rustc 1 -> reference (book) 2 - [doc] rustdoc (book) - [doc] rust-by-example (book) - [build] rustc 0 -> LintDocs 1 - [doc] rustc (book) - [doc] cargo (book) - [doc] clippy (book) - [doc] embedded-book (book) - [doc] edition-guide (book) - [doc] style-guide (book) - [doc] rustc 1 -> releases 2 - [build] rustc 0 -> Linkchecker 1 - [test] link-check - [test] tier-check - [test] rustc 1 -> rust-analyzer 2 - [doc] rustc (book) - [test] rustc 1 -> lint-docs 2 - [build] rustc 0 -> RustdocTheme 1 - [test] rustdoc-theme 2 - [test] compiletest-rustdoc-ui 2 - [build] rustc 0 -> JsonDocCk 1 - [build] rustc 0 -> JsonDocLint 1 - [test] compiletest-rustdoc-json 2 - [doc] rustc 1 -> rustc 2 - [build] rustc 0 -> HtmlChecker 1 - [test] html-check - [test] test-float-parse - [build] rustc 0 -> RunMakeSupport 1 - [test] compiletest-run-make 2 - [build] rustc 1 -> cargo 2 - [test] compiletest-run-make-cargo 2 - [test] intrinsic-test - "); + expect_test::expect![[r#" + [build] rustc 0 -> Tidy 1 + [test] tidy <> + [build] rustdoc 0 + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> rustc 2 + [build] rustc 2 -> std 2 + [build] rustc 0 -> Compiletest 1 + [test] compiletest-ui 2 + [test] compiletest-crashes 2 + [build] rustc 0 -> CoverageDump 1 + [test] compiletest-coverage 2 + [test] compiletest-coverage 2 + [build] rustc 2 -> std 2 + [test] compiletest-mir-opt 2 + [test] compiletest-codegen-llvm 2 + [test] compiletest-codegen-units 2 + [test] compiletest-assembly-gcc 2 + [test] compiletest-assembly-llvm 2 + [test] compiletest-incremental 2 + [test] compiletest-debuginfo 2 + [build] rustc 2 -> rustc 3 + [test] compiletest-ui-fulldeps 2 + [build] rustdoc 2 + [test] compiletest-rustdoc-html 2 + [test] compiletest-coverage-run-rustdoc 2 + [test] compiletest-pretty 2 + [build] rustc 2 -> std 2 + [build] rustc 1 -> std 1 + [build] rustdoc 1 + [test] rustc 1 -> CrateLibrustc 2 + [test] crate-bootstrap src/tools/coverage-dump + [test] crate-bootstrap src/tools/jsondoclint + [test] crate-bootstrap src/tools/replace-version-placeholder + [test] crate-bootstrap tidyselftest + [build] rustc 0 -> UnstableBookGen 1 + [build] rustc 0 -> Rustbook 1 + [doc] unstable-book (book) + [doc] book (book) + [doc] book/first-edition (book) + [doc] book/second-edition (book) + [doc] book/2018-edition (book) + [doc] rustc 1 -> standalone 2 + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] + [build] rustc 1 -> error-index 2 + [doc] rustc 1 -> error-index 2 + [doc] nomicon (book) + [doc] rustc 1 -> reference (book) 2 + [doc] rustdoc (book) + [doc] rust-by-example (book) + [build] rustc 0 -> LintDocs 1 + [doc] rustc (book) + [doc] cargo (book) + [doc] clippy (book) + [doc] embedded-book (book) + [doc] edition-guide (book) + [doc] style-guide (book) + [doc] rustc 1 -> releases 2 + [build] rustc 0 -> Linkchecker 1 + [test] link-check + [test] tier-check + [test] rustc 1 -> rust-analyzer 2 + [doc] rustc (book) + [test] rustc 1 -> lint-docs 2 + [build] rustc 0 -> RustdocTheme 1 + [test] rustdoc-theme 2 + [test] compiletest-rustdoc-ui 2 + [build] rustc 0 -> JsonDocCk 1 + [build] rustc 0 -> JsonDocLint 1 + [test] compiletest-rustdoc-json 2 + [doc] rustc 1 -> rustc 2 + [build] rustc 0 -> HtmlChecker 1 + [test] html-check + [test] test-float-parse + [build] rustc 0 -> RunMakeSupport 1 + [test] compiletest-run-make 2 + [build] rustc 1 -> cargo 2 + [test] compiletest-run-make-cargo 2 + [test] intrinsic-test "#]].assert_eq(&prepare_test_config(&ctx) + .stage(2) + .render_steps()); } #[test] fn test_compiler_stage_1() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("test") - .path("compiler") - .stage(1) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 0 -> std 0 - [build] rustdoc 0 - [test] rustc 0 -> CrateLibrustc 1 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 0 -> std 0 + [build] rustdoc 0 + [test] rustc 0 -> CrateLibrustc 1 "#]] + .assert_eq(&ctx.config("test").path("compiler").stage(1).render_steps()); } #[test] fn test_compiler_stage_2() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("test") - .path("compiler") - .stage(2) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 1 -> rustc 2 - [build] rustc 1 -> std 1 - [build] rustdoc 1 - [test] rustc 1 -> CrateLibrustc 2 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> rustc 2 + [build] rustc 1 -> std 1 + [build] rustdoc 1 + [test] rustc 1 -> CrateLibrustc 2 "#]] + .assert_eq(&ctx.config("test").path("compiler").stage(2).render_steps()); } #[test] @@ -2216,80 +2067,65 @@ mod snapshot { #[test] fn test_library_tests_only_does_not_build_rustdoc() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("test").args(&["--tests", "library/core"]).render_steps(), - @r" + expect_test::expect![[r#" [build] llvm [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - "); + [build] rustc 1 -> std 1 "#]] + .assert_eq(&ctx.config("test").args(&["--tests", "library/core"]).render_steps()); } #[test] fn test_cargo_stage_1() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("test") - .path("cargo") - .render_steps(), @r" - [build] rustc 0 -> cargo 1 - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustdoc 1 - [build] rustdoc 0 - [test] rustc 0 -> cargo 1 - "); + expect_test::expect![[r#" + [build] rustc 0 -> cargo 1 + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustdoc 1 + [build] rustdoc 0 + [test] rustc 0 -> cargo 1 "#]] + .assert_eq(&ctx.config("test").path("cargo").render_steps()); } #[test] fn test_cargo_stage_2() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("test") - .path("cargo") - .stage(2) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 1 -> cargo 2 - [build] rustc 1 -> rustc 2 - [build] rustc 2 -> std 2 - [build] rustdoc 2 - [build] rustdoc 1 - [test] rustc 1 -> cargo 2 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> cargo 2 + [build] rustc 1 -> rustc 2 + [build] rustc 2 -> std 2 + [build] rustdoc 2 + [build] rustdoc 1 + [test] rustc 1 -> cargo 2 "#]] + .assert_eq(&ctx.config("test").path("cargo").stage(2).render_steps()); } #[test] fn test_cargotest() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("test") - .path("cargotest") - .render_steps(), @r" - [build] rustc 0 -> cargo 1 - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 0 -> CargoTest 1 - [build] rustdoc 1 - [test] cargotest 1 - "); + expect_test::expect![[r#" + [build] rustc 0 -> cargo 1 + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 0 -> CargoTest 1 + [build] rustdoc 1 + [test] cargotest 1 "#]] + .assert_eq(&ctx.config("test").path("cargotest").render_steps()); } #[test] fn test_tier_check() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("test") - .path("tier-check") - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [test] tier-check - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [test] tier-check "#]] + .assert_eq(&ctx.config("test").path("tier-check").render_steps()); } // Differential snapshots for `./x test run-make` run `./x test run-make-cargo`: only @@ -2297,199 +2133,176 @@ mod snapshot { #[test] fn test_run_make_no_cargo() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("test") - .path("run-make") - .render_steps(), @" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 0 -> Compiletest 1 - [build] rustc 0 -> RunMakeSupport 1 - [build] rustdoc 1 - [test] compiletest-run-make 1 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 0 -> Compiletest 1 + [build] rustc 0 -> RunMakeSupport 1 + [build] rustdoc 1 + [test] compiletest-run-make 1 "#]] + .assert_eq(&ctx.config("test").path("run-make").render_steps()); } #[test] fn test_run_make_cargo_builds_cargo() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("test") - .path("run-make-cargo") - .render_steps(), @" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 0 -> Compiletest 1 - [build] rustc 0 -> RunMakeSupport 1 - [build] rustc 0 -> cargo 1 - [build] rustdoc 1 - [test] compiletest-run-make-cargo 1 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 0 -> Compiletest 1 + [build] rustc 0 -> RunMakeSupport 1 + [build] rustc 0 -> cargo 1 + [build] rustdoc 1 + [test] compiletest-run-make-cargo 1 "#]] + .assert_eq(&ctx.config("test").path("run-make-cargo").render_steps()); } #[test] fn doc_all() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("doc") - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 0 -> UnstableBookGen 1 - [build] rustc 0 -> Rustbook 1 - [doc] unstable-book (book) - [doc] book (book) - [doc] book/first-edition (book) - [doc] book/second-edition (book) - [doc] book/2018-edition (book) - [build] rustdoc 0 - [doc] rustc 0 -> standalone 1 - [build] rustdoc 1 - [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] - [build] rustc 0 -> error-index 1 - [doc] rustc 0 -> error-index 1 - [doc] nomicon (book) - [doc] rustc 1 -> reference (book) 2 - [doc] rustdoc (book) - [doc] rust-by-example (book) - [build] rustc 0 -> LintDocs 1 - [doc] rustc (book) - [doc] cargo (book) - [doc] clippy (book) - [doc] embedded-book (book) - [doc] edition-guide (book) - [doc] style-guide (book) - [doc] rustc 0 -> releases 1 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 0 -> UnstableBookGen 1 + [build] rustc 0 -> Rustbook 1 + [doc] unstable-book (book) + [doc] book (book) + [doc] book/first-edition (book) + [doc] book/second-edition (book) + [doc] book/2018-edition (book) + [build] rustdoc 0 + [doc] rustc 0 -> standalone 1 + [build] rustdoc 1 + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] + [build] rustc 0 -> error-index 1 + [doc] rustc 0 -> error-index 1 + [doc] nomicon (book) + [doc] rustc 1 -> reference (book) 2 + [doc] rustdoc (book) + [doc] rust-by-example (book) + [build] rustc 0 -> LintDocs 1 + [doc] rustc (book) + [doc] cargo (book) + [doc] clippy (book) + [doc] embedded-book (book) + [doc] edition-guide (book) + [doc] style-guide (book) + [doc] rustc 0 -> releases 1 "#]].assert_eq(&ctx.config("doc") + .render_steps()); } #[test] fn doc_library() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("doc") - .path("library") - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustdoc 1 - [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustdoc 1 + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind]"#]].assert_eq(&ctx.config("doc") + .path("library") + .render_steps()); } #[test] fn doc_compiler_with_tools() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("doc") - .arg("compiler-with-tools") - .render_steps(), @" - [build] rustdoc 0 - [doc] rustc 0 -> rustc 1 - [build] llvm - [build] rustc 0 -> rustc 1 - [doc] rustc 0 -> Rustdoc 1 - [doc] rustc 0 -> Rustfmt 1 - [doc] rustc 0 -> Clippy 1 - [doc] rustc 0 -> Miri 1 - [doc] rustc 0 -> Cargo 1 - [doc] rustc 0 -> Tidy 1 - [doc] rustc 0 -> Bootstrap 1 - [doc] rustc 0 -> BuildHelper 1 - [doc] rustc 0 -> Compiletest 1 - [doc] rustc 0 -> RunMakeSupport 1 - [doc] rustc 0 -> CompilerWithTools 1 - "); + expect_test::expect![[r#" + [build] rustdoc 0 + [doc] rustc 0 -> rustc 1 + [build] llvm + [build] rustc 0 -> rustc 1 + [doc] rustc 0 -> Rustdoc 1 + [doc] rustc 0 -> Rustfmt 1 + [doc] rustc 0 -> Clippy 1 + [doc] rustc 0 -> Miri 1 + [doc] rustc 0 -> Cargo 1 + [doc] rustc 0 -> Tidy 1 + [doc] rustc 0 -> Bootstrap 1 + [doc] rustc 0 -> BuildHelper 1 + [doc] rustc 0 -> Compiletest 1 + [doc] rustc 0 -> RunMakeSupport 1 + [doc] rustc 0 -> CompilerWithTools 1 "#]] + .assert_eq(&ctx.config("doc").arg("compiler-with-tools").render_steps()); } #[test] fn doc_cargo_stage_1() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("doc") - .path("cargo") - .render_steps(), @r" - [build] rustdoc 0 - [doc] rustc 0 -> Cargo 1 - "); + expect_test::expect![[r#" + [build] rustdoc 0 + [doc] rustc 0 -> Cargo 1 "#]] + .assert_eq(&ctx.config("doc").path("cargo").render_steps()); } #[test] fn doc_cargo_stage_2() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("doc") - .path("cargo") - .stage(2) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustdoc 1 - [doc] rustc 1 -> Cargo 2 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustdoc 1 + [doc] rustc 1 -> Cargo 2 "#]] + .assert_eq(&ctx.config("doc").path("cargo").stage(2).render_steps()); } #[test] fn doc_core() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("doc") - .path("core") - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustdoc 1 - [doc] rustc 1 -> std 1 crates=[core] - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustdoc 1 + [doc] rustc 1 -> std 1 crates=[core]"#]] + .assert_eq(&ctx.config("doc").path("core").render_steps()); } #[test] fn doc_core_no_std_target() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("doc") - .path("core") - .override_target_no_std(&host_target()) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustdoc 1 - [doc] rustc 1 -> std 1 crates=[core] - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustdoc 1 + [doc] rustc 1 -> std 1 crates=[core]"#]] + .assert_eq( + &ctx.config("doc").path("core").override_target_no_std(&host_target()).render_steps(), + ); } #[test] fn doc_library_no_std_target() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("doc") + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustdoc 1 + [doc] rustc 1 -> std 1 crates=[alloc,core]"#]] + .assert_eq( + &ctx.config("doc") .path("library") .override_target_no_std(&host_target()) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustdoc 1 - [doc] rustc 1 -> std 1 crates=[alloc,core] - "); + .render_steps(), + ); } #[test] fn doc_library_no_std_target_cross_compile() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("doc") + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustdoc 1 + [doc] rustc 1 -> std 1 crates=[alloc,core]"#]] + .assert_eq( + &ctx.config("doc") .path("library") .targets(&[TEST_TRIPLE_1]) .override_target_no_std(TEST_TRIPLE_1) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustdoc 1 - [doc] rustc 1 -> std 1 crates=[alloc,core] - "); + .render_steps(), + ); } #[test] @@ -2502,30 +2315,22 @@ mod snapshot { #[test] fn doc_compiler_stage_1() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("doc") - .path("compiler") - .stage(1) - .render_steps(), @" - [build] rustdoc 0 - [doc] rustc 0 -> rustc 1 - "); + expect_test::expect![[r#" + [build] rustdoc 0 + [doc] rustc 0 -> rustc 1 "#]] + .assert_eq(&ctx.config("doc").path("compiler").stage(1).render_steps()); } #[test] fn doc_compiler_stage_2() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("doc") - .path("compiler") - .stage(2) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustdoc 1 - [doc] rustc 1 -> rustc 2 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustdoc 1 + [doc] rustc 1 -> rustc 2 "#]] + .assert_eq(&ctx.config("doc").path("compiler").stage(2).render_steps()); } #[test] @@ -2538,454 +2343,415 @@ mod snapshot { #[test] fn doc_compiletest_stage_1() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("doc") - .path("src/tools/compiletest") - .stage(1) - .render_steps(), @r" - [build] rustdoc 0 - [doc] rustc 0 -> Compiletest 1 - "); + expect_test::expect![[r#" + [build] rustdoc 0 + [doc] rustc 0 -> Compiletest 1 "#]] + .assert_eq(&ctx.config("doc").path("src/tools/compiletest").stage(1).render_steps()); } #[test] fn doc_compiletest_stage_2() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("doc") - .path("src/tools/compiletest") - .stage(2) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustdoc 1 - [doc] rustc 1 -> Compiletest 2 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustdoc 1 + [doc] rustc 1 -> Compiletest 2 "#]] + .assert_eq(&ctx.config("doc").path("src/tools/compiletest").stage(2).render_steps()); } // Reference should be auto-bumped to stage 2. #[test] fn doc_reference() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("doc") - .path("reference") - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 0 -> Rustbook 1 - [doc] rustc 1 -> reference (book) 2 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 0 -> Rustbook 1 + [doc] rustc 1 -> reference (book) 2 "#]] + .assert_eq(&ctx.config("doc").path("reference").render_steps()); } #[test] fn clippy_ci() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("clippy") - .path("ci") - .stage(2) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 0 -> clippy-driver 1 - [build] rustc 0 -> cargo-clippy 1 - [clippy] rustc 1 -> bootstrap 2 - [clippy] rustc 1 -> std 1 - [clippy] rustc 1 -> rustc 2 - [check] rustc 1 -> rustc 2 - [clippy] rustc 1 -> rustc_codegen_gcc 2 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 0 -> clippy-driver 1 + [build] rustc 0 -> cargo-clippy 1 + [clippy] rustc 1 -> bootstrap 2 + [clippy] rustc 1 -> std 1 + [clippy] rustc 1 -> rustc 2 + [check] rustc 1 -> rustc 2 + [clippy] rustc 1 -> rustc_codegen_gcc 2 "#]] + .assert_eq(&ctx.config("clippy").path("ci").stage(2).render_steps()); } #[test] fn clippy_compiler_stage1() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("clippy") - .path("compiler") - .render_steps(), @"[clippy] rustc 0 -> rustc 1 "); + expect_test::expect![["[clippy] rustc 0 -> rustc 1 "]] + .assert_eq(&ctx.config("clippy").path("compiler").render_steps()); } #[test] fn clippy_compiler_stage2() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("clippy") - .path("compiler") - .stage(2) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 0 -> clippy-driver 1 - [build] rustc 0 -> cargo-clippy 1 - [clippy] rustc 1 -> rustc 2 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 0 -> clippy-driver 1 + [build] rustc 0 -> cargo-clippy 1 + [clippy] rustc 1 -> rustc 2 "#]] + .assert_eq(&ctx.config("clippy").path("compiler").stage(2).render_steps()); } #[test] fn clippy_std_stage1() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("clippy") - .path("std") - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 0 -> clippy-driver 1 - [build] rustc 0 -> cargo-clippy 1 - [clippy] rustc 1 -> std 1 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 0 -> clippy-driver 1 + [build] rustc 0 -> cargo-clippy 1 + [clippy] rustc 1 -> std 1 "#]] + .assert_eq(&ctx.config("clippy").path("std").render_steps()); } #[test] fn clippy_std_stage2() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("clippy") - .path("std") - .stage(2) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 1 -> rustc 2 - [build] rustc 1 -> clippy-driver 2 - [build] rustc 1 -> cargo-clippy 2 - [clippy] rustc 2 -> std 2 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> rustc 2 + [build] rustc 1 -> clippy-driver 2 + [build] rustc 1 -> cargo-clippy 2 + [clippy] rustc 2 -> std 2 "#]] + .assert_eq(&ctx.config("clippy").path("std").stage(2).render_steps()); } #[test] fn clippy_miri_stage1() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("clippy") - .path("miri") - .stage(1) - .render_steps(), @" - [check] rustc 0 -> rustc 1 - [clippy] rustc 0 -> miri 1 - "); + expect_test::expect![[r#" + [check] rustc 0 -> rustc 1 + [clippy] rustc 0 -> miri 1 "#]] + .assert_eq(&ctx.config("clippy").path("miri").stage(1).render_steps()); } #[test] fn clippy_miri_stage2() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("clippy") - .path("miri") - .stage(2) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [check] rustc 1 -> rustc 2 - [build] rustc 0 -> clippy-driver 1 - [build] rustc 0 -> cargo-clippy 1 - [clippy] rustc 1 -> miri 2 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [check] rustc 1 -> rustc 2 + [build] rustc 0 -> clippy-driver 1 + [build] rustc 0 -> cargo-clippy 1 + [clippy] rustc 1 -> miri 2 "#]] + .assert_eq(&ctx.config("clippy").path("miri").stage(2).render_steps()); } #[test] fn clippy_bootstrap() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("clippy") - .path("bootstrap") - .render_steps(), @"[clippy] rustc 0 -> bootstrap 1 "); + expect_test::expect![["[clippy] rustc 0 -> bootstrap 1 "]] + .assert_eq(&ctx.config("clippy").path("bootstrap").render_steps()); } #[test] fn install_plain() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("install") - .args(&[ - // Using backslashes fails with `--set` - "--set", &format!("install.prefix={}", ctx.normalized_dir()), - "--set", &format!("install.bindir={}", ctx.normalized_dir()), - "--set", &format!("install.libdir={}", ctx.normalized_dir()), - "--set", &format!("install.datadir={}", ctx.normalized_dir()), - "--set", &format!("install.mandir={}", ctx.normalized_dir()), - "--set", &format!("install.sysconfdir={}", ctx.normalized_dir()), - "--build", "x86_64-unknown-linux-gnu", - "--host", "x86_64-unknown-linux-gnu", - "--target", "x86_64-unknown-linux-gnu", - ]) - .get_steps() - .render_with(RenderConfig { - normalize_host: false - }), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 0 -> UnstableBookGen 1 - [build] rustc 0 -> Rustbook 1 - [doc] unstable-book (book) - [doc] book (book) - [doc] book/first-edition (book) - [doc] book/second-edition (book) - [doc] book/2018-edition (book) - [build] rustdoc 1 - [doc] rustc 1 -> standalone 2 - [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] - [build] rustc 1 -> rustc 2 - [build] rustc 1 -> error-index 2 - [doc] rustc 1 -> error-index 2 - [doc] nomicon (book) - [doc] rustc 1 -> reference (book) 2 - [doc] rustdoc (book) - [doc] rust-by-example (book) - [build] rustc 0 -> LintDocs 1 - [doc] rustc (book) - [doc] cargo (book) - [doc] clippy (book) - [doc] embedded-book (book) - [doc] edition-guide (book) - [doc] style-guide (book) - [doc] rustc 1 -> releases 2 - [build] rustc 0 -> RustInstaller 1 - [dist] docs - [dist] rustc 1 -> std 1 - [build] rustdoc 2 - [build] rustc 0 -> GenerateCopyright 1 - [dist] rustc - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 0 -> UnstableBookGen 1 + [build] rustc 0 -> Rustbook 1 + [doc] unstable-book (book) + [doc] book (book) + [doc] book/first-edition (book) + [doc] book/second-edition (book) + [doc] book/2018-edition (book) + [build] rustdoc 1 + [doc] rustc 1 -> standalone 2 + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] + [build] rustc 1 -> rustc 2 + [build] rustc 1 -> error-index 2 + [doc] rustc 1 -> error-index 2 + [doc] nomicon (book) + [doc] rustc 1 -> reference (book) 2 + [doc] rustdoc (book) + [doc] rust-by-example (book) + [build] rustc 0 -> LintDocs 1 + [doc] rustc (book) + [doc] cargo (book) + [doc] clippy (book) + [doc] embedded-book (book) + [doc] edition-guide (book) + [doc] style-guide (book) + [doc] rustc 1 -> releases 2 + [build] rustc 0 -> RustInstaller 1 + [dist] docs + [dist] rustc 1 -> std 1 + [build] rustdoc 2 + [build] rustc 0 -> GenerateCopyright 1 + [dist] rustc "#]].assert_eq(&ctx.config("install") + .args(&[ + // Using backslashes fails with `--set` + "--set", &format!("install.prefix={}", ctx.normalized_dir()), + "--set", &format!("install.bindir={}", ctx.normalized_dir()), + "--set", &format!("install.libdir={}", ctx.normalized_dir()), + "--set", &format!("install.datadir={}", ctx.normalized_dir()), + "--set", &format!("install.mandir={}", ctx.normalized_dir()), + "--set", &format!("install.sysconfdir={}", ctx.normalized_dir()), + "--build", "x86_64-unknown-linux-gnu", + "--host", "x86_64-unknown-linux-gnu", + "--target", "x86_64-unknown-linux-gnu", + ]) + .get_steps() + .render_with(RenderConfig { + normalize_host: false + })); } #[test] fn install_src() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("install") + expect_test::expect![[r#" + [build] rustc 0 -> RustInstaller 1 + [dist] src <>"#]] + .assert_eq( + &ctx.config("install") .path("rust-src") .args(&[ // Using backslashes fails with `--set` - "--set", &format!("install.prefix={}", ctx.normalized_dir()), - "--set", &format!("install.bindir={}", ctx.normalized_dir()), - "--set", &format!("install.libdir={}", ctx.normalized_dir()), - "--set", &format!("install.datadir={}", ctx.normalized_dir()), - "--set", &format!("install.mandir={}", ctx.normalized_dir()), - "--set", &format!("install.sysconfdir={}", ctx.normalized_dir()), - "--build", "x86_64-unknown-linux-gnu", - "--host", "x86_64-unknown-linux-gnu", - "--target", "x86_64-unknown-linux-gnu", + "--set", + &format!("install.prefix={}", ctx.normalized_dir()), + "--set", + &format!("install.bindir={}", ctx.normalized_dir()), + "--set", + &format!("install.libdir={}", ctx.normalized_dir()), + "--set", + &format!("install.datadir={}", ctx.normalized_dir()), + "--set", + &format!("install.mandir={}", ctx.normalized_dir()), + "--set", + &format!("install.sysconfdir={}", ctx.normalized_dir()), + "--build", + "x86_64-unknown-linux-gnu", + "--host", + "x86_64-unknown-linux-gnu", + "--target", + "x86_64-unknown-linux-gnu", ]) .get_steps() - .render_with(RenderConfig { - normalize_host: false - }), @r" - [build] rustc 0 -> RustInstaller 1 - [dist] src <> - "); + .render_with(RenderConfig { normalize_host: false }), + ); } #[test] fn install_src_no_docs() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("install") + expect_test::expect![[r#" + [build] rustc 0 -> RustInstaller 1 + [dist] src <>"#]] + .assert_eq( + &ctx.config("install") .path("rust-src") .args(&[ // Using backslashes fails with `--set` - "--set", &format!("install.prefix={}", ctx.normalized_dir()), - "--set", &format!("install.bindir={}", ctx.normalized_dir()), - "--set", &format!("install.libdir={}", ctx.normalized_dir()), - "--set", &format!("install.datadir={}", ctx.normalized_dir()), - "--set", &format!("install.mandir={}", ctx.normalized_dir()), - "--set", &format!("install.sysconfdir={}", ctx.normalized_dir()), - "--set", "build.docs=false", - "--build", "x86_64-unknown-linux-gnu", - "--host", "x86_64-unknown-linux-gnu", - "--target", "x86_64-unknown-linux-gnu", + "--set", + &format!("install.prefix={}", ctx.normalized_dir()), + "--set", + &format!("install.bindir={}", ctx.normalized_dir()), + "--set", + &format!("install.libdir={}", ctx.normalized_dir()), + "--set", + &format!("install.datadir={}", ctx.normalized_dir()), + "--set", + &format!("install.mandir={}", ctx.normalized_dir()), + "--set", + &format!("install.sysconfdir={}", ctx.normalized_dir()), + "--set", + "build.docs=false", + "--build", + "x86_64-unknown-linux-gnu", + "--host", + "x86_64-unknown-linux-gnu", + "--target", + "x86_64-unknown-linux-gnu", ]) .get_steps() - .render_with(RenderConfig { - normalize_host: false - }), @r" - [build] rustc 0 -> RustInstaller 1 - [dist] src <> - "); + .render_with(RenderConfig { normalize_host: false }), + ); } #[test] fn install_extended() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("install") - .args(&[ - // Using backslashes fails with `--set` - "--set", &format!("install.prefix={}", ctx.normalized_dir()), - "--set", &format!("install.bindir={}", ctx.normalized_dir()), - "--set", &format!("install.libdir={}", ctx.normalized_dir()), - "--set", &format!("install.datadir={}", ctx.normalized_dir()), - "--set", &format!("install.mandir={}", ctx.normalized_dir()), - "--set", &format!("install.sysconfdir={}", ctx.normalized_dir()), - "--set", "build.extended=true", - // For Cranelift to be disted - "--build", "x86_64-unknown-linux-gnu", - "--host", "x86_64-unknown-linux-gnu", - ]) - .get_steps() - .render_with(RenderConfig { - normalize_host: false - }), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 0 -> WasmComponentLd 1 - [build] rustc 1 -> std 1 - [build] rustc 0 -> UnstableBookGen 1 - [build] rustc 0 -> Rustbook 1 - [doc] unstable-book (book) - [doc] book (book) - [doc] book/first-edition (book) - [doc] book/second-edition (book) - [doc] book/2018-edition (book) - [build] rustdoc 1 - [doc] rustc 1 -> standalone 2 - [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] - [build] rustc 1 -> rustc 2 - [build] rustc 1 -> WasmComponentLd 2 - [build] rustc 1 -> error-index 2 - [doc] rustc 1 -> error-index 2 - [doc] nomicon (book) - [doc] rustc 1 -> reference (book) 2 - [doc] rustdoc (book) - [doc] rust-by-example (book) - [build] rustc 0 -> LintDocs 1 - [doc] rustc (book) - [doc] cargo (book) - [doc] clippy (book) - [doc] embedded-book (book) - [doc] edition-guide (book) - [doc] style-guide (book) - [doc] rustc 1 -> releases 2 - [build] rustc 0 -> RustInstaller 1 - [dist] docs - [dist] rustc 1 -> std 1 - [build] rustdoc 2 - [build] rustc 1 -> rust-analyzer-proc-macro-srv 2 - [build] rustc 0 -> GenerateCopyright 1 - [dist] rustc - [dist] rustc 1 -> rustc-dev 2 - [build] rustc 1 -> cargo 2 - [dist] rustc 1 -> cargo 2 - [build] rustc 1 -> rust-analyzer 2 - [dist] rustc 1 -> rust-analyzer 2 - [build] rustc 1 -> rustfmt 2 - [build] rustc 1 -> cargo-fmt 2 - [dist] rustc 1 -> rustfmt 2 - [build] rustc 1 -> clippy-driver 2 - [build] rustc 1 -> cargo-clippy 2 - [dist] rustc 1 -> clippy 2 - [build] rustc 1 -> miri 2 - [build] rustc 1 -> cargo-miri 2 - [dist] rustc 1 -> miri 2 - [dist] src <> - [build] rustc 1 -> rustc_codegen_cranelift 2 - [dist] rustc 1 -> rustc_codegen_cranelift 2 - [build] rustc 1 -> LlvmBitcodeLinker 2 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 0 -> WasmComponentLd 1 + [build] rustc 1 -> std 1 + [build] rustc 0 -> UnstableBookGen 1 + [build] rustc 0 -> Rustbook 1 + [doc] unstable-book (book) + [doc] book (book) + [doc] book/first-edition (book) + [doc] book/second-edition (book) + [doc] book/2018-edition (book) + [build] rustdoc 1 + [doc] rustc 1 -> standalone 2 + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] + [build] rustc 1 -> rustc 2 + [build] rustc 1 -> WasmComponentLd 2 + [build] rustc 1 -> error-index 2 + [doc] rustc 1 -> error-index 2 + [doc] nomicon (book) + [doc] rustc 1 -> reference (book) 2 + [doc] rustdoc (book) + [doc] rust-by-example (book) + [build] rustc 0 -> LintDocs 1 + [doc] rustc (book) + [doc] cargo (book) + [doc] clippy (book) + [doc] embedded-book (book) + [doc] edition-guide (book) + [doc] style-guide (book) + [doc] rustc 1 -> releases 2 + [build] rustc 0 -> RustInstaller 1 + [dist] docs + [dist] rustc 1 -> std 1 + [build] rustdoc 2 + [build] rustc 1 -> rust-analyzer-proc-macro-srv 2 + [build] rustc 0 -> GenerateCopyright 1 + [dist] rustc + [dist] rustc 1 -> rustc-dev 2 + [build] rustc 1 -> cargo 2 + [dist] rustc 1 -> cargo 2 + [build] rustc 1 -> rust-analyzer 2 + [dist] rustc 1 -> rust-analyzer 2 + [build] rustc 1 -> rustfmt 2 + [build] rustc 1 -> cargo-fmt 2 + [dist] rustc 1 -> rustfmt 2 + [build] rustc 1 -> clippy-driver 2 + [build] rustc 1 -> cargo-clippy 2 + [dist] rustc 1 -> clippy 2 + [build] rustc 1 -> miri 2 + [build] rustc 1 -> cargo-miri 2 + [dist] rustc 1 -> miri 2 + [dist] src <> + [build] rustc 1 -> rustc_codegen_cranelift 2 + [dist] rustc 1 -> rustc_codegen_cranelift 2 + [build] rustc 1 -> LlvmBitcodeLinker 2 "#]].assert_eq(&ctx.config("install") + .args(&[ + // Using backslashes fails with `--set` + "--set", &format!("install.prefix={}", ctx.normalized_dir()), + "--set", &format!("install.bindir={}", ctx.normalized_dir()), + "--set", &format!("install.libdir={}", ctx.normalized_dir()), + "--set", &format!("install.datadir={}", ctx.normalized_dir()), + "--set", &format!("install.mandir={}", ctx.normalized_dir()), + "--set", &format!("install.sysconfdir={}", ctx.normalized_dir()), + "--set", "build.extended=true", + // For Cranelift to be disted + "--build", "x86_64-unknown-linux-gnu", + "--host", "x86_64-unknown-linux-gnu", + ]) + .get_steps() + .render_with(RenderConfig { + normalize_host: false + })); } #[test] fn cargo_miri_stage_1() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("test") - .args(&["cargo-miri"]) - .stage(1) - .get_steps() - .render(), @" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 0 -> miri 1 - [build] rustc 0 -> cargo-miri 1 - [build] rustdoc 1 - [build] rustc 1 -> std 1 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 0 -> miri 1 + [build] rustc 0 -> cargo-miri 1 + [build] rustdoc 1 + [build] rustc 1 -> std 1 "#]] + .assert_eq(&ctx.config("test").args(&["cargo-miri"]).stage(1).get_steps().render()); } #[test] fn cargo_miri_stage_2() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("test") - .args(&["cargo-miri"]) - .stage(2) - .get_steps() - .render(), @" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 1 -> rustc 2 - [build] rustc 1 -> miri 2 - [build] rustc 1 -> cargo-miri 2 - [build] rustdoc 2 - [build] rustc 2 -> std 2 - [build] rustc 0 -> cargo 1 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> rustc 2 + [build] rustc 1 -> miri 2 + [build] rustc 1 -> cargo-miri 2 + [build] rustdoc 2 + [build] rustc 2 -> std 2 + [build] rustc 0 -> cargo 1 "#]] + .assert_eq(&ctx.config("test").args(&["cargo-miri"]).stage(2).get_steps().render()); } #[test] fn test_float_parse() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("test") - .path("src/tools/test-float-parse") - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustdoc 1 - [test] test-float-parse - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustdoc 1 + [test] test-float-parse "#]] + .assert_eq(&ctx.config("test").path("src/tools/test-float-parse").render_steps()); } #[test] fn test_float_parse_cross() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("test") + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> std 1 + [build] rustdoc 1 + [test] test-float-parse "#]] + .assert_eq( + &ctx.config("test") .path("src/tools/test-float-parse") .targets(&[TEST_TRIPLE_1]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 1 -> std 1 - [build] rustdoc 1 - [test] test-float-parse - "); + .render_steps(), + ); } // Check that `x run miri --target FOO` actually builds miri for the host. #[test] fn run_miri() { let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("run") - .path("miri") - .stage(1) - .targets(&[TEST_TRIPLE_1]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 0 -> miri 1 - [build] rustc 0 -> cargo-miri 1 - [run] rustc 0 -> miri 1 - "); + expect_test::expect![[r#" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 0 -> miri 1 + [build] rustc 0 -> cargo-miri 1 + [run] rustc 0 -> miri 1 "#]] + .assert_eq( + &ctx.config("run").path("miri").stage(1).targets(&[TEST_TRIPLE_1]).render_steps(), + ); } #[test] fn fix_compiler() { let ctx = TestCtx::new(); - insta::assert_snapshot!(ctx.config("fix").path("compiler").render_steps(), @"[fix] rustc 0 -> rustc 1 (78 crates)"); + expect_test::expect![["[fix] rustc 0 -> rustc 1 (78 crates)"]] + .assert_eq(&ctx.config("fix").path("compiler").render_steps()); } } From 7ed40b326767af5251872aaacc8385ed834a1d4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 24 Oct 2026 16:33:24 +0200 Subject: [PATCH 33/49] Update documentation --- src/bootstrap/README.md | 4 +--- src/bootstrap/src/core/builder/cli_paths/tests.rs | 5 +---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index 03d178630f8bb..dda7cecf64486 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -222,9 +222,7 @@ please file issues on the [Rust issue tracker][rust-issue-tracker]. ## Testing To run bootstrap tests, execute `x test bootstrap`. -If you want to bless snapshot tests, -then install `cargo-insta` (`cargo install --locked cargo-insta`), -and then run `cargo insta review --manifest-path src/bootstrap/Cargo.toml`. +If you want to bless snapshot tests, use `x test bootstrap --bless`. ## Changelog diff --git a/src/bootstrap/src/core/builder/cli_paths/tests.rs b/src/bootstrap/src/core/builder/cli_paths/tests.rs index 5dd888b3fda4c..ce07ee9e807eb 100644 --- a/src/bootstrap/src/core/builder/cli_paths/tests.rs +++ b/src/bootstrap/src/core/builder/cli_paths/tests.rs @@ -124,10 +124,7 @@ macro_rules! declare_tests { // Snapshot tests for bootstrap's command-line path-to-step handling. // -// To bless these tests as necessary, choose one: -// - Run `INSTA_UPDATE=always ./x test bootstrap` -// - Run `./x test bootstrap --bless` -// - Follow the instructions for `cargo-insta` in bootstrap's README.md +// To bless these tests as necessary, run `./x test bootstrap --bless`. // // These snapshot tests capture _current_ behavior, to prevent unintended // changes or regressions. If the current behavior is wrong or undersirable, From a39251d2c2b20b3b1c43a5d621e2ea0c97241721 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 25 Oct 2026 10:45:57 +0100 Subject: [PATCH 34/49] Ignore more std functions body --- library/std/src/os/fd/owned.rs | 19 ++++++++++++ library/std/src/os/fd/raw.rs | 10 ++++++ library/std/src/os/linux/fs.rs | 18 +++++++++++ library/std/src/os/linux/process.rs | 1 + library/std/src/os/net/linux_ext/socket.rs | 5 +++ library/std/src/os/net/linux_ext/tcp.rs | 3 ++ library/std/src/os/unix/ffi/os_str.rs | 3 ++ library/std/src/os/unix/fs.rs | 18 +++++++++++ library/std/src/os/unix/fs/dirs.rs | 7 +++++ library/std/src/os/unix/io/mod.rs | 2 ++ library/std/src/os/unix/net/addr.rs | 5 +++ library/std/src/os/unix/net/ancillary.rs | 6 ++++ library/std/src/os/unix/net/datagram.rs | 14 +++++++++ library/std/src/os/unix/net/listener.rs | 8 +++++ library/std/src/os/unix/net/stream.rs | 13 ++++++++ library/std/src/os/unix/process.rs | 36 ++++++++++++++++++++++ library/std/src/os/unix/thread.rs | 3 ++ library/std/src/os/wasi/fs.rs | 4 +++ 18 files changed, 175 insertions(+) diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index dd6336748db2c..c336b11e91f7c 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -10,6 +10,7 @@ use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use crate::alloc::Allocator; #[cfg(not(target_os = "trusty"))] use crate::fs; +use crate::macros::rustdoc_skip_body; use crate::marker::PhantomData; use crate::mem::ManuallyDrop; #[cfg(not(any( @@ -136,6 +137,7 @@ impl BorrowedFd<'_> { target_os = "motor" )))] #[stable(feature = "io_safety", since = "1.63.0")] + #[rustdoc_skip_body] pub fn try_clone_to_owned(&self) -> io::Result { // We want to atomically duplicate this file descriptor and set the // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This @@ -225,6 +227,7 @@ impl FromRawFd for OwnedFd { #[stable(feature = "io_safety", since = "1.63.0")] impl Drop for OwnedFd { #[inline] + #[rustdoc_skip_body] fn drop(&mut self) { unsafe { // Note that errors are ignored when closing a file descriptor. According to POSIX 2024, @@ -344,6 +347,7 @@ impl AsFd for OwnedFd { #[cfg(not(target_os = "trusty"))] impl AsFd for fs::File { #[inline] + #[rustdoc_skip_body] fn as_fd(&self) -> BorrowedFd<'_> { self.as_inner().as_fd() } @@ -354,6 +358,7 @@ impl AsFd for fs::File { impl From for OwnedFd { /// Takes ownership of a [`File`](fs::File)'s underlying file descriptor. #[inline] + #[rustdoc_skip_body] fn from(file: fs::File) -> OwnedFd { file.into_inner().into_inner().into_inner() } @@ -365,6 +370,7 @@ impl From for fs::File { /// Returns a [`File`](fs::File) that takes ownership of the given /// file descriptor. #[inline] + #[rustdoc_skip_body] fn from(owned_fd: OwnedFd) -> Self { Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd))) } @@ -374,6 +380,7 @@ impl From for fs::File { #[cfg(not(target_os = "trusty"))] impl AsFd for crate::net::TcpStream { #[inline] + #[rustdoc_skip_body] fn as_fd(&self) -> BorrowedFd<'_> { self.as_inner().socket().as_fd() } @@ -384,6 +391,7 @@ impl AsFd for crate::net::TcpStream { impl From for OwnedFd { /// Takes ownership of a [`TcpStream`](crate::net::TcpStream)'s socket file descriptor. #[inline] + #[rustdoc_skip_body] fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd { tcp_stream.into_inner().into_socket().into_inner().into_inner() } @@ -393,6 +401,7 @@ impl From for OwnedFd { #[cfg(not(target_os = "trusty"))] impl From for crate::net::TcpStream { #[inline] + #[rustdoc_skip_body] fn from(owned_fd: OwnedFd) -> Self { Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( owned_fd, @@ -404,6 +413,7 @@ impl From for crate::net::TcpStream { #[cfg(not(target_os = "trusty"))] impl AsFd for crate::net::TcpListener { #[inline] + #[rustdoc_skip_body] fn as_fd(&self) -> BorrowedFd<'_> { self.as_inner().socket().as_fd() } @@ -414,6 +424,7 @@ impl AsFd for crate::net::TcpListener { impl From for OwnedFd { /// Takes ownership of a [`TcpListener`](crate::net::TcpListener)'s socket file descriptor. #[inline] + #[rustdoc_skip_body] fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd { tcp_listener.into_inner().into_socket().into_inner().into_inner() } @@ -423,6 +434,7 @@ impl From for OwnedFd { #[cfg(not(target_os = "trusty"))] impl From for crate::net::TcpListener { #[inline] + #[rustdoc_skip_body] fn from(owned_fd: OwnedFd) -> Self { Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( owned_fd, @@ -434,6 +446,7 @@ impl From for crate::net::TcpListener { #[cfg(not(target_os = "trusty"))] impl AsFd for crate::net::UdpSocket { #[inline] + #[rustdoc_skip_body] fn as_fd(&self) -> BorrowedFd<'_> { self.as_inner().socket().as_fd() } @@ -444,6 +457,7 @@ impl AsFd for crate::net::UdpSocket { impl From for OwnedFd { /// Takes ownership of a [`UdpSocket`](crate::net::UdpSocket)'s file descriptor. #[inline] + #[rustdoc_skip_body] fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd { udp_socket.into_inner().into_socket().into_inner().into_inner() } @@ -453,6 +467,7 @@ impl From for OwnedFd { #[cfg(not(target_os = "trusty"))] impl From for crate::net::UdpSocket { #[inline] + #[rustdoc_skip_body] fn from(owned_fd: OwnedFd) -> Self { Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( owned_fd, @@ -613,6 +628,7 @@ impl<'a> AsFd for io::StderrLock<'a> { #[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl AsFd for io::PipeReader { + #[rustdoc_skip_body] fn as_fd(&self) -> BorrowedFd<'_> { self.0.as_fd() } @@ -621,6 +637,7 @@ impl AsFd for io::PipeReader { #[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl From for OwnedFd { + #[rustdoc_skip_body] fn from(pipe: io::PipeReader) -> Self { pipe.0.into_inner() } @@ -629,6 +646,7 @@ impl From for OwnedFd { #[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl AsFd for io::PipeWriter { + #[rustdoc_skip_body] fn as_fd(&self) -> BorrowedFd<'_> { self.0.as_fd() } @@ -637,6 +655,7 @@ impl AsFd for io::PipeWriter { #[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl From for OwnedFd { + #[rustdoc_skip_body] fn from(pipe: io::PipeWriter) -> Self { pipe.0.into_inner() } diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs index 4d7b6a3e5fb53..41904018d095a 100644 --- a/library/std/src/os/fd/raw.rs +++ b/library/std/src/os/fd/raw.rs @@ -13,6 +13,7 @@ use crate::alloc::Allocator; #[cfg(not(target_os = "trusty"))] use crate::fs; use crate::io; +use crate::macros::rustdoc_skip_body; #[cfg(target_os = "hermit")] use crate::os::hermit::io::OwnedFd; #[cfg(all(not(target_os = "hermit"), not(target_os = "motor")))] @@ -172,6 +173,7 @@ impl FromRawFd for RawFd { #[cfg(not(target_os = "trusty"))] impl AsRawFd for fs::File { #[inline] + #[rustdoc_skip_body] fn as_raw_fd(&self) -> RawFd { self.as_inner().as_raw_fd() } @@ -180,6 +182,7 @@ impl AsRawFd for fs::File { #[cfg(not(target_os = "trusty"))] impl FromRawFd for fs::File { #[inline] + #[rustdoc_skip_body] unsafe fn from_raw_fd(fd: RawFd) -> fs::File { unsafe { fs::File::from(OwnedFd::from_raw_fd(fd)) } } @@ -188,6 +191,7 @@ impl FromRawFd for fs::File { #[cfg(not(target_os = "trusty"))] impl IntoRawFd for fs::File { #[inline] + #[rustdoc_skip_body] fn into_raw_fd(self) -> RawFd { self.into_inner().into_inner().into_raw_fd() } @@ -293,6 +297,7 @@ impl AsRawFd for Box { #[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl AsRawFd for io::PipeReader { + #[rustdoc_skip_body] fn as_raw_fd(&self) -> RawFd { self.0.as_raw_fd() } @@ -301,6 +306,7 @@ impl AsRawFd for io::PipeReader { #[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl FromRawFd for io::PipeReader { + #[rustdoc_skip_body] unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { Self::from_inner(unsafe { FromRawFd::from_raw_fd(raw_fd) }) } @@ -309,6 +315,7 @@ impl FromRawFd for io::PipeReader { #[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl IntoRawFd for io::PipeReader { + #[rustdoc_skip_body] fn into_raw_fd(self) -> RawFd { self.0.into_raw_fd() } @@ -317,6 +324,7 @@ impl IntoRawFd for io::PipeReader { #[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl AsRawFd for io::PipeWriter { + #[rustdoc_skip_body] fn as_raw_fd(&self) -> RawFd { self.0.as_raw_fd() } @@ -325,6 +333,7 @@ impl AsRawFd for io::PipeWriter { #[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl FromRawFd for io::PipeWriter { + #[rustdoc_skip_body] unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { Self::from_inner(unsafe { FromRawFd::from_raw_fd(raw_fd) }) } @@ -333,6 +342,7 @@ impl FromRawFd for io::PipeWriter { #[stable(feature = "anonymous_pipe", since = "1.87.0")] #[cfg(not(target_os = "trusty"))] impl IntoRawFd for io::PipeWriter { + #[rustdoc_skip_body] fn into_raw_fd(self) -> RawFd { self.0.into_raw_fd() } diff --git a/library/std/src/os/linux/fs.rs b/library/std/src/os/linux/fs.rs index 0e8fa0a15da09..1f4021811e350 100644 --- a/library/std/src/os/linux/fs.rs +++ b/library/std/src/os/linux/fs.rs @@ -5,6 +5,7 @@ #![stable(feature = "metadata_ext", since = "1.1.0")] use crate::fs::Metadata; +use crate::macros::rustdoc_skip_body; #[allow(deprecated)] use crate::os::linux::raw; use crate::sys::AsInner; @@ -344,6 +345,7 @@ pub trait MetadataExt { #[stable(feature = "metadata_ext", since = "1.1.0")] impl MetadataExt for Metadata { #[allow(deprecated)] + #[rustdoc_skip_body] fn as_raw_stat(&self) -> &raw::stat { #[cfg(target_env = "musl")] unsafe { @@ -354,30 +356,39 @@ impl MetadataExt for Metadata { &*(self.as_inner().as_inner() as *const libc::stat64 as *const raw::stat) } } + #[rustdoc_skip_body] fn st_dev(&self) -> u64 { self.as_inner().as_inner().st_dev as u64 } + #[rustdoc_skip_body] fn st_ino(&self) -> u64 { self.as_inner().as_inner().st_ino as u64 } + #[rustdoc_skip_body] fn st_mode(&self) -> u32 { self.as_inner().as_inner().st_mode as u32 } + #[rustdoc_skip_body] fn st_nlink(&self) -> u64 { self.as_inner().as_inner().st_nlink as u64 } + #[rustdoc_skip_body] fn st_uid(&self) -> u32 { self.as_inner().as_inner().st_uid as u32 } + #[rustdoc_skip_body] fn st_gid(&self) -> u32 { self.as_inner().as_inner().st_gid as u32 } + #[rustdoc_skip_body] fn st_rdev(&self) -> u64 { self.as_inner().as_inner().st_rdev as u64 } + #[rustdoc_skip_body] fn st_size(&self) -> u64 { self.as_inner().as_inner().st_size as u64 } + #[rustdoc_skip_body] fn st_atime(&self) -> i64 { let file_attr = self.as_inner(); #[cfg(all(target_env = "gnu", target_pointer_width = "32"))] @@ -386,9 +397,11 @@ impl MetadataExt for Metadata { } file_attr.as_inner().st_atime as i64 } + #[rustdoc_skip_body] fn st_atime_nsec(&self) -> i64 { self.as_inner().as_inner().st_atime_nsec as i64 } + #[rustdoc_skip_body] fn st_mtime(&self) -> i64 { let file_attr = self.as_inner(); #[cfg(all(target_env = "gnu", target_pointer_width = "32"))] @@ -397,9 +410,11 @@ impl MetadataExt for Metadata { } file_attr.as_inner().st_mtime as i64 } + #[rustdoc_skip_body] fn st_mtime_nsec(&self) -> i64 { self.as_inner().as_inner().st_mtime_nsec as i64 } + #[rustdoc_skip_body] fn st_ctime(&self) -> i64 { let file_attr = self.as_inner(); #[cfg(all(target_env = "gnu", target_pointer_width = "32"))] @@ -408,12 +423,15 @@ impl MetadataExt for Metadata { } file_attr.as_inner().st_ctime as i64 } + #[rustdoc_skip_body] fn st_ctime_nsec(&self) -> i64 { self.as_inner().as_inner().st_ctime_nsec as i64 } + #[rustdoc_skip_body] fn st_blksize(&self) -> u64 { self.as_inner().as_inner().st_blksize as u64 } + #[rustdoc_skip_body] fn st_blocks(&self) -> u64 { self.as_inner().as_inner().st_blocks as u64 } diff --git a/library/std/src/os/linux/process.rs b/library/std/src/os/linux/process.rs index 26a4ab4b4c603..19cc16822f98d 100644 --- a/library/std/src/os/linux/process.rs +++ b/library/std/src/os/linux/process.rs @@ -221,6 +221,7 @@ pub impl(self) trait CommandExt { } impl CommandExt for process::Command { + #[rustdoc_skip_body] fn create_pidfd(&mut self, val: bool) -> &mut process::Command { self.as_inner_mut().create_pidfd(val); self diff --git a/library/std/src/os/net/linux_ext/socket.rs b/library/std/src/os/net/linux_ext/socket.rs index 777587fe4ce7c..67936e28f5f3f 100644 --- a/library/std/src/os/net/linux_ext/socket.rs +++ b/library/std/src/os/net/linux_ext/socket.rs @@ -1,6 +1,7 @@ //! Linux and Android-specific socket functionality. use crate::io; +use crate::macros::rustdoc_skip_body; use crate::os::unix::net; use crate::sys::AsInner; @@ -51,10 +52,12 @@ pub impl(self) trait UnixSocketExt { #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] impl UnixSocketExt for net::UnixDatagram { + #[rustdoc_skip_body] fn passcred(&self) -> io::Result { self.as_inner().passcred() } + #[rustdoc_skip_body] fn set_passcred(&self, passcred: bool) -> io::Result<()> { self.as_inner().set_passcred(passcred) } @@ -62,10 +65,12 @@ impl UnixSocketExt for net::UnixDatagram { #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] impl UnixSocketExt for net::UnixStream { + #[rustdoc_skip_body] fn passcred(&self) -> io::Result { self.as_inner().passcred() } + #[rustdoc_skip_body] fn set_passcred(&self, passcred: bool) -> io::Result<()> { self.as_inner().set_passcred(passcred) } diff --git a/library/std/src/os/net/linux_ext/tcp.rs b/library/std/src/os/net/linux_ext/tcp.rs index 2fc6b2769568e..726655b54d174 100644 --- a/library/std/src/os/net/linux_ext/tcp.rs +++ b/library/std/src/os/net/linux_ext/tcp.rs @@ -2,6 +2,7 @@ //! //! [`std::net`]: crate::net +use crate::macros::rustdoc_skip_body; use crate::sys::AsInner; #[cfg(target_os = "linux")] use crate::time::Duration; @@ -131,10 +132,12 @@ pub impl(self) trait TcpStreamExt { #[stable(feature = "tcp_quickack", since = "1.89.0")] impl TcpStreamExt for net::TcpStream { + #[rustdoc_skip_body] fn set_quickack(&self, quickack: bool) -> io::Result<()> { self.as_inner().as_inner().set_quickack(quickack) } + #[rustdoc_skip_body] fn quickack(&self) -> io::Result { self.as_inner().as_inner().quickack() } diff --git a/library/std/src/os/unix/ffi/os_str.rs b/library/std/src/os/unix/ffi/os_str.rs index 5beabd5618084..3a9312eb84692 100644 --- a/library/std/src/os/unix/ffi/os_str.rs +++ b/library/std/src/os/unix/ffi/os_str.rs @@ -1,4 +1,5 @@ use crate::ffi::{OsStr, OsString}; +use crate::macros::rustdoc_skip_body; use crate::mem; use crate::sys::os_str::Buf; use crate::sys::{AsInner, FromInner, IntoInner}; @@ -29,6 +30,7 @@ impl OsStringExt for OsString { FromInner::from_inner(Buf { inner: vec }) } #[inline] + #[rustdoc_skip_body] fn into_vec(self) -> Vec { self.into_inner().inner } @@ -57,6 +59,7 @@ impl OsStrExt for OsStr { unsafe { mem::transmute(slice) } } #[inline] + #[rustdoc_skip_body] fn as_bytes(&self) -> &[u8] { &self.as_inner().inner } diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index 6edb464b949d5..7a9524054ef7b 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -12,6 +12,7 @@ use super::platform::fs::MetadataExt as _; use crate::ffi::OsStr; use crate::fs::{self, OpenOptions, Permissions}; use crate::io::BorrowedCursor; +use crate::macros::rustdoc_skip_body; use crate::os::unix::io::{AsFd, AsRawFd}; use crate::path::Path; use crate::sys::{AsInner, AsInnerMut, FromInner}; @@ -372,12 +373,14 @@ impl FileExt for fs::File { fn read_buf_at(&self, buf: BorrowedCursor<'_, u8>, offset: u64) -> io::Result<()> { self.as_inner().read_buf_at(buf, offset) } + #[rustdoc_skip_body] fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut<'_>], offset: u64) -> io::Result { self.as_inner().read_vectored_at(bufs, offset) } fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { self.as_inner().write_at(buf, offset) } + #[rustdoc_skip_body] fn write_vectored_at(&self, bufs: &[io::IoSlice<'_>], offset: u64) -> io::Result { self.as_inner().write_vectored_at(bufs, offset) } @@ -476,6 +479,7 @@ pub trait PermissionsExt { #[stable(feature = "fs_ext", since = "1.1.0")] impl PermissionsExt for Permissions { + #[rustdoc_skip_body] fn mode(&self) -> u32 { self.as_inner().mode() } @@ -545,11 +549,13 @@ pub trait OpenOptionsExt { #[stable(feature = "fs_ext", since = "1.1.0")] impl OpenOptionsExt for OpenOptions { + #[rustdoc_skip_body] fn mode(&mut self, mode: u32) -> &mut OpenOptions { self.as_inner_mut().mode(mode); self } + #[rustdoc_skip_body] fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions { self.as_inner_mut().custom_flags(flags); self @@ -1006,15 +1012,19 @@ pub trait FileTypeExt { #[stable(feature = "file_type_ext", since = "1.5.0")] impl FileTypeExt for fs::FileType { + #[rustdoc_skip_body] fn is_block_device(&self) -> bool { self.as_inner().is(libc::S_IFBLK) } + #[rustdoc_skip_body] fn is_char_device(&self) -> bool { self.as_inner().is(libc::S_IFCHR) } + #[rustdoc_skip_body] fn is_fifo(&self) -> bool { self.as_inner().is(libc::S_IFIFO) } + #[rustdoc_skip_body] fn is_socket(&self) -> bool { self.as_inner().is(libc::S_IFSOCK) } @@ -1048,6 +1058,7 @@ pub trait DirEntryExt { #[stable(feature = "dir_entry_ext", since = "1.1.0")] impl DirEntryExt for fs::DirEntry { + #[rustdoc_skip_body] fn ino(&self) -> u64 { self.as_inner().ino() } @@ -1082,6 +1093,7 @@ pub impl(self) trait DirEntryExt2 { #[unstable(feature = "dir_entry_ext2", issue = "85573")] impl DirEntryExt2 for fs::DirEntry { + #[rustdoc_skip_body] fn file_name_ref(&self) -> &OsStr { self.as_inner().file_name_os_str() } @@ -1130,6 +1142,7 @@ pub trait DirBuilderExt { #[stable(feature = "dir_builder", since = "1.6.0")] impl DirBuilderExt for fs::DirBuilder { + #[rustdoc_skip_body] fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder { self.as_inner_mut().set_mode(mode); self @@ -1164,6 +1177,7 @@ impl DirBuilderExt for fs::DirBuilder { /// } /// ``` #[stable(feature = "unix_chown", since = "1.73.0")] +#[rustdoc_skip_body] pub fn chown>(dir: P, uid: Option, gid: Option) -> io::Result<()> { sys::fs::chown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX)) } @@ -1185,6 +1199,7 @@ pub fn chown>(dir: P, uid: Option, gid: Option) -> io:: /// } /// ``` #[stable(feature = "unix_chown", since = "1.73.0")] +#[rustdoc_skip_body] pub fn fchown(fd: F, uid: Option, gid: Option) -> io::Result<()> { sys::fs::fchown(fd.as_fd().as_raw_fd(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX)) } @@ -1206,6 +1221,7 @@ pub fn fchown(fd: F, uid: Option, gid: Option) -> io::Result< /// } /// ``` #[stable(feature = "unix_chown", since = "1.73.0")] +#[rustdoc_skip_body] pub fn lchown>(dir: P, uid: Option, gid: Option) -> io::Result<()> { sys::fs::lchown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX)) } @@ -1232,6 +1248,7 @@ pub fn lchown>(dir: P, uid: Option, gid: Option) -> io: /// ``` #[stable(feature = "unix_chroot", since = "1.56.0")] #[cfg(not(target_os = "fuchsia"))] +#[rustdoc_skip_body] pub fn chroot>(dir: P) -> io::Result<()> { sys::fs::chroot(dir.as_ref()) } @@ -1269,6 +1286,7 @@ pub fn chroot>(dir: P) -> io::Result<()> { /// # } /// ``` #[unstable(feature = "unix_mkfifo", issue = "139324")] +#[rustdoc_skip_body] pub fn mkfifo>(path: P, permissions: Permissions) -> io::Result<()> { sys::fs::mkfifo(path.as_ref(), permissions.mode()) } diff --git a/library/std/src/os/unix/fs/dirs.rs b/library/std/src/os/unix/fs/dirs.rs index 5d8e13c7a730a..8081cb633acff 100644 --- a/library/std/src/os/unix/fs/dirs.rs +++ b/library/std/src/os/unix/fs/dirs.rs @@ -2,6 +2,7 @@ use crate::env::{self, SplitPathsRef}; use crate::ffi::{OsStr, OsString}; use crate::fs::{self, HomeDirs, MediaDirs}; use crate::io::{self, ErrorKind, const_error}; +use crate::macros::rustdoc_skip_body; use crate::path::{Path, PathBuf}; #[derive(Debug, Default, Clone)] @@ -247,14 +248,17 @@ impl HomeDirsExt for HomeDirs { Ok(dirs) } + #[rustdoc_skip_body] fn runtime_home(&self) -> Option<&Path> { self.extra.runtime.as_deref() } + #[rustdoc_skip_body] fn config_dirs(&self) -> Option> { self.extra.config_path.as_deref().map(XdgDirs::new) } + #[rustdoc_skip_body] fn data_dirs(&self) -> Option> { self.extra.data_path.as_deref().map(XdgDirs::new) } @@ -302,6 +306,7 @@ impl MediaDirsExt for MediaDirs { Ok(xdg::parse_user_dirs(&spec, &user_home)) } + #[rustdoc_skip_body] fn templates(&self) -> Option<&Path> { self.extra.templates.as_deref() } @@ -338,6 +343,7 @@ mod xdg { use crate::env::{self, join_paths, var_os}; use crate::ffi::OsString; use crate::io::{self, ErrorKind, const_error}; + use crate::macros::rustdoc_skip_body; use crate::ops::Deref; use crate::os::unix::ffi::{OsStrExt, OsStringExt}; use crate::path::{Path, PathBuf}; @@ -377,6 +383,7 @@ mod xdg { dirs(env).unwrap_or_else(|| fallback.into()) } + #[rustdoc_skip_body] pub fn parse_user_dirs<'a>(spec: &'a [u8], user_home: &Path) -> MediaDirs { let mut dirs = MediaDirs::empty(); diff --git a/library/std/src/os/unix/io/mod.rs b/library/std/src/os/unix/io/mod.rs index 099bdd35439a1..7804c4382f90c 100644 --- a/library/std/src/os/unix/io/mod.rs +++ b/library/std/src/os/unix/io/mod.rs @@ -93,6 +93,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::io::{self, Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock, Write}; +use crate::macros::rustdoc_skip_body; #[stable(feature = "rust1", since = "1.0.0")] pub use crate::os::fd::*; #[allow(unused_imports)] // not used on all targets @@ -209,6 +210,7 @@ fn null_fd() -> io::Result { /// Replaces the underlying file descriptor with the one from `other`. /// Does not set CLOEXEC. +#[rustdoc_skip_body] fn replace_stdio_fd(this: BorrowedFd<'_>, other: OwnedFd) -> io::Result<()> { cfg_select! { all(target_os = "wasi", target_env = "p1") => { diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index b03b359cdea91..e5fcb93b88308 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -1,5 +1,6 @@ use crate::byte_str::ByteStr; use crate::ffi::OsStr; +use crate::macros::rustdoc_skip_body; #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "cygwin"))] use crate::os::net::linux_ext; use crate::os::unix::ffi::OsStrExt; @@ -22,6 +23,7 @@ mod libc { const SUN_PATH_OFFSET: usize = mem::offset_of!(libc::sockaddr_un, sun_path); +#[rustdoc_skip_body] pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { // SAFETY: All zeros is a valid representation for `sockaddr_un`. let mut addr: libc::sockaddr_un = unsafe { mem::zeroed() }; @@ -109,6 +111,7 @@ impl SocketAddr { } } + #[rustdoc_skip_body] pub(super) fn from_parts( addr: libc::sockaddr_un, mut len: libc::socklen_t, @@ -251,6 +254,7 @@ impl SocketAddr { if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None } } + #[rustdoc_skip_body] fn address(&self) -> AddressKind<'_> { let len = self.len as usize - SUN_PATH_OFFSET; let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; @@ -281,6 +285,7 @@ impl linux_ext::addr::SocketAddrExt for SocketAddr { if let AddressKind::Abstract(name) = self.address() { Some(name.as_bytes()) } else { None } } + #[rustdoc_skip_body] fn from_abstract_name(name: N) -> io::Result where N: AsRef<[u8]>, diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs index bdf0384e34f80..acd564eb9c157 100644 --- a/library/std/src/os/unix/net/ancillary.rs +++ b/library/std/src/os/unix/net/ancillary.rs @@ -2,6 +2,7 @@ use super::{SocketAddr, sockaddr_un}; use crate::io::{self, IoSlice, IoSliceMut}; +use crate::macros::rustdoc_skip_body; use crate::marker::PhantomData; use crate::mem::zeroed; use crate::os::unix::io::RawFd; @@ -30,6 +31,7 @@ mod libc { pub type uid_t = u32; } +#[rustdoc_skip_body] pub(super) fn recv_vectored_with_ancillary_from( socket: &Socket, bufs: &mut [IoSliceMut<'_>], @@ -60,6 +62,7 @@ pub(super) fn recv_vectored_with_ancillary_from( } } +#[rustdoc_skip_body] pub(super) fn send_vectored_with_ancillary_to( socket: &Socket, path: Option<&Path>, @@ -87,6 +90,7 @@ pub(super) fn send_vectored_with_ancillary_to( } } +#[rustdoc_skip_body] fn add_to_ancillary_data( buffer: &mut [u8], length: &mut usize, @@ -503,6 +507,7 @@ impl<'a> AncillaryData<'a> { AncillaryData::ScmCredentials(scm_credentials) } + #[rustdoc_skip_body] fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Result { unsafe { let cmsg_len_zero = libc::CMSG_LEN(0) as usize; @@ -543,6 +548,7 @@ pub struct Messages<'a> { impl<'a> Iterator for Messages<'a> { type Item = Result, AncillaryError>; + #[rustdoc_skip_body] fn next(&mut self) -> Option { unsafe { let mut msg: libc::msghdr = zeroed(); diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index 309f80f7923b2..901263a7aa123 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -19,6 +19,7 @@ use super::{SocketAddr, sockaddr_un}; use super::{SocketAncillary, recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to}; #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "cygwin"))] use crate::io::{IoSlice, IoSliceMut}; +use crate::macros::rustdoc_skip_body; use crate::net::Shutdown; use crate::os::unix::io::{ AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd, unsafe_impl_fd_asrefs, @@ -298,6 +299,7 @@ impl UnixDatagram { /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] + #[rustdoc_skip_body] pub fn local_addr(&self) -> io::Result { SocketAddr::new(|addr, len| unsafe { libc::getsockname(self.as_raw_fd(), addr, len) }) } @@ -323,6 +325,7 @@ impl UnixDatagram { /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] + #[rustdoc_skip_body] pub fn peer_addr(&self) -> io::Result { SocketAddr::new(|addr, len| unsafe { libc::getpeername(self.as_raw_fd(), addr, len) }) } @@ -602,6 +605,7 @@ impl UnixDatagram { /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] + #[rustdoc_skip_body] pub fn send(&self, buf: &[u8]) -> io::Result { self.0.write(buf) } @@ -743,6 +747,7 @@ impl UnixDatagram { /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] + #[rustdoc_skip_body] pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { self.0.set_timeout(timeout, libc::SO_RCVTIMEO) } @@ -789,6 +794,7 @@ impl UnixDatagram { /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] + #[rustdoc_skip_body] pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { self.0.set_timeout(timeout, libc::SO_SNDTIMEO) } @@ -811,6 +817,7 @@ impl UnixDatagram { /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] + #[rustdoc_skip_body] pub fn read_timeout(&self) -> io::Result> { self.0.timeout(libc::SO_RCVTIMEO) } @@ -833,6 +840,7 @@ impl UnixDatagram { /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] + #[rustdoc_skip_body] pub fn write_timeout(&self) -> io::Result> { self.0.timeout(libc::SO_SNDTIMEO) } @@ -877,6 +885,7 @@ impl UnixDatagram { /// ``` #[cfg(any(doc, target_os = "linux", target_os = "freebsd", target_os = "openbsd",))] #[unstable(feature = "unix_set_mark", issue = "96467")] + #[rustdoc_skip_body] pub fn set_mark(&self, mark: u32) -> io::Result<()> { self.0.set_mark(mark) } @@ -980,6 +989,7 @@ impl UnixDatagram { /// } /// ``` #[unstable(feature = "unix_socket_peek", issue = "76923")] + #[rustdoc_skip_body] pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { self.recv_from_flags(buf, libc::MSG_PEEK) } @@ -988,6 +998,7 @@ impl UnixDatagram { #[stable(feature = "unix_socket", since = "1.10.0")] impl AsRawFd for UnixDatagram { #[inline] + #[rustdoc_skip_body] fn as_raw_fd(&self) -> RawFd { self.0.as_inner().as_raw_fd() } @@ -996,6 +1007,7 @@ impl AsRawFd for UnixDatagram { #[stable(feature = "unix_socket", since = "1.10.0")] impl FromRawFd for UnixDatagram { #[inline] + #[rustdoc_skip_body] unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram { UnixDatagram(Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd)))) } @@ -1004,6 +1016,7 @@ impl FromRawFd for UnixDatagram { #[stable(feature = "unix_socket", since = "1.10.0")] impl IntoRawFd for UnixDatagram { #[inline] + #[rustdoc_skip_body] fn into_raw_fd(self) -> RawFd { self.0.into_inner().into_inner().into_raw_fd() } @@ -1012,6 +1025,7 @@ impl IntoRawFd for UnixDatagram { #[stable(feature = "io_safety", since = "1.63.0")] impl AsFd for UnixDatagram { #[inline] + #[rustdoc_skip_body] fn as_fd(&self) -> BorrowedFd<'_> { self.0.as_inner().as_fd() } diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index 713ad2944a8cb..cc0bcdf9e614c 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -1,4 +1,5 @@ use super::{SocketAddr, UnixStream, sockaddr_un}; +use crate::macros::rustdoc_skip_body; use crate::os::unix::io::{ AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd, unsafe_impl_fd_asrefs, }; @@ -225,6 +226,7 @@ impl UnixListener { /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] + #[rustdoc_skip_body] pub fn local_addr(&self) -> io::Result { SocketAddr::new(|addr, len| unsafe { libc::getsockname(self.as_raw_fd(), addr, len) }) } @@ -320,6 +322,7 @@ impl UnixListener { #[stable(feature = "unix_socket", since = "1.10.0")] impl AsRawFd for UnixListener { #[inline] + #[rustdoc_skip_body] fn as_raw_fd(&self) -> RawFd { self.0.as_inner().as_raw_fd() } @@ -328,6 +331,7 @@ impl AsRawFd for UnixListener { #[stable(feature = "unix_socket", since = "1.10.0")] impl FromRawFd for UnixListener { #[inline] + #[rustdoc_skip_body] unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { UnixListener(Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd)))) } @@ -336,6 +340,7 @@ impl FromRawFd for UnixListener { #[stable(feature = "unix_socket", since = "1.10.0")] impl IntoRawFd for UnixListener { #[inline] + #[rustdoc_skip_body] fn into_raw_fd(self) -> RawFd { self.0.into_inner().into_inner().into_raw_fd() } @@ -344,6 +349,7 @@ impl IntoRawFd for UnixListener { #[stable(feature = "io_safety", since = "1.63.0")] impl AsFd for UnixListener { #[inline] + #[rustdoc_skip_body] fn as_fd(&self) -> BorrowedFd<'_> { self.0.as_inner().as_fd() } @@ -352,6 +358,7 @@ impl AsFd for UnixListener { #[stable(feature = "io_safety", since = "1.63.0")] impl From for UnixListener { #[inline] + #[rustdoc_skip_body] fn from(fd: OwnedFd) -> UnixListener { UnixListener(Socket::from_inner(FromInner::from_inner(fd))) } @@ -366,6 +373,7 @@ unsafe_impl_fd_asrefs!(UnixListener); impl From for OwnedFd { /// Takes ownership of a [`UnixListener`]'s socket file descriptor. #[inline] + #[rustdoc_skip_body] fn from(listener: UnixListener) -> OwnedFd { listener.0.into_inner().into_inner() } diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index 00c3e75592ee2..3ad76f77aa475 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -39,6 +39,7 @@ use super::{SocketAncillary, recv_vectored_with_ancillary_from, send_vectored_wi use super::{UCred, peer_cred}; use crate::fmt; use crate::io::{self, IoSlice, IoSliceMut}; +use crate::macros::rustdoc_skip_body; use crate::net::Shutdown; use crate::os::unix::io::{ AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd, unsafe_impl_fd_asrefs, @@ -225,6 +226,7 @@ impl UnixStream { /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] + #[rustdoc_skip_body] pub fn local_addr(&self) -> io::Result { SocketAddr::new(|addr, len| unsafe { libc::getsockname(self.as_raw_fd(), addr, len) }) } @@ -244,6 +246,7 @@ impl UnixStream { /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] + #[rustdoc_skip_body] pub fn peer_addr(&self) -> io::Result { SocketAddr::new(|addr, len| unsafe { libc::getpeername(self.as_raw_fd(), addr, len) }) } @@ -320,6 +323,7 @@ impl UnixStream { /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] + #[rustdoc_skip_body] pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { self.0.set_timeout(timeout, libc::SO_RCVTIMEO) } @@ -365,6 +369,7 @@ impl UnixStream { /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] + #[rustdoc_skip_body] pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { self.0.set_timeout(timeout, libc::SO_SNDTIMEO) } @@ -386,6 +391,7 @@ impl UnixStream { /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] + #[rustdoc_skip_body] pub fn read_timeout(&self) -> io::Result> { self.0.timeout(libc::SO_RCVTIMEO) } @@ -408,6 +414,7 @@ impl UnixStream { /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] + #[rustdoc_skip_body] pub fn write_timeout(&self) -> io::Result> { self.0.timeout(libc::SO_SNDTIMEO) } @@ -452,6 +459,7 @@ impl UnixStream { /// ``` #[cfg(any(doc, target_os = "linux", target_os = "freebsd", target_os = "openbsd",))] #[unstable(feature = "unix_set_mark", issue = "96467")] + #[rustdoc_skip_body] pub fn set_mark(&self, mark: u32) -> io::Result<()> { self.0.set_mark(mark) } @@ -696,6 +704,7 @@ impl io::Write for UnixStream { #[stable(feature = "unix_socket", since = "1.10.0")] impl<'a> io::Write for &'a UnixStream { + #[rustdoc_skip_body] fn write(&mut self, buf: &[u8]) -> io::Result { self.0.send_with_flags(buf, MSG_NOSIGNAL) } @@ -718,6 +727,7 @@ impl<'a> io::Write for &'a UnixStream { #[stable(feature = "unix_socket", since = "1.10.0")] impl AsRawFd for UnixStream { #[inline] + #[rustdoc_skip_body] fn as_raw_fd(&self) -> RawFd { self.0.as_raw_fd() } @@ -726,6 +736,7 @@ impl AsRawFd for UnixStream { #[stable(feature = "unix_socket", since = "1.10.0")] impl FromRawFd for UnixStream { #[inline] + #[rustdoc_skip_body] unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { UnixStream(Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd)))) } @@ -734,6 +745,7 @@ impl FromRawFd for UnixStream { #[stable(feature = "unix_socket", since = "1.10.0")] impl IntoRawFd for UnixStream { #[inline] + #[rustdoc_skip_body] fn into_raw_fd(self) -> RawFd { self.0.into_raw_fd() } @@ -742,6 +754,7 @@ impl IntoRawFd for UnixStream { #[stable(feature = "io_safety", since = "1.63.0")] impl AsFd for UnixStream { #[inline] + #[rustdoc_skip_body] fn as_fd(&self) -> BorrowedFd<'_> { self.0.as_fd() } diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index edd7d8dfb092d..1aa6076f3a7ed 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -5,6 +5,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::ffi::OsStr; +use crate::macros::rustdoc_skip_body; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::path::Path; #[cfg(doc)] @@ -252,21 +253,25 @@ pub impl(self) trait CommandExt { #[stable(feature = "rust1", since = "1.0.0")] impl CommandExt for process::Command { + #[rustdoc_skip_body] fn uid(&mut self, id: UserId) -> &mut process::Command { self.as_inner_mut().uid(id); self } + #[rustdoc_skip_body] fn gid(&mut self, id: GroupId) -> &mut process::Command { self.as_inner_mut().gid(id); self } + #[rustdoc_skip_body] fn groups(&mut self, groups: &[GroupId]) -> &mut process::Command { self.as_inner_mut().groups(groups); self } + #[rustdoc_skip_body] unsafe fn pre_exec(&mut self, f: F) -> &mut process::Command where F: FnMut() -> io::Result<()> + Send + Sync + 'static, @@ -275,12 +280,14 @@ impl CommandExt for process::Command { self } + #[rustdoc_skip_body] fn exec(&mut self) -> io::Error { // NOTE: This may *not* be safe to call after `libc::fork`, because it // may allocate. That may be worth fixing at some point in the future. self.as_inner_mut().exec(sys::process::Stdio::Inherit) } + #[rustdoc_skip_body] fn arg0(&mut self, arg: S) -> &mut process::Command where S: AsRef, @@ -289,16 +296,19 @@ impl CommandExt for process::Command { self } + #[rustdoc_skip_body] fn process_group(&mut self, pgroup: i32) -> &mut process::Command { self.as_inner_mut().pgroup(pgroup); self } + #[rustdoc_skip_body] fn chroot>(&mut self, dir: P) -> &mut process::Command { self.as_inner_mut().chroot(dir.as_ref()); self } + #[rustdoc_skip_body] fn setsid(&mut self, setsid: bool) -> &mut process::Command { self.as_inner_mut().setsid(setsid); self @@ -443,26 +453,32 @@ pub impl(self) trait ExitStatusExt { #[stable(feature = "rust1", since = "1.0.0")] impl ExitStatusExt for process::ExitStatus { + #[rustdoc_skip_body] fn from_raw(raw: i32) -> Self { process::ExitStatus::from_inner(From::from(raw)) } + #[rustdoc_skip_body] fn signal(&self) -> Option { self.as_inner().signal() } + #[rustdoc_skip_body] fn core_dumped(&self) -> bool { self.as_inner().core_dumped() } + #[rustdoc_skip_body] fn stopped_signal(&self) -> Option { self.as_inner().stopped_signal() } + #[rustdoc_skip_body] fn continued(&self) -> bool { self.as_inner().continued() } + #[rustdoc_skip_body] fn into_raw(self) -> i32 { self.as_inner().into_raw().into() } @@ -594,15 +610,18 @@ pub impl(self) trait ChildExt { #[unstable(feature = "unix_send_signal", issue = "141975")] impl ChildExt for process::Child { + #[rustdoc_skip_body] fn send_signal(&self, signal: i32) -> io::Result<()> { self.handle.send_signal(signal) } + #[rustdoc_skip_body] fn send_process_group_signal(&self, signal: i32) -> io::Result<()> { self.handle.send_process_group_signal(signal) } #[cfg(not(target_os = "espidf"))] + #[rustdoc_skip_body] fn kill_process_group(&mut self) -> io::Result<()> { self.handle.send_process_group_signal(libc::SIGKILL) } @@ -619,6 +638,7 @@ impl ChildExt for process::Child { #[stable(feature = "process_extensions", since = "1.2.0")] impl FromRawFd for process::Stdio { #[inline] + #[rustdoc_skip_body] unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio { let fd = sys::fd::FileDesc::from_raw_fd(fd); let io = sys::process::Stdio::Fd(fd); @@ -631,6 +651,7 @@ impl From for process::Stdio { /// Takes ownership of a file descriptor and returns a [`Stdio`](process::Stdio) /// that can attach a stream to it. #[inline] + #[rustdoc_skip_body] fn from(fd: OwnedFd) -> process::Stdio { let fd = sys::fd::FileDesc::from_inner(fd); let io = sys::process::Stdio::Fd(fd); @@ -641,6 +662,7 @@ impl From for process::Stdio { #[stable(feature = "process_extensions", since = "1.2.0")] impl AsRawFd for process::ChildStdin { #[inline] + #[rustdoc_skip_body] fn as_raw_fd(&self) -> RawFd { self.as_inner().as_raw_fd() } @@ -649,6 +671,7 @@ impl AsRawFd for process::ChildStdin { #[stable(feature = "process_extensions", since = "1.2.0")] impl AsRawFd for process::ChildStdout { #[inline] + #[rustdoc_skip_body] fn as_raw_fd(&self) -> RawFd { self.as_inner().as_raw_fd() } @@ -657,6 +680,7 @@ impl AsRawFd for process::ChildStdout { #[stable(feature = "process_extensions", since = "1.2.0")] impl AsRawFd for process::ChildStderr { #[inline] + #[rustdoc_skip_body] fn as_raw_fd(&self) -> RawFd { self.as_inner().as_raw_fd() } @@ -665,6 +689,7 @@ impl AsRawFd for process::ChildStderr { #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawFd for process::ChildStdin { #[inline] + #[rustdoc_skip_body] fn into_raw_fd(self) -> RawFd { self.into_inner().into_inner().into_raw_fd() } @@ -673,6 +698,7 @@ impl IntoRawFd for process::ChildStdin { #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawFd for process::ChildStdout { #[inline] + #[rustdoc_skip_body] fn into_raw_fd(self) -> RawFd { self.into_inner().into_inner().into_raw_fd() } @@ -681,6 +707,7 @@ impl IntoRawFd for process::ChildStdout { #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawFd for process::ChildStderr { #[inline] + #[rustdoc_skip_body] fn into_raw_fd(self) -> RawFd { self.into_inner().into_inner().into_raw_fd() } @@ -689,6 +716,7 @@ impl IntoRawFd for process::ChildStderr { #[stable(feature = "io_safety", since = "1.63.0")] impl AsFd for crate::process::ChildStdin { #[inline] + #[rustdoc_skip_body] fn as_fd(&self) -> BorrowedFd<'_> { self.as_inner().as_fd() } @@ -698,6 +726,7 @@ impl AsFd for crate::process::ChildStdin { impl From for OwnedFd { /// Takes ownership of a [`ChildStdin`](crate::process::ChildStdin)'s file descriptor. #[inline] + #[rustdoc_skip_body] fn from(child_stdin: crate::process::ChildStdin) -> OwnedFd { child_stdin.into_inner().into_inner() } @@ -710,6 +739,7 @@ impl From for OwnedFd { #[stable(feature = "child_stream_from_fd", since = "1.74.0")] impl From for process::ChildStdin { #[inline] + #[rustdoc_skip_body] fn from(fd: OwnedFd) -> process::ChildStdin { let pipe = ChildPipe::from_inner(fd); process::ChildStdin::from_inner(pipe) @@ -719,6 +749,7 @@ impl From for process::ChildStdin { #[stable(feature = "io_safety", since = "1.63.0")] impl AsFd for crate::process::ChildStdout { #[inline] + #[rustdoc_skip_body] fn as_fd(&self) -> BorrowedFd<'_> { self.as_inner().as_fd() } @@ -728,6 +759,7 @@ impl AsFd for crate::process::ChildStdout { impl From for OwnedFd { /// Takes ownership of a [`ChildStdout`](crate::process::ChildStdout)'s file descriptor. #[inline] + #[rustdoc_skip_body] fn from(child_stdout: crate::process::ChildStdout) -> OwnedFd { child_stdout.into_inner().into_inner() } @@ -740,6 +772,7 @@ impl From for OwnedFd { #[stable(feature = "child_stream_from_fd", since = "1.74.0")] impl From for process::ChildStdout { #[inline] + #[rustdoc_skip_body] fn from(fd: OwnedFd) -> process::ChildStdout { let pipe = ChildPipe::from_inner(fd); process::ChildStdout::from_inner(pipe) @@ -749,6 +782,7 @@ impl From for process::ChildStdout { #[stable(feature = "io_safety", since = "1.63.0")] impl AsFd for crate::process::ChildStderr { #[inline] + #[rustdoc_skip_body] fn as_fd(&self) -> BorrowedFd<'_> { self.as_inner().as_fd() } @@ -758,6 +792,7 @@ impl AsFd for crate::process::ChildStderr { impl From for OwnedFd { /// Takes ownership of a [`ChildStderr`](crate::process::ChildStderr)'s file descriptor. #[inline] + #[rustdoc_skip_body] fn from(child_stderr: crate::process::ChildStderr) -> OwnedFd { child_stderr.into_inner().into_inner() } @@ -770,6 +805,7 @@ impl From for OwnedFd { #[stable(feature = "child_stream_from_fd", since = "1.74.0")] impl From for process::ChildStderr { #[inline] + #[rustdoc_skip_body] fn from(fd: OwnedFd) -> process::ChildStderr { let pipe = ChildPipe::from_inner(fd); process::ChildStderr::from_inner(pipe) diff --git a/library/std/src/os/unix/thread.rs b/library/std/src/os/unix/thread.rs index c19ccaf742da9..f022b01056615 100644 --- a/library/std/src/os/unix/thread.rs +++ b/library/std/src/os/unix/thread.rs @@ -4,6 +4,7 @@ #![stable(feature = "thread_extensions", since = "1.9.0")] +use crate::macros::rustdoc_skip_body; #[allow(deprecated)] use crate::os::unix::raw::pthread_t; use crate::sys::{AsInner, IntoInner}; @@ -35,11 +36,13 @@ impl JoinHandleExt for JoinHandle { // is an integer but libc::pthread_t is a pointer. Exposed provenance is the // safe choice here, but `as` also works when it's int2int or ptr2ptr. #[allow(implicit_provenance_casts)] + #[rustdoc_skip_body] fn as_pthread_t(&self) -> RawPthread { self.as_inner().id() as RawPthread } #[allow(implicit_provenance_casts)] // see above for why + #[rustdoc_skip_body] fn into_pthread_t(self) -> RawPthread { self.into_inner().into_id() as RawPthread } diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs index 811ab7ea8480b..0d64cefec2ea3 100644 --- a/library/std/src/os/wasi/fs.rs +++ b/library/std/src/os/wasi/fs.rs @@ -233,6 +233,7 @@ impl FileExt for File { self.as_inner().read_buf_at(buf, offset) } + #[rustdoc_skip_body] fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { self.as_inner().read_vectored_at(bufs, offset) } @@ -241,6 +242,7 @@ impl FileExt for File { self.as_inner().write_at(buf, offset) } + #[rustdoc_skip_body] fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { self.as_inner().write_vectored_at(bufs, offset) } @@ -317,6 +319,7 @@ pub trait OpenOptionsExt { } impl OpenOptionsExt for OpenOptions { + #[rustdoc_skip_body] fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions { self.as_inner_mut().custom_flags(flags); self @@ -383,6 +386,7 @@ pub trait DirEntryExt { } impl DirEntryExt for fs::DirEntry { + #[rustdoc_skip_body] fn ino(&self) -> u64 { self.as_inner().ino() } From 1a3a14c34b6bc7341143bdc6192947bcd2fc1b69 Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Mon, 26 Oct 2026 16:51:41 +0800 Subject: [PATCH 35/49] latest rebase Signed-off-by: Richard Tjokroutomo --- compiler/rustc_ast_lowering/src/contract.rs | 38 +++++++-------------- compiler/rustc_ast_lowering/src/expr.rs | 15 +++----- compiler/rustc_ast_lowering/src/path.rs | 10 ++++-- 3 files changed, 25 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/contract.rs b/compiler/rustc_ast_lowering/src/contract.rs index 5c7cbf6f79305..9ceec41533d8e 100644 --- a/compiler/rustc_ast_lowering/src/contract.rs +++ b/compiler/rustc_ast_lowering/src/contract.rs @@ -1,7 +1,6 @@ use std::sync::Arc; use rustc_attr_ir::lang_items::LangItem; -use rustc_attr_ir::target::{AstTarget, Target}; use rustc_span::sym; use crate::LoweringContext; @@ -61,12 +60,8 @@ impl<'hir> LoweringContext<'_, 'hir> { postcond_checker, ); - let wrapped_body = self.wrap_body_with_contract_check( - body, - contract_check, - postcond_checker.span, - ens, - ); + let wrapped_body = + self.wrap_body_with_contract_check(body, contract_check, postcond_checker.span); self.expr_block(wrapped_body) } (None, Some(ens)) => { @@ -95,12 +90,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let contract_check = self.lower_contract_check_with_postcond(contract_decls, None, postcond_checker); - let wrapped_body = self.wrap_body_with_contract_check( - body, - contract_check, - postcond_checker.span, - ens, - ); + let wrapped_body = + self.wrap_body_with_contract_check(body, contract_check, postcond_checker.span); self.expr_block(wrapped_body) } (Some(req), None) => { @@ -245,7 +236,6 @@ impl<'hir> LoweringContext<'_, 'hir> { body: impl FnOnce(&mut Self) -> rustc_hir::Expr<'hir>, contract_check: &'hir rustc_hir::Expr<'hir>, postcond_span: rustc_span::Span, - ast_expr: &rustc_ast::Expr, ) -> &'hir rustc_hir::Block<'hir> { let check_ident: rustc_span::Ident = rustc_span::Ident::new(sym::__ensures_checker, postcond_span); @@ -274,8 +264,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let body = self.arena.alloc(body(self)); // Finally, inject an ensures check on the implicit return of the body. - let body = - self.inject_ensures_check(body, postcond_span, check_ident, check_hir_id, ast_expr); + let body = self.inject_ensures_check(body, postcond_span, check_ident, check_hir_id); // Flatten the body into precond, then postcond, then wrapped body. let wrapped_body = self.block_all( @@ -291,16 +280,14 @@ impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn checked_return( &mut self, opt_expr: Option<&'hir rustc_hir::Expr<'hir>>, - ast_expr: &rustc_ast::Expr, ) -> rustc_hir::ExprKind<'hir> { - let checked_ret = if let Some((check_span, check_ident, check_hir_id)) = - self.contract_ensures - { - let expr = opt_expr.unwrap_or_else(|| self.expr_unit(check_span)); - Some(self.inject_ensures_check(expr, check_span, check_ident, check_hir_id, ast_expr)) - } else { - opt_expr - }; + let checked_ret = + if let Some((check_span, check_ident, check_hir_id)) = self.contract_ensures { + let expr = opt_expr.unwrap_or_else(|| self.expr_unit(check_span)); + Some(self.inject_ensures_check(expr, check_span, check_ident, check_hir_id)) + } else { + opt_expr + }; rustc_hir::ExprKind::Ret(checked_ret) } @@ -311,7 +298,6 @@ impl<'hir> LoweringContext<'_, 'hir> { span: rustc_span::Span, cond_ident: rustc_span::Ident, cond_hir_id: rustc_hir::HirId, - ast_expr: &rustc_ast::Expr, ) -> &'hir rustc_hir::Expr<'hir> { // { // let ret = { body }; diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 7ab08ebade496..d4328d75faad3 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -494,9 +494,9 @@ impl<'hir> LoweringContext<'_, 'hir> { } ExprKind::Ret(box_e) => { let expr = box_e.as_ref().map(|x| self.lower_expr(x)); - self.checked_return(expr, e) + self.checked_return(expr) } - ExprKind::Yeet(sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref(), e), + ExprKind::Yeet(sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref()), ExprKind::Become(sub_expr) => { let sub_expr = self.lower_expr(sub_expr); hir::ExprKind::Become(sub_expr) @@ -2027,7 +2027,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ), )) } else { - let ret_expr = self.checked_return(Some(from_residual_expr), sub_expr); + let ret_expr = self.checked_return(Some(from_residual_expr)); self.arena.alloc(self.expr(try_span, ret_expr)) }; @@ -2051,12 +2051,7 @@ impl<'hir> LoweringContext<'_, 'hir> { /// ``` /// But to simplify this, there's a `from_yeet` lang item function which /// handles the combined `FromResidual::from_residual(Yeet(residual))`. - fn lower_expr_yeet( - &mut self, - span: Span, - sub_expr: Option<&Expr>, - ast_expr: &rustc_ast::Expr, - ) -> hir::ExprKind<'hir> { + fn lower_expr_yeet(&mut self, span: Span, sub_expr: Option<&Expr>) -> hir::ExprKind<'hir> { // The expression (if present) or `()` otherwise. let (yeeted_span, yeeted_expr) = if let Some(sub_expr) = sub_expr { (sub_expr.span, self.lower_expr(sub_expr)) @@ -2084,7 +2079,7 @@ impl<'hir> LoweringContext<'_, 'hir> { Some(from_yeet_expr), ) } - TryBlockScope::Function => self.checked_return(Some(from_yeet_expr), ast_expr), + TryBlockScope::Function => self.checked_return(Some(from_yeet_expr)), } } diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index f410a9d280347..0dfd0f10f920e 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use rustc_ast::{self as ast, *}; -use rustc_attr_ir::target::Target; +use rustc_attr_ir::target::{AstTarget, Target}; use rustc_errors::StashKey; use rustc_hir::def::{DefKind, PerNS, Res}; use rustc_hir::def_id::DefId; @@ -523,7 +523,13 @@ impl<'hir> LoweringContext<'_, 'hir> { // FIXME uses the segments HIR id which is not correct, it should // be the parameters HIR id instead. This is currently not lowered. for input in inputs { - self.lower_attrs(segment_hir_id, &input.attrs, input.span, Target::Param); + self.lower_attrs( + segment_hir_id, + &input.attrs, + input.span, + Target::Param, + AstTarget::Param(input), + ); } let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| { From c96cf939da4f3939239cce5d83278108fd1dd3ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 26 Oct 2026 12:15:26 +0100 Subject: [PATCH 36/49] Normalize Windows path separators in bootstrap snapshots --- src/bootstrap/src/core/builder/cli_paths/tests.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/builder/cli_paths/tests.rs b/src/bootstrap/src/core/builder/cli_paths/tests.rs index ce07ee9e807eb..6432836a09565 100644 --- a/src/bootstrap/src/core/builder/cli_paths/tests.rs +++ b/src/bootstrap/src/core/builder/cli_paths/tests.rs @@ -61,13 +61,14 @@ fn render_steps_for_cli_args(args_str: &str) -> String { fn snapshot_test_inner(name: &str, args_str: &str) { let name = Path::new("snapshots").join(format!("{name}.snap")); let steps = render_steps_for_cli_args(args_str); - let file = file!(); + // Normalize Windows path separators + let file = file!().replace("\\", "/"); let content = format!( r"--- source: {file} expression: {args_str} --- -{steps}" +{steps}", ); expect_test::expect_file![name].assert_eq(&content); } From 3e63be17b1dc7ac5ab74e5e07aeed33e64f9682e Mon Sep 17 00:00:00 2001 From: Eva van Houten Date: Sat, 22 Aug 2026 14:35:23 +0200 Subject: [PATCH 37/49] Replace check_attr_crate_level with check_target --- .../rustc_attr_parsing/src/attributes/doc.rs | 35 ++++++++----------- .../rustc_attr_parsing/src/diagnostics.rs | 7 ---- 2 files changed, 15 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 7dc5c6ce9f2b8..44f9a1b44b8ed 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -14,8 +14,8 @@ use super::prelude::{ALL_TARGETS, AllowedTargets}; use super::{AcceptMapping, AttributeParser, template}; use crate::context::{AcceptContext, FinalizeContext}; use crate::diagnostics::{ - AttrCrateLevelOnly, DocAliasBadChar, DocAliasDuplicated, DocAliasEmpty, DocAliasMalformed, - DocAliasStartEnd, DocAttrNotCrateLevel, DocAttributeNotAttribute, DocAutoCfgExpectsHideOrShow, + DocAliasBadChar, DocAliasDuplicated, DocAliasEmpty, DocAliasMalformed, DocAliasStartEnd, + DocAttrNotCrateLevel, DocAttributeNotAttribute, DocAutoCfgExpectsHideOrShow, DocAutoCfgHideShowExpectsList, DocAutoCfgHideShowNoIdentBeforeValues, DocAutoCfgHideShowUnexpectedItem, DocAutoCfgHideShowUnexpectedItemAfterValues, DocAutoCfgHideShowValuesMix, DocAutoCfgWrongLiteral, DocInlineConflict, DocInlineOnlyUse, @@ -26,6 +26,7 @@ use crate::diagnostics::{ use crate::parser::{ ArgParser, MetaItemListParser, MetaItemOrLitParser, MetaItemParser, OwnedPathParser, }; +use crate::target_checking::Policy::Allow; fn check_keyword(cx: &mut AcceptContext<'_, '_>, keyword: Symbol, span: Span) -> bool { // FIXME: Once rustdoc can handle URL conflicts on case insensitive file systems, we @@ -63,15 +64,6 @@ fn check_attr_not_crate_level( true } -/// Checks that an attribute is used at the crate level. Returns `true` if valid. -fn check_attr_crate_level(cx: &mut AcceptContext<'_, '_>, span: Span) -> bool { - if cx.shared.target != Target::Crate { - cx.emit_lint(INVALID_DOC_ATTRIBUTES, AttrCrateLevelOnly, span); - return false; - } - true -} - // FIXME: To be removed once merged and replace with `cx.expected_name_value(span, _name)`. fn expected_name_value(cx: &mut AcceptContext<'_, '_>, span: Span, _name: Option) { cx.emit_lint(INVALID_DOC_ATTRIBUTES, ExpectedNameValue, span); @@ -163,9 +155,10 @@ impl DocParser { return; } - if !check_attr_crate_level(cx, path.span()) { - return; - } + cx.check_target( + &sym::no_crate_inject.to_string(), + &AllowedTargets::AllowList(&[Allow(Target::Crate)]), + ); self.attribute.no_crate_inject = Some(path.span()) } @@ -552,9 +545,10 @@ impl DocParser { return; } let span = path.span(); - if !check_attr_crate_level(cx, span) { - return; - } + cx.check_target( + concat!("(", stringify!($ident), ")"), + &AllowedTargets::AllowList(&[Allow(Target::Crate)]), + ); self.attribute.$ident = Some(span); }}; } @@ -570,9 +564,10 @@ impl DocParser { return; }; - if !check_attr_crate_level(cx, path.span()) { - return; - } + cx.check_target( + &s.to_string(), + &AllowedTargets::AllowList(&[Allow(Target::Crate)]), + ); // FIXME: It's errorring when the attribute is passed multiple times on the command // line. diff --git a/compiler/rustc_attr_parsing/src/diagnostics.rs b/compiler/rustc_attr_parsing/src/diagnostics.rs index b5bfbc9e3dc3b..9aee8725b3a88 100644 --- a/compiler/rustc_attr_parsing/src/diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/diagnostics.rs @@ -320,13 +320,6 @@ pub(crate) struct DocTestUnknown { #[diag("`#![doc(test(...)]` does not take a literal")] pub(crate) struct DocTestLiteral; -#[derive(Diagnostic)] -#[diag("this attribute can only be applied at the crate level")] -#[note( - "read for more information" -)] -pub(crate) struct AttrCrateLevelOnly; - #[derive(Diagnostic)] #[diag("conflicting doc inlining attributes")] #[help("remove one of the conflicting attributes")] From 8ec63ba5b9a24b36aefac29576929dc512e3a496 Mon Sep 17 00:00:00 2001 From: Eva van Houten Date: Fri, 28 Aug 2026 14:13:43 +0200 Subject: [PATCH 38/49] Fix string casting --- compiler/rustc_attr_parsing/src/attributes/doc.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 44f9a1b44b8ed..395922f1208b2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -156,7 +156,7 @@ impl DocParser { } cx.check_target( - &sym::no_crate_inject.to_string(), + sym::no_crate_inject.as_str(), &AllowedTargets::AllowList(&[Allow(Target::Crate)]), ); @@ -564,10 +564,7 @@ impl DocParser { return; }; - cx.check_target( - &s.to_string(), - &AllowedTargets::AllowList(&[Allow(Target::Crate)]), - ); + cx.check_target(s.as_str(), &AllowedTargets::AllowList(&[Allow(Target::Crate)])); // FIXME: It's errorring when the attribute is passed multiple times on the command // line. From 4842ce98a3245bceb49953c33eadc3e647dd0fc1 Mon Sep 17 00:00:00 2001 From: Eva van Houten Date: Fri, 28 Aug 2026 14:33:47 +0200 Subject: [PATCH 39/49] Add test for doc attr crate-level target checks --- tests/ui/attributes/doc-crate-level.rs | 43 +++++ tests/ui/attributes/doc-crate-level.stderr | 204 +++++++++++++++++++++ 2 files changed, 247 insertions(+) create mode 100644 tests/ui/attributes/doc-crate-level.rs create mode 100644 tests/ui/attributes/doc-crate-level.stderr diff --git a/tests/ui/attributes/doc-crate-level.rs b/tests/ui/attributes/doc-crate-level.rs new file mode 100644 index 0000000000000..89d934a5dd257 --- /dev/null +++ b/tests/ui/attributes/doc-crate-level.rs @@ -0,0 +1,43 @@ +#![feature(rustdoc_internals)] +#![doc(fake_variadic)] +//~^ ERROR `#![doc(fake_variadic = "...")]` isn't allowed as a crate-level attribute +#![doc(alias = "test")] +//~^ ERROR `#![doc(alias = "...")]` isn't allowed as a crate-level attribute +#![doc(search_unbox)] +//~^ ERROR `#![doc(search_unbox = "...")]` isn't allowed as a crate-level attribute + +#[doc(rust_logo)] +//~^ ERROR crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` +#[doc(html_favicon_url = "example.org")] +//~^ ERROR crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` +#[doc(html_logo_url = "example.org")] +//~^ ERROR crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` +#[doc(html_playground_url = "example.org")] +//~^ ERROR crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` +#[doc(issue_tracker_base_url = "example.org")] +//~^ ERROR crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` +#[doc(html_root_url = "example.org")] +//~^ ERROR crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` +#[doc(html_no_source)] +//~^ ERROR crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` +#[doc(test(no_crate_inject))] +//~^ ERROR crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` +fn function() {} + +#![doc(rust_logo)] +//~^ ERROR an inner attribute is not permitted in this context +#![doc(html_favicon_url = "example.org")] +//~^ ERROR an inner attribute is not permitted in this context +#![doc(html_logo_url = "example.org")] +//~^ ERROR an inner attribute is not permitted in this context +#![doc(html_playground_url = "example.org")] +//~^ ERROR an inner attribute is not permitted in this context +#![doc(issue_tracker_base_url = "example.org")] +//~^ ERROR an inner attribute is not permitted in this context +#![doc(html_root_url = "example.org")] +//~^ ERROR an inner attribute is not permitted in this context +#![doc(html_no_source)] +//~^ ERROR an inner attribute is not permitted in this context +#![doc(test(no_crate_inject))] +//~^ ERROR an inner attribute is not permitted in this context +fn main() {} diff --git a/tests/ui/attributes/doc-crate-level.stderr b/tests/ui/attributes/doc-crate-level.stderr new file mode 100644 index 0000000000000..5f5b853e5fd4e --- /dev/null +++ b/tests/ui/attributes/doc-crate-level.stderr @@ -0,0 +1,204 @@ +error: an inner attribute is not permitted in this context + --> $DIR/doc-crate-level.rs:27:1 + | +LL | #![doc(rust_logo)] + | ^^^^^^^^^^^^^^^^^^ +... +LL | fn main() {} + | ------------ the inner attribute doesn't annotate this function + | + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + +error: an inner attribute is not permitted in this context + --> $DIR/doc-crate-level.rs:29:1 + | +LL | #![doc(html_favicon_url = "example.org")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn main() {} + | ------------ the inner attribute doesn't annotate this function + | + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + +error: an inner attribute is not permitted in this context + --> $DIR/doc-crate-level.rs:31:1 + | +LL | #![doc(html_logo_url = "example.org")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn main() {} + | ------------ the inner attribute doesn't annotate this function + | + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + +error: an inner attribute is not permitted in this context + --> $DIR/doc-crate-level.rs:33:1 + | +LL | #![doc(html_playground_url = "example.org")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn main() {} + | ------------ the inner attribute doesn't annotate this function + | + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + +error: an inner attribute is not permitted in this context + --> $DIR/doc-crate-level.rs:35:1 + | +LL | #![doc(issue_tracker_base_url = "example.org")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn main() {} + | ------------ the inner attribute doesn't annotate this function + | + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + +error: an inner attribute is not permitted in this context + --> $DIR/doc-crate-level.rs:37:1 + | +LL | #![doc(html_root_url = "example.org")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn main() {} + | ------------ the inner attribute doesn't annotate this function + | + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + +error: an inner attribute is not permitted in this context + --> $DIR/doc-crate-level.rs:39:1 + | +LL | #![doc(html_no_source)] + | ^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn main() {} + | ------------ the inner attribute doesn't annotate this function + | + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + +error: an inner attribute is not permitted in this context + --> $DIR/doc-crate-level.rs:41:1 + | +LL | #![doc(test(no_crate_inject))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | fn main() {} + | ------------ the inner attribute doesn't annotate this function + | + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + +error: `#![doc(fake_variadic = "...")]` isn't allowed as a crate-level attribute + --> $DIR/doc-crate-level.rs:2:8 + | +LL | #![doc(fake_variadic)] + | ^^^^^^^^^^^^^ + +error: `#![doc(alias = "...")]` isn't allowed as a crate-level attribute + --> $DIR/doc-crate-level.rs:4:16 + | +LL | #![doc(alias = "test")] + | ^^^^^^ + +error: `#![doc(search_unbox = "...")]` isn't allowed as a crate-level attribute + --> $DIR/doc-crate-level.rs:6:8 + | +LL | #![doc(search_unbox)] + | ^^^^^^^^^^^^ + +error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` + --> $DIR/doc-crate-level.rs:9:1 + | +LL | #[doc(rust_logo)] + | ^^^^^^^^^^^^^^^^^ + | +note: this attribute does not have an `!`, which means it is applied to this function + --> $DIR/doc-crate-level.rs:25:1 + | +LL | fn function() {} + | ^^^^^^^^^^^^^^^^ + +error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` + --> $DIR/doc-crate-level.rs:11:1 + | +LL | #[doc(html_favicon_url = "example.org")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: this attribute does not have an `!`, which means it is applied to this function + --> $DIR/doc-crate-level.rs:25:1 + | +LL | fn function() {} + | ^^^^^^^^^^^^^^^^ + +error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` + --> $DIR/doc-crate-level.rs:13:1 + | +LL | #[doc(html_logo_url = "example.org")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: this attribute does not have an `!`, which means it is applied to this function + --> $DIR/doc-crate-level.rs:25:1 + | +LL | fn function() {} + | ^^^^^^^^^^^^^^^^ + +error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` + --> $DIR/doc-crate-level.rs:15:1 + | +LL | #[doc(html_playground_url = "example.org")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: this attribute does not have an `!`, which means it is applied to this function + --> $DIR/doc-crate-level.rs:25:1 + | +LL | fn function() {} + | ^^^^^^^^^^^^^^^^ + +error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` + --> $DIR/doc-crate-level.rs:17:1 + | +LL | #[doc(issue_tracker_base_url = "example.org")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: this attribute does not have an `!`, which means it is applied to this function + --> $DIR/doc-crate-level.rs:25:1 + | +LL | fn function() {} + | ^^^^^^^^^^^^^^^^ + +error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` + --> $DIR/doc-crate-level.rs:19:1 + | +LL | #[doc(html_root_url = "example.org")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: this attribute does not have an `!`, which means it is applied to this function + --> $DIR/doc-crate-level.rs:25:1 + | +LL | fn function() {} + | ^^^^^^^^^^^^^^^^ + +error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` + --> $DIR/doc-crate-level.rs:21:1 + | +LL | #[doc(html_no_source)] + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: this attribute does not have an `!`, which means it is applied to this function + --> $DIR/doc-crate-level.rs:25:1 + | +LL | fn function() {} + | ^^^^^^^^^^^^^^^^ + +error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` + --> $DIR/doc-crate-level.rs:23:1 + | +LL | #[doc(test(no_crate_inject))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: this attribute does not have an `!`, which means it is applied to this function + --> $DIR/doc-crate-level.rs:25:1 + | +LL | fn function() {} + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 19 previous errors + From f1a42285d64a21d7a2fc814678aa1a2eb7b13d54 Mon Sep 17 00:00:00 2001 From: Eva van Houten Date: Tue, 1 Sep 2026 14:05:36 +0200 Subject: [PATCH 40/49] Minimize doc-crate-level test for clarity --- tests/ui/attributes/doc-crate-level.rs | 22 --- tests/ui/attributes/doc-crate-level.stderr | 140 +++----------------- tests/ui/feature-gates/doc-rust-logo.rs | 2 - tests/ui/feature-gates/doc-rust-logo.stderr | 11 +- 4 files changed, 18 insertions(+), 157 deletions(-) diff --git a/tests/ui/attributes/doc-crate-level.rs b/tests/ui/attributes/doc-crate-level.rs index 89d934a5dd257..1acd8c46d35ad 100644 --- a/tests/ui/attributes/doc-crate-level.rs +++ b/tests/ui/attributes/doc-crate-level.rs @@ -1,10 +1,4 @@ #![feature(rustdoc_internals)] -#![doc(fake_variadic)] -//~^ ERROR `#![doc(fake_variadic = "...")]` isn't allowed as a crate-level attribute -#![doc(alias = "test")] -//~^ ERROR `#![doc(alias = "...")]` isn't allowed as a crate-level attribute -#![doc(search_unbox)] -//~^ ERROR `#![doc(search_unbox = "...")]` isn't allowed as a crate-level attribute #[doc(rust_logo)] //~^ ERROR crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` @@ -24,20 +18,4 @@ //~^ ERROR crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` fn function() {} -#![doc(rust_logo)] -//~^ ERROR an inner attribute is not permitted in this context -#![doc(html_favicon_url = "example.org")] -//~^ ERROR an inner attribute is not permitted in this context -#![doc(html_logo_url = "example.org")] -//~^ ERROR an inner attribute is not permitted in this context -#![doc(html_playground_url = "example.org")] -//~^ ERROR an inner attribute is not permitted in this context -#![doc(issue_tracker_base_url = "example.org")] -//~^ ERROR an inner attribute is not permitted in this context -#![doc(html_root_url = "example.org")] -//~^ ERROR an inner attribute is not permitted in this context -#![doc(html_no_source)] -//~^ ERROR an inner attribute is not permitted in this context -#![doc(test(no_crate_inject))] -//~^ ERROR an inner attribute is not permitted in this context fn main() {} diff --git a/tests/ui/attributes/doc-crate-level.stderr b/tests/ui/attributes/doc-crate-level.stderr index 5f5b853e5fd4e..b44d9c39b613a 100644 --- a/tests/ui/attributes/doc-crate-level.stderr +++ b/tests/ui/attributes/doc-crate-level.stderr @@ -1,204 +1,98 @@ -error: an inner attribute is not permitted in this context - --> $DIR/doc-crate-level.rs:27:1 - | -LL | #![doc(rust_logo)] - | ^^^^^^^^^^^^^^^^^^ -... -LL | fn main() {} - | ------------ the inner attribute doesn't annotate this function - | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files - -error: an inner attribute is not permitted in this context - --> $DIR/doc-crate-level.rs:29:1 - | -LL | #![doc(html_favicon_url = "example.org")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | fn main() {} - | ------------ the inner attribute doesn't annotate this function - | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files - -error: an inner attribute is not permitted in this context - --> $DIR/doc-crate-level.rs:31:1 - | -LL | #![doc(html_logo_url = "example.org")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | fn main() {} - | ------------ the inner attribute doesn't annotate this function - | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files - -error: an inner attribute is not permitted in this context - --> $DIR/doc-crate-level.rs:33:1 - | -LL | #![doc(html_playground_url = "example.org")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | fn main() {} - | ------------ the inner attribute doesn't annotate this function - | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files - -error: an inner attribute is not permitted in this context - --> $DIR/doc-crate-level.rs:35:1 - | -LL | #![doc(issue_tracker_base_url = "example.org")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | fn main() {} - | ------------ the inner attribute doesn't annotate this function - | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files - -error: an inner attribute is not permitted in this context - --> $DIR/doc-crate-level.rs:37:1 - | -LL | #![doc(html_root_url = "example.org")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | fn main() {} - | ------------ the inner attribute doesn't annotate this function - | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files - -error: an inner attribute is not permitted in this context - --> $DIR/doc-crate-level.rs:39:1 - | -LL | #![doc(html_no_source)] - | ^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | fn main() {} - | ------------ the inner attribute doesn't annotate this function - | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files - -error: an inner attribute is not permitted in this context - --> $DIR/doc-crate-level.rs:41:1 - | -LL | #![doc(test(no_crate_inject))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | fn main() {} - | ------------ the inner attribute doesn't annotate this function - | - = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files - -error: `#![doc(fake_variadic = "...")]` isn't allowed as a crate-level attribute - --> $DIR/doc-crate-level.rs:2:8 - | -LL | #![doc(fake_variadic)] - | ^^^^^^^^^^^^^ - -error: `#![doc(alias = "...")]` isn't allowed as a crate-level attribute - --> $DIR/doc-crate-level.rs:4:16 - | -LL | #![doc(alias = "test")] - | ^^^^^^ - -error: `#![doc(search_unbox = "...")]` isn't allowed as a crate-level attribute - --> $DIR/doc-crate-level.rs:6:8 - | -LL | #![doc(search_unbox)] - | ^^^^^^^^^^^^ - error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` - --> $DIR/doc-crate-level.rs:9:1 + --> $DIR/doc-crate-level.rs:3:1 | LL | #[doc(rust_logo)] | ^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this function - --> $DIR/doc-crate-level.rs:25:1 + --> $DIR/doc-crate-level.rs:19:1 | LL | fn function() {} | ^^^^^^^^^^^^^^^^ error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` - --> $DIR/doc-crate-level.rs:11:1 + --> $DIR/doc-crate-level.rs:5:1 | LL | #[doc(html_favicon_url = "example.org")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this function - --> $DIR/doc-crate-level.rs:25:1 + --> $DIR/doc-crate-level.rs:19:1 | LL | fn function() {} | ^^^^^^^^^^^^^^^^ error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` - --> $DIR/doc-crate-level.rs:13:1 + --> $DIR/doc-crate-level.rs:7:1 | LL | #[doc(html_logo_url = "example.org")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this function - --> $DIR/doc-crate-level.rs:25:1 + --> $DIR/doc-crate-level.rs:19:1 | LL | fn function() {} | ^^^^^^^^^^^^^^^^ error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` - --> $DIR/doc-crate-level.rs:15:1 + --> $DIR/doc-crate-level.rs:9:1 | LL | #[doc(html_playground_url = "example.org")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this function - --> $DIR/doc-crate-level.rs:25:1 + --> $DIR/doc-crate-level.rs:19:1 | LL | fn function() {} | ^^^^^^^^^^^^^^^^ error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` - --> $DIR/doc-crate-level.rs:17:1 + --> $DIR/doc-crate-level.rs:11:1 | LL | #[doc(issue_tracker_base_url = "example.org")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this function - --> $DIR/doc-crate-level.rs:25:1 + --> $DIR/doc-crate-level.rs:19:1 | LL | fn function() {} | ^^^^^^^^^^^^^^^^ error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` - --> $DIR/doc-crate-level.rs:19:1 + --> $DIR/doc-crate-level.rs:13:1 | LL | #[doc(html_root_url = "example.org")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this function - --> $DIR/doc-crate-level.rs:25:1 + --> $DIR/doc-crate-level.rs:19:1 | LL | fn function() {} | ^^^^^^^^^^^^^^^^ error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` - --> $DIR/doc-crate-level.rs:21:1 + --> $DIR/doc-crate-level.rs:15:1 | LL | #[doc(html_no_source)] | ^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this function - --> $DIR/doc-crate-level.rs:25:1 + --> $DIR/doc-crate-level.rs:19:1 | LL | fn function() {} | ^^^^^^^^^^^^^^^^ error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` - --> $DIR/doc-crate-level.rs:23:1 + --> $DIR/doc-crate-level.rs:17:1 | LL | #[doc(test(no_crate_inject))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this function - --> $DIR/doc-crate-level.rs:25:1 + --> $DIR/doc-crate-level.rs:19:1 | LL | fn function() {} | ^^^^^^^^^^^^^^^^ -error: aborting due to 19 previous errors +error: aborting due to 8 previous errors diff --git a/tests/ui/feature-gates/doc-rust-logo.rs b/tests/ui/feature-gates/doc-rust-logo.rs index 08857cc778f5b..2ad7272ceafe0 100644 --- a/tests/ui/feature-gates/doc-rust-logo.rs +++ b/tests/ui/feature-gates/doc-rust-logo.rs @@ -2,6 +2,4 @@ //~^ ERROR this subset of the `doc` attribute is meant for internal use only //! This is not an official rust crate -#[doc(rust_logo)] -//~^ WARN this attribute can only be applied at the crate level fn main() {} diff --git a/tests/ui/feature-gates/doc-rust-logo.stderr b/tests/ui/feature-gates/doc-rust-logo.stderr index 802187e6a598c..bd5a2aa43dd5b 100644 --- a/tests/ui/feature-gates/doc-rust-logo.stderr +++ b/tests/ui/feature-gates/doc-rust-logo.stderr @@ -8,15 +8,6 @@ LL | #![doc(rust_logo)] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: the `#[doc(rust_logo)]` attribute is used for Rust branding -warning: this attribute can only be applied at the crate level - --> $DIR/doc-rust-logo.rs:5:7 - | -LL | #[doc(rust_logo)] - | ^^^^^^^^^ - | - = note: read for more information - = note: `#[warn(invalid_doc_attributes)]` on by default - -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0658`. From 30c334f748f47d3fa6175993bcd748271c850a7f Mon Sep 17 00:00:00 2001 From: Eva van Houten Date: Fri, 11 Sep 2026 12:47:30 +0200 Subject: [PATCH 41/49] Restore crate level doc attr warning --- .../rustc_attr_parsing/src/attributes/doc.rs | 9 +- .../rustc_attr_parsing/src/diagnostics.rs | 7 ++ .../rustc_attr_parsing/src/target_checking.rs | 12 ++- tests/ui/attributes/doc-crate-level.rs | 17 ++-- tests/ui/attributes/doc-crate-level.stderr | 83 ++++++------------- 5 files changed, 59 insertions(+), 69 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 395922f1208b2..c7335c1aab171 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -157,7 +157,7 @@ impl DocParser { cx.check_target( sym::no_crate_inject.as_str(), - &AllowedTargets::AllowList(&[Allow(Target::Crate)]), + &AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]), ); self.attribute.no_crate_inject = Some(path.span()) @@ -547,7 +547,7 @@ impl DocParser { let span = path.span(); cx.check_target( concat!("(", stringify!($ident), ")"), - &AllowedTargets::AllowList(&[Allow(Target::Crate)]), + &AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]), ); self.attribute.$ident = Some(span); }}; @@ -564,7 +564,10 @@ impl DocParser { return; }; - cx.check_target(s.as_str(), &AllowedTargets::AllowList(&[Allow(Target::Crate)])); + cx.check_target( + s.as_str(), + &AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]), + ); // FIXME: It's errorring when the attribute is passed multiple times on the command // line. diff --git a/compiler/rustc_attr_parsing/src/diagnostics.rs b/compiler/rustc_attr_parsing/src/diagnostics.rs index 9aee8725b3a88..2b41db75ed5bb 100644 --- a/compiler/rustc_attr_parsing/src/diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/diagnostics.rs @@ -340,6 +340,13 @@ pub(crate) struct DocInlineOnlyUse { pub item_span: Span, } +#[derive(Diagnostic)] +#[diag("this attribute can only be applied at the crate level")] +#[note( + "read for more information" +)] +pub(crate) struct AttrCrateLevelOnly; + #[derive(Diagnostic)] #[diag("`#[diagnostic::do_not_recommend]` does not expect any arguments")] pub(crate) struct DoNotRecommendDoesNotExpectArgs; diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index 7eb3e8e1f319a..723f4a31823ab 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -6,7 +6,7 @@ use rustc_attr_ir::{AttrItem, Attribute, AttributeKind}; use rustc_errors::{DiagArgValue, MultiSpan, StashKey}; use rustc_feature::Features; use rustc_lint_defs::builtin::{ - MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES, USELESS_DEPRECATED, + INVALID_DOC_ATTRIBUTES, MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES, USELESS_DEPRECATED, }; use rustc_span::{BytePos, FileName, RemapPathScopeComponents, Span, Symbol, sym}; @@ -244,6 +244,16 @@ impl<'sess> AttributeParser<'sess> { }) .unwrap_or_default(); + if name == "doc" { + let diag = crate::diagnostics::AttrCrateLevelOnly; + if warn { + cx.emit_lint(INVALID_DOC_ATTRIBUTES, diag, attr_span); + } else { + cx.emit_err(diag); + } + return; + } + let diag = crate::diagnostics::InvalidAttrStyle { name, is_used_as_inner, diff --git a/tests/ui/attributes/doc-crate-level.rs b/tests/ui/attributes/doc-crate-level.rs index 1acd8c46d35ad..c58866022e2c2 100644 --- a/tests/ui/attributes/doc-crate-level.rs +++ b/tests/ui/attributes/doc-crate-level.rs @@ -1,21 +1,22 @@ +//@check-pass #![feature(rustdoc_internals)] #[doc(rust_logo)] -//~^ ERROR crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` +//~^ WARN this attribute can only be applied at the crate level #[doc(html_favicon_url = "example.org")] -//~^ ERROR crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` +//~^ WARN this attribute can only be applied at the crate level #[doc(html_logo_url = "example.org")] -//~^ ERROR crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` +//~^ WARN this attribute can only be applied at the crate level #[doc(html_playground_url = "example.org")] -//~^ ERROR crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` +//~^ WARN this attribute can only be applied at the crate level #[doc(issue_tracker_base_url = "example.org")] -//~^ ERROR crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` +//~^ WARN this attribute can only be applied at the crate level #[doc(html_root_url = "example.org")] -//~^ ERROR crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` +//~^ WARN this attribute can only be applied at the crate level #[doc(html_no_source)] -//~^ ERROR crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` +//~^ WARN this attribute can only be applied at the crate level #[doc(test(no_crate_inject))] -//~^ ERROR crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` +//~^ WARN this attribute can only be applied at the crate level fn function() {} fn main() {} diff --git a/tests/ui/attributes/doc-crate-level.stderr b/tests/ui/attributes/doc-crate-level.stderr index b44d9c39b613a..71c385e576101 100644 --- a/tests/ui/attributes/doc-crate-level.stderr +++ b/tests/ui/attributes/doc-crate-level.stderr @@ -1,98 +1,67 @@ -error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` - --> $DIR/doc-crate-level.rs:3:1 +warning: this attribute can only be applied at the crate level + --> $DIR/doc-crate-level.rs:4:1 | LL | #[doc(rust_logo)] | ^^^^^^^^^^^^^^^^^ | -note: this attribute does not have an `!`, which means it is applied to this function - --> $DIR/doc-crate-level.rs:19:1 - | -LL | fn function() {} - | ^^^^^^^^^^^^^^^^ + = note: read for more information + = note: `#[warn(invalid_doc_attributes)]` on by default -error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` - --> $DIR/doc-crate-level.rs:5:1 +warning: this attribute can only be applied at the crate level + --> $DIR/doc-crate-level.rs:6:1 | LL | #[doc(html_favicon_url = "example.org")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: this attribute does not have an `!`, which means it is applied to this function - --> $DIR/doc-crate-level.rs:19:1 - | -LL | fn function() {} - | ^^^^^^^^^^^^^^^^ + = note: read for more information -error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` - --> $DIR/doc-crate-level.rs:7:1 +warning: this attribute can only be applied at the crate level + --> $DIR/doc-crate-level.rs:8:1 | LL | #[doc(html_logo_url = "example.org")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: this attribute does not have an `!`, which means it is applied to this function - --> $DIR/doc-crate-level.rs:19:1 - | -LL | fn function() {} - | ^^^^^^^^^^^^^^^^ + = note: read for more information -error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` - --> $DIR/doc-crate-level.rs:9:1 +warning: this attribute can only be applied at the crate level + --> $DIR/doc-crate-level.rs:10:1 | LL | #[doc(html_playground_url = "example.org")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: this attribute does not have an `!`, which means it is applied to this function - --> $DIR/doc-crate-level.rs:19:1 - | -LL | fn function() {} - | ^^^^^^^^^^^^^^^^ + = note: read for more information -error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` - --> $DIR/doc-crate-level.rs:11:1 +warning: this attribute can only be applied at the crate level + --> $DIR/doc-crate-level.rs:12:1 | LL | #[doc(issue_tracker_base_url = "example.org")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: this attribute does not have an `!`, which means it is applied to this function - --> $DIR/doc-crate-level.rs:19:1 - | -LL | fn function() {} - | ^^^^^^^^^^^^^^^^ + = note: read for more information -error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` - --> $DIR/doc-crate-level.rs:13:1 +warning: this attribute can only be applied at the crate level + --> $DIR/doc-crate-level.rs:14:1 | LL | #[doc(html_root_url = "example.org")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: this attribute does not have an `!`, which means it is applied to this function - --> $DIR/doc-crate-level.rs:19:1 - | -LL | fn function() {} - | ^^^^^^^^^^^^^^^^ + = note: read for more information -error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` - --> $DIR/doc-crate-level.rs:15:1 +warning: this attribute can only be applied at the crate level + --> $DIR/doc-crate-level.rs:16:1 | LL | #[doc(html_no_source)] | ^^^^^^^^^^^^^^^^^^^^^^ | -note: this attribute does not have an `!`, which means it is applied to this function - --> $DIR/doc-crate-level.rs:19:1 - | -LL | fn function() {} - | ^^^^^^^^^^^^^^^^ + = note: read for more information -error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![doc]` - --> $DIR/doc-crate-level.rs:17:1 +warning: this attribute can only be applied at the crate level + --> $DIR/doc-crate-level.rs:18:1 | LL | #[doc(test(no_crate_inject))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: this attribute does not have an `!`, which means it is applied to this function - --> $DIR/doc-crate-level.rs:19:1 - | -LL | fn function() {} - | ^^^^^^^^^^^^^^^^ + = note: read for more information -error: aborting due to 8 previous errors +warning: 8 warnings emitted From c6fdfff7afbf874bf90790278f84337fcd7807bf Mon Sep 17 00:00:00 2001 From: Eva van Houten Date: Mon, 14 Sep 2026 15:37:41 +0200 Subject: [PATCH 42/49] Bless rustdoc ui test --- .../lints/invalid-crate-level-lint.rs | 3 ++- .../lints/invalid-crate-level-lint.stderr | 19 ++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/tests/rustdoc-ui/lints/invalid-crate-level-lint.rs b/tests/rustdoc-ui/lints/invalid-crate-level-lint.rs index afb0a5987deb3..e38a63cd12550 100644 --- a/tests/rustdoc-ui/lints/invalid-crate-level-lint.rs +++ b/tests/rustdoc-ui/lints/invalid-crate-level-lint.rs @@ -6,7 +6,8 @@ pub mod bar { #![doc(test(no_crate_inject))] - //~^ ERROR can only be applied at the crate level + //~^ ERROR unused attribute + //~| WARN this was previously accepted by the compiler but is being phased out #[doc(test(no_crate_inject))] //~^ ERROR can only be applied at the crate level diff --git a/tests/rustdoc-ui/lints/invalid-crate-level-lint.stderr b/tests/rustdoc-ui/lints/invalid-crate-level-lint.stderr index 7569cf575e510..b98b6fda035f4 100644 --- a/tests/rustdoc-ui/lints/invalid-crate-level-lint.stderr +++ b/tests/rustdoc-ui/lints/invalid-crate-level-lint.stderr @@ -1,8 +1,8 @@ error: this attribute can only be applied at the crate level - --> $DIR/invalid-crate-level-lint.rs:4:12 + --> $DIR/invalid-crate-level-lint.rs:4:1 | LL | #[doc(test(no_crate_inject))] - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: read for more information note: the lint level is defined here @@ -11,19 +11,24 @@ note: the lint level is defined here LL | #![deny(invalid_doc_attributes)] | ^^^^^^^^^^^^^^^^^^^^^^ -error: this attribute can only be applied at the crate level +error: unused attribute --> $DIR/invalid-crate-level-lint.rs:8:17 | LL | #![doc(test(no_crate_inject))] - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ help: remove this attribute | - = note: read for more information +note: attribute also specified here + --> $DIR/invalid-crate-level-lint.rs:4:12 + | +LL | #[doc(test(no_crate_inject))] + | ^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: this attribute can only be applied at the crate level - --> $DIR/invalid-crate-level-lint.rs:11:16 + --> $DIR/invalid-crate-level-lint.rs:12:5 | LL | #[doc(test(no_crate_inject))] - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: read for more information From 873c9c0db291550bf5814094614d334242e1bd36 Mon Sep 17 00:00:00 2001 From: Eva van Houten Date: Mon, 26 Oct 2026 11:52:20 +0100 Subject: [PATCH 43/49] Revert rust-logo test --- tests/ui/feature-gates/doc-rust-logo.rs | 2 ++ tests/ui/feature-gates/doc-rust-logo.stderr | 11 ++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/ui/feature-gates/doc-rust-logo.rs b/tests/ui/feature-gates/doc-rust-logo.rs index 2ad7272ceafe0..08857cc778f5b 100644 --- a/tests/ui/feature-gates/doc-rust-logo.rs +++ b/tests/ui/feature-gates/doc-rust-logo.rs @@ -2,4 +2,6 @@ //~^ ERROR this subset of the `doc` attribute is meant for internal use only //! This is not an official rust crate +#[doc(rust_logo)] +//~^ WARN this attribute can only be applied at the crate level fn main() {} diff --git a/tests/ui/feature-gates/doc-rust-logo.stderr b/tests/ui/feature-gates/doc-rust-logo.stderr index bd5a2aa43dd5b..47f7e7480bf1a 100644 --- a/tests/ui/feature-gates/doc-rust-logo.stderr +++ b/tests/ui/feature-gates/doc-rust-logo.stderr @@ -8,6 +8,15 @@ LL | #![doc(rust_logo)] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: the `#[doc(rust_logo)]` attribute is used for Rust branding -error: aborting due to 1 previous error +warning: this attribute can only be applied at the crate level + --> $DIR/doc-rust-logo.rs:5:1 + | +LL | #[doc(rust_logo)] + | ^^^^^^^^^^^^^^^^^ + | + = note: read for more information + = note: `#[warn(invalid_doc_attributes)]` on by default + +error: aborting due to 1 previous error; 1 warning emitted For more information about this error, try `rustc --explain E0658`. From 1708abc66462ac1d8dc8f1a88c41ba4244785234 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Fri, 23 Oct 2026 12:27:32 +0000 Subject: [PATCH 44/49] re-insertion of params in input list should not roll over --- compiler/rustc_hir_typeck/src/expr.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 7dc4b8d7674ca..b9490e599d9fb 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1515,9 +1515,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .type_of(param.def_id) .instantiate(self.tcx, method.args) .skip_norm_wip(); + // Insert function argument const param types back into the inputs. // We use pos - 1 since method_inputs skips self, but arg_pos counts it. - method_inputs.to_mut().insert(pos as usize - 1, ty); + if let Some(pos) = pos.checked_sub(1) { + method_inputs.to_mut().insert(pos as usize, ty); + } } let method_tuple_args_flag = From 814e7719e6c9e8b684843ac4240df6574f93f109 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Fri, 23 Oct 2026 12:28:25 +0000 Subject: [PATCH 45/49] check whether the original param to not allow later self, to be considered as the first self --- compiler/rustc_ty_utils/src/assoc.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index bff2f1e6804af..6b30019127f27 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -2,7 +2,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_hir::definitions::{DefPathData, PerParentDisambiguatorState}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{self as hir, ImplItemImplKind, ItemKind}; +use rustc_hir::{self as hir, Generics, ImplItemImplKind, ItemKind}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt}; use rustc_span::symbol::kw; @@ -76,8 +76,14 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AssocItem { assoc_item } -fn fn_has_self_parameter(tcx: TyCtxt<'_>, owner_id: hir::OwnerId) -> bool { +fn fn_has_self_parameter(tcx: TyCtxt<'_>, owner_id: hir::OwnerId, generics: &Generics<'_>) -> bool { + // With `function_arg_const_generics`, const parameters are moved into the + // generics. We check the original `arg_pos` to avoid treating a later `self` + // as a valid receiver after the const parameters are removed. matches!(tcx.fn_arg_idents(owner_id.def_id), [Some(Ident { name: kw::SelfLower, .. }), ..]) + && !generics.params.iter().any(|param| { + matches!(param.kind, hir::GenericParamKind::Const { arg_pos: Some(0), .. }) + }) } fn associated_item_from_trait_item( @@ -88,9 +94,10 @@ fn associated_item_from_trait_item( let name = trait_item.ident.name; let kind = match trait_item.kind { hir::TraitItemKind::Const(_, _) => ty::AssocKind::Const { name }, - hir::TraitItemKind::Fn { .. } => { - ty::AssocKind::Fn { name, has_self: fn_has_self_parameter(tcx, owner_id) } - } + hir::TraitItemKind::Fn { .. } => ty::AssocKind::Fn { + name, + has_self: fn_has_self_parameter(tcx, owner_id, trait_item.generics), + }, hir::TraitItemKind::Type { .. } => { ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) } } @@ -104,9 +111,10 @@ fn associated_item_from_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_> let name = impl_item.ident.name; let kind = match impl_item.kind { hir::ImplItemKind::Const(..) => ty::AssocKind::Const { name }, - hir::ImplItemKind::Fn(..) => { - ty::AssocKind::Fn { name, has_self: fn_has_self_parameter(tcx, owner_id) } - } + hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn { + name, + has_self: fn_has_self_parameter(tcx, owner_id, impl_item.generics), + }, hir::ImplItemKind::Type(..) => { ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) } } From 84cbe3e84edfcdf1a6fe7f034a96c30b850cd7fb Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Fri, 23 Oct 2026 12:29:48 +0000 Subject: [PATCH 46/49] add test for example --- .../self-param-after-const-param.rs | 16 +++++++ .../self-param-after-const-param.stderr | 42 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 tests/ui/const-generics/function_arg_const_generics/self-param-after-const-param.rs create mode 100644 tests/ui/const-generics/function_arg_const_generics/self-param-after-const-param.stderr diff --git a/tests/ui/const-generics/function_arg_const_generics/self-param-after-const-param.rs b/tests/ui/const-generics/function_arg_const_generics/self-param-after-const-param.rs new file mode 100644 index 0000000000000..f9de0a02112bd --- /dev/null +++ b/tests/ui/const-generics/function_arg_const_generics/self-param-after-const-param.rs @@ -0,0 +1,16 @@ +#![feature(function_arg_const_generics, gca_min_const_items)] + +trait Foo { + fn a(const N: usize, self: [isize; N]) -> isize; //~ ERROR + fn b(&self) -> isize { + self.a() + 2 //~ ERROR E0599 + } +} + +impl Foo for isize { + fn a(&self) -> isize { //~ ERROR E0185 + 3 + } +} + +fn main() {} diff --git a/tests/ui/const-generics/function_arg_const_generics/self-param-after-const-param.stderr b/tests/ui/const-generics/function_arg_const_generics/self-param-after-const-param.stderr new file mode 100644 index 0000000000000..0253d69602aff --- /dev/null +++ b/tests/ui/const-generics/function_arg_const_generics/self-param-after-const-param.stderr @@ -0,0 +1,42 @@ +error: unexpected `self` parameter in function + --> $DIR/self-param-after-const-param.rs:4:26 + | +LL | fn a(const N: usize, self: [isize; N]) -> isize; + | ^^^^ must be the first parameter of an associated function + +error[E0185]: method `a` has a `&self` declaration in the impl, but not in the trait + --> $DIR/self-param-after-const-param.rs:11:5 + | +LL | fn a(const N: usize, self: [isize; N]) -> isize; + | ------------------------------------------------ trait method declared without `&self` +... +LL | fn a(&self) -> isize { + | ^^^^^^^^^^^^^^^^^^^^ `&self` used in impl + +error[E0599]: no method named `a` found for reference `&Self` in the current scope + --> $DIR/self-param-after-const-param.rs:6:14 + | +LL | self.a() + 2 + | ^ 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 `Foo` + --> $DIR/self-param-after-const-param.rs:4:5 + | +LL | fn a(const N: usize, self: [isize; N]) -> isize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use associated function syntax instead + | +LL - self.a() + 2 +LL + Self::a() + 2 + | +help: there is a method `b` with a similar name + | +LL - self.a() + 2 +LL + self.b() + 2 + | + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0185, E0599. +For more information about an error, try `rustc --explain E0185`. From ef9f215be307583525d05544887006bee4ec5a68 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Mon, 26 Oct 2026 11:55:15 +0000 Subject: [PATCH 47/49] scream if pos is lesser than zero --- compiler/rustc_hir_typeck/src/expr.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index b9490e599d9fb..6059ede2ecdc6 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1518,9 +1518,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Insert function argument const param types back into the inputs. // We use pos - 1 since method_inputs skips self, but arg_pos counts it. - if let Some(pos) = pos.checked_sub(1) { - method_inputs.to_mut().insert(pos as usize, ty); - } + method_inputs.to_mut().insert( + pos.checked_sub(1).expect("pos should always be greater than 0") as usize, + ty, + ); } let method_tuple_args_flag = From 86bc6b19ffb871003b612d3c032e8ae2fecbc7cf Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 26 Oct 2026 13:49:35 +0100 Subject: [PATCH 48/49] Add test showing the problem --- .../missing-dot-on-if-condition-expression.rs | 16 ++++++++++++ ...sing-dot-on-if-condition-expression.stderr | 25 ++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/tests/ui/parser/recover/missing-dot-on-if-condition-expression.rs b/tests/ui/parser/recover/missing-dot-on-if-condition-expression.rs index c4a9ed66a8322..66ffc046d1345 100644 --- a/tests/ui/parser/recover/missing-dot-on-if-condition-expression.rs +++ b/tests/ui/parser/recover/missing-dot-on-if-condition-expression.rs @@ -47,6 +47,22 @@ fn foo8() { //~^ ERROR expected `{`, found `a` //~| HELP you might have meant to write a field access } +fn foo9() { + macro_rules! m { + (static a : () = $e:expr) => { + static a: () = $e; + }; + } + + m! { static a : () = { + let x = (vec![1, 2, 3],); + for _ in x 0 {} + //~^ ERROR expected `{`, found `0` + //~| ERROR expected `{`, found `0` + //~| HELP you might have meant to write a field access + //~| HELP you might have meant to write a field access + } } +} struct S { a: A, diff --git a/tests/ui/parser/recover/missing-dot-on-if-condition-expression.stderr b/tests/ui/parser/recover/missing-dot-on-if-condition-expression.stderr index bfb72b9568281..73f6184e99e9d 100644 --- a/tests/ui/parser/recover/missing-dot-on-if-condition-expression.stderr +++ b/tests/ui/parser/recover/missing-dot-on-if-condition-expression.stderr @@ -97,5 +97,28 @@ help: you might have meant to write a field access LL | for _ in x.a.b {} | + -error: aborting due to 9 previous errors +error: expected `{`, found `0` + --> $DIR/missing-dot-on-if-condition-expression.rs:59:20 + | +LL | for _ in x 0 {} + | ^ expected `{` + | +help: you might have meant to write a field access + | +LL | for _ in x.0 {} + | + + +error: expected `{`, found `0` + --> $DIR/missing-dot-on-if-condition-expression.rs:59:20 + | +LL | for _ in x 0 {} + | ^ expected `{` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: you might have meant to write a field access + | +LL | for _ in x.0 {} + | + + +error: aborting due to 11 previous errors From 2bec100a1ebf76e30a400023ca627c122ae32146 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 26 Oct 2026 13:54:26 +0100 Subject: [PATCH 49/49] Only recover if we may for `recover_missing_dot` --- compiler/rustc_parse/src/parser/diagnostics.rs | 11 ++++------- compiler/rustc_parse/src/parser/stmt.rs | 4 ++-- .../missing-dot-on-if-condition-expression.rs | 2 -- ...issing-dot-on-if-condition-expression.stderr | 17 ++++------------- 4 files changed, 10 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index d734a70399b11..b6d31acb0b1e8 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -127,18 +127,15 @@ pub enum AttemptLocalParseRecovery { } impl AttemptLocalParseRecovery { - pub(super) fn yes(&self) -> bool { + pub(super) fn yes(&self, p: &Parser<'_>) -> bool { match self { - AttemptLocalParseRecovery::Yes => true, + AttemptLocalParseRecovery::Yes => p.may_recover(), AttemptLocalParseRecovery::No => false, } } - pub(super) fn no(&self) -> bool { - match self { - AttemptLocalParseRecovery::Yes => false, - AttemptLocalParseRecovery::No => true, - } + pub(super) fn no(&self, p: &Parser<'_>) -> bool { + !self.yes(p) } } diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 4382420a59b7c..49bcdbbe8fa57 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -765,7 +765,7 @@ impl<'a> Parser<'a> { snapshot = Some(self.create_snapshot_for_diagnostic()); } let stmt = match self.parse_full_stmt(recover) { - Err(mut err) if recover.yes() => { + Err(mut err) if recover.yes(self) => { if let Some(ref mut snapshot) = snapshot { snapshot.recover_vcs_conflict_marker(); } @@ -1072,7 +1072,7 @@ impl<'a> Parser<'a> { let res = self.check_mistyped_turbofish_with_multiple_type_params(e, expr); - Some(if recover.no() { + Some(if recover.no(self) { res? } else { res.unwrap_or_else(|mut e| { diff --git a/tests/ui/parser/recover/missing-dot-on-if-condition-expression.rs b/tests/ui/parser/recover/missing-dot-on-if-condition-expression.rs index 66ffc046d1345..5e09f3e5a614c 100644 --- a/tests/ui/parser/recover/missing-dot-on-if-condition-expression.rs +++ b/tests/ui/parser/recover/missing-dot-on-if-condition-expression.rs @@ -58,8 +58,6 @@ fn foo9() { let x = (vec![1, 2, 3],); for _ in x 0 {} //~^ ERROR expected `{`, found `0` - //~| ERROR expected `{`, found `0` - //~| HELP you might have meant to write a field access //~| HELP you might have meant to write a field access } } } diff --git a/tests/ui/parser/recover/missing-dot-on-if-condition-expression.stderr b/tests/ui/parser/recover/missing-dot-on-if-condition-expression.stderr index 73f6184e99e9d..22f1e1525172d 100644 --- a/tests/ui/parser/recover/missing-dot-on-if-condition-expression.stderr +++ b/tests/ui/parser/recover/missing-dot-on-if-condition-expression.stderr @@ -100,6 +100,9 @@ LL | for _ in x.a.b {} error: expected `{`, found `0` --> $DIR/missing-dot-on-if-condition-expression.rs:59:20 | +LL | (static a : () = $e:expr) => { + | ------- while parsing argument for this `expr` macro fragment +... LL | for _ in x 0 {} | ^ expected `{` | @@ -108,17 +111,5 @@ help: you might have meant to write a field access LL | for _ in x.0 {} | + -error: expected `{`, found `0` - --> $DIR/missing-dot-on-if-condition-expression.rs:59:20 - | -LL | for _ in x 0 {} - | ^ expected `{` - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: you might have meant to write a field access - | -LL | for _ in x.0 {} - | + - -error: aborting due to 11 previous errors +error: aborting due to 10 previous errors