From e9ddf54d16ea4563714185cf744fd753c734261a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 22 Mar 2025 13:57:27 +0100 Subject: [PATCH 01/17] Group test diffs by stage in post-merge analysis --- src/ci/citool/src/analysis.rs | 43 ++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/src/ci/citool/src/analysis.rs b/src/ci/citool/src/analysis.rs index 2088ce2962097..98e9be0f35af3 100644 --- a/src/ci/citool/src/analysis.rs +++ b/src/ci/citool/src/analysis.rs @@ -210,6 +210,7 @@ struct TestSuiteData { #[derive(Hash, PartialEq, Eq, Debug, Clone)] struct Test { name: String, + stage: u8, is_doctest: bool, } @@ -218,27 +219,24 @@ fn aggregate_tests(metrics: &JsonRoot) -> TestSuiteData { let mut tests = HashMap::new(); let test_suites = get_test_suites(&metrics); for suite in test_suites { + let stage = match suite.metadata { + TestSuiteMetadata::CargoPackage { stage, .. } => stage, + TestSuiteMetadata::Compiletest { stage, .. } => stage, + } as u8; for test in &suite.tests { // Poor man's detection of doctests based on the "(line XYZ)" suffix let is_doctest = matches!(suite.metadata, TestSuiteMetadata::CargoPackage { .. }) && test.name.contains("(line"); - let test_entry = Test { name: generate_test_name(&test.name, &suite), is_doctest }; + let test_entry = Test { name: generate_test_name(&test.name), stage, is_doctest }; tests.insert(test_entry, test.outcome.clone()); } } TestSuiteData { tests } } -/// Normalizes Windows-style path delimiters to Unix-style paths -/// and adds suite metadata to the test name. -fn generate_test_name(name: &str, suite: &TestSuite) -> String { - let name = name.replace('\\', "/"); - let stage = match suite.metadata { - TestSuiteMetadata::CargoPackage { stage, .. } => stage, - TestSuiteMetadata::Compiletest { stage, .. } => stage, - }; - - format!("{name} (stage {stage})") +/// Normalizes Windows-style path delimiters to Unix-style paths. +fn generate_test_name(name: &str) -> String { + name.replace('\\', "/") } /// Prints test changes in Markdown format to stdout. @@ -321,16 +319,25 @@ fn report_test_diffs(diff: AggregatedTestDiffs) { // Sort diffs by job group and test name grouped_diffs.sort_by(|(d1, g1), (d2, g2)| g1.cmp(&g2).then(d1.test.name.cmp(&d2.test.name))); + // Now group the tests by stage + let mut grouped_by_stage: BTreeMap> = Default::default(); + for (diff, group) in grouped_diffs { + grouped_by_stage.entry(diff.test.stage).or_default().push((diff, group)) + } + output_details( &format!("Show {} test {}\n", original_diff_count, pluralize("diff", original_diff_count)), || { - for (diff, job_group) in grouped_diffs { - println!( - "- `{}`: {} ({})", - diff.test.name, - format_diff(&diff.diff), - format_job_group(job_group) - ); + for (stage, diffs) in grouped_by_stage { + println!("## Stage {stage}"); + for (diff, job_group) in diffs { + println!( + "- `{}`: {} ({})", + diff.test.name, + format_diff(&diff.diff), + format_job_group(job_group) + ); + } } let extra_diffs = diffs.len().saturating_sub(max_diff_count); From eb3707e4b49e7d19d048cf2187d6e3643be9dba2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 6 Mar 2025 20:50:51 +0000 Subject: [PATCH 02/17] Stabilize precise_capturing_in_traits --- compiler/rustc_ast_lowering/messages.ftl | 3 --- compiler/rustc_ast_lowering/src/errors.rs | 8 ------- compiler/rustc_ast_lowering/src/lib.rs | 22 ------------------- compiler/rustc_feature/src/accepted.rs | 2 ++ compiler/rustc_feature/src/unstable.rs | 2 -- ...eature-gate-precise_capturing_in_traits.rs | 6 ----- ...re-gate-precise_capturing_in_traits.stderr | 13 ----------- tests/ui/impl-trait/in-trait/dump.rs | 2 +- .../ui/impl-trait/in-trait/refine-captures.rs | 2 -- .../in-trait/refine-captures.stderr | 8 +++---- tests/ui/impl-trait/in-trait/variance.rs | 2 +- .../forgot-to-capture-type.rs | 2 -- .../forgot-to-capture-type.stderr | 4 ++-- .../impl-trait/precise-capturing/redundant.rs | 1 - .../precise-capturing/redundant.stderr | 10 ++++----- .../rpitit-captures-more-method-lifetimes.rs | 2 -- ...itit-captures-more-method-lifetimes.stderr | 4 ++-- .../rpitit-impl-captures-too-much.rs | 2 -- .../rpitit-impl-captures-too-much.stderr | 4 ++-- .../precise-capturing/rpitit-outlives-2.rs | 2 -- .../precise-capturing/rpitit-outlives.rs | 2 -- .../ui/impl-trait/precise-capturing/rpitit.rs | 2 -- .../precise-capturing/rpitit.stderr | 6 ++--- .../precise-capturing/self-capture.rs | 2 -- 24 files changed, 22 insertions(+), 91 deletions(-) delete mode 100644 tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.rs delete mode 100644 tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.stderr diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 65e5b530bbe3b..5ef76fb64aaf2 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -141,9 +141,6 @@ ast_lowering_never_pattern_with_guard = ast_lowering_no_precise_captures_on_apit = `use<...>` precise capturing syntax not allowed in argument-position `impl Trait` -ast_lowering_no_precise_captures_on_rpitit = `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits - .note = currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope - ast_lowering_previously_used_here = previously used here ast_lowering_register1 = register `{$reg1_name}` diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index ceeb5dffbea04..576fa9731e906 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -444,14 +444,6 @@ pub(crate) struct NoPreciseCapturesOnApit { pub span: Span, } -#[derive(Diagnostic)] -#[diag(ast_lowering_no_precise_captures_on_rpitit)] -#[note] -pub(crate) struct NoPreciseCapturesOnRpitit { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(ast_lowering_yield_in_closure)] pub(crate) struct YieldInClosure { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index e08850da4a7a8..787706597368f 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1438,28 +1438,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // frequently opened issues show. let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None); - // Feature gate for RPITIT + use<..> - match origin { - rustc_hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: Some(_), .. } => { - if !self.tcx.features().precise_capturing_in_traits() - && let Some(span) = bounds.iter().find_map(|bound| match *bound { - ast::GenericBound::Use(_, span) => Some(span), - _ => None, - }) - { - let mut diag = - self.tcx.dcx().create_err(errors::NoPreciseCapturesOnRpitit { span }); - add_feature_diagnostics( - &mut diag, - self.tcx.sess, - sym::precise_capturing_in_traits, - ); - diag.emit(); - } - } - _ => {} - } - self.lower_opaque_inner(opaque_ty_node_id, origin, opaque_ty_span, |this| { this.lower_param_bounds(bounds, itctx) }) diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 980f394603549..88e6593572bc6 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -331,6 +331,8 @@ declare_features! ( (accepted, pattern_parentheses, "1.31.0", Some(51087)), /// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args. (accepted, precise_capturing, "1.82.0", Some(123432)), + /// Allows `use<..>` precise capturign on impl Trait in traits. + (accepted, precise_capturing_in_traits, "CURRENT_RUSTC_VERSION", Some(130044)), /// Allows procedural macros in `proc-macro` crates. (accepted, proc_macro, "1.29.0", Some(38356)), /// Allows multi-segment paths in attributes and derives. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 4707daea08910..72468dd4714d7 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -600,8 +600,6 @@ declare_features! ( (incomplete, pin_ergonomics, "1.83.0", Some(130494)), /// Allows postfix match `expr.match { ... }` (unstable, postfix_match, "1.79.0", Some(121618)), - /// Allows `use<..>` precise capturign on impl Trait in traits. - (unstable, precise_capturing_in_traits, "1.83.0", Some(130044)), /// Allows macro attributes on expressions, statements and non-inline modules. (unstable, proc_macro_hygiene, "1.30.0", Some(54727)), /// Allows the use of raw-dylibs on ELF platforms diff --git a/tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.rs b/tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.rs deleted file mode 100644 index 308b41dfc68ab..0000000000000 --- a/tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.rs +++ /dev/null @@ -1,6 +0,0 @@ -trait Foo { - fn test() -> impl Sized + use; - //~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position -} - -fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.stderr b/tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.stderr deleted file mode 100644 index b2c6bf61124d9..0000000000000 --- a/tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits - --> $DIR/feature-gate-precise_capturing_in_traits.rs:2:31 - | -LL | fn test() -> impl Sized + use; - | ^^^^^^^^^ - | - = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope - = note: see issue #130044 for more information - = help: add `#![feature(precise_capturing_in_traits)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 1 previous error - diff --git a/tests/ui/impl-trait/in-trait/dump.rs b/tests/ui/impl-trait/in-trait/dump.rs index 47198d5115058..20b0e60702faa 100644 --- a/tests/ui/impl-trait/in-trait/dump.rs +++ b/tests/ui/impl-trait/in-trait/dump.rs @@ -1,6 +1,6 @@ //@ compile-flags: -Zverbose-internals -#![feature(precise_capturing_in_traits, rustc_attrs)] +#![feature(rustc_attrs)] #![rustc_hidden_type_of_opaques] trait Foo { diff --git a/tests/ui/impl-trait/in-trait/refine-captures.rs b/tests/ui/impl-trait/in-trait/refine-captures.rs index e7dffcb52aae3..199cc464c4e52 100644 --- a/tests/ui/impl-trait/in-trait/refine-captures.rs +++ b/tests/ui/impl-trait/in-trait/refine-captures.rs @@ -1,5 +1,3 @@ -#![feature(precise_capturing_in_traits)] - trait LifetimeParam<'a> { fn test() -> impl Sized; } diff --git a/tests/ui/impl-trait/in-trait/refine-captures.stderr b/tests/ui/impl-trait/in-trait/refine-captures.stderr index 166991894d166..6f213f1614499 100644 --- a/tests/ui/impl-trait/in-trait/refine-captures.stderr +++ b/tests/ui/impl-trait/in-trait/refine-captures.stderr @@ -1,5 +1,5 @@ warning: impl trait in impl method captures fewer lifetimes than in trait - --> $DIR/refine-captures.rs:8:31 + --> $DIR/refine-captures.rs:6:31 | LL | fn test() -> impl Sized + use<> {} | ^^^^^ @@ -13,7 +13,7 @@ LL | fn test() -> impl Sized + use<'a> {} | ++ warning: impl trait in impl method captures fewer lifetimes than in trait - --> $DIR/refine-captures.rs:22:31 + --> $DIR/refine-captures.rs:20:31 | LL | fn test() -> impl Sized + use<> {} | ^^^^^ @@ -26,7 +26,7 @@ LL | fn test() -> impl Sized + use<'a> {} | ++ warning: impl trait in impl method captures fewer lifetimes than in trait - --> $DIR/refine-captures.rs:27:31 + --> $DIR/refine-captures.rs:25:31 | LL | fn test() -> impl Sized + use<'b> {} | ^^^^^^^ @@ -39,7 +39,7 @@ LL | fn test() -> impl Sized + use<'a, 'b> {} | ++++ error: `impl Trait` must mention all type parameters in scope in `use<...>` - --> $DIR/refine-captures.rs:32:18 + --> $DIR/refine-captures.rs:30:18 | LL | impl TypeParam for u64 { | - type parameter is implicitly captured by this `impl Trait` diff --git a/tests/ui/impl-trait/in-trait/variance.rs b/tests/ui/impl-trait/in-trait/variance.rs index cd2f43fca9a67..c0f569c690abf 100644 --- a/tests/ui/impl-trait/in-trait/variance.rs +++ b/tests/ui/impl-trait/in-trait/variance.rs @@ -1,4 +1,4 @@ -#![feature(rustc_attrs, precise_capturing_in_traits)] +#![feature(rustc_attrs)] #![allow(internal_features)] #![rustc_variance_of_opaques] diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs index 6c2477c9744ab..1b52b17020195 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs @@ -1,5 +1,3 @@ -#![feature(precise_capturing_in_traits)] - fn type_param() -> impl Sized + use<> {} //~^ ERROR `impl Trait` must mention all type parameters in scope diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr index 93b44a0c18c27..93c35203f1dcb 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr @@ -1,5 +1,5 @@ error: `impl Trait` must mention all type parameters in scope in `use<...>` - --> $DIR/forgot-to-capture-type.rs:3:23 + --> $DIR/forgot-to-capture-type.rs:1:23 | LL | fn type_param() -> impl Sized + use<> {} | - ^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | fn type_param() -> impl Sized + use<> {} = note: currently, all type parameters are required to be mentioned in the precise captures list error: `impl Trait` must mention the `Self` type of the trait in `use<...>` - --> $DIR/forgot-to-capture-type.rs:7:17 + --> $DIR/forgot-to-capture-type.rs:5:17 | LL | trait Foo { | --------- `Self` type parameter is implicitly captured by this `impl Trait` diff --git a/tests/ui/impl-trait/precise-capturing/redundant.rs b/tests/ui/impl-trait/precise-capturing/redundant.rs index 32dc09273175d..2385827db228e 100644 --- a/tests/ui/impl-trait/precise-capturing/redundant.rs +++ b/tests/ui/impl-trait/precise-capturing/redundant.rs @@ -1,6 +1,5 @@ //@ edition: 2024 -#![feature(precise_capturing_in_traits)] #![deny(impl_trait_redundant_captures)] fn hello<'a>() -> impl Sized + use<'a> {} diff --git a/tests/ui/impl-trait/precise-capturing/redundant.stderr b/tests/ui/impl-trait/precise-capturing/redundant.stderr index 5c8b35c228585..c9f84d360e3c6 100644 --- a/tests/ui/impl-trait/precise-capturing/redundant.stderr +++ b/tests/ui/impl-trait/precise-capturing/redundant.stderr @@ -1,5 +1,5 @@ error: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:6:19 + --> $DIR/redundant.rs:5:19 | LL | fn hello<'a>() -> impl Sized + use<'a> {} | ^^^^^^^^^^^^^------- @@ -7,13 +7,13 @@ LL | fn hello<'a>() -> impl Sized + use<'a> {} | help: remove the `use<...>` syntax | note: the lint level is defined here - --> $DIR/redundant.rs:4:9 + --> $DIR/redundant.rs:3:9 | LL | #![deny(impl_trait_redundant_captures)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:11:27 + --> $DIR/redundant.rs:10:27 | LL | fn inherent(&self) -> impl Sized + use<'_> {} | ^^^^^^^^^^^^^------- @@ -21,7 +21,7 @@ LL | fn inherent(&self) -> impl Sized + use<'_> {} | help: remove the `use<...>` syntax error: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:16:22 + --> $DIR/redundant.rs:15:22 | LL | fn in_trait() -> impl Sized + use<'a, Self>; | ^^^^^^^^^^^^^------------- @@ -29,7 +29,7 @@ LL | fn in_trait() -> impl Sized + use<'a, Self>; | help: remove the `use<...>` syntax error: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:20:22 + --> $DIR/redundant.rs:19:22 | LL | fn in_trait() -> impl Sized + use<'a> {} | ^^^^^^^^^^^^^------- diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs index b39c1408c0509..f6126c0333914 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs +++ b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs @@ -2,8 +2,6 @@ // trait definition, which is not allowed. Due to the default lifetime capture // rules of RPITITs, this is only doable if we use precise capturing. -#![feature(precise_capturing_in_traits)] - pub trait Foo { fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use; } diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.stderr b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.stderr index 45f755d3cc1be..d90660188806e 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.stderr +++ b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.stderr @@ -1,5 +1,5 @@ error: return type captures more lifetimes than trait definition - --> $DIR/rpitit-captures-more-method-lifetimes.rs:12:40 + --> $DIR/rpitit-captures-more-method-lifetimes.rs:10:40 | LL | fn bar<'im: 'im>(&'im mut self) -> impl Sized + use<'im> {} | --- ^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | fn bar<'im: 'im>(&'im mut self) -> impl Sized + use<'im> {} | this lifetime was captured | note: hidden type must only reference lifetimes captured by this impl trait - --> $DIR/rpitit-captures-more-method-lifetimes.rs:8:40 + --> $DIR/rpitit-captures-more-method-lifetimes.rs:6:40 | LL | fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use; | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.rs b/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.rs index b16b0522d6e11..115cab1cb9929 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.rs +++ b/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.rs @@ -1,5 +1,3 @@ -#![feature(precise_capturing_in_traits)] - struct Invariant<'a>(&'a mut &'a mut ()); trait Trait { diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.stderr b/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.stderr index 360f0d7e7f37f..123e0acf171c4 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.stderr +++ b/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.stderr @@ -1,5 +1,5 @@ error: return type captures more lifetimes than trait definition - --> $DIR/rpitit-impl-captures-too-much.rs:10:39 + --> $DIR/rpitit-impl-captures-too-much.rs:8:39 | LL | fn hello(self_: Invariant<'_>) -> impl Sized + use; | -- this lifetime was captured @@ -8,7 +8,7 @@ LL | fn hello(self_: Invariant<'_>) -> impl Sized + use<'_> {} | ^^^^^^^^^^^^^^^^^^^^ | note: hidden type must only reference lifetimes captured by this impl trait - --> $DIR/rpitit-impl-captures-too-much.rs:6:39 + --> $DIR/rpitit-impl-captures-too-much.rs:4:39 | LL | fn hello(self_: Invariant<'_>) -> impl Sized + use; | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-outlives-2.rs b/tests/ui/impl-trait/precise-capturing/rpitit-outlives-2.rs index 6f7e1a0eaefae..6fc129a6480c7 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit-outlives-2.rs +++ b/tests/ui/impl-trait/precise-capturing/rpitit-outlives-2.rs @@ -2,8 +2,6 @@ // Ensure that we skip uncaptured args from RPITITs when comptuing outlives. -#![feature(precise_capturing_in_traits)] - struct Invariant(*mut T); trait Foo { diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-outlives.rs b/tests/ui/impl-trait/precise-capturing/rpitit-outlives.rs index 94d81d766f725..616368d25cf46 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit-outlives.rs +++ b/tests/ui/impl-trait/precise-capturing/rpitit-outlives.rs @@ -3,8 +3,6 @@ // Ensure that we skip uncaptured args from RPITITs when collecting the regions // to enforce member constraints in opaque type inference. -#![feature(precise_capturing_in_traits)] - struct Invariant(*mut T); trait Foo { diff --git a/tests/ui/impl-trait/precise-capturing/rpitit.rs b/tests/ui/impl-trait/precise-capturing/rpitit.rs index 3f887e8e47f1c..91c52817d8573 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit.rs +++ b/tests/ui/impl-trait/precise-capturing/rpitit.rs @@ -3,8 +3,6 @@ // To fix this soundly, we need to make sure that all the trait header args // remain captured, since they affect trait selection. -#![feature(precise_capturing_in_traits)] - fn eq_types(_: T, _: T) {} trait TraitLt<'a: 'a> { diff --git a/tests/ui/impl-trait/precise-capturing/rpitit.stderr b/tests/ui/impl-trait/precise-capturing/rpitit.stderr index 498eae54a1c68..ff461e81079b8 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit.stderr +++ b/tests/ui/impl-trait/precise-capturing/rpitit.stderr @@ -1,5 +1,5 @@ error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list - --> $DIR/rpitit.rs:11:19 + --> $DIR/rpitit.rs:9:19 | LL | trait TraitLt<'a: 'a> { | -- all lifetime parameters originating from a trait are captured implicitly @@ -7,7 +7,7 @@ LL | fn hello() -> impl Sized + use; | ^^^^^^^^^^^^^^^^^^^^^^ error: lifetime may not live long enough - --> $DIR/rpitit.rs:15:5 + --> $DIR/rpitit.rs:13:5 | LL | fn trait_lt<'a, 'b, T: for<'r> TraitLt<'r>> () { | -- -- lifetime `'b` defined here @@ -24,7 +24,7 @@ LL | | ); = help: consider adding the following bound: `'a: 'b` error: lifetime may not live long enough - --> $DIR/rpitit.rs:15:5 + --> $DIR/rpitit.rs:13:5 | LL | fn trait_lt<'a, 'b, T: for<'r> TraitLt<'r>> () { | -- -- lifetime `'b` defined here diff --git a/tests/ui/impl-trait/precise-capturing/self-capture.rs b/tests/ui/impl-trait/precise-capturing/self-capture.rs index 15985da50b55e..66fbfc780438a 100644 --- a/tests/ui/impl-trait/precise-capturing/self-capture.rs +++ b/tests/ui/impl-trait/precise-capturing/self-capture.rs @@ -1,7 +1,5 @@ //@ check-pass -#![feature(precise_capturing_in_traits)] - trait Foo { fn bar<'a>() -> impl Sized + use; } From fbcf7657055a5a562fa7cc176e4bafec9e99c661 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 24 Mar 2025 02:02:10 +0100 Subject: [PATCH 03/17] Revert "resume one waiter at a call" This reverts commit cc1e4ede9388d87750c3751f41e8c6c4f6cae995. --- compiler/rustc_query_system/src/query/job.rs | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 37b305d0a8b50..a8c2aa98cd083 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -477,8 +477,8 @@ fn remove_cycle( /// Detects query cycles by using depth first search over all active query jobs. /// If a query cycle is found it will break the cycle by finding an edge which /// uses a query latch and then resuming that waiter. -/// There may be multiple cycles involved in a deadlock, but we only search -/// one cycle at a call and resume one waiter at once. See `FIXME` below. +/// There may be multiple cycles involved in a deadlock, so this searches +/// all active queries for cycles before finally resuming all the waiters at once. pub fn break_query_cycles(query_map: QueryMap, registry: &rayon_core::Registry) { let mut wakelist = Vec::new(); let mut jobs: Vec = query_map.keys().cloned().collect(); @@ -488,19 +488,6 @@ pub fn break_query_cycles(query_map: QueryMap, registry: &rayon_core::Registry) while jobs.len() > 0 { if remove_cycle(&query_map, &mut jobs, &mut wakelist) { found_cycle = true; - - // FIXME(#137731): Resume all the waiters at once may cause deadlocks, - // so we resume one waiter at a call for now. It's still unclear whether - // it's due to possible issues in rustc-rayon or instead in the handling - // of query cycles. - // This seem to only appear when multiple query cycles errors - // are involved, so this reduction in parallelism, while suboptimal, is not - // universal and only the deadlock handler will encounter these cases. - // The workaround shows loss of potential gains, but there still are big - // improvements in the common case, and no regressions compared to the - // single-threaded case. More investigation is still needed, and once fixed, - // we can wake up all the waiters up. - break; } } From 14786ce645ef96c732f8b30154bc939ee4ba9faf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 24 Mar 2025 02:09:14 +0100 Subject: [PATCH 04/17] Batch mark waiters as unblocked when resuming in the deadlock handler --- compiler/rustc_query_system/src/query/job.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index a8c2aa98cd083..e6ab7c4ef5745 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -506,9 +506,15 @@ pub fn break_query_cycles(query_map: QueryMap, registry: &rayon_core::Registry) ); } - // FIXME: Ensure this won't cause a deadlock before we return + // Mark all the thread we're about to wake up as unblocked. This needs to be done before + // we wake the threads up as otherwise Rayon could detect a deadlock if a thread we + // resumed fell asleep and this thread had yet to mark the remaining threads as unblocked. + for _ in 0..wakelist.len() { + rayon_core::mark_unblocked(registry); + } + for waiter in wakelist.into_iter() { - waiter.notify(registry); + waiter.condvar.notify_one(); } } From b672659472e792198390d94f926be61f894547b6 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Sun, 23 Mar 2025 19:32:20 -0700 Subject: [PATCH 05/17] Trusty: Fix build for anonymous pipes and std::sys::process PRs #136842 (Add libstd support for Trusty targets), #137793 (Stablize anonymous pipe), and #136929 (std: move process implementations to `sys`) merged around the same time, so update Trusty to take them into account. --- library/std/src/os/fd/owned.rs | 9 +++++++-- library/std/src/os/fd/raw.rs | 9 +++++++-- library/std/src/sys/pal/trusty/mod.rs | 2 -- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index 2dcbfc966189d..be73e7dee9c7b 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -15,9 +15,8 @@ use crate::mem::ManuallyDrop; target_os = "trusty" )))] use crate::sys::cvt; -use crate::sys_common::FromInner; #[cfg(not(target_os = "trusty"))] -use crate::sys_common::{AsInner, IntoInner}; +use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::{fmt, io}; type ValidRawFd = core::num::niche_types::NotAllOnes; @@ -507,6 +506,7 @@ impl<'a> AsFd for io::StderrLock<'a> { } #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[cfg(not(target_os = "trusty"))] impl AsFd for io::PipeReader { fn as_fd(&self) -> BorrowedFd<'_> { self.0.as_fd() @@ -514,6 +514,7 @@ impl AsFd for io::PipeReader { } #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[cfg(not(target_os = "trusty"))] impl From for OwnedFd { fn from(pipe: io::PipeReader) -> Self { pipe.0.into_inner() @@ -521,6 +522,7 @@ impl From for OwnedFd { } #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[cfg(not(target_os = "trusty"))] impl AsFd for io::PipeWriter { fn as_fd(&self) -> BorrowedFd<'_> { self.0.as_fd() @@ -528,6 +530,7 @@ impl AsFd for io::PipeWriter { } #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[cfg(not(target_os = "trusty"))] impl From for OwnedFd { fn from(pipe: io::PipeWriter) -> Self { pipe.0.into_inner() @@ -535,6 +538,7 @@ impl From for OwnedFd { } #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[cfg(not(target_os = "trusty"))] impl From for io::PipeReader { fn from(owned_fd: OwnedFd) -> Self { Self(FromInner::from_inner(owned_fd)) @@ -542,6 +546,7 @@ impl From for io::PipeReader { } #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[cfg(not(target_os = "trusty"))] impl From for io::PipeWriter { fn from(owned_fd: OwnedFd) -> Self { Self(FromInner::from_inner(owned_fd)) diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs index 596b21a52044b..c800c1489ad27 100644 --- a/library/std/src/os/fd/raw.rs +++ b/library/std/src/os/fd/raw.rs @@ -18,9 +18,8 @@ use crate::os::unix::io::AsFd; use crate::os::unix::io::OwnedFd; #[cfg(target_os = "wasi")] use crate::os::wasi::io::OwnedFd; -use crate::sys_common::FromInner; #[cfg(not(target_os = "trusty"))] -use crate::sys_common::{AsInner, IntoInner}; +use crate::sys_common::{AsInner, FromInner, IntoInner}; /// Raw file descriptors. #[stable(feature = "rust1", since = "1.0.0")] @@ -287,6 +286,7 @@ impl AsRawFd for Box { } #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[cfg(not(target_os = "trusty"))] impl AsRawFd for io::PipeReader { fn as_raw_fd(&self) -> RawFd { self.0.as_raw_fd() @@ -294,6 +294,7 @@ impl AsRawFd for io::PipeReader { } #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[cfg(not(target_os = "trusty"))] impl FromRawFd for io::PipeReader { unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { Self::from_inner(unsafe { FromRawFd::from_raw_fd(raw_fd) }) @@ -301,6 +302,7 @@ impl FromRawFd for io::PipeReader { } #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[cfg(not(target_os = "trusty"))] impl IntoRawFd for io::PipeReader { fn into_raw_fd(self) -> RawFd { self.0.into_raw_fd() @@ -308,6 +310,7 @@ impl IntoRawFd for io::PipeReader { } #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[cfg(not(target_os = "trusty"))] impl AsRawFd for io::PipeWriter { fn as_raw_fd(&self) -> RawFd { self.0.as_raw_fd() @@ -315,6 +318,7 @@ impl AsRawFd for io::PipeWriter { } #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[cfg(not(target_os = "trusty"))] impl FromRawFd for io::PipeWriter { unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { Self::from_inner(unsafe { FromRawFd::from_raw_fd(raw_fd) }) @@ -322,6 +326,7 @@ impl FromRawFd for io::PipeWriter { } #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[cfg(not(target_os = "trusty"))] impl IntoRawFd for io::PipeWriter { fn into_raw_fd(self) -> RawFd { self.0.into_raw_fd() diff --git a/library/std/src/sys/pal/trusty/mod.rs b/library/std/src/sys/pal/trusty/mod.rs index 7034b643d8e8e..5295d3fdc9145 100644 --- a/library/std/src/sys/pal/trusty/mod.rs +++ b/library/std/src/sys/pal/trusty/mod.rs @@ -11,8 +11,6 @@ pub mod env; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; -#[path = "../unsupported/process.rs"] -pub mod process; #[path = "../unsupported/thread.rs"] pub mod thread; #[path = "../unsupported/time.rs"] From 38c39ffc6c6e19867f450c7204f341aeb0c495ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 24 Mar 2025 03:53:19 +0100 Subject: [PATCH 06/17] Remove `QueryWaiter::notify` --- compiler/rustc_query_system/src/query/job.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index e6ab7c4ef5745..5ed8fb5393fe7 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -163,13 +163,6 @@ struct QueryWaiter { cycle: Mutex>, } -impl QueryWaiter { - fn notify(&self, registry: &rayon_core::Registry) { - rayon_core::mark_unblocked(registry); - self.condvar.notify_one(); - } -} - #[derive(Debug)] struct QueryLatchInfo { complete: bool, @@ -232,7 +225,8 @@ impl QueryLatch { info.complete = true; let registry = rayon_core::Registry::current(); for waiter in info.waiters.drain(..) { - waiter.notify(®istry); + rayon_core::mark_unblocked(®istry); + waiter.condvar.notify_one(); } } From 02e1f118cd5adb995c3801cc7703faaba8910ccc Mon Sep 17 00:00:00 2001 From: Eduard Stefes Date: Mon, 24 Mar 2025 11:54:44 +0100 Subject: [PATCH 07/17] Fix ui pattern_types test for big-endian platforms The newly added pattern types validity tests fail on s390x and presumably other big-endian systems, due to print of raw values with padding bytes. To fix the tests remove the raw output values in the error note by `normalize-stderr`. --- tests/ui/type/pattern_types/validity.rs | 2 ++ tests/ui/type/pattern_types/validity.stderr | 26 ++++++++++----------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/tests/ui/type/pattern_types/validity.rs b/tests/ui/type/pattern_types/validity.rs index 5a6a688e1b305..c61bb71ac252f 100644 --- a/tests/ui/type/pattern_types/validity.rs +++ b/tests/ui/type/pattern_types/validity.rs @@ -1,4 +1,6 @@ //! Check that pattern types have their validity checked +// Strip out raw byte dumps to make tests platform-independent: +//@ normalize-stderr: "([[:xdigit:]]{2}\s){4,8}\s+│\s.{4,8}" -> "HEX_DUMP" #![feature(pattern_types, const_trait_impl, pattern_type_range_trait)] #![feature(pattern_type_macro)] diff --git a/tests/ui/type/pattern_types/validity.stderr b/tests/ui/type/pattern_types/validity.stderr index 5bc18cfba3f7d..b990ec2d3682f 100644 --- a/tests/ui/type/pattern_types/validity.stderr +++ b/tests/ui/type/pattern_types/validity.stderr @@ -1,22 +1,22 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/validity.rs:8:1 + --> $DIR/validity.rs:10:1 | LL | const BAD: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { - 00 00 00 00 │ .... + HEX_DUMP } error[E0080]: evaluation of constant value failed - --> $DIR/validity.rs:11:1 + --> $DIR/validity.rs:13:1 | LL | const BAD_UNINIT: pattern_type!(u32 is 1..) = | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory error[E0080]: evaluation of constant value failed - --> $DIR/validity.rs:15:1 + --> $DIR/validity.rs:17:1 | LL | const BAD_PTR: pattern_type!(usize is 1..) = unsafe { std::mem::transmute(&42) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer @@ -25,53 +25,53 @@ LL | const BAD_PTR: pattern_type!(usize is 1..) = unsafe { std::mem::transmute(& = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/validity.rs:18:1 + --> $DIR/validity.rs:20:1 | LL | const BAD_AGGREGATE: (pattern_type!(u32 is 1..), u32) = (unsafe { std::mem::transmute(0) }, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { - 00 00 00 00 00 00 00 00 │ ........ + HEX_DUMP } error[E0080]: it is undefined behavior to use this value - --> $DIR/validity.rs:24:1 + --> $DIR/validity.rs:26:1 | LL | const BAD_FOO: Foo = Foo(Bar(unsafe { std::mem::transmute(0) })); | ^^^^^^^^^^^^^^^^^^ constructing invalid value at .0.0: encountered 0, but expected something greater or equal to 1 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { - 00 00 00 00 │ .... + HEX_DUMP } error[E0080]: evaluation of constant value failed - --> $DIR/validity.rs:27:1 + --> $DIR/validity.rs:29:1 | LL | const CHAR_UNINIT: pattern_type!(char is 'A'..'Z') = | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory error[E0080]: it is undefined behavior to use this value - --> $DIR/validity.rs:31:1 + --> $DIR/validity.rs:33:1 | LL | const CHAR_OOB_PAT: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute('a') }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 97, but expected something in the range 65..=89 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { - 61 00 00 00 │ a... + HEX_DUMP } error[E0080]: it is undefined behavior to use this value - --> $DIR/validity.rs:34:1 + --> $DIR/validity.rs:36:1 | LL | const CHAR_OOB: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute(u32::MAX) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { - ff ff ff ff │ .... + HEX_DUMP } error: aborting due to 8 previous errors From 43653c1835d59de69c6a5977b52df4708e6fddca Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 23 Mar 2025 22:13:52 +0300 Subject: [PATCH 08/17] linker: Fix staticlib naming for UEFI It uses `libname.a` instead of the standard MSVC naming `name.lib`. Naming for import libraries isn't touched. --- compiler/rustc_codegen_ssa/src/back/link.rs | 7 ++++++- compiler/rustc_codegen_ssa/src/back/linker.rs | 10 +++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 74597f6263d4f..99b4591051af1 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1494,7 +1494,12 @@ fn print_native_static_libs( | NativeLibKind::Unspecified => { let verbatim = lib.verbatim; if sess.target.is_like_msvc { - Some(format!("{}{}", name, if verbatim { "" } else { ".lib" })) + let (prefix, suffix) = if verbatim { + ("", "") + } else { + (&*sess.target.staticlib_prefix, &*sess.target.staticlib_suffix) + }; + Some(format!("{prefix}{name}{suffix}")) } else if sess.target.linker_flavor.is_gnu() { Some(format!("-l{}{}", if verbatim { ":" } else { "" }, name)) } else { diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 3f5e0c1bce9c1..7f24d79b83b28 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -958,9 +958,13 @@ impl<'a> Linker for MsvcLinker<'a> { if let Some(path) = try_find_native_static_library(self.sess, name, verbatim) { self.link_staticlib_by_path(&path, whole_archive); } else { - let prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" }; - let suffix = if verbatim { "" } else { ".lib" }; - self.link_arg(format!("{prefix}{name}{suffix}")); + let opts = if whole_archive { "/WHOLEARCHIVE:" } else { "" }; + let (prefix, suffix) = if verbatim { + ("", "") + } else { + (&*self.sess.target.staticlib_prefix, &*self.sess.target.staticlib_suffix) + }; + self.link_arg(format!("{opts}{prefix}{name}{suffix}")); } } From 27e95f95e6dfcc1effa1f106c90fe53ab2236b76 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 23 Mar 2025 22:18:21 +0300 Subject: [PATCH 09/17] linker: Avoid calling `linker_and_flavor` twice --- compiler/rustc_codegen_ssa/src/back/link.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 99b4591051af1..360f6d82dbc32 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -670,7 +670,7 @@ fn link_natively( ) { info!("preparing {:?} to {:?}", crate_type, out_filename); let (linker_path, flavor) = linker_and_flavor(sess); - let self_contained_components = self_contained_components(sess, crate_type); + let self_contained_components = self_contained_components(sess, crate_type, &linker_path); // On AIX, we ship all libraries as .a big_af archive // the expected format is lib.a(libname.so) for the actual @@ -1788,8 +1788,7 @@ fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind { } // Returns true if linker is located within sysroot -fn detect_self_contained_mingw(sess: &Session) -> bool { - let (linker, _) = linker_and_flavor(sess); +fn detect_self_contained_mingw(sess: &Session, linker: &Path) -> bool { // Assume `-C linker=rust-lld` as self-contained mode if linker == Path::new("rust-lld") { return true; @@ -1797,7 +1796,7 @@ fn detect_self_contained_mingw(sess: &Session) -> bool { let linker_with_extension = if cfg!(windows) && linker.extension().is_none() { linker.with_extension("exe") } else { - linker + linker.to_path_buf() }; for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) { let full_path = dir.join(&linker_with_extension); @@ -1812,7 +1811,11 @@ fn detect_self_contained_mingw(sess: &Session) -> bool { /// Various toolchain components used during linking are used from rustc distribution /// instead of being found somewhere on the host system. /// We only provide such support for a very limited number of targets. -fn self_contained_components(sess: &Session, crate_type: CrateType) -> LinkSelfContainedComponents { +fn self_contained_components( + sess: &Session, + crate_type: CrateType, + linker: &Path, +) -> LinkSelfContainedComponents { // Turn the backwards compatible bool values for `self_contained` into fully inferred // `LinkSelfContainedComponents`. let self_contained = @@ -1841,7 +1844,7 @@ fn self_contained_components(sess: &Session, crate_type: CrateType) -> LinkSelfC LinkSelfContainedDefault::InferredForMingw => { sess.host == sess.target && sess.target.vendor != "uwp" - && detect_self_contained_mingw(sess) + && detect_self_contained_mingw(sess, linker) } } }; From 7c55782e0c1d01dfd7ceab3b4e682c12e24308d8 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 25 Mar 2025 00:00:10 +0300 Subject: [PATCH 10/17] rustc_session: Add a helper function for obtaining staticlib prefix and suffix --- compiler/rustc_codegen_ssa/src/back/link.rs | 6 +----- compiler/rustc_codegen_ssa/src/back/linker.rs | 11 ++++------ compiler/rustc_metadata/src/native_libs.rs | 21 +++++++++---------- compiler/rustc_session/src/output.rs | 2 +- compiler/rustc_session/src/session.rs | 8 +++++++ 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 360f6d82dbc32..a564e0e391fee 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1494,11 +1494,7 @@ fn print_native_static_libs( | NativeLibKind::Unspecified => { let verbatim = lib.verbatim; if sess.target.is_like_msvc { - let (prefix, suffix) = if verbatim { - ("", "") - } else { - (&*sess.target.staticlib_prefix, &*sess.target.staticlib_suffix) - }; + let (prefix, suffix) = sess.staticlib_components(verbatim); Some(format!("{prefix}{name}{suffix}")) } else if sess.target.linker_flavor.is_gnu() { Some(format!("-l{}{}", if verbatim { ":" } else { "" }, name)) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 7f24d79b83b28..bcf18cf57be23 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -450,9 +450,10 @@ impl<'a> GccLinker<'a> { // The output filename already contains `dll_suffix` so // the resulting import library will have a name in the // form of libfoo.dll.a - let mut implib_name = OsString::from(&*self.sess.target.staticlib_prefix); + let (prefix, suffix) = self.sess.staticlib_components(false); + let mut implib_name = OsString::from(prefix); implib_name.push(name); - implib_name.push(&*self.sess.target.staticlib_suffix); + implib_name.push(suffix); let mut out_implib = OsString::from("--out-implib="); out_implib.push(out_filename.with_file_name(implib_name)); self.link_arg(out_implib); @@ -959,11 +960,7 @@ impl<'a> Linker for MsvcLinker<'a> { self.link_staticlib_by_path(&path, whole_archive); } else { let opts = if whole_archive { "/WHOLEARCHIVE:" } else { "" }; - let (prefix, suffix) = if verbatim { - ("", "") - } else { - (&*self.sess.target.staticlib_prefix, &*self.sess.target.staticlib_suffix) - }; + let (prefix, suffix) = self.sess.staticlib_components(verbatim); self.link_arg(format!("{opts}{prefix}{name}{suffix}")); } } diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 1671b7e06b0af..f63ae8079dcd4 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -95,14 +95,14 @@ pub fn try_find_native_static_library( name: &str, verbatim: bool, ) -> Option { + let default = sess.staticlib_components(verbatim); let formats = if verbatim { - vec![("".into(), "".into())] + vec![default] } else { - let os = (sess.target.staticlib_prefix.clone(), sess.target.staticlib_suffix.clone()); // On Windows, static libraries sometimes show up as libfoo.a and other // times show up as foo.lib - let unix = ("lib".into(), ".a".into()); - if os == unix { vec![os] } else { vec![os, unix] } + let unix = ("lib", ".a"); + if default == unix { vec![default] } else { vec![default, unix] } }; walk_native_lib_search_dirs(sess, None, |dir, is_framework| { @@ -124,18 +124,17 @@ pub fn try_find_native_dynamic_library( name: &str, verbatim: bool, ) -> Option { + let default = sess.staticlib_components(verbatim); let formats = if verbatim { - vec![("".into(), "".into())] + vec![default] } else { // While the official naming convention for MSVC import libraries - // is foo.lib... - let os = (sess.target.staticlib_prefix.clone(), sess.target.staticlib_suffix.clone()); - // ... Meson follows the libfoo.dll.a convention to + // is foo.lib, Meson follows the libfoo.dll.a convention to // disambiguate .a for static libraries - let meson = ("lib".into(), ".dll.a".into()); + let meson = ("lib", ".dll.a"); // and MinGW uses .a altogether - let mingw = ("lib".into(), ".a".into()); - vec![os, meson, mingw] + let mingw = ("lib", ".a"); + vec![default, meson, mingw] }; walk_native_lib_search_dirs(sess, None, |dir, is_framework| { diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index b37a80274c0cb..a24919e434cc5 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -103,7 +103,7 @@ pub fn filename_for_input( OutFileName::Real(outputs.out_directory.join(&format!("{prefix}{libname}{suffix}"))) } CrateType::Staticlib => { - let (prefix, suffix) = (&sess.target.staticlib_prefix, &sess.target.staticlib_suffix); + let (prefix, suffix) = sess.staticlib_components(false); OutFileName::Real(outputs.out_directory.join(&format!("{prefix}{libname}{suffix}"))) } CrateType::Executable => { diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 1c9adea281dc7..a87b1961a9951 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -586,6 +586,14 @@ impl Session { .or(self.target.options.default_visibility) .unwrap_or(SymbolVisibility::Interposable) } + + pub fn staticlib_components(&self, verbatim: bool) -> (&str, &str) { + if verbatim { + ("", "") + } else { + (&*self.target.staticlib_prefix, &*self.target.staticlib_suffix) + } + } } // JUSTIFICATION: defn of the suggested wrapper fns From 1a8ddee65c2a36941d8fe3806beff727a3834d1e Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Mon, 24 Mar 2025 23:01:11 +0100 Subject: [PATCH 11/17] Add target maintainer information for powerpc64-unknown-linux-musl We intend to fix the outstanding issues on the target and eventually promote it to tier 2. We have the capacity to maintain this target in the future and already perform regular builds of rustc for this target. Currently, all host tools except miri build fine, but I have a patch for libffi-sys to make miri also compile fine for this target that is pending review [1]. While at it, add an option for the musl root for this target. [1]: https://github.com/tov/libffi-rs/pull/100 Signed-off-by: Jens Reidel --- src/bootstrap/configure.py | 5 ++ src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 2 +- .../powerpc64-unknown-linux-musl.md | 52 +++++++++++++++++++ 4 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 src/doc/rustc/src/platform-support/powerpc64-unknown-linux-musl.md diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index f6afe09672409..0d4d6e0ff54c6 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -249,6 +249,11 @@ def v(*args): "target.mips64el-unknown-linux-muslabi64.musl-root", "mips64el-unknown-linux-muslabi64 install directory", ) +v( + "musl-root-powerpc64", + "target.powerpc64-unknown-linux-musl.musl-root", + "powerpc64-unknown-linux-musl install directory", +) v( "musl-root-powerpc64le", "target.powerpc64le-unknown-linux-musl.musl-root", diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 542ee9fffce3a..fee61933f5cf2 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -72,6 +72,7 @@ - [powerpc-unknown-linux-gnuspe](platform-support/powerpc-unknown-linux-gnuspe.md) - [powerpc-unknown-linux-muslspe](platform-support/powerpc-unknown-linux-muslspe.md) - [powerpc64-ibm-aix](platform-support/aix.md) + - [powerpc64-unknown-linux-musl](platform-support/powerpc64-unknown-linux-musl.md) - [powerpc64le-unknown-linux-gnu](platform-support/powerpc64le-unknown-linux-gnu.md) - [powerpc64le-unknown-linux-musl](platform-support/powerpc64le-unknown-linux-musl.md) - [riscv32e\*-unknown-none-elf](platform-support/riscv32e-unknown-none-elf.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index e8f8684740ac0..3a8f84069ccc4 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -356,7 +356,7 @@ target | std | host | notes [`powerpc-wrs-vxworks-spe`](platform-support/vxworks.md) | ✓ | | [`powerpc64-ibm-aix`](platform-support/aix.md) | ? | | 64-bit AIX (7.2 and newer) [`powerpc64-unknown-freebsd`](platform-support/freebsd.md) | ✓ | ✓ | PPC64 FreeBSD (ELFv2) -`powerpc64-unknown-linux-musl` | ? | | 64-bit PowerPC Linux with musl 1.2.3 +[`powerpc64-unknown-linux-musl`](platform-support/powerpc64-unknown-linux-musl.md) | ✓ | ✓ | PPC64 Linux (kernel 4.19, musl 1.2.3) [`powerpc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/powerpc64 [`powerpc64-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | [`powerpc64le-unknown-freebsd`](platform-support/freebsd.md) | ✓ | ✓ | PPC64LE FreeBSD diff --git a/src/doc/rustc/src/platform-support/powerpc64-unknown-linux-musl.md b/src/doc/rustc/src/platform-support/powerpc64-unknown-linux-musl.md new file mode 100644 index 0000000000000..0f78dcc089cc1 --- /dev/null +++ b/src/doc/rustc/src/platform-support/powerpc64-unknown-linux-musl.md @@ -0,0 +1,52 @@ +# powerpc64-unknown-linux-musl + +**Tier: 3** + +Target for 64-bit big endian PowerPC Linux programs using musl libc. +This target uses the ELF v2 ABI. + +## Target maintainers + +- [@Gelbpunkt](https://github.com/Gelbpunkt) +- [@famfo](https://github.com/famfo) +- [@neuschaefer](https://github.com/neuschaefer) + +## Requirements + +Building the target itself requires a 64-bit big endian PowerPC compiler that +is supported by `cc-rs`. + +## Building the target + +The target can be built by enabling it for a `rustc` build. + +```toml +[build] +target = ["powerpc64-unknown-linux-musl"] +``` + +Make sure your C compiler is included in `$PATH`, then add it to the +`bootstrap.toml`: + +```toml +[target.powerpc64-unknown-linux-musl] +cc = "powerpc64-linux-musl-gcc" +cxx = "powerpc64-linux-musl-g++" +ar = "powerpc64-linux-musl-ar" +linker = "powerpc64-linux-musl-gcc" +``` + +## Building Rust programs + +Rust does not yet ship pre-compiled artifacts for this target. To compile for +this target, you will first need to build Rust with the target enabled (see +"Building the target" above). + +## Cross-compilation + +This target can be cross-compiled from any host. + +## Testing + +This target can be tested as normal with `x.py` on a 64-bit big endian PowerPC +host or via QEMU emulation. From 90c541d637c0857c6d5b1c3bf835e2f02f7175a9 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Mon, 24 Mar 2025 13:56:45 +0900 Subject: [PATCH 12/17] ignore doctests only in specified targets add necessary lines fix ui test error --- src/librustdoc/html/markdown.rs | 9 +++++---- tests/rustdoc-ui/doctest/per-target-ignores.rs | 14 ++++++++++++++ tests/rustdoc-ui/doctest/per-target-ignores.stdout | 6 ++++++ 3 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 tests/rustdoc-ui/doctest/per-target-ignores.rs create mode 100644 tests/rustdoc-ui/doctest/per-target-ignores.stdout diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 5aab4199d43b1..0d547a6a0d92d 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1201,11 +1201,12 @@ impl LangString { seen_rust_tags = !seen_other_tags; } LangStringToken::LangToken(x) - if let Some(ignore) = x.strip_prefix("ignore-") - && enable_per_target_ignores => + if let Some(ignore) = x.strip_prefix("ignore-") => { - ignores.push(ignore.to_owned()); - seen_rust_tags = !seen_other_tags; + if enable_per_target_ignores { + ignores.push(ignore.to_owned()); + seen_rust_tags = !seen_other_tags; + } } LangStringToken::LangToken("rust") => { data.rust = true; diff --git a/tests/rustdoc-ui/doctest/per-target-ignores.rs b/tests/rustdoc-ui/doctest/per-target-ignores.rs new file mode 100644 index 0000000000000..3dea7099b4be3 --- /dev/null +++ b/tests/rustdoc-ui/doctest/per-target-ignores.rs @@ -0,0 +1,14 @@ +//@ only-aarch64 +//@ compile-flags:--test +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ check-pass + +///```ignore-x86_64 +/// assert!(cfg!(not(target_arch = "x86_64"))); +///``` +pub fn foo() -> u8 { + 4 +} + +fn main() {} diff --git a/tests/rustdoc-ui/doctest/per-target-ignores.stdout b/tests/rustdoc-ui/doctest/per-target-ignores.stdout new file mode 100644 index 0000000000000..fe7282144dd8b --- /dev/null +++ b/tests/rustdoc-ui/doctest/per-target-ignores.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/per-target-ignores.rs - foo (line 7) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + From 6bea9c7a5465e27efbadced28322e6faf78bb174 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 25 Mar 2025 12:50:47 +1100 Subject: [PATCH 13/17] rustdoc: remove useless `Symbol::is_empty` checks. There are a number of `is_empty` checks that can never fail. This commit removes them. --- src/librustdoc/clean/inline.rs | 12 +----- src/librustdoc/formats/cache.rs | 2 +- src/librustdoc/html/render/sidebar.rs | 62 ++++++++++++++++----------- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index e973b89b2375b..4fd669ab6d136 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -211,17 +211,7 @@ pub(crate) fn load_attrs<'hir>(cx: &DocContext<'hir>, did: DefId) -> &'hir [hir: } pub(crate) fn item_relative_path(tcx: TyCtxt<'_>, def_id: DefId) -> Vec { - tcx.def_path(def_id) - .data - .into_iter() - .filter_map(|elem| { - // extern blocks (and a few others things) have an empty name. - match elem.data.get_opt_name() { - Some(s) if !s.is_empty() => Some(s), - _ => None, - } - }) - .collect() + tcx.def_path(def_id).data.into_iter().filter_map(|elem| elem.data.get_opt_name()).collect() } /// Record an external fully qualified name in the external_paths cache. diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 2648641e53e75..e74fd67fbdaf4 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -288,7 +288,7 @@ impl DocFolder for CacheBuilder<'_, '_> { // Keep track of the fully qualified path for this item. let pushed = match item.name { - Some(n) if !n.is_empty() => { + Some(n) => { self.cache.stack.push(n); true } diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index 3130815af0bd0..79719f008645e 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -731,20 +731,20 @@ fn get_methods<'a>( ) -> Vec> { i.items .iter() - .filter_map(|item| match item.name { - Some(ref name) if !name.is_empty() && item.is_method() => { - if !for_deref || super::should_render_item(item, deref_mut, tcx) { - Some(Link::new( - get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::Method)), - name.as_str(), - )) - } else { - None - } + .filter_map(|item| { + if let Some(ref name) = item.name + && item.is_method() + && (!for_deref || super::should_render_item(item, deref_mut, tcx)) + { + Some(Link::new( + get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::Method)), + name.as_str(), + )) + } else { + None } - _ => None, }) - .collect::>() + .collect() } fn get_associated_constants<'a>( @@ -753,14 +753,19 @@ fn get_associated_constants<'a>( ) -> Vec> { i.items .iter() - .filter_map(|item| match item.name { - Some(ref name) if !name.is_empty() && item.is_associated_const() => Some(Link::new( - get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::AssocConst)), - name.as_str(), - )), - _ => None, + .filter_map(|item| { + if let Some(ref name) = item.name + && item.is_associated_const() + { + Some(Link::new( + get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::AssocConst)), + name.as_str(), + )) + } else { + None + } }) - .collect::>() + .collect() } fn get_associated_types<'a>( @@ -769,12 +774,17 @@ fn get_associated_types<'a>( ) -> Vec> { i.items .iter() - .filter_map(|item| match item.name { - Some(ref name) if !name.is_empty() && item.is_associated_type() => Some(Link::new( - get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::AssocType)), - name.as_str(), - )), - _ => None, + .filter_map(|item| { + if let Some(ref name) = item.name + && item.is_associated_type() + { + Some(Link::new( + get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::AssocType)), + name.as_str(), + )) + } else { + None + } }) - .collect::>() + .collect() } From 2bf0c2df147e98ead4297ccc6a62b2f7f6c48c3e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 24 Mar 2025 22:43:44 +0000 Subject: [PATCH 14/17] Make printing define_opaque less goofy --- .../rustc_ast_pretty/src/pprust/state/item.rs | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 6236f8ecfb524..8486e80937819 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -652,13 +652,7 @@ impl<'a> State<'a> { ) { let ast::Fn { defaultness, generics, sig, contract, body, define_opaque } = func; - if let Some(define_opaque) = define_opaque { - for (_, path) in define_opaque { - self.word("define opaques from "); - self.print_path(path, false, 0); - self.word(","); - } - } + self.print_define_opaques(define_opaque); if body.is_some() { self.head(""); @@ -678,6 +672,24 @@ impl<'a> State<'a> { } } + fn print_define_opaques( + &mut self, + define_opaque: Option<&[(ast::NodeId, ast::Path)]>, + ) { + if let Some(define_opaque) = define_opaque { + self.word("#[define_opaque("); + for (i, (_, path)) in define_opaque.iter().enumerate() { + if i != 0 { + self.word_space(","); + } + + self.print_path(path, false, 0); + } + self.word(")]"); + } + self.hardbreak_if_not_bol(); + } + fn print_contract(&mut self, contract: &ast::FnContract) { if let Some(pred) = &contract.requires { self.word("rustc_requires"); From f8df298d74ad4a385ca0b14e65ae154a9b8fa5c5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 24 Mar 2025 23:19:18 +0000 Subject: [PATCH 15/17] Allow defining opaques in statics and consts --- compiler/rustc_ast/src/ast.rs | 2 + compiler/rustc_ast/src/mut_visit.rs | 54 +++++++++----- compiler/rustc_ast/src/visit.rs | 53 ++++++++++++-- compiler/rustc_ast_lowering/src/item.rs | 72 ++++++++++++++----- .../rustc_ast_pretty/src/pprust/state/item.rs | 65 +++++++++++------ .../rustc_builtin_macros/src/define_opaque.rs | 5 ++ compiler/rustc_builtin_macros/src/test.rs | 1 + compiler/rustc_expand/src/build.rs | 11 ++- compiler/rustc_parse/src/parser/item.rs | 13 +++- compiler/rustc_resolve/src/def_collector.rs | 8 ++- compiler/rustc_resolve/src/late.rs | 51 +++++++++---- .../clippy/clippy_utils/src/ast_utils/mod.rs | 8 +++ tests/ui/impl-trait/define-via-const.rs | 12 ++++ .../ui/type-alias-impl-trait/issue-53092-2.rs | 5 +- .../issue-53092-2.stderr | 51 ++++++++----- .../type-alias-impl-trait-const.rs | 10 +-- .../type-alias-impl-trait-const.stderr | 57 --------------- 17 files changed, 315 insertions(+), 163 deletions(-) create mode 100644 tests/ui/impl-trait/define-via-const.rs delete mode 100644 tests/ui/type-alias-impl-trait/type-alias-impl-trait-const.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 5b7545b339663..fd27be2132614 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3535,6 +3535,7 @@ pub struct StaticItem { pub safety: Safety, pub mutability: Mutability, pub expr: Option>, + pub define_opaque: Option>, } #[derive(Clone, Encodable, Decodable, Debug)] @@ -3543,6 +3544,7 @@ pub struct ConstItem { pub generics: Generics, pub ty: P, pub expr: Option>, + pub define_opaque: Option>, } // Adding a new variant? Please update `test_item` in `tests/ui/macros/stringify.rs`. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 4edd086430000..b8d85958bfd76 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -987,10 +987,7 @@ fn walk_fn(vis: &mut T, kind: FnKind<'_>) { } vis.visit_span(span); - for (id, path) in define_opaque.iter_mut().flatten() { - vis.visit_id(id); - vis.visit_path(path) - } + walk_define_opaques(vis, define_opaque); } FnKind::Closure(binder, coroutine_kind, decl, body) => { vis.visit_closure_binder(binder); @@ -1258,12 +1255,19 @@ impl WalkItemKind for ItemKind { match self { ItemKind::ExternCrate(_orig_name) => {} ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree), - ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => { + ItemKind::Static(box StaticItem { + ty, + safety: _, + mutability: _, + expr, + define_opaque, + }) => { vis.visit_ty(ty); visit_opt(expr, |expr| vis.visit_expr(expr)); + walk_define_opaques(vis, define_opaque); } ItemKind::Const(item) => { - visit_const_item(item, vis); + walk_const_item(vis, item); } ItemKind::Fn(func) => { vis.visit_fn(FnKind::Fn(FnCtxt::Free, ident, visibility, &mut *func), span, id); @@ -1382,7 +1386,7 @@ impl WalkItemKind for AssocItemKind { ) { match self { AssocItemKind::Const(item) => { - visit_const_item(item, visitor); + walk_const_item(visitor, item); } AssocItemKind::Fn(func) => { visitor.visit_fn( @@ -1442,14 +1446,13 @@ impl WalkItemKind for AssocItemKind { } } -fn visit_const_item( - ConstItem { defaultness, generics, ty, expr }: &mut ConstItem, - visitor: &mut T, -) { - visit_defaultness(visitor, defaultness); - visitor.visit_generics(generics); - visitor.visit_ty(ty); - visit_opt(expr, |expr| visitor.visit_expr(expr)); +fn walk_const_item(vis: &mut T, item: &mut ConstItem) { + let ConstItem { defaultness, generics, ty, expr, define_opaque } = item; + visit_defaultness(vis, defaultness); + vis.visit_generics(generics); + vis.visit_ty(ty); + visit_opt(expr, |expr| vis.visit_expr(expr)); + walk_define_opaques(vis, define_opaque); } fn walk_fn_header(vis: &mut T, header: &mut FnHeader) { @@ -1526,9 +1529,16 @@ impl WalkItemKind for ForeignItemKind { visitor: &mut impl MutVisitor, ) { match self { - ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => { + ForeignItemKind::Static(box StaticItem { + ty, + mutability: _, + expr, + safety: _, + define_opaque, + }) => { visitor.visit_ty(ty); visit_opt(expr, |expr| visitor.visit_expr(expr)); + walk_define_opaques(visitor, define_opaque); } ForeignItemKind::Fn(func) => { visitor.visit_fn( @@ -1929,6 +1939,18 @@ fn walk_capture_by(vis: &mut T, capture_by: &mut CaptureBy) { } } +fn walk_define_opaques( + vis: &mut T, + define_opaque: &mut Option>, +) { + if let Some(define_opaque) = define_opaque { + for (id, path) in define_opaque { + vis.visit_id(id); + vis.visit_path(path) + } + } +} + /// Some value for the AST node that is valid but possibly meaningless. Similar /// to `Default` but not intended for wide use. The value will never be used /// meaningfully, it exists just to support unwinding in `visit_clobber` in the diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index ce8d6df75afb2..8c0be6f483993 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -16,6 +16,7 @@ pub use rustc_ast_ir::visit::VisitorResult; pub use rustc_ast_ir::{try_visit, visit_opt, walk_list, walk_visitable_list}; use rustc_span::{Ident, Span}; +use thin_vec::ThinVec; use crate::ast::*; use crate::ptr::P; @@ -371,14 +372,28 @@ impl WalkItemKind for ItemKind { match self { ItemKind::ExternCrate(_rename) => {} ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, id, false)), - ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => { + ItemKind::Static(box StaticItem { + ty, + safety: _, + mutability: _, + expr, + define_opaque, + }) => { try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); + try_visit!(walk_define_opaques(visitor, define_opaque)); } - ItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => { + ItemKind::Const(box ConstItem { + defaultness: _, + generics, + ty, + expr, + define_opaque, + }) => { try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); + try_visit!(walk_define_opaques(visitor, define_opaque)); } ItemKind::Fn(func) => { let kind = FnKind::Fn(FnCtxt::Free, ident, vis, &*func); @@ -729,9 +744,16 @@ impl WalkItemKind for ForeignItemKind { visitor: &mut V, ) -> V::Result { match self { - ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => { + ForeignItemKind::Static(box StaticItem { + ty, + mutability: _, + expr, + safety: _, + define_opaque, + }) => { try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); + try_visit!(walk_define_opaques(visitor, define_opaque)); } ForeignItemKind::Fn(func) => { let kind = FnKind::Fn(FnCtxt::Foreign, ident, vis, &*func); @@ -907,9 +929,7 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu try_visit!(visitor.visit_fn_decl(decl)); visit_opt!(visitor, visit_contract, contract); visit_opt!(visitor, visit_block, body); - for (id, path) in define_opaque.iter().flatten() { - try_visit!(visitor.visit_path(path, *id)) - } + try_visit!(walk_define_opaques(visitor, define_opaque)); } FnKind::Closure(binder, coroutine_kind, decl, body) => { try_visit!(visitor.visit_closure_binder(binder)); @@ -933,10 +953,17 @@ impl WalkItemKind for AssocItemKind { visitor: &mut V, ) -> V::Result { match self { - AssocItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => { + AssocItemKind::Const(box ConstItem { + defaultness: _, + generics, + ty, + expr, + define_opaque, + }) => { try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); + try_visit!(walk_define_opaques(visitor, define_opaque)); } AssocItemKind::Fn(func) => { let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, vis, &*func); @@ -1337,3 +1364,15 @@ pub fn walk_attr_args<'a, V: Visitor<'a>>(visitor: &mut V, args: &'a AttrArgs) - } V::Result::output() } + +fn walk_define_opaques<'a, V: Visitor<'a>>( + visitor: &mut V, + define_opaque: &'a Option>, +) -> V::Result { + if let Some(define_opaque) = define_opaque { + for (id, path) in define_opaque { + try_visit!(visitor.visit_path(path, *id)); + } + } + V::Result::output() +} diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 219bf62c916dd..c3031a65dd21d 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -188,14 +188,21 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_use_tree(use_tree, &prefix, id, vis_span, attrs) } - ItemKind::Static(box ast::StaticItem { ty: t, safety: _, mutability: m, expr: e }) => { + ItemKind::Static(box ast::StaticItem { + ty: t, + safety: _, + mutability: m, + expr: e, + define_opaque, + }) => { debug_assert_ne!(ident.name, kw::Empty); let ident = self.lower_ident(ident); let (ty, body_id) = self.lower_const_item(t, span, e.as_deref(), ImplTraitPosition::StaticTy); + self.lower_define_opaque(hir_id, define_opaque); hir::ItemKind::Static(ident, ty, *m, body_id) } - ItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => { + ItemKind::Const(box ast::ConstItem { generics, ty, expr, define_opaque, .. }) => { debug_assert_ne!(ident.name, kw::Empty); let ident = self.lower_ident(ident); let (generics, (ty, body_id)) = self.lower_generics( @@ -206,6 +213,7 @@ impl<'hir> LoweringContext<'_, 'hir> { this.lower_const_item(ty, span, expr.as_deref(), ImplTraitPosition::ConstTy) }, ); + self.lower_define_opaque(hir_id, &define_opaque); hir::ItemKind::Const(ident, ty, generics, body_id) } ItemKind::Fn(box Fn { @@ -243,7 +251,7 @@ impl<'hir> LoweringContext<'_, 'hir> { header: this.lower_fn_header(*header, hir::Safety::Safe, attrs), span: this.lower_span(*fn_sig_span), }; - this.lower_define_opaque(hir_id, &define_opaque); + this.lower_define_opaque(hir_id, define_opaque); let ident = this.lower_ident(ident); hir::ItemKind::Fn { ident, @@ -662,7 +670,7 @@ impl<'hir> LoweringContext<'_, 'hir> { owner_id, ident: self.lower_ident(i.ident), kind: match &i.kind { - ForeignItemKind::Fn(box Fn { sig, generics, .. }) => { + ForeignItemKind::Fn(box Fn { sig, generics, define_opaque, .. }) => { let fdec = &sig.decl; let itctx = ImplTraitContext::Universal; let (generics, (decl, fn_args)) = @@ -683,17 +691,31 @@ impl<'hir> LoweringContext<'_, 'hir> { // Unmarked safety in unsafe block defaults to unsafe. let header = self.lower_fn_header(sig.header, hir::Safety::Unsafe, attrs); + if define_opaque.is_some() { + self.dcx().span_err(i.span, "foreign functions cannot define opaque types"); + } + hir::ForeignItemKind::Fn( hir::FnSig { header, decl, span: self.lower_span(sig.span) }, fn_args, generics, ) } - ForeignItemKind::Static(box StaticItem { ty, mutability, expr: _, safety }) => { + ForeignItemKind::Static(box StaticItem { + ty, + mutability, + expr: _, + safety, + define_opaque, + }) => { let ty = self .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); let safety = self.lower_safety(*safety, hir::Safety::Unsafe); + if define_opaque.is_some() { + self.dcx().span_err(i.span, "foreign statics cannot define opaque types"); + } + hir::ForeignItemKind::Static(ty, *mutability, safety) } ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type, @@ -801,7 +823,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let trait_item_def_id = hir_id.expect_owner(); let (generics, kind, has_default) = match &i.kind { - AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => { + AssocItemKind::Const(box ConstItem { generics, ty, expr, define_opaque, .. }) => { let (generics, kind) = self.lower_generics( generics, i.id, @@ -814,6 +836,18 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::TraitItemKind::Const(ty, body) }, ); + + if define_opaque.is_some() { + if expr.is_some() { + self.lower_define_opaque(hir_id, &define_opaque); + } else { + self.dcx().span_err( + i.span, + "only trait consts with default bodies can define opaque types", + ); + } + } + (generics, kind, expr.is_some()) } AssocItemKind::Fn(box Fn { sig, generics, body: None, define_opaque, .. }) => { @@ -951,18 +985,20 @@ impl<'hir> LoweringContext<'_, 'hir> { let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); let (generics, kind) = match &i.kind { - AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics( - generics, - i.id, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), - |this| { - let ty = - this.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); - let body = this.lower_const_body(i.span, expr.as_deref()); - - hir::ImplItemKind::Const(ty, body) - }, - ), + AssocItemKind::Const(box ConstItem { generics, ty, expr, define_opaque, .. }) => self + .lower_generics( + generics, + i.id, + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + |this| { + let ty = this + .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); + let body = this.lower_const_body(i.span, expr.as_deref()); + this.lower_define_opaque(hir_id, &define_opaque); + + hir::ImplItemKind::Const(ty, body) + }, + ), AssocItemKind::Fn(box Fn { sig, generics, body, contract, define_opaque, .. }) => { let body_id = self.lower_maybe_coroutine_body( sig.span, diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 8486e80937819..d406a56c05da0 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -37,18 +37,23 @@ impl<'a> State<'a> { ast::ForeignItemKind::Fn(func) => { self.print_fn_full(ident, vis, attrs, &*func); } - ast::ForeignItemKind::Static(box ast::StaticItem { ty, mutability, expr, safety }) => { - self.print_item_const( - ident, - Some(*mutability), - &ast::Generics::default(), - ty, - expr.as_deref(), - vis, - *safety, - ast::Defaultness::Final, - ) - } + ast::ForeignItemKind::Static(box ast::StaticItem { + ty, + mutability, + expr, + safety, + define_opaque, + }) => self.print_item_const( + ident, + Some(*mutability), + &ast::Generics::default(), + ty, + expr.as_deref(), + vis, + *safety, + ast::Defaultness::Final, + define_opaque.as_deref(), + ), ast::ForeignItemKind::TyAlias(box ast::TyAlias { defaultness, generics, @@ -86,7 +91,9 @@ impl<'a> State<'a> { vis: &ast::Visibility, safety: ast::Safety, defaultness: ast::Defaultness, + define_opaque: Option<&[(ast::NodeId, ast::Path)]>, ) { + self.print_define_opaques(define_opaque); self.head(""); self.print_visibility(vis); self.print_safety(safety); @@ -174,7 +181,13 @@ impl<'a> State<'a> { self.print_use_tree(tree); self.word(";"); } - ast::ItemKind::Static(box StaticItem { ty, safety, mutability: mutbl, expr: body }) => { + ast::ItemKind::Static(box StaticItem { + ty, + safety, + mutability: mutbl, + expr: body, + define_opaque, + }) => { self.print_safety(*safety); self.print_item_const( item.ident, @@ -185,9 +198,16 @@ impl<'a> State<'a> { &item.vis, ast::Safety::Default, ast::Defaultness::Final, + define_opaque.as_deref(), ); } - ast::ItemKind::Const(box ast::ConstItem { defaultness, generics, ty, expr }) => { + ast::ItemKind::Const(box ast::ConstItem { + defaultness, + generics, + ty, + expr, + define_opaque, + }) => { self.print_item_const( item.ident, None, @@ -197,6 +217,7 @@ impl<'a> State<'a> { &item.vis, ast::Safety::Default, *defaultness, + define_opaque.as_deref(), ); } ast::ItemKind::Fn(func) => { @@ -537,7 +558,13 @@ impl<'a> State<'a> { ast::AssocItemKind::Fn(func) => { self.print_fn_full(ident, vis, attrs, &*func); } - ast::AssocItemKind::Const(box ast::ConstItem { defaultness, generics, ty, expr }) => { + ast::AssocItemKind::Const(box ast::ConstItem { + defaultness, + generics, + ty, + expr, + define_opaque, + }) => { self.print_item_const( ident, None, @@ -547,6 +574,7 @@ impl<'a> State<'a> { vis, ast::Safety::Default, *defaultness, + define_opaque.as_deref(), ); } ast::AssocItemKind::Type(box ast::TyAlias { @@ -652,7 +680,7 @@ impl<'a> State<'a> { ) { let ast::Fn { defaultness, generics, sig, contract, body, define_opaque } = func; - self.print_define_opaques(define_opaque); + self.print_define_opaques(define_opaque.as_deref()); if body.is_some() { self.head(""); @@ -672,10 +700,7 @@ impl<'a> State<'a> { } } - fn print_define_opaques( - &mut self, - define_opaque: Option<&[(ast::NodeId, ast::Path)]>, - ) { + fn print_define_opaques(&mut self, define_opaque: Option<&[(ast::NodeId, ast::Path)]>) { if let Some(define_opaque) = define_opaque { self.word("#[define_opaque("); for (i, (_, path)) in define_opaque.iter().enumerate() { diff --git a/compiler/rustc_builtin_macros/src/define_opaque.rs b/compiler/rustc_builtin_macros/src/define_opaque.rs index 9777e772cf208..bd5c48e3d346d 100644 --- a/compiler/rustc_builtin_macros/src/define_opaque.rs +++ b/compiler/rustc_builtin_macros/src/define_opaque.rs @@ -11,15 +11,20 @@ pub(crate) fn expand( let define_opaque = match &mut item { Annotatable::Item(p) => match &mut p.kind { ast::ItemKind::Fn(f) => Some(&mut f.define_opaque), + ast::ItemKind::Const(ct) => Some(&mut ct.define_opaque), + ast::ItemKind::Static(si) => Some(&mut si.define_opaque), _ => None, }, Annotatable::AssocItem(i, _assoc_ctxt) => match &mut i.kind { ast::AssocItemKind::Fn(func) => Some(&mut func.define_opaque), + ast::AssocItemKind::Const(ct) => Some(&mut ct.define_opaque), _ => None, }, Annotatable::Stmt(s) => match &mut s.kind { ast::StmtKind::Item(p) => match &mut p.kind { ast::ItemKind::Fn(f) => Some(&mut f.define_opaque), + ast::ItemKind::Const(ct) => Some(&mut ct.define_opaque), + ast::ItemKind::Static(si) => Some(&mut si.define_opaque), _ => None, }, _ => None, diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index a05fff2dcd1c1..239f8657284d5 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -285,6 +285,7 @@ pub(crate) fn expand_test_or_bench( defaultness: ast::Defaultness::Final, generics: ast::Generics::default(), ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))), + define_opaque: None, // test::TestDescAndFn { expr: Some( cx.expr_struct( diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index ee7f68cc2f01c..2c9b5f40d0dfe 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -698,8 +698,14 @@ impl<'a> ExtCtxt<'a> { name, AttrVec::new(), ast::ItemKind::Static( - ast::StaticItem { ty, safety: ast::Safety::Default, mutability, expr: Some(expr) } - .into(), + ast::StaticItem { + ty, + safety: ast::Safety::Default, + mutability, + expr: Some(expr), + define_opaque: None, + } + .into(), ), ) } @@ -723,6 +729,7 @@ impl<'a> ExtCtxt<'a> { generics: ast::Generics::default(), ty, expr: Some(expr), + define_opaque: None, } .into(), ), diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index f4df4044dd2ea..38a2eab5544f6 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -265,6 +265,7 @@ impl<'a> Parser<'a> { generics, ty, expr, + define_opaque: None, })), ) } @@ -980,13 +981,20 @@ impl<'a> Parser<'a> { let kind = match AssocItemKind::try_from(kind) { Ok(kind) => kind, Err(kind) => match kind { - ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => { + ItemKind::Static(box StaticItem { + ty, + safety: _, + mutability: _, + expr, + define_opaque, + }) => { self.dcx().emit_err(errors::AssociatedStaticItemNotAllowed { span }); AssocItemKind::Const(Box::new(ConstItem { defaultness: Defaultness::Final, generics: Generics::default(), ty, expr, + define_opaque, })) } _ => return self.error_bad_item_kind(span, &kind, "`trait`s or `impl`s"), @@ -1254,6 +1262,7 @@ impl<'a> Parser<'a> { mutability: Mutability::Not, expr, safety: Safety::Default, + define_opaque: None, })) } _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"), @@ -1397,7 +1406,7 @@ impl<'a> Parser<'a> { self.expect_semi()?; - Ok((ident, StaticItem { ty, safety, mutability, expr })) + Ok((ident, StaticItem { ty, safety, mutability, expr, define_opaque: None })) } /// Parse a constant item with the prefix `"const"` already parsed. diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 33f529851ae4f..fcb638a117e31 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -244,7 +244,13 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { let def_kind = match fi.kind { - ForeignItemKind::Static(box StaticItem { ty: _, mutability, expr: _, safety }) => { + ForeignItemKind::Static(box StaticItem { + ty: _, + mutability, + expr: _, + safety, + define_opaque: _, + }) => { let safety = match safety { ast::Safety::Unsafe(_) | ast::Safety::Default => hir::Safety::Unsafe, ast::Safety::Safe(_) => hir::Safety::Safe, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index f8808582353ad..9cbdb83a30fa2 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -36,6 +36,7 @@ use rustc_session::parse::feature_err; use rustc_span::source_map::{Spanned, respan}; use rustc_span::{BytePos, Ident, Span, Symbol, SyntaxContext, kw, sym}; use smallvec::{SmallVec, smallvec}; +use thin_vec::ThinVec; use tracing::{debug, instrument, trace}; use crate::{ @@ -2662,10 +2663,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }, |this| visit::walk_item(this, item), ); - - for (id, path) in define_opaque.iter().flatten() { - self.smart_resolve_path(*id, &None, path, PathSource::DefineOpaques); - } + self.resolve_define_opaques(define_opaque); } ItemKind::Enum(_, ref generics) @@ -2751,7 +2749,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }); } - ItemKind::Static(box ast::StaticItem { ref ty, ref expr, .. }) => { + ItemKind::Static(box ast::StaticItem { + ref ty, ref expr, ref define_opaque, .. + }) => { self.with_static_rib(def_kind, |this| { this.with_lifetime_rib( LifetimeRibKind::Elided(LifetimeRes::Static { @@ -2767,9 +2767,16 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { this.resolve_const_body(expr, Some((item.ident, ConstantItemKind::Static))); } }); + self.resolve_define_opaques(define_opaque); } - ItemKind::Const(box ast::ConstItem { ref generics, ref ty, ref expr, .. }) => { + ItemKind::Const(box ast::ConstItem { + ref generics, + ref ty, + ref expr, + ref define_opaque, + .. + }) => { self.with_generic_param_rib( &generics.params, RibKind::Item( @@ -2803,6 +2810,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } }, ); + self.resolve_define_opaques(define_opaque); } ItemKind::Use(ref use_tree) => { @@ -3102,7 +3110,13 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { for item in trait_items { self.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id)); match &item.kind { - AssocItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => { + AssocItemKind::Const(box ast::ConstItem { + generics, + ty, + expr, + define_opaque, + .. + }) => { self.with_generic_param_rib( &generics.params, RibKind::AssocItem, @@ -3135,13 +3149,13 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ) }, ); + + self.resolve_define_opaques(define_opaque); } AssocItemKind::Fn(box Fn { generics, define_opaque, .. }) => { walk_assoc_item(self, generics, LifetimeBinderKind::Function, item); - for (id, path) in define_opaque.iter().flatten() { - self.smart_resolve_path(*id, &None, path, PathSource::DefineOpaques); - } + self.resolve_define_opaques(define_opaque); } AssocItemKind::Delegation(delegation) => { self.with_generic_param_rib( @@ -3306,7 +3320,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { use crate::ResolutionError::*; self.resolve_doc_links(&item.attrs, MaybeExported::ImplItem(trait_id.ok_or(&item.vis))); match &item.kind { - AssocItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => { + AssocItemKind::Const(box ast::ConstItem { + generics, ty, expr, define_opaque, .. + }) => { debug!("resolve_implementation AssocItemKind::Const"); self.with_generic_param_rib( &generics.params, @@ -3350,6 +3366,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ); }, ); + self.resolve_define_opaques(define_opaque); } AssocItemKind::Fn(box Fn { generics, define_opaque, .. }) => { debug!("resolve_implementation AssocItemKind::Fn"); @@ -3379,9 +3396,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }, ); - for (id, path) in define_opaque.iter().flatten() { - self.smart_resolve_path(*id, &None, path, PathSource::DefineOpaques); - } + self.resolve_define_opaques(define_opaque); } AssocItemKind::Type(box TyAlias { generics, .. }) => { self.diag_metadata.in_non_gat_assoc_type = Some(generics.params.is_empty()); @@ -5103,6 +5118,14 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }); } } + + fn resolve_define_opaques(&mut self, define_opaque: &Option>) { + if let Some(define_opaque) = define_opaque { + for (id, path) in define_opaque { + self.smart_resolve_path(*id, &None, path, PathSource::DefineOpaques); + } + } + } } /// Walks the whole crate in DFS order, visiting each item, counting the declared number of diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 54261079fcad8..6023ae9cc7b16 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -336,12 +336,14 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { mutability: lm, expr: le, safety: ls, + define_opaque: _, }), Static(box StaticItem { ty: rt, mutability: rm, expr: re, safety: rs, + define_opaque: _, }), ) => lm == rm && ls == rs && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()), ( @@ -350,12 +352,14 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { generics: lg, ty: lt, expr: le, + define_opaque: _, }), Const(box ConstItem { defaultness: rd, generics: rg, ty: rt, expr: re, + define_opaque: _, }), ) => eq_defaultness(*ld, *rd) && eq_generics(lg, rg) && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()), ( @@ -490,12 +494,14 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { mutability: lm, expr: le, safety: ls, + define_opaque: _, }), Static(box StaticItem { ty: rt, mutability: rm, expr: re, safety: rs, + define_opaque: _, }), ) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()) && ls == rs, ( @@ -557,12 +563,14 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { generics: lg, ty: lt, expr: le, + define_opaque: _, }), Const(box ConstItem { defaultness: rd, generics: rg, ty: rt, expr: re, + define_opaque: _, }), ) => eq_defaultness(*ld, *rd) && eq_generics(lg, rg) && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()), ( diff --git a/tests/ui/impl-trait/define-via-const.rs b/tests/ui/impl-trait/define-via-const.rs new file mode 100644 index 0000000000000..a4b9123654c45 --- /dev/null +++ b/tests/ui/impl-trait/define-via-const.rs @@ -0,0 +1,12 @@ +//@ check-pass + +#![feature(type_alias_impl_trait)] + +type Closure = impl Fn(u32) -> u32; + +#[define_opaque(Closure)] +const ADDER: Closure = |x| x + 1; + +fn main() { + let z = (ADDER)(1); +} diff --git a/tests/ui/type-alias-impl-trait/issue-53092-2.rs b/tests/ui/type-alias-impl-trait/issue-53092-2.rs index 5f44a9aa2dfa9..1a530d27971a5 100644 --- a/tests/ui/type-alias-impl-trait/issue-53092-2.rs +++ b/tests/ui/type-alias-impl-trait/issue-53092-2.rs @@ -2,14 +2,15 @@ #![allow(dead_code)] type Bug = impl Fn(T) -> U + Copy; +//~^ ERROR cycle detected when computing type of `Bug::{opaque#0}` #[define_opaque(Bug)] -//~^ ERROR: only functions and methods can define opaque types const CONST_BUG: Bug = unsafe { std::mem::transmute(|_: u8| ()) }; +//~^ ERROR item does not constrain `Bug::{opaque#0}` #[define_opaque(Bug)] fn make_bug>() -> Bug { - |x| x.into() //~ ERROR is not satisfied + |x| x.into() } fn main() { diff --git a/tests/ui/type-alias-impl-trait/issue-53092-2.stderr b/tests/ui/type-alias-impl-trait/issue-53092-2.stderr index 5739662ff80bc..3062e55dc4909 100644 --- a/tests/ui/type-alias-impl-trait/issue-53092-2.stderr +++ b/tests/ui/type-alias-impl-trait/issue-53092-2.stderr @@ -1,25 +1,42 @@ -error: only functions and methods can define opaque types - --> $DIR/issue-53092-2.rs:6:1 +error[E0391]: cycle detected when computing type of `Bug::{opaque#0}` + --> $DIR/issue-53092-2.rs:4:18 | -LL | #[define_opaque(Bug)] - | ^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: the trait bound `U: From` is not satisfied - --> $DIR/issue-53092-2.rs:12:5 +LL | type Bug = impl Fn(T) -> U + Copy; + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires computing type of opaque `Bug::{opaque#0}`... + --> $DIR/issue-53092-2.rs:4:18 + | +LL | type Bug = impl Fn(T) -> U + Copy; + | ^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `CONST_BUG`... + --> $DIR/issue-53092-2.rs:8:1 | -LL | |x| x.into() - | ^^^^^^^^^^^^ the trait `From` is not implemented for `U` +LL | const CONST_BUG: Bug = unsafe { std::mem::transmute(|_: u8| ()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which requires computing layout of `Bug`... + = note: ...which requires normalizing `Bug`... + = note: ...which again requires computing type of `Bug::{opaque#0}`, completing the cycle +note: cycle used when checking that `Bug::{opaque#0}` is well-formed + --> $DIR/issue-53092-2.rs:4:18 + | +LL | type Bug = impl Fn(T) -> U + Copy; + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: item does not constrain `Bug::{opaque#0}` + --> $DIR/issue-53092-2.rs:8:7 | -note: required by a bound in `make_bug` - --> $DIR/issue-53092-2.rs:11:19 +LL | const CONST_BUG: Bug = unsafe { std::mem::transmute(|_: u8| ()) }; + | ^^^^^^^^^ | -LL | fn make_bug>() -> Bug { - | ^^^^^^^ required by this bound in `make_bug` -help: consider restricting type parameter `U` with trait `From` + = note: consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]` +note: this opaque type is supposed to be constrained + --> $DIR/issue-53092-2.rs:4:18 | -LL | type Bug> = impl Fn(T) -> U + Copy; - | +++++++++++++++++++++++ +LL | type Bug = impl Fn(T) -> U + Copy; + | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs index b5533eeecba5f..e21627e14b098 100644 --- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs @@ -1,19 +1,15 @@ +//@ check-pass + #![feature(type_alias_impl_trait)] -// Ensures that `const` items can not constrain an opaque `impl Trait`. use std::fmt::Debug; pub type Foo = impl Debug; -//~^ ERROR unconstrained opaque type #[define_opaque(Foo)] -//~^ ERROR only functions and methods can define opaque types const _FOO: Foo = 5; -//~^ ERROR mismatched types #[define_opaque(Foo)] -//~^ ERROR only functions and methods can define opaque types -static _BAR: Foo = 22_u32; -//~^ ERROR mismatched types +static _BAR: Foo = 22_i32; fn main() {} diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-const.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-const.stderr deleted file mode 100644 index dc15da665f325..0000000000000 --- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-const.stderr +++ /dev/null @@ -1,57 +0,0 @@ -error: only functions and methods can define opaque types - --> $DIR/type-alias-impl-trait-const.rs:9:1 - | -LL | #[define_opaque(Foo)] - | ^^^^^^^^^^^^^^^^^^^^^ - -error: only functions and methods can define opaque types - --> $DIR/type-alias-impl-trait-const.rs:14:1 - | -LL | #[define_opaque(Foo)] - | ^^^^^^^^^^^^^^^^^^^^^ - -error: unconstrained opaque type - --> $DIR/type-alias-impl-trait-const.rs:6:16 - | -LL | pub type Foo = impl Debug; - | ^^^^^^^^^^ - | - = note: `Foo` must be used in combination with a concrete type within the same crate - -error[E0308]: mismatched types - --> $DIR/type-alias-impl-trait-const.rs:11:19 - | -LL | pub type Foo = impl Debug; - | ---------- the expected opaque type -... -LL | const _FOO: Foo = 5; - | ^ expected opaque type, found integer - | - = note: expected opaque type `Foo` - found type `{integer}` -note: this item must have a `#[define_opaque(Foo)]` attribute to be able to define hidden types - --> $DIR/type-alias-impl-trait-const.rs:11:7 - | -LL | const _FOO: Foo = 5; - | ^^^^ - -error[E0308]: mismatched types - --> $DIR/type-alias-impl-trait-const.rs:16:20 - | -LL | pub type Foo = impl Debug; - | ---------- the expected opaque type -... -LL | static _BAR: Foo = 22_u32; - | ^^^^^^ expected opaque type, found `u32` - | - = note: expected opaque type `Foo` - found type `u32` -note: this item must have a `#[define_opaque(Foo)]` attribute to be able to define hidden types - --> $DIR/type-alias-impl-trait-const.rs:16:8 - | -LL | static _BAR: Foo = 22_u32; - | ^^^^ - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0308`. From 0827f765864a17ac6354cc12ff353043cba62286 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 24 Mar 2025 23:19:33 +0000 Subject: [PATCH 16/17] Test define opaques in extern items --- .../rustc_builtin_macros/src/define_opaque.rs | 5 ++++- tests/ui/impl-trait/define-via-extern.rs | 16 ++++++++++++++++ tests/ui/impl-trait/define-via-extern.stderr | 14 ++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 tests/ui/impl-trait/define-via-extern.rs create mode 100644 tests/ui/impl-trait/define-via-extern.stderr diff --git a/compiler/rustc_builtin_macros/src/define_opaque.rs b/compiler/rustc_builtin_macros/src/define_opaque.rs index bd5c48e3d346d..cd02e81f5689c 100644 --- a/compiler/rustc_builtin_macros/src/define_opaque.rs +++ b/compiler/rustc_builtin_macros/src/define_opaque.rs @@ -52,7 +52,10 @@ pub(crate) fn expand( .collect(), ); } else { - ecx.dcx().span_err(meta_item.span, "only functions and methods can define opaque types"); + ecx.dcx().span_err( + meta_item.span, + "only functions, statics, and consts can define opaque types", + ); } vec![item] diff --git a/tests/ui/impl-trait/define-via-extern.rs b/tests/ui/impl-trait/define-via-extern.rs new file mode 100644 index 0000000000000..599c31ff917fc --- /dev/null +++ b/tests/ui/impl-trait/define-via-extern.rs @@ -0,0 +1,16 @@ +#![feature(type_alias_impl_trait)] + +type Hi = impl Sized; + +extern "C" { + #[define_opaque(Hi)] fn foo(); + //~^ ERROR only functions, statics, and consts can define opaque types + + #[define_opaque(Hi)] static HI: Hi; + //~^ ERROR only functions, statics, and consts can define opaque types +} + +#[define_opaque(Hi)] +fn main() { + let _: Hi = 0; +} diff --git a/tests/ui/impl-trait/define-via-extern.stderr b/tests/ui/impl-trait/define-via-extern.stderr new file mode 100644 index 0000000000000..4a0ca5edd47d0 --- /dev/null +++ b/tests/ui/impl-trait/define-via-extern.stderr @@ -0,0 +1,14 @@ +error: only functions, statics, and consts can define opaque types + --> $DIR/define-via-extern.rs:6:5 + | +LL | #[define_opaque(Hi)] fn foo(); + | ^^^^^^^^^^^^^^^^^^^^ + +error: only functions, statics, and consts can define opaque types + --> $DIR/define-via-extern.rs:9:5 + | +LL | #[define_opaque(Hi)] static HI: Hi; + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + From 154cb083e705feca7509143352887dd293db61b2 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Tue, 25 Mar 2025 21:02:54 +0100 Subject: [PATCH 17/17] Override PartialOrd methods for bool I noticed that `PartialOrd` implementation for `bool` does not override the individual operator methods, unlike the other primitive types like `char` and integers. This commit extracts these `PartialOrd` overrides shared by the other primitive types into a macro and calls it on `bool` too. --- library/core/src/cmp.rs | 50 +++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 0b0dbf723b658..0dc2cc72e06cc 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1810,9 +1810,9 @@ mod impls { #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for $t { #[inline] - fn eq(&self, other: &$t) -> bool { (*self) == (*other) } + fn eq(&self, other: &Self) -> bool { *self == *other } #[inline] - fn ne(&self, other: &$t) -> bool { (*self) != (*other) } + fn ne(&self, other: &Self) -> bool { *self != *other } } )*) } @@ -1842,8 +1842,18 @@ mod impls { eq_impl! { () bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } - macro_rules! chaining_methods_impl { - ($t:ty) => { + #[rustfmt::skip] + macro_rules! partial_ord_methods_primitive_impl { + () => { + #[inline(always)] + fn lt(&self, other: &Self) -> bool { *self < *other } + #[inline(always)] + fn le(&self, other: &Self) -> bool { *self <= *other } + #[inline(always)] + fn gt(&self, other: &Self) -> bool { *self > *other } + #[inline(always)] + fn ge(&self, other: &Self) -> bool { *self >= *other } + // These implementations are the same for `Ord` or `PartialOrd` types // because if either is NAN the `==` test will fail so we end up in // the `Break` case and the comparison will correctly return `false`. @@ -1876,7 +1886,7 @@ mod impls { #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for $t { #[inline] - fn partial_cmp(&self, other: &$t) -> Option { + fn partial_cmp(&self, other: &Self) -> Option { match (*self <= *other, *self >= *other) { (false, false) => None, (false, true) => Some(Greater), @@ -1884,16 +1894,8 @@ mod impls { (true, true) => Some(Equal), } } - #[inline(always)] - fn lt(&self, other: &$t) -> bool { (*self) < (*other) } - #[inline(always)] - fn le(&self, other: &$t) -> bool { (*self) <= (*other) } - #[inline(always)] - fn ge(&self, other: &$t) -> bool { (*self) >= (*other) } - #[inline(always)] - fn gt(&self, other: &$t) -> bool { (*self) > (*other) } - - chaining_methods_impl!($t); + + partial_ord_methods_primitive_impl!(); } )*) } @@ -1912,6 +1914,8 @@ mod impls { fn partial_cmp(&self, other: &bool) -> Option { Some(self.cmp(other)) } + + partial_ord_methods_primitive_impl!(); } partial_ord_impl! { f16 f32 f64 f128 } @@ -1921,25 +1925,17 @@ mod impls { #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for $t { #[inline] - fn partial_cmp(&self, other: &$t) -> Option { + fn partial_cmp(&self, other: &Self) -> Option { Some(crate::intrinsics::three_way_compare(*self, *other)) } - #[inline(always)] - fn lt(&self, other: &$t) -> bool { (*self) < (*other) } - #[inline(always)] - fn le(&self, other: &$t) -> bool { (*self) <= (*other) } - #[inline(always)] - fn ge(&self, other: &$t) -> bool { (*self) >= (*other) } - #[inline(always)] - fn gt(&self, other: &$t) -> bool { (*self) > (*other) } - - chaining_methods_impl!($t); + + partial_ord_methods_primitive_impl!(); } #[stable(feature = "rust1", since = "1.0.0")] impl Ord for $t { #[inline] - fn cmp(&self, other: &$t) -> Ordering { + fn cmp(&self, other: &Self) -> Ordering { crate::intrinsics::three_way_compare(*self, *other) } }