From 3ca752f9798ba49e3e81a94dac66c0a394395552 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 21 Jul 2025 10:07:35 +0000 Subject: [PATCH 01/13] Trait aliases are rare large ast nodes, box them --- compiler/rustc_ast/src/ast.rs | 23 +++++++++++++------ compiler/rustc_ast/src/visit.rs | 2 +- compiler/rustc_ast_lowering/src/item.rs | 2 +- .../rustc_ast_pretty/src/pprust/state/item.rs | 5 ++-- compiler/rustc_lint/src/nonstandard_style.rs | 4 +++- compiler/rustc_parse/src/parser/item.rs | 2 +- .../rustc_resolve/src/build_reduced_graph.rs | 5 ++-- compiler/rustc_resolve/src/late.rs | 4 ++-- .../clippy/clippy_utils/src/ast_utils/mod.rs | 15 +++++++++--- src/tools/rustfmt/src/visitor.rs | 8 +++---- tests/ui/stats/input-stats.stderr | 18 +++++++-------- 11 files changed, 54 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 94c15094f5251..81efafc2d1dca 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3540,8 +3540,9 @@ impl Item { ItemKind::Const(i) => Some(&i.generics), ItemKind::Fn(i) => Some(&i.generics), ItemKind::TyAlias(i) => Some(&i.generics), - ItemKind::TraitAlias(_, generics, _) - | ItemKind::Enum(_, generics, _) + ItemKind::TraitAlias(i) => Some(&i.generics), + + ItemKind::Enum(_, generics, _) | ItemKind::Struct(_, generics, _) | ItemKind::Union(_, generics, _) => Some(&generics), ItemKind::Trait(i) => Some(&i.generics), @@ -3623,6 +3624,14 @@ impl Default for FnHeader { } } +#[derive(Clone, Encodable, Decodable, Debug, Walkable)] +pub struct TraitAlias { + pub ident: Ident, + pub generics: Generics, + #[visitable(extra = BoundKind::Bound)] + pub bounds: GenericBounds, +} + #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct Trait { pub constness: Const, @@ -3795,7 +3804,7 @@ pub enum ItemKind { /// Trait alias. /// /// E.g., `trait Foo = Bar + Quux;`. - TraitAlias(Ident, Generics, GenericBounds), + TraitAlias(Box), /// An implementation. /// /// E.g., `impl Foo { .. }` or `impl Trait for Foo { .. }`. @@ -3828,7 +3837,7 @@ impl ItemKind { | ItemKind::Struct(ident, ..) | ItemKind::Union(ident, ..) | ItemKind::Trait(box Trait { ident, .. }) - | ItemKind::TraitAlias(ident, ..) + | ItemKind::TraitAlias(box TraitAlias { ident, .. }) | ItemKind::MacroDef(ident, _) | ItemKind::Delegation(box Delegation { ident, .. }) => Some(ident), @@ -3885,7 +3894,7 @@ impl ItemKind { | Self::Struct(_, generics, _) | Self::Union(_, generics, _) | Self::Trait(box Trait { generics, .. }) - | Self::TraitAlias(_, generics, _) + | Self::TraitAlias(box TraitAlias { generics, .. }) | Self::Impl(Impl { generics, .. }) => Some(generics), _ => None, } @@ -4047,8 +4056,8 @@ mod size_asserts { static_assert_size!(GenericBound, 88); static_assert_size!(Generics, 40); static_assert_size!(Impl, 64); - static_assert_size!(Item, 144); - static_assert_size!(ItemKind, 80); + static_assert_size!(Item, 136); + static_assert_size!(ItemKind, 72); static_assert_size!(LitKind, 24); static_assert_size!(Local, 96); static_assert_size!(MetaItemLit, 40); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 03e5a6edeece5..ed47c5f5274f6 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -833,7 +833,7 @@ macro_rules! common_visitor_and_walkers { visit_visitable!($($mut)? vis, impl_), ItemKind::Trait(trait_) => visit_visitable!($($mut)? vis, trait_), - ItemKind::TraitAlias(ident, generics, bounds) => { + ItemKind::TraitAlias(box TraitAlias { ident, generics, bounds }) => { visit_visitable!($($mut)? vis, ident, generics); visit_visitable_with!($($mut)? vis, bounds, BoundKind::Bound) } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 8527108f70419..56ceeb7ac581f 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -415,7 +415,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); hir::ItemKind::Trait(constness, *is_auto, safety, ident, generics, bounds, items) } - ItemKind::TraitAlias(ident, generics, bounds) => { + ItemKind::TraitAlias(box TraitAlias { ident, generics, bounds }) => { let ident = self.lower_ident(*ident); let (generics, bounds) = self.lower_generics( generics, diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 3412660863407..36f1387d4b08a 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -1,7 +1,6 @@ use ast::StaticItem; use itertools::{Itertools, Position}; -use rustc_ast as ast; -use rustc_ast::ModKind; +use rustc_ast::{self as ast, ModKind, TraitAlias}; use rustc_span::Ident; use crate::pp::BoxMarker; @@ -386,7 +385,7 @@ impl<'a> State<'a> { let empty = item.attrs.is_empty() && items.is_empty(); self.bclose(item.span, empty, cb); } - ast::ItemKind::TraitAlias(ident, generics, bounds) => { + ast::ItemKind::TraitAlias(box TraitAlias { ident, generics, bounds }) => { let (cb, ib) = self.head(visibility_qualified(&item.vis, "trait")); self.print_ident(*ident); self.print_generic_params(&generics.params); diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 7f643a551bb70..b90abe0a24f15 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -160,7 +160,9 @@ impl EarlyLintPass for NonCamelCaseTypes { ast::ItemKind::Trait(box ast::Trait { ident, .. }) => { self.check_case(cx, "trait", ident) } - ast::ItemKind::TraitAlias(ident, _, _) => self.check_case(cx, "trait alias", ident), + ast::ItemKind::TraitAlias(box ast::TraitAlias { ident, .. }) => { + self.check_case(cx, "trait alias", ident) + } // N.B. This check is only for inherent associated types, so that we don't lint against // trait impls where we should have warned for the trait definition already. diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 11eae9e2d903e..fde98d14ce11f 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -955,7 +955,7 @@ impl<'a> Parser<'a> { self.psess.gated_spans.gate(sym::trait_alias, whole_span); - Ok(ItemKind::TraitAlias(ident, generics, bounds)) + Ok(ItemKind::TraitAlias(Box::new(TraitAlias { ident, generics, bounds }))) } else { // It's a normal trait. generics.where_clause = self.parse_where_clause()?; diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 88fbc6dcb6650..886ffcffbb4d9 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -10,7 +10,7 @@ use std::sync::Arc; use rustc_ast::visit::{self, AssocCtxt, Visitor, WalkItemKind}; use rustc_ast::{ self as ast, AssocItem, AssocItemKind, Block, ConstItem, Delegation, Fn, ForeignItem, - ForeignItemKind, Inline, Item, ItemKind, NodeId, StaticItem, StmtKind, TyAlias, + ForeignItemKind, Inline, Item, ItemKind, NodeId, StaticItem, StmtKind, TraitAlias, TyAlias, }; use rustc_attr_parsing as attr; use rustc_attr_parsing::AttributeParser; @@ -844,7 +844,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } // These items live in the type namespace. - ItemKind::TyAlias(box TyAlias { ident, .. }) | ItemKind::TraitAlias(ident, ..) => { + ItemKind::TyAlias(box TyAlias { ident, .. }) + | ItemKind::TraitAlias(box TraitAlias { ident, .. }) => { self.r.define_local(parent, ident, TypeNS, res, vis, sp, expansion); } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index fd7ace368aa67..e3051dc38eca2 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2645,7 +2645,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ); } - ItemKind::TraitAlias(_, ref generics, ref bounds) => { + ItemKind::TraitAlias(box TraitAlias { ref generics, ref bounds, .. }) => { // Create a new rib for the trait-wide type parameters. self.with_generic_param_rib( &generics.params, @@ -5164,7 +5164,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { | ItemKind::Union(_, generics, _) | ItemKind::Impl(Impl { generics, .. }) | ItemKind::Trait(box Trait { generics, .. }) - | ItemKind::TraitAlias(_, generics, _) => { + | ItemKind::TraitAlias(box TraitAlias { generics, .. }) => { if let ItemKind::Fn(box Fn { sig, .. }) = &item.kind { self.collect_fn_info(sig.header, &sig.decl, item.id, &item.attrs); } 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 22b74ab16d615..4df1eb508713c 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -473,9 +473,18 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { && over(lb, rb, eq_generic_bound) && over(lis, ris, |l, r| eq_item(l, r, eq_assoc_item_kind)) }, - (TraitAlias(li, lg, lb), TraitAlias(ri, rg, rb)) => { - eq_id(*li, *ri) && eq_generics(lg, rg) && over(lb, rb, eq_generic_bound) - }, + ( + TraitAlias(box ast::TraitAlias { + ident: li, + generics: lg, + bounds: lb, + }), + TraitAlias(box ast::TraitAlias { + ident: ri, + generics: rg, + bounds: rb, + }), + ) => eq_id(*li, *ri) && eq_generics(lg, rg) && over(lb, rb, eq_generic_bound), ( Impl(ast::Impl { generics: lg, diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index a3acbb218ff29..633a17a40108f 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -497,14 +497,14 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { let rw = self.with_context(|ctx| format_trait(ctx, item, block_indent)); self.push_rewrite(item.span, rw); } - ast::ItemKind::TraitAlias(ident, ref generics, ref generic_bounds) => { + ast::ItemKind::TraitAlias(ref ta) => { let shape = Shape::indented(self.block_indent, self.config); let rw = format_trait_alias( &self.get_context(), - ident, + ta.ident, &item.vis, - generics, - generic_bounds, + &ta.generics, + &ta.bounds, shape, ); self.push_rewrite(item.span, rw); diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr index 4a73a4747ad0c..648f6698073fc 100644 --- a/tests/ui/stats/input-stats.stderr +++ b/tests/ui/stats/input-stats.stderr @@ -2,14 +2,14 @@ ast-stats ================================================================ ast-stats POST EXPANSION AST STATS: input_stats ast-stats Name Accumulated Size Count Item Size ast-stats ---------------------------------------------------------------- -ast-stats Item 1_584 (NN.N%) 11 144 -ast-stats - Enum 144 (NN.N%) 1 -ast-stats - ExternCrate 144 (NN.N%) 1 -ast-stats - ForeignMod 144 (NN.N%) 1 -ast-stats - Impl 144 (NN.N%) 1 -ast-stats - Trait 144 (NN.N%) 1 -ast-stats - Fn 288 (NN.N%) 2 -ast-stats - Use 576 (NN.N%) 4 +ast-stats Item 1_496 (NN.N%) 11 136 +ast-stats - Enum 136 (NN.N%) 1 +ast-stats - ExternCrate 136 (NN.N%) 1 +ast-stats - ForeignMod 136 (NN.N%) 1 +ast-stats - Impl 136 (NN.N%) 1 +ast-stats - Trait 136 (NN.N%) 1 +ast-stats - Fn 272 (NN.N%) 2 +ast-stats - Use 544 (NN.N%) 4 ast-stats Ty 896 (NN.N%) 14 64 ast-stats - Ptr 64 (NN.N%) 1 ast-stats - Ref 64 (NN.N%) 1 @@ -57,7 +57,7 @@ ast-stats GenericArgs 40 (NN.N%) 1 40 ast-stats - AngleBracketed 40 (NN.N%) 1 ast-stats Crate 40 (NN.N%) 1 40 ast-stats ---------------------------------------------------------------- -ast-stats Total 7_528 129 +ast-stats Total 7_440 129 ast-stats ================================================================ hir-stats ================================================================ hir-stats HIR STATS: input_stats From d6d9fa8efda83c4c83c6850d71a91322c663723f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 13 Oct 2025 13:44:32 +0200 Subject: [PATCH 02/13] Add new `--bypass-ignore-backends` option --- src/bootstrap/src/core/build_steps/test.rs | 3 +++ src/bootstrap/src/core/config/flags.rs | 10 ++++++++++ src/etc/completions/x.fish | 1 + src/etc/completions/x.ps1 | 1 + src/etc/completions/x.py.fish | 1 + src/etc/completions/x.py.ps1 | 1 + src/etc/completions/x.py.sh | 2 +- src/etc/completions/x.py.zsh | 1 + src/etc/completions/x.sh | 2 +- src/etc/completions/x.zsh | 1 + src/tools/compiletest/src/common.rs | 2 ++ src/tools/compiletest/src/directives.rs | 2 +- src/tools/compiletest/src/lib.rs | 4 +++- src/tools/compiletest/src/rustdoc_gui_test.rs | 1 + 14 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 52915abca1504..e1b3ff92a07b8 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1965,6 +1965,9 @@ Please disable assertions with `rust.debug-assertions = false`. cmd.arg("--default-codegen-backend") .arg(builder.config.default_codegen_backend(test_compiler.host).name()); } + if builder.config.cmd.bypass_ignore_backends() { + cmd.arg("--bypass-ignore-backends"); + } if builder.build.config.llvm_enzyme { cmd.arg("--has-enzyme"); diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index 9e408505933d3..bf089d25ffec8 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -422,6 +422,9 @@ pub enum Subcommand { #[arg(long)] /// Use a different codegen backend when running tests. test_codegen_backend: Option, + #[arg(long)] + /// Ignore `//@ ignore-backends` directives. + bypass_ignore_backends: bool, }, /// Build and run some test suites *in Miri* Miri { @@ -668,6 +671,13 @@ impl Subcommand { _ => None, } } + + pub fn bypass_ignore_backends(&self) -> bool { + match self { + Subcommand::Test { bypass_ignore_backends, .. } => *bypass_ignore_backends, + _ => false, + } + } } /// Returns the shell completion for a given shell, if the result differs from the current diff --git a/src/etc/completions/x.fish b/src/etc/completions/x.fish index 544f9b97237cb..a837be680dcdd 100644 --- a/src/etc/completions/x.fish +++ b/src/etc/completions/x.fish @@ -336,6 +336,7 @@ complete -c x -n "__fish_x_using_subcommand test" -l force-rerun -d 'rerun tests complete -c x -n "__fish_x_using_subcommand test" -l only-modified -d 'only run tests that result has been changed' complete -c x -n "__fish_x_using_subcommand test" -l rustfix-coverage -d 'enable this to generate a Rustfix coverage file, which is saved in `//rustfix_missing_coverage.txt`' complete -c x -n "__fish_x_using_subcommand test" -l no-capture -d 'don\'t capture stdout/stderr of tests' +complete -c x -n "__fish_x_using_subcommand test" -l bypass-ignore-backends -d 'Ignore `//@ ignore-backends` directives' complete -c x -n "__fish_x_using_subcommand test" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x -n "__fish_x_using_subcommand test" -s i -l incremental -d 'use incremental compilation' complete -c x -n "__fish_x_using_subcommand test" -l include-default-paths -d 'include default paths in addition to the provided ones' diff --git a/src/etc/completions/x.ps1 b/src/etc/completions/x.ps1 index b03acf930f70d..1a02adbddfea7 100644 --- a/src/etc/completions/x.ps1 +++ b/src/etc/completions/x.ps1 @@ -383,6 +383,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--only-modified', '--only-modified', [CompletionResultType]::ParameterName, 'only run tests that result has been changed') [CompletionResult]::new('--rustfix-coverage', '--rustfix-coverage', [CompletionResultType]::ParameterName, 'enable this to generate a Rustfix coverage file, which is saved in `//rustfix_missing_coverage.txt`') [CompletionResult]::new('--no-capture', '--no-capture', [CompletionResultType]::ParameterName, 'don''t capture stdout/stderr of tests') + [CompletionResult]::new('--bypass-ignore-backends', '--bypass-ignore-backends', [CompletionResultType]::ParameterName, 'Ignore `//@ ignore-backends` directives') [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation') diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish index 08e4cd26ce887..63b7987fb290e 100644 --- a/src/etc/completions/x.py.fish +++ b/src/etc/completions/x.py.fish @@ -336,6 +336,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand test" -l force-rerun -d 'rerun complete -c x.py -n "__fish_x.py_using_subcommand test" -l only-modified -d 'only run tests that result has been changed' complete -c x.py -n "__fish_x.py_using_subcommand test" -l rustfix-coverage -d 'enable this to generate a Rustfix coverage file, which is saved in `//rustfix_missing_coverage.txt`' complete -c x.py -n "__fish_x.py_using_subcommand test" -l no-capture -d 'don\'t capture stdout/stderr of tests' +complete -c x.py -n "__fish_x.py_using_subcommand test" -l bypass-ignore-backends -d 'Ignore `//@ ignore-backends` directives' complete -c x.py -n "__fish_x.py_using_subcommand test" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x.py -n "__fish_x.py_using_subcommand test" -s i -l incremental -d 'use incremental compilation' complete -c x.py -n "__fish_x.py_using_subcommand test" -l include-default-paths -d 'include default paths in addition to the provided ones' diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1 index 3d95d88af4955..cac70f722098f 100644 --- a/src/etc/completions/x.py.ps1 +++ b/src/etc/completions/x.py.ps1 @@ -383,6 +383,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--only-modified', '--only-modified', [CompletionResultType]::ParameterName, 'only run tests that result has been changed') [CompletionResult]::new('--rustfix-coverage', '--rustfix-coverage', [CompletionResultType]::ParameterName, 'enable this to generate a Rustfix coverage file, which is saved in `//rustfix_missing_coverage.txt`') [CompletionResult]::new('--no-capture', '--no-capture', [CompletionResultType]::ParameterName, 'don''t capture stdout/stderr of tests') + [CompletionResult]::new('--bypass-ignore-backends', '--bypass-ignore-backends', [CompletionResultType]::ParameterName, 'Ignore `//@ ignore-backends` directives') [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation') diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh index 8ff0eaf35c89a..cff17f431d33d 100644 --- a/src/etc/completions/x.py.sh +++ b/src/etc/completions/x.py.sh @@ -3875,7 +3875,7 @@ _x.py() { return 0 ;; x.py__test) - opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --test-codegen-backend --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --test-codegen-backend --bypass-ignore-backends --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh index 9d2d73e582ec6..47cdaf97befcc 100644 --- a/src/etc/completions/x.py.zsh +++ b/src/etc/completions/x.py.zsh @@ -383,6 +383,7 @@ _arguments "${_arguments_options[@]}" : \ '--only-modified[only run tests that result has been changed]' \ '--rustfix-coverage[enable this to generate a Rustfix coverage file, which is saved in \`//rustfix_missing_coverage.txt\`]' \ '--no-capture[don'\''t capture stdout/stderr of tests]' \ +'--bypass-ignore-backends[Ignore \`//@ ignore-backends\` directives]' \ '*-v[use verbose output (-vv for very verbose)]' \ '*--verbose[use verbose output (-vv for very verbose)]' \ '-i[use incremental compilation]' \ diff --git a/src/etc/completions/x.sh b/src/etc/completions/x.sh index c1b73fb7c9e34..700617bfeba0e 100644 --- a/src/etc/completions/x.sh +++ b/src/etc/completions/x.sh @@ -3875,7 +3875,7 @@ _x() { return 0 ;; x__test) - opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --test-codegen-backend --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --test-codegen-backend --bypass-ignore-backends --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/src/etc/completions/x.zsh b/src/etc/completions/x.zsh index 29237ef9bf8fd..b960be4a1b10a 100644 --- a/src/etc/completions/x.zsh +++ b/src/etc/completions/x.zsh @@ -383,6 +383,7 @@ _arguments "${_arguments_options[@]}" : \ '--only-modified[only run tests that result has been changed]' \ '--rustfix-coverage[enable this to generate a Rustfix coverage file, which is saved in \`//rustfix_missing_coverage.txt\`]' \ '--no-capture[don'\''t capture stdout/stderr of tests]' \ +'--bypass-ignore-backends[Ignore \`//@ ignore-backends\` directives]' \ '*-v[use verbose output (-vv for very verbose)]' \ '*--verbose[use verbose output (-vv for very verbose)]' \ '-i[use incremental compilation]' \ diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 8e47d51ee4dbd..f55670dd61402 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -710,6 +710,8 @@ pub struct Config { pub default_codegen_backend: CodegenBackend, /// Name/path of the backend to use instead of `default_codegen_backend`. pub override_codegen_backend: Option, + /// Whether to ignore `//@ ignore-backends`. + pub bypass_backends: bool, } impl Config { diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 0318ed2b3d119..aad8f475fc52e 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -1493,7 +1493,7 @@ fn ignore_backends(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision } } }) { - if config.default_codegen_backend == backend { + if !config.bypass_backends && config.default_codegen_backend == backend { return IgnoreDecision::Ignore { reason: format!("{} backend is marked as ignore", backend.as_str()), }; diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 11a462c3d44a6..f21e6077cdddc 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -217,7 +217,8 @@ fn parse_config(args: Vec) -> Config { "override-codegen-backend", "the codegen backend to use instead of the default one", "CODEGEN BACKEND [NAME | PATH]", - ); + ) + .optflag("", "bypass-ignore-backends", "ignore `//@ ignore-backends` directives"); let (argv0, args_) = args.split_first().unwrap(); if args.len() == 1 || args[1] == "-h" || args[1] == "--help" { @@ -484,6 +485,7 @@ fn parse_config(args: Vec) -> Config { default_codegen_backend, override_codegen_backend, + bypass_backends: matches.opt_present("bypass-ignore-backends"), } } diff --git a/src/tools/compiletest/src/rustdoc_gui_test.rs b/src/tools/compiletest/src/rustdoc_gui_test.rs index 4bd3531f4b433..aa83c93ea975b 100644 --- a/src/tools/compiletest/src/rustdoc_gui_test.rs +++ b/src/tools/compiletest/src/rustdoc_gui_test.rs @@ -138,5 +138,6 @@ fn incomplete_config_for_rustdoc_gui_test() -> Config { minicore_path: Default::default(), default_codegen_backend: CodegenBackend::Llvm, override_codegen_backend: None, + bypass_backends: Default::default(), } } From 36ac107e3d7fa647f826ac46b0857252385a603d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 29 Oct 2025 14:02:02 +0100 Subject: [PATCH 03/13] Add rustc-dev-guide documentation for new `--bypass-ignore-backends` command line flag --- src/doc/rustc-dev-guide/src/tests/directives.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 12ceef0c928de..045c8c71f9cd2 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -207,7 +207,9 @@ settings: on `wasm32-unknown-unknown` target because the target does not support the `proc-macro` crate type. - `needs-target-std` — ignores if target platform does not have std support. -- `ignore-backends` — ignores the listed backends, separated by whitespace characters. +- `ignore-backends` — ignores the listed backends, separated by whitespace characters. Please note + that this directive can be overriden with the `--bypass-ignore-backends=[BACKEND]` command line + flag. - `needs-backends` — only runs the test if current codegen backend is listed. The following directives will check LLVM support: From 5aa2a90724e2f647cf118f0a80bffab46b5a36d6 Mon Sep 17 00:00:00 2001 From: Binlogo Date: Wed, 29 Oct 2025 21:21:25 +0800 Subject: [PATCH 04/13] Improve diagnose for unconditional panic when resource limit --- compiler/rustc_interface/src/util.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 5e9cb42365049..1ddde9340916f 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -287,7 +287,15 @@ pub(crate) fn run_in_thread_pool_with_globals< pool.install(|| f(current_gcx.into_inner(), proxy)) }, ) - .unwrap() + .unwrap_or_else(|err| { + let mut diag = thread_builder_diag.early_struct_fatal(format!( + "failed to spawn compiler thread pool: could not create {threads} threads ({err})", + )); + diag.help( + "try lowering `-Z threads` or checking the operating system's resource limits", + ); + diag.emit(); + }) }) }) } From 8cf55ea51c227c12d039c9696c72537e2669526f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 29 Oct 2025 19:49:24 +0100 Subject: [PATCH 05/13] Rename `bypass_backends` into `bypass_ignore_backends` --- src/tools/compiletest/src/common.rs | 2 +- src/tools/compiletest/src/directives.rs | 2 +- src/tools/compiletest/src/lib.rs | 2 +- src/tools/compiletest/src/rustdoc_gui_test.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index f55670dd61402..1f893fecb54b0 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -711,7 +711,7 @@ pub struct Config { /// Name/path of the backend to use instead of `default_codegen_backend`. pub override_codegen_backend: Option, /// Whether to ignore `//@ ignore-backends`. - pub bypass_backends: bool, + pub bypass_ignore_backends: bool, } impl Config { diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index aad8f475fc52e..5988f59fd92f7 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -1493,7 +1493,7 @@ fn ignore_backends(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision } } }) { - if !config.bypass_backends && config.default_codegen_backend == backend { + if !config.bypass_ignore_backends && config.default_codegen_backend == backend { return IgnoreDecision::Ignore { reason: format!("{} backend is marked as ignore", backend.as_str()), }; diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index f21e6077cdddc..b524017e4dadd 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -485,7 +485,7 @@ fn parse_config(args: Vec) -> Config { default_codegen_backend, override_codegen_backend, - bypass_backends: matches.opt_present("bypass-ignore-backends"), + bypass_ignore_backends: matches.opt_present("bypass-ignore-backends"), } } diff --git a/src/tools/compiletest/src/rustdoc_gui_test.rs b/src/tools/compiletest/src/rustdoc_gui_test.rs index aa83c93ea975b..60a7e6d47d2fb 100644 --- a/src/tools/compiletest/src/rustdoc_gui_test.rs +++ b/src/tools/compiletest/src/rustdoc_gui_test.rs @@ -138,6 +138,6 @@ fn incomplete_config_for_rustdoc_gui_test() -> Config { minicore_path: Default::default(), default_codegen_backend: CodegenBackend::Llvm, override_codegen_backend: None, - bypass_backends: Default::default(), + bypass_ignore_backends: Default::default(), } } From a09c4fc8626e4a5216404164efab2167bd8b2f96 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Wed, 29 Oct 2025 18:17:28 +0100 Subject: [PATCH 06/13] Fix types being marked as dead when they are inferred generic arguments Signed-off-by: Jonathan Brouwer --- compiler/rustc_passes/src/dead.rs | 11 ++++++++++- tests/ui/lint/dead-code/inferred-generic-arg.rs | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 tests/ui/lint/dead-code/inferred-generic-arg.rs diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 877b5ad93bfca..6d34587684bb3 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -125,9 +125,13 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { ) => { self.check_def_id(def_id); } - _ if self.in_pat => {} Res::PrimTy(..) | Res::SelfCtor(..) | Res::Local(..) => {} Res::Def(DefKind::Ctor(CtorOf::Variant, ..), ctor_def_id) => { + // Using a variant in patterns should not make the variant live, + // since we can just remove the match arm that matches the pattern + if self.in_pat { + return; + } let variant_id = self.tcx.parent(ctor_def_id); let enum_id = self.tcx.parent(variant_id); self.check_def_id(enum_id); @@ -136,6 +140,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } } Res::Def(DefKind::Variant, variant_id) => { + // Using a variant in patterns should not make the variant live, + // since we can just remove the match arm that matches the pattern + if self.in_pat { + return; + } let enum_id = self.tcx.parent(variant_id); self.check_def_id(enum_id); if !self.ignore_variant_stack.contains(&variant_id) { diff --git a/tests/ui/lint/dead-code/inferred-generic-arg.rs b/tests/ui/lint/dead-code/inferred-generic-arg.rs new file mode 100644 index 0000000000000..106d6e7763c8b --- /dev/null +++ b/tests/ui/lint/dead-code/inferred-generic-arg.rs @@ -0,0 +1,16 @@ +//@ check-pass + +#![deny(dead_code)] + +#[derive(Default)] +struct Test { + +} + +fn main() { + if let Some::(test) = magic::() { } +} + +fn magic() -> Option { + Some(T::default()) +} From 5f6772c2a70180d397226388116a20fa414c556c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 21 Jul 2025 10:04:10 +0000 Subject: [PATCH 07/13] Constify trait aliases --- compiler/rustc_ast/src/ast.rs | 1 + compiler/rustc_ast/src/visit.rs | 4 +- compiler/rustc_ast_lowering/src/item.rs | 5 +- .../rustc_ast_pretty/src/pprust/state/item.rs | 7 ++- compiler/rustc_hir/src/hir.rs | 10 ++-- compiler/rustc_hir/src/intravisit.rs | 2 +- .../src/collect/predicates_of.rs | 4 +- .../src/collect/resolve_bound_vars.rs | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 6 ++- .../rustc_hir_typeck/src/method/suggest.rs | 2 +- compiler/rustc_parse/messages.ftl | 1 - compiler/rustc_parse/src/errors.rs | 8 ---- compiler/rustc_parse/src/parser/item.rs | 5 +- .../src/error_reporting/traits/mod.rs | 5 +- .../src/error_reporting/traits/suggestions.rs | 4 +- src/librustdoc/clean/mod.rs | 2 +- .../clippy_lints/src/item_name_repetitions.rs | 2 +- .../clippy/clippy_utils/src/ast_utils/mod.rs | 9 +++- tests/ui/consts/trait_alias.fail.stderr | 46 +++++++++++++++++++ tests/ui/consts/trait_alias.pass.stderr | 40 ++++++++++++++++ tests/ui/consts/trait_alias.rs | 31 +++++++++++++ 21 files changed, 157 insertions(+), 39 deletions(-) create mode 100644 tests/ui/consts/trait_alias.fail.stderr create mode 100644 tests/ui/consts/trait_alias.pass.stderr create mode 100644 tests/ui/consts/trait_alias.rs diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 81efafc2d1dca..6b7c8e6c19405 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3626,6 +3626,7 @@ impl Default for FnHeader { #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct TraitAlias { + pub constness: Const, pub ident: Ident, pub generics: Generics, #[visitable(extra = BoundKind::Bound)] diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index ed47c5f5274f6..d850698f47b08 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -833,8 +833,8 @@ macro_rules! common_visitor_and_walkers { visit_visitable!($($mut)? vis, impl_), ItemKind::Trait(trait_) => visit_visitable!($($mut)? vis, trait_), - ItemKind::TraitAlias(box TraitAlias { ident, generics, bounds }) => { - visit_visitable!($($mut)? vis, ident, generics); + ItemKind::TraitAlias(box TraitAlias { constness, ident, generics, bounds}) => { + visit_visitable!($($mut)? vis, constness, ident, generics); visit_visitable_with!($($mut)? vis, bounds, BoundKind::Bound) } ItemKind::MacCall(m) => diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 56ceeb7ac581f..177f33c0d8f1c 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -415,7 +415,8 @@ impl<'hir> LoweringContext<'_, 'hir> { ); hir::ItemKind::Trait(constness, *is_auto, safety, ident, generics, bounds, items) } - ItemKind::TraitAlias(box TraitAlias { ident, generics, bounds }) => { + ItemKind::TraitAlias(box TraitAlias { constness, ident, generics, bounds }) => { + let constness = self.lower_constness(*constness); let ident = self.lower_ident(*ident); let (generics, bounds) = self.lower_generics( generics, @@ -429,7 +430,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) }, ); - hir::ItemKind::TraitAlias(ident, generics, bounds) + hir::ItemKind::TraitAlias(constness, ident, generics, bounds) } ItemKind::MacroDef(ident, MacroDef { body, macro_rules }) => { let ident = self.lower_ident(*ident); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 36f1387d4b08a..294d03a83b161 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -385,8 +385,11 @@ impl<'a> State<'a> { let empty = item.attrs.is_empty() && items.is_empty(); self.bclose(item.span, empty, cb); } - ast::ItemKind::TraitAlias(box TraitAlias { ident, generics, bounds }) => { - let (cb, ib) = self.head(visibility_qualified(&item.vis, "trait")); + ast::ItemKind::TraitAlias(box TraitAlias { constness, ident, generics, bounds }) => { + let (cb, ib) = self.head(""); + self.print_visibility(&item.vis); + self.print_constness(*constness); + self.word_nbsp("trait"); self.print_ident(*ident); self.print_generic_params(&generics.params); self.nbsp(); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 38cb12cf24bcb..31842e2023dc3 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4245,8 +4245,8 @@ impl<'hir> Item<'hir> { ItemKind::Trait(constness, is_auto, safety, ident, generics, bounds, items), (*constness, *is_auto, *safety, *ident, generics, bounds, items); - expect_trait_alias, (Ident, &'hir Generics<'hir>, GenericBounds<'hir>), - ItemKind::TraitAlias(ident, generics, bounds), (*ident, generics, bounds); + expect_trait_alias, (Constness, Ident, &'hir Generics<'hir>, GenericBounds<'hir>), + ItemKind::TraitAlias(constness, ident, generics, bounds), (*constness, *ident, generics, bounds); expect_impl, &Impl<'hir>, ItemKind::Impl(imp), imp; } @@ -4423,7 +4423,7 @@ pub enum ItemKind<'hir> { &'hir [TraitItemId], ), /// A trait alias. - TraitAlias(Ident, &'hir Generics<'hir>, GenericBounds<'hir>), + TraitAlias(Constness, Ident, &'hir Generics<'hir>, GenericBounds<'hir>), /// An implementation, e.g., `impl Trait for Foo { .. }`. Impl(Impl<'hir>), @@ -4468,7 +4468,7 @@ impl ItemKind<'_> { | ItemKind::Struct(ident, ..) | ItemKind::Union(ident, ..) | ItemKind::Trait(_, _, _, ident, ..) - | ItemKind::TraitAlias(ident, ..) => Some(ident), + | ItemKind::TraitAlias(_, ident, ..) => Some(ident), ItemKind::Use(_, UseKind::Glob | UseKind::ListStem) | ItemKind::ForeignMod { .. } @@ -4486,7 +4486,7 @@ impl ItemKind<'_> { | ItemKind::Struct(_, generics, _) | ItemKind::Union(_, generics, _) | ItemKind::Trait(_, _, _, _, generics, _, _) - | ItemKind::TraitAlias(_, generics, _) + | ItemKind::TraitAlias(_, _, generics, _) | ItemKind::Impl(Impl { generics, .. }) => generics, _ => return None, }) diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index dde71e499c47a..4ab0500cafbcf 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -626,7 +626,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_trait_item_ref, trait_item_refs); } - ItemKind::TraitAlias(ident, ref generics, bounds) => { + ItemKind::TraitAlias(_constness, ident, ref generics, bounds) => { try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); walk_list!(visitor, visit_param_bound, bounds); diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 79aaa0cb79701..65aa19b913429 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -167,7 +167,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen } } ItemKind::Trait(_, _, _, _, _, self_bounds, ..) - | ItemKind::TraitAlias(_, _, self_bounds) => { + | ItemKind::TraitAlias(_, _, _, self_bounds) => { is_trait = Some((self_bounds, item.span)); } _ => {} @@ -654,7 +654,7 @@ pub(super) fn implied_predicates_with_filter<'tcx>( let (generics, superbounds) = match item.kind { hir::ItemKind::Trait(.., generics, supertraits, _) => (generics, supertraits), - hir::ItemKind::TraitAlias(_, generics, supertraits) => (generics, supertraits), + hir::ItemKind::TraitAlias(_, _, generics, supertraits) => (generics, supertraits), _ => span_bug!(item.span, "super_predicates invoked on non-trait"), }; diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 8133f9f68234b..14e48594c006c 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -632,7 +632,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { | hir::ItemKind::Struct(_, generics, _) | hir::ItemKind::Union(_, generics, _) | hir::ItemKind::Trait(_, _, _, _, generics, ..) - | hir::ItemKind::TraitAlias(_, generics, ..) + | hir::ItemKind::TraitAlias(_, _, generics, ..) | hir::ItemKind::Impl(hir::Impl { generics, .. }) => { // These kinds of items have only early-bound lifetime parameters. self.visit_early(item.hir_id(), generics, |this| intravisit::walk_item(this, item)); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index ed5f61b3c69ab..f838a592d94e2 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -765,8 +765,10 @@ impl<'a> State<'a> { } self.bclose(item.span, cb); } - hir::ItemKind::TraitAlias(ident, generics, bounds) => { - let (cb, ib) = self.head("trait"); + hir::ItemKind::TraitAlias(constness, ident, generics, bounds) => { + let (cb, ib) = self.head(""); + self.print_constness(constness); + self.word_nbsp("trait"); self.print_ident(ident); self.print_generic_params(generics.params); self.nbsp(); diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 8f2e06dd71272..0ddf5dd477848 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1594,7 +1594,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Node::Item(hir::Item { kind: hir::ItemKind::Trait(_, _, _, ident, ..) - | hir::ItemKind::TraitAlias(ident, ..), + | hir::ItemKind::TraitAlias(_, ident, ..), .. }) // We may also encounter unsatisfied GAT or method bounds diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 52a35c98a98b5..1862900077f0f 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -863,7 +863,6 @@ parse_too_short_hex_escape = numeric character escape is too short parse_trailing_vert_not_allowed = a trailing `{$token}` is not allowed in an or-pattern parse_trait_alias_cannot_be_auto = trait aliases cannot be `auto` -parse_trait_alias_cannot_be_const = trait aliases cannot be `const` parse_trait_alias_cannot_be_unsafe = trait aliases cannot be `unsafe` parse_trait_impl_modifier_in_inherent_impl = inherent impls cannot be {$modifier_name} diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 6d536aa850b3d..a35c5c304d95e 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1999,14 +1999,6 @@ pub(crate) struct TraitAliasCannotBeAuto { pub span: Span, } -#[derive(Diagnostic)] -#[diag(parse_trait_alias_cannot_be_const)] -pub(crate) struct TraitAliasCannotBeConst { - #[primary_span] - #[label(parse_trait_alias_cannot_be_const)] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(parse_trait_alias_cannot_be_unsafe)] pub(crate) struct TraitAliasCannotBeUnsafe { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index fde98d14ce11f..4bb0d05c4f37c 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -943,9 +943,6 @@ impl<'a> Parser<'a> { self.expect_semi()?; let whole_span = lo.to(self.prev_token.span); - if let Const::Yes(_) = constness { - self.dcx().emit_err(errors::TraitAliasCannotBeConst { span: whole_span }); - } if is_auto == IsAuto::Yes { self.dcx().emit_err(errors::TraitAliasCannotBeAuto { span: whole_span }); } @@ -955,7 +952,7 @@ impl<'a> Parser<'a> { self.psess.gated_spans.gate(sym::trait_alias, whole_span); - Ok(ItemKind::TraitAlias(Box::new(TraitAlias { ident, generics, bounds }))) + Ok(ItemKind::TraitAlias(Box::new(TraitAlias { constness, ident, generics, bounds }))) } else { // It's a normal trait. generics.where_clause = self.parse_where_clause()?; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index ded5969e83c5c..8e4c7cec0dcf0 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -476,9 +476,8 @@ pub fn report_dyn_incompatibility<'tcx>( let trait_str = tcx.def_path_str(trait_def_id); let trait_span = tcx.hir_get_if_local(trait_def_id).and_then(|node| match node { hir::Node::Item(item) => match item.kind { - hir::ItemKind::Trait(_, _, _, ident, ..) | hir::ItemKind::TraitAlias(ident, _, _) => { - Some(ident.span) - } + hir::ItemKind::Trait(_, _, _, ident, ..) + | hir::ItemKind::TraitAlias(_, ident, _, _) => Some(ident.span), _ => unreachable!(), }, _ => None, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 4ecc48d6cc40f..cd0dbb4d87f99 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -364,7 +364,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | hir::ItemKind::Fn { generics, .. } | hir::ItemKind::TyAlias(_, generics, _) | hir::ItemKind::Const(_, generics, _, _) - | hir::ItemKind::TraitAlias(_, generics, _), + | hir::ItemKind::TraitAlias(_, _, generics, _), .. }) | hir::Node::TraitItem(hir::TraitItem { generics, .. }) @@ -444,7 +444,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | hir::ItemKind::Fn { generics, .. } | hir::ItemKind::TyAlias(_, generics, _) | hir::ItemKind::Const(_, generics, _, _) - | hir::ItemKind::TraitAlias(_, generics, _), + | hir::ItemKind::TraitAlias(_, _, generics, _), .. }) if finder.can_suggest_bound(generics) => { // Missing generic type parameter bound. diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4a95f21a3a5bd..7f23023622f61 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2828,7 +2828,7 @@ fn clean_maybe_renamed_item<'tcx>( variants: def.variants.iter().map(|v| clean_variant(v, cx)).collect(), generics: clean_generics(generics, cx), }), - ItemKind::TraitAlias(_, generics, bounds) => TraitAliasItem(TraitAlias { + ItemKind::TraitAlias(_, _, generics, bounds) => TraitAliasItem(TraitAlias { generics: clean_generics(generics, cx), bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), }), diff --git a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs index 76f5fdfaa8dcf..22767901614e1 100644 --- a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs +++ b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs @@ -528,7 +528,7 @@ impl LateLintPass<'_> for ItemNameRepetitions { | ItemKind::Macro(ident, ..) | ItemKind::Static(_, ident, ..) | ItemKind::Trait(_, _, _, ident, ..) - | ItemKind::TraitAlias(ident, ..) + | ItemKind::TraitAlias(_, ident, ..) | ItemKind::TyAlias(ident, ..) | ItemKind::Union(ident, ..) | ItemKind::Use(_, UseKind::Single(ident)) => ident, 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 4df1eb508713c..839b46325b5ea 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -478,13 +478,20 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { ident: li, generics: lg, bounds: lb, + constness: lc, }), TraitAlias(box ast::TraitAlias { ident: ri, generics: rg, bounds: rb, + constness: rc, }), - ) => eq_id(*li, *ri) && eq_generics(lg, rg) && over(lb, rb, eq_generic_bound), + ) => { + matches!(lc, ast::Const::No) == matches!(rc, ast::Const::No) + && eq_id(*li, *ri) + && eq_generics(lg, rg) + && over(lb, rb, eq_generic_bound) + }, ( Impl(ast::Impl { generics: lg, diff --git a/tests/ui/consts/trait_alias.fail.stderr b/tests/ui/consts/trait_alias.fail.stderr new file mode 100644 index 0000000000000..97eb685b16a90 --- /dev/null +++ b/tests/ui/consts/trait_alias.fail.stderr @@ -0,0 +1,46 @@ +error: `[const]` is not allowed here + --> $DIR/trait_alias.rs:14:19 + | +LL | const trait Foo = [const] Bar + Baz; + | ^^^^^^^ + | + = note: this item cannot have `[const]` trait bounds + +error: `[const]` can only be applied to `const` traits + --> $DIR/trait_alias.rs:17:17 + | +LL | const fn foo(x: &T) { + | ^^^^^^^ can't be applied to `Foo` + | +help: mark `Foo` as `const` to allow it to have `const` implementations + | +LL | #[const_trait] const trait Foo = [const] Bar + Baz; + | ++++++++++++++ + +error: `[const]` can only be applied to `const` traits + --> $DIR/trait_alias.rs:17:17 + | +LL | const fn foo(x: &T) { + | ^^^^^^^ can't be applied to `Foo` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: mark `Foo` as `const` to allow it to have `const` implementations + | +LL | #[const_trait] const trait Foo = [const] Bar + Baz; + | ++++++++++++++ + +error[E0277]: the trait bound `T: [const] Bar` is not satisfied + --> $DIR/trait_alias.rs:20:7 + | +LL | x.bar(); + | ^^^ + +error[E0277]: the trait bound `T: [const] Baz` is not satisfied + --> $DIR/trait_alias.rs:24:11 + | +LL | x.baz(); + | ^^^ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/trait_alias.pass.stderr b/tests/ui/consts/trait_alias.pass.stderr new file mode 100644 index 0000000000000..00e7e2ca98c75 --- /dev/null +++ b/tests/ui/consts/trait_alias.pass.stderr @@ -0,0 +1,40 @@ +error: `[const]` is not allowed here + --> $DIR/trait_alias.rs:14:19 + | +LL | const trait Foo = [const] Bar + Baz; + | ^^^^^^^ + | + = note: this item cannot have `[const]` trait bounds + +error: `[const]` can only be applied to `const` traits + --> $DIR/trait_alias.rs:17:17 + | +LL | const fn foo(x: &T) { + | ^^^^^^^ can't be applied to `Foo` + | +help: mark `Foo` as `const` to allow it to have `const` implementations + | +LL | #[const_trait] const trait Foo = [const] Bar + Baz; + | ++++++++++++++ + +error: `[const]` can only be applied to `const` traits + --> $DIR/trait_alias.rs:17:17 + | +LL | const fn foo(x: &T) { + | ^^^^^^^ can't be applied to `Foo` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: mark `Foo` as `const` to allow it to have `const` implementations + | +LL | #[const_trait] const trait Foo = [const] Bar + Baz; + | ++++++++++++++ + +error[E0277]: the trait bound `T: [const] Bar` is not satisfied + --> $DIR/trait_alias.rs:20:7 + | +LL | x.bar(); + | ^^^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/trait_alias.rs b/tests/ui/consts/trait_alias.rs new file mode 100644 index 0000000000000..945465de2ff8c --- /dev/null +++ b/tests/ui/consts/trait_alias.rs @@ -0,0 +1,31 @@ +#![feature(trait_alias, const_trait_impl)] +//@ revisions: pass fail + +const trait Bar { + fn bar(&self) {} +} +const trait Baz { + fn baz(&self) {} +} + +impl const Bar for () {} +impl const Baz for () {} + +const trait Foo = [const] Bar + Baz; +//~^ ERROR: `[const]` is not allowed here + +const fn foo(x: &T) { + //~^ ERROR: `[const]` can only be applied to `const` traits + //~| ERROR: `[const]` can only be applied to `const` traits + x.bar(); + //~^ ERROR: the trait bound `T: [const] Bar` is not satisfied + #[cfg(fail)] + { + x.baz(); + //[fail]~^ ERROR: the trait bound `T: [const] Baz` is not satisfied + } +} + +const _: () = foo(&()); + +fn main() {} From 8b122f1e11a0a6bf7447d03e633b553a5c623c8a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 21 Jul 2025 11:35:45 +0000 Subject: [PATCH 08/13] Generate const predicates for const trait aliases --- .../rustc_ast_passes/src/ast_validation.rs | 8 +++ compiler/rustc_hir_analysis/src/collect.rs | 2 +- .../src/collect/predicates_of.rs | 18 ++++--- compiler/rustc_middle/src/ty/mod.rs | 3 +- tests/ui/consts/trait_alias.fail.stderr | 51 +++++-------------- tests/ui/consts/trait_alias.pass.stderr | 43 ++++------------ tests/ui/consts/trait_alias.rs | 5 +- 7 files changed, 45 insertions(+), 85 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 93f8b74ad561f..6b218f34363dd 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1192,6 +1192,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> { walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait); }); } + ItemKind::TraitAlias(box TraitAlias { constness, generics, bounds, .. }) => { + let disallowed = matches!(constness, ast::Const::No) + .then(|| TildeConstReason::Trait { span: item.span }); + self.with_tilde_const(disallowed, |this| { + this.visit_generics(generics); + walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits) + }); + } ItemKind::Mod(safety, ident, mod_kind) => { if let &Safety::Unsafe(span) = safety { self.dcx().emit_err(errors::UnsafeItem { span, kind: "module" }); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 89ab710ff8218..1386070e3d9b6 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -847,7 +847,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { hir::ItemKind::Trait(constness, is_auto, safety, ..) => { (constness, false, is_auto == hir::IsAuto::Yes, safety) } - hir::ItemKind::TraitAlias(..) => (hir::Constness::NotConst, true, false, hir::Safety::Safe), + hir::ItemKind::TraitAlias(constness, ..) => (constness, true, false, hir::Safety::Safe), _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"), }; diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 65aa19b913429..88deed1be6838 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -1031,7 +1031,8 @@ pub(super) fn const_conditions<'tcx>( Node::Item(item) => match item.kind { hir::ItemKind::Impl(impl_) => (impl_.generics, None, false), hir::ItemKind::Fn { generics, .. } => (generics, None, false), - hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => { + hir::ItemKind::TraitAlias(_, _, generics, supertraits) + | hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => { (generics, Some((item.owner_id.def_id, supertraits)), false) } _ => bug!("const_conditions called on wrong item: {def_id:?}"), @@ -1143,13 +1144,14 @@ pub(super) fn explicit_implied_const_bounds<'tcx>( span_bug!(tcx.def_span(def_id), "RPITIT in impl should not have item bounds") } None => match tcx.hir_node_by_def_id(def_id) { - Node::Item(hir::Item { kind: hir::ItemKind::Trait(..), .. }) => { - implied_predicates_with_filter( - tcx, - def_id.to_def_id(), - PredicateFilter::SelfConstIfConst, - ) - } + Node::Item(hir::Item { + kind: hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..), + .. + }) => implied_predicates_with_filter( + tcx, + def_id.to_def_id(), + PredicateFilter::SelfConstIfConst, + ), Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. }) | Node::OpaqueTy(_) => { explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::ConstIfConst) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 93d0c77c1daee..905874f05628f 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2101,7 +2101,7 @@ impl<'tcx> TyCtxt<'tcx> { DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) => { self.constness(def_id) == hir::Constness::Const } - DefKind::Trait => self.is_const_trait(def_id), + DefKind::TraitAlias | DefKind::Trait => self.is_const_trait(def_id), DefKind::AssocTy => { let parent_def_id = self.parent(def_id); match self.def_kind(parent_def_id) { @@ -2144,7 +2144,6 @@ impl<'tcx> TyCtxt<'tcx> { | DefKind::Variant | DefKind::TyAlias | DefKind::ForeignTy - | DefKind::TraitAlias | DefKind::TyParam | DefKind::Const | DefKind::ConstParam diff --git a/tests/ui/consts/trait_alias.fail.stderr b/tests/ui/consts/trait_alias.fail.stderr index 97eb685b16a90..e9148f0bfece2 100644 --- a/tests/ui/consts/trait_alias.fail.stderr +++ b/tests/ui/consts/trait_alias.fail.stderr @@ -1,46 +1,23 @@ -error: `[const]` is not allowed here - --> $DIR/trait_alias.rs:14:19 - | -LL | const trait Foo = [const] Bar + Baz; - | ^^^^^^^ +error[E0277]: the trait bound `T: [const] Baz` is not satisfied + --> $DIR/trait_alias.rs:20:11 | - = note: this item cannot have `[const]` trait bounds +LL | x.baz(); + | ^^^ -error: `[const]` can only be applied to `const` traits - --> $DIR/trait_alias.rs:17:17 +error[E0277]: the trait bound `(): const Foo` is not satisfied + --> $DIR/trait_alias.rs:25:19 | -LL | const fn foo(x: &T) { - | ^^^^^^^ can't be applied to `Foo` - | -help: mark `Foo` as `const` to allow it to have `const` implementations +LL | const _: () = foo(&()); + | --- ^^^ + | | + | required by a bound introduced by this call | -LL | #[const_trait] const trait Foo = [const] Bar + Baz; - | ++++++++++++++ - -error: `[const]` can only be applied to `const` traits - --> $DIR/trait_alias.rs:17:17 +note: required by a bound in `foo` + --> $DIR/trait_alias.rs:16:17 | LL | const fn foo(x: &T) { - | ^^^^^^^ can't be applied to `Foo` - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `const` to allow it to have `const` implementations - | -LL | #[const_trait] const trait Foo = [const] Bar + Baz; - | ++++++++++++++ - -error[E0277]: the trait bound `T: [const] Bar` is not satisfied - --> $DIR/trait_alias.rs:20:7 - | -LL | x.bar(); - | ^^^ - -error[E0277]: the trait bound `T: [const] Baz` is not satisfied - --> $DIR/trait_alias.rs:24:11 - | -LL | x.baz(); - | ^^^ + | ^^^^^^^^^^^ required by this bound in `foo` -error: aborting due to 5 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/trait_alias.pass.stderr b/tests/ui/consts/trait_alias.pass.stderr index 00e7e2ca98c75..d107ddbf8e457 100644 --- a/tests/ui/consts/trait_alias.pass.stderr +++ b/tests/ui/consts/trait_alias.pass.stderr @@ -1,40 +1,17 @@ -error: `[const]` is not allowed here - --> $DIR/trait_alias.rs:14:19 +error[E0277]: the trait bound `(): const Foo` is not satisfied + --> $DIR/trait_alias.rs:25:19 | -LL | const trait Foo = [const] Bar + Baz; - | ^^^^^^^ +LL | const _: () = foo(&()); + | --- ^^^ + | | + | required by a bound introduced by this call | - = note: this item cannot have `[const]` trait bounds - -error: `[const]` can only be applied to `const` traits - --> $DIR/trait_alias.rs:17:17 - | -LL | const fn foo(x: &T) { - | ^^^^^^^ can't be applied to `Foo` - | -help: mark `Foo` as `const` to allow it to have `const` implementations - | -LL | #[const_trait] const trait Foo = [const] Bar + Baz; - | ++++++++++++++ - -error: `[const]` can only be applied to `const` traits - --> $DIR/trait_alias.rs:17:17 +note: required by a bound in `foo` + --> $DIR/trait_alias.rs:16:17 | LL | const fn foo(x: &T) { - | ^^^^^^^ can't be applied to `Foo` - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `const` to allow it to have `const` implementations - | -LL | #[const_trait] const trait Foo = [const] Bar + Baz; - | ++++++++++++++ - -error[E0277]: the trait bound `T: [const] Bar` is not satisfied - --> $DIR/trait_alias.rs:20:7 - | -LL | x.bar(); - | ^^^ + | ^^^^^^^^^^^ required by this bound in `foo` -error: aborting due to 4 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/trait_alias.rs b/tests/ui/consts/trait_alias.rs index 945465de2ff8c..0755c1126b06b 100644 --- a/tests/ui/consts/trait_alias.rs +++ b/tests/ui/consts/trait_alias.rs @@ -12,13 +12,9 @@ impl const Bar for () {} impl const Baz for () {} const trait Foo = [const] Bar + Baz; -//~^ ERROR: `[const]` is not allowed here const fn foo(x: &T) { - //~^ ERROR: `[const]` can only be applied to `const` traits - //~| ERROR: `[const]` can only be applied to `const` traits x.bar(); - //~^ ERROR: the trait bound `T: [const] Bar` is not satisfied #[cfg(fail)] { x.baz(); @@ -27,5 +23,6 @@ const fn foo(x: &T) { } const _: () = foo(&()); +//~^ ERROR: `(): const Foo` is not satisfied fn main() {} From 544a5a3e0e6d4c69d62b8e331732c896fe3376d0 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 21 Jul 2025 13:57:44 +0000 Subject: [PATCH 09/13] Make const trait aliases work in next solver --- .../src/collect/predicates_of.rs | 22 +++++++------ .../src/solve/effect_goals.rs | 31 +++++++++++++++++-- tests/ui/consts/trait_alias.fail.stderr | 18 ++--------- tests/ui/consts/trait_alias.pass.stderr | 17 ---------- tests/ui/consts/trait_alias.rs | 3 +- 5 files changed, 45 insertions(+), 46 deletions(-) delete mode 100644 tests/ui/consts/trait_alias.pass.stderr diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 88deed1be6838..2eefe1eb3e922 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -1031,9 +1031,11 @@ pub(super) fn const_conditions<'tcx>( Node::Item(item) => match item.kind { hir::ItemKind::Impl(impl_) => (impl_.generics, None, false), hir::ItemKind::Fn { generics, .. } => (generics, None, false), - hir::ItemKind::TraitAlias(_, _, generics, supertraits) - | hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => { - (generics, Some((item.owner_id.def_id, supertraits)), false) + hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => { + (generics, Some((Some(item.owner_id.def_id), supertraits)), false) + } + hir::ItemKind::TraitAlias(_, _, generics, supertraits) => { + (generics, Some((None, supertraits)), false) } _ => bug!("const_conditions called on wrong item: {def_id:?}"), }, @@ -1090,12 +1092,14 @@ pub(super) fn const_conditions<'tcx>( } if let Some((def_id, supertraits)) = trait_def_id_and_supertraits { - // We've checked above that the trait is conditionally const. - bounds.push(( - ty::Binder::dummy(ty::TraitRef::identity(tcx, def_id.to_def_id())) - .to_host_effect_clause(tcx, ty::BoundConstness::Maybe), - DUMMY_SP, - )); + if let Some(def_id) = def_id { + // We've checked above that the trait is conditionally const. + bounds.push(( + ty::Binder::dummy(ty::TraitRef::identity(tcx, def_id.to_def_id())) + .to_host_effect_clause(tcx, ty::BoundConstness::Maybe), + DUMMY_SP, + )); + } icx.lowerer().lower_bounds( tcx.types.self_param, diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 48bd0963c8743..c18f22ca0fb10 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -196,10 +196,35 @@ where } fn consider_trait_alias_candidate( - _ecx: &mut EvalCtxt<'_, D>, - _goal: Goal, + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, ) -> Result, NoSolution> { - unreachable!("trait aliases are never const") + let cx = ecx.cx(); + + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { + let where_clause_bounds = cx + .predicates_of(goal.predicate.def_id().into()) + .iter_instantiated(cx, goal.predicate.trait_ref.args) + .map(|p| goal.with(cx, p)); + + let const_conditions = cx + .const_conditions(goal.predicate.def_id().into()) + .iter_instantiated(cx, goal.predicate.trait_ref.args) + .map(|bound_trait_ref| { + goal.with( + cx, + bound_trait_ref.to_host_effect_clause(cx, goal.predicate.constness), + ) + }); + // While you could think of trait aliases to have a single builtin impl + // which uses its implied trait bounds as where-clauses, using + // `GoalSource::ImplWhereClause` here would be incorrect, as we also + // impl them, which means we're "stepping out of the impl constructor" + // again. To handle this, we treat these cycles as ambiguous for now. + ecx.add_goals(GoalSource::Misc, where_clause_bounds); + ecx.add_goals(GoalSource::Misc, const_conditions); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) } fn consider_builtin_sizedness_candidates( diff --git a/tests/ui/consts/trait_alias.fail.stderr b/tests/ui/consts/trait_alias.fail.stderr index e9148f0bfece2..bb0a4e22efcf3 100644 --- a/tests/ui/consts/trait_alias.fail.stderr +++ b/tests/ui/consts/trait_alias.fail.stderr @@ -1,23 +1,9 @@ error[E0277]: the trait bound `T: [const] Baz` is not satisfied - --> $DIR/trait_alias.rs:20:11 + --> $DIR/trait_alias.rs:22:11 | LL | x.baz(); | ^^^ -error[E0277]: the trait bound `(): const Foo` is not satisfied - --> $DIR/trait_alias.rs:25:19 - | -LL | const _: () = foo(&()); - | --- ^^^ - | | - | required by a bound introduced by this call - | -note: required by a bound in `foo` - --> $DIR/trait_alias.rs:16:17 - | -LL | const fn foo(x: &T) { - | ^^^^^^^^^^^ required by this bound in `foo` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/trait_alias.pass.stderr b/tests/ui/consts/trait_alias.pass.stderr deleted file mode 100644 index d107ddbf8e457..0000000000000 --- a/tests/ui/consts/trait_alias.pass.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0277]: the trait bound `(): const Foo` is not satisfied - --> $DIR/trait_alias.rs:25:19 - | -LL | const _: () = foo(&()); - | --- ^^^ - | | - | required by a bound introduced by this call - | -note: required by a bound in `foo` - --> $DIR/trait_alias.rs:16:17 - | -LL | const fn foo(x: &T) { - | ^^^^^^^^^^^ required by this bound in `foo` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/trait_alias.rs b/tests/ui/consts/trait_alias.rs index 0755c1126b06b..2496ef609865a 100644 --- a/tests/ui/consts/trait_alias.rs +++ b/tests/ui/consts/trait_alias.rs @@ -1,5 +1,7 @@ #![feature(trait_alias, const_trait_impl)] //@ revisions: pass fail +//@ compile-flags: -Znext-solver +//@[pass] check-pass const trait Bar { fn bar(&self) {} @@ -23,6 +25,5 @@ const fn foo(x: &T) { } const _: () = foo(&()); -//~^ ERROR: `(): const Foo` is not satisfied fn main() {} From bc4d612d46f8cfc63a4718109450572b071fb2d8 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 21 Jul 2025 14:10:20 +0000 Subject: [PATCH 10/13] Prepare test for old solver --- tests/ui/consts/trait_alias.fail.stderr | 18 ++++++++++++++++-- tests/ui/consts/trait_alias.next_fail.stderr | 9 +++++++++ tests/ui/consts/trait_alias.pass.stderr | 17 +++++++++++++++++ tests/ui/consts/trait_alias.rs | 12 +++++++----- 4 files changed, 49 insertions(+), 7 deletions(-) create mode 100644 tests/ui/consts/trait_alias.next_fail.stderr create mode 100644 tests/ui/consts/trait_alias.pass.stderr diff --git a/tests/ui/consts/trait_alias.fail.stderr b/tests/ui/consts/trait_alias.fail.stderr index bb0a4e22efcf3..8cf9a7c877702 100644 --- a/tests/ui/consts/trait_alias.fail.stderr +++ b/tests/ui/consts/trait_alias.fail.stderr @@ -1,9 +1,23 @@ error[E0277]: the trait bound `T: [const] Baz` is not satisfied - --> $DIR/trait_alias.rs:22:11 + --> $DIR/trait_alias.rs:23:11 | LL | x.baz(); | ^^^ -error: aborting due to 1 previous error +error[E0277]: the trait bound `(): const Foo` is not satisfied + --> $DIR/trait_alias.rs:28:19 + | +LL | const _: () = foo(&()); + | --- ^^^ + | | + | required by a bound introduced by this call + | +note: required by a bound in `foo` + --> $DIR/trait_alias.rs:19:17 + | +LL | const fn foo(x: &T) { + | ^^^^^^^^^^^ required by this bound in `foo` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/trait_alias.next_fail.stderr b/tests/ui/consts/trait_alias.next_fail.stderr new file mode 100644 index 0000000000000..1a72b9c70de79 --- /dev/null +++ b/tests/ui/consts/trait_alias.next_fail.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `T: [const] Baz` is not satisfied + --> $DIR/trait_alias.rs:23:11 + | +LL | x.baz(); + | ^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/trait_alias.pass.stderr b/tests/ui/consts/trait_alias.pass.stderr new file mode 100644 index 0000000000000..bbd598e80785e --- /dev/null +++ b/tests/ui/consts/trait_alias.pass.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `(): const Foo` is not satisfied + --> $DIR/trait_alias.rs:28:19 + | +LL | const _: () = foo(&()); + | --- ^^^ + | | + | required by a bound introduced by this call + | +note: required by a bound in `foo` + --> $DIR/trait_alias.rs:19:17 + | +LL | const fn foo(x: &T) { + | ^^^^^^^^^^^ required by this bound in `foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/trait_alias.rs b/tests/ui/consts/trait_alias.rs index 2496ef609865a..4062c19f52d22 100644 --- a/tests/ui/consts/trait_alias.rs +++ b/tests/ui/consts/trait_alias.rs @@ -1,7 +1,8 @@ #![feature(trait_alias, const_trait_impl)] -//@ revisions: pass fail -//@ compile-flags: -Znext-solver -//@[pass] check-pass +//@ revisions: next_pass next_fail pass fail +//@[next_pass] compile-flags: -Znext-solver +//@[next_fail] compile-flags: -Znext-solver +//@[next_pass] check-pass const trait Bar { fn bar(&self) {} @@ -17,13 +18,14 @@ const trait Foo = [const] Bar + Baz; const fn foo(x: &T) { x.bar(); - #[cfg(fail)] + #[cfg(any(fail, next_fail))] { x.baz(); - //[fail]~^ ERROR: the trait bound `T: [const] Baz` is not satisfied + //[fail,next_fail]~^ ERROR: the trait bound `T: [const] Baz` is not satisfied } } const _: () = foo(&()); +//[fail,pass]~^ ERROR: `(): const Foo` is not satisfied fn main() {} From b9e7cf61bea80490b970ff7429e1fa8acc00f025 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 22 Jul 2025 07:23:33 +0000 Subject: [PATCH 11/13] Make const trait aliases work in the old solver --- .../src/traits/effects.rs | 40 +++++++++++++++++++ tests/ui/consts/trait_alias.fail.stderr | 18 +-------- tests/ui/consts/trait_alias.next_fail.stderr | 2 +- tests/ui/consts/trait_alias.pass.stderr | 17 -------- tests/ui/consts/trait_alias.rs | 2 +- 5 files changed, 44 insertions(+), 35 deletions(-) delete mode 100644 tests/ui/consts/trait_alias.pass.stderr diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index 7f2a9999d6464..d2094046ed44e 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -69,6 +69,12 @@ pub fn evaluate_host_effect_obligation<'tcx>( Err(EvaluationFailure::NoSolution) => {} } + match evaluate_host_effect_from_trait_alias(selcx, obligation) { + Ok(result) => return Ok(result), + Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous), + Err(EvaluationFailure::NoSolution) => {} + } + Err(EvaluationFailure::NoSolution) } @@ -496,3 +502,37 @@ fn evaluate_host_effect_from_selection_candidate<'tcx>( } }) } + +fn evaluate_host_effect_from_trait_alias<'tcx>( + selcx: &mut SelectionContext<'_, 'tcx>, + obligation: &HostEffectObligation<'tcx>, +) -> Result>, EvaluationFailure> { + let tcx = selcx.tcx(); + let def_id = obligation.predicate.def_id(); + if !tcx.trait_is_alias(def_id) { + return Err(EvaluationFailure::NoSolution); + } + + Ok(tcx + .const_conditions(def_id) + .instantiate(tcx, obligation.predicate.trait_ref.args) + .into_iter() + .map(|(trait_ref, span)| { + Obligation::new( + tcx, + obligation.cause.clone().derived_host_cause( + ty::Binder::dummy(obligation.predicate), + |derived| { + ObligationCauseCode::ImplDerivedHost(Box::new(ImplDerivedHostCause { + derived, + impl_def_id: def_id, + span, + })) + }, + ), + obligation.param_env, + trait_ref.to_host_effect_clause(tcx, obligation.predicate.constness), + ) + }) + .collect()) +} diff --git a/tests/ui/consts/trait_alias.fail.stderr b/tests/ui/consts/trait_alias.fail.stderr index 8cf9a7c877702..16675206a7a4b 100644 --- a/tests/ui/consts/trait_alias.fail.stderr +++ b/tests/ui/consts/trait_alias.fail.stderr @@ -1,23 +1,9 @@ error[E0277]: the trait bound `T: [const] Baz` is not satisfied - --> $DIR/trait_alias.rs:23:11 + --> $DIR/trait_alias.rs:24:11 | LL | x.baz(); | ^^^ -error[E0277]: the trait bound `(): const Foo` is not satisfied - --> $DIR/trait_alias.rs:28:19 - | -LL | const _: () = foo(&()); - | --- ^^^ - | | - | required by a bound introduced by this call - | -note: required by a bound in `foo` - --> $DIR/trait_alias.rs:19:17 - | -LL | const fn foo(x: &T) { - | ^^^^^^^^^^^ required by this bound in `foo` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/trait_alias.next_fail.stderr b/tests/ui/consts/trait_alias.next_fail.stderr index 1a72b9c70de79..16675206a7a4b 100644 --- a/tests/ui/consts/trait_alias.next_fail.stderr +++ b/tests/ui/consts/trait_alias.next_fail.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `T: [const] Baz` is not satisfied - --> $DIR/trait_alias.rs:23:11 + --> $DIR/trait_alias.rs:24:11 | LL | x.baz(); | ^^^ diff --git a/tests/ui/consts/trait_alias.pass.stderr b/tests/ui/consts/trait_alias.pass.stderr deleted file mode 100644 index bbd598e80785e..0000000000000 --- a/tests/ui/consts/trait_alias.pass.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0277]: the trait bound `(): const Foo` is not satisfied - --> $DIR/trait_alias.rs:28:19 - | -LL | const _: () = foo(&()); - | --- ^^^ - | | - | required by a bound introduced by this call - | -note: required by a bound in `foo` - --> $DIR/trait_alias.rs:19:17 - | -LL | const fn foo(x: &T) { - | ^^^^^^^^^^^ required by this bound in `foo` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/trait_alias.rs b/tests/ui/consts/trait_alias.rs index 4062c19f52d22..3d9a60cefc7cc 100644 --- a/tests/ui/consts/trait_alias.rs +++ b/tests/ui/consts/trait_alias.rs @@ -3,6 +3,7 @@ //@[next_pass] compile-flags: -Znext-solver //@[next_fail] compile-flags: -Znext-solver //@[next_pass] check-pass +//@[pass] check-pass const trait Bar { fn bar(&self) {} @@ -26,6 +27,5 @@ const fn foo(x: &T) { } const _: () = foo(&()); -//[fail,pass]~^ ERROR: `(): const Foo` is not satisfied fn main() {} From a6ca44cf4092c790664d7218c032ea47ba41f0bc Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 22 Jul 2025 08:11:23 +0000 Subject: [PATCH 12/13] Add more tests --- src/tools/rustfmt/tests/source/trait.rs | 2 ++ src/tools/rustfmt/tests/target/trait.rs | 2 ++ tests/ui/consts/trait_alias_method_call.rs | 31 ++++++++++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 tests/ui/consts/trait_alias_method_call.rs diff --git a/src/tools/rustfmt/tests/source/trait.rs b/src/tools/rustfmt/tests/source/trait.rs index b6db9e1590d41..1970646f7770c 100644 --- a/src/tools/rustfmt/tests/source/trait.rs +++ b/src/tools/rustfmt/tests/source/trait.rs @@ -181,3 +181,5 @@ trait Visible { pub fn f(); pub fn g() {} } + +const trait Foomp = Hash; \ No newline at end of file diff --git a/src/tools/rustfmt/tests/target/trait.rs b/src/tools/rustfmt/tests/target/trait.rs index 7f067991b267b..cc2b59dc61629 100644 --- a/src/tools/rustfmt/tests/target/trait.rs +++ b/src/tools/rustfmt/tests/target/trait.rs @@ -218,3 +218,5 @@ trait Visible { pub fn f(); pub fn g() {} } + +trait Foomp = Hash; diff --git a/tests/ui/consts/trait_alias_method_call.rs b/tests/ui/consts/trait_alias_method_call.rs new file mode 100644 index 0000000000000..75c51f8f031b1 --- /dev/null +++ b/tests/ui/consts/trait_alias_method_call.rs @@ -0,0 +1,31 @@ +//! Test that we do not need to handle host effects in `expand_trait_aliases` + +#![feature(trait_alias, const_trait_impl)] +//@ check-pass + +mod foo { + pub const trait Bar { + fn bar(&self) {} + } + pub const trait Baz { + fn baz(&self) {} + } + + impl const Bar for () {} + impl const Baz for () {} + + pub const trait Foo = [const] Bar + Baz; +} + +use foo::Foo as _; + + +const _: () = { + // Ok via `[const] Bar` on `Foo` + ().bar(); + // Also works, because everything is fully concrete, so we're ignoring that + // `Baz` is not a const trait bound of `Foo`. + ().baz(); +}; + +fn main() {} From ebb249d69e84df66f183b45b45c51e21ad0d0988 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 23 Jul 2025 14:29:01 +0000 Subject: [PATCH 13/13] Fix formatting of const trait aliases --- src/tools/rustfmt/src/items.rs | 15 +++++++-------- src/tools/rustfmt/src/visitor.rs | 9 +-------- src/tools/rustfmt/tests/target/const_trait.rs | 5 +++++ src/tools/rustfmt/tests/target/trait.rs | 2 +- 4 files changed, 14 insertions(+), 17 deletions(-) create mode 100644 src/tools/rustfmt/tests/target/const_trait.rs diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index a2e89c10a4803..ecaa4670f61d2 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -1375,22 +1375,21 @@ impl<'a> Rewrite for TraitAliasBounds<'a> { pub(crate) fn format_trait_alias( context: &RewriteContext<'_>, - ident: symbol::Ident, + ta: &ast::TraitAlias, vis: &ast::Visibility, - generics: &ast::Generics, - generic_bounds: &ast::GenericBounds, shape: Shape, ) -> Option { - let alias = rewrite_ident(context, ident); + let alias = rewrite_ident(context, ta.ident); // 6 = "trait ", 2 = " =" let g_shape = shape.offset_left(6)?.sub_width(2)?; - let generics_str = rewrite_generics(context, alias, generics, g_shape).ok()?; + let generics_str = rewrite_generics(context, alias, &ta.generics, g_shape).ok()?; let vis_str = format_visibility(context, vis); - let lhs = format!("{vis_str}trait {generics_str} ="); + let constness = format_constness(ta.constness); + let lhs = format!("{vis_str}{constness}trait {generics_str} ="); // 1 = ";" let trait_alias_bounds = TraitAliasBounds { - generic_bounds, - generics, + generic_bounds: &ta.bounds, + generics: &ta.generics, }; rewrite_assign_rhs( context, diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index 633a17a40108f..c521b497a2d99 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -499,14 +499,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { } ast::ItemKind::TraitAlias(ref ta) => { let shape = Shape::indented(self.block_indent, self.config); - let rw = format_trait_alias( - &self.get_context(), - ta.ident, - &item.vis, - &ta.generics, - &ta.bounds, - shape, - ); + let rw = format_trait_alias(&self.get_context(), ta, &item.vis, shape); self.push_rewrite(item.span, rw); } ast::ItemKind::ExternCrate(..) => { diff --git a/src/tools/rustfmt/tests/target/const_trait.rs b/src/tools/rustfmt/tests/target/const_trait.rs new file mode 100644 index 0000000000000..c4c88b17fc500 --- /dev/null +++ b/src/tools/rustfmt/tests/target/const_trait.rs @@ -0,0 +1,5 @@ +#![feature(trait_alias, const_trait_impl)] + +const trait Bar {} + +const trait Foo = Bar; diff --git a/src/tools/rustfmt/tests/target/trait.rs b/src/tools/rustfmt/tests/target/trait.rs index cc2b59dc61629..7a65b13d629e7 100644 --- a/src/tools/rustfmt/tests/target/trait.rs +++ b/src/tools/rustfmt/tests/target/trait.rs @@ -219,4 +219,4 @@ trait Visible { pub fn g() {} } -trait Foomp = Hash; +const trait Foomp = Hash;