From 99d02fb40fd339255ed08596ebeb41e9b8a09d45 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 7 Nov 2024 16:09:39 +1100 Subject: [PATCH 01/44] Optimize `check_keyword_case`. `to_lowercase` allocates, but `eq_ignore_ascii_case` doesn't. This path is hot enough that this makes a small but noticeable difference in benchmarking. --- compiler/rustc_parse/src/parser/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 50a8b6542df..042ee96bbe8 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -641,9 +641,10 @@ impl<'a> Parser<'a> { return true; } + // Do an ASCII case-insensitive match, because all keywords are ASCII. if case == Case::Insensitive && let Some((ident, IdentIsRaw::No)) = self.token.ident() - && ident.as_str().to_lowercase() == kw.as_str().to_lowercase() + && ident.as_str().eq_ignore_ascii_case(kw.as_str()) { true } else { From 93f225856557d5930b64b329237a9a43e09637bc Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 7 Nov 2024 16:08:26 +1100 Subject: [PATCH 02/44] Use iteration instead of indexing to access ribs. This gives a small but noticeable performance improvement. --- compiler/rustc_resolve/src/ident.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index b80e0e196ca..c8f7a12132c 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -311,13 +311,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Walk backwards up the ribs in scope. let mut module = self.graph_root; - for i in (0..ribs.len()).rev() { - debug!("walk rib\n{:?}", ribs[i].bindings); + for (i, rib) in ribs.iter().enumerate().rev() { + debug!("walk rib\n{:?}", rib.bindings); // Use the rib kind to determine whether we are resolving parameters // (macro 2.0 hygiene) or local variables (`macro_rules` hygiene). - let rib_ident = if ribs[i].kind.contains_params() { normalized_ident } else { ident }; - if let Some((original_rib_ident_def, res)) = ribs[i].bindings.get_key_value(&rib_ident) - { + let rib_ident = if rib.kind.contains_params() { normalized_ident } else { ident }; + if let Some((original_rib_ident_def, res)) = rib.bindings.get_key_value(&rib_ident) { // The ident resolves to a type parameter or local variable. return Some(LexicalScopeBinding::Res(self.validate_res_from_ribs( i, @@ -329,7 +328,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ))); } - module = match ribs[i].kind { + module = match rib.kind { RibKind::Module(module) => module, RibKind::MacroDefinition(def) if def == self.macro_def(ident.span.ctxt()) => { // If an invocation of this macro created `ident`, give up on `ident` From d1d8be1d137404a52cdd28e78a9a9c59d38615b0 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 8 Nov 2024 08:50:51 +1100 Subject: [PATCH 03/44] Tweak a `resolutions` loop. In this case field access is more concise and easier to read than destructuring, and it matches how other similar loops are done elsewhere. --- compiler/rustc_resolve/src/lib.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 9abb3180388..cf37a4e3389 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1809,12 +1809,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { assoc_item: Option<(Symbol, Namespace)>, ) -> bool { match (trait_module, assoc_item) { - (Some(trait_module), Some((name, ns))) => { - self.resolutions(trait_module).borrow().iter().any(|resolution| { - let (&BindingKey { ident: assoc_ident, ns: assoc_ns, .. }, _) = resolution; - assoc_ns == ns && assoc_ident.name == name - }) - } + (Some(trait_module), Some((name, ns))) => self + .resolutions(trait_module) + .borrow() + .iter() + .any(|(key, _name_resolution)| key.ns == ns && key.ident.name == name), _ => true, } } From d34f2823fdaeeee3bced7834d43589a3954bc62f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 8 Nov 2024 09:00:39 +1100 Subject: [PATCH 04/44] Use `for_each_child` in a suitable place. `for_each_child` exists for this exact pattern. --- compiler/rustc_resolve/src/diagnostics.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 5437ca65935..5b78acd904a 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -535,14 +535,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { filter_fn: &impl Fn(Res) -> bool, ctxt: Option, ) { - for (key, resolution) in self.resolutions(module).borrow().iter() { - if let Some(binding) = resolution.borrow().binding { - let res = binding.res(); - if filter_fn(res) && ctxt.map_or(true, |ctxt| ctxt == key.ident.span.ctxt()) { - names.push(TypoSuggestion::typo_from_ident(key.ident, res)); - } + module.for_each_child(self, |_this, ident, _ns, binding| { + let res = binding.res(); + if filter_fn(res) && ctxt.map_or(true, |ctxt| ctxt == ident.span.ctxt()) { + names.push(TypoSuggestion::typo_from_ident(ident, res)); } - } + }); } /// Combines an error with provided span and emits it. From e7dffeedcffce81f709da8a076b8ff437b8d3060 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 8 Nov 2024 10:42:07 +1100 Subject: [PATCH 05/44] Use an atom comparison for a keyword check. Instead of a string comparison. --- compiler/rustc_resolve/src/ident.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index c8f7a12132c..d8e1e296b22 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1199,7 +1199,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Still doesn't deal with upvars if let Some(span) = finalize { let (span, resolution_error) = match item { - None if rib_ident.as_str() == "self" => (span, LowercaseSelf), + None if rib_ident.name == kw::SelfLower => { + (span, LowercaseSelf) + } None => { // If we have a `let name = expr;`, we have the span for // `name` and use that to see if it is followed by a type From d71c06d022b07518f97072ad36cbe2c8a25eee2d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 8 Nov 2024 15:16:16 +1100 Subject: [PATCH 06/44] Remove two `_ext` methods. `resolve_ident_in_module` is a very thin wrapper around `resolve_ident_in_module_ext`, and `resolve_ident_in_module_unadjusted` is a very thin wrapper around `resolve_ident_in_module_unadjusted_ext`. The wrappers make the call sites slightly more concise, but I don't think that's worth the extra code and indirection. This commit removes the two wrappers and removes the `_ext` suffixes from the inner methods. --- compiler/rustc_resolve/src/ident.rs | 69 ++++++----------------------- 1 file changed, 13 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index d8e1e296b22..b8e07ef5402 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -349,6 +349,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, ns, parent_scope, + false, finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }), ignore_binding, None, @@ -493,7 +494,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Scope::CrateRoot => { let root_ident = Ident::new(kw::PathRoot, ident.span); let root_module = this.resolve_crate_root(root_ident); - let binding = this.resolve_ident_in_module_ext( + let binding = this.resolve_ident_in_module( ModuleOrUniformRoot::Module(root_module), ident, ns, @@ -515,7 +516,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } Scope::Module(module, derive_fallback_lint_id) => { let adjusted_parent_scope = &ParentScope { module, ..*parent_scope }; - let binding = this.resolve_ident_in_module_unadjusted_ext( + let binding = this.resolve_ident_in_module_unadjusted( ModuleOrUniformRoot::Module(module), ident, ns, @@ -589,6 +590,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, ns, parent_scope, + false, None, ignore_binding, ignore_import, @@ -747,35 +749,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, ignore_import: Option>, ) -> Result, Determinacy> { - self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, None, None, ignore_import) + self.resolve_ident_in_module(module, ident, ns, parent_scope, None, None, ignore_import) .map_err(|(determinacy, _)| determinacy) } #[instrument(level = "debug", skip(self))] pub(crate) fn resolve_ident_in_module( - &mut self, - module: ModuleOrUniformRoot<'ra>, - ident: Ident, - ns: Namespace, - parent_scope: &ParentScope<'ra>, - finalize: Option, - ignore_binding: Option>, - ignore_import: Option>, - ) -> Result, Determinacy> { - self.resolve_ident_in_module_ext( - module, - ident, - ns, - parent_scope, - finalize, - ignore_binding, - ignore_import, - ) - .map_err(|(determinacy, _)| determinacy) - } - - #[instrument(level = "debug", skip(self))] - fn resolve_ident_in_module_ext( &mut self, module: ModuleOrUniformRoot<'ra>, mut ident: Ident, @@ -802,7 +781,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // No adjustments } } - self.resolve_ident_in_module_unadjusted_ext( + self.resolve_ident_in_module_unadjusted( module, ident, ns, @@ -814,34 +793,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) } - #[instrument(level = "debug", skip(self))] - fn resolve_ident_in_module_unadjusted( - &mut self, - module: ModuleOrUniformRoot<'ra>, - ident: Ident, - ns: Namespace, - parent_scope: &ParentScope<'ra>, - finalize: Option, - ignore_binding: Option>, - ignore_import: Option>, - ) -> Result, Determinacy> { - self.resolve_ident_in_module_unadjusted_ext( - module, - ident, - ns, - parent_scope, - false, - finalize, - ignore_binding, - ignore_import, - ) - .map_err(|(determinacy, _)| determinacy) - } - /// Attempts to resolve `ident` in namespaces `ns` of `module`. /// Invariant: if `finalize` is `Some`, expansion and import resolution must be complete. #[instrument(level = "debug", skip(self))] - fn resolve_ident_in_module_unadjusted_ext( + fn resolve_ident_in_module_unadjusted( &mut self, module: ModuleOrUniformRoot<'ra>, ident: Ident, @@ -1046,13 +1001,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ignore_binding, ignore_import, ) { - Err(Determined) => continue, + Err((Determined, _)) => continue, Ok(binding) if !self.is_accessible_from(binding.vis, single_import.parent_scope.module) => { continue; } - Ok(_) | Err(Undetermined) => return Err((Undetermined, Weak::No)), + Ok(_) | Err((Undetermined, _)) => return Err((Undetermined, Weak::No)), } } @@ -1121,19 +1076,20 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, ns, adjusted_parent_scope, + false, None, ignore_binding, ignore_import, ); match result { - Err(Determined) => continue, + Err((Determined, _)) => continue, Ok(binding) if !self.is_accessible_from(binding.vis, glob_import.parent_scope.module) => { continue; } - Ok(_) | Err(Undetermined) => return Err((Undetermined, Weak::Yes)), + Ok(_) | Err((Undetermined, _)) => return Err((Undetermined, Weak::Yes)), } } @@ -1564,6 +1520,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ignore_binding, ignore_import, ) + .map_err(|(determinacy, _)| determinacy) } else if let Some(ribs) = ribs && let Some(TypeNS | ValueNS) = opt_ns { From 6e0e9edbe034b8ce764f91abb5c12b7871e09e9c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 8 Nov 2024 15:24:13 +1100 Subject: [PATCH 07/44] Move a call outside a loop. This path isn't hot enough for this to affect performance, but there's no point repeating the same computation multiple times. --- compiler/rustc_resolve/src/late.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index f4a85c358e3..26b345f5941 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1688,9 +1688,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } } + let normalized_ident = ident.normalize_to_macros_2_0(); let mut outer_res = None; for rib in lifetime_rib_iter { - let normalized_ident = ident.normalize_to_macros_2_0(); if let Some((&outer, _)) = rib.bindings.get_key_value(&normalized_ident) { outer_res = Some(outer); break; From 66cc7d6a05f2fadbe100e12ebc65d511fa690aea Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 14 Nov 2024 10:20:45 +1100 Subject: [PATCH 08/44] Replace the `restricted_shadowing` boolean argument with an enum. It makes the code clearer. --- compiler/rustc_resolve/src/ident.rs | 34 +++++++++++++++++++---------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index b8e07ef5402..ad825d7813d 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -38,6 +38,12 @@ impl From for bool { } } +#[derive(Debug, PartialEq)] +enum Shadowing { + Restricted, + Unrestricted, +} + impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// A generic scope visitor. /// Visits scopes in order to resolve some identifier in them or perform other actions. @@ -349,7 +355,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, ns, parent_scope, - false, + Shadowing::Unrestricted, finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }), ignore_binding, None, @@ -521,7 +527,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, ns, adjusted_parent_scope, - !matches!(scope_set, ScopeSet::Late(..)), + if matches!(scope_set, ScopeSet::Late(..)) { + Shadowing::Unrestricted + } else { + Shadowing::Restricted + }, finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }), ignore_binding, ignore_import, @@ -590,7 +600,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, ns, parent_scope, - false, + Shadowing::Unrestricted, None, ignore_binding, ignore_import, @@ -786,7 +796,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, ns, adjusted_parent_scope, - false, + Shadowing::Unrestricted, finalize, ignore_binding, ignore_import, @@ -802,7 +812,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident: Ident, ns: Namespace, parent_scope: &ParentScope<'ra>, - restricted_shadowing: bool, + shadowing: Shadowing, finalize: Option, // This binding should be ignored during in-module resolution, so that we don't get // "self-confirming" import resolutions during import validation and checking. @@ -812,7 +822,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let module = match module { ModuleOrUniformRoot::Module(module) => module, ModuleOrUniformRoot::CrateRootAndExternPrelude => { - assert!(!restricted_shadowing); + assert_eq!(shadowing, Shadowing::Unrestricted); let binding = self.early_resolve_ident_in_lexical_scope( ident, ScopeSet::AbsolutePath(ns), @@ -825,7 +835,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return binding.map_err(|determinacy| (determinacy, Weak::No)); } ModuleOrUniformRoot::ExternPrelude => { - assert!(!restricted_shadowing); + assert_eq!(shadowing, Shadowing::Unrestricted); return if ns != TypeNS { Err((Determined, Weak::No)) } else if let Some(binding) = self.extern_prelude_get(ident, finalize.is_some()) { @@ -838,7 +848,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; } ModuleOrUniformRoot::CurrentScope => { - assert!(!restricted_shadowing); + assert_eq!(shadowing, Shadowing::Unrestricted); if ns == TypeNS { if ident.name == kw::Crate || ident.name == kw::DollarCrate { let module = self.resolve_crate_root(ident); @@ -897,7 +907,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Forbid expanded shadowing to avoid time travel. if let Some(shadowed_glob) = resolution.shadowed_glob - && restricted_shadowing + && shadowing == Shadowing::Restricted && binding.expansion != LocalExpnId::ROOT && binding.res() != shadowed_glob.res() { @@ -912,7 +922,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }); } - if !restricted_shadowing + if shadowing == Shadowing::Unrestricted && binding.expansion != LocalExpnId::ROOT && let NameBindingKind::Import { import, .. } = binding.kind && matches!(import.kind, ImportKind::MacroExport) @@ -1024,7 +1034,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // and prohibit access to macro-expanded `macro_export` macros instead (unless restricted // shadowing is enabled, see `macro_expanded_macro_export_errors`). if let Some(binding) = binding { - if binding.determined() || ns == MacroNS || restricted_shadowing { + if binding.determined() || ns == MacroNS || shadowing == Shadowing::Restricted { return check_usable(self, binding); } else { return Err((Undetermined, Weak::No)); @@ -1076,7 +1086,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, ns, adjusted_parent_scope, - false, + Shadowing::Unrestricted, None, ignore_binding, ignore_import, From 12747f188a9dba7b13cf1ccb01fef74c6ce3294e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 14 Nov 2024 11:34:49 +1100 Subject: [PATCH 09/44] Remove `Resolver::empty_disambiguator`. It was added in #115367 for anonymous ADTs. Those changes were then reverted in #131045, but `empty_disambiguator` was left behind, perhaps by mistake. It seems to be unnecessary. --- compiler/rustc_resolve/src/lib.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index cf37a4e3389..e382295b8f6 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1082,8 +1082,6 @@ pub struct Resolver<'ra, 'tcx> { binding_parent_modules: FxHashMap, Module<'ra>>, underscore_disambiguator: u32, - /// Disambiguator for anonymous adts. - empty_disambiguator: u32, /// Maps glob imports to the names of items actually imported. glob_map: FxHashMap>, @@ -1462,7 +1460,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { module_children: Default::default(), trait_map: NodeMap::default(), underscore_disambiguator: 0, - empty_disambiguator: 0, empty_module, module_map, block_map: Default::default(), @@ -1841,9 +1838,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let disambiguator = if ident.name == kw::Underscore { self.underscore_disambiguator += 1; self.underscore_disambiguator - } else if ident.name == kw::Empty { - self.empty_disambiguator += 1; - self.empty_disambiguator } else { 0 }; From 12eaa3ab8465431d18696489e29be95fedf4da6d Mon Sep 17 00:00:00 2001 From: Sam Estep Date: Wed, 13 Nov 2024 23:19:47 -0500 Subject: [PATCH 10/44] Print total node count in `-Z hir-stats` --- compiler/rustc_passes/src/hir_stats.rs | 9 ++++++++- tests/ui/stats/hir-stats.rs | 2 +- tests/ui/stats/hir-stats.stderr | 6 +++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 55fdbac8ad6..db34189be2a 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -126,6 +126,7 @@ impl<'k> StatCollector<'k> { }); let total_size = nodes.iter().map(|(_, node)| node.stats.count * node.stats.size).sum(); + let total_count = nodes.iter().map(|(_, node)| node.stats.count).sum(); eprintln!("{prefix} {title}"); eprintln!( @@ -167,7 +168,13 @@ impl<'k> StatCollector<'k> { } } eprintln!("{prefix} ----------------------------------------------------------------"); - eprintln!("{} {:<18}{:>10}", prefix, "Total", to_readable_str(total_size)); + eprintln!( + "{} {:<18}{:>10} {:>14}", + prefix, + "Total", + to_readable_str(total_size), + to_readable_str(total_count), + ); eprintln!("{prefix}"); } } diff --git a/tests/ui/stats/hir-stats.rs b/tests/ui/stats/hir-stats.rs index 7c5da8cf554..dc4a90c0059 100644 --- a/tests/ui/stats/hir-stats.rs +++ b/tests/ui/stats/hir-stats.rs @@ -1,6 +1,6 @@ //@ check-pass //@ compile-flags: -Zhir-stats -//@ only-x86_64 +//@ only-64bit // layout randomization affects the hir stat output //@ needs-deterministic-layouts diff --git a/tests/ui/stats/hir-stats.stderr b/tests/ui/stats/hir-stats.stderr index bd0c8cbc3b1..2cc2c8019fa 100644 --- a/tests/ui/stats/hir-stats.stderr +++ b/tests/ui/stats/hir-stats.stderr @@ -53,7 +53,7 @@ ast-stats-1 - Enum 136 ( 2.0%) 1 ast-stats-1 - Fn 272 ( 4.1%) 2 ast-stats-1 - Use 408 ( 6.1%) 3 ast-stats-1 ---------------------------------------------------------------- -ast-stats-1 Total 6_640 +ast-stats-1 Total 6_640 116 ast-stats-1 ast-stats-2 POST EXPANSION AST STATS ast-stats-2 Name Accumulated Size Count Item Size @@ -113,7 +113,7 @@ ast-stats-2 - ForeignMod 136 ( 1.9%) 1 ast-stats-2 - Fn 272 ( 3.7%) 2 ast-stats-2 - Use 544 ( 7.5%) 4 ast-stats-2 ---------------------------------------------------------------- -ast-stats-2 Total 7_288 +ast-stats-2 Total 7_288 127 ast-stats-2 hir-stats HIR STATS hir-stats Name Accumulated Size Count Item Size @@ -174,5 +174,5 @@ hir-stats - Use 352 ( 3.9%) 4 hir-stats Path 1_240 (13.7%) 31 40 hir-stats PathSegment 1_920 (21.3%) 40 48 hir-stats ---------------------------------------------------------------- -hir-stats Total 9_024 +hir-stats Total 9_024 180 hir-stats From 090c24fbbfde43ebffb8a05e26bff4aceb98dfb8 Mon Sep 17 00:00:00 2001 From: Sam Estep Date: Thu, 14 Nov 2024 16:12:17 -0500 Subject: [PATCH 11/44] Merge `-Zhir-stats` into `-Zinput-stats` --- compiler/rustc_ast_passes/src/lib.rs | 1 - compiler/rustc_ast_passes/src/node_count.rs | 129 ------------------ compiler/rustc_interface/src/passes.rs | 29 +--- compiler/rustc_interface/src/tests.rs | 1 - .../src/{hir_stats.rs => input_stats.rs} | 0 compiler/rustc_passes/src/lib.rs | 2 +- compiler/rustc_session/src/options.rs | 4 +- .../ui/stats/{hir-stats.rs => input-stats.rs} | 4 +- .../{hir-stats.stderr => input-stats.stderr} | 0 triagebot.toml | 2 +- 10 files changed, 12 insertions(+), 160 deletions(-) delete mode 100644 compiler/rustc_ast_passes/src/node_count.rs rename compiler/rustc_passes/src/{hir_stats.rs => input_stats.rs} (100%) rename tests/ui/stats/{hir-stats.rs => input-stats.rs} (92%) rename tests/ui/stats/{hir-stats.stderr => input-stats.stderr} (100%) diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index 88c6bde3106..86752da79ae 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -18,7 +18,6 @@ pub mod ast_validation; mod errors; pub mod feature_gate; -pub mod node_count; pub mod show_span; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_ast_passes/src/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs deleted file mode 100644 index 9e7204df8ad..00000000000 --- a/compiler/rustc_ast_passes/src/node_count.rs +++ /dev/null @@ -1,129 +0,0 @@ -// Simply gives a rough count of the number of nodes in an AST. - -use rustc_ast::visit::*; -use rustc_ast::*; -use rustc_span::Span; -use rustc_span::symbol::Ident; - -pub struct NodeCounter { - pub count: usize, -} - -impl NodeCounter { - pub fn new() -> NodeCounter { - NodeCounter { count: 0 } - } -} - -impl<'ast> Visitor<'ast> for NodeCounter { - fn visit_ident(&mut self, _ident: &Ident) { - self.count += 1; - } - fn visit_foreign_item(&mut self, i: &ForeignItem) { - self.count += 1; - walk_item(self, i) - } - fn visit_item(&mut self, i: &Item) { - self.count += 1; - walk_item(self, i) - } - fn visit_local(&mut self, l: &Local) { - self.count += 1; - walk_local(self, l) - } - fn visit_block(&mut self, b: &Block) { - self.count += 1; - walk_block(self, b) - } - fn visit_stmt(&mut self, s: &Stmt) { - self.count += 1; - walk_stmt(self, s) - } - fn visit_arm(&mut self, a: &Arm) { - self.count += 1; - walk_arm(self, a) - } - fn visit_pat(&mut self, p: &Pat) { - self.count += 1; - walk_pat(self, p) - } - fn visit_expr(&mut self, ex: &Expr) { - self.count += 1; - walk_expr(self, ex) - } - fn visit_ty(&mut self, t: &Ty) { - self.count += 1; - walk_ty(self, t) - } - fn visit_generic_param(&mut self, param: &GenericParam) { - self.count += 1; - walk_generic_param(self, param) - } - fn visit_generics(&mut self, g: &Generics) { - self.count += 1; - walk_generics(self, g) - } - fn visit_fn(&mut self, fk: visit::FnKind<'_>, _: Span, _: NodeId) { - self.count += 1; - walk_fn(self, fk) - } - fn visit_assoc_item(&mut self, ti: &AssocItem, ctxt: AssocCtxt) { - self.count += 1; - walk_assoc_item(self, ti, ctxt); - } - fn visit_trait_ref(&mut self, t: &TraitRef) { - self.count += 1; - walk_trait_ref(self, t) - } - fn visit_param_bound(&mut self, bounds: &GenericBound, _ctxt: BoundKind) { - self.count += 1; - walk_param_bound(self, bounds) - } - fn visit_poly_trait_ref(&mut self, t: &PolyTraitRef) { - self.count += 1; - walk_poly_trait_ref(self, t) - } - fn visit_variant_data(&mut self, s: &VariantData) { - self.count += 1; - walk_struct_def(self, s) - } - fn visit_field_def(&mut self, s: &FieldDef) { - self.count += 1; - walk_field_def(self, s) - } - fn visit_enum_def(&mut self, enum_definition: &EnumDef) { - self.count += 1; - walk_enum_def(self, enum_definition) - } - fn visit_variant(&mut self, v: &Variant) { - self.count += 1; - walk_variant(self, v) - } - fn visit_lifetime(&mut self, lifetime: &Lifetime, _: visit::LifetimeCtxt) { - self.count += 1; - walk_lifetime(self, lifetime) - } - fn visit_mac_call(&mut self, mac: &MacCall) { - self.count += 1; - walk_mac(self, mac) - } - fn visit_path(&mut self, path: &Path, _id: NodeId) { - self.count += 1; - walk_path(self, path) - } - fn visit_use_tree(&mut self, use_tree: &UseTree, id: NodeId, _nested: bool) { - self.count += 1; - walk_use_tree(self, use_tree, id) - } - fn visit_generic_args(&mut self, generic_args: &GenericArgs) { - self.count += 1; - walk_generic_args(self, generic_args) - } - fn visit_assoc_item_constraint(&mut self, constraint: &AssocItemConstraint) { - self.count += 1; - walk_assoc_item_constraint(self, constraint) - } - fn visit_attribute(&mut self, _attr: &Attribute) { - self.count += 1; - } -} diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index fd850d2f39a..9a58636783a 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -5,7 +5,7 @@ use std::path::{Path, PathBuf}; use std::sync::{Arc, LazyLock}; use std::{env, fs, iter}; -use rustc_ast::{self as ast, visit}; +use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::parallel; use rustc_data_structures::steal::Steal; @@ -24,7 +24,7 @@ use rustc_middle::util::Providers; use rustc_parse::{ new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal, validate_attr, }; -use rustc_passes::{abi_test, hir_stats, layout_test}; +use rustc_passes::{abi_test, input_stats, layout_test}; use rustc_resolve::Resolver; use rustc_session::code_stats::VTableSizeInfo; use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType}; @@ -54,28 +54,17 @@ pub(crate) fn parse<'a>(sess: &'a Session) -> Result { }) .map_err(|parse_error| parse_error.emit())?; - if sess.opts.unstable_opts.input_stats { - eprintln!("Lines of code: {}", sess.source_map().count_lines()); - eprintln!("Pre-expansion node count: {}", count_nodes(&krate)); - } - if let Some(ref s) = sess.opts.unstable_opts.show_span { rustc_ast_passes::show_span::run(sess.dcx(), s, &krate); } - if sess.opts.unstable_opts.hir_stats { - hir_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS", "ast-stats-1"); + if sess.opts.unstable_opts.input_stats { + input_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS", "ast-stats-1"); } Ok(krate) } -fn count_nodes(krate: &ast::Crate) -> usize { - let mut counter = rustc_ast_passes::node_count::NodeCounter::new(); - visit::walk_crate(&mut counter, krate); - counter.count -} - fn pre_expansion_lint<'a>( sess: &Session, features: &Features, @@ -290,11 +279,7 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) { let mut lint_buffer = resolver.lint_buffer.steal(); if sess.opts.unstable_opts.input_stats { - eprintln!("Post-expansion node count: {}", count_nodes(krate)); - } - - if sess.opts.unstable_opts.hir_stats { - hir_stats::print_ast_stats(krate, "POST EXPANSION AST STATS", "ast-stats-2"); + input_stats::print_ast_stats(krate, "POST EXPANSION AST STATS", "ast-stats-2"); } // Needs to go *after* expansion to be able to check the results of macro expansion. @@ -820,8 +805,8 @@ pub(crate) fn create_global_ctxt<'tcx>( /// Runs all analyses that we guarantee to run, even if errors were reported in earlier analyses. /// This function never fails. fn run_required_analyses(tcx: TyCtxt<'_>) { - if tcx.sess.opts.unstable_opts.hir_stats { - rustc_passes::hir_stats::print_hir_stats(tcx); + if tcx.sess.opts.unstable_opts.input_stats { + rustc_passes::input_stats::print_hir_stats(tcx); } #[cfg(debug_assertions)] rustc_passes::hir_id_validator::check_crate(tcx); diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 2361231b3fb..e48c4d46b59 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -698,7 +698,6 @@ fn test_unstable_options_tracking_hash() { untracked!(dylib_lto, true); untracked!(emit_stack_sizes, true); untracked!(future_incompat_test, true); - untracked!(hir_stats, true); untracked!(identify_regions, true); untracked!(incremental_info, true); untracked!(incremental_verify_ich, true); diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/input_stats.rs similarity index 100% rename from compiler/rustc_passes/src/hir_stats.rs rename to compiler/rustc_passes/src/input_stats.rs diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 664da65068d..8f53b71319d 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -27,7 +27,7 @@ pub mod entry; mod errors; #[cfg(debug_assertions)] pub mod hir_id_validator; -pub mod hir_stats; +pub mod input_stats; mod lang_items; pub mod layout_test; mod lib_features; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index f485e8cace5..d94b503de18 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1805,8 +1805,6 @@ options! { environment variable `RUSTC_GRAPHVIZ_FONT` (default: `Courier, monospace`)"), has_thread_local: Option = (None, parse_opt_bool, [TRACKED], "explicitly enable the `cfg(target_thread_local)` directive"), - hir_stats: bool = (false, parse_bool, [UNTRACKED], - "print some statistics about AST and HIR (default: no)"), human_readable_cgu_names: bool = (false, parse_bool, [TRACKED], "generate human-readable, predictable names for codegen units (default: no)"), identify_regions: bool = (false, parse_bool, [UNTRACKED], @@ -1838,7 +1836,7 @@ options! { inline_mir_threshold: Option = (None, parse_opt_number, [TRACKED], "a default MIR inlining threshold (default: 50)"), input_stats: bool = (false, parse_bool, [UNTRACKED], - "gather statistics about the input (default: no)"), + "print some statistics about AST and HIR (default: no)"), instrument_mcount: bool = (false, parse_bool, [TRACKED], "insert function instrument code for mcount-based tracing (default: no)"), instrument_xray: Option = (None, parse_instrument_xray, [TRACKED], diff --git a/tests/ui/stats/hir-stats.rs b/tests/ui/stats/input-stats.rs similarity index 92% rename from tests/ui/stats/hir-stats.rs rename to tests/ui/stats/input-stats.rs index dc4a90c0059..f19a53cc610 100644 --- a/tests/ui/stats/hir-stats.rs +++ b/tests/ui/stats/input-stats.rs @@ -1,5 +1,5 @@ //@ check-pass -//@ compile-flags: -Zhir-stats +//@ compile-flags: -Zinput-stats //@ only-64bit // layout randomization affects the hir stat output //@ needs-deterministic-layouts @@ -11,7 +11,7 @@ // The aim here is to include at least one of every different type of top-level -// AST/HIR node reported by `-Zhir-stats`. +// AST/HIR node reported by `-Zinput-stats`. #![allow(dead_code)] diff --git a/tests/ui/stats/hir-stats.stderr b/tests/ui/stats/input-stats.stderr similarity index 100% rename from tests/ui/stats/hir-stats.stderr rename to tests/ui/stats/input-stats.stderr diff --git a/triagebot.toml b/triagebot.toml index 462d5df306f..8903d836944 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -886,7 +886,7 @@ message = "This PR changes a file inside `tests/crashes`. If a crash was fixed, message = "Changes to the code generated for builtin derived traits." cc = ["@nnethercote"] -[mentions."tests/ui/stats/hir-stats.stderr"] +[mentions."tests/ui/stats/input-stats.stderr"] message = "Changes to the size of AST and/or HIR nodes." cc = ["@nnethercote"] From 53194251285f126c8031d742c932b7fa8af09238 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 15 Nov 2024 14:09:37 -0800 Subject: [PATCH 12/44] Move diagnostic::on_unimplemented test to the directory with all the other tests --- .../on_unimplemented}/custom-on-unimplemented-diagnostic.rs | 0 .../on_unimplemented}/custom-on-unimplemented-diagnostic.stderr | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{traits => diagnostic_namespace/on_unimplemented}/custom-on-unimplemented-diagnostic.rs (100%) rename tests/ui/{traits => diagnostic_namespace/on_unimplemented}/custom-on-unimplemented-diagnostic.stderr (100%) diff --git a/tests/ui/traits/custom-on-unimplemented-diagnostic.rs b/tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.rs similarity index 100% rename from tests/ui/traits/custom-on-unimplemented-diagnostic.rs rename to tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.rs diff --git a/tests/ui/traits/custom-on-unimplemented-diagnostic.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.stderr similarity index 100% rename from tests/ui/traits/custom-on-unimplemented-diagnostic.stderr rename to tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.stderr From da58efb11df229eac6eb727c2884546310f9ffde Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sun, 5 May 2024 19:57:24 -0400 Subject: [PATCH 13/44] Improve VecCache under parallel frontend This replaces the single Vec allocation with a series of progressively larger buckets. With the cfg for parallel enabled but with -Zthreads=1, this looks like a slight regression in i-count and cycle counts (<0.1%). With the parallel frontend at -Zthreads=4, this is an improvement (-5% wall-time from 5.788 to 5.4688 on libcore) than our current Lock-based approach, likely due to reducing the bouncing of the cache line holding the lock. At -Zthreads=32 it's a huge improvement (-46%: 8.829 -> 4.7319 seconds). --- compiler/rustc_data_structures/src/lib.rs | 2 + .../rustc_data_structures/src/vec_cache.rs | 324 ++++++++++++++++++ .../src/vec_cache/tests.rs | 95 +++++ compiler/rustc_middle/src/query/keys.rs | 7 +- compiler/rustc_query_system/src/lib.rs | 1 + .../rustc_query_system/src/query/caches.rs | 94 ++--- 6 files changed, 458 insertions(+), 65 deletions(-) create mode 100644 compiler/rustc_data_structures/src/vec_cache.rs create mode 100644 compiler/rustc_data_structures/src/vec_cache/tests.rs diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index afac08ae6f8..93abc0d2958 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -22,6 +22,7 @@ #![feature(auto_traits)] #![feature(cfg_match)] #![feature(core_intrinsics)] +#![feature(dropck_eyepatch)] #![feature(extend_one)] #![feature(file_buffered)] #![feature(hash_raw_entry)] @@ -79,6 +80,7 @@ pub mod thinvec; pub mod transitive_relation; pub mod unhash; pub mod unord; +pub mod vec_cache; pub mod work_queue; mod atomic_ref; diff --git a/compiler/rustc_data_structures/src/vec_cache.rs b/compiler/rustc_data_structures/src/vec_cache.rs new file mode 100644 index 00000000000..eb251b587c8 --- /dev/null +++ b/compiler/rustc_data_structures/src/vec_cache.rs @@ -0,0 +1,324 @@ +//! VecCache maintains a mapping from K -> (V, I) pairing. K and I must be roughly u32-sized, and V +//! must be Copy. +//! +//! VecCache supports efficient concurrent put/get across the key space, with write-once semantics +//! (i.e., a given key can only be put once). Subsequent puts will panic. +//! +//! This is currently used for query caching. + +use std::fmt::Debug; +use std::marker::PhantomData; +use std::sync::atomic::{AtomicPtr, AtomicU32, AtomicUsize, Ordering}; + +use rustc_index::Idx; + +struct Slot { + // We never construct &Slot so it's fine for this to not be in an UnsafeCell. + value: V, + // This is both an index and a once-lock. + // + // 0: not yet initialized. + // 1: lock held, initializing. + // 2..u32::MAX - 2: initialized. + index_and_lock: AtomicU32, +} + +/// This uniquely identifies a single `Slot` entry in the buckets map, and provides accessors for +/// either getting the value or putting a value. +#[derive(Copy, Clone, Debug)] +struct SlotIndex { + // the index of the bucket in VecCache (0 to 20) + bucket_idx: usize, + // number of entries in that bucket + entries: usize, + // the index of the slot within the bucket + index_in_bucket: usize, +} + +// This makes sure the counts are consistent with what we allocate, precomputing each bucket a +// compile-time. Visiting all powers of two is enough to hit all the buckets. +// +// We confirm counts are accurate in the slot_index_exhaustive test. +const ENTRIES_BY_BUCKET: [usize; 21] = { + let mut entries = [0; 21]; + let mut key = 0; + loop { + let si = SlotIndex::from_index(key); + entries[si.bucket_idx] = si.entries; + if key == 0 { + key = 1; + } else if key == (1 << 31) { + break; + } else { + key <<= 1; + } + } + entries +}; + +impl SlotIndex { + // This unpacks a flat u32 index into identifying which bucket it belongs to and the offset + // within that bucket. As noted in the VecCache docs, buckets double in size with each index. + // Typically that would mean 31 buckets (2^0 + 2^1 ... + 2^31 = u32::MAX - 1), but to reduce + // the size of the VecCache struct and avoid uselessly small allocations, we instead have the + // first bucket have 2**12 entries. To simplify the math, the second bucket also 2**12 entries, + // and buckets double from there. + // + // We assert that [0, 2**32 - 1] uniquely map through this function to individual, consecutive + // slots (see `slot_index_exhaustive` in tests). + #[inline] + const fn from_index(idx: u32) -> Self { + let mut bucket = match idx.checked_ilog2() { + Some(x) => x as usize, + None => 0, + }; + let entries; + let running_sum; + if bucket <= 11 { + entries = 1 << 12; + running_sum = 0; + bucket = 0; + } else { + entries = 1 << bucket; + running_sum = entries; + bucket = bucket - 11; + } + SlotIndex { bucket_idx: bucket, entries, index_in_bucket: idx as usize - running_sum } + } + + // SAFETY: Buckets must be managed solely by functions here (i.e., get/put on SlotIndex) and + // `self` comes from SlotIndex::from_index + #[inline] + unsafe fn get(&self, buckets: &[AtomicPtr>; 21]) -> Option<(V, u32)> { + // SAFETY: `bucket_idx` is ilog2(u32).saturating_sub(11), which is at most 21, i.e., + // in-bounds of buckets. See `from_index` for computation. + let bucket = unsafe { buckets.get_unchecked(self.bucket_idx) }; + let ptr = bucket.load(Ordering::Acquire); + // Bucket is not yet initialized: then we obviously won't find this entry in that bucket. + if ptr.is_null() { + return None; + } + assert!(self.index_in_bucket < self.entries); + // SAFETY: `bucket` was allocated (so <= isize in total bytes) to hold `entries`, so this + // must be inbounds. + let slot = unsafe { ptr.add(self.index_in_bucket) }; + + // SAFETY: initialized bucket has zeroed all memory within the bucket, so we are valid for + // AtomicU32 access. + let index_and_lock = unsafe { &(*slot).index_and_lock }; + let current = index_and_lock.load(Ordering::Acquire); + let index = match current { + 0 => return None, + // Treat "initializing" as actually just not initialized at all. + // The only reason this is a separate state is that `complete` calls could race and + // we can't allow that, but from load perspective there's no difference. + 1 => return None, + _ => current - 2, + }; + + // SAFETY: + // * slot is a valid pointer (buckets are always valid for the index we get). + // * value is initialized since we saw a >= 2 index above. + // * `V: Copy`, so safe to read. + let value = unsafe { (*slot).value }; + Some((value, index)) + } + + fn bucket_ptr(&self, bucket: &AtomicPtr>) -> *mut Slot { + let ptr = bucket.load(Ordering::Acquire); + if ptr.is_null() { self.initialize_bucket(bucket) } else { ptr } + } + + #[cold] + fn initialize_bucket(&self, bucket: &AtomicPtr>) -> *mut Slot { + static LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(()); + + // If we are initializing the bucket, then acquire a global lock. + // + // This path is quite cold, so it's cheap to use a global lock. This ensures that we never + // have multiple allocations for the same bucket. + let _allocator_guard = LOCK.lock().unwrap_or_else(|e| e.into_inner()); + + let ptr = bucket.load(Ordering::Acquire); + + // OK, now under the allocator lock, if we're still null then it's definitely us that will + // initialize this bucket. + if ptr.is_null() { + let bucket_layout = + std::alloc::Layout::array::>(self.entries as usize).unwrap(); + // This is more of a sanity check -- this code is very cold, so it's safe to pay a + // little extra cost here. + assert!(bucket_layout.size() > 0); + // SAFETY: Just checked that size is non-zero. + let allocated = unsafe { std::alloc::alloc_zeroed(bucket_layout).cast::>() }; + if allocated.is_null() { + std::alloc::handle_alloc_error(bucket_layout); + } + bucket.store(allocated, Ordering::Release); + allocated + } else { + // Otherwise some other thread initialized this bucket after we took the lock. In that + // case, just return early. + ptr + } + } + + /// Returns true if this successfully put into the map. + #[inline] + fn put(&self, buckets: &[AtomicPtr>; 21], value: V, extra: u32) -> bool { + // SAFETY: `bucket_idx` is ilog2(u32).saturating_sub(11), which is at most 21, i.e., + // in-bounds of buckets. + let bucket = unsafe { buckets.get_unchecked(self.bucket_idx) }; + let ptr = self.bucket_ptr(bucket); + + assert!(self.index_in_bucket < self.entries); + // SAFETY: `bucket` was allocated (so <= isize in total bytes) to hold `entries`, so this + // must be inbounds. + let slot = unsafe { ptr.add(self.index_in_bucket) }; + + // SAFETY: initialized bucket has zeroed all memory within the bucket, so we are valid for + // AtomicU32 access. + let index_and_lock = unsafe { &(*slot).index_and_lock }; + match index_and_lock.compare_exchange(0, 1, Ordering::AcqRel, Ordering::Acquire) { + Ok(_) => { + // We have acquired the initialization lock. It is our job to write `value` and + // then set the lock to the real index. + + unsafe { + (&raw mut (*slot).value).write(value); + } + + index_and_lock.store(extra.checked_add(2).unwrap(), Ordering::Release); + + true + } + + // Treat "initializing" as the caller's fault. Callers are responsible for ensuring that + // there are no races on initialization. In the compiler's current usage for query + // caches, that's the "active query map" which ensures each query actually runs once + // (even if concurrently started). + Err(1) => panic!("caller raced calls to put()"), + + // This slot was already populated. Also ignore, currently this is the same as + // "initializing". + Err(_) => false, + } + } +} + +pub struct VecCache { + // Entries per bucket: + // Bucket 0: 4096 2^12 + // Bucket 1: 4096 2^12 + // Bucket 2: 8192 + // Bucket 3: 16384 + // ... + // Bucket 19: 1073741824 + // Bucket 20: 2147483648 + // The total number of entries if all buckets are initialized is u32::MAX-1. + buckets: [AtomicPtr>; 21], + + // In the compiler's current usage these are only *read* during incremental and self-profiling. + // They are an optimization over iterating the full buckets array. + present: [AtomicPtr>; 21], + len: AtomicUsize, + + key: PhantomData<(K, I)>, +} + +impl Default for VecCache { + fn default() -> Self { + VecCache { + buckets: Default::default(), + key: PhantomData, + len: Default::default(), + present: Default::default(), + } + } +} + +// SAFETY: No access to `V` is made. +unsafe impl Drop for VecCache { + fn drop(&mut self) { + // We have unique ownership, so no locks etc. are needed. Since `K` and `V` are both `Copy`, + // we are also guaranteed to just need to deallocate any large arrays (not iterate over + // contents). + // + // Confirm no need to deallocate invidual entries. Note that `V: Copy` is asserted on + // insert/lookup but not necessarily construction, primarily to avoid annoyingly propagating + // the bounds into struct definitions everywhere. + assert!(!std::mem::needs_drop::()); + assert!(!std::mem::needs_drop::()); + + for (idx, bucket) in self.buckets.iter().enumerate() { + let bucket = bucket.load(Ordering::Acquire); + if !bucket.is_null() { + let layout = std::alloc::Layout::array::>(ENTRIES_BY_BUCKET[idx]).unwrap(); + unsafe { + std::alloc::dealloc(bucket.cast(), layout); + } + } + } + + for (idx, bucket) in self.present.iter().enumerate() { + let bucket = bucket.load(Ordering::Acquire); + if !bucket.is_null() { + let layout = std::alloc::Layout::array::>(ENTRIES_BY_BUCKET[idx]).unwrap(); + unsafe { + std::alloc::dealloc(bucket.cast(), layout); + } + } + } + } +} + +impl VecCache +where + K: Eq + Idx + Copy + Debug, + V: Copy, + I: Idx + Copy, +{ + #[inline(always)] + pub fn lookup(&self, key: &K) -> Option<(V, I)> { + let key = u32::try_from(key.index()).unwrap(); + let slot_idx = SlotIndex::from_index(key); + match unsafe { slot_idx.get(&self.buckets) } { + Some((value, idx)) => Some((value, I::new(idx as usize))), + None => None, + } + } + + #[inline] + pub fn complete(&self, key: K, value: V, index: I) { + let key = u32::try_from(key.index()).unwrap(); + let slot_idx = SlotIndex::from_index(key); + if slot_idx.put(&self.buckets, value, index.index() as u32) { + let present_idx = self.len.fetch_add(1, Ordering::Relaxed); + let slot = SlotIndex::from_index(present_idx as u32); + // We should always be uniquely putting due to `len` fetch_add returning unique values. + assert!(slot.put(&self.present, (), key)); + } + } + + pub fn iter(&self, f: &mut dyn FnMut(&K, &V, I)) { + for idx in 0..self.len.load(Ordering::Acquire) { + let key = SlotIndex::from_index(idx as u32); + match unsafe { key.get(&self.present) } { + // This shouldn't happen in our current usage (iter is really only + // used long after queries are done running), but if we hit this in practice it's + // probably fine to just break early. + None => unreachable!(), + Some(((), key)) => { + let key = K::new(key as usize); + // unwrap() is OK: present entries are always written only after we put the real + // entry. + let value = self.lookup(&key).unwrap(); + f(&key, &value.0, value.1); + } + } + } + } +} + +#[cfg(test)] +mod tests; diff --git a/compiler/rustc_data_structures/src/vec_cache/tests.rs b/compiler/rustc_data_structures/src/vec_cache/tests.rs new file mode 100644 index 00000000000..a05f2741362 --- /dev/null +++ b/compiler/rustc_data_structures/src/vec_cache/tests.rs @@ -0,0 +1,95 @@ +use super::*; + +#[test] +#[cfg(not(miri))] +fn vec_cache_empty() { + let cache: VecCache = VecCache::default(); + for key in 0..u32::MAX { + assert!(cache.lookup(&key).is_none()); + } +} + +#[test] +fn vec_cache_insert_and_check() { + let cache: VecCache = VecCache::default(); + cache.complete(0, 1, 2); + assert_eq!(cache.lookup(&0), Some((1, 2))); +} + +#[test] +fn sparse_inserts() { + let cache: VecCache = VecCache::default(); + let end = if cfg!(target_pointer_width = "64") && cfg!(target_os = "linux") { + // For paged memory, 64-bit systems we should be able to sparsely allocate all of the pages + // needed for these inserts cheaply (without needing to actually have gigabytes of resident + // memory). + 31 + } else { + // Otherwise, still run the test but scaled back: + // + // Each slot is 5 bytes, so 2^25 entries (on non-virtual memory systems, like e.g. Windows) will + // mean 160 megabytes of allocated memory. Going beyond that is probably not reasonable for + // tests. + 25 + }; + for shift in 0..end { + let key = 1u32 << shift; + cache.complete(key, shift, key); + assert_eq!(cache.lookup(&key), Some((shift, key))); + } +} + +#[test] +fn concurrent_stress_check() { + let cache: VecCache = VecCache::default(); + std::thread::scope(|s| { + for idx in 0..100 { + let cache = &cache; + s.spawn(move || { + cache.complete(idx, idx, idx); + }); + } + }); + + for idx in 0..100 { + assert_eq!(cache.lookup(&idx), Some((idx, idx))); + } +} + +#[test] +fn slot_entries_table() { + assert_eq!(ENTRIES_BY_BUCKET, [ + 4096, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, + 8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, + 2147483648 + ]); +} + +#[test] +#[cfg(not(miri))] +fn slot_index_exhaustive() { + let mut buckets = [0u32; 21]; + for idx in 0..=u32::MAX { + buckets[SlotIndex::from_index(idx).bucket_idx] += 1; + } + let mut prev = None::; + for idx in 0..=u32::MAX { + let slot_idx = SlotIndex::from_index(idx); + if let Some(p) = prev { + if p.bucket_idx == slot_idx.bucket_idx { + assert_eq!(p.index_in_bucket + 1, slot_idx.index_in_bucket); + } else { + assert_eq!(slot_idx.index_in_bucket, 0); + } + } else { + assert_eq!(idx, 0); + assert_eq!(slot_idx.index_in_bucket, 0); + assert_eq!(slot_idx.bucket_idx, 0); + } + + assert_eq!(buckets[slot_idx.bucket_idx], slot_idx.entries as u32); + assert_eq!(ENTRIES_BY_BUCKET[slot_idx.bucket_idx], slot_idx.entries, "{}", idx); + + prev = Some(slot_idx); + } +} diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index fe28ef0f70c..1fbebf4b093 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -2,6 +2,7 @@ use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalModDefId, ModDefId}; use rustc_hir::hir_id::{HirId, OwnerId}; +use rustc_query_system::dep_graph::DepNodeIndex; use rustc_query_system::query::{DefIdCache, DefaultCache, SingleCache, VecCache}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{DUMMY_SP, Span}; @@ -110,7 +111,7 @@ impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> { } impl Key for CrateNum { - type Cache = VecCache; + type Cache = VecCache; fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -127,7 +128,7 @@ impl AsLocalKey for CrateNum { } impl Key for OwnerId { - type Cache = VecCache; + type Cache = VecCache; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.to_def_id().default_span(tcx) @@ -139,7 +140,7 @@ impl Key for OwnerId { } impl Key for LocalDefId { - type Cache = VecCache; + type Cache = VecCache; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.to_def_id().default_span(tcx) diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index ba7a631fb54..a85e8a55a21 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -2,6 +2,7 @@ #![allow(rustc::potential_query_instability, internal_features)] #![feature(assert_matches)] #![feature(core_intrinsics)] +#![feature(dropck_eyepatch)] #![feature(hash_raw_entry)] #![feature(let_chains)] #![feature(min_specialization)] diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs index a4ced3d2c24..e6f3d97742d 100644 --- a/compiler/rustc_query_system/src/query/caches.rs +++ b/compiler/rustc_query_system/src/query/caches.rs @@ -3,9 +3,10 @@ use std::hash::Hash; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sharded::{self, Sharded}; -use rustc_data_structures::sync::{Lock, OnceLock}; +use rustc_data_structures::sync::OnceLock; +pub use rustc_data_structures::vec_cache::VecCache; use rustc_hir::def_id::LOCAL_CRATE; -use rustc_index::{Idx, IndexVec}; +use rustc_index::Idx; use rustc_span::def_id::{DefId, DefIndex}; use crate::dep_graph::DepNodeIndex; @@ -100,52 +101,10 @@ where } } -pub struct VecCache { - cache: Lock>>, -} - -impl Default for VecCache { - fn default() -> Self { - VecCache { cache: Default::default() } - } -} - -impl QueryCache for VecCache -where - K: Eq + Idx + Copy + Debug, - V: Copy, -{ - type Key = K; - type Value = V; - - #[inline(always)] - fn lookup(&self, key: &K) -> Option<(V, DepNodeIndex)> { - let lock = self.cache.lock(); - if let Some(Some(value)) = lock.get(*key) { Some(*value) } else { None } - } - - #[inline] - fn complete(&self, key: K, value: V, index: DepNodeIndex) { - let mut lock = self.cache.lock(); - lock.insert(key, (value, index)); - } - - fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) { - for (k, v) in self.cache.lock().iter_enumerated() { - if let Some(v) = v { - f(&k, &v.0, v.1); - } - } - } -} - pub struct DefIdCache { /// Stores the local DefIds in a dense map. Local queries are much more often dense, so this is /// a win over hashing query keys at marginal memory cost (~5% at most) compared to FxHashMap. - /// - /// The second element of the tuple is the set of keys actually present in the IndexVec, used - /// for faster iteration in `iter()`. - local: Lock<(IndexVec>, Vec)>, + local: VecCache, foreign: DefaultCache, } @@ -165,8 +124,7 @@ where #[inline(always)] fn lookup(&self, key: &DefId) -> Option<(V, DepNodeIndex)> { if key.krate == LOCAL_CRATE { - let cache = self.local.lock(); - cache.0.get(key.index).and_then(|v| *v) + self.local.lookup(&key.index) } else { self.foreign.lookup(key) } @@ -175,27 +133,39 @@ where #[inline] fn complete(&self, key: DefId, value: V, index: DepNodeIndex) { if key.krate == LOCAL_CRATE { - let mut cache = self.local.lock(); - let (cache, present) = &mut *cache; - let slot = cache.ensure_contains_elem(key.index, Default::default); - if slot.is_none() { - // FIXME: Only store the present set when running in incremental mode. `iter` is not - // used outside of saving caches to disk and self-profile. - present.push(key.index); - } - *slot = Some((value, index)); + self.local.complete(key.index, value, index) } else { self.foreign.complete(key, value, index) } } fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) { - let guard = self.local.lock(); - let (cache, present) = &*guard; - for &idx in present.iter() { - let value = cache[idx].unwrap(); - f(&DefId { krate: LOCAL_CRATE, index: idx }, &value.0, value.1); - } + self.local.iter(&mut |key, value, index| { + f(&DefId { krate: LOCAL_CRATE, index: *key }, value, index); + }); self.foreign.iter(f); } } + +impl QueryCache for VecCache +where + K: Idx + Eq + Hash + Copy + Debug, + V: Copy, +{ + type Key = K; + type Value = V; + + #[inline(always)] + fn lookup(&self, key: &K) -> Option<(V, DepNodeIndex)> { + self.lookup(key) + } + + #[inline] + fn complete(&self, key: K, value: V, index: DepNodeIndex) { + self.complete(key, value, index) + } + + fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) { + self.iter(f) + } +} From 2765432d325d548e1a5e01e6c294d4f43cdbdb81 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 8 Nov 2024 13:59:02 +1100 Subject: [PATCH 14/44] Improve `{BTreeMap,HashMap}::get_key_value` docs. They are unusual methods. The docs don't really describe the cases when they might be useful (as opposed to just `get`), and the examples don't demonstrate the interesting cases at all. This commit improves the docs and the examples. --- library/alloc/src/collections/btree/map.rs | 46 ++++++++++++++++++++-- library/std/src/collections/hash/map.rs | 40 +++++++++++++++++-- 2 files changed, 78 insertions(+), 8 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 66353ccfa47..213924d1d02 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -677,7 +677,11 @@ impl BTreeMap { } } - /// Returns the key-value pair corresponding to the supplied key. + /// Returns the key-value pair corresponding to the supplied key. This is + /// potentially useful: + /// - for key types where non-identical keys can be considered equal; + /// - for getting the `&K` stored key value from a borrowed `&Q` lookup key; or + /// - for getting a reference to a key with the same lifetime as the collection. /// /// The supplied key may be any borrowed form of the map's key type, but the ordering /// on the borrowed form *must* match the ordering on the key type. @@ -685,12 +689,46 @@ impl BTreeMap { /// # Examples /// /// ``` + /// use std::cmp::Ordering; /// use std::collections::BTreeMap; /// + /// #[derive(Clone, Copy, Debug)] + /// struct S { + /// id: u32, + /// # #[allow(unused)] // prevents a "field `name` is never read" error + /// name: &'static str, // ignored by equality and ordering operations + /// } + /// + /// impl PartialEq for S { + /// fn eq(&self, other: &S) -> bool { + /// self.id == other.id + /// } + /// } + /// + /// impl Eq for S {} + /// + /// impl PartialOrd for S { + /// fn partial_cmp(&self, other: &S) -> Option { + /// self.id.partial_cmp(&other.id) + /// } + /// } + /// + /// impl Ord for S { + /// fn cmp(&self, other: &S) -> Ordering { + /// self.id.cmp(&other.id) + /// } + /// } + /// + /// let j_a = S { id: 1, name: "Jessica" }; + /// let j_b = S { id: 1, name: "Jess" }; + /// let p = S { id: 2, name: "Paul" }; + /// assert_eq!(j_a, j_b); + /// /// let mut map = BTreeMap::new(); - /// map.insert(1, "a"); - /// assert_eq!(map.get_key_value(&1), Some((&1, &"a"))); - /// assert_eq!(map.get_key_value(&2), None); + /// map.insert(j_a, "Paris"); + /// assert_eq!(map.get_key_value(&j_a), Some((&j_a, &"Paris"))); + /// assert_eq!(map.get_key_value(&j_b), Some((&j_a, &"Paris"))); // the notable case + /// assert_eq!(map.get_key_value(&p), None); /// ``` #[stable(feature = "map_get_key_value", since = "1.40.0")] pub fn get_key_value(&self, k: &Q) -> Option<(&K, &V)> diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index ded4f404d78..24bbc2f32cf 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -880,7 +880,11 @@ where self.base.get(k) } - /// Returns the key-value pair corresponding to the supplied key. + /// Returns the key-value pair corresponding to the supplied key. This is + /// potentially useful: + /// - for key types where non-identical keys can be considered equal; + /// - for getting the `&K` stored key value from a borrowed `&Q` lookup key; or + /// - for getting a reference to a key with the same lifetime as the collection. /// /// The supplied key may be any borrowed form of the map's key type, but /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for @@ -890,11 +894,39 @@ where /// /// ``` /// use std::collections::HashMap; + /// use std::hash::{Hash, Hasher}; + /// + /// #[derive(Clone, Copy, Debug)] + /// struct S { + /// id: u32, + /// # #[allow(unused)] // prevents a "field `name` is never read" error + /// name: &'static str, // ignored by equality and hashing operations + /// } + /// + /// impl PartialEq for S { + /// fn eq(&self, other: &S) -> bool { + /// self.id == other.id + /// } + /// } + /// + /// impl Eq for S {} + /// + /// impl Hash for S { + /// fn hash(&self, state: &mut H) { + /// self.id.hash(state); + /// } + /// } + /// + /// let j_a = S { id: 1, name: "Jessica" }; + /// let j_b = S { id: 1, name: "Jess" }; + /// let p = S { id: 2, name: "Paul" }; + /// assert_eq!(j_a, j_b); /// /// let mut map = HashMap::new(); - /// map.insert(1, "a"); - /// assert_eq!(map.get_key_value(&1), Some((&1, &"a"))); - /// assert_eq!(map.get_key_value(&2), None); + /// map.insert(j_a, "Paris"); + /// assert_eq!(map.get_key_value(&j_a), Some((&j_a, &"Paris"))); + /// assert_eq!(map.get_key_value(&j_b), Some((&j_a, &"Paris"))); // the notable case + /// assert_eq!(map.get_key_value(&p), None); /// ``` #[inline] #[stable(feature = "map_get_key_value", since = "1.40.0")] From 8ea02578cdae8a11f2c918c4d202696b95c26cc0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 18 Nov 2024 17:00:44 +0100 Subject: [PATCH 15/44] Fix typo --- src/librustdoc/html/render/span_map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index b314b060368..fec6779965a 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -36,7 +36,7 @@ pub(crate) enum LinkFromSrc { /// It returns the `krate`, the source code files and the `span` correspondence map. /// /// Note about the `span` correspondence map: the keys are actually `(lo, hi)` of `span`s. We don't -/// need the `span` context later on, only their position, so instead of keep a whole `Span`, we +/// need the `span` context later on, only their position, so instead of keeping a whole `Span`, we /// only keep the `lo` and `hi`. pub(crate) fn collect_spans_and_sources( tcx: TyCtxt<'_>, From 786b7477f6d40e0b79cd15dff0301a4aa53d7daf Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 18 Nov 2024 17:56:52 +0100 Subject: [PATCH 16/44] Fix items with generics not having their jump to def link generated --- src/librustdoc/html/render/span_map.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index fec6779965a..d4cca562d6c 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -45,9 +45,9 @@ pub(crate) fn collect_spans_and_sources( include_sources: bool, generate_link_to_definition: bool, ) -> (FxIndexMap, FxHashMap) { - let mut visitor = SpanMapVisitor { tcx, matches: FxHashMap::default() }; - if include_sources { + let mut visitor = SpanMapVisitor { tcx, matches: FxHashMap::default() }; + if generate_link_to_definition { tcx.hir().walk_toplevel_module(&mut visitor); } @@ -76,7 +76,22 @@ impl<'tcx> SpanMapVisitor<'tcx> { } else { LinkFromSrc::External(def_id) }; - self.matches.insert(path.span, link); + // In case the path ends with generics, we remove them from the span. + let span = path + .segments + .last() + .map(|last| { + // In `use` statements, the included item is not in the path segments. + // However, it doesn't matter because you can't have generics on `use` + // statements. + if path.span.contains(last.ident.span) { + path.span.with_hi(last.ident.span.hi()) + } else { + path.span + } + }) + .unwrap_or(path.span); + self.matches.insert(span, link); } Res::Local(_) => { if let Some(span) = self.tcx.hir().res_span(path.res) { From 8b0f8cb73c29b9466d817c3d7fda4ff52b90c4a7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 18 Nov 2024 17:57:27 +0100 Subject: [PATCH 17/44] Add regression test for jump to def links on items with generics --- tests/rustdoc/link-on-path-with-generics.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tests/rustdoc/link-on-path-with-generics.rs diff --git a/tests/rustdoc/link-on-path-with-generics.rs b/tests/rustdoc/link-on-path-with-generics.rs new file mode 100644 index 00000000000..22ba36c9f15 --- /dev/null +++ b/tests/rustdoc/link-on-path-with-generics.rs @@ -0,0 +1,14 @@ +// This test ensures that paths with generics still get their link to their definition +// correctly generated. + +//@ compile-flags: -Zunstable-options --generate-link-to-definition +#![crate_name = "foo"] + +//@ has 'src/foo/link-on-path-with-generics.rs.html' + +pub struct Soyo(T); +pub struct Saya; + +//@ has - '//pre[@class="rust"]//a[@href="#9"]' 'Soyo' +//@ has - '//pre[@class="rust"]//a[@href="#10"]' 'Saya' +pub fn bar(s: Soyo, x: Saya) {} From 31f5c3ba69f68c911773e2f126e98994c60bf58e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Nov 2024 18:17:02 +0100 Subject: [PATCH 18/44] const_panic: inline in bootstrap builds to avoid f16/f128 crashes --- library/core/src/panic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index e702056f00a..179aadf0c28 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -215,7 +215,7 @@ pub macro const_panic { #[noinline] if const #[track_caller] #[inline] { // Inline this, to prevent codegen $crate::panic!($const_msg) - } else #[track_caller] { // Do not inline this, it makes perf worse + } else #[track_caller] #[cfg_attr(bootstrap, inline)] { // Do not inline this, it makes perf worse $crate::panic!($runtime_msg) } ) From cc48194bafb621e1312e318c5911edef9a3b9e00 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 3 Nov 2024 21:05:49 +0100 Subject: [PATCH 19/44] Report `unexpected_cfgs` lint in external macros --- compiler/rustc_lint_defs/src/builtin.rs | 1 + tests/ui/check-cfg/auxiliary/cfg_macro.rs | 11 +++++++++++ tests/ui/check-cfg/report-in-external-macros.rs | 12 ++++++++++++ .../ui/check-cfg/report-in-external-macros.stderr | 14 ++++++++++++++ 4 files changed, 38 insertions(+) create mode 100644 tests/ui/check-cfg/auxiliary/cfg_macro.rs create mode 100644 tests/ui/check-cfg/report-in-external-macros.rs create mode 100644 tests/ui/check-cfg/report-in-external-macros.stderr diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index efdb4b077e9..313a7badf19 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3185,6 +3185,7 @@ declare_lint! { pub UNEXPECTED_CFGS, Warn, "detects unexpected names and values in `#[cfg]` conditions", + report_in_external_macro } declare_lint! { diff --git a/tests/ui/check-cfg/auxiliary/cfg_macro.rs b/tests/ui/check-cfg/auxiliary/cfg_macro.rs new file mode 100644 index 00000000000..d68accd9202 --- /dev/null +++ b/tests/ui/check-cfg/auxiliary/cfg_macro.rs @@ -0,0 +1,11 @@ +// Inspired by https://github.com/rust-lang/cargo/issues/14775 + +pub fn my_lib_func() {} + +#[macro_export] +macro_rules! my_lib_macro { + () => { + #[cfg(my_lib_cfg)] + $crate::my_lib_func() + }; +} diff --git a/tests/ui/check-cfg/report-in-external-macros.rs b/tests/ui/check-cfg/report-in-external-macros.rs new file mode 100644 index 00000000000..56550b04af3 --- /dev/null +++ b/tests/ui/check-cfg/report-in-external-macros.rs @@ -0,0 +1,12 @@ +// This test checks that we emit the `unexpected_cfgs` lint even in code +// coming from an external macro. + +//@ check-pass +//@ no-auto-check-cfg +//@ aux-crate: cfg_macro=cfg_macro.rs +//@ compile-flags: --check-cfg=cfg() + +fn main() { + cfg_macro::my_lib_macro!(); + //~^ WARNING unexpected `cfg` condition name +} diff --git a/tests/ui/check-cfg/report-in-external-macros.stderr b/tests/ui/check-cfg/report-in-external-macros.stderr new file mode 100644 index 00000000000..11300a4e402 --- /dev/null +++ b/tests/ui/check-cfg/report-in-external-macros.stderr @@ -0,0 +1,14 @@ +warning: unexpected `cfg` condition name: `my_lib_cfg` + --> $DIR/report-in-external-macros.rs:10:5 + | +LL | cfg_macro::my_lib_macro!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `fmt_debug`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows` + = help: to expect this configuration use `--check-cfg=cfg(my_lib_cfg)` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + = note: this warning originates in the macro `cfg_macro::my_lib_macro` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 1 warning emitted + From e8bd643450c79181751aad61020a868dd6f76acd Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 4 Nov 2024 19:17:39 +0100 Subject: [PATCH 20/44] Update `anstream` to 0.6.18 to fix a check-cfg issue --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e5025a1ba4f..c8d26559728 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -111,9 +111,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.17" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", From 58664de837a967c9afe440d218dec11ecbd0c5e1 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 7 Nov 2024 23:34:12 +0100 Subject: [PATCH 21/44] Bump `stdarch` to the latest master --- library/stdarch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/stdarch b/library/stdarch index ff9a4445038..e5e00aab0a8 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit ff9a4445038eae46fd095188740946808581bc0e +Subproject commit e5e00aab0a8c8fa35fb7865e88fa82366f615c53 From 79c8e64162e8992df3cee65e059e13e1bc2c4aa2 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 16 Nov 2024 17:44:54 +0100 Subject: [PATCH 22/44] Update `xshell` and `xshell-macros` to v0.2.7 --- src/tools/miri/miri-script/Cargo.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tools/miri/miri-script/Cargo.lock b/src/tools/miri/miri-script/Cargo.lock index 8dad30df6d1..0c0fe477cdd 100644 --- a/src/tools/miri/miri-script/Cargo.lock +++ b/src/tools/miri/miri-script/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "anyhow" @@ -521,15 +521,15 @@ checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" [[package]] name = "xshell" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db0ab86eae739efd1b054a8d3d16041914030ac4e01cd1dca0cf252fd8b6437" +checksum = "9e7290c623014758632efe00737145b6867b66292c42167f2ec381eb566a373d" dependencies = [ "xshell-macros", ] [[package]] name = "xshell-macros" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d422e8e38ec76e2f06ee439ccc765e9c6a9638b9e7c9f2e8255e4d41e8bd852" +checksum = "32ac00cd3f8ec9c1d33fb3e7958a82df6989c42d747bd326c822b1d625283547" From 3fbcc1f4b974c407c6e836541a0c5f94467d12c6 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 18 Nov 2024 11:34:53 -0700 Subject: [PATCH 23/44] rustdoc-search: use smart binary search in bitmaps Addresses a comment from [jsha's benchmarking], where the `contains` function showed up in the profiler. This commit pulls it from about 5% of the runtime to about 0.5%. [jsha's benchmarking]: https://rust-lang.zulipchat.com/#narrow/channel/266220-t-rustdoc/topic/search.20profiling/near/481868761 --- src/librustdoc/html/static/js/search.js | 42 +++++++++++++++++++------ 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index c1a021e9f8d..bee5327f6fc 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1053,9 +1053,17 @@ class RoaringBitmap { contains(keyvalue) { const key = keyvalue >> 16; const value = keyvalue & 0xFFFF; - for (let i = 0; i < this.keys.length; ++i) { - if (this.keys[i] === key) { - return this.containers[i].contains(value); + let left = 0; + let right = this.keys.length - 1; + while (left <= right) { + const mid = Math.floor((left + right) / 2); + const x = this.keys[mid]; + if (x < key) { + left = mid + 1; + } else if (x > key) { + right = mid - 1; + } else { + return this.containers[mid].contains(value); } } return false; @@ -1068,11 +1076,18 @@ class RoaringBitmapRun { this.array = array; } contains(value) { - const l = this.runcount * 4; - for (let i = 0; i < l; i += 4) { + let left = 0; + let right = this.runcount - 1; + while (left <= right) { + const mid = Math.floor((left + right) / 2); + const i = mid * 4; const start = this.array[i] | (this.array[i + 1] << 8); const lenm1 = this.array[i + 2] | (this.array[i + 3] << 8); - if (value >= start && value <= (start + lenm1)) { + if ((start + lenm1) < value) { + left = mid + 1; + } else if (start > value) { + right = mid - 1; + } else { return true; } } @@ -1085,10 +1100,17 @@ class RoaringBitmapArray { this.array = array; } contains(value) { - const l = this.cardinality * 2; - for (let i = 0; i < l; i += 2) { - const start = this.array[i] | (this.array[i + 1] << 8); - if (value === start) { + let left = 0; + let right = this.cardinality - 1; + while (left <= right) { + const mid = Math.floor((left + right) / 2); + const i = mid * 2; + const x = this.array[i] | (this.array[i + 1] << 8); + if (x < value) { + left = mid + 1; + } else if (x > value) { + right = mid - 1; + } else { return true; } } From 8f95079cfc36387c3f0b792b1c8c157f67c5be19 Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Mon, 18 Nov 2024 19:43:04 +0100 Subject: [PATCH 24/44] Document s390x-unknown-linux targets This adds documentation for the following existing targets: s390x-unknown-linux-gnu (Tier 2 with host tools) s390x-unknown-linux-musl (Tier 3) I volunteer as maintainer for these targets going forward. Signed-off-by: Ulrich Weigand --- src/doc/rustc/src/SUMMARY.md | 2 + src/doc/rustc/src/platform-support.md | 4 +- .../s390x-unknown-linux-gnu.md | 112 ++++++++++++++++++ .../s390x-unknown-linux-musl.md | 83 +++++++++++++ 4 files changed, 199 insertions(+), 2 deletions(-) create mode 100644 src/doc/rustc/src/platform-support/s390x-unknown-linux-gnu.md create mode 100644 src/doc/rustc/src/platform-support/s390x-unknown-linux-musl.md diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 18f76ac6fe0..f3d8a4edd6c 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -72,6 +72,8 @@ - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md) - [riscv64gc-unknown-linux-gnu](platform-support/riscv64gc-unknown-linux-gnu.md) - [riscv64gc-unknown-linux-musl](platform-support/riscv64gc-unknown-linux-musl.md) + - [s390x-unknown-linux-gnu](platform-support/s390x-unknown-linux-gnu.md) + - [s390x-unknown-linux-musl](platform-support/s390x-unknown-linux-musl.md) - [sparc-unknown-none-elf](./platform-support/sparc-unknown-none-elf.md) - [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md) - [\*-nto-qnx-\*](platform-support/nto-qnx.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 500eaafb63f..243cb3b2fc8 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -99,7 +99,7 @@ target | notes `powerpc64le-unknown-linux-gnu` | PPC64LE Linux (kernel 3.10, glibc 2.17) [`riscv64gc-unknown-linux-gnu`](platform-support/riscv64gc-unknown-linux-gnu.md) | RISC-V Linux (kernel 4.20, glibc 2.29) [`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | RISC-V Linux (kernel 4.20, musl 1.2.3) -`s390x-unknown-linux-gnu` | S390x Linux (kernel 3.2, glibc 2.17) +[`s390x-unknown-linux-gnu`](platform-support/s390x-unknown-linux-gnu.md) | S390x Linux (kernel 3.2, glibc 2.17) `x86_64-unknown-freebsd` | 64-bit FreeBSD `x86_64-unknown-illumos` | illumos `x86_64-unknown-linux-musl` | 64-bit Linux with musl 1.2.3 @@ -367,7 +367,7 @@ target | std | host | notes [`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64 [`riscv64-linux-android`](platform-support/android.md) | | | RISC-V 64-bit Android [`riscv64-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | -`s390x-unknown-linux-musl` | | | S390x Linux (kernel 3.2, musl 1.2.3) +[`s390x-unknown-linux-musl`](platform-support/s390x-unknown-linux-musl.md) | | | S390x Linux (kernel 3.2, musl 1.2.3) `sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux [`sparc-unknown-none-elf`](./platform-support/sparc-unknown-none-elf.md) | * | | Bare 32-bit SPARC V7+ [`sparc64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/sparc64 diff --git a/src/doc/rustc/src/platform-support/s390x-unknown-linux-gnu.md b/src/doc/rustc/src/platform-support/s390x-unknown-linux-gnu.md new file mode 100644 index 00000000000..b514a254e27 --- /dev/null +++ b/src/doc/rustc/src/platform-support/s390x-unknown-linux-gnu.md @@ -0,0 +1,112 @@ +# `s390x-unknown-linux-gnu` + +**Tier: 2 (with Host Tools)** + +IBM z/Architecture (s390x) targets (including IBM Z and LinuxONE) running Linux. + +## Target maintainers + +- Ulrich Weigand, , [@uweigand](https://github.com/uweigand) + +## Requirements + +This target requires: + +* Linux Kernel version 3.2 or later +* glibc 2.17 or later + +Code generated by the target uses the z/Architecture ISA assuming a minimum +architecture level of z10 (Eighth Edition of the z/Architecture Principles +of Operation), and is compliant with the s390x ELF ABI. + +Reference material: + +* [z/Architecture Principles of Operation][s390x-isa] +* [z/Architecture ELF Application Binary Interface][s390x-abi] + +[s390x-isa]: https://publibfp.dhe.ibm.com/epubs/pdf/a227832d.pdf +[s390x-abi]: https://github.com/IBM/s390x-abi + +## Building the target + +This target is distributed through `rustup`, and otherwise requires no +special configuration. + +If you need to build your own Rust for some reason though, the target can be +enabled in `config.toml`. For example: + +```toml +[build] +target = ["s390x-unknown-linux-gnu"] +``` + +## Building Rust programs + +On a s390x Linux host, the `s390x-unknown-linux-gnu` target should be +automatically installed and used by default. + +On a non-s390x host, add the target: + +```bash +rustup target add s390x-unknown-linux-gnu +``` + +Then cross compile crates with: + +```bash +cargo build --target s390x-unknown-linux-gnu +``` + +## Testing + +There are no special requirements for testing and running the target. +For testing cross builds on the host, please refer to the "Cross-compilation +toolchains and C code" section below. + +## Cross-compilation toolchains and C code + +Rust code built using the target is compatible with C code compiled with +GCC or Clang using the `s390x-unknown-linux-gnu` target triple (via either +native or cross-compilation). + +On Ubuntu, a s390x cross-toolchain can be installed with: + +```bash +apt install gcc-s390x-linux-gnu g++-s390x-linux-gnu libc6-dev-s390x-cross +``` + +Depending on your system, you may need to configure the target to use the GNU +GCC linker. To use it, add the following to your `.cargo/config.toml`: + +```toml +[target.s390x-unknown-linux-gnu] +linker = "s390x-linux-gnu-gcc" +``` + +If your `s390x-linux-gnu-*` toolchain is not in your `PATH` you may need to +configure additional settings: + +```toml +[target.s390x-unknown-linux-gnu] +# Adjust the paths to point at your toolchain +cc = "/TOOLCHAIN_PATH/bin/s390x-linux-gnu-gcc" +cxx = "/TOOLCHAIN_PATH/bin/s390x-linux-gnu-g++" +ar = "/TOOLCHAIN_PATH/bin/s390x-linux-gnu-ar" +ranlib = "/TOOLCHAIN_PATH/bin/s390x-linux-gnu-ranlib" +linker = "/TOOLCHAIN_PATH/bin/s390x-linux-gnu-gcc" +``` + +To test cross compiled binaries on a non-s390x host, you can use +[`qemu`](https://www.qemu.org/docs/master/system/target-s390x.html). +On Ubuntu, a s390x emulator can be obtained with: + +```bash +apt install qemu-system-s390x +``` + +Then, in `.cargo/config.toml` set the `runner`: + +```toml +[target.s390x-unknown-linux-gnu] +runner = "qemu-s390x-static -L /usr/s390x-linux-gnu" +``` diff --git a/src/doc/rustc/src/platform-support/s390x-unknown-linux-musl.md b/src/doc/rustc/src/platform-support/s390x-unknown-linux-musl.md new file mode 100644 index 00000000000..e00f8db7f8e --- /dev/null +++ b/src/doc/rustc/src/platform-support/s390x-unknown-linux-musl.md @@ -0,0 +1,83 @@ +# `s390x-unknown-linux-musl` + +**Tier: 3** + +IBM z/Architecture (s390x) targets (including IBM Z and LinuxONE) running Linux. + +## Target maintainers + +- Ulrich Weigand, , [@uweigand](https://github.com/uweigand) + +## Requirements + +This target requires: + +* Linux Kernel version 3.2 or later +* musl 1.2.3 or later + +Code generated by the target uses the z/Architecture ISA assuming a minimum +architecture level of z10 (Eighth Edition of the z/Architecture Principles +of Operation), and is compliant with the s390x ELF ABI. + +Reference material: + +* [z/Architecture Principles of Operation][s390x-isa] +* [z/Architecture ELF Application Binary Interface][s390x-abi] + +[s390x-isa]: https://publibfp.dhe.ibm.com/epubs/pdf/a227832d.pdf +[s390x-abi]: https://github.com/IBM/s390x-abi + +## Building the target + +Because it is Tier 3, Rust does not yet ship pre-compiled artifacts for this +target. + +Therefore, you can build Rust with support for the target by adding it to the +target list in `config.toml`, a sample configuration is shown below. + +```toml +[build] +target = ["s390x-unknown-linux-musl"] +``` + +## 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). + +## Testing + +There are no special requirements for testing and running the target. +For testing cross builds on the host, please refer to the "Cross-compilation +toolchains and C code" section below. + +## Cross-compilation toolchains and C code + +Rust code built using the target is compatible with C code compiled with +GCC or Clang using the `s390x-unknown-linux-musl` target triple (via either +native or cross-compilation). + +Depending on your system, you may need to configure the target to use the GNU +GCC linker. To use it, add the following to your `.cargo/config.toml`: + +```toml +[target.s390x-unknown-linux-musl] +linker = "s390x-linux-musl-gcc" +``` + +If your `s390x-linux-musl-*` toolchain is not in your `PATH` you may need to +configure additional settings: + +```toml +[target.s390x-unknown-linux-musl] +# Adjust the paths to point at your toolchain +cc = "/TOOLCHAIN_PATH/bin/s390x-linux-musl-gcc" +cxx = "/TOOLCHAIN_PATH/bin/s390x-linux-musl-g++" +ar = "/TOOLCHAIN_PATH/bin/s390x-linux-musl-ar" +ranlib = "/TOOLCHAIN_PATH/bin/s390x-linux-musl-ranlib" +linker = "/TOOLCHAIN_PATH/bin/s390x-linux-musl-gcc" +``` + +To test cross compiled binaries on a non-s390x host, you can use +[`qemu`](https://www.qemu.org/docs/master/system/target-s390x.html). From 1b0e78738b062200a1982082ad2a68023715a670 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 18 Nov 2024 10:45:26 -0800 Subject: [PATCH 25/44] Add reference annotations for diagnostic attributes This adds reference annotations for `diagnostic::on_unimplmented` and the `diagnostic` namespace in general. --- .../deny_malformed_attribute.rs | 2 + .../deny_malformed_attribute.stderr | 4 +- .../malformed_foreign_on_unimplemented.rs | 1 + .../malformed_foreign_on_unimplemented.stderr | 36 ++++----- .../non_existing_attributes_accepted.rs | 1 + .../non_existing_attributes_accepted.stderr | 4 +- .../on_unimplemented/broken_format.rs | 1 + .../on_unimplemented/broken_format.stderr | 54 +++++++------- .../custom-on-unimplemented-diagnostic.rs | 2 + .../custom-on-unimplemented-diagnostic.stderr | 8 +- ...options_of_the_internal_rustc_attribute.rs | 4 + ...ons_of_the_internal_rustc_attribute.stderr | 74 +++++++++---------- ...o_not_fail_parsing_on_invalid_options_1.rs | 2 + ...t_fail_parsing_on_invalid_options_1.stderr | 54 +++++++------- .../error_is_shown_in_downstream_crates.rs | 1 + ...error_is_shown_in_downstream_crates.stderr | 4 +- ...ed_options_and_continue_to_use_fallback.rs | 2 + ...ptions_and_continue_to_use_fallback.stderr | 14 ++-- .../on_unimplemented/multiple_notes.rs | 1 + .../on_unimplemented/multiple_notes.stderr | 12 +-- .../on_unimplemented_simple.rs | 2 + .../on_unimplemented_simple.stderr | 6 +- .../report_warning_on_duplicated_options.rs | 1 + ...eport_warning_on_duplicated_options.stderr | 14 ++-- .../ui/diagnostic_namespace/suggest_typos.rs | 1 + .../diagnostic_namespace/suggest_typos.stderr | 8 +- .../negative-bounds/on-unimplemented.rs | 2 + .../negative-bounds/on-unimplemented.stderr | 2 +- 28 files changed, 170 insertions(+), 147 deletions(-) diff --git a/tests/ui/diagnostic_namespace/deny_malformed_attribute.rs b/tests/ui/diagnostic_namespace/deny_malformed_attribute.rs index 1d946a14aff..a46c856d38e 100644 --- a/tests/ui/diagnostic_namespace/deny_malformed_attribute.rs +++ b/tests/ui/diagnostic_namespace/deny_malformed_attribute.rs @@ -1,3 +1,5 @@ +//@ reference: attributes.diagnostic.namespace.unknown-invalid-syntax + #![deny(unknown_or_malformed_diagnostic_attributes)] #[diagnostic::unknown_attribute] diff --git a/tests/ui/diagnostic_namespace/deny_malformed_attribute.stderr b/tests/ui/diagnostic_namespace/deny_malformed_attribute.stderr index a646d3613de..32be9db5317 100644 --- a/tests/ui/diagnostic_namespace/deny_malformed_attribute.stderr +++ b/tests/ui/diagnostic_namespace/deny_malformed_attribute.stderr @@ -1,11 +1,11 @@ error: unknown diagnostic attribute - --> $DIR/deny_malformed_attribute.rs:3:15 + --> $DIR/deny_malformed_attribute.rs:5:15 | LL | #[diagnostic::unknown_attribute] | ^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/deny_malformed_attribute.rs:1:9 + --> $DIR/deny_malformed_attribute.rs:3:9 | LL | #![deny(unknown_or_malformed_diagnostic_attributes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.rs b/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.rs index 8b7467a17d0..b90dd0c7c94 100644 --- a/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.rs +++ b/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.rs @@ -1,5 +1,6 @@ //@ edition:2021 //@ aux-build:bad_on_unimplemented.rs +//@ reference: attributes.diagnostic.on_unimplemented.syntax // Do not ICE when encountering a malformed `#[diagnostic::on_unimplemented]` annotation in a // dependency when incorrectly used (#124651). diff --git a/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.stderr b/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.stderr index c3e56550b70..f1258ad6b9a 100644 --- a/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.stderr +++ b/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `(): bad_on_unimplemented::MissingAttr` is not satisfied - --> $DIR/malformed_foreign_on_unimplemented.rs:22:18 + --> $DIR/malformed_foreign_on_unimplemented.rs:23:18 | LL | missing_attr(()); | ------------ ^^ the trait `bad_on_unimplemented::MissingAttr` is not implemented for `()` @@ -7,13 +7,13 @@ LL | missing_attr(()); | required by a bound introduced by this call | note: required by a bound in `missing_attr` - --> $DIR/malformed_foreign_on_unimplemented.rs:11:20 + --> $DIR/malformed_foreign_on_unimplemented.rs:12:20 | LL | fn missing_attr(_: T) {} | ^^^^^^^^^^^ required by this bound in `missing_attr` error[E0277]: the trait bound `(): bad_on_unimplemented::DuplicateAttr` is not satisfied - --> $DIR/malformed_foreign_on_unimplemented.rs:23:20 + --> $DIR/malformed_foreign_on_unimplemented.rs:24:20 | LL | duplicate_attr(()); | -------------- ^^ a @@ -22,13 +22,13 @@ LL | duplicate_attr(()); | = help: the trait `bad_on_unimplemented::DuplicateAttr` is not implemented for `()` note: required by a bound in `duplicate_attr` - --> $DIR/malformed_foreign_on_unimplemented.rs:12:22 + --> $DIR/malformed_foreign_on_unimplemented.rs:13:22 | LL | fn duplicate_attr(_: T) {} | ^^^^^^^^^^^^^ required by this bound in `duplicate_attr` error[E0277]: the trait bound `(): bad_on_unimplemented::NotMetaList` is not satisfied - --> $DIR/malformed_foreign_on_unimplemented.rs:24:19 + --> $DIR/malformed_foreign_on_unimplemented.rs:25:19 | LL | not_meta_list(()); | ------------- ^^ the trait `bad_on_unimplemented::NotMetaList` is not implemented for `()` @@ -36,13 +36,13 @@ LL | not_meta_list(()); | required by a bound introduced by this call | note: required by a bound in `not_meta_list` - --> $DIR/malformed_foreign_on_unimplemented.rs:13:21 + --> $DIR/malformed_foreign_on_unimplemented.rs:14:21 | LL | fn not_meta_list(_: T) {} | ^^^^^^^^^^^ required by this bound in `not_meta_list` error[E0277]: the trait bound `(): bad_on_unimplemented::Empty` is not satisfied - --> $DIR/malformed_foreign_on_unimplemented.rs:25:11 + --> $DIR/malformed_foreign_on_unimplemented.rs:26:11 | LL | empty(()); | ----- ^^ the trait `bad_on_unimplemented::Empty` is not implemented for `()` @@ -50,13 +50,13 @@ LL | empty(()); | required by a bound introduced by this call | note: required by a bound in `empty` - --> $DIR/malformed_foreign_on_unimplemented.rs:14:13 + --> $DIR/malformed_foreign_on_unimplemented.rs:15:13 | LL | fn empty(_: T) {} | ^^^^^ required by this bound in `empty` error[E0277]: the trait bound `(): bad_on_unimplemented::WrongDelim` is not satisfied - --> $DIR/malformed_foreign_on_unimplemented.rs:26:17 + --> $DIR/malformed_foreign_on_unimplemented.rs:27:17 | LL | wrong_delim(()); | ----------- ^^ the trait `bad_on_unimplemented::WrongDelim` is not implemented for `()` @@ -64,13 +64,13 @@ LL | wrong_delim(()); | required by a bound introduced by this call | note: required by a bound in `wrong_delim` - --> $DIR/malformed_foreign_on_unimplemented.rs:15:19 + --> $DIR/malformed_foreign_on_unimplemented.rs:16:19 | LL | fn wrong_delim(_: T) {} | ^^^^^^^^^^ required by this bound in `wrong_delim` error[E0277]: the trait bound `(): bad_on_unimplemented::BadFormatter<()>` is not satisfied - --> $DIR/malformed_foreign_on_unimplemented.rs:27:19 + --> $DIR/malformed_foreign_on_unimplemented.rs:28:19 | LL | bad_formatter(()); | ------------- ^^ () @@ -79,13 +79,13 @@ LL | bad_formatter(()); | = help: the trait `bad_on_unimplemented::BadFormatter<()>` is not implemented for `()` note: required by a bound in `bad_formatter` - --> $DIR/malformed_foreign_on_unimplemented.rs:16:21 + --> $DIR/malformed_foreign_on_unimplemented.rs:17:21 | LL | fn bad_formatter>(_: T) {} | ^^^^^^^^^^^^^^^^ required by this bound in `bad_formatter` error[E0277]: the trait bound `(): bad_on_unimplemented::NoImplicitArgs` is not satisfied - --> $DIR/malformed_foreign_on_unimplemented.rs:28:22 + --> $DIR/malformed_foreign_on_unimplemented.rs:29:22 | LL | no_implicit_args(()); | ---------------- ^^ test {} @@ -94,13 +94,13 @@ LL | no_implicit_args(()); | = help: the trait `bad_on_unimplemented::NoImplicitArgs` is not implemented for `()` note: required by a bound in `no_implicit_args` - --> $DIR/malformed_foreign_on_unimplemented.rs:17:24 + --> $DIR/malformed_foreign_on_unimplemented.rs:18:24 | LL | fn no_implicit_args(_: T) {} | ^^^^^^^^^^^^^^ required by this bound in `no_implicit_args` error[E0277]: the trait bound `(): bad_on_unimplemented::MissingArg` is not satisfied - --> $DIR/malformed_foreign_on_unimplemented.rs:29:17 + --> $DIR/malformed_foreign_on_unimplemented.rs:30:17 | LL | missing_arg(()); | ----------- ^^ {missing} @@ -109,13 +109,13 @@ LL | missing_arg(()); | = help: the trait `bad_on_unimplemented::MissingArg` is not implemented for `()` note: required by a bound in `missing_arg` - --> $DIR/malformed_foreign_on_unimplemented.rs:18:19 + --> $DIR/malformed_foreign_on_unimplemented.rs:19:19 | LL | fn missing_arg(_: T) {} | ^^^^^^^^^^ required by this bound in `missing_arg` error[E0277]: the trait bound `(): bad_on_unimplemented::BadArg` is not satisfied - --> $DIR/malformed_foreign_on_unimplemented.rs:30:13 + --> $DIR/malformed_foreign_on_unimplemented.rs:31:13 | LL | bad_arg(()); | ------- ^^ {_} @@ -124,7 +124,7 @@ LL | bad_arg(()); | = help: the trait `bad_on_unimplemented::BadArg` is not implemented for `()` note: required by a bound in `bad_arg` - --> $DIR/malformed_foreign_on_unimplemented.rs:19:15 + --> $DIR/malformed_foreign_on_unimplemented.rs:20:15 | LL | fn bad_arg(_: T) {} | ^^^^^^ required by this bound in `bad_arg` diff --git a/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.rs b/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.rs index f6957b1448d..02c1352482c 100644 --- a/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.rs +++ b/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.rs @@ -1,4 +1,5 @@ //@ check-pass +//@ reference: attributes.diagnostic.namespace.unknown-invalid-syntax #[diagnostic::non_existing_attribute] //~^WARN unknown diagnostic attribute pub trait Bar { diff --git a/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr b/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr index c073ec9b103..753077b365e 100644 --- a/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr +++ b/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr @@ -1,5 +1,5 @@ warning: unknown diagnostic attribute - --> $DIR/non_existing_attributes_accepted.rs:2:15 + --> $DIR/non_existing_attributes_accepted.rs:3:15 | LL | #[diagnostic::non_existing_attribute] | ^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[diagnostic::non_existing_attribute] = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: unknown diagnostic attribute - --> $DIR/non_existing_attributes_accepted.rs:7:15 + --> $DIR/non_existing_attributes_accepted.rs:8:15 | LL | #[diagnostic::non_existing_attribute(with_option = "foo")] | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs index 3ca58b28181..44f269eb967 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs @@ -1,3 +1,4 @@ +//@ reference: attributes.diagnostic.on_unimplemented.invalid-string #[diagnostic::on_unimplemented(message = "{{Test } thing")] //~^WARN unmatched `}` found //~|WARN unmatched `}` found diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr index b4ed06cb63d..7fd51c7527f 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr @@ -1,5 +1,5 @@ warning: unmatched `}` found - --> $DIR/broken_format.rs:1:32 + --> $DIR/broken_format.rs:2:32 | LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")] = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: positional format arguments are not allowed here - --> $DIR/broken_format.rs:6:32 + --> $DIR/broken_format.rs:7:32 | LL | #[diagnostic::on_unimplemented(message = "Test {}")] | ^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {}")] = help: only named format arguments with the name of one of the generic types are allowed in this context warning: positional format arguments are not allowed here - --> $DIR/broken_format.rs:11:32 + --> $DIR/broken_format.rs:12:32 | LL | #[diagnostic::on_unimplemented(message = "Test {1:}")] | ^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {1:}")] = help: only named format arguments with the name of one of the generic types are allowed in this context warning: invalid format specifier - --> $DIR/broken_format.rs:16:32 + --> $DIR/broken_format.rs:17:32 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -31,19 +31,19 @@ LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")] = help: no format specifier are supported in this position warning: expected `}`, found `!` - --> $DIR/broken_format.rs:21:32 + --> $DIR/broken_format.rs:22:32 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unmatched `}` found - --> $DIR/broken_format.rs:21:32 + --> $DIR/broken_format.rs:22:32 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unmatched `}` found - --> $DIR/broken_format.rs:1:32 + --> $DIR/broken_format.rs:2:32 | LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -51,7 +51,7 @@ LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: {{Test } thing - --> $DIR/broken_format.rs:35:13 + --> $DIR/broken_format.rs:36:13 | LL | check_1(()); | ------- ^^ the trait `ImportantTrait1` is not implemented for `()` @@ -59,18 +59,18 @@ LL | check_1(()); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/broken_format.rs:4:1 + --> $DIR/broken_format.rs:5:1 | LL | trait ImportantTrait1 {} | ^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `check_1` - --> $DIR/broken_format.rs:28:20 + --> $DIR/broken_format.rs:29:20 | LL | fn check_1(_: impl ImportantTrait1) {} | ^^^^^^^^^^^^^^^ required by this bound in `check_1` warning: positional format arguments are not allowed here - --> $DIR/broken_format.rs:6:32 + --> $DIR/broken_format.rs:7:32 | LL | #[diagnostic::on_unimplemented(message = "Test {}")] | ^^^^^^^^^^^^^^^^^^^ @@ -79,7 +79,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {}")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Test {} - --> $DIR/broken_format.rs:37:13 + --> $DIR/broken_format.rs:38:13 | LL | check_2(()); | ------- ^^ the trait `ImportantTrait2` is not implemented for `()` @@ -87,18 +87,18 @@ LL | check_2(()); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/broken_format.rs:9:1 + --> $DIR/broken_format.rs:10:1 | LL | trait ImportantTrait2 {} | ^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `check_2` - --> $DIR/broken_format.rs:29:20 + --> $DIR/broken_format.rs:30:20 | LL | fn check_2(_: impl ImportantTrait2) {} | ^^^^^^^^^^^^^^^ required by this bound in `check_2` warning: positional format arguments are not allowed here - --> $DIR/broken_format.rs:11:32 + --> $DIR/broken_format.rs:12:32 | LL | #[diagnostic::on_unimplemented(message = "Test {1:}")] | ^^^^^^^^^^^^^^^^^^^^^ @@ -107,7 +107,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {1:}")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Test {1} - --> $DIR/broken_format.rs:39:13 + --> $DIR/broken_format.rs:40:13 | LL | check_3(()); | ------- ^^ the trait `ImportantTrait3` is not implemented for `()` @@ -115,18 +115,18 @@ LL | check_3(()); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/broken_format.rs:14:1 + --> $DIR/broken_format.rs:15:1 | LL | trait ImportantTrait3 {} | ^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `check_3` - --> $DIR/broken_format.rs:30:20 + --> $DIR/broken_format.rs:31:20 | LL | fn check_3(_: impl ImportantTrait3) {} | ^^^^^^^^^^^^^^^ required by this bound in `check_3` warning: invalid format specifier - --> $DIR/broken_format.rs:16:32 + --> $DIR/broken_format.rs:17:32 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -135,7 +135,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Test () - --> $DIR/broken_format.rs:41:13 + --> $DIR/broken_format.rs:42:13 | LL | check_4(()); | ------- ^^ the trait `ImportantTrait4` is not implemented for `()` @@ -143,18 +143,18 @@ LL | check_4(()); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/broken_format.rs:19:1 + --> $DIR/broken_format.rs:20:1 | LL | trait ImportantTrait4 {} | ^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `check_4` - --> $DIR/broken_format.rs:31:20 + --> $DIR/broken_format.rs:32:20 | LL | fn check_4(_: impl ImportantTrait4) {} | ^^^^^^^^^^^^^^^ required by this bound in `check_4` warning: expected `}`, found `!` - --> $DIR/broken_format.rs:21:32 + --> $DIR/broken_format.rs:22:32 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -162,7 +162,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: unmatched `}` found - --> $DIR/broken_format.rs:21:32 + --> $DIR/broken_format.rs:22:32 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -170,7 +170,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Test {Self:!} - --> $DIR/broken_format.rs:43:13 + --> $DIR/broken_format.rs:44:13 | LL | check_5(()); | ------- ^^ the trait `ImportantTrait5` is not implemented for `()` @@ -178,12 +178,12 @@ LL | check_5(()); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/broken_format.rs:26:1 + --> $DIR/broken_format.rs:27:1 | LL | trait ImportantTrait5 {} | ^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `check_5` - --> $DIR/broken_format.rs:32:20 + --> $DIR/broken_format.rs:33:20 | LL | fn check_5(_: impl ImportantTrait5) {} | ^^^^^^^^^^^^^^^ required by this bound in `check_5` diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.rs b/tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.rs index d7e257ef3bb..1173c939038 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.rs @@ -1,3 +1,5 @@ +//@ reference: attributes.diagnostic.on_unimplemented.intro +//@ reference: attributes.diagnostic.on_unimplemented.keys #[diagnostic::on_unimplemented(message = "my message", label = "my label", note = "my note")] pub trait ProviderLt {} diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.stderr index f9788360d06..4c1838620b3 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.stderr @@ -1,5 +1,5 @@ error[E0599]: my message - --> $DIR/custom-on-unimplemented-diagnostic.rs:15:7 + --> $DIR/custom-on-unimplemented-diagnostic.rs:17:7 | LL | struct B; | -------- method `request` not found for this struct because it doesn't satisfy `B: ProviderExt` or `B: ProviderLt` @@ -8,7 +8,7 @@ LL | B.request(); | ^^^^^^^ my label | note: trait bound `B: ProviderLt` was not satisfied - --> $DIR/custom-on-unimplemented-diagnostic.rs:10:18 + --> $DIR/custom-on-unimplemented-diagnostic.rs:12:18 | LL | impl ProviderExt for T {} | ^^^^^^^^^^ ----------- - @@ -16,13 +16,13 @@ LL | impl ProviderExt for T {} | unsatisfied trait bound introduced here = note: my note note: the trait `ProviderLt` must be implemented - --> $DIR/custom-on-unimplemented-diagnostic.rs:2:1 + --> $DIR/custom-on-unimplemented-diagnostic.rs:4:1 | LL | pub trait ProviderLt {} | ^^^^^^^^^^^^^^^^^^^^ = help: items from traits can only be used if the trait is implemented and in scope note: `ProviderExt` defines an item `request`, perhaps you need to implement it - --> $DIR/custom-on-unimplemented-diagnostic.rs:4:1 + --> $DIR/custom-on-unimplemented-diagnostic.rs:6:1 | LL | pub trait ProviderExt { | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs index 30a85ff2199..b76b550fcb2 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs @@ -1,3 +1,7 @@ +//@ reference: attributes.diagnostic.on_unimplemented.format-parameters +//@ reference: attributes.diagnostic.on_unimplemented.keys +//@ reference: attributes.diagnostic.on_unimplemented.syntax +//@ reference: attributes.diagnostic.on_unimplemented.invalid-formats #[diagnostic::on_unimplemented( on(_Self = "&str"), //~^WARN malformed `on_unimplemented` attribute diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr index e34b917f67e..bb455d92940 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr @@ -1,5 +1,5 @@ warning: `#[diagnostic::on_unimplemented]` can only be applied to trait definitions - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:22:1 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:26:1 | LL | #[diagnostic::on_unimplemented(message = "Not allowed to apply it on a impl")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[diagnostic::on_unimplemented(message = "Not allowed to apply it on a impl = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:2:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:6:5 | LL | on(_Self = "&str"), | ^^^^^^^^^^^^^^^^^^ invalid option found here @@ -15,7 +15,7 @@ LL | on(_Self = "&str"), = help: only `message`, `note` and `label` are allowed as options warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:8:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:12:5 | LL | parent_label = "in this scope", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -23,7 +23,7 @@ LL | parent_label = "in this scope", = help: only `message`, `note` and `label` are allowed as options warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:11:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:15:5 | LL | append_const_msg | ^^^^^^^^^^^^^^^^ invalid option found here @@ -31,7 +31,7 @@ LL | append_const_msg = help: only `message`, `note` and `label` are allowed as options warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:17:32 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:21:32 | LL | #[diagnostic::on_unimplemented = "Message"] | ^^^^^^^^^^^ invalid option found here @@ -39,7 +39,7 @@ LL | #[diagnostic::on_unimplemented = "Message"] = help: only `message`, `note` and `label` are allowed as options warning: there is no parameter `from_desugaring` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -47,7 +47,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `direct` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -55,7 +55,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `cause` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -63,7 +63,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `integral` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,7 +71,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `integer` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -79,7 +79,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `float` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -87,7 +87,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `_Self` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -95,7 +95,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `crate_local` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -103,7 +103,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `Trait` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -111,7 +111,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `ItemContext` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -119,7 +119,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = help: expect either a generic argument name or `{Self}` as format argument warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:2:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:6:5 | LL | on(_Self = "&str"), | ^^^^^^^^^^^^^^^^^^ invalid option found here @@ -128,7 +128,7 @@ LL | on(_Self = "&str"), = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:8:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:12:5 | LL | parent_label = "in this scope", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -137,7 +137,7 @@ LL | parent_label = "in this scope", = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:11:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:15:5 | LL | append_const_msg | ^^^^^^^^^^^^^^^^ invalid option found here @@ -146,7 +146,7 @@ LL | append_const_msg = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: trait has `()` and `i32` as params - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:59:15 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:63:15 | LL | takes_foo(()); | --------- ^^ trait has `()` and `i32` as params @@ -156,18 +156,18 @@ LL | takes_foo(()); = help: the trait `Foo` is not implemented for `()` = note: trait has `()` and `i32` as params help: this trait has no implementations, consider adding one - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:15:1 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:19:1 | LL | trait Foo {} | ^^^^^^^^^^^^ note: required by a bound in `takes_foo` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:54:22 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:58:22 | LL | fn takes_foo(_: impl Foo) {} | ^^^^^^^^ required by this bound in `takes_foo` warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:17:32 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:21:32 | LL | #[diagnostic::on_unimplemented = "Message"] | ^^^^^^^^^^^ invalid option found here @@ -176,7 +176,7 @@ LL | #[diagnostic::on_unimplemented = "Message"] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `(): Bar` is not satisfied - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:61:15 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:65:15 | LL | takes_bar(()); | --------- ^^ the trait `Bar` is not implemented for `()` @@ -185,13 +185,13 @@ LL | takes_bar(()); | = help: the trait `Bar` is implemented for `i32` note: required by a bound in `takes_bar` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:55:22 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:59:22 | LL | fn takes_bar(_: impl Bar) {} | ^^^ required by this bound in `takes_bar` warning: there is no parameter `from_desugaring` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -200,7 +200,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `direct` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -209,7 +209,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `cause` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -218,7 +218,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `integral` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -227,7 +227,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `integer` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -236,7 +236,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `float` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -245,7 +245,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `_Self` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -254,7 +254,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `crate_local` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -263,7 +263,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `Trait` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -272,7 +272,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `ItemContext` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -281,7 +281,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: {from_desugaring}{direct}{cause}{integral}{integer} - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:63:15 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:67:15 | LL | takes_baz(()); | --------- ^^ {float}{_Self}{crate_local}{Trait}{ItemContext} @@ -290,12 +290,12 @@ LL | takes_baz(()); | = help: the trait `Baz` is not implemented for `()` help: this trait has no implementations, consider adding one - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:52:1 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:56:1 | LL | trait Baz {} | ^^^^^^^^^ note: required by a bound in `takes_baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:56:22 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:60:22 | LL | fn takes_baz(_: impl Baz) {} | ^^^ required by this bound in `takes_baz` diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs index b4234066bb1..8328c10d2a0 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs @@ -1,3 +1,5 @@ +//@ reference: attributes.diagnostic.on_unimplemented.syntax +//@ reference: attributes.diagnostic.on_unimplemented.unknown-keys #[diagnostic::on_unimplemented(unsupported = "foo")] //~^WARN malformed `on_unimplemented` attribute //~|WARN malformed `on_unimplemented` attribute diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr index dc0c1948236..11263580b15 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr @@ -1,5 +1,5 @@ warning: `#[diagnostic::on_unimplemented]` can only be applied to trait definitions - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:6:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:8:1 | LL | #[diagnostic::on_unimplemented(message = "Baz")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[diagnostic::on_unimplemented(message = "Baz")] = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:1:32 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:3:32 | LL | #[diagnostic::on_unimplemented(unsupported = "foo")] | ^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -15,7 +15,7 @@ LL | #[diagnostic::on_unimplemented(unsupported = "foo")] = help: only `message`, `note` and `label` are allowed as options warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:10:50 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:12:50 | LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")] | ^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -23,7 +23,7 @@ LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")] = help: only `message`, `note` and `label` are allowed as options warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:15:50 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:17:50 | LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -31,7 +31,7 @@ LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = help: only `message`, `note` and `label` are allowed as options warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:20:32 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:22:32 | LL | #[diagnostic::on_unimplemented = "boom"] | ^^^^^^^^ invalid option found here @@ -39,7 +39,7 @@ LL | #[diagnostic::on_unimplemented = "boom"] = help: only `message`, `note` and `label` are allowed as options warning: missing options for `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:24:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:1 | LL | #[diagnostic::on_unimplemented] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -47,7 +47,7 @@ LL | #[diagnostic::on_unimplemented] = help: at least one of the `message`, `note` and `label` options are expected warning: there is no parameter `DoesNotExist` on trait `Test` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:29:32 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:32 | LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -55,7 +55,7 @@ LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")] = help: expect either a generic argument name or `{Self}` as format argument warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:1:32 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:3:32 | LL | #[diagnostic::on_unimplemented(unsupported = "foo")] | ^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -64,7 +64,7 @@ LL | #[diagnostic::on_unimplemented(unsupported = "foo")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `i32: Foo` is not satisfied - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:41:14 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:43:14 | LL | take_foo(1_i32); | -------- ^^^^^ the trait `Foo` is not implemented for `i32` @@ -72,18 +72,18 @@ LL | take_foo(1_i32); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:4:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:6:1 | LL | trait Foo {} | ^^^^^^^^^ note: required by a bound in `take_foo` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:34:21 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:36:21 | LL | fn take_foo(_: impl Foo) {} | ^^^ required by this bound in `take_foo` warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:10:50 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:12:50 | LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")] | ^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -92,7 +92,7 @@ LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Boom - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:43:14 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:45:14 | LL | take_baz(1_i32); | -------- ^^^^^ the trait `Baz` is not implemented for `i32` @@ -100,18 +100,18 @@ LL | take_baz(1_i32); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:13:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:15:1 | LL | trait Baz {} | ^^^^^^^^^ note: required by a bound in `take_baz` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:35:21 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:37:21 | LL | fn take_baz(_: impl Baz) {} | ^^^ required by this bound in `take_baz` warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:15:50 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:17:50 | LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -120,7 +120,7 @@ LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Boom - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:45:15 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:47:15 | LL | take_boom(1_i32); | --------- ^^^^^ the trait `Boom` is not implemented for `i32` @@ -128,18 +128,18 @@ LL | take_boom(1_i32); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:18:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:20:1 | LL | trait Boom {} | ^^^^^^^^^^ note: required by a bound in `take_boom` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:36:22 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:38:22 | LL | fn take_boom(_: impl Boom) {} | ^^^^ required by this bound in `take_boom` warning: missing options for `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:24:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:1 | LL | #[diagnostic::on_unimplemented] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -148,7 +148,7 @@ LL | #[diagnostic::on_unimplemented] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `i32: Whatever` is not satisfied - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:47:19 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:49:19 | LL | take_whatever(1_i32); | ------------- ^^^^^ the trait `Whatever` is not implemented for `i32` @@ -156,18 +156,18 @@ LL | take_whatever(1_i32); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:27:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:29:1 | LL | trait Whatever {} | ^^^^^^^^^^^^^^ note: required by a bound in `take_whatever` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:37:26 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:39:26 | LL | fn take_whatever(_: impl Whatever) {} | ^^^^^^^^ required by this bound in `take_whatever` warning: there is no parameter `DoesNotExist` on trait `Test` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:29:32 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:32 | LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -176,7 +176,7 @@ LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: {DoesNotExist} - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:49:15 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:51:15 | LL | take_test(()); | --------- ^^ the trait `Test` is not implemented for `()` @@ -184,12 +184,12 @@ LL | take_test(()); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:32:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:34:1 | LL | trait Test {} | ^^^^^^^^^^ note: required by a bound in `take_test` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:38:22 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:40:22 | LL | fn take_test(_: impl Test) {} | ^^^^ required by this bound in `take_test` diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.rs b/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.rs index 7eaff73dca1..dff209d4761 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.rs @@ -1,4 +1,5 @@ //@ aux-build:other.rs +//@ reference: attributes.diagnostic.on_unimplemented.intro extern crate other; diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.stderr index a9968538d0d..c0dd6d9628a 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.stderr @@ -1,5 +1,5 @@ error[E0277]: Message - --> $DIR/error_is_shown_in_downstream_crates.rs:10:14 + --> $DIR/error_is_shown_in_downstream_crates.rs:11:14 | LL | take_foo(()); | -------- ^^ label @@ -9,7 +9,7 @@ LL | take_foo(()); = help: the trait `Foo` is not implemented for `()` = note: Note note: required by a bound in `take_foo` - --> $DIR/error_is_shown_in_downstream_crates.rs:7:21 + --> $DIR/error_is_shown_in_downstream_crates.rs:8:21 | LL | fn take_foo(_: impl Foo) {} | ^^^ required by this bound in `take_foo` diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs index 5b25fb234bc..c638681173d 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs @@ -1,3 +1,5 @@ +//@ reference: attributes.diagnostic.on_unimplemented.repetition +//@ reference: attributes.diagnostic.on_unimplemented.syntax #[diagnostic::on_unimplemented( if(Self = "()"), //~^WARN malformed `on_unimplemented` attribute diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr index 56d125e20e5..e00846da77b 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr @@ -1,5 +1,5 @@ warning: malformed `on_unimplemented` attribute - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:2:5 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:4:5 | LL | if(Self = "()"), | ^^^^^^^^^^^^^^^ invalid option found here @@ -8,7 +8,7 @@ LL | if(Self = "()"), = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: `message` is ignored due to previous definition of `message` - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:8:32 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:10:32 | LL | message = "custom message", | -------------------------- `message` is first declared here @@ -17,7 +17,7 @@ LL | #[diagnostic::on_unimplemented(message = "fallback!!")] | ^^^^^^^^^^^^^^^^^^^^^^ `message` is already declared here warning: malformed `on_unimplemented` attribute - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:2:5 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:4:5 | LL | if(Self = "()"), | ^^^^^^^^^^^^^^^ invalid option found here @@ -26,7 +26,7 @@ LL | if(Self = "()"), = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: `message` is ignored due to previous definition of `message` - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:8:32 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:10:32 | LL | message = "custom message", | -------------------------- `message` is first declared here @@ -37,7 +37,7 @@ LL | #[diagnostic::on_unimplemented(message = "fallback!!")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: custom message - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:18:15 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:20:15 | LL | takes_foo(()); | --------- ^^ fallback label @@ -48,12 +48,12 @@ LL | takes_foo(()); = note: custom note = note: fallback note help: this trait has no implementations, consider adding one - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:13:1 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:15:1 | LL | trait Foo {} | ^^^^^^^^^ note: required by a bound in `takes_foo` - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:15:22 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:17:22 | LL | fn takes_foo(_: impl Foo) {} | ^^^ required by this bound in `takes_foo` diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.rs b/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.rs index a5982f6492c..dc0f850031e 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.rs @@ -1,3 +1,4 @@ +//@ reference: attributes.diagnostic.on_unimplemented.note-repetition #[diagnostic::on_unimplemented(message = "Foo", label = "Bar", note = "Baz", note = "Boom")] trait Foo {} diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.stderr index 93a0d0b3f41..6567269be3b 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.stderr @@ -1,5 +1,5 @@ error[E0277]: Foo - --> $DIR/multiple_notes.rs:12:15 + --> $DIR/multiple_notes.rs:13:15 | LL | takes_foo(()); | --------- ^^ Bar @@ -10,18 +10,18 @@ LL | takes_foo(()); = note: Baz = note: Boom help: this trait has no implementations, consider adding one - --> $DIR/multiple_notes.rs:2:1 + --> $DIR/multiple_notes.rs:3:1 | LL | trait Foo {} | ^^^^^^^^^ note: required by a bound in `takes_foo` - --> $DIR/multiple_notes.rs:8:22 + --> $DIR/multiple_notes.rs:9:22 | LL | fn takes_foo(_: impl Foo) {} | ^^^ required by this bound in `takes_foo` error[E0277]: Bar - --> $DIR/multiple_notes.rs:14:15 + --> $DIR/multiple_notes.rs:15:15 | LL | takes_bar(()); | --------- ^^ Foo @@ -32,12 +32,12 @@ LL | takes_bar(()); = note: Baz = note: Baz2 help: this trait has no implementations, consider adding one - --> $DIR/multiple_notes.rs:6:1 + --> $DIR/multiple_notes.rs:7:1 | LL | trait Bar {} | ^^^^^^^^^ note: required by a bound in `takes_bar` - --> $DIR/multiple_notes.rs:9:22 + --> $DIR/multiple_notes.rs:10:22 | LL | fn takes_bar(_: impl Bar) {} | ^^^ required by this bound in `takes_bar` diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.rs b/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.rs index 7ca03127759..e584077c643 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.rs @@ -1,3 +1,5 @@ +//@ reference: attributes.diagnostic.on_unimplemented.intro +//@ reference: attributes.diagnostic.on_unimplemented.keys #[diagnostic::on_unimplemented(message = "Foo", label = "Bar", note = "Baz")] trait Foo {} diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.stderr index 6b17f40c6dd..de57f7044bf 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.stderr @@ -1,5 +1,5 @@ error[E0277]: Foo - --> $DIR/on_unimplemented_simple.rs:7:15 + --> $DIR/on_unimplemented_simple.rs:9:15 | LL | takes_foo(()); | --------- ^^ Bar @@ -9,12 +9,12 @@ LL | takes_foo(()); = help: the trait `Foo` is not implemented for `()` = note: Baz help: this trait has no implementations, consider adding one - --> $DIR/on_unimplemented_simple.rs:2:1 + --> $DIR/on_unimplemented_simple.rs:4:1 | LL | trait Foo {} | ^^^^^^^^^ note: required by a bound in `takes_foo` - --> $DIR/on_unimplemented_simple.rs:4:22 + --> $DIR/on_unimplemented_simple.rs:6:22 | LL | fn takes_foo(_: impl Foo) {} | ^^^ required by this bound in `takes_foo` diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.rs b/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.rs index 8c0b8150417..d0eb608c40f 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.rs @@ -1,3 +1,4 @@ +//@ reference: attributes.diagnostic.on_unimplemented.repetition #[diagnostic::on_unimplemented( message = "first message", label = "first label", diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.stderr index 43ab6bf25a1..feafe2cee76 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.stderr @@ -1,5 +1,5 @@ warning: `message` is ignored due to previous definition of `message` - --> $DIR/report_warning_on_duplicated_options.rs:7:5 + --> $DIR/report_warning_on_duplicated_options.rs:8:5 | LL | message = "first message", | ------------------------- `message` is first declared here @@ -10,7 +10,7 @@ LL | message = "second message", = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: `label` is ignored due to previous definition of `label` - --> $DIR/report_warning_on_duplicated_options.rs:10:5 + --> $DIR/report_warning_on_duplicated_options.rs:11:5 | LL | label = "first label", | --------------------- `label` is first declared here @@ -19,7 +19,7 @@ LL | label = "second label", | ^^^^^^^^^^^^^^^^^^^^^^ `label` is already declared here warning: `message` is ignored due to previous definition of `message` - --> $DIR/report_warning_on_duplicated_options.rs:7:5 + --> $DIR/report_warning_on_duplicated_options.rs:8:5 | LL | message = "first message", | ------------------------- `message` is first declared here @@ -30,7 +30,7 @@ LL | message = "second message", = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: `label` is ignored due to previous definition of `label` - --> $DIR/report_warning_on_duplicated_options.rs:10:5 + --> $DIR/report_warning_on_duplicated_options.rs:11:5 | LL | label = "first label", | --------------------- `label` is first declared here @@ -41,7 +41,7 @@ LL | label = "second label", = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: first message - --> $DIR/report_warning_on_duplicated_options.rs:21:15 + --> $DIR/report_warning_on_duplicated_options.rs:22:15 | LL | takes_foo(()); | --------- ^^ first label @@ -52,12 +52,12 @@ LL | takes_foo(()); = note: custom note = note: second note help: this trait has no implementations, consider adding one - --> $DIR/report_warning_on_duplicated_options.rs:15:1 + --> $DIR/report_warning_on_duplicated_options.rs:16:1 | LL | trait Foo {} | ^^^^^^^^^ note: required by a bound in `takes_foo` - --> $DIR/report_warning_on_duplicated_options.rs:18:22 + --> $DIR/report_warning_on_duplicated_options.rs:19:22 | LL | fn takes_foo(_: impl Foo) {} | ^^^ required by this bound in `takes_foo` diff --git a/tests/ui/diagnostic_namespace/suggest_typos.rs b/tests/ui/diagnostic_namespace/suggest_typos.rs index b25f097a8ad..6fa4f800462 100644 --- a/tests/ui/diagnostic_namespace/suggest_typos.rs +++ b/tests/ui/diagnostic_namespace/suggest_typos.rs @@ -1,3 +1,4 @@ +//@ reference: attributes.diagnostic.namespace.unknown-invalid-syntax #![deny(unknown_or_malformed_diagnostic_attributes)] #[diagnostic::onunimplemented] diff --git a/tests/ui/diagnostic_namespace/suggest_typos.stderr b/tests/ui/diagnostic_namespace/suggest_typos.stderr index 307311258f2..ff4ee9717d4 100644 --- a/tests/ui/diagnostic_namespace/suggest_typos.stderr +++ b/tests/ui/diagnostic_namespace/suggest_typos.stderr @@ -1,11 +1,11 @@ error: unknown diagnostic attribute - --> $DIR/suggest_typos.rs:3:15 + --> $DIR/suggest_typos.rs:4:15 | LL | #[diagnostic::onunimplemented] | ^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/suggest_typos.rs:1:9 + --> $DIR/suggest_typos.rs:2:9 | LL | #![deny(unknown_or_malformed_diagnostic_attributes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | #[diagnostic::on_unimplemented] | ~~~~~~~~~~~~~~~~ error: unknown diagnostic attribute - --> $DIR/suggest_typos.rs:8:15 + --> $DIR/suggest_typos.rs:9:15 | LL | #[diagnostic::un_onimplemented] | ^^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | #[diagnostic::on_unimplemented] | ~~~~~~~~~~~~~~~~ error: unknown diagnostic attribute - --> $DIR/suggest_typos.rs:13:15 + --> $DIR/suggest_typos.rs:14:15 | LL | #[diagnostic::on_implemented] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/traits/negative-bounds/on-unimplemented.rs b/tests/ui/traits/negative-bounds/on-unimplemented.rs index 34582590861..5f2a705ed56 100644 --- a/tests/ui/traits/negative-bounds/on-unimplemented.rs +++ b/tests/ui/traits/negative-bounds/on-unimplemented.rs @@ -1,3 +1,5 @@ +//@ reference: attributes.diagnostic.on_unimplemented.intro + #![feature(negative_bounds)] #[diagnostic::on_unimplemented(message = "this ain't fooing")] diff --git a/tests/ui/traits/negative-bounds/on-unimplemented.stderr b/tests/ui/traits/negative-bounds/on-unimplemented.stderr index ed473d57917..8a295611010 100644 --- a/tests/ui/traits/negative-bounds/on-unimplemented.stderr +++ b/tests/ui/traits/negative-bounds/on-unimplemented.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `NotFoo: !Foo` is not satisfied - --> $DIR/on-unimplemented.rs:7:15 + --> $DIR/on-unimplemented.rs:9:15 | LL | fn hello() -> impl !Foo { | ^^^^^^^^^ the trait bound `NotFoo: !Foo` is not satisfied From 3adbc16385b3e581a094c66402d38cbbc6dcd1a2 Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Mon, 18 Nov 2024 12:00:42 -0500 Subject: [PATCH 26/44] Update books --- src/doc/edition-guide | 2 +- src/doc/nomicon | 2 +- src/doc/reference | 2 +- src/doc/rustc-dev-guide | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/edition-guide b/src/doc/edition-guide index 2d482e203eb..915f9b319c2 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit 2d482e203eb6d6e353814cf1415c5f94e590b9e0 +Subproject commit 915f9b319c2823f310430ecdecd86264a7870d7e diff --git a/src/doc/nomicon b/src/doc/nomicon index 456b904f791..eac89a3cbe6 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 456b904f791751892b01282fd2757904993c4c26 +Subproject commit eac89a3cbe6c4714e5029ae8b5a1c556fd4e8c42 diff --git a/src/doc/reference b/src/doc/reference index da0f6dad767..41ccb0e6478 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit da0f6dad767670da0e8cd5af8a7090db3272f626 +Subproject commit 41ccb0e6478305401dad92e8fd3d04a4304edb4c diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index 6a5accdaf10..b679e71c2d6 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit 6a5accdaf10255882b1e6c59dfe5f1c79ac95484 +Subproject commit b679e71c2d66c6fe13e06b99ac61773b866213f0 From 3ae8036f663eae1b040167f5e665171a9c5881f3 Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Mon, 18 Nov 2024 21:31:39 +0100 Subject: [PATCH 27/44] Update src/doc/rustc/src/platform-support/s390x-unknown-linux-gnu.md Co-authored-by: Josh Stone --- src/doc/rustc/src/platform-support/s390x-unknown-linux-gnu.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/rustc/src/platform-support/s390x-unknown-linux-gnu.md b/src/doc/rustc/src/platform-support/s390x-unknown-linux-gnu.md index b514a254e27..60e06c404c0 100644 --- a/src/doc/rustc/src/platform-support/s390x-unknown-linux-gnu.md +++ b/src/doc/rustc/src/platform-support/s390x-unknown-linux-gnu.md @@ -7,6 +7,7 @@ IBM z/Architecture (s390x) targets (including IBM Z and LinuxONE) running Linux. ## Target maintainers - Ulrich Weigand, , [@uweigand](https://github.com/uweigand) +- Josh Stone, , [@cuviper](https://github.com/cuviper) ## Requirements From 826d023561178fdc7bf961beba820fd460b0d89a Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 18 Nov 2024 13:37:53 -0700 Subject: [PATCH 28/44] rustdoc-search: add descriptive comments to bitmap class --- src/librustdoc/html/static/js/search.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index bee5327f6fc..9e5cf497211 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -988,6 +988,12 @@ class VlqHexDecoder { } class RoaringBitmap { constructor(str) { + // https://github.com/RoaringBitmap/RoaringFormatSpec + // + // Roaring bitmaps are used for flags that can be kept in their + // compressed form, even when loaded into memory. This decoder + // turns the containers into objects, but uses byte array + // slices of the original format for the data payload. const strdecoded = atob(str); const u8array = new Uint8Array(strdecoded.length); for (let j = 0; j < strdecoded.length; ++j) { @@ -1053,6 +1059,13 @@ class RoaringBitmap { contains(keyvalue) { const key = keyvalue >> 16; const value = keyvalue & 0xFFFF; + // Binary search algorithm copied from + // https://en.wikipedia.org/wiki/Binary_search#Procedure + // + // Format is required by specification to be sorted. + // Because keys are 16 bits and unique, length can't be + // bigger than 2**16, and because we have 32 bits of safe int, + // left + right can't overflow. let left = 0; let right = this.keys.length - 1; while (left <= right) { @@ -1076,6 +1089,11 @@ class RoaringBitmapRun { this.array = array; } contains(value) { + // Binary search algorithm copied from + // https://en.wikipedia.org/wiki/Binary_search#Procedure + // + // Since runcount is stored as 16 bits, left + right + // can't overflow. let left = 0; let right = this.runcount - 1; while (left <= right) { @@ -1100,6 +1118,11 @@ class RoaringBitmapArray { this.array = array; } contains(value) { + // Binary search algorithm copied from + // https://en.wikipedia.org/wiki/Binary_search#Procedure + // + // Since cardinality can't be higher than 4096, left + right + // cannot overflow. let left = 0; let right = this.cardinality - 1; while (left <= right) { From ed465f209038f108e85f78bf3f8870aab127012e Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Mon, 18 Nov 2024 23:20:41 +0000 Subject: [PATCH 29/44] rustdoc book: Move `--test-builder(--wrapper)?` docs to unstable section. --- src/doc/rustdoc/src/command-line-arguments.md | 29 ---------------- src/doc/rustdoc/src/unstable-features.md | 33 +++++++++++++++++++ 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/src/doc/rustdoc/src/command-line-arguments.md b/src/doc/rustdoc/src/command-line-arguments.md index f8fb5284472..1af5e2b0e1d 100644 --- a/src/doc/rustdoc/src/command-line-arguments.md +++ b/src/doc/rustdoc/src/command-line-arguments.md @@ -447,32 +447,3 @@ This flag is **deprecated** and **has no effect**. Rustdoc only supports Rust source code and Markdown input formats. If the file ends in `.md` or `.markdown`, `rustdoc` treats it as a Markdown file. Otherwise, it assumes that the input file is Rust. - -## `--test-builder`: `rustc`-like program to build tests - -Using this flag looks like this: - -```bash -$ rustdoc --test-builder /path/to/rustc src/lib.rs -``` - -Rustdoc will use the provided program to compile tests instead of the default `rustc` program from -the sysroot. - -## `--test-builder-wrapper`: wrap calls to the test builder - -Using this flag looks like this: - -```bash -$ rustdoc --test-builder-wrapper /path/to/rustc-wrapper src/lib.rs -$ rustdoc \ - --test-builder-wrapper rustc-wrapper1 \ - --test-builder-wrapper rustc-wrapper2 \ - --test-builder rustc \ - src/lib.rs -``` - -Similar to cargo `build.rustc-wrapper` option, this flag takes a `rustc` wrapper program. -The first argument to the program will be the test builder program. - -This flag can be passed multiple times to nest wrappers. diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index ebbe141b6f5..e9524c0b78d 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -627,3 +627,36 @@ add the `--scrape-tests` flag. This flag enables the generation of links in the source code pages which allow the reader to jump to a type definition. + +### `--test-builder`: `rustc`-like program to build tests + + * Tracking issue: [#102981](https://github.com/rust-lang/rust/issues/102981) + +Using this flag looks like this: + +```bash +$ rustdoc --test-builder /path/to/rustc src/lib.rs +``` + +Rustdoc will use the provided program to compile tests instead of the default `rustc` program from +the sysroot. + +### `--test-builder-wrapper`: wrap calls to the test builder + + * Tracking issue: [#102981](https://github.com/rust-lang/rust/issues/102981) + +Using this flag looks like this: + +```bash +$ rustdoc -Zunstable-options --test-builder-wrapper /path/to/rustc-wrapper src/lib.rs +$ rustdoc -Zunstable-options \ + --test-builder-wrapper rustc-wrapper1 \ + --test-builder-wrapper rustc-wrapper2 \ + --test-builder rustc \ + src/lib.rs +``` + +Similar to cargo `build.rustc-wrapper` option, this flag takes a `rustc` wrapper program. +The first argument to the program will be the test builder program. + +This flag can be passed multiple times to nest wrappers. From d20a310582ee57d0e1c2936dfc23c1b8b43e3ac2 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Mon, 18 Nov 2024 23:29:27 +0000 Subject: [PATCH 30/44] RELEASES.md: Don't document unstable `--test-build-wrapper` --- RELEASES.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 40ddba6dbc5..54465621b73 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -670,13 +670,6 @@ Cargo - [Support `target..rustdocflags` officially](https://github.com/rust-lang/cargo/pull/13197/) - [Stabilize global cache data tracking](https://github.com/rust-lang/cargo/pull/13492/) - - -Misc ----- - -- [rustdoc: add `--test-builder-wrapper` arg to support wrappers such as RUSTC_WRAPPER when building doctests](https://github.com/rust-lang/rust/pull/114651/) - Compatibility Notes From 4c8a23ab0dad20f37e3d132e9bb429690f2191d4 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 29 Oct 2024 09:23:57 +1100 Subject: [PATCH 31/44] Don't pass `universal_regions` unnecessarily. `TypeChecker` already has it in a field. --- compiler/rustc_borrowck/src/type_check/input_output.rs | 9 ++++----- compiler/rustc_borrowck/src/type_check/mod.rs | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 7effd5c5a68..bbe2b55d8c4 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -19,7 +19,7 @@ use tracing::{debug, instrument}; use super::{Locations, TypeChecker}; use crate::renumber::RegionCtxt; -use crate::universal_regions::{DefiningTy, UniversalRegions}; +use crate::universal_regions::DefiningTy; impl<'a, 'tcx> TypeChecker<'a, 'tcx> { /// Check explicit closure signature annotation, @@ -124,11 +124,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } - #[instrument(skip(self, body, universal_regions), level = "debug")] + #[instrument(skip(self, body), level = "debug")] pub(super) fn equate_inputs_and_outputs( &mut self, body: &Body<'tcx>, - universal_regions: &UniversalRegions<'tcx>, normalized_inputs_and_output: &[Ty<'tcx>], ) { let (&normalized_output_ty, normalized_input_tys) = @@ -161,7 +160,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if let Some(mir_yield_ty) = body.yield_ty() { let yield_span = body.local_decls[RETURN_PLACE].source_info.span; self.equate_normalized_input_or_output( - universal_regions.yield_ty.unwrap(), + self.universal_regions.yield_ty.unwrap(), mir_yield_ty, yield_span, ); @@ -170,7 +169,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if let Some(mir_resume_ty) = body.resume_ty() { let yield_span = body.local_decls[RETURN_PLACE].source_info.span; self.equate_normalized_input_or_output( - universal_regions.resume_ty.unwrap(), + self.universal_regions.resume_ty.unwrap(), mir_resume_ty, yield_span, ); diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index ac0219684d8..93c7050dbbe 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -180,7 +180,7 @@ pub(crate) fn type_check<'a, 'tcx>( verifier.visit_body(body); checker.typeck_mir(body); - checker.equate_inputs_and_outputs(body, &universal_regions, &normalized_inputs_and_output); + checker.equate_inputs_and_outputs(body, &normalized_inputs_and_output); checker.check_signature_annotation(body); liveness::generate(&mut checker, body, &elements, flow_inits, move_data); From 227ecc803fe79974c38e224fb49e13fe5feb378b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 29 Oct 2024 12:36:56 +1100 Subject: [PATCH 32/44] Make `TypeChecker::known_type_outlives_obligations` owned. This avoids the need to arena allocate it. `ConstraintConversion` needs some simple lifetime adjustments to allow this. --- .../rustc_borrowck/src/type_check/constraint_conversion.rs | 4 ++-- .../rustc_borrowck/src/type_check/free_region_relations.rs | 6 ++---- compiler/rustc_borrowck/src/type_check/mod.rs | 6 +++--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 6c86968389a..67915371b1f 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -37,7 +37,7 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> { region_bound_pairs: &'a RegionBoundPairs<'tcx>, implicit_region_bound: ty::Region<'tcx>, param_env: ty::ParamEnv<'tcx>, - known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>], + known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>], locations: Locations, span: Span, category: ConstraintCategory<'tcx>, @@ -52,7 +52,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { region_bound_pairs: &'a RegionBoundPairs<'tcx>, implicit_region_bound: ty::Region<'tcx>, param_env: ty::ParamEnv<'tcx>, - known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>], + known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>], locations: Locations, span: Span, category: ConstraintCategory<'tcx>, diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 8e1faf025e2..03b8020b373 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -46,7 +46,7 @@ type NormalizedInputsAndOutput<'tcx> = Vec>; pub(crate) struct CreateResult<'tcx> { pub(crate) universal_region_relations: Frozen>, pub(crate) region_bound_pairs: RegionBoundPairs<'tcx>, - pub(crate) known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>], + pub(crate) known_type_outlives_obligations: Vec>, pub(crate) normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>, } @@ -250,8 +250,6 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { known_type_outlives_obligations.push(outlives); } - let known_type_outlives_obligations = - self.infcx.tcx.arena.alloc_slice(&known_type_outlives_obligations); let unnormalized_input_output_tys = self .universal_regions @@ -340,7 +338,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { &self.region_bound_pairs, self.implicit_region_bound, param_env, - known_type_outlives_obligations, + &known_type_outlives_obligations, Locations::All(span), span, ConstraintCategory::Internal, diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 93c7050dbbe..b9bf052f002 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -844,7 +844,7 @@ struct TypeChecker<'a, 'tcx> { /// all of the promoted items. user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>, region_bound_pairs: &'a RegionBoundPairs<'tcx>, - known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>], + known_type_outlives_obligations: Vec>, implicit_region_bound: ty::Region<'tcx>, reported_errors: FxIndexSet<(Ty<'tcx>, Span)>, universal_regions: &'a UniversalRegions<'tcx>, @@ -1028,7 +1028,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.region_bound_pairs, self.implicit_region_bound, self.param_env, - self.known_type_outlives_obligations, + &self.known_type_outlives_obligations, locations, locations.span(self.body), category, @@ -2790,7 +2790,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.region_bound_pairs, self.implicit_region_bound, self.param_env, - self.known_type_outlives_obligations, + &self.known_type_outlives_obligations, locations, self.body.span, // irrelevant; will be overridden. ConstraintCategory::Boring, // same as above. From ed11fbe5dfc4abab912f5b6b80191730d9e64e61 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 29 Oct 2024 13:08:50 +1100 Subject: [PATCH 33/44] Make `TypeChecker::region_bound_pairs` owned. No reason not to be, and it's simpler that way. --- compiler/rustc_borrowck/src/type_check/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index b9bf052f002..bca57d645dd 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -162,7 +162,7 @@ pub(crate) fn type_check<'a, 'tcx>( last_span: body.span, body, user_type_annotations: &body.user_type_annotations, - region_bound_pairs: ®ion_bound_pairs, + region_bound_pairs, known_type_outlives_obligations, implicit_region_bound, reported_errors: Default::default(), @@ -843,7 +843,7 @@ struct TypeChecker<'a, 'tcx> { /// User type annotations are shared between the main MIR and the MIR of /// all of the promoted items. user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>, - region_bound_pairs: &'a RegionBoundPairs<'tcx>, + region_bound_pairs: RegionBoundPairs<'tcx>, known_type_outlives_obligations: Vec>, implicit_region_bound: ty::Region<'tcx>, reported_errors: FxIndexSet<(Ty<'tcx>, Span)>, @@ -1025,7 +1025,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { constraint_conversion::ConstraintConversion::new( self.infcx, self.universal_regions, - self.region_bound_pairs, + &self.region_bound_pairs, self.implicit_region_bound, self.param_env, &self.known_type_outlives_obligations, @@ -2787,7 +2787,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { constraint_conversion::ConstraintConversion::new( self.infcx, self.universal_regions, - self.region_bound_pairs, + &self.region_bound_pairs, self.implicit_region_bound, self.param_env, &self.known_type_outlives_obligations, From 952c6d5c965bace1b329537579c287de7569c621 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 29 Oct 2024 14:21:40 +1100 Subject: [PATCH 34/44] Clean up `UniversalRegions`. There is an `Rc` within `UniversalRegionRelations`, and yet the two types get passed around in tandem a lot. This commit makes `UniversalRegionRelations` own `UniversalRegions`, removing the `Rc` (which wasn't truly needed) and the tandem-passing. This requires adding a `universal_relations` method to `UniversalRegionRelations`, and renaming a couple of existing methods producing iterators to avoid a name clash. --- compiler/rustc_borrowck/src/nll.rs | 8 +--- compiler/rustc_borrowck/src/polonius/mod.rs | 15 ++---- .../src/region_infer/dump_mir.rs | 3 +- .../rustc_borrowck/src/region_infer/mod.rs | 48 +++++++++---------- .../src/region_infer/opaque_types.rs | 6 +-- .../src/region_infer/reverse_sccs.rs | 2 +- .../src/type_check/free_region_relations.rs | 10 ++-- .../src/type_check/liveness/mod.rs | 4 +- compiler/rustc_borrowck/src/type_check/mod.rs | 6 +-- .../rustc_borrowck/src/universal_regions.rs | 4 +- 10 files changed, 46 insertions(+), 60 deletions(-) diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index f76603d5679..2e5ca6959a8 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -96,8 +96,6 @@ pub(crate) fn compute_regions<'a, 'tcx>( let mut all_facts = (polonius_input || AllFacts::enabled(infcx.tcx)).then_some(AllFacts::default()); - let universal_regions = Rc::new(universal_regions); - let elements = Rc::new(DenseLocationMap::new(body)); // Run the MIR type-checker. @@ -107,7 +105,7 @@ pub(crate) fn compute_regions<'a, 'tcx>( param_env, body, promoted, - Rc::clone(&universal_regions), + universal_regions, location_table, borrow_set, &mut all_facts, @@ -140,11 +138,10 @@ pub(crate) fn compute_regions<'a, 'tcx>( body, borrow_set, move_data, - &universal_regions, &universal_region_relations, ); - if let Some(guar) = universal_regions.tainted_by_errors() { + if let Some(guar) = universal_region_relations.universal_regions.tainted_by_errors() { // Suppress unhelpful extra errors in `infer_opaque_types` by clearing out all // outlives bounds that we may end up checking. outlives_constraints = Default::default(); @@ -157,7 +154,6 @@ pub(crate) fn compute_regions<'a, 'tcx>( let mut regioncx = RegionInferenceContext::new( infcx, var_origins, - universal_regions, placeholder_indices, universal_region_relations, outlives_constraints, diff --git a/compiler/rustc_borrowck/src/polonius/mod.rs b/compiler/rustc_borrowck/src/polonius/mod.rs index 6862eb13427..9fccc00bdaf 100644 --- a/compiler/rustc_borrowck/src/polonius/mod.rs +++ b/compiler/rustc_borrowck/src/polonius/mod.rs @@ -12,7 +12,6 @@ use crate::borrow_set::BorrowSet; use crate::facts::{AllFacts, PoloniusRegionVid}; use crate::location::LocationTable; use crate::type_check::free_region_relations::UniversalRegionRelations; -use crate::universal_regions::UniversalRegions; mod loan_invalidations; mod loan_kills; @@ -32,7 +31,6 @@ pub(crate) fn emit_facts<'tcx>( body: &Body<'tcx>, borrow_set: &BorrowSet<'tcx>, move_data: &MoveData<'_>, - universal_regions: &UniversalRegions<'_>, universal_region_relations: &UniversalRegionRelations<'_>, ) { let Some(all_facts) = all_facts else { @@ -41,12 +39,7 @@ pub(crate) fn emit_facts<'tcx>( }; let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation"); emit_move_facts(all_facts, move_data, location_table, body); - emit_universal_region_facts( - all_facts, - borrow_set, - universal_regions, - universal_region_relations, - ); + emit_universal_region_facts(all_facts, borrow_set, universal_region_relations); emit_cfg_and_loan_kills_facts(all_facts, tcx, location_table, body, borrow_set); emit_loan_invalidations_facts(all_facts, tcx, location_table, body, borrow_set); } @@ -129,7 +122,6 @@ fn emit_move_facts( fn emit_universal_region_facts( all_facts: &mut AllFacts, borrow_set: &BorrowSet<'_>, - universal_regions: &UniversalRegions<'_>, universal_region_relations: &UniversalRegionRelations<'_>, ) { // 1: universal regions are modeled in Polonius as a pair: @@ -138,9 +130,10 @@ fn emit_universal_region_facts( // the `borrow_set`, their `BorrowIndex` are synthesized as the universal region index // added to the existing number of loans, as if they succeeded them in the set. // + let universal_regions = &universal_region_relations.universal_regions; all_facts .universal_region - .extend(universal_regions.universal_regions().map(PoloniusRegionVid::from)); + .extend(universal_regions.universal_regions_iter().map(PoloniusRegionVid::from)); let borrow_count = borrow_set.len(); debug!( "emit_universal_region_facts: polonius placeholders, num_universals={}, borrow_count={}", @@ -148,7 +141,7 @@ fn emit_universal_region_facts( borrow_count ); - for universal_region in universal_regions.universal_regions() { + for universal_region in universal_regions.universal_regions_iter() { let universal_region_idx = universal_region.index(); let placeholder_loan_idx = borrow_count + universal_region_idx; all_facts.placeholder.push((universal_region.into(), placeholder_loan_idx.into())); diff --git a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs index 6b8dd1a49e7..ef3d6309c19 100644 --- a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs +++ b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs @@ -23,7 +23,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { for region in self.regions() { if let NllRegionVariableOrigin::FreeRegion = self.definitions[region].origin { - let classification = self.universal_regions.region_classification(region).unwrap(); + let classification = + self.universal_regions().region_classification(region).unwrap(); let outlived_by = self.universal_region_relations.regions_outlived_by(region); writeln!( out, diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 7e317ea6554..01d259653b8 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -191,10 +191,6 @@ pub struct RegionInferenceContext<'tcx> { /// Type constraints that we check after solving. type_tests: Vec>, - /// Information about the universally quantified regions in scope - /// on this function. - universal_regions: Rc>, - /// Information about how the universally quantified regions in /// scope on this function relate to one another. universal_region_relations: Frozen>, @@ -399,7 +395,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(crate) fn new( infcx: &BorrowckInferCtxt<'tcx>, var_infos: VarInfos, - universal_regions: Rc>, placeholder_indices: Rc, universal_region_relations: Frozen>, mut outlives_constraints: OutlivesConstraintSet<'tcx>, @@ -409,7 +404,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { liveness_constraints: LivenessValues, elements: Rc, ) -> Self { - debug!("universal_regions: {:#?}", universal_regions); + let universal_regions = &universal_region_relations.universal_regions; + + debug!("universal_regions: {:#?}", universal_region_relations.universal_regions); debug!("outlives constraints: {:#?}", outlives_constraints); debug!("placeholder_indices: {:#?}", placeholder_indices); debug!("type tests: {:#?}", type_tests); @@ -453,7 +450,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { universe_causes, scc_values, type_tests, - universal_regions, universal_region_relations, }; @@ -518,7 +514,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn init_free_and_bound_regions(&mut self) { // Update the names (if any) // This iterator has unstable order but we collect it all into an IndexVec - for (external_name, variable) in self.universal_regions.named_universal_regions() { + for (external_name, variable) in + self.universal_region_relations.universal_regions.named_universal_regions_iter() + { debug!( "init_free_and_bound_regions: region {:?} has external name {:?}", variable, external_name @@ -562,7 +560,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// /// (Panics if `r` is not a registered universal region.) pub(crate) fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid { - self.universal_regions.to_region_vid(r) + self.universal_regions().to_region_vid(r) } /// Returns an iterator over all the outlives constraints. @@ -574,7 +572,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// Adds annotations for `#[rustc_regions]`; see `UniversalRegions::annotate`. pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diag<'_, ()>) { - self.universal_regions.annotate(tcx, err) + self.universal_regions().annotate(tcx, err) } /// Returns `true` if the region `r` contains the point `p`. @@ -686,7 +684,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { if outlives_requirements.is_empty() { (None, errors_buffer) } else { - let num_external_vids = self.universal_regions.num_global_and_external_regions(); + let num_external_vids = self.universal_regions().num_global_and_external_regions(); ( Some(ClosureRegionRequirements { num_external_vids, outlives_requirements }), errors_buffer, @@ -989,7 +987,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // always be in the root universe. if let Some(p) = self.scc_values.placeholders_contained_in(r_scc).next() { debug!("encountered placeholder in higher universe: {:?}, requiring 'static", p); - let static_r = self.universal_regions.fr_static; + let static_r = self.universal_regions().fr_static; propagated_outlives_requirements.push(ClosureOutlivesRequirement { subject, outlived_free_region: static_r, @@ -1032,8 +1030,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { // avoid potential non-determinism we approximate this by requiring // T: '1 and T: '2. for upper_bound in non_local_ub { - debug_assert!(self.universal_regions.is_universal_region(upper_bound)); - debug_assert!(!self.universal_regions.is_local_free_region(upper_bound)); + debug_assert!(self.universal_regions().is_universal_region(upper_bound)); + debug_assert!(!self.universal_regions().is_local_free_region(upper_bound)); let requirement = ClosureOutlivesRequirement { subject, @@ -1101,7 +1099,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // To do so, we simply check every candidate `u_r` for equality. self.scc_values .universal_regions_outlived_by(r_scc) - .filter(|&u_r| !self.universal_regions.is_local_free_region(u_r)) + .filter(|&u_r| !self.universal_regions().is_local_free_region(u_r)) .find(|&u_r| self.eval_equal(u_r, r_vid)) .map(|u_r| ty::Region::new_var(tcx, u_r)) // In case we could not find a named region to map to, @@ -1139,9 +1137,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Find the smallest universal region that contains all other // universal regions within `region`. - let mut lub = self.universal_regions.fr_fn_body; + let mut lub = self.universal_regions().fr_fn_body; let r_scc = self.constraint_sccs.scc(r); - let static_r = self.universal_regions.fr_static; + let static_r = self.universal_regions().fr_static; for ur in self.scc_values.universal_regions_outlived_by(r_scc) { let new_lub = self.universal_region_relations.postdom_upper_bound(lub, ur); debug!(?ur, ?lub, ?new_lub); @@ -1288,12 +1286,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!( "sup_region's value = {:?} universal={:?}", self.region_value_str(sup_region), - self.universal_regions.is_universal_region(sup_region), + self.universal_regions().is_universal_region(sup_region), ); debug!( "sub_region's value = {:?} universal={:?}", self.region_value_str(sub_region), - self.universal_regions.is_universal_region(sub_region), + self.universal_regions().is_universal_region(sub_region), ); let sub_region_scc = self.constraint_sccs.scc(sub_region); @@ -1308,7 +1306,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { by super `{sup_region_scc:?}`, promoting to static", ); - return self.eval_outlives(sup_region, self.universal_regions.fr_static); + return self.eval_outlives(sup_region, self.universal_regions().fr_static); } // Both the `sub_region` and `sup_region` consist of the union @@ -1332,7 +1330,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Now we have to compare all the points in the sub region and make // sure they exist in the sup region. - if self.universal_regions.is_universal_region(sup_region) { + if self.universal_regions().is_universal_region(sup_region) { // Micro-opt: universal regions contain all points. debug!("super is universal and hence contains all points"); return true; @@ -1736,7 +1734,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!("provides_universal_region(r={:?}, fr1={:?}, fr2={:?})", r, fr1, fr2); let result = { r == fr2 || { - fr2 == self.universal_regions.fr_static && self.cannot_name_placeholder(fr1, r) + fr2 == self.universal_regions().fr_static && self.cannot_name_placeholder(fr1, r) } }; debug!("provides_universal_region: result = {:?}", result); @@ -1837,7 +1835,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // A constraint like `'r: 'x` can come from our constraint // graph. - let fr_static = self.universal_regions.fr_static; + let fr_static = self.universal_regions().fr_static; let outgoing_edges_from_graph = self.constraint_graph.outgoing_edges(r, &self.constraints, fr_static); @@ -1952,7 +1950,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } pub(crate) fn universal_regions(&self) -> &UniversalRegions<'tcx> { - self.universal_regions.as_ref() + &self.universal_region_relations.universal_regions } /// Tries to find the best constraint to blame for the fact that @@ -2212,7 +2210,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// Access to the region graph, built from the outlives constraints. pub(crate) fn region_graph(&self) -> RegionGraph<'_, 'tcx, graph::Normal> { - self.constraint_graph.region_graph(&self.constraints, self.universal_regions.fr_static) + self.constraint_graph.region_graph(&self.constraints, self.universal_regions().fr_static) } /// Returns whether the given region is considered live at all points: whether it is a diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index d676ce59cfe..993d5d86333 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -74,7 +74,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!(?opaque_type_key, ?concrete_type); let mut arg_regions: Vec<(ty::RegionVid, ty::Region<'_>)> = - vec![(self.universal_regions.fr_static, infcx.tcx.lifetimes.re_static)]; + vec![(self.universal_regions().fr_static, infcx.tcx.lifetimes.re_static)]; let opaque_type_key = opaque_type_key.fold_captured_lifetime_args(infcx.tcx, |region| { @@ -88,12 +88,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { // the same name and simplifies subsequent handling. // See [rustc-dev-guide chapter] § "Semantic lifetime equality". NllRegionVariableOrigin::FreeRegion => self - .universal_regions .universal_regions() + .universal_regions_iter() .filter(|&ur| { // See [rustc-dev-guide chapter] § "Closure restrictions". !matches!( - self.universal_regions.region_classification(ur), + self.universal_regions().region_classification(ur), Some(RegionClassification::External) ) }) diff --git a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs index cfd5a92787e..d0cfe572d08 100644 --- a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs +++ b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs @@ -45,8 +45,8 @@ impl RegionInferenceContext<'_> { let graph = self.constraint_sccs.reverse(); let mut paired_scc_regions = self - .universal_regions .universal_regions() + .universal_regions_iter() .map(|region| (self.constraint_sccs.scc(region), region)) .collect::>(); paired_scc_regions.sort(); diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 03b8020b373..9d36e841a95 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -1,5 +1,3 @@ -use std::rc::Rc; - use rustc_data_structures::frozen::Frozen; use rustc_data_structures::transitive_relation::{TransitiveRelation, TransitiveRelationBuilder}; use rustc_hir::def::DefKind; @@ -23,7 +21,7 @@ use crate::universal_regions::UniversalRegions; #[derive(Debug)] pub(crate) struct UniversalRegionRelations<'tcx> { - universal_regions: Rc>, + pub(crate) universal_regions: UniversalRegions<'tcx>, /// Stores the outlives relations that are known to hold from the /// implied bounds, in-scope where-clauses, and that sort of @@ -54,7 +52,7 @@ pub(crate) fn create<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, implicit_region_bound: ty::Region<'tcx>, - universal_regions: Rc>, + universal_regions: UniversalRegions<'tcx>, constraints: &mut MirTypeckRegionConstraints<'tcx>, ) -> CreateResult<'tcx> { UniversalRegionRelationsBuilder { @@ -184,7 +182,7 @@ impl UniversalRegionRelations<'_> { struct UniversalRegionRelationsBuilder<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - universal_regions: Rc>, + universal_regions: UniversalRegions<'tcx>, implicit_region_bound: ty::Region<'tcx>, constraints: &'a mut MirTypeckRegionConstraints<'tcx>, @@ -220,7 +218,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { // region `'r`, all of which are provided by our caller let fr_static = self.universal_regions.fr_static; let fr_fn_body = self.universal_regions.fr_fn_body; - for fr in self.universal_regions.universal_regions() { + for fr in self.universal_regions.universal_regions_iter() { debug!("build: relating free region {:?} to itself and to 'static", fr); self.relate_universal_regions(fr, fr); self.relate_universal_regions(fr_static, fr); diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs index 84fb36dd32a..fd51cc94548 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs @@ -39,7 +39,7 @@ pub(super) fn generate<'a, 'tcx>( let free_regions = regions_that_outlive_free_regions( typeck.infcx.num_region_vars(), - typeck.universal_regions, + &typeck.universal_regions, &typeck.constraints.outlives_constraints, ); let (relevant_live_locals, boring_locals) = @@ -107,7 +107,7 @@ fn regions_that_outlive_free_regions<'tcx>( let rev_region_graph = rev_constraint_graph.region_graph(constraint_set, fr_static); // Stack for the depth-first search. Start out with all the free regions. - let mut stack: Vec<_> = universal_regions.universal_regions().collect(); + let mut stack: Vec<_> = universal_regions.universal_regions_iter().collect(); // Set of all free regions, plus anything that outlives them. Initially // just contains the free regions. diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index bca57d645dd..01397898958 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -121,7 +121,7 @@ pub(crate) fn type_check<'a, 'tcx>( param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, promoted: &IndexSlice>, - universal_regions: Rc>, + universal_regions: UniversalRegions<'tcx>, location_table: &LocationTable, borrow_set: &BorrowSet<'tcx>, all_facts: &mut Option, @@ -150,7 +150,7 @@ pub(crate) fn type_check<'a, 'tcx>( infcx, param_env, implicit_region_bound, - Rc::clone(&universal_regions), + universal_regions, &mut constraints, ); @@ -166,7 +166,7 @@ pub(crate) fn type_check<'a, 'tcx>( known_type_outlives_obligations, implicit_region_bound, reported_errors: Default::default(), - universal_regions: &universal_regions, + universal_regions: &universal_region_relations.universal_regions, location_table, all_facts, borrow_set, diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index b63144f560f..953c48706f3 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -312,7 +312,7 @@ impl<'tcx> UniversalRegions<'tcx> { /// Returns an iterator over all the RegionVids corresponding to /// universally quantified free regions. - pub(crate) fn universal_regions(&self) -> impl Iterator { + pub(crate) fn universal_regions_iter(&self) -> impl Iterator { (FIRST_GLOBAL_INDEX..self.num_universals).map(RegionVid::from_usize) } @@ -336,7 +336,7 @@ impl<'tcx> UniversalRegions<'tcx> { } /// Gets an iterator over all the early-bound regions that have names. - pub(crate) fn named_universal_regions<'s>( + pub(crate) fn named_universal_regions_iter<'s>( &'s self, ) -> impl Iterator, ty::RegionVid)> + 's { self.indices.indices.iter().map(|(&r, &v)| (r, v)) From 2709dc8a138c23390992ce53275113be6e2db208 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 29 Oct 2024 15:01:35 +1100 Subject: [PATCH 35/44] Compute `upvars` lazily. It can be computed from `tcx` on demand, instead of computing it eagerly and passing it around. --- compiler/rustc_borrowck/src/lib.rs | 1 - compiler/rustc_borrowck/src/nll.rs | 2 -- compiler/rustc_borrowck/src/type_check/mod.rs | 7 +++---- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 7eaf265d410..16bcb27aa5a 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -217,7 +217,6 @@ fn do_mir_borrowck<'tcx>( &mut flow_inits, &move_data, &borrow_set, - tcx.closure_captures(def), consumer_options, ); diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 2e5ca6959a8..e2bdb6746c3 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -85,7 +85,6 @@ pub(crate) fn compute_regions<'a, 'tcx>( flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, borrow_set: &BorrowSet<'tcx>, - upvars: &[&ty::CapturedPlace<'tcx>], consumer_options: Option, ) -> NllOutput<'tcx> { let is_polonius_legacy_enabled = infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled(); @@ -112,7 +111,6 @@ pub(crate) fn compute_regions<'a, 'tcx>( flow_inits, move_data, Rc::clone(&elements), - upvars, ); // Create the region inference context, taking ownership of the diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 01397898958..bbf11722658 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -128,7 +128,6 @@ pub(crate) fn type_check<'a, 'tcx>( flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, elements: Rc, - upvars: &[&ty::CapturedPlace<'tcx>], ) -> MirTypeckResults<'tcx> { let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body); let mut constraints = MirTypeckRegionConstraints { @@ -171,7 +170,6 @@ pub(crate) fn type_check<'a, 'tcx>( all_facts, borrow_set, constraints: &mut constraints, - upvars, }; checker.check_user_type_annotations(); @@ -852,7 +850,6 @@ struct TypeChecker<'a, 'tcx> { all_facts: &'a mut Option, borrow_set: &'a BorrowSet<'tcx>, constraints: &'a mut MirTypeckRegionConstraints<'tcx>, - upvars: &'a [&'a ty::CapturedPlace<'tcx>], } /// Holder struct for passing results from MIR typeck to the rest of the non-lexical regions @@ -2631,8 +2628,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); let tcx = self.infcx.tcx; + let def = self.body.source.def_id().expect_local(); + let upvars = tcx.closure_captures(def); let field = - path_utils::is_upvar_field_projection(tcx, self.upvars, borrowed_place.as_ref(), body); + path_utils::is_upvar_field_projection(tcx, upvars, borrowed_place.as_ref(), body); let category = if let Some(field) = field { ConstraintCategory::ClosureUpvar(field) } else { From fe3c49fe9a2249b5c0e4aaa2941ce82ad993eba4 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 29 Oct 2024 15:16:31 +1100 Subject: [PATCH 36/44] Inline and remove `TypeVerifier::new`. It has a single call site. --- compiler/rustc_borrowck/src/type_check/mod.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index bbf11722658..207066b5044 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -174,7 +174,7 @@ pub(crate) fn type_check<'a, 'tcx>( checker.check_user_type_annotations(); - let mut verifier = TypeVerifier::new(&mut checker, promoted); + let mut verifier = TypeVerifier { cx: &mut checker, promoted, last_span: body.span }; verifier.visit_body(body); checker.typeck_mir(body); @@ -465,13 +465,6 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { } impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { - fn new( - cx: &'a mut TypeChecker<'b, 'tcx>, - promoted: &'b IndexSlice>, - ) -> Self { - TypeVerifier { promoted, last_span: cx.body.span, cx } - } - fn body(&self) -> &Body<'tcx> { self.cx.body } From 801b150737f7e3e7dba84f97387732453f2e915f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 1 Nov 2024 09:19:03 +1100 Subject: [PATCH 37/44] Don't refcount `PlaceholderIndices`. It's not necessary. --- compiler/rustc_borrowck/src/nll.rs | 1 - compiler/rustc_borrowck/src/region_infer/mod.rs | 2 +- compiler/rustc_borrowck/src/region_infer/values.rs | 5 ++--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index e2bdb6746c3..24b822503ea 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -126,7 +126,6 @@ pub(crate) fn compute_regions<'a, 'tcx>( universe_causes, type_tests, } = constraints; - let placeholder_indices = Rc::new(placeholder_indices); // If requested, emit legacy polonius facts. polonius::emit_facts( diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 01d259653b8..e1b76878539 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -395,7 +395,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(crate) fn new( infcx: &BorrowckInferCtxt<'tcx>, var_infos: VarInfos, - placeholder_indices: Rc, + placeholder_indices: PlaceholderIndices, universal_region_relations: Frozen>, mut outlives_constraints: OutlivesConstraintSet<'tcx>, member_constraints_in: MemberConstraintSet<'tcx, RegionVid>, diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index 519edfafda5..a16bce63839 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -258,10 +258,9 @@ impl PlaceholderIndices { /// Here, the variable `'0` would contain the free region `'a`, /// because (since it is returned) it must live for at least `'a`. But /// it would also contain various points from within the function. -#[derive(Clone)] pub(crate) struct RegionValues { elements: Rc, - placeholder_indices: Rc, + placeholder_indices: PlaceholderIndices, points: SparseIntervalMatrix, free_regions: SparseBitMatrix, @@ -277,7 +276,7 @@ impl RegionValues { pub(crate) fn new( elements: Rc, num_universal_regions: usize, - placeholder_indices: Rc, + placeholder_indices: PlaceholderIndices, ) -> Self { let num_points = elements.num_points(); let num_placeholders = placeholder_indices.len(); From c9283f8fa9cd93100f9a566807bf08330813d993 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 1 Nov 2024 09:32:48 +1100 Subject: [PATCH 38/44] Pass `constraints` to `RegionInferenceContext::new`. Instead of destructuring it in advance and passing all the components individually. It's less code that way. --- compiler/rustc_borrowck/src/nll.rs | 28 ++------------- .../rustc_borrowck/src/region_infer/mod.rs | 34 +++++++++++++------ 2 files changed, 25 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 24b822503ea..97f51352eb3 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -30,7 +30,7 @@ use crate::diagnostics::RegionErrors; use crate::facts::{AllFacts, AllFactsExt, RustcFacts}; use crate::location::LocationTable; use crate::region_infer::RegionInferenceContext; -use crate::type_check::{self, MirTypeckRegionConstraints, MirTypeckResults}; +use crate::type_check::{self, MirTypeckResults}; use crate::universal_regions::UniversalRegions; use crate::{BorrowckInferCtxt, polonius, renumber}; @@ -117,15 +117,6 @@ pub(crate) fn compute_regions<'a, 'tcx>( // region inference data that was contained in `infcx`, and the // base constraints generated by the type-check. let var_origins = infcx.get_region_var_origins(); - let MirTypeckRegionConstraints { - placeholder_indices, - placeholder_index_to_region: _, - liveness_constraints, - mut outlives_constraints, - mut member_constraints, - universe_causes, - type_tests, - } = constraints; // If requested, emit legacy polonius facts. polonius::emit_facts( @@ -138,26 +129,11 @@ pub(crate) fn compute_regions<'a, 'tcx>( &universal_region_relations, ); - if let Some(guar) = universal_region_relations.universal_regions.tainted_by_errors() { - // Suppress unhelpful extra errors in `infer_opaque_types` by clearing out all - // outlives bounds that we may end up checking. - outlives_constraints = Default::default(); - member_constraints = Default::default(); - - // Also taint the entire scope. - infcx.set_tainted_by_errors(guar); - } - let mut regioncx = RegionInferenceContext::new( infcx, var_origins, - placeholder_indices, + constraints, universal_region_relations, - outlives_constraints, - member_constraints, - universe_causes, - type_tests, - liveness_constraints, elements, ); diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index e1b76878539..0ddb4e110e3 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -31,11 +31,9 @@ use crate::diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo}; use crate::member_constraints::{MemberConstraintSet, NllMemberConstraintIndex}; use crate::nll::PoloniusOutput; use crate::region_infer::reverse_sccs::ReverseSccGraph; -use crate::region_infer::values::{ - LivenessValues, PlaceholderIndices, RegionElement, RegionValues, ToElementIndex, -}; -use crate::type_check::Locations; +use crate::region_infer::values::{LivenessValues, RegionElement, RegionValues, ToElementIndex}; use crate::type_check::free_region_relations::UniversalRegionRelations; +use crate::type_check::{Locations, MirTypeckRegionConstraints}; use crate::universal_regions::UniversalRegions; mod dump_mir; @@ -395,22 +393,36 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(crate) fn new( infcx: &BorrowckInferCtxt<'tcx>, var_infos: VarInfos, - placeholder_indices: PlaceholderIndices, + constraints: MirTypeckRegionConstraints<'tcx>, universal_region_relations: Frozen>, - mut outlives_constraints: OutlivesConstraintSet<'tcx>, - member_constraints_in: MemberConstraintSet<'tcx, RegionVid>, - universe_causes: FxIndexMap>, - type_tests: Vec>, - liveness_constraints: LivenessValues, elements: Rc, ) -> Self { let universal_regions = &universal_region_relations.universal_regions; + let MirTypeckRegionConstraints { + placeholder_indices, + placeholder_index_to_region: _, + liveness_constraints, + mut outlives_constraints, + mut member_constraints, + universe_causes, + type_tests, + } = constraints; debug!("universal_regions: {:#?}", universal_region_relations.universal_regions); debug!("outlives constraints: {:#?}", outlives_constraints); debug!("placeholder_indices: {:#?}", placeholder_indices); debug!("type tests: {:#?}", type_tests); + if let Some(guar) = universal_region_relations.universal_regions.tainted_by_errors() { + // Suppress unhelpful extra errors in `infer_opaque_types` by clearing out all + // outlives bounds that we may end up checking. + outlives_constraints = Default::default(); + member_constraints = Default::default(); + + // Also taint the entire scope. + infcx.set_tainted_by_errors(guar); + } + // Create a RegionDefinition for each inference variable. let definitions: IndexVec<_, _> = var_infos .iter() @@ -435,7 +447,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } let member_constraints = - Rc::new(member_constraints_in.into_mapped(|r| constraint_sccs.scc(r))); + Rc::new(member_constraints.into_mapped(|r| constraint_sccs.scc(r))); let mut result = Self { var_infos, From af50fe407e5fedcae86435abdc285067829d6f58 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 1 Nov 2024 13:51:00 +1100 Subject: [PATCH 39/44] Put `param_env` into `infcx`. Because they get passed around together a lot. --- .../src/diagnostics/bound_region_errors.rs | 2 +- .../src/diagnostics/conflict_errors.rs | 43 ++++++++++--------- .../rustc_borrowck/src/diagnostics/mod.rs | 8 ++-- .../src/diagnostics/move_errors.rs | 2 +- .../src/diagnostics/mutability_errors.rs | 4 +- .../src/diagnostics/region_errors.rs | 6 +-- compiler/rustc_borrowck/src/lib.rs | 12 ++---- compiler/rustc_borrowck/src/nll.rs | 7 +-- .../src/type_check/canonical.rs | 12 +++--- .../src/type_check/free_region_relations.rs | 23 +++++----- .../src/type_check/liveness/trace.rs | 3 +- compiler/rustc_borrowck/src/type_check/mod.rs | 18 ++++---- .../src/type_check/relate_tys.rs | 2 +- .../rustc_borrowck/src/universal_regions.rs | 11 ++--- 14 files changed, 72 insertions(+), 81 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 0897d140d60..90d12ea8328 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -60,7 +60,7 @@ impl<'tcx> UniverseInfo<'tcx> { UniverseInfo::RelateTys { expected, found } => { let err = mbcx.infcx.err_ctxt().report_mismatched_types( &cause, - mbcx.param_env, + mbcx.infcx.param_env, expected, found, TypeError::RegionsPlaceholderMismatch, diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 129a30661d6..c11103af476 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -266,7 +266,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } } - if self.param_env.caller_bounds().iter().any(|c| { + if self.infcx.param_env.caller_bounds().iter().any(|c| { c.as_trait_clause().is_some_and(|pred| { pred.skip_binder().self_ty() == ty && self.infcx.tcx.is_fn_trait(pred.def_id()) }) @@ -682,13 +682,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // Normalize before comparing to see through type aliases and projections. let old_ty = ty::EarlyBinder::bind(ty).instantiate(tcx, generic_args); let new_ty = ty::EarlyBinder::bind(ty).instantiate(tcx, new_args); - if let Ok(old_ty) = - tcx.try_normalize_erasing_regions(self.infcx.typing_env(self.param_env), old_ty) - && let Ok(new_ty) = tcx.try_normalize_erasing_regions( - self.infcx.typing_env(self.param_env), - new_ty, - ) - { + if let Ok(old_ty) = tcx.try_normalize_erasing_regions( + self.infcx.typing_env(self.infcx.param_env), + old_ty, + ) && let Ok(new_ty) = tcx.try_normalize_erasing_regions( + self.infcx.typing_env(self.infcx.param_env), + new_ty, + ) { old_ty == new_ty } else { false @@ -707,15 +707,16 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // Test the callee's predicates, substituting in `ref_ty` for the moved argument type. clauses.instantiate(tcx, new_args).predicates.iter().all(|&(mut clause)| { // Normalize before testing to see through type aliases and projections. - if let Ok(normalized) = - tcx.try_normalize_erasing_regions(self.infcx.typing_env(self.param_env), clause) - { + if let Ok(normalized) = tcx.try_normalize_erasing_regions( + self.infcx.typing_env(self.infcx.param_env), + clause, + ) { clause = normalized; } self.infcx.predicate_must_hold_modulo_regions(&Obligation::new( tcx, ObligationCause::dummy(), - self.param_env, + self.infcx.param_env, clause, )) }) @@ -904,7 +905,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let ty = moved_place.ty(self.body, self.infcx.tcx).ty; debug!("ty: {:?}, kind: {:?}", ty, ty.kind()); - let Some(assign_value) = self.infcx.err_ctxt().ty_kind_suggestion(self.param_env, ty) + let Some(assign_value) = self.infcx.err_ctxt().ty_kind_suggestion(self.infcx.param_env, ty) else { return; }; @@ -1304,7 +1305,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { pub(crate) fn implements_clone(&self, ty: Ty<'tcx>) -> bool { let Some(clone_trait_def) = self.infcx.tcx.lang_items().clone_trait() else { return false }; self.infcx - .type_implements_trait(clone_trait_def, [ty], self.param_env) + .type_implements_trait(clone_trait_def, [ty], self.infcx.param_env) .must_apply_modulo_regions() } @@ -1437,7 +1438,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let ocx = ObligationCtxt::new_with_diagnostics(self.infcx); let cause = ObligationCause::misc(span, self.mir_def_id()); - ocx.register_bound(cause, self.param_env, ty, def_id); + ocx.register_bound(cause, self.infcx.param_env, ty, def_id); let errors = ocx.select_all_or_error(); // Only emit suggestion if all required predicates are on generic @@ -1957,7 +1958,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { && let ty::Ref(_, inner, _) = rcvr_ty.kind() && let inner = inner.peel_refs() && (Holds { ty: inner }).visit_ty(local_ty).is_break() - && let None = self.infcx.type_implements_trait_shallow(clone, inner, self.param_env) + && let None = + self.infcx.type_implements_trait_shallow(clone, inner, self.infcx.param_env) { err.span_label( span, @@ -1989,7 +1991,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let obligation = Obligation::new( self.infcx.tcx, ObligationCause::dummy(), - self.param_env, + self.infcx.param_env, trait_ref, ); self.infcx.err_ctxt().suggest_derive( @@ -3398,7 +3400,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) && self .infcx - .type_implements_trait(iter_trait, [return_ty], self.param_env) + .type_implements_trait(iter_trait, [return_ty], self.infcx.param_env) .must_apply_modulo_regions() { err.span_suggestion_hidden( @@ -3839,14 +3841,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| { Instance::try_resolve( tcx, - self.infcx.typing_env(self.param_env), + self.infcx.typing_env(self.infcx.param_env), deref_target, method_args, ) .transpose() }); if let Some(Ok(instance)) = deref_target { - let deref_target_ty = instance.ty(tcx, self.infcx.typing_env(self.param_env)); + let deref_target_ty = + instance.ty(tcx, self.infcx.typing_env(self.infcx.param_env)); err.note(format!("borrow occurs due to deref coercion to `{deref_target_ty}`")); err.span_note(tcx.def_span(instance.def_id()), "deref defined here"); } diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 6c63da819c7..bda96726738 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -864,7 +864,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let kind = call_kind( self.infcx.tcx, - self.infcx.typing_env(self.param_env), + self.infcx.typing_env(self.infcx.param_env), method_did, method_args, *fn_span, @@ -1160,7 +1160,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let suggest = match tcx.get_diagnostic_item(sym::IntoIterator) { Some(def_id) => type_known_to_meet_bound_modulo_regions( self.infcx, - self.param_env, + self.infcx.param_env, Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty), def_id, ), @@ -1224,7 +1224,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { BoundRegionConversionTime::FnCall, tcx.fn_sig(method_did).instantiate(tcx, method_args).input(0), ) - && self.infcx.can_eq(self.param_env, ty, self_ty) + && self.infcx.can_eq(self.infcx.param_env, ty, self_ty) { err.subdiagnostic(CaptureReasonSuggest::FreshReborrow { span: move_span.shrink_to_hi(), @@ -1258,7 +1258,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if let Some(errors) = self.infcx.type_implements_trait_shallow( clone_trait, ty, - self.param_env, + self.infcx.param_env, ) && !has_sugg { let msg = match &errors[..] { diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 15cc9c20ab7..4ba6b2e94ec 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -305,7 +305,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let Some(copy_trait_def) = self.infcx.tcx.lang_items().copy_trait() else { return false }; // This is only going to be ambiguous if there are incoherent impls, because otherwise // ambiguity should never happen in MIR. - self.infcx.type_implements_trait(copy_trait_def, [ty], self.param_env).may_apply() + self.infcx.type_implements_trait(copy_trait_def, [ty], self.infcx.param_env).may_apply() } fn report_cannot_move_from_static(&mut self, place: Place<'tcx>, span: Span) -> Diag<'infcx> { diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index d064bf098e4..c5ebf3c547e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1242,7 +1242,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { .type_implements_trait_shallow( clone_trait, ty.peel_refs(), - self.param_env, + self.infcx.param_env, ) .as_deref() { @@ -1279,7 +1279,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let obligation = traits::Obligation::new( self.infcx.tcx, traits::ObligationCause::dummy(), - self.param_env, + self.infcx.param_env, trait_ref, ); self.infcx.err_ctxt().suggest_derive( diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index d4660d8af43..c38747f6675 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -952,7 +952,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if let Ok(Some(instance)) = ty::Instance::try_resolve( tcx, - self.infcx.typing_env(self.param_env), + self.infcx.typing_env(self.infcx.param_env), *fn_did, self.infcx.resolve_vars_if_possible(args), ) { @@ -1091,7 +1091,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { peeled_ty = ref_ty; count += 1; } - if !self.infcx.type_is_copy_modulo_regions(self.param_env, peeled_ty) { + if !self.infcx.type_is_copy_modulo_regions(self.infcx.param_env, peeled_ty) { return; } @@ -1160,7 +1160,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let ocx = ObligationCtxt::new(&self.infcx); ocx.register_obligations(preds.iter().map(|(pred, span)| { trace!(?pred); - Obligation::misc(tcx, span, self.mir_def_id(), self.param_env, pred) + Obligation::misc(tcx, span, self.mir_def_id(), self.infcx.param_env, pred) })); if ocx.select_all_or_error().is_empty() && count > 0 { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 16bcb27aa5a..a6a554a54c0 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -140,7 +140,6 @@ fn do_mir_borrowck<'tcx>( ) -> (BorrowCheckResult<'tcx>, Option>>) { let def = input_body.source.def_id().expect_local(); let infcx = BorrowckInferCtxt::new(tcx, def); - let param_env = tcx.param_env(def); let mut local_names = IndexVec::from_elem(None, &input_body.local_decls); for var_debug_info in &input_body.var_debug_info { @@ -175,8 +174,7 @@ fn do_mir_borrowck<'tcx>( // will have a lifetime tied to the inference context. let mut body_owned = input_body.clone(); let mut promoted = input_promoted.to_owned(); - let free_regions = - nll::replace_regions_in_mir(&infcx, param_env, &mut body_owned, &mut promoted); + let free_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted); let body = &body_owned; // no further changes // FIXME(-Znext-solver): A bit dubious that we're only registering @@ -213,7 +211,6 @@ fn do_mir_borrowck<'tcx>( body, &promoted, &location_table, - param_env, &mut flow_inits, &move_data, &borrow_set, @@ -250,7 +247,6 @@ fn do_mir_borrowck<'tcx>( let promoted_body = &promoted[idx]; let mut promoted_mbcx = MirBorrowckCtxt { infcx: &infcx, - param_env, body: promoted_body, move_data: &move_data, location_table: &location_table, // no need to create a real one for the promoted, it is not used @@ -290,7 +286,6 @@ fn do_mir_borrowck<'tcx>( let mut mbcx = MirBorrowckCtxt { infcx: &infcx, - param_env, body, move_data: &move_data, location_table: &location_table, @@ -447,12 +442,14 @@ fn get_flow_results<'a, 'tcx>( pub(crate) struct BorrowckInferCtxt<'tcx> { pub(crate) infcx: InferCtxt<'tcx>, pub(crate) reg_var_to_origin: RefCell>, + pub(crate) param_env: ParamEnv<'tcx>, } impl<'tcx> BorrowckInferCtxt<'tcx> { pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { let infcx = tcx.infer_ctxt().build(TypingMode::analysis_in_body(tcx, def_id)); - BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()) } + let param_env = tcx.param_env(def_id); + BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()), param_env } } pub(crate) fn next_region_var( @@ -531,7 +528,6 @@ impl<'tcx> Deref for BorrowckInferCtxt<'tcx> { struct MirBorrowckCtxt<'a, 'infcx, 'tcx> { infcx: &'infcx BorrowckInferCtxt<'tcx>, - param_env: ParamEnv<'tcx>, body: &'a Body<'tcx>, move_data: &'a MoveData<'tcx>, diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 97f51352eb3..f435f21e2aa 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -50,10 +50,9 @@ pub(crate) struct NllOutput<'tcx> { /// Rewrites the regions in the MIR to use NLL variables, also scraping out the set of universal /// regions (e.g., region parameters) declared on the function. That set will need to be given to /// `compute_regions`. -#[instrument(skip(infcx, param_env, body, promoted), level = "debug")] +#[instrument(skip(infcx, body, promoted), level = "debug")] pub(crate) fn replace_regions_in_mir<'tcx>( infcx: &BorrowckInferCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, body: &mut Body<'tcx>, promoted: &mut IndexSlice>, ) -> UniversalRegions<'tcx> { @@ -62,7 +61,7 @@ pub(crate) fn replace_regions_in_mir<'tcx>( debug!(?def); // Compute named region information. This also renumbers the inputs/outputs. - let universal_regions = UniversalRegions::new(infcx, def, param_env); + let universal_regions = UniversalRegions::new(infcx, def); // Replace all remaining regions with fresh inference variables. renumber::renumber_mir(infcx, body, promoted); @@ -81,7 +80,6 @@ pub(crate) fn compute_regions<'a, 'tcx>( body: &Body<'tcx>, promoted: &IndexSlice>, location_table: &LocationTable, - param_env: ty::ParamEnv<'tcx>, flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, borrow_set: &BorrowSet<'tcx>, @@ -101,7 +99,6 @@ pub(crate) fn compute_regions<'a, 'tcx>( let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } = type_check::type_check( infcx, - param_env, body, promoted, universal_regions, diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index aee13ca8cd7..68b843d4d0d 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -132,7 +132,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { locations: Locations, category: ConstraintCategory<'tcx>, ) { - let param_env = self.param_env; + let param_env = self.infcx.param_env; let predicate = predicate.upcast(self.tcx()); let _: Result<_, ErrorGuaranteed> = self.fully_perform_op( locations, @@ -158,7 +158,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { where T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx, { - let param_env = self.param_env; + let param_env = self.infcx.param_env; let result: Result<_, ErrorGuaranteed> = self.fully_perform_op( location.to_locations(), category, @@ -176,7 +176,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let tcx = self.tcx(); if self.infcx.next_trait_solver() { let body = self.body; - let param_env = self.param_env; + let param_env = self.infcx.param_env; self.fully_perform_op( location.to_locations(), ConstraintCategory::Boring, @@ -223,7 +223,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let _: Result<_, ErrorGuaranteed> = self.fully_perform_op( Locations::All(span), ConstraintCategory::Boring, - self.param_env.and(type_op::ascribe_user_type::AscribeUserType { mir_ty, user_ty }), + self.infcx + .param_env + .and(type_op::ascribe_user_type::AscribeUserType { mir_ty, user_ty }), ); } @@ -250,7 +252,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let mir_ty = self.normalize(mir_ty, Locations::All(span)); let cause = ObligationCause::dummy_with_span(span); - let param_env = self.param_env; + let param_env = self.infcx.param_env; let _: Result<_, ErrorGuaranteed> = self.fully_perform_op( Locations::All(span), ConstraintCategory::Boring, diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 9d36e841a95..ea965eb6545 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -234,7 +234,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { // In the new solver, normalize the type-outlives obligation assumptions. if self.infcx.next_trait_solver() { match deeply_normalize( - self.infcx.at(&ObligationCause::misc(span, defining_ty_def_id), self.param_env), + self.infcx.at(&ObligationCause::misc(span, defining_ty_def_id), param_env), outlives, ) { Ok(normalized_outlives) => { @@ -274,15 +274,15 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { if let Some(c) = constraints_unnorm { constraints.push(c) } - let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = self - .param_env - .and(type_op::normalize::Normalize { value: ty }) - .fully_perform(self.infcx, span) - .unwrap_or_else(|guar| TypeOpOutput { - output: Ty::new_error(self.infcx.tcx, guar), - constraints: None, - error_info: None, - }); + let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = + param_env + .and(type_op::normalize::Normalize { value: ty }) + .fully_perform(self.infcx, span) + .unwrap_or_else(|guar| TypeOpOutput { + output: Ty::new_error(self.infcx.tcx, guar), + constraints: None, + error_info: None, + }); if let Some(c) = constraints_normalize { constraints.push(c) } @@ -312,8 +312,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { // Add implied bounds from impl header. if matches!(tcx.def_kind(defining_ty_def_id), DefKind::AssocFn | DefKind::AssocConst) { for &(ty, _) in tcx.assumed_wf_types(tcx.local_parent(defining_ty_def_id)) { - let result: Result<_, ErrorGuaranteed> = self - .param_env + let result: Result<_, ErrorGuaranteed> = param_env .and(type_op::normalize::Normalize { value: ty }) .fully_perform(self.infcx, span); let Ok(TypeOpOutput { output: norm_ty, constraints: c, .. }) = result else { diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 72f6a605279..7bdd1564aff 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -608,7 +608,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { value.visit_with(&mut for_liveness::FreeRegionsVisitor { tcx: typeck.tcx(), - param_env: typeck.param_env, + param_env: typeck.infcx.param_env, op: |r| { let live_region_vid = typeck.universal_regions.to_region_vid(r); @@ -621,6 +621,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,); match typeck + .infcx .param_env .and(DropckOutlives { dropped_ty }) .fully_perform(typeck.infcx, DUMMY_SP) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 207066b5044..d4d7ab21603 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -118,7 +118,6 @@ mod relate_tys; /// - `elements` -- MIR region map pub(crate) fn type_check<'a, 'tcx>( infcx: &BorrowckInferCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, promoted: &IndexSlice>, universal_regions: UniversalRegions<'tcx>, @@ -147,7 +146,7 @@ pub(crate) fn type_check<'a, 'tcx>( known_type_outlives_obligations, } = free_region_relations::create( infcx, - param_env, + infcx.param_env, implicit_region_bound, universal_regions, &mut constraints, @@ -157,7 +156,6 @@ pub(crate) fn type_check<'a, 'tcx>( let mut checker = TypeChecker { infcx, - param_env, last_span: body.span, body, user_type_annotations: &body.user_type_annotations, @@ -828,7 +826,6 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { /// NLL region checking. struct TypeChecker<'a, 'tcx> { infcx: &'a BorrowckInferCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, last_span: Span, body: &'a Body<'tcx>, /// User type annotations are shared between the main MIR and the MIR of @@ -1017,7 +1014,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.universal_regions, &self.region_bound_pairs, self.implicit_region_bound, - self.param_env, + self.infcx.param_env, &self.known_type_outlives_obligations, locations, locations.span(self.body), @@ -1517,9 +1514,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // The signature in this call can reference region variables, // so erase them before calling a query. let output_ty = self.tcx().erase_regions(sig.output()); - if !output_ty - .is_privately_uninhabited(self.tcx(), self.infcx.typing_env(self.param_env)) - { + if !output_ty.is_privately_uninhabited( + self.tcx(), + self.infcx.typing_env(self.infcx.param_env), + ) { span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig); } } @@ -1729,7 +1727,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // `Sized` bound in no way depends on precise regions, so this // shouldn't affect `is_sized`. let erased_ty = tcx.erase_regions(ty); - if !erased_ty.is_sized(tcx, self.param_env) { + if !erased_ty.is_sized(tcx, self.infcx.param_env) { // in current MIR construction, all non-control-flow rvalue // expressions evaluate through `as_temp` or `into` a return // slot or local, so to find all unsized rvalues it is enough @@ -2781,7 +2779,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.universal_regions, &self.region_bound_pairs, self.implicit_region_bound, - self.param_env, + self.infcx.param_env, &self.known_type_outlives_obligations, locations, self.body.span, // irrelevant; will be overridden. diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index e2f3e065bc0..752b2bf1a24 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -522,7 +522,7 @@ impl<'b, 'tcx> PredicateEmittingRelation> for NllTypeRelating<'_ } fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.type_checker.param_env + self.type_checker.infcx.param_env } fn register_predicates( diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 953c48706f3..f1c23aa26a9 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -248,12 +248,8 @@ impl<'tcx> UniversalRegions<'tcx> { /// MIR -- that is, all the regions that appear in the function's /// signature. This will also compute the relationships that are /// known between those regions. - pub(crate) fn new( - infcx: &BorrowckInferCtxt<'tcx>, - mir_def: LocalDefId, - param_env: ty::ParamEnv<'tcx>, - ) -> Self { - UniversalRegionsBuilder { infcx, mir_def, param_env }.build() + pub(crate) fn new(infcx: &BorrowckInferCtxt<'tcx>, mir_def: LocalDefId) -> Self { + UniversalRegionsBuilder { infcx, mir_def }.build() } /// Given a reference to a closure type, extracts all the values @@ -426,7 +422,6 @@ impl<'tcx> UniversalRegions<'tcx> { struct UniversalRegionsBuilder<'infcx, 'tcx> { infcx: &'infcx BorrowckInferCtxt<'tcx>, mir_def: LocalDefId, - param_env: ty::ParamEnv<'tcx>, } const FR: NllRegionVariableOrigin = NllRegionVariableOrigin::FreeRegion; @@ -435,7 +430,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { fn build(self) -> UniversalRegions<'tcx> { debug!("build(mir_def={:?})", self.mir_def); - let param_env = self.param_env; + let param_env = self.infcx.param_env; debug!("build: param_env={:?}", param_env); assert_eq!(FIRST_GLOBAL_INDEX, self.infcx.num_region_vars()); From 75108b60679ea622f57f06f636b3c02b3879eb53 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 5 Nov 2024 11:52:38 +1100 Subject: [PATCH 40/44] Pass `flow_inits` by value. It's simpler that way, and we don't need the explicit `drop`. --- compiler/rustc_borrowck/src/lib.rs | 8 ++------ compiler/rustc_borrowck/src/nll.rs | 2 +- compiler/rustc_borrowck/src/type_check/liveness/mod.rs | 2 +- compiler/rustc_borrowck/src/type_check/liveness/trace.rs | 4 ++-- compiler/rustc_borrowck/src/type_check/mod.rs | 2 +- 5 files changed, 7 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index a6a554a54c0..03f7b05d1e3 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -190,7 +190,7 @@ fn do_mir_borrowck<'tcx>( .iter_enumerated() .map(|(idx, body)| (idx, MoveData::gather_moves(body, tcx, |_| true))); - let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data) + let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data) .iterate_to_fixpoint(tcx, body, Some("borrowck")) .into_results_cursor(body); @@ -211,16 +211,12 @@ fn do_mir_borrowck<'tcx>( body, &promoted, &location_table, - &mut flow_inits, + flow_inits, &move_data, &borrow_set, consumer_options, ); - // `flow_inits` is large, so we drop it as soon as possible. This reduces - // peak memory usage significantly on some benchmarks. - drop(flow_inits); - // Dump MIR results into a file, if that is enabled. This let us // write unit-tests, as well as helping with debugging. nll::dump_nll_mir(&infcx, body, ®ioncx, &opt_closure_req, &borrow_set); diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index f435f21e2aa..be02e2f48df 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -80,7 +80,7 @@ pub(crate) fn compute_regions<'a, 'tcx>( body: &Body<'tcx>, promoted: &IndexSlice>, location_table: &LocationTable, - flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, + flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, borrow_set: &BorrowSet<'tcx>, consumer_options: Option, diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs index fd51cc94548..20d19a53752 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs @@ -32,7 +32,7 @@ pub(super) fn generate<'a, 'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, body: &Body<'tcx>, elements: &DenseLocationMap, - flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, + flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, ) { debug!("liveness::generate"); diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 7bdd1564aff..3ec36c16cbf 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -38,7 +38,7 @@ pub(super) fn trace<'a, 'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, body: &Body<'tcx>, elements: &DenseLocationMap, - flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, + flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, relevant_live_locals: Vec, boring_locals: Vec, @@ -113,7 +113,7 @@ struct LivenessContext<'a, 'typeck, 'b, 'tcx> { /// Results of dataflow tracking which variables (and paths) have been /// initialized. - flow_inits: &'a mut ResultsCursor<'b, 'tcx, MaybeInitializedPlaces<'b, 'tcx>>, + flow_inits: ResultsCursor<'b, 'tcx, MaybeInitializedPlaces<'b, 'tcx>>, /// Index indicating where each variable is assigned, used, or /// dropped. diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index d4d7ab21603..58a23b9e558 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -124,7 +124,7 @@ pub(crate) fn type_check<'a, 'tcx>( location_table: &LocationTable, borrow_set: &BorrowSet<'tcx>, all_facts: &mut Option, - flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, + flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, elements: Rc, ) -> MirTypeckResults<'tcx> { From 59e339f76658bd8bd55f7514c95ffb5f39c94227 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Tue, 19 Nov 2024 05:01:59 +0000 Subject: [PATCH 41/44] Introduce `min_generic_const_args` and directly represent paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Boxy UwU Co-authored-by: León Orell Valerian Liehr --- compiler/rustc_ast_lowering/src/lib.rs | 106 ++++++----- compiler/rustc_feature/src/unstable.rs | 2 + compiler/rustc_hir_analysis/src/collect.rs | 23 ++- .../src/collect/predicates_of.rs | 5 +- .../src/hir_ty_lowering/bounds.rs | 8 +- .../src/hir_ty_lowering/generics.rs | 19 +- .../src/hir_ty_lowering/mod.rs | 167 +++++++++++++++--- compiler/rustc_hir_analysis/src/lib.rs | 15 +- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 9 +- compiler/rustc_middle/src/ty/consts.rs | 104 +---------- compiler/rustc_middle/src/ty/context.rs | 6 +- compiler/rustc_middle/src/ty/mod.rs | 3 +- compiler/rustc_span/src/symbol.rs | 1 + src/librustdoc/clean/mod.rs | 15 +- tests/crashes/132985.rs | 17 ++ tests/crashes/auxiliary/aux132985.rs | 6 + .../auxiliary/xcrate-const-ctor-a.rs | 6 + .../using-static-as-const-arg.rs | 7 + .../ui/const-generics/xcrate-const-ctor-b.rs | 15 ++ .../feature-gate-min-generic-const-args.rs | 11 ++ ...feature-gate-min-generic-const-args.stderr | 11 ++ 21 files changed, 361 insertions(+), 195 deletions(-) create mode 100644 tests/crashes/132985.rs create mode 100644 tests/crashes/auxiliary/aux132985.rs create mode 100644 tests/ui/const-generics/auxiliary/xcrate-const-ctor-a.rs create mode 100644 tests/ui/const-generics/using-static-as-const-arg.rs create mode 100644 tests/ui/const-generics/xcrate-const-ctor-b.rs create mode 100644 tests/ui/feature-gates/feature-gate-min-generic-const-args.rs create mode 100644 tests/ui/feature-gates/feature-gate-min-generic-const-args.stderr diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index d53280751fc..0b2969a49ba 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2052,6 +2052,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } + /// Used when lowering a type argument that turned out to actually be a const argument. + /// + /// Only use for that purpose since otherwise it will create a duplicate def. #[instrument(level = "debug", skip(self))] fn lower_const_path_to_const_arg( &mut self, @@ -2060,51 +2063,58 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ty_id: NodeId, span: Span, ) -> &'hir hir::ConstArg<'hir> { - let ct_kind = match res { - Res::Def(DefKind::ConstParam, _) => { - let qpath = self.lower_qpath( - ty_id, - &None, - path, - ParamMode::Optional, - AllowReturnTypeNotation::No, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), - None, - ); - hir::ConstArgKind::Path(qpath) - } - _ => { - // Construct an AnonConst where the expr is the "ty"'s path. + let tcx = self.tcx; - let parent_def_id = self.current_def_id_parent; - let node_id = self.next_node_id(); - let span = self.lower_span(span); + // FIXME(min_generic_const_args): we only allow one-segment const paths for now + let ct_kind = if path.is_potential_trivial_const_arg() + && (tcx.features().min_generic_const_args() + || matches!(res, Res::Def(DefKind::ConstParam, _))) + { + let qpath = self.lower_qpath( + ty_id, + &None, + path, + ParamMode::Optional, + AllowReturnTypeNotation::No, + // FIXME(min_generic_const_args): update for `fn foo() -> Bar>` support + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + ); + hir::ConstArgKind::Path(qpath) + } else { + // Construct an AnonConst where the expr is the "ty"'s path. - // Add a definition for the in-band const def. - let def_id = - self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, span); - let hir_id = self.lower_node_id(node_id); + let parent_def_id = self.current_def_id_parent; + let node_id = self.next_node_id(); + let span = self.lower_span(span); - let path_expr = Expr { - id: ty_id, - kind: ExprKind::Path(None, path.clone()), + // Add a definition for the in-band const def. + // We're lowering a const argument that was originally thought to be a type argument, + // so the def collector didn't create the def ahead of time. That's why we have to do + // it here. + let def_id = + self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, span); + let hir_id = self.lower_node_id(node_id); + + let path_expr = Expr { + id: ty_id, + kind: ExprKind::Path(None, path.clone()), + span, + attrs: AttrVec::new(), + tokens: None, + }; + + let ct = self.with_new_scopes(span, |this| { + self.arena.alloc(hir::AnonConst { + def_id, + hir_id, + body: this.with_def_id_parent(def_id, |this| { + this.lower_const_body(path_expr.span, Some(&path_expr)) + }), span, - attrs: AttrVec::new(), - tokens: None, - }; - - let ct = self.with_new_scopes(span, |this| { - self.arena.alloc(hir::AnonConst { - def_id, - hir_id, - body: this.with_def_id_parent(def_id, |this| { - this.lower_const_body(path_expr.span, Some(&path_expr)) - }), - span, - }) - }); - hir::ConstArgKind::Anon(ct) - } + }) + }); + hir::ConstArgKind::Anon(ct) }; self.arena.alloc(hir::ConstArg { @@ -2122,6 +2132,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { #[instrument(level = "debug", skip(self))] fn lower_anon_const_to_const_arg_direct(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> { + let tcx = self.tcx; // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments // currently have to be wrapped in curly brackets, so it's necessary to special-case. let expr = if let ExprKind::Block(block, _) = &anon.value.kind @@ -2135,18 +2146,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; let maybe_res = self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res()); - debug!("res={:?}", maybe_res); - // FIXME(min_generic_const_args): for now we only lower params to ConstArgKind::Path - if let Some(res) = maybe_res - && let Res::Def(DefKind::ConstParam, _) = res - && let ExprKind::Path(qself, path) = &expr.kind + // FIXME(min_generic_const_args): we only allow one-segment const paths for now + if let ExprKind::Path(None, path) = &expr.kind + && path.is_potential_trivial_const_arg() + && (tcx.features().min_generic_const_args() + || matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _)))) { let qpath = self.lower_qpath( expr.id, - qself, + &None, path, ParamMode::Optional, AllowReturnTypeNotation::No, + // FIXME(min_generic_const_args): update for `fn foo() -> Bar>` support ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index a67a5776449..2acebebb419 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -529,6 +529,8 @@ declare_features! ( (unstable, macro_metavar_expr_concat, "1.81.0", Some(124225)), /// Allows `#[marker]` on certain traits allowing overlapping implementations. (unstable, marker_trait_attr, "1.30.0", Some(29864)), + /// Enables the generic const args MVP (only bare paths, not arbitrary computation). + (incomplete, min_generic_const_args, "CURRENT_RUSTC_VERSION", Some(132980)), /// A minimal, sound subset of specialization intended to be used by the /// standard library until the soundness issues with specialization /// are fixed. diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 63a0e7d31c3..1a925597c6c 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -46,7 +46,7 @@ use tracing::{debug, instrument}; use crate::check::intrinsic::intrinsic_operation_unsafety; use crate::errors; -use crate::hir_ty_lowering::{HirTyLowerer, RegionInferReason}; +use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason}; pub(crate) mod dump; mod generics_of; @@ -88,6 +88,7 @@ pub fn provide(providers: &mut Providers) { coroutine_for_closure, opaque_ty_origin, rendered_precise_capturing_args, + const_param_default, ..*providers }; } @@ -1790,3 +1791,23 @@ fn rendered_precise_capturing_args<'tcx>( _ => None, }) } + +fn const_param_default<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> ty::EarlyBinder<'tcx, Const<'tcx>> { + let default_ct = match tcx.hir_node_by_def_id(def_id) { + hir::Node::GenericParam(hir::GenericParam { + kind: hir::GenericParamKind::Const { default: Some(ct), .. }, + .. + }) => ct, + _ => span_bug!( + tcx.def_span(def_id), + "`const_param_default` expected a generic parameter with a constant" + ), + }; + let icx = ItemCtxt::new(tcx, def_id); + // FIXME(const_generics): investigate which places do and don't need const ty feeding + let ct = icx.lowerer().lower_const_arg(default_ct, FeedConstTy::No); + ty::EarlyBinder::bind(ct) +} diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 7ce12d48160..0f37d61beb0 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -223,11 +223,12 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen trace!(?predicates); } hir::GenericParamKind::Const { .. } => { + let param_def_id = param.def_id.to_def_id(); let ct_ty = tcx - .type_of(param.def_id.to_def_id()) + .type_of(param_def_id) .no_bound_vars() .expect("const parameters cannot be generic"); - let ct = icx.lowerer().lower_const_param(param.hir_id); + let ct = icx.lowerer().lower_const_param(param_def_id, param.hir_id); predicates .insert((ty::ClauseKind::ConstArgHasType(ct, ct_ty).upcast(tcx), param.span)); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 1cade402c54..6ebe1cedcaf 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -19,7 +19,9 @@ use tracing::{debug, instrument}; use super::errors::GenericsArgsErrExtend; use crate::bounds::Bounds; use crate::errors; -use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer, PredicateFilter, RegionInferReason}; +use crate::hir_ty_lowering::{ + AssocItemQSelf, FeedConstTy, HirTyLowerer, PredicateFilter, RegionInferReason, +}; impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Add a `Sized` bound to the `bounds` if appropriate. @@ -346,9 +348,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::AssocItemConstraintKind::Equality { term } => { let term = match term { hir::Term::Ty(ty) => self.lower_ty(ty).into(), - hir::Term::Const(ct) => { - ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::No).into() - } + hir::Term::Const(ct) => self.lower_const_arg(ct, FeedConstTy::No).into(), }; // Find any late-bound regions declared in `ty` that are not diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index 6e8a9ded4f3..ae1279d428c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -115,17 +115,22 @@ fn generic_arg_mismatch_err( } } (GenericArg::Const(cnst), GenericParamDefKind::Type { .. }) => { - // FIXME(min_generic_const_args): once ConstArgKind::Path is used for non-params too, - // this should match against that instead of ::Anon - if let hir::ConstArgKind::Anon(anon) = cnst.kind + if let hir::ConstArgKind::Path(qpath) = cnst.kind + && let rustc_hir::QPath::Resolved(_, path) = qpath + && let Res::Def(DefKind::Fn { .. }, id) = path.res + { + err.help(format!("`{}` is a function item, not a type", tcx.item_name(id))); + err.help("function item types cannot be named directly"); + } else if let hir::ConstArgKind::Anon(anon) = cnst.kind && let body = tcx.hir().body(anon.body) && let rustc_hir::ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body.value.kind + && let Res::Def(DefKind::Fn { .. }, id) = path.res { - if let Res::Def(DefKind::Fn { .. }, id) = path.res { - err.help(format!("`{}` is a function item, not a type", tcx.item_name(id))); - err.help("function item types cannot be named directly"); - } + // FIXME(min_generic_const_args): this branch is dead once new const path lowering + // (for single-segment paths) is no longer gated + err.help(format!("`{}` is a function item, not a type", tcx.item_name(id))); + err.help("function item types cannot be named directly"); } } _ => {} diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index ed39708981b..f7035531e88 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -30,7 +30,7 @@ use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, struct_span_code_err, }; use rustc_hir as hir; -use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; +use rustc_hir::def::{CtorKind, CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{GenericArg, GenericArgs, HirId}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; @@ -217,6 +217,23 @@ impl AssocItemQSelf { } } +/// In some cases, [`hir::ConstArg`]s that are being used in the type system +/// through const generics need to have their type "fed" to them +/// using the query system. +/// +/// Use this enum with [`Const::from_const_arg`] to instruct it with the +/// desired behavior. +#[derive(Debug, Clone, Copy)] +pub enum FeedConstTy { + /// Feed the type. + /// + /// The `DefId` belongs to the const param that we are supplying + /// this (anon) const arg to. + Param(DefId), + /// Don't feed the type. + No, +} + /// New-typed boolean indicating whether explicit late-bound lifetimes /// are present in a set of generic arguments. /// @@ -500,8 +517,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { handle_ty_args(has_default, &inf.to_ty()) } (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => { - ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::Param(param.def_id)) - .into() + self.lowerer.lower_const_arg(ct, FeedConstTy::Param(param.def_id)).into() } (&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { self.lowerer.ct_infer(Some(param), inf.span).into() @@ -979,8 +995,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let term: ty::Term<'_> = match term { hir::Term::Ty(ty) => self.lower_ty(ty).into(), hir::Term::Const(ct) => { - ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::No) - .into() + self.lower_const_arg(ct, FeedConstTy::No).into() } }; // FIXME(#97583): This isn't syntactically well-formed! @@ -2025,23 +2040,138 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// /// Early-bound const parameters get lowered to [`ty::ConstKind::Param`] /// and late-bound ones to [`ty::ConstKind::Bound`]. - pub(crate) fn lower_const_param(&self, hir_id: HirId) -> Const<'tcx> { + pub(crate) fn lower_const_param(&self, param_def_id: DefId, path_hir_id: HirId) -> Const<'tcx> { let tcx = self.tcx(); - match tcx.named_bound_var(hir_id) { - Some(rbv::ResolvedArg::EarlyBound(def_id)) => { + + match tcx.named_bound_var(path_hir_id) { + Some(rbv::ResolvedArg::EarlyBound(_)) => { // Find the name and index of the const parameter by indexing the generics of // the parent item and construct a `ParamConst`. - let item_def_id = tcx.local_parent(def_id); + let item_def_id = tcx.parent(param_def_id); let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&def_id.to_def_id()]; - let name = tcx.item_name(def_id.to_def_id()); + let index = generics.param_def_id_to_index[¶m_def_id]; + let name = tcx.item_name(param_def_id); ty::Const::new_param(tcx, ty::ParamConst::new(index, name)) } Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => { ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index)) } Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar), - arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", hir_id), + arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", path_hir_id), + } + } + + /// Convert a [`hir::ConstArg`] to a [`ty::Const`](Const). + #[instrument(skip(self), level = "debug")] + pub fn lower_const_arg( + &self, + const_arg: &hir::ConstArg<'tcx>, + feed: FeedConstTy, + ) -> Const<'tcx> { + let tcx = self.tcx(); + + if let FeedConstTy::Param(param_def_id) = feed + && let hir::ConstArgKind::Anon(anon) = &const_arg.kind + { + tcx.feed_anon_const_type(anon.def_id, tcx.type_of(param_def_id)); + } + + let hir_id = const_arg.hir_id; + match const_arg.kind { + hir::ConstArgKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { + debug!(?maybe_qself, ?path); + let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); + self.lower_const_path_resolved(opt_self_ty, path, hir_id) + } + hir::ConstArgKind::Path(qpath) => ty::Const::new_error_with_message( + tcx, + qpath.span(), + format!("Const::lower_const_arg: invalid qpath {qpath:?}"), + ), + hir::ConstArgKind::Anon(anon) => Const::from_anon_const(tcx, anon.def_id), + } + } + + fn lower_const_path_resolved( + &self, + opt_self_ty: Option>, + path: &hir::Path<'tcx>, + hir_id: HirId, + ) -> Const<'tcx> { + let tcx = self.tcx(); + let span = path.span; + match path.res { + Res::Def(DefKind::ConstParam, def_id) => { + assert_eq!(opt_self_ty, None); + let _ = self.prohibit_generic_args( + path.segments.iter(), + GenericsArgsErrExtend::Param(def_id), + ); + self.lower_const_param(def_id, hir_id) + } + Res::Def(DefKind::Const | DefKind::Ctor(_, CtorKind::Const), did) => { + assert_eq!(opt_self_ty, None); + let _ = self.prohibit_generic_args( + path.segments.split_last().unwrap().1.iter(), + GenericsArgsErrExtend::None, + ); + let args = self.lower_generic_args_of_path_segment( + span, + did, + path.segments.last().unwrap(), + ); + ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(did, args)) + } + Res::Def(DefKind::Static { .. }, _) => { + span_bug!(span, "use of bare `static` ConstArgKind::Path's not yet supported") + } + // FIXME(const_generics): create real const to allow fn items as const paths + Res::Def(DefKind::Fn | DefKind::AssocFn, _) => ty::Const::new_error_with_message( + tcx, + span, + "fn items cannot be used as const args", + ), + + // Exhaustive match to be clear about what exactly we're considering to be + // an invalid Res for a const path. + Res::Def( + DefKind::Mod + | DefKind::Enum + | DefKind::Variant + | DefKind::Ctor(CtorOf::Variant, CtorKind::Fn) + | DefKind::Struct + | DefKind::Ctor(CtorOf::Struct, CtorKind::Fn) + | DefKind::OpaqueTy + | DefKind::TyAlias + | DefKind::TraitAlias + | DefKind::AssocTy + | DefKind::Union + | DefKind::Trait + | DefKind::ForeignTy + | DefKind::AssocConst + | DefKind::TyParam + | DefKind::Macro(_) + | DefKind::LifetimeParam + | DefKind::Use + | DefKind::ForeignMod + | DefKind::AnonConst + | DefKind::InlineConst + | DefKind::Field + | DefKind::Impl { .. } + | DefKind::Closure + | DefKind::ExternCrate + | DefKind::GlobalAsm + | DefKind::SyntheticCoroutineBody, + _, + ) + | Res::PrimTy(_) + | Res::SelfTyParam { .. } + | Res::SelfTyAlias { .. } + | Res::SelfCtor(_) + | Res::Local(_) + | Res::ToolMod + | Res::NonMacroAttr(_) + | Res::Err => Const::new_error_with_message(tcx, span, "invalid Res for const path"), } } @@ -2053,14 +2183,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - /// Lower a type from the HIR to our internal notion of a type given some extra data for diagnostics. - /// - /// Extra diagnostic data: - /// - /// 1. `borrowed`: Whether trait object types are borrowed like in `&dyn Trait`. - /// Used to avoid emitting redundant errors. - /// 2. `in_path`: Whether the type appears inside of a path. - /// Used to provide correct diagnostics for bare trait object types. + /// Lower a type from the HIR to our internal notion of a type. #[instrument(level = "debug", skip(self), ret)] pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { let tcx = self.tcx(); @@ -2189,7 +2312,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let length = match length { hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span), hir::ArrayLen::Body(constant) => { - ty::Const::from_const_arg(tcx, constant, ty::FeedConstTy::No) + self.lower_const_arg(constant, FeedConstTy::No) } }; @@ -2247,7 +2370,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .type_of(def_id) .no_bound_vars() .expect("const parameter types cannot be generic"); - let ct = self.lower_const_param(expr.hir_id); + let ct = self.lower_const_param(def_id, expr.hir_id); (ct, ty) } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 5830636c6e8..564e45c677d 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -97,12 +97,14 @@ use rustc_hir::def::DefKind; use rustc_middle::middle; use rustc_middle::mir::interpret::GlobalId; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Const, Ty, TyCtxt}; use rustc_session::parse::feature_err; use rustc_span::Span; use rustc_span::symbol::sym; use rustc_trait_selection::traits; +use self::hir_ty_lowering::{FeedConstTy, HirTyLowerer}; + rustc_fluent_macro::fluent_messages! { "../messages.ftl" } fn require_c_abi_if_c_variadic( @@ -226,3 +228,14 @@ pub fn lower_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { let env_def_id = tcx.hir().get_parent_item(hir_ty.hir_id); collect::ItemCtxt::new(tcx, env_def_id.def_id).lower_ty(hir_ty) } + +/// This is for rustdoc. +// FIXME(const_generics): having special methods for rustdoc in `rustc_hir_analysis` is cursed +pub fn lower_const_arg_for_rustdoc<'tcx>( + tcx: TyCtxt<'tcx>, + hir_ct: &hir::ConstArg<'tcx>, + feed: FeedConstTy, +) -> Const<'tcx> { + let env_def_id = tcx.hir().get_parent_item(hir_ct.hir_id); + collect::ItemCtxt::new(tcx, env_def_id.def_id).lowerer().lower_const_arg(hir_ct, feed) +} diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index f0738491609..ce6ce0381a9 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -14,8 +14,8 @@ use rustc_hir_analysis::hir_ty_lowering::generics::{ check_generic_arg_count_for_call, lower_generic_args, }; use rustc_hir_analysis::hir_ty_lowering::{ - ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgsLowerer, - GenericPathSegment, HirTyLowerer, IsMethodCall, RegionInferReason, + ExplicitLateBound, FeedConstTy, GenericArgCountMismatch, GenericArgCountResult, + GenericArgsLowerer, GenericPathSegment, HirTyLowerer, IsMethodCall, RegionInferReason, }; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::{DefineOpaqueTypes, InferResult}; @@ -491,7 +491,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span), hir::ArrayLen::Body(const_arg) => { let span = const_arg.span(); - let c = ty::Const::from_const_arg(self.tcx, const_arg, ty::FeedConstTy::No); + let c = self.lowerer().lower_const_arg(const_arg, FeedConstTy::No); self.register_wf_obligation(c.into(), span, ObligationCauseCode::WellFormed(None)); self.normalize(span, c) } @@ -503,8 +503,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { const_arg: &'tcx hir::ConstArg<'tcx>, param_def_id: DefId, ) -> ty::Const<'tcx> { - let ct = - ty::Const::from_const_arg(self.tcx, const_arg, ty::FeedConstTy::Param(param_def_id)); + let ct = self.lowerer().lower_const_arg(const_arg, FeedConstTy::Param(param_def_id)); self.register_wf_obligation( ct.into(), self.tcx.hir().span(const_arg.hir_id), diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 3bd09fc91c6..d853edb34c9 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -1,13 +1,14 @@ +use std::borrow::Cow; + use rustc_data_structures::intern::Interned; use rustc_error_messages::MultiSpan; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{self as hir, HirId}; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::{self as hir}; use rustc_macros::HashStable; use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo}; use tracing::{debug, instrument}; -use crate::middle::resolve_bound_vars as rbv; use crate::mir::interpret::{LitToConstInput, Scalar}; use crate::ty::{self, GenericArgs, Ty, TyCtxt, TypeVisitableExt}; @@ -142,7 +143,7 @@ impl<'tcx> Const<'tcx> { pub fn new_error_with_message>( tcx: TyCtxt<'tcx>, span: S, - msg: &'static str, + msg: impl Into>, ) -> Const<'tcx> { let reported = tcx.dcx().span_delayed_bug(span, msg); Const::new_error(tcx, reported) @@ -183,46 +184,8 @@ impl<'tcx> rustc_type_ir::inherent::Const> for Const<'tcx> { } } -/// In some cases, [`hir::ConstArg`]s that are being used in the type system -/// through const generics need to have their type "fed" to them -/// using the query system. -/// -/// Use this enum with [`Const::from_const_arg`] to instruct it with the -/// desired behavior. -#[derive(Debug, Clone, Copy)] -pub enum FeedConstTy { - /// Feed the type. - /// - /// The `DefId` belongs to the const param that we are supplying - /// this (anon) const arg to. - Param(DefId), - /// Don't feed the type. - No, -} - impl<'tcx> Const<'tcx> { - /// Convert a [`hir::ConstArg`] to a [`ty::Const`](Self). - #[instrument(skip(tcx), level = "debug")] - pub fn from_const_arg( - tcx: TyCtxt<'tcx>, - const_arg: &'tcx hir::ConstArg<'tcx>, - feed: FeedConstTy, - ) -> Self { - if let FeedConstTy::Param(param_def_id) = feed - && let hir::ConstArgKind::Anon(anon) = &const_arg.kind - { - tcx.feed_anon_const_type(anon.def_id, tcx.type_of(param_def_id)); - } - - match const_arg.kind { - hir::ConstArgKind::Path(qpath) => { - // FIXME(min_generic_const_args): for now only params are lowered to ConstArgKind::Path - Self::from_param(tcx, qpath, const_arg.hir_id) - } - hir::ConstArgKind::Anon(anon) => Self::from_anon_const(tcx, anon.def_id), - } - } - + // FIXME: move this and try_from_lit to hir_ty_lowering like lower_const_arg/from_const_arg /// Literals and const generic parameters are eagerly converted to a constant, everything else /// becomes `Unevaluated`. #[instrument(skip(tcx), level = "debug")] @@ -240,7 +203,7 @@ impl<'tcx> Const<'tcx> { let ty = tcx.type_of(def).no_bound_vars().expect("const parameter types cannot be generic"); - match Self::try_from_lit_or_param(tcx, ty, expr) { + match Self::try_from_lit(tcx, ty, expr) { Some(v) => v, None => ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst { def: def.to_def_id(), @@ -249,40 +212,8 @@ impl<'tcx> Const<'tcx> { } } - /// Lower a const param to a [`Const`]. - /// - /// IMPORTANT: `qpath` must be a const param, otherwise this will panic - fn from_param(tcx: TyCtxt<'tcx>, qpath: hir::QPath<'tcx>, hir_id: HirId) -> Self { - let hir::QPath::Resolved(_, &hir::Path { res: Res::Def(DefKind::ConstParam, def_id), .. }) = - qpath - else { - span_bug!(qpath.span(), "non-param {qpath:?} passed to Const::from_param") - }; - - match tcx.named_bound_var(hir_id) { - Some(rbv::ResolvedArg::EarlyBound(_)) => { - // Find the name and index of the const parameter by indexing the generics of - // the parent item and construct a `ParamConst`. - let item_def_id = tcx.parent(def_id); - let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&def_id]; - let name = tcx.item_name(def_id); - ty::Const::new_param(tcx, ty::ParamConst::new(index, name)) - } - Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => { - ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index)) - } - Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar), - arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", hir_id), - } - } - #[instrument(skip(tcx), level = "debug")] - fn try_from_lit_or_param( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - expr: &'tcx hir::Expr<'tcx>, - ) -> Option { + fn try_from_lit(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, expr: &'tcx hir::Expr<'tcx>) -> Option { // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments // currently have to be wrapped in curly brackets, so it's necessary to special-case. let expr = match &expr.kind { @@ -321,7 +252,7 @@ impl<'tcx> Const<'tcx> { Err(e) => { tcx.dcx().span_delayed_bug( expr.span, - format!("Const::from_anon_const: couldn't lit_to_const {e:?}"), + format!("Const::try_from_lit: couldn't lit_to_const {e:?}"), ); } } @@ -414,20 +345,3 @@ impl<'tcx> Const<'tcx> { matches!(self.kind(), ty::ConstKind::Infer(_)) } } - -pub fn const_param_default<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: LocalDefId, -) -> ty::EarlyBinder<'tcx, Const<'tcx>> { - let default_ct = match tcx.hir_node_by_def_id(def_id) { - hir::Node::GenericParam(hir::GenericParam { - kind: hir::GenericParamKind::Const { default: Some(ct), .. }, - .. - }) => ct, - _ => span_bug!( - tcx.def_span(def_id), - "`const_param_default` expected a generic parameter with a constant" - ), - }; - ty::EarlyBinder::bind(Const::from_const_arg(tcx, default_ct, FeedConstTy::No)) -} diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 2ba1bf2822f..68c3b064eee 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -30,7 +30,7 @@ use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, MultiSpan, }; use rustc_hir as hir; -use rustc_hir::def::DefKind; +use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::definitions::Definitions; use rustc_hir::intravisit::Visitor; @@ -230,7 +230,9 @@ impl<'tcx> Interner for TyCtxt<'tcx> { DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy, DefKind::TyAlias => ty::AliasTermKind::WeakTy, DefKind::AssocConst => ty::AliasTermKind::ProjectionConst, - DefKind::AnonConst => ty::AliasTermKind::UnevaluatedConst, + DefKind::AnonConst | DefKind::Const | DefKind::Ctor(_, CtorKind::Const) => { + ty::AliasTermKind::UnevaluatedConst + } kind => bug!("unexpected DefKind in AliasTy: {kind:?}"), } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index cddd6110c23..965a8c8c95e 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -62,7 +62,7 @@ pub use self::closure::{ place_to_string_for_capture, }; pub use self::consts::{ - Const, ConstInt, ConstKind, Expr, ExprKind, FeedConstTy, ScalarInt, UnevaluatedConst, ValTree, + Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree, }; pub use self::context::{ CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, @@ -2249,7 +2249,6 @@ pub fn provide(providers: &mut Providers) { incoherent_impls: trait_def::incoherent_impls_provider, trait_impls_in_crate: trait_def::trait_impls_in_crate_provider, traits: trait_def::traits_provider, - const_param_default: consts::const_param_default, vtable_allocation: vtable::vtable_allocation_provider, ..*providers }; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index a562d34abde..e4261822040 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1226,6 +1226,7 @@ symbols! { min_const_generics, min_const_unsafe_fn, min_exhaustive_patterns, + min_generic_const_args, min_specialization, min_type_alias_impl_trait, minnumf128, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f0787d286fd..e42350dc5e6 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -42,7 +42,8 @@ use rustc_errors::{FatalError, struct_span_code_err}; use rustc_hir::PredicateOrigin; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE, LocalDefId}; -use rustc_hir_analysis::lower_ty; +use rustc_hir_analysis::hir_ty_lowering::FeedConstTy; +use rustc_hir_analysis::{lower_const_arg_for_rustdoc, lower_ty}; use rustc_middle::metadata::Reexport; use rustc_middle::middle::resolve_bound_vars as rbv; use rustc_middle::ty::{self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, TypingMode}; @@ -435,10 +436,10 @@ fn clean_middle_term<'tcx>( fn clean_hir_term<'tcx>(term: &hir::Term<'tcx>, cx: &mut DocContext<'tcx>) -> Term { match term { hir::Term::Ty(ty) => Term::Type(clean_ty(ty, cx)), - hir::Term::Const(c) => Term::Constant(clean_middle_const( - ty::Binder::dummy(ty::Const::from_const_arg(cx.tcx, c, ty::FeedConstTy::No)), - cx, - )), + hir::Term::Const(c) => { + let ct = lower_const_arg_for_rustdoc(cx.tcx, c, FeedConstTy::No); + Term::Constant(clean_middle_const(ty::Binder::dummy(ct), cx)) + } } } @@ -625,7 +626,7 @@ fn clean_generic_param<'tcx>( (param.name.ident().name, GenericParamDefKind::Const { ty: Box::new(clean_ty(ty, cx)), default: default.map(|ct| { - Box::new(ty::Const::from_const_arg(cx.tcx, ct, ty::FeedConstTy::No).to_string()) + Box::new(lower_const_arg_for_rustdoc(cx.tcx, ct, FeedConstTy::No).to_string()) }), synthetic, }) @@ -1813,7 +1814,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T // `const_eval_poly` tries to first substitute generic parameters which // results in an ICE while manually constructing the constant and using `eval` // does nothing for `ConstKind::Param`. - let ct = ty::Const::from_const_arg(cx.tcx, const_arg, ty::FeedConstTy::No); + let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, FeedConstTy::No); let ct = if let hir::ConstArgKind::Anon(hir::AnonConst { def_id, .. }) = const_arg.kind { diff --git a/tests/crashes/132985.rs b/tests/crashes/132985.rs new file mode 100644 index 00000000000..2735074f44d --- /dev/null +++ b/tests/crashes/132985.rs @@ -0,0 +1,17 @@ +//@ known-bug: #132985 +//@ aux-build:aux132985.rs + +#![allow(incomplete_features)] +#![feature(min_generic_const_args)] +#![feature(adt_const_params)] + +extern crate aux132985; +use aux132985::Foo; + +fn bar() {} + +fn baz() { + bar::<{ Foo }>(); +} + +fn main() {} diff --git a/tests/crashes/auxiliary/aux132985.rs b/tests/crashes/auxiliary/aux132985.rs new file mode 100644 index 00000000000..7ae5567bdc5 --- /dev/null +++ b/tests/crashes/auxiliary/aux132985.rs @@ -0,0 +1,6 @@ +#![feature(adt_const_params)] + +use std::marker::ConstParamTy; + +#[derive(Eq, PartialEq, ConstParamTy)] +pub struct Foo; diff --git a/tests/ui/const-generics/auxiliary/xcrate-const-ctor-a.rs b/tests/ui/const-generics/auxiliary/xcrate-const-ctor-a.rs new file mode 100644 index 00000000000..7ae5567bdc5 --- /dev/null +++ b/tests/ui/const-generics/auxiliary/xcrate-const-ctor-a.rs @@ -0,0 +1,6 @@ +#![feature(adt_const_params)] + +use std::marker::ConstParamTy; + +#[derive(Eq, PartialEq, ConstParamTy)] +pub struct Foo; diff --git a/tests/ui/const-generics/using-static-as-const-arg.rs b/tests/ui/const-generics/using-static-as-const-arg.rs new file mode 100644 index 00000000000..2e8a2a14484 --- /dev/null +++ b/tests/ui/const-generics/using-static-as-const-arg.rs @@ -0,0 +1,7 @@ +//@ check-pass + +pub static STATIC: u32 = 0; +pub struct Foo; +pub const FOO: Foo<{STATIC}> = Foo; + +fn main() {} diff --git a/tests/ui/const-generics/xcrate-const-ctor-b.rs b/tests/ui/const-generics/xcrate-const-ctor-b.rs new file mode 100644 index 00000000000..dce2e43b316 --- /dev/null +++ b/tests/ui/const-generics/xcrate-const-ctor-b.rs @@ -0,0 +1,15 @@ +//@ check-pass +//@ aux-build:xcrate-const-ctor-a.rs + +#![feature(adt_const_params)] + +extern crate xcrate_const_ctor_a; +use xcrate_const_ctor_a::Foo; + +fn bar() {} + +fn baz() { + bar::<{ Foo }>(); +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-min-generic-const-args.rs b/tests/ui/feature-gates/feature-gate-min-generic-const-args.rs new file mode 100644 index 00000000000..171509876d1 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-min-generic-const-args.rs @@ -0,0 +1,11 @@ +trait Trait { + const ASSOC: usize; +} + +// FIXME(min_generic_const_args): implement support for this, behind the feature gate +fn foo() -> [u8; ::ASSOC] { + //~^ ERROR generic parameters may not be used in const operations + loop {} +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-min-generic-const-args.stderr b/tests/ui/feature-gates/feature-gate-min-generic-const-args.stderr new file mode 100644 index 00000000000..04d96b4c11e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-min-generic-const-args.stderr @@ -0,0 +1,11 @@ +error: generic parameters may not be used in const operations + --> $DIR/feature-gate-min-generic-const-args.rs:6:29 + | +LL | fn foo() -> [u8; ::ASSOC] { + | ^ cannot perform const operation using `T` + | + = note: type parameters may not be used in const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: aborting due to 1 previous error + From 473b5d52909b046938eb44350eb119d3529acfd0 Mon Sep 17 00:00:00 2001 From: Boxy Date: Tue, 19 Nov 2024 06:06:47 +0000 Subject: [PATCH 42/44] Fix broken intra-doc link --- compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index f7035531e88..01276abec22 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -221,7 +221,7 @@ impl AssocItemQSelf { /// through const generics need to have their type "fed" to them /// using the query system. /// -/// Use this enum with [`Const::from_const_arg`] to instruct it with the +/// Use this enum with `::lower_const_arg` to instruct it with the /// desired behavior. #[derive(Debug, Clone, Copy)] pub enum FeedConstTy { From 7931a8ddef674da07d1254c8e1af39c76e311e49 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Nov 2024 08:01:45 +0100 Subject: [PATCH 43/44] ignore an occasionally-failing test in Miri --- library/std/src/sync/rwlock/tests.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/std/src/sync/rwlock/tests.rs b/library/std/src/sync/rwlock/tests.rs index 02ac1c85b91..29cad4400f1 100644 --- a/library/std/src/sync/rwlock/tests.rs +++ b/library/std/src/sync/rwlock/tests.rs @@ -550,6 +550,9 @@ fn test_downgrade_observe() { } #[test] +// FIXME: On macOS we use a provenance-incorrect implementation and Miri catches that issue. +// See for details. +#[cfg_attr(all(miri, target_os = "macos"), ignore)] fn test_downgrade_atomic() { const NEW_VALUE: i32 = -1; From 00903cf9c9d2e6e23e76fea25ba8b2627e312bf9 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Tue, 19 Nov 2024 21:41:31 -0500 Subject: [PATCH 44/44] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 69e595908e2..66221abdeca 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 69e595908e2c420e7f0d1be34e6c5b984c8cfb84 +Subproject commit 66221abdeca2002d318fde6efff516aab091df0e