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 22e2b8df08c9e110fa1910a105e2f6d225195bb9 Mon Sep 17 00:00:00 2001 From: Jesus Checa Hidalgo Date: Thu, 22 Oct 2026 13:19:53 +0200 Subject: [PATCH 06/49] Use explicit target cpu in tests parsing generated asm These tests expect generated asm based on assumed target CPU, but some Linux distros use a different CPU baseline, causing a false positive. --- tests/assembly-llvm/c-variadic/s390x.rs | 2 +- tests/assembly-llvm/slp-vectorize-closure.rs | 2 +- tests/assembly-llvm/x86_64-typed-swap.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/assembly-llvm/c-variadic/s390x.rs b/tests/assembly-llvm/c-variadic/s390x.rs index 7dfcda83fda3b..4880f5430f542 100644 --- a/tests/assembly-llvm/c-variadic/s390x.rs +++ b/tests/assembly-llvm/c-variadic/s390x.rs @@ -1,7 +1,7 @@ //@ add-minicore //@ assembly-output: emit-asm // -//@ compile-flags: -Copt-level=3 --target s390x-unknown-linux-gnu +//@ compile-flags: -Copt-level=3 --target s390x-unknown-linux-gnu -Ctarget-cpu=z10 //@ needs-llvm-components: systemz #![feature(no_core, lang_items, intrinsics, rustc_attrs)] #![no_core] diff --git a/tests/assembly-llvm/slp-vectorize-closure.rs b/tests/assembly-llvm/slp-vectorize-closure.rs index fcdb469a24139..7b0893d905f82 100644 --- a/tests/assembly-llvm/slp-vectorize-closure.rs +++ b/tests/assembly-llvm/slp-vectorize-closure.rs @@ -2,7 +2,7 @@ //! Regression test for . //! also see //@ assembly-output: emit-asm -//@ compile-flags: -Copt-level=3 +//@ compile-flags: -Copt-level=3 -Ctarget-cpu=x86-64-v2 //@ only-x86_64 // to test SSE instructions diff --git a/tests/assembly-llvm/x86_64-typed-swap.rs b/tests/assembly-llvm/x86_64-typed-swap.rs index a6753011d3620..ea34c2dcac7d7 100644 --- a/tests/assembly-llvm/x86_64-typed-swap.rs +++ b/tests/assembly-llvm/x86_64-typed-swap.rs @@ -3,7 +3,7 @@ //@ [LIN] only-linux //@ only-x86_64 //@ assembly-output: emit-asm -//@ compile-flags: --crate-type=lib -Copt-level=3 +//@ compile-flags: --crate-type=lib -Copt-level=3 -Ctarget-cpu=x86-64-v2 use std::arch::x86_64::__m128; use std::mem::swap; From 26c788b5ef2ae6e47df99f64d2678a470a6e5d17 Mon Sep 17 00:00:00 2001 From: Philip Sampaio Date: Thu, 22 Oct 2026 18:00:00 -0300 Subject: [PATCH 07/49] Add regression tests for transmutability issues The commit with the fix is ee135be0415aa531339d2a536207f32b15a0acac, and is associated with the PR: https://github.com/rust-lang/rust/pull/154991 Closes https://github.com/rust-lang/rust/issues/153357 Closes https://github.com/rust-lang/rust/issues/154536 --- .../impl-transmute-from-returning-box.rs | 14 ++++++++++ .../impl-transmute-from-returning-box.stderr | 27 +++++++++++++++++++ .../with-fn-mut-and-impl-sized.rs | 15 +++++++++++ .../with-fn-mut-and-impl-sized.stderr | 21 +++++++++++++++ 4 files changed, 77 insertions(+) create mode 100644 tests/ui/transmutability/impl-transmute-from-returning-box.rs create mode 100644 tests/ui/transmutability/impl-transmute-from-returning-box.stderr create mode 100644 tests/ui/transmutability/with-fn-mut-and-impl-sized.rs create mode 100644 tests/ui/transmutability/with-fn-mut-and-impl-sized.stderr diff --git a/tests/ui/transmutability/impl-transmute-from-returning-box.rs b/tests/ui/transmutability/impl-transmute-from-returning-box.rs new file mode 100644 index 0000000000000..15f0c6f2baa9b --- /dev/null +++ b/tests/ui/transmutability/impl-transmute-from-returning-box.rs @@ -0,0 +1,14 @@ +// Regression test for: https://github.com/rust-lang/rust/issues/154536 +// @compile-flags: -Znext-solver + +#![feature(transmutability)] +#![feature(unboxed_closures)] + +pub fn box_factory() -> impl std::mem::TransmuteFrom() { + //~^ ERROR: `()` cannot be safely transmuted into `Box<()>` + //~^^ ERROR: associated type `Output` not found for `TransmuteFrom` + //~^^^ ERROR: associated type `Output` not found for `TransmuteFrom` + Box::new(()) +} + +fn main() {} diff --git a/tests/ui/transmutability/impl-transmute-from-returning-box.stderr b/tests/ui/transmutability/impl-transmute-from-returning-box.stderr new file mode 100644 index 0000000000000..25b3d6d03d422 --- /dev/null +++ b/tests/ui/transmutability/impl-transmute-from-returning-box.stderr @@ -0,0 +1,27 @@ +error[E0220]: associated type `Output` not found for `TransmuteFrom` + --> $DIR/impl-transmute-from-returning-box.rs:7:40 + | +LL | pub fn box_factory() -> impl std::mem::TransmuteFrom() { + | ^^^^^^^^^^^^^^^ associated type `Output` not found + +error[E0220]: associated type `Output` not found for `TransmuteFrom` + --> $DIR/impl-transmute-from-returning-box.rs:7:40 + | +LL | pub fn box_factory() -> impl std::mem::TransmuteFrom() { + | ^^^^^^^^^^^^^^^ associated type `Output` not found + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0277]: `()` cannot be safely transmuted into `Box<()>` + --> $DIR/impl-transmute-from-returning-box.rs:7:25 + | +LL | pub fn box_factory() -> impl std::mem::TransmuteFrom() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ analyzing the transmutability of `Box<()>` is not yet supported +... +LL | Box::new(()) + | ------------ return type was inferred to be `Box<()>` here + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0220, E0277. +For more information about an error, try `rustc --explain E0220`. diff --git a/tests/ui/transmutability/with-fn-mut-and-impl-sized.rs b/tests/ui/transmutability/with-fn-mut-and-impl-sized.rs new file mode 100644 index 0000000000000..8c2096d8afb8d --- /dev/null +++ b/tests/ui/transmutability/with-fn-mut-and-impl-sized.rs @@ -0,0 +1,15 @@ +// Regression test for: https://github.com/rust-lang/rust/issues/153357 +//@compile-flags: -Znext-solver + +#![feature(transmutability)] +#![feature(unboxed_closures)] + +use std::cell::Ref; + +fn delay C, C: std::mem::TransmuteFrom()>(make: Make) -> impl Sized {} +//~^ ERROR: missing generics for struct `Ref` +//~^^ ERROR: associated type `Output` not found for `TransmuteFrom` + +fn main() { + delay(|0| delay) +} diff --git a/tests/ui/transmutability/with-fn-mut-and-impl-sized.stderr b/tests/ui/transmutability/with-fn-mut-and-impl-sized.stderr new file mode 100644 index 0000000000000..f70f7c7c9aabe --- /dev/null +++ b/tests/ui/transmutability/with-fn-mut-and-impl-sized.stderr @@ -0,0 +1,21 @@ +error[E0107]: missing generics for struct `Ref` + --> $DIR/with-fn-mut-and-impl-sized.rs:9:22 + | +LL | fn delay C, C: std::mem::TransmuteFrom()>(make: Make) -> impl Sized {} + | ^^^ expected 1 generic argument + | +help: add missing generic argument + | +LL | fn delay) -> C, C: std::mem::TransmuteFrom()>(make: Make) -> impl Sized {} + | +++ + +error[E0220]: associated type `Output` not found for `TransmuteFrom` + --> $DIR/with-fn-mut-and-impl-sized.rs:9:46 + | +LL | fn delay C, C: std::mem::TransmuteFrom()>(make: Make) -> impl Sized {} + | ^^^^^^^^^^^^^^^ associated type `Output` not found + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0107, E0220. +For more information about an error, try `rustc --explain E0107`. From e97ea967e2657c24ad05674818dfbd09d3c84182 Mon Sep 17 00:00:00 2001 From: Philip Sampaio Date: Fri, 23 Oct 2026 15:46:28 -0300 Subject: [PATCH 08/49] Add revisions for both old and next solver Suggestion from @lsunsi in the PR :) --- ...l-transmute-from-returning-box.next.stderr | 24 +++++++++++++++++++ ...l-transmute-from-returning-box.old.stderr} | 6 ++--- .../impl-transmute-from-returning-box.rs | 4 +++- ...=> with-fn-mut-and-impl-sized.next.stderr} | 4 ++-- .../with-fn-mut-and-impl-sized.old.stderr | 21 ++++++++++++++++ .../with-fn-mut-and-impl-sized.rs | 4 +++- 6 files changed, 56 insertions(+), 7 deletions(-) create mode 100644 tests/ui/transmutability/impl-transmute-from-returning-box.next.stderr rename tests/ui/transmutability/{impl-transmute-from-returning-box.stderr => impl-transmute-from-returning-box.old.stderr} (86%) rename tests/ui/transmutability/{with-fn-mut-and-impl-sized.stderr => with-fn-mut-and-impl-sized.next.stderr} (89%) create mode 100644 tests/ui/transmutability/with-fn-mut-and-impl-sized.old.stderr diff --git a/tests/ui/transmutability/impl-transmute-from-returning-box.next.stderr b/tests/ui/transmutability/impl-transmute-from-returning-box.next.stderr new file mode 100644 index 0000000000000..eb3db28958cb1 --- /dev/null +++ b/tests/ui/transmutability/impl-transmute-from-returning-box.next.stderr @@ -0,0 +1,24 @@ +error[E0220]: associated type `Output` not found for `TransmuteFrom` + --> $DIR/impl-transmute-from-returning-box.rs:9:40 + | +LL | pub fn box_factory() -> impl std::mem::TransmuteFrom() { + | ^^^^^^^^^^^^^^^ associated type `Output` not found + +error[E0220]: associated type `Output` not found for `TransmuteFrom` + --> $DIR/impl-transmute-from-returning-box.rs:9:40 + | +LL | pub fn box_factory() -> impl std::mem::TransmuteFrom() { + | ^^^^^^^^^^^^^^^ associated type `Output` not found + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0277]: `()` cannot be safely transmuted into `Box<()>` + --> $DIR/impl-transmute-from-returning-box.rs:9:25 + | +LL | pub fn box_factory() -> impl std::mem::TransmuteFrom() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ analyzing the transmutability of `Box<()>` is not yet supported + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0220, E0277. +For more information about an error, try `rustc --explain E0220`. diff --git a/tests/ui/transmutability/impl-transmute-from-returning-box.stderr b/tests/ui/transmutability/impl-transmute-from-returning-box.old.stderr similarity index 86% rename from tests/ui/transmutability/impl-transmute-from-returning-box.stderr rename to tests/ui/transmutability/impl-transmute-from-returning-box.old.stderr index 25b3d6d03d422..5c6e8a1686f65 100644 --- a/tests/ui/transmutability/impl-transmute-from-returning-box.stderr +++ b/tests/ui/transmutability/impl-transmute-from-returning-box.old.stderr @@ -1,11 +1,11 @@ error[E0220]: associated type `Output` not found for `TransmuteFrom` - --> $DIR/impl-transmute-from-returning-box.rs:7:40 + --> $DIR/impl-transmute-from-returning-box.rs:9:40 | LL | pub fn box_factory() -> impl std::mem::TransmuteFrom() { | ^^^^^^^^^^^^^^^ associated type `Output` not found error[E0220]: associated type `Output` not found for `TransmuteFrom` - --> $DIR/impl-transmute-from-returning-box.rs:7:40 + --> $DIR/impl-transmute-from-returning-box.rs:9:40 | LL | pub fn box_factory() -> impl std::mem::TransmuteFrom() { | ^^^^^^^^^^^^^^^ associated type `Output` not found @@ -13,7 +13,7 @@ LL | pub fn box_factory() -> impl std::mem::TransmuteFrom() { = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: `()` cannot be safely transmuted into `Box<()>` - --> $DIR/impl-transmute-from-returning-box.rs:7:25 + --> $DIR/impl-transmute-from-returning-box.rs:9:25 | LL | pub fn box_factory() -> impl std::mem::TransmuteFrom() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ analyzing the transmutability of `Box<()>` is not yet supported diff --git a/tests/ui/transmutability/impl-transmute-from-returning-box.rs b/tests/ui/transmutability/impl-transmute-from-returning-box.rs index 15f0c6f2baa9b..7631acd96fa54 100644 --- a/tests/ui/transmutability/impl-transmute-from-returning-box.rs +++ b/tests/ui/transmutability/impl-transmute-from-returning-box.rs @@ -1,5 +1,7 @@ // Regression test for: https://github.com/rust-lang/rust/issues/154536 -// @compile-flags: -Znext-solver +//@ revisions: old next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ [next] compile-flags: -Znext-solver #![feature(transmutability)] #![feature(unboxed_closures)] diff --git a/tests/ui/transmutability/with-fn-mut-and-impl-sized.stderr b/tests/ui/transmutability/with-fn-mut-and-impl-sized.next.stderr similarity index 89% rename from tests/ui/transmutability/with-fn-mut-and-impl-sized.stderr rename to tests/ui/transmutability/with-fn-mut-and-impl-sized.next.stderr index f70f7c7c9aabe..70bcfc07bb2d8 100644 --- a/tests/ui/transmutability/with-fn-mut-and-impl-sized.stderr +++ b/tests/ui/transmutability/with-fn-mut-and-impl-sized.next.stderr @@ -1,5 +1,5 @@ error[E0107]: missing generics for struct `Ref` - --> $DIR/with-fn-mut-and-impl-sized.rs:9:22 + --> $DIR/with-fn-mut-and-impl-sized.rs:11:22 | LL | fn delay C, C: std::mem::TransmuteFrom()>(make: Make) -> impl Sized {} | ^^^ expected 1 generic argument @@ -10,7 +10,7 @@ LL | fn delay) -> C, C: std::mem::TransmuteFrom()>(make: Make | +++ error[E0220]: associated type `Output` not found for `TransmuteFrom` - --> $DIR/with-fn-mut-and-impl-sized.rs:9:46 + --> $DIR/with-fn-mut-and-impl-sized.rs:11:46 | LL | fn delay C, C: std::mem::TransmuteFrom()>(make: Make) -> impl Sized {} | ^^^^^^^^^^^^^^^ associated type `Output` not found diff --git a/tests/ui/transmutability/with-fn-mut-and-impl-sized.old.stderr b/tests/ui/transmutability/with-fn-mut-and-impl-sized.old.stderr new file mode 100644 index 0000000000000..70bcfc07bb2d8 --- /dev/null +++ b/tests/ui/transmutability/with-fn-mut-and-impl-sized.old.stderr @@ -0,0 +1,21 @@ +error[E0107]: missing generics for struct `Ref` + --> $DIR/with-fn-mut-and-impl-sized.rs:11:22 + | +LL | fn delay C, C: std::mem::TransmuteFrom()>(make: Make) -> impl Sized {} + | ^^^ expected 1 generic argument + | +help: add missing generic argument + | +LL | fn delay) -> C, C: std::mem::TransmuteFrom()>(make: Make) -> impl Sized {} + | +++ + +error[E0220]: associated type `Output` not found for `TransmuteFrom` + --> $DIR/with-fn-mut-and-impl-sized.rs:11:46 + | +LL | fn delay C, C: std::mem::TransmuteFrom()>(make: Make) -> impl Sized {} + | ^^^^^^^^^^^^^^^ associated type `Output` not found + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0107, E0220. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/transmutability/with-fn-mut-and-impl-sized.rs b/tests/ui/transmutability/with-fn-mut-and-impl-sized.rs index 8c2096d8afb8d..b98b573fcda11 100644 --- a/tests/ui/transmutability/with-fn-mut-and-impl-sized.rs +++ b/tests/ui/transmutability/with-fn-mut-and-impl-sized.rs @@ -1,5 +1,7 @@ // Regression test for: https://github.com/rust-lang/rust/issues/153357 -//@compile-flags: -Znext-solver +//@ revisions: old next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ [next] compile-flags: -Znext-solver #![feature(transmutability)] #![feature(unboxed_closures)] From 74ef3f56b6d41398dc832cdec40948c26433ba6f Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 21 Oct 2026 15:42:14 +0200 Subject: [PATCH 09/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 10/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 11/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 12/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 13/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 14/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 15/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 16/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 8c3a4b06b9c47feda3d470e00b5c2ddbcd3ce126 Mon Sep 17 00:00:00 2001 From: zakrad <49591476+zakrad@users.noreply.github.com> Date: Sun, 25 Oct 2026 17:50:01 +0330 Subject: [PATCH 17/49] Add codegen test for power of two implying nonzero with debuginfo --- ...o-implies-nonzero-with-debuginfo-137359.rs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 tests/codegen-llvm/issues/power-of-two-implies-nonzero-with-debuginfo-137359.rs diff --git a/tests/codegen-llvm/issues/power-of-two-implies-nonzero-with-debuginfo-137359.rs b/tests/codegen-llvm/issues/power-of-two-implies-nonzero-with-debuginfo-137359.rs new file mode 100644 index 0000000000000..4cd15000e7bbf --- /dev/null +++ b/tests/codegen-llvm/issues/power-of-two-implies-nonzero-with-debuginfo-137359.rs @@ -0,0 +1,32 @@ +//! Regression test for . +//! +//! With debuginfo enabled, LLVM did not use the fact that a power of two +//! is never zero. + +//@ compile-flags: -Copt-level=3 -Cdebuginfo=2 +//@ min-llvm-version: 23 + +#![crate_type = "lib"] + +use std::hint::assert_unchecked; + +// CHECK-LABEL: @power_of_two_is_nonzero +#[no_mangle] +pub unsafe fn power_of_two_is_nonzero(x: u32) -> bool { + // CHECK-NOT: icmp + // CHECK: ret i1 false + assert_unchecked(x.is_power_of_two()); + x == 0 +} + +// CHECK-LABEL: @rem_by_power_of_two +#[no_mangle] +pub unsafe fn rem_by_power_of_two(x: u32, y: u32) -> u32 { + // CHECK-NOT: urem + // CHECK-NOT: panic + // CHECK: %[[MASK:.+]] = add i32 %y, -1 + // CHECK: %[[REM:.+]] = and i32 %[[MASK]], %x + // CHECK: ret i32 %[[REM]] + assert_unchecked(y.is_power_of_two()); + x % y +} From badf74d846057e6cccf6f82048771ba78a0664bb Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Wed, 9 Sep 2026 00:17:36 +0800 Subject: [PATCH 18/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 19/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 20/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 21/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 22/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 23/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 24/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 25/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 26/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 27/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 28/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 29/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 30/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 31/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 32/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 33/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 34/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 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