From 0160c60c7883910fbd9eb59dc2b7bad2b5a3e01a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 9 Mar 2025 19:32:51 +0000 Subject: [PATCH 1/7] Check type of const param correctly in MIR typeck --- compiler/rustc_borrowck/src/type_check/mod.rs | 16 +++++++++++ .../rustc_borrowck/src/universal_regions.rs | 14 ++++++++++ .../adt_const_params/check-type-in-mir.rs | 16 +++++++++++ .../adt_const_params/check-type-in-mir.stderr | 14 ++++++++++ .../check-type-in-mir.rs | 12 +++++++++ .../check-type-in-mir.stderr | 27 +++++++++++++++++++ 6 files changed, 99 insertions(+) create mode 100644 tests/ui/const-generics/adt_const_params/check-type-in-mir.rs create mode 100644 tests/ui/const-generics/adt_const_params/check-type-in-mir.stderr create mode 100644 tests/ui/const-generics/generic_const_parameter_types/check-type-in-mir.rs create mode 100644 tests/ui/const-generics/generic_const_parameter_types/check-type-in-mir.stderr diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index d2eb7a52f78a0..d6a80e22602dc 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1773,6 +1773,22 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { { span_mirbug!(self, constant, "bad static type {:?} ({:?})", constant, terr); } + } else if let Const::Ty(_, ct) = constant.const_ + && let ty::ConstKind::Param(p) = ct.kind() + { + let body_def_id = self.universal_regions.defining_ty.def_id(); + let const_param = tcx.generics_of(body_def_id).const_param(p, tcx); + self.ascribe_user_type( + constant.const_.ty(), + ty::UserType::new(ty::UserTypeKind::TypeOf( + const_param.def_id, + UserArgs { + args: self.universal_regions.defining_ty.args(), + user_self_ty: None, + }, + )), + locations.span(self.body), + ); } if let ty::FnDef(def_id, args) = *constant.const_.ty().kind() { diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index cfac9b36832fd..994a5ad32b308 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -184,6 +184,20 @@ impl<'tcx> DefiningTy<'tcx> { | DefiningTy::GlobalAsm(def_id) => def_id, } } + + /// Returns the args of the `DefiningTy`. These are equivalent to the identity + /// substs of the body, but replaced with region vids. + pub(crate) fn args(&self) -> ty::GenericArgsRef<'tcx> { + match *self { + DefiningTy::Closure(_, args) + | DefiningTy::Coroutine(_, args) + | DefiningTy::CoroutineClosure(_, args) + | DefiningTy::FnDef(_, args) + | DefiningTy::Const(_, args) + | DefiningTy::InlineConst(_, args) => args, + DefiningTy::GlobalAsm(_) => ty::List::empty(), + } + } } #[derive(Debug)] diff --git a/tests/ui/const-generics/adt_const_params/check-type-in-mir.rs b/tests/ui/const-generics/adt_const_params/check-type-in-mir.rs new file mode 100644 index 0000000000000..bec485b001c04 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/check-type-in-mir.rs @@ -0,0 +1,16 @@ +// Ensure that we actually treat `N`'s type as `Invariant<'static>` in MIR typeck. + +#![feature(adt_const_params)] + +use std::marker::ConstParamTy; +use std::ops::Deref; + +#[derive(ConstParamTy, PartialEq, Eq)] +struct Invariant<'a>(<&'a () as Deref>::Target); + +fn test<'a, const N: Invariant<'static>>() { + let x: Invariant<'a> = N; + //~^ ERROR lifetime may not live long enough +} + +fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/check-type-in-mir.stderr b/tests/ui/const-generics/adt_const_params/check-type-in-mir.stderr new file mode 100644 index 0000000000000..7e265f33f35bd --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/check-type-in-mir.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/check-type-in-mir.rs:12:28 + | +LL | fn test<'a, const N: Invariant<'static>>() { + | -- lifetime `'a` defined here +LL | let x: Invariant<'a> = N; + | ^ assignment requires that `'a` must outlive `'static` + | + = note: requirement occurs because of the type `Invariant<'_>`, which makes the generic argument `'_` invariant + = note: the struct `Invariant<'a>` is invariant over the parameter `'a` + = help: see for more information about variance + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/generic_const_parameter_types/check-type-in-mir.rs b/tests/ui/const-generics/generic_const_parameter_types/check-type-in-mir.rs new file mode 100644 index 0000000000000..d3bc544ed6c58 --- /dev/null +++ b/tests/ui/const-generics/generic_const_parameter_types/check-type-in-mir.rs @@ -0,0 +1,12 @@ +// Ensure that we actually treat `N`'s type as `&'a u32` in MIR typeck. + +#![feature(unsized_const_params, adt_const_params, generic_const_parameter_types)] +//~^ WARN the feature `unsized_const_params` is incomplete +//~| WARN the feature `generic_const_parameter_types` is incomplete + +fn foo<'a, const N: &'a u32>() { + let b: &'static u32 = N; + //~^ ERROR lifetime may not live long enough +} + +fn main() {} diff --git a/tests/ui/const-generics/generic_const_parameter_types/check-type-in-mir.stderr b/tests/ui/const-generics/generic_const_parameter_types/check-type-in-mir.stderr new file mode 100644 index 0000000000000..3dc7ce438fa93 --- /dev/null +++ b/tests/ui/const-generics/generic_const_parameter_types/check-type-in-mir.stderr @@ -0,0 +1,27 @@ +warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/check-type-in-mir.rs:3:12 + | +LL | #![feature(unsized_const_params, adt_const_params, generic_const_parameter_types)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #95174 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: the feature `generic_const_parameter_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/check-type-in-mir.rs:3:52 + | +LL | #![feature(unsized_const_params, adt_const_params, generic_const_parameter_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #137626 for more information + +error: lifetime may not live long enough + --> $DIR/check-type-in-mir.rs:8:12 + | +LL | fn foo<'a, const N: &'a u32>() { + | -- lifetime `'a` defined here +LL | let b: &'static u32 = N; + | ^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + +error: aborting due to 1 previous error; 2 warnings emitted + From 79034bd291c13b92d68561ba957dc898c6ad3ae7 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Wed, 12 Mar 2025 20:58:56 -0400 Subject: [PATCH 2/7] fix(linker): prevent overflow when estimating CLI arg list length This also updates the estimate on Windows of the length argument list to `saturating_add` to avoid overflow. --- compiler/rustc_codegen_ssa/src/back/command.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/command.rs b/compiler/rustc_codegen_ssa/src/back/command.rs index 383d0579e528a..8425238604151 100644 --- a/compiler/rustc_codegen_ssa/src/back/command.rs +++ b/compiler/rustc_codegen_ssa/src/back/command.rs @@ -166,7 +166,8 @@ impl Command { // [1]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa // [2]: https://devblogs.microsoft.com/oldnewthing/?p=41553 - let estimated_command_line_len = self.args.iter().map(|a| a.len()).sum::(); + let estimated_command_line_len = + self.args.iter().fold(0usize, |acc, a| acc.saturating_add(a.as_encoded_bytes().len())); estimated_command_line_len > 1024 * 6 } } From a672448f0d223bcfa6907d17c321015ac83606d7 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Fri, 14 Mar 2025 08:55:53 -0400 Subject: [PATCH 3/7] fix(linker): use arg list estimate on only Windows Though I doubt anyone running rustc outside Unix/Windows --- compiler/rustc_codegen_ssa/src/back/command.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/command.rs b/compiler/rustc_codegen_ssa/src/back/command.rs index 8425238604151..863d5e7cdd4bd 100644 --- a/compiler/rustc_codegen_ssa/src/back/command.rs +++ b/compiler/rustc_codegen_ssa/src/back/command.rs @@ -139,7 +139,7 @@ impl Command { pub(crate) fn very_likely_to_exceed_some_spawn_limit(&self) -> bool { // We mostly only care about Windows in this method, on Unix the limits // can be gargantuan anyway so we're pretty unlikely to hit them - if cfg!(unix) { + if cfg!(not(windows)) { return false; } From 08166b5b239beb794a48bec52adc6e5261b166d1 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Fri, 14 Mar 2025 09:43:30 -0400 Subject: [PATCH 4/7] feat(linker): check ARG_MAX on Unix platforms On Unix the limits can be gargantuan anyway so we're pretty unlikely to hit them, but might still exceed it. We consult ARG_MAX here to get an estimate. --- .../rustc_codegen_ssa/src/back/command.rs | 48 ++++++++++++++++--- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/command.rs b/compiler/rustc_codegen_ssa/src/back/command.rs index 863d5e7cdd4bd..05351bd6ca379 100644 --- a/compiler/rustc_codegen_ssa/src/back/command.rs +++ b/compiler/rustc_codegen_ssa/src/back/command.rs @@ -137,12 +137,42 @@ impl Command { /// Returns a `true` if we're pretty sure that this'll blow OS spawn limits, /// or `false` if we should attempt to spawn and see what the OS says. pub(crate) fn very_likely_to_exceed_some_spawn_limit(&self) -> bool { - // We mostly only care about Windows in this method, on Unix the limits - // can be gargantuan anyway so we're pretty unlikely to hit them - if cfg!(not(windows)) { + #[cfg(not(any(windows, unix)))] + { return false; } + // On Unix the limits can be gargantuan anyway so we're pretty + // unlikely to hit them, but might still exceed it. + // We consult ARG_MAX here to get an estimate. + #[cfg(unix)] + { + let ptr_size = mem::size_of::(); + // arg + \0 + pointer + let args_size = self.args.iter().fold(0usize, |acc, a| { + let arg = a.as_encoded_bytes().len(); + let nul = 1; + acc.saturating_add(arg).saturating_add(nul).saturating_add(ptr_size) + }); + // key + `=` + value + \0 + pointer + let envs_size = self.env.iter().fold(0usize, |acc, (k, v)| { + let k = k.as_encoded_bytes().len(); + let eq = 1; + let v = v.as_encoded_bytes().len(); + let nul = 1; + acc.saturating_add(k) + .saturating_add(eq) + .saturating_add(v) + .saturating_add(nul) + .saturating_add(ptr_size) + }); + let arg_max = match unsafe { libc::sysconf(libc::_SC_ARG_MAX) } { + -1 => return false, // Go to OS anyway. + max => max as usize, + }; + return args_size.saturating_add(envs_size) > arg_max; + } + // Ok so on Windows to spawn a process is 32,768 characters in its // command line [1]. Unfortunately we don't actually have access to that // as it's calculated just before spawning. Instead we perform a @@ -165,10 +195,14 @@ impl Command { // // [1]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa // [2]: https://devblogs.microsoft.com/oldnewthing/?p=41553 - - let estimated_command_line_len = - self.args.iter().fold(0usize, |acc, a| acc.saturating_add(a.as_encoded_bytes().len())); - estimated_command_line_len > 1024 * 6 + #[cfg(windows)] + { + let estimated_command_line_len = self + .args + .iter() + .fold(0usize, |acc, a| acc.saturating_add(a.as_encoded_bytes().len())); + return estimated_command_line_len > 1024 * 6; + } } } From a891139df1f7b3c8c4a07b3d6ca79a459d6d81d1 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 14 Mar 2025 17:18:41 +0300 Subject: [PATCH 5/7] resolve: Avoid some unstable iteration --- compiler/rustc_data_structures/src/unord.rs | 6 +++++ compiler/rustc_middle/src/ty/mod.rs | 3 ++- .../rustc_resolve/src/build_reduced_graph.rs | 1 + compiler/rustc_resolve/src/diagnostics.rs | 15 ++++-------- compiler/rustc_resolve/src/ident.rs | 1 + compiler/rustc_resolve/src/late.rs | 24 +++++++++---------- .../rustc_resolve/src/late/diagnostics.rs | 12 ++++++++-- compiler/rustc_resolve/src/lib.rs | 24 +++++++++---------- compiler/rustc_resolve/src/macros.rs | 6 ++--- 9 files changed, 51 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs index 34895d3efe6ca..90a77e1e58062 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -259,6 +259,12 @@ impl UnordSet { self.inner.is_empty() } + /// If the set has only one element, returns it, otherwise returns `None`. + #[inline] + pub fn get_only(&self) -> Option<&V> { + if self.inner.len() == 1 { self.inner.iter().next() } else { None } + } + #[inline] pub fn insert(&mut self, v: V) -> bool { self.inner.insert(v) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index ad9d32fd6c152..57101360ba2fc 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -33,6 +33,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; +use rustc_data_structures::unord::UnordMap; use rustc_errors::{Diag, ErrorGuaranteed}; use rustc_hir::LangItem; use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res}; @@ -168,7 +169,7 @@ pub struct ResolverGlobalCtxt { /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`. pub expn_that_defined: FxHashMap, pub effective_visibilities: EffectiveVisibilities, - pub extern_crate_map: FxHashMap, + pub extern_crate_map: UnordMap, pub maybe_unused_trait_imports: FxIndexSet, pub module_children: LocalDefIdMap>, pub glob_map: FxHashMap>, diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 42fe01b1c84c3..763e9207a126b 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1115,6 +1115,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } }); } else { + #[allow(rustc::potential_query_instability)] // FIXME for ident in single_imports.iter().cloned() { let result = self.r.maybe_resolve_ident_in_module( ModuleOrUniformRoot::Module(module), diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 41f4254eede44..5361af98f3c74 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -6,6 +6,7 @@ use rustc_ast::{ }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, MultiSpan, SuggestionStyle, @@ -1467,6 +1468,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return; } + #[allow(rustc::potential_query_instability)] // FIXME let unused_macro = self.unused_macros.iter().find_map(|(def_id, (_, unused_ident))| { if unused_ident.name == ident.name { Some((def_id, unused_ident)) } else { None } }); @@ -2863,18 +2865,11 @@ fn show_candidates( } else { // Get the unique item kinds and if there's only one, we use the right kind name // instead of the more generic "items". - let mut kinds = accessible_path_strings + let kinds = accessible_path_strings .iter() .map(|(_, descr, _, _, _)| *descr) - .collect::>() - .into_iter(); - let kind = if let Some(kind) = kinds.next() - && let None = kinds.next() - { - kind - } else { - "item" - }; + .collect::>(); + let kind = if let Some(kind) = kinds.get_only() { kind } else { "item" }; let s = if kind.ends_with('s') { "es" } else { "s" }; ("one of these", kind, s, String::new(), "") diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 5f0a2a597e9b4..27d63198836a3 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -946,6 +946,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Check if one of single imports can still define the name, // if it can then our result is not determined and can be invalidated. + #[allow(rustc::potential_query_instability)] // FIXME for single_import in &resolution.single_imports { if ignore_import == Some(*single_import) { // This branch handles a cycle in single imports. diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index f3f6c55158068..6056a69ee71f6 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -18,6 +18,7 @@ use rustc_ast::visit::{ }; use rustc_ast::*; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; +use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::codes::*; use rustc_errors::{ Applicability, DiagArgValue, ErrorGuaranteed, IntoDiagArg, StashKey, Suggestions, @@ -47,8 +48,6 @@ mod diagnostics; type Res = def::Res; -type IdentMap = FxHashMap; - use diagnostics::{ElisionFnParameter, LifetimeElisionCandidate, MissingLifetime}; #[derive(Copy, Clone, Debug)] @@ -273,8 +272,8 @@ impl RibKind<'_> { /// resolving, the name is looked up from inside out. #[derive(Debug)] pub(crate) struct Rib<'ra, R = Res> { - pub bindings: IdentMap, - pub patterns_with_skipped_bindings: FxHashMap)>>, + pub bindings: FxHashMap, + pub patterns_with_skipped_bindings: UnordMap)>>, pub kind: RibKind<'ra>, } @@ -1605,12 +1604,12 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // for better diagnostics. let mut forward_ty_ban_rib_const_param_ty = Rib { bindings: forward_ty_ban_rib.bindings.clone(), - patterns_with_skipped_bindings: FxHashMap::default(), + patterns_with_skipped_bindings: Default::default(), kind: RibKind::ForwardGenericParamBan(ForwardGenericParamBanReason::ConstParamTy), }; let mut forward_const_ban_rib_const_param_ty = Rib { bindings: forward_const_ban_rib.bindings.clone(), - patterns_with_skipped_bindings: FxHashMap::default(), + patterns_with_skipped_bindings: Default::default(), kind: RibKind::ForwardGenericParamBan(ForwardGenericParamBanReason::ConstParamTy), }; // We'll ban these with a `ConstParamTy` rib, so just clear these ribs for better @@ -2334,7 +2333,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { let local_candidates = self.lifetime_elision_candidates.take(); if let Some(candidates) = local_candidates { - let distinct: FxHashSet<_> = candidates.iter().map(|(res, _)| *res).collect(); + let distinct: UnordSet<_> = candidates.iter().map(|(res, _)| *res).collect(); let lifetime_count = distinct.len(); if lifetime_count != 0 { parameter_info.push(ElisionFnParameter { @@ -2358,14 +2357,13 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } })); } - let mut distinct_iter = distinct.into_iter(); - if let Some(res) = distinct_iter.next() { + if !distinct.is_empty() { match elision_lifetime { // We are the first parameter to bind lifetimes. Elision::None => { - if distinct_iter.next().is_none() { + if let Some(res) = distinct.get_only() { // We have a single lifetime => success. - elision_lifetime = Elision::Param(res) + elision_lifetime = Elision::Param(*res) } else { // We have multiple lifetimes => error. elision_lifetime = Elision::Err; @@ -2890,6 +2888,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { break; } + #[allow(rustc::potential_query_instability)] // FIXME seen_bindings .extend(parent_rib.bindings.keys().map(|ident| (*ident, ident.span))); } @@ -4004,7 +4003,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } } - fn innermost_rib_bindings(&mut self, ns: Namespace) -> &mut IdentMap { + fn innermost_rib_bindings(&mut self, ns: Namespace) -> &mut FxHashMap { &mut self.ribs[ns].last_mut().unwrap().bindings } @@ -5202,6 +5201,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut late_resolution_visitor = LateResolutionVisitor::new(self); late_resolution_visitor.resolve_doc_links(&krate.attrs, MaybeExported::Ok(CRATE_NODE_ID)); visit::walk_crate(&mut late_resolution_visitor, krate); + #[allow(rustc::potential_query_instability)] // FIXME for (id, span) in late_resolution_visitor.diag_metadata.unused_labels.iter() { self.lint_buffer.buffer_lint( lint::builtin::UNUSED_LABELS, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 84858cfc1b1e4..bcfcc8000c718 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -830,6 +830,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if let Some(rib) = &self.last_block_rib && let RibKind::Normal = rib.kind { + #[allow(rustc::potential_query_instability)] // FIXME for (ident, &res) in &rib.bindings { if let Res::Local(_) = res && path.len() == 1 @@ -1018,6 +1019,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if let Some(err_code) = err.code { if err_code == E0425 { for label_rib in &self.label_ribs { + #[allow(rustc::potential_query_instability)] // FIXME for (label_ident, node_id) in &label_rib.bindings { let ident = path.last().unwrap().ident; if format!("'{ident}") == label_ident.to_string() { @@ -1177,7 +1179,10 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let [segment] = path else { return }; let None = following_seg else { return }; for rib in self.ribs[ValueNS].iter().rev() { - for (def_id, spans) in &rib.patterns_with_skipped_bindings { + let patterns_with_skipped_bindings = self.r.tcx.with_stable_hashing_context(|hcx| { + rib.patterns_with_skipped_bindings.to_sorted(&hcx, true) + }); + for (def_id, spans) in patterns_with_skipped_bindings { if let DefKind::Struct | DefKind::Variant = self.r.tcx.def_kind(*def_id) && let Some(fields) = self.r.field_idents(*def_id) { @@ -2052,7 +2057,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if self .r .extern_crate_map - .iter() + .items() // FIXME: This doesn't include impls like `impl Default for String`. .flat_map(|(_, crate_)| self.r.tcx.implementations_of_trait((*crate_, default_trait))) .filter_map(|(_, simplified_self_ty)| *simplified_self_ty) @@ -2261,6 +2266,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { }; // Locals and type parameters + #[allow(rustc::potential_query_instability)] // FIXME for (ident, &res) in &rib.bindings { if filter_fn(res) && ident.span.ctxt() == rib_ctxt { names.push(TypoSuggestion::typo_from_ident(*ident, res)); @@ -2788,6 +2794,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let within_scope = self.is_label_valid_from_rib(rib_index); let rib = &self.label_ribs[rib_index]; + #[allow(rustc::potential_query_instability)] // FIXME let names = rib .bindings .iter() @@ -2799,6 +2806,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { // Upon finding a similar name, get the ident that it was from - the span // contained within helps make a useful diagnostic. In addition, determine // whether this candidate is within scope. + #[allow(rustc::potential_query_instability)] // FIXME let (ident, _) = rib.bindings.iter().find(|(ident, _)| ident.name == symbol).unwrap(); (*ident, within_scope) }) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 495ce843fcd22..447d5283e27ec 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -9,7 +9,6 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] -#![allow(rustc::potential_query_instability)] #![allow(rustc::untranslatable_diagnostic)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] @@ -47,6 +46,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::FreezeReadGuard; +use rustc_data_structures::unord::UnordMap; use rustc_errors::{Applicability, Diag, ErrCode, ErrorGuaranteed}; use rustc_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind}; use rustc_feature::BUILTIN_ATTRIBUTES; @@ -1046,7 +1046,7 @@ pub struct Resolver<'ra, 'tcx> { graph_root: Module<'ra>, prelude: Option>, - extern_prelude: FxHashMap>, + extern_prelude: FxIndexMap>, /// N.B., this is used only for better diagnostics, not name resolution itself. field_names: LocalDefIdMap>, @@ -1079,7 +1079,7 @@ pub struct Resolver<'ra, 'tcx> { extra_lifetime_params_map: NodeMap>, /// `CrateNum` resolutions of `extern crate` items. - extern_crate_map: FxHashMap, + extern_crate_map: UnordMap, module_children: LocalDefIdMap>, trait_map: NodeMap>, @@ -1102,7 +1102,7 @@ pub struct Resolver<'ra, 'tcx> { /// some AST passes can generate identifiers that only resolve to local or /// lang items. empty_module: Module<'ra>, - module_map: FxHashMap>, + module_map: FxIndexMap>, binding_parent_modules: FxHashMap, Module<'ra>>, underscore_disambiguator: u32, @@ -1136,7 +1136,7 @@ pub struct Resolver<'ra, 'tcx> { macro_names: FxHashSet, builtin_macros: FxHashMap, registered_tools: &'tcx RegisteredTools, - macro_use_prelude: FxHashMap>, + macro_use_prelude: FxIndexMap>, macro_map: FxHashMap, dummy_ext_bang: Arc, dummy_ext_derive: Arc, @@ -1145,7 +1145,7 @@ pub struct Resolver<'ra, 'tcx> { ast_transform_scopes: FxHashMap>, unused_macros: FxHashMap, /// A map from the macro to all its potentially unused arms. - unused_macro_rules: FxIndexMap>, + unused_macro_rules: FxIndexMap>, proc_macro_stubs: FxHashSet, /// Traces collected during macro resolution and validated when it's complete. single_segment_macro_resolutions: @@ -1259,7 +1259,7 @@ impl<'ra> ResolverArenas<'ra> { expn_id: ExpnId, span: Span, no_implicit_prelude: bool, - module_map: &mut FxHashMap>, + module_map: &mut FxIndexMap>, module_self_bindings: &mut FxHashMap, NameBinding<'ra>>, ) -> Module<'ra> { let module = Module(Interned::new_unchecked(self.modules.alloc(ModuleData::new( @@ -1404,7 +1404,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { arenas: &'ra ResolverArenas<'ra>, ) -> Resolver<'ra, 'tcx> { let root_def_id = CRATE_DEF_ID.to_def_id(); - let mut module_map = FxHashMap::default(); + let mut module_map = FxIndexMap::default(); let mut module_self_bindings = FxHashMap::default(); let graph_root = arenas.new_module( None, @@ -1421,8 +1421,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ExpnId::root(), DUMMY_SP, true, - &mut FxHashMap::default(), - &mut FxHashMap::default(), + &mut Default::default(), + &mut Default::default(), ); let mut def_id_to_node_id = IndexVec::default(); @@ -1437,7 +1437,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut invocation_parents = FxHashMap::default(); invocation_parents.insert(LocalExpnId::ROOT, InvocationParent::ROOT); - let mut extern_prelude: FxHashMap> = tcx + let mut extern_prelude: FxIndexMap> = tcx .sess .opts .externs @@ -1536,7 +1536,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { macro_names: FxHashSet::default(), builtin_macros: Default::default(), registered_tools, - macro_use_prelude: FxHashMap::default(), + macro_use_prelude: Default::default(), macro_map: FxHashMap::default(), dummy_ext_bang: Arc::new(SyntaxExtension::dummy_bang(edition)), dummy_ext_derive: Arc::new(SyntaxExtension::dummy_derive(edition)), diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 984dfff3ea56e..7100d89ad61a8 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -323,6 +323,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { } fn check_unused_macros(&mut self) { + #[allow(rustc::potential_query_instability)] // FIXME for (_, &(node_id, ident)) in self.unused_macros.iter() { self.lint_buffer.buffer_lint( UNUSED_MACROS, @@ -333,10 +334,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { } for (&def_id, unused_arms) in self.unused_macro_rules.iter() { - let mut unused_arms = unused_arms.iter().collect::>(); - unused_arms.sort_by_key(|&(&arm_i, _)| arm_i); - - for (&arm_i, &(ident, rule_span)) in unused_arms { + for (&arm_i, &(ident, rule_span)) in unused_arms.to_sorted_stable_ord() { if self.unused_macros.contains_key(&def_id) { // We already lint the entire macro as unused continue; From e54bde6d473941ff45643f494a902f23b19e7c9a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 14 Mar 2025 19:38:29 +0000 Subject: [PATCH 6/7] Remove fake borrows of refs that are converted into non-refs in MakeByMoveBody --- .../src/coroutine/by_move_body.rs | 41 +++++++++- ...oo-{closure#0}-{closure#0}.built.after.mir | 81 +++++++++++++++++++ ...oo-{closure#0}-{closure#1}.built.after.mir | 64 +++++++++++++++ .../async_closure_fake_read_for_by_move.rs | 18 +++++ 4 files changed, 202 insertions(+), 2 deletions(-) create mode 100644 tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#0}.built.after.mir create mode 100644 tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#1}.built.after.mir create mode 100644 tests/mir-opt/async_closure_fake_read_for_by_move.rs diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs index 9cd7045a0a222..89a306c610477 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -178,7 +178,7 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>( ), }; - ( + Some(( FieldIdx::from_usize(child_field_idx + num_args), ( FieldIdx::from_usize(parent_field_idx + num_args), @@ -186,9 +186,10 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>( peel_deref, child_precise_captures, ), - ) + )) }, ) + .flatten() .collect(); if coroutine_kind == ty::ClosureKind::FnOnce { @@ -312,10 +313,46 @@ impl<'tcx> MutVisitor<'tcx> for MakeByMoveBody<'tcx> { self.super_place(place, context, location); } + fn visit_statement(&mut self, statement: &mut mir::Statement<'tcx>, location: mir::Location) { + // Remove fake borrows of closure captures if that capture has been + // replaced with a by-move version of that capture. + // + // For example, imagine we capture `Foo` in the parent and `&Foo` + // in the child. We will emit two fake borrows like: + // + // ``` + // _2 = &fake shallow (*(_1.0: &Foo)); + // _3 = &fake shallow (_1.0: &Foo); + // ``` + // + // However, since this transform is responsible for replacing + // `_1.0: &Foo` with `_1.0: Foo`, that makes the second fake borrow + // obsolete, and we should replace it with a nop. + // + // As a side-note, we don't actually even care about fake borrows + // here at all since they're fully a MIR borrowck artifact, and we + // don't need to borrowck by-move MIR bodies. But it's best to preserve + // as much as we can between these two bodies :) + if let mir::StatementKind::Assign(box (_, rvalue)) = &statement.kind + && let mir::Rvalue::Ref(_, mir::BorrowKind::Fake(mir::FakeBorrowKind::Shallow), place) = + rvalue + && let mir::PlaceRef { + local: ty::CAPTURE_STRUCT_LOCAL, + projection: [mir::ProjectionElem::Field(idx, _)], + } = place.as_ref() + && let Some(&(_, _, true, _)) = self.field_remapping.get(&idx) + { + statement.kind = mir::StatementKind::Nop; + } + + self.super_statement(statement, location); + } + fn visit_local_decl(&mut self, local: mir::Local, local_decl: &mut mir::LocalDecl<'tcx>) { // Replace the type of the self arg. if local == ty::CAPTURE_STRUCT_LOCAL { local_decl.ty = self.by_move_coroutine_ty; } + self.super_local_decl(local, local_decl); } } diff --git a/tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#0}.built.after.mir b/tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#0}.built.after.mir new file mode 100644 index 0000000000000..0c8a17ff70b2e --- /dev/null +++ b/tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#0}.built.after.mir @@ -0,0 +1,81 @@ +// MIR for `foo::{closure#0}::{closure#0}` after built + +fn foo::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_fake_read_for_by_move.rs:12:27: 15:6}, _2: ResumeTy) -> () +yields () + { + debug _task_context => _2; + debug f => (*(_1.0: &&Foo)); + let mut _0: (); + let mut _3: &Foo; + let mut _4: &&Foo; + let mut _5: &&&Foo; + let mut _6: isize; + let mut _7: bool; + + bb0: { + PlaceMention((*(_1.0: &&Foo))); + _6 = discriminant((*(*(_1.0: &&Foo)))); + switchInt(move _6) -> [0: bb2, otherwise: bb1]; + } + + bb1: { + _0 = const (); + goto -> bb10; + } + + bb2: { + falseEdge -> [real: bb5, imaginary: bb1]; + } + + bb3: { + goto -> bb1; + } + + bb4: { + FakeRead(ForMatchedPlace(None), (*(_1.0: &&Foo))); + unreachable; + } + + bb5: { + _3 = &fake shallow (*(*(_1.0: &&Foo))); + _4 = &fake shallow (*(_1.0: &&Foo)); + _5 = &fake shallow (_1.0: &&Foo); + StorageLive(_7); + _7 = const true; + switchInt(move _7) -> [0: bb8, otherwise: bb7]; + } + + bb6: { + falseEdge -> [real: bb3, imaginary: bb1]; + } + + bb7: { + StorageDead(_7); + FakeRead(ForMatchGuard, _3); + FakeRead(ForMatchGuard, _4); + FakeRead(ForMatchGuard, _5); + _0 = const (); + goto -> bb10; + } + + bb8: { + goto -> bb9; + } + + bb9: { + StorageDead(_7); + goto -> bb6; + } + + bb10: { + drop(_1) -> [return: bb11, unwind: bb12]; + } + + bb11: { + return; + } + + bb12 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#1}.built.after.mir b/tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#1}.built.after.mir new file mode 100644 index 0000000000000..bd0baddb1f892 --- /dev/null +++ b/tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#1}.built.after.mir @@ -0,0 +1,64 @@ +// MIR for `foo::{closure#0}::{closure#1}` after built + +fn foo::{closure#0}::{closure#1}(_1: {async closure body@$DIR/async_closure_fake_read_for_by_move.rs:12:27: 15:6}, _2: ResumeTy) -> () +yields () + { + debug _task_context => _2; + debug f => (_1.0: &Foo); + let mut _0: (); + let mut _3: &Foo; + let mut _4: &&Foo; + let mut _5: &&&Foo; + let mut _6: isize; + let mut _7: bool; + + bb0: { + PlaceMention((_1.0: &Foo)); + _6 = discriminant((*(_1.0: &Foo))); + switchInt(move _6) -> [0: bb2, otherwise: bb1]; + } + + bb1: { + _0 = const (); + goto -> bb6; + } + + bb2: { + falseEdge -> [real: bb3, imaginary: bb1]; + } + + bb3: { + _3 = &fake shallow (*(_1.0: &Foo)); + _4 = &fake shallow (_1.0: &Foo); + nop; + StorageLive(_7); + _7 = const true; + switchInt(move _7) -> [0: bb5, otherwise: bb4]; + } + + bb4: { + StorageDead(_7); + FakeRead(ForMatchGuard, _3); + FakeRead(ForMatchGuard, _4); + FakeRead(ForMatchGuard, _5); + _0 = const (); + goto -> bb6; + } + + bb5: { + StorageDead(_7); + falseEdge -> [real: bb1, imaginary: bb1]; + } + + bb6: { + drop(_1) -> [return: bb7, unwind: bb8]; + } + + bb7: { + return; + } + + bb8 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/async_closure_fake_read_for_by_move.rs b/tests/mir-opt/async_closure_fake_read_for_by_move.rs new file mode 100644 index 0000000000000..3c5aec94bbfe5 --- /dev/null +++ b/tests/mir-opt/async_closure_fake_read_for_by_move.rs @@ -0,0 +1,18 @@ +//@ edition:2021 +// skip-filecheck + +enum Foo { + Bar, + Baz, +} + +// EMIT_MIR async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#0}.built.after.mir +// EMIT_MIR async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#1}.built.after.mir +fn foo(f: &Foo) { + let x = async move || match f { + Foo::Bar if true => {} + _ => {} + }; +} + +fn main() {} From ecce387ef6de214ef23396395377a9d1779bcdd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= <39484203+jieyouxu@users.noreply.github.com> Date: Sat, 15 Mar 2025 09:26:02 +0800 Subject: [PATCH 7/7] Mark myself as unavailable for reviews --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index 0096b22da1711..293ad259910fd 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1082,6 +1082,7 @@ contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" users_on_vacation = [ "jyn514", "ChrisDenton", + "jieyouxu", ] [[assign.warn_non_default_branch.exceptions]]