diff --git a/Cargo.lock b/Cargo.lock index 63c7d97bce43f..35ad4472e6a3c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -184,9 +184,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "askama" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03341eae1125472b0672fbf35cc9aa7b74cd8e0c3d02f02c28a04678f12aaa7a" +checksum = "10a800c6f7c005e5bcb76ff0b9e61c9e54ad379ce4e83a88ed14ff487a73776d" dependencies = [ "askama_macros", "itoa", @@ -197,9 +197,9 @@ dependencies = [ [[package]] name = "askama_derive" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "461bd78f3da90b5e44eee4272cfb1c4832aa3dcdb6c370aedd3eb253d2b9e3ca" +checksum = "0cb7657165bac49b5c533850e7cd67c1c60059aefc31088f89aa431c8a90d5d9" dependencies = [ "askama_parser", "basic-toml", @@ -214,18 +214,18 @@ dependencies = [ [[package]] name = "askama_macros" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba49fb22ee3074574b8510abd9495d4f0bb9b8f87e8e45ee31e2cee508f7a8e5" +checksum = "e55eacd3e54d32483cd10d0a881a0f28a40f3a763704ac9b8693edc39d7321c7" dependencies = [ "askama_derive", ] [[package]] name = "askama_parser" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e33eb7484958aaa1f27e9adb556f5d557331cd891bdbb33781bc1f9550b6f6e" +checksum = "20c3df8886ab5acdcd76eee93b3e2df1ef734251438b5b942b5fea22c50d2a0f" dependencies = [ "rustc-hash 2.1.1", "serde", diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index f83931d375996..986ade57fb31d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -1,3 +1,4 @@ +use rustc_abi::FieldIdx; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, Diag}; use rustc_hir::intravisit::Visitor; @@ -7,7 +8,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex}; use rustc_span::def_id::DefId; -use rustc_span::{BytePos, DUMMY_SP, ExpnKind, MacroKind, Span}; +use rustc_span::{BytePos, ExpnKind, MacroKind, Span}; use rustc_trait_selection::error_reporting::traits::FindExprBySpan; use rustc_trait_selection::infer::InferCtxtExt; use tracing::debug; @@ -472,49 +473,30 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if def_id.as_local() == Some(self.mir_def_id()) && let Some(upvar_field) = upvar_field => { - let closure_kind_ty = closure_args.as_closure().kind_ty(); - let closure_kind = match closure_kind_ty.to_opt_closure_kind() { - Some(kind @ (ty::ClosureKind::Fn | ty::ClosureKind::FnMut)) => kind, - Some(ty::ClosureKind::FnOnce) => { - bug!("closure kind does not match first argument type") - } - None => bug!("closure kind not inferred by borrowck"), - }; - let capture_description = - format!("captured variable in an `{closure_kind}` closure"); - - let upvar = &self.upvars[upvar_field.index()]; - let upvar_hir_id = upvar.get_root_variable(); - let upvar_name = upvar.to_string(tcx); - let upvar_span = tcx.hir_span(upvar_hir_id); - - let place_name = self.describe_any_place(move_place.as_ref()); - - let place_description = - if self.is_upvar_field_projection(move_place.as_ref()).is_some() { - format!("{place_name}, a {capture_description}") - } else { - format!("{place_name}, as `{upvar_name}` is a {capture_description}") - }; - - debug!( - "report: closure_kind_ty={:?} closure_kind={:?} place_description={:?}", - closure_kind_ty, closure_kind, place_description, - ); - - let closure_span = tcx.def_span(def_id); - - self.cannot_move_out_of(span, &place_description) - .with_span_label(upvar_span, "captured outer variable") - .with_span_label( - closure_span, - format!("captured by this `{closure_kind}` closure"), - ) - .with_span_help( - self.get_closure_bound_clause_span(*def_id), - "`Fn` and `FnMut` closures require captured values to be able to be \ - consumed multiple times, but `FnOnce` closures may consume them only once", - ) + self.report_closure_move_error( + span, + move_place, + *def_id, + closure_args.as_closure().kind_ty(), + upvar_field, + ty::Asyncness::No, + ) + } + ty::CoroutineClosure(def_id, closure_args) + if def_id.as_local() == Some(self.mir_def_id()) + && let Some(upvar_field) = upvar_field + && self + .get_closure_bound_clause_span(*def_id, ty::Asyncness::Yes) + .is_some() => + { + self.report_closure_move_error( + span, + move_place, + *def_id, + closure_args.as_coroutine_closure().kind_ty(), + upvar_field, + ty::Asyncness::Yes, + ) } _ => { let source = self.borrowed_content_source(deref_base); @@ -563,45 +545,134 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { err } - fn get_closure_bound_clause_span(&self, def_id: DefId) -> Span { + fn report_closure_move_error( + &self, + span: Span, + move_place: Place<'tcx>, + def_id: DefId, + closure_kind_ty: Ty<'tcx>, + upvar_field: FieldIdx, + asyncness: ty::Asyncness, + ) -> Diag<'infcx> { + let tcx = self.infcx.tcx; + + let closure_kind = match closure_kind_ty.to_opt_closure_kind() { + Some(kind @ (ty::ClosureKind::Fn | ty::ClosureKind::FnMut)) => kind, + Some(ty::ClosureKind::FnOnce) => { + bug!("closure kind does not match first argument type") + } + None => bug!("closure kind not inferred by borrowck"), + }; + + let async_prefix = if asyncness.is_async() { "Async" } else { "" }; + let capture_description = + format!("captured variable in an `{async_prefix}{closure_kind}` closure"); + + let upvar = &self.upvars[upvar_field.index()]; + let upvar_hir_id = upvar.get_root_variable(); + let upvar_name = upvar.to_string(tcx); + let upvar_span = tcx.hir_span(upvar_hir_id); + + let place_name = self.describe_any_place(move_place.as_ref()); + + let place_description = if self.is_upvar_field_projection(move_place.as_ref()).is_some() { + format!("{place_name}, a {capture_description}") + } else { + format!("{place_name}, as `{upvar_name}` is a {capture_description}") + }; + + debug!(?closure_kind_ty, ?closure_kind, ?place_description); + + let closure_span = tcx.def_span(def_id); + + let help_msg = format!( + "`{async_prefix}Fn` and `{async_prefix}FnMut` closures require captured values to \ + be able to be consumed multiple times, but `{async_prefix}FnOnce` closures may \ + consume them only once" + ); + + let mut err = self + .cannot_move_out_of(span, &place_description) + .with_span_label(upvar_span, "captured outer variable") + .with_span_label( + closure_span, + format!("captured by this `{async_prefix}{closure_kind}` closure"), + ); + + if let Some(bound_span) = self.get_closure_bound_clause_span(def_id, asyncness) { + err.span_help(bound_span, help_msg); + } else if !asyncness.is_async() { + // For sync closures, always emit the help message even without a span. + // For async closures, we only enter this branch if we found a valid span + // (due to the match guard), so no fallback is needed. + err.help(help_msg); + } + + err + } + + fn get_closure_bound_clause_span( + &self, + def_id: DefId, + asyncness: ty::Asyncness, + ) -> Option { let tcx = self.infcx.tcx; let typeck_result = tcx.typeck(self.mir_def_id()); // Check whether the closure is an argument to a call, if so, // get the instantiated where-bounds of that call. let closure_hir_id = tcx.local_def_id_to_hir_id(def_id.expect_local()); - let hir::Node::Expr(parent) = tcx.parent_hir_node(closure_hir_id) else { return DUMMY_SP }; + let hir::Node::Expr(parent) = tcx.parent_hir_node(closure_hir_id) else { return None }; let predicates = match parent.kind { hir::ExprKind::Call(callee, _) => { - let Some(ty) = typeck_result.node_type_opt(callee.hir_id) else { return DUMMY_SP }; - let ty::FnDef(fn_def_id, args) = ty.kind() else { return DUMMY_SP }; + let ty = typeck_result.node_type_opt(callee.hir_id)?; + let ty::FnDef(fn_def_id, args) = ty.kind() else { return None }; tcx.predicates_of(fn_def_id).instantiate(tcx, args) } hir::ExprKind::MethodCall(..) => { - let Some((_, method)) = typeck_result.type_dependent_def(parent.hir_id) else { - return DUMMY_SP; - }; + let (_, method) = typeck_result.type_dependent_def(parent.hir_id)?; let args = typeck_result.node_args(parent.hir_id); tcx.predicates_of(method).instantiate(tcx, args) } - _ => return DUMMY_SP, + _ => return None, }; - // Check whether one of the where-bounds requires the closure to impl `Fn[Mut]`. + // Check whether one of the where-bounds requires the closure to impl `Fn[Mut]` + // or `AsyncFn[Mut]`. for (pred, span) in predicates.predicates.iter().zip(predicates.spans.iter()) { - if let Some(clause) = pred.as_trait_clause() - && let ty::Closure(clause_closure_def_id, _) = clause.self_ty().skip_binder().kind() - && *clause_closure_def_id == def_id - && (tcx.lang_items().fn_mut_trait() == Some(clause.def_id()) - || tcx.lang_items().fn_trait() == Some(clause.def_id())) - { - // Found `` - // We point at the `Fn()` or `FnMut()` bound that coerced the closure, which - // could be changed to `FnOnce()` to avoid the move error. - return *span; + let dominated_by_fn_trait = self + .closure_clause_kind(*pred, def_id, asyncness) + .is_some_and(|kind| matches!(kind, ty::ClosureKind::Fn | ty::ClosureKind::FnMut)); + if dominated_by_fn_trait { + // Found `` or + // ``. + // We point at the bound that coerced the closure, which could be changed + // to `FnOnce()` or `AsyncFnOnce()` to avoid the move error. + return Some(*span); } } - DUMMY_SP + None + } + + /// If `pred` is a trait clause binding the closure `def_id` to `Fn`/`FnMut`/`FnOnce` + /// (or their async equivalents based on `asyncness`), returns the corresponding + /// `ClosureKind`. Otherwise returns `None`. + fn closure_clause_kind( + &self, + pred: ty::Clause<'tcx>, + def_id: DefId, + asyncness: ty::Asyncness, + ) -> Option { + let tcx = self.infcx.tcx; + let clause = pred.as_trait_clause()?; + let kind = match asyncness { + ty::Asyncness::Yes => tcx.async_fn_trait_kind_from_def_id(clause.def_id()), + ty::Asyncness::No => tcx.fn_trait_kind_from_def_id(clause.def_id()), + }?; + match clause.self_ty().skip_binder().kind() { + ty::Closure(id, _) | ty::CoroutineClosure(id, _) if *id == def_id => Some(kind), + _ => None, + } } fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span: Span) { diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 2f8c6b8763987..0e6a1a414e45f 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -91,20 +91,32 @@ macro_rules! declare_passes { )+ )* - static PASS_NAMES: LazyLock> = LazyLock::new(|| [ + static PASS_NAMES: LazyLock> = LazyLock::new(|| { + let mut set = FxIndexSet::default(); // Fake marker pass - "PreCodegen", + set.insert("PreCodegen"); $( $( - stringify!($pass_name), - $( - $( - $mod_name::$pass_name::$ident.name(), - )* - )? + set.extend(pass_names!($mod_name : $pass_name $( { $($ident),* } )? )); )+ )* - ].into_iter().collect()); + set + }); + }; +} + +macro_rules! pass_names { + // pass groups: only pass names inside are considered pass_names + ($mod_name:ident : $pass_group:ident { $($pass_name:ident),* $(,)? }) => { + [ + $( + $mod_name::$pass_group::$pass_name.name(), + )* + ] + }; + // lone pass names: stringify the struct or enum name + ($mod_name:ident : $pass_name:ident) => { + [stringify!($pass_name)] }; } diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index b628224db5369..d6310b62b2759 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -67,11 +67,11 @@ impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDA // This is `impl QueryDispatcher for SemiDynamicQueryDispatcher`. impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDABLE: bool> - QueryDispatcher> - for SemiDynamicQueryDispatcher<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE> + QueryDispatcher for SemiDynamicQueryDispatcher<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE> where for<'a> C::Key: HashStable>, { + type Qcx = QueryCtxt<'tcx>; type Key = C::Key; type Value = C::Value; type Cache = C; @@ -104,10 +104,7 @@ where } #[inline(always)] - fn query_cache<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a Self::Cache - where - 'tcx: 'a, - { + fn query_cache<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a Self::Cache { // Safety: // This is just manually doing the subfield referencing through pointer math. unsafe { @@ -215,15 +212,13 @@ where /// on the type `rustc_query_impl::query_impl::$name::QueryType`. trait QueryDispatcherUnerased<'tcx> { type UnerasedValue; - type Dispatcher: QueryDispatcher>; + type Dispatcher: QueryDispatcher>; const NAME: &'static &'static str; fn query_dispatcher(tcx: TyCtxt<'tcx>) -> Self::Dispatcher; - fn restore_val( - value: >>::Value, - ) -> Self::UnerasedValue; + fn restore_val(value: ::Value) -> Self::UnerasedValue; } pub fn query_system<'a>( diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 6ead03a527a7a..0223981fd55dc 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -414,7 +414,7 @@ pub(crate) fn encode_query_results<'a, 'tcx, Q>( } pub(crate) fn query_key_hash_verify<'tcx>( - query: impl QueryDispatcher>, + query: impl QueryDispatcher>, qcx: QueryCtxt<'tcx>, ) { let _timer = qcx.tcx.prof.generic_activity_with_arg("query_key_hash_verify_for", query.name()); @@ -442,7 +442,7 @@ pub(crate) fn query_key_hash_verify<'tcx>( fn try_load_from_on_disk_cache<'tcx, Q>(query: Q, tcx: TyCtxt<'tcx>, dep_node: DepNode) where - Q: QueryDispatcher>, + Q: QueryDispatcher>, { debug_assert!(tcx.dep_graph.is_green(&dep_node)); @@ -488,7 +488,7 @@ where fn force_from_dep_node<'tcx, Q>(query: Q, tcx: TyCtxt<'tcx>, dep_node: DepNode) -> bool where - Q: QueryDispatcher>, + Q: QueryDispatcher>, { // We must avoid ever having to call `force_from_dep_node()` for a // `DepNode::codegen_unit`: @@ -523,8 +523,7 @@ pub(crate) fn make_dep_kind_vtable_for_query<'tcx, Q>( where Q: QueryDispatcherUnerased<'tcx>, { - let fingerprint_style = - >>::Key::fingerprint_style(); + let fingerprint_style = ::Key::fingerprint_style(); if is_anon || !fingerprint_style.reconstructible() { return DepKindVTable { @@ -731,7 +730,7 @@ macro_rules! define_queries { } #[inline(always)] - fn restore_val(value: >>::Value) -> Self::UnerasedValue { + fn restore_val(value: ::Value) -> Self::UnerasedValue { restore::>(value) } } diff --git a/compiler/rustc_query_system/src/query/dispatcher.rs b/compiler/rustc_query_system/src/query/dispatcher.rs index bba1703dfbb6b..1ca76a70364c9 100644 --- a/compiler/rustc_query_system/src/query/dispatcher.rs +++ b/compiler/rustc_query_system/src/query/dispatcher.rs @@ -5,13 +5,18 @@ use rustc_data_structures::fingerprint::Fingerprint; use rustc_span::ErrorGuaranteed; use super::QueryStackFrameExtra; -use crate::dep_graph::{DepKind, DepNode, DepNodeParams, SerializedDepNodeIndex}; +use crate::dep_graph::{DepKind, DepNode, DepNodeParams, HasDepContext, SerializedDepNodeIndex}; use crate::ich::StableHashingContext; use crate::query::caches::QueryCache; use crate::query::{CycleError, CycleErrorHandling, DepNodeIndex, QueryContext, QueryState}; pub type HashResult = Option, &V) -> Fingerprint>; +/// Unambiguous shorthand for `::DepContext`. +#[expect(type_alias_bounds)] +type DepContextOf = + <::Qcx as HasDepContext>::DepContext; + /// Trait that can be used as a vtable for a single query, providing operations /// and metadata for that query. /// @@ -20,12 +25,15 @@ pub type HashResult = Option, &V) -> Fingerp /// Those types are not visible from this `rustc_query_system` crate. /// /// "Dispatcher" should be understood as a near-synonym of "vtable". -pub trait QueryDispatcher: Copy { +pub trait QueryDispatcher: Copy { fn name(self) -> &'static str; + /// Query context used by this dispatcher, i.e. `rustc_query_impl::QueryCtxt`. + type Qcx: QueryContext; + // `Key` and `Value` are `Copy` instead of `Clone` to ensure copying them stays cheap, // but it isn't necessary. - type Key: DepNodeParams + Eq + Hash + Copy + Debug; + type Key: DepNodeParams> + Eq + Hash + Copy + Debug; type Value: Copy; type Cache: QueryCache; @@ -33,36 +41,40 @@ pub trait QueryDispatcher: Copy { fn format_value(self) -> fn(&Self::Value) -> String; // Don't use this method to access query results, instead use the methods on TyCtxt - fn query_state<'a>(self, tcx: Qcx) -> &'a QueryState - where - Qcx: 'a; + fn query_state<'a>( + self, + tcx: Self::Qcx, + ) -> &'a QueryState::QueryInfo>; // Don't use this method to access query results, instead use the methods on TyCtxt - fn query_cache<'a>(self, tcx: Qcx) -> &'a Self::Cache - where - Qcx: 'a; + fn query_cache<'a>(self, tcx: Self::Qcx) -> &'a Self::Cache; - fn cache_on_disk(self, tcx: Qcx::DepContext, key: &Self::Key) -> bool; + fn cache_on_disk(self, tcx: DepContextOf, key: &Self::Key) -> bool; // Don't use this method to compute query results, instead use the methods on TyCtxt - fn execute_query(self, tcx: Qcx::DepContext, k: Self::Key) -> Self::Value; + fn execute_query(self, tcx: DepContextOf, k: Self::Key) -> Self::Value; - fn compute(self, tcx: Qcx, key: Self::Key) -> Self::Value; + fn compute(self, tcx: Self::Qcx, key: Self::Key) -> Self::Value; fn try_load_from_disk( self, - tcx: Qcx, + tcx: Self::Qcx, key: &Self::Key, prev_index: SerializedDepNodeIndex, index: DepNodeIndex, ) -> Option; - fn loadable_from_disk(self, qcx: Qcx, key: &Self::Key, idx: SerializedDepNodeIndex) -> bool; + fn loadable_from_disk( + self, + qcx: Self::Qcx, + key: &Self::Key, + idx: SerializedDepNodeIndex, + ) -> bool; /// Synthesize an error value to let compilation continue after a cycle. fn value_from_cycle_error( self, - tcx: Qcx::DepContext, + tcx: DepContextOf, cycle_error: &CycleError, guar: ErrorGuaranteed, ) -> Self::Value; @@ -77,7 +89,7 @@ pub trait QueryDispatcher: Copy { fn hash_result(self) -> HashResult; // Just here for convenience and checking that the key matches the kind, don't override this. - fn construct_dep_node(self, tcx: Qcx::DepContext, key: &Self::Key) -> DepNode { + fn construct_dep_node(self, tcx: DepContextOf, key: &Self::Key) -> DepNode { DepNode::construct(tcx, self.dep_kind(), key) } } diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 9afad1546e9eb..7e9f83e8fe82b 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -19,7 +19,9 @@ use rustc_span::{DUMMY_SP, Span}; use tracing::instrument; use super::{QueryDispatcher, QueryStackFrameExtra}; -use crate::dep_graph::{DepContext, DepGraphData, DepNode, DepNodeIndex, DepNodeParams}; +use crate::dep_graph::{ + DepContext, DepGraphData, DepNode, DepNodeIndex, DepNodeParams, HasDepContext, +}; use crate::ich::StableHashingContext; use crate::query::caches::QueryCache; use crate::query::job::{QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryLatch, report_cycle}; @@ -124,24 +126,22 @@ where #[cold] #[inline(never)] -fn mk_cycle(query: Q, qcx: Qcx, cycle_error: CycleError) -> Q::Value +fn mk_cycle(query: Q, qcx: Q::Qcx, cycle_error: CycleError) -> Q::Value where - Q: QueryDispatcher, - Qcx: QueryContext, + Q: QueryDispatcher, { let error = report_cycle(qcx.dep_context().sess(), &cycle_error); handle_cycle_error(query, qcx, &cycle_error, error) } -fn handle_cycle_error( +fn handle_cycle_error( query: Q, - qcx: Qcx, + qcx: Q::Qcx, cycle_error: &CycleError, error: Diag<'_>, ) -> Q::Value where - Q: QueryDispatcher, - Qcx: QueryContext, + Q: QueryDispatcher, { match query.cycle_error_handling() { CycleErrorHandling::Error => { @@ -272,15 +272,14 @@ where #[cold] #[inline(never)] -fn cycle_error( +fn cycle_error( query: Q, - qcx: Qcx, + qcx: Q::Qcx, try_execute: QueryJobId, span: Span, ) -> (Q::Value, Option) where - Q: QueryDispatcher, - Qcx: QueryContext, + Q: QueryDispatcher, { // Ensure there was no errors collecting all active jobs. // We need the complete map to ensure we find a cycle to break. @@ -291,17 +290,16 @@ where } #[inline(always)] -fn wait_for_query( +fn wait_for_query( query: Q, - qcx: Qcx, + qcx: Q::Qcx, span: Span, key: Q::Key, - latch: QueryLatch, + latch: QueryLatch<::QueryInfo>, current: Option, ) -> (Q::Value, Option) where - Q: QueryDispatcher, - Qcx: QueryContext, + Q: QueryDispatcher, { // For parallel queries, we'll block and wait until the query running // in another thread has completed. Record how long we wait in the @@ -341,16 +339,15 @@ where } #[inline(never)] -fn try_execute_query( +fn try_execute_query( query: Q, - qcx: Qcx, + qcx: Q::Qcx, span: Span, key: Q::Key, dep_node: Option, ) -> (Q::Value, Option) where - Q: QueryDispatcher, - Qcx: QueryContext, + Q: QueryDispatcher, { let state = query.query_state(qcx); let key_hash = sharded::make_hash(&key); @@ -382,7 +379,7 @@ where // Drop the lock before we start executing the query drop(state_lock); - execute_job::<_, _, INCR>(query, qcx, state, key, key_hash, id, dep_node) + execute_job::(query, qcx, state, key, key_hash, id, dep_node) } Entry::Occupied(mut entry) => { match &mut entry.get_mut().1 { @@ -411,18 +408,17 @@ where } #[inline(always)] -fn execute_job( +fn execute_job( query: Q, - qcx: Qcx, - state: &QueryState, + qcx: Q::Qcx, + state: &QueryState::QueryInfo>, key: Q::Key, key_hash: u64, id: QueryJobId, dep_node: Option, ) -> (Q::Value, Option) where - Q: QueryDispatcher, - Qcx: QueryContext, + Q: QueryDispatcher, { // Use `JobOwner` so the query will be poisoned if executing it panics. let job_owner = JobOwner { state, key }; @@ -484,15 +480,14 @@ where // Fast path for when incr. comp. is off. #[inline(always)] -fn execute_job_non_incr( +fn execute_job_non_incr( query: Q, - qcx: Qcx, + qcx: Q::Qcx, key: Q::Key, job_id: QueryJobId, ) -> (Q::Value, DepNodeIndex) where - Q: QueryDispatcher, - Qcx: QueryContext, + Q: QueryDispatcher, { debug_assert!(!qcx.dep_context().dep_graph().is_fully_enabled()); @@ -521,17 +516,16 @@ where } #[inline(always)] -fn execute_job_incr( +fn execute_job_incr( query: Q, - qcx: Qcx, - dep_graph_data: &DepGraphData, + qcx: Q::Qcx, + dep_graph_data: &DepGraphData<::Deps>, key: Q::Key, mut dep_node_opt: Option, job_id: QueryJobId, ) -> (Q::Value, DepNodeIndex) where - Q: QueryDispatcher, - Qcx: QueryContext, + Q: QueryDispatcher, { if !query.anon() && !query.eval_always() { // `to_dep_node` is expensive for some `DepKind`s. @@ -577,16 +571,15 @@ where } #[inline(always)] -fn try_load_from_disk_and_cache_in_memory( +fn try_load_from_disk_and_cache_in_memory( query: Q, - dep_graph_data: &DepGraphData, - qcx: Qcx, + dep_graph_data: &DepGraphData<::Deps>, + qcx: Q::Qcx, key: &Q::Key, dep_node: &DepNode, ) -> Option<(Q::Value, DepNodeIndex)> where - Q: QueryDispatcher, - Qcx: QueryContext, + Q: QueryDispatcher, { // Note this function can be called concurrently from the same query // We must ensure that this is handled correctly. @@ -764,15 +757,14 @@ fn incremental_verify_ich_failed( /// /// Note: The optimization is only available during incr. comp. #[inline(never)] -fn ensure_must_run( +fn ensure_must_run( query: Q, - qcx: Qcx, + qcx: Q::Qcx, key: &Q::Key, check_cache: bool, ) -> (bool, Option) where - Q: QueryDispatcher, - Qcx: QueryContext, + Q: QueryDispatcher, { if query.eval_always() { return (true, None); @@ -817,27 +809,25 @@ pub enum QueryMode { } #[inline(always)] -pub fn get_query_non_incr(query: Q, qcx: Qcx, span: Span, key: Q::Key) -> Q::Value +pub fn get_query_non_incr(query: Q, qcx: Q::Qcx, span: Span, key: Q::Key) -> Q::Value where - Q: QueryDispatcher, - Qcx: QueryContext, + Q: QueryDispatcher, { debug_assert!(!qcx.dep_context().dep_graph().is_fully_enabled()); - ensure_sufficient_stack(|| try_execute_query::(query, qcx, span, key, None).0) + ensure_sufficient_stack(|| try_execute_query::(query, qcx, span, key, None).0) } #[inline(always)] -pub fn get_query_incr( +pub fn get_query_incr( query: Q, - qcx: Qcx, + qcx: Q::Qcx, span: Span, key: Q::Key, mode: QueryMode, ) -> Option where - Q: QueryDispatcher, - Qcx: QueryContext, + Q: QueryDispatcher, { debug_assert!(qcx.dep_context().dep_graph().is_fully_enabled()); @@ -851,19 +841,17 @@ where None }; - let (result, dep_node_index) = ensure_sufficient_stack(|| { - try_execute_query::<_, _, true>(query, qcx, span, key, dep_node) - }); + let (result, dep_node_index) = + ensure_sufficient_stack(|| try_execute_query::(query, qcx, span, key, dep_node)); if let Some(dep_node_index) = dep_node_index { qcx.dep_context().dep_graph().read_index(dep_node_index) } Some(result) } -pub fn force_query(query: Q, qcx: Qcx, key: Q::Key, dep_node: DepNode) +pub fn force_query(query: Q, qcx: Q::Qcx, key: Q::Key, dep_node: DepNode) where - Q: QueryDispatcher, - Qcx: QueryContext, + Q: QueryDispatcher, { // We may be concurrently trying both execute and force a query. // Ensure that only one of them runs the query. @@ -875,6 +863,6 @@ where debug_assert!(!query.anon()); ensure_sufficient_stack(|| { - try_execute_query::<_, _, true>(query, qcx, DUMMY_SP, key, Some(dep_node)) + try_execute_query::(query, qcx, DUMMY_SP, key, Some(dep_node)) }); } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index e06ca59771e61..f0dffd8829da3 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -60,7 +60,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - /// Create a name definitinon from the given components, and put it into the local module. + /// Create a name definition from the given components, and put it into the local module. fn define_local( &mut self, parent: Module<'ra>, @@ -76,7 +76,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.plant_decl_into_local_module(ident, orig_ident.span, ns, decl); } - /// Create a name definitinon from the given components, and put it into the extern module. + /// Create a name definition from the given components, and put it into the extern module. fn define_extern( &self, parent: Module<'ra>, diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 6cab5728a2818..3889fca30bc87 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -854,7 +854,6 @@ impl LinkedList { /// # Examples /// /// ``` - /// #![feature(push_mut)] /// use std::collections::LinkedList; /// /// let mut dl = LinkedList::from([1, 2, 3]); @@ -863,7 +862,7 @@ impl LinkedList { /// *ptr += 4; /// assert_eq!(dl.front().unwrap(), &6); /// ``` - #[unstable(feature = "push_mut", issue = "135974")] + #[stable(feature = "push_mut", since = "CURRENT_RUSTC_VERSION")] #[must_use = "if you don't need a reference to the value, use `LinkedList::push_front` instead"] pub fn push_front_mut(&mut self, elt: T) -> &mut T { let mut node = @@ -926,7 +925,6 @@ impl LinkedList { /// # Examples /// /// ``` - /// #![feature(push_mut)] /// use std::collections::LinkedList; /// /// let mut dl = LinkedList::from([1, 2, 3]); @@ -935,7 +933,7 @@ impl LinkedList { /// *ptr += 4; /// assert_eq!(dl.back().unwrap(), &6); /// ``` - #[unstable(feature = "push_mut", issue = "135974")] + #[stable(feature = "push_mut", since = "CURRENT_RUSTC_VERSION")] #[must_use = "if you don't need a reference to the value, use `LinkedList::push_back` instead"] pub fn push_back_mut(&mut self, elt: T) -> &mut T { let mut node = diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index c51317a1a68f7..eda29db442572 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -2168,7 +2168,6 @@ impl VecDeque { /// # Examples /// /// ``` - /// #![feature(push_mut)] /// use std::collections::VecDeque; /// /// let mut d = VecDeque::from([1, 2, 3]); @@ -2176,7 +2175,7 @@ impl VecDeque { /// *x -= 1; /// assert_eq!(d.front(), Some(&7)); /// ``` - #[unstable(feature = "push_mut", issue = "135974")] + #[stable(feature = "push_mut", since = "CURRENT_RUSTC_VERSION")] #[must_use = "if you don't need a reference to the value, use `VecDeque::push_front` instead"] pub fn push_front_mut(&mut self, value: T) -> &mut T { if self.is_full() { @@ -2212,7 +2211,6 @@ impl VecDeque { /// # Examples /// /// ``` - /// #![feature(push_mut)] /// use std::collections::VecDeque; /// /// let mut d = VecDeque::from([1, 2, 3]); @@ -2220,7 +2218,7 @@ impl VecDeque { /// *x += 1; /// assert_eq!(d.back(), Some(&10)); /// ``` - #[unstable(feature = "push_mut", issue = "135974")] + #[stable(feature = "push_mut", since = "CURRENT_RUSTC_VERSION")] #[must_use = "if you don't need a reference to the value, use `VecDeque::push_back` instead"] pub fn push_back_mut(&mut self, value: T) -> &mut T { if self.is_full() { @@ -2419,7 +2417,6 @@ impl VecDeque { /// # Examples /// /// ``` - /// #![feature(push_mut)] /// use std::collections::VecDeque; /// /// let mut vec_deque = VecDeque::from([1, 2, 3]); @@ -2428,7 +2425,7 @@ impl VecDeque { /// *x += 7; /// assert_eq!(vec_deque, &[1, 12, 2, 3]); /// ``` - #[unstable(feature = "push_mut", issue = "135974")] + #[stable(feature = "push_mut", since = "CURRENT_RUSTC_VERSION")] #[must_use = "if you don't need a reference to the value, use `VecDeque::insert` instead"] pub fn insert_mut(&mut self, index: usize, value: T) -> &mut T { assert!(index <= self.len(), "index out of bounds"); diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index aaf22e80ec601..6cbe89d9da4f2 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1003,9 +1003,6 @@ const impl Vec { /// # Examples /// /// ``` - /// #![feature(push_mut)] - /// - /// /// let mut vec = vec![1, 2]; /// let last = vec.push_mut(3); /// assert_eq!(*last, 3); @@ -1023,7 +1020,7 @@ const impl Vec { /// vector's elements to a larger allocation. This expensive operation is /// offset by the *capacity* *O*(1) insertions it allows. #[inline] - #[unstable(feature = "push_mut", issue = "135974")] + #[stable(feature = "push_mut", since = "CURRENT_RUSTC_VERSION")] #[must_use = "if you don't need a reference to the value, use `Vec::push` instead"] pub fn push_mut(&mut self, value: T) -> &mut T { // Inform codegen that the length does not change across grow_one(). @@ -2196,7 +2193,6 @@ impl Vec { /// # Examples /// /// ``` - /// #![feature(push_mut)] /// let mut vec = vec![1, 3, 5, 9]; /// let x = vec.insert_mut(3, 6); /// *x += 1; @@ -2210,7 +2206,7 @@ impl Vec { /// the insertion index is 0. #[cfg(not(no_global_oom_handling))] #[inline] - #[unstable(feature = "push_mut", issue = "135974")] + #[stable(feature = "push_mut", since = "CURRENT_RUSTC_VERSION")] #[track_caller] #[must_use = "if you don't need a reference to the value, use `Vec::insert` instead"] pub fn insert_mut(&mut self, index: usize, element: T) -> &mut T { @@ -2689,7 +2685,6 @@ impl Vec { /// Takes *O*(1) time. #[inline] #[unstable(feature = "vec_push_within_capacity", issue = "100486")] - // #[unstable(feature = "push_mut", issue = "135974")] pub fn push_within_capacity(&mut self, value: T) -> Result<&mut T, T> { if self.len == self.buf.capacity() { return Err(value); diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 00b71f9a997c4..2566d1471ab7f 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1386,6 +1386,43 @@ impl *const T { pub const fn cast_uninit(self) -> *const MaybeUninit { self as _ } + + /// Forms a raw slice from a pointer and a length. + /// + /// The `len` argument is the number of **elements**, not the number of bytes. + /// + /// This function is safe, but actually using the return value is unsafe. + /// See the documentation of [`slice::from_raw_parts`] for slice safety requirements. + /// + /// [`slice::from_raw_parts`]: crate::slice::from_raw_parts + /// + /// # Examples + /// + /// ```rust + /// #![feature(ptr_cast_slice)] + /// // create a slice pointer when starting out with a pointer to the first element + /// let x = [5, 6, 7]; + /// let raw_pointer = x.as_ptr(); + /// let slice = raw_pointer.cast_slice(3); + /// assert_eq!(unsafe { &*slice }[2], 7); + /// ``` + /// + /// You must ensure that the pointer is valid and not null before dereferencing + /// the raw slice. A slice reference must never have a null pointer, even if it's empty. + /// + /// ```rust,should_panic + /// #![feature(ptr_cast_slice)] + /// use std::ptr; + /// let danger: *const [u8] = ptr::null::().cast_slice(0); + /// unsafe { + /// danger.as_ref().expect("references must not be null"); + /// } + /// ``` + #[inline] + #[unstable(feature = "ptr_cast_slice", issue = "149103")] + pub const fn cast_slice(self, len: usize) -> *const [T] { + slice_from_raw_parts(self, len) + } } impl *const MaybeUninit { /// Casts from a maybe-uninitialized type to its initialized version. diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 11e0a83bd7ec0..20e71bc2a1a56 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1655,6 +1655,51 @@ impl *mut T { pub const fn cast_uninit(self) -> *mut MaybeUninit { self as _ } + + /// Forms a raw mutable slice from a pointer and a length. + /// + /// The `len` argument is the number of **elements**, not the number of bytes. + /// + /// Performs the same functionality as [`cast_slice`] on a `*const T`, except that a + /// raw mutable slice is returned, as opposed to a raw immutable slice. + /// + /// This function is safe, but actually using the return value is unsafe. + /// See the documentation of [`slice::from_raw_parts_mut`] for slice safety requirements. + /// + /// [`slice::from_raw_parts_mut`]: crate::slice::from_raw_parts_mut + /// [`cast_slice`]: pointer::cast_slice + /// + /// # Examples + /// + /// ```rust + /// #![feature(ptr_cast_slice)] + /// + /// let x = &mut [5, 6, 7]; + /// let slice = x.as_mut_ptr().cast_slice(3); + /// + /// unsafe { + /// (*slice)[2] = 99; // assign a value at an index in the slice + /// }; + /// + /// assert_eq!(unsafe { &*slice }[2], 99); + /// ``` + /// + /// You must ensure that the pointer is valid and not null before dereferencing + /// the raw slice. A slice reference must never have a null pointer, even if it's empty. + /// + /// ```rust,should_panic + /// #![feature(ptr_cast_slice)] + /// use std::ptr; + /// let danger: *mut [u8] = ptr::null_mut::().cast_slice(0); + /// unsafe { + /// danger.as_mut().expect("references must not be null"); + /// } + /// ``` + #[inline] + #[unstable(feature = "ptr_cast_slice", issue = "149103")] + pub const fn cast_slice(self, len: usize) -> *mut [T] { + slice_from_raw_parts_mut(self, len) + } } impl *mut MaybeUninit { /// Casts from a maybe-uninitialized type to its initialized version. diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index cb43d095f5d1a..7b9e638289bf0 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -1377,6 +1377,35 @@ impl NonNull { pub const fn cast_uninit(self) -> NonNull> { self.cast() } + + /// Creates a non-null raw slice from a thin pointer and a length. + /// + /// The `len` argument is the number of **elements**, not the number of bytes. + /// + /// This function is safe, but dereferencing the return value is unsafe. + /// See the documentation of [`slice::from_raw_parts`] for slice safety requirements. + /// + /// # Examples + /// + /// ```rust + /// #![feature(ptr_cast_slice)] + /// use std::ptr::NonNull; + /// + /// // create a slice pointer when starting out with a pointer to the first element + /// let mut x = [5, 6, 7]; + /// let nonnull_pointer = NonNull::new(x.as_mut_ptr()).unwrap(); + /// let slice = nonnull_pointer.cast_slice(3); + /// assert_eq!(unsafe { slice.as_ref()[2] }, 7); + /// ``` + /// + /// (Note that this example artificially demonstrates a use of this method, + /// but `let slice = NonNull::from(&x[..]);` would be a better way to write code like this.) + #[inline] + #[must_use] + #[unstable(feature = "ptr_cast_slice", issue = "149103")] + pub const fn cast_slice(self, len: usize) -> NonNull<[T]> { + NonNull::slice_from_raw_parts(self, len) + } } impl NonNull> { /// Casts from a maybe-uninitialized type to its initialized version. diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 5c068ad2471ad..615b767a4ea5a 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -728,7 +728,7 @@ pub fn temp_dir() -> PathBuf { /// /// You expected to safely execute the current executable, but you're /// instead executing something completely different. The code you -/// just executed run with your privileges. +/// just executed runs with your privileges. /// /// This sort of behavior has been known to [lead to privilege escalation] when /// used incorrectly. diff --git a/src/ci/citool/Cargo.toml b/src/ci/citool/Cargo.toml index b394c6fbefffc..c2a926b3eaef5 100644 --- a/src/ci/citool/Cargo.toml +++ b/src/ci/citool/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] anyhow = "1" -askama = "0.15.2" +askama = "0.15.3" clap = { version = "4.5", features = ["derive"] } csv = "1" diff = "0.1" diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 43006435fcdee..efc44a8a2d51f 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" [dependencies] # tidy-alphabetical-start arrayvec = { version = "0.7", default-features = false } -askama = { version = "0.15.2", default-features = false, features = ["alloc", "config", "derive"] } +askama = { version = "0.15.3", default-features = false, features = ["alloc", "config", "derive"] } base64 = "0.21.7" indexmap = { version = "2", features = ["serde"] } itertools = "0.12" diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css index 6f44854b6914e..363cec3116a96 100644 --- a/src/librustdoc/html/static/css/noscript.css +++ b/src/librustdoc/html/static/css/noscript.css @@ -163,7 +163,7 @@ nav.sub { --headings-border-bottom-color: #d2d2d2; --border-color: #e0e0e0; --button-background-color: #f0f0f0; - --right-side-color: grey; + --right-side-color: #d0d0d0; --code-attribute-color: #999; --toggles-color: #999; --toggle-filter: invert(100%); diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 6c34d31cc918c..9e47f80a7fe24 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -359,7 +359,8 @@ summary.hideme, .rustdoc-breadcrumbs, .search-switcher, /* This selector is for the items listed in the "all items" page. */ -ul.all-items { +ul.all-items, +.deprecated-count { font-family: "Fira Sans", Arial, NanumBarunGothic, sans-serif; } @@ -2671,6 +2672,18 @@ However, it's not needed with smaller screen width because the doc/code block is display: none; } +.deprecated-count { + display: none; +} +/* +The `:not(:empty)` is a little trick to not have to add conditions in JS to hide/show the marker. +It's entirely based on whether it has content and if the setting is enabled. +*/ +.hide-deprecated-items .deprecated-count:not(:empty) { + display: block; + margin: 10px 0; +} + /* WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY If you update this line, then you also need to update the line with the same warning @@ -3286,7 +3299,7 @@ by default. --headings-border-bottom-color: #d2d2d2; --border-color: #e0e0e0; --button-background-color: #f0f0f0; - --right-side-color: grey; + --right-side-color: #d0d0d0; --code-attribute-color: #999; --toggles-color: #999; --toggle-filter: invert(100%); diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 9961c1447ec2a..55ff48846dcb3 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -158,6 +158,7 @@ const REGEX_INVALID_TYPE_FILTER = /[^a-z]/ui; const MAX_RESULTS = 200; const NO_TYPE_FILTER = -1; +const DEPRECATED_COUNT_SELECTOR = "deprecated-count"; /** * The [edit distance] is a metric for measuring the difference between two strings. @@ -4904,7 +4905,12 @@ async function addTab(results, query, display, finishedCallback, isTypeSearch) { let output = document.createElement("ul"); output.className = "search-results " + extraClass; + const deprecatedCountElem = document.createElement("span"); + deprecatedCountElem.className = DEPRECATED_COUNT_SELECTOR; + output.appendChild(deprecatedCountElem); + let count = 0; + let deprecatedCount = 0; /** @type {Promise[]} */ const descList = []; @@ -4922,6 +4928,10 @@ async function addTab(results, query, display, finishedCallback, isTypeSearch) { link.className = "result-" + type; if (obj.item.deprecated) { link.className += " deprecated"; + deprecatedCount += 1; + const plural = deprecatedCount > 1 ? "s" : ""; + deprecatedCountElem.innerText = + `${deprecatedCount} deprecated item${plural} hidden by setting`; } link.href = obj.href; @@ -5411,7 +5421,7 @@ function registerSearchEvents() { const active = document.activeElement; if (active) { const previous = active.previousElementSibling; - if (previous) { + if (previous && previous.className !== DEPRECATED_COUNT_SELECTOR) { // @ts-expect-error previous.focus(); } else { diff --git a/src/tools/generate-copyright/Cargo.toml b/src/tools/generate-copyright/Cargo.toml index e1a5ca31a1db6..965f7f992e758 100644 --- a/src/tools/generate-copyright/Cargo.toml +++ b/src/tools/generate-copyright/Cargo.toml @@ -8,7 +8,7 @@ description = "Produces a manifest of all the copyrighted materials in the Rust [dependencies] anyhow = "1.0.65" -askama = "0.15.2" +askama = "0.15.3" cargo_metadata = "0.21" serde = { version = "1.0.147", features = ["derive"] } serde_json = "1.0.85" diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 94c24f11ed12f..0d9a22556dfa9 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -32,6 +32,7 @@ fn main() { let npm: PathBuf = env::args_os().nth(5).expect("need name/path of npm command").into(); let root_manifest = root_path.join("Cargo.toml"); + let typos_toml = root_path.join("typos.toml"); let src_path = root_path.join("src"); let tests_path = root_path.join("tests"); let library_path = root_path.join("library"); @@ -143,6 +144,7 @@ fn main() { check!(edition, &library_path); check!(alphabetical, &root_manifest); + check!(alphabetical, &typos_toml); check!(alphabetical, &src_path); check!(alphabetical, &tests_path); check!(alphabetical, &compiler_path); diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index bf51810810a6c..b5643034d45c5 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -73,6 +73,57 @@ pub fn check(root_path: &Path, tidy_ctx: TidyCtx) { )); } } + + // The list of subdirectories in ui tests. + // Compare previous subdirectory with current subdirectory + // to sync with `tests/ui/README.md`. + // See + let mut prev_line = String::new(); + let mut is_sorted = true; + let documented_subdirs: BTreeSet<_> = include_str!("../../../../tests/ui/README.md") + .lines() + .filter_map(|line| { + static_regex!(r"^##.*?`(?[^`]+)`").captures(line).map(|cap| { + let dir = &cap["dir"]; + // FIXME(reddevilmidzy) normalize subdirs title in tests/ui/README.md + if dir.ends_with('/') { + dir.strip_suffix('/').unwrap().to_string() + } else { + dir.to_string() + } + }) + }) + .inspect(|line| { + if prev_line.as_str() > line.as_str() { + is_sorted = false; + } + + prev_line = line.clone(); + }) + .collect(); + let filesystem_subdirs = collect_ui_tests_subdirs(&path); + let is_modified = !filesystem_subdirs.eq(&documented_subdirs); + + if !is_sorted { + check.error("`tests/ui/README.md` is not in order"); + } + if is_modified { + for directory in documented_subdirs.symmetric_difference(&filesystem_subdirs) { + if documented_subdirs.contains(directory) { + check.error(format!( + "ui subdirectory `{directory}` is listed in `tests/ui/README.md` but does not exist in the filesystem" + )); + } else { + check.error(format!( + "ui subdirectory `{directory}` exists in the filesystem but is not documented in `tests/ui/README.md`" + )); + } + } + check.error( + "`tests/ui/README.md` subdirectory listing is out of sync with the filesystem. \ + Please add or remove subdirectory entries (## headers with backtick-wrapped names) to match the actual directories in `tests/ui/`" + ); + } } fn deny_new_top_level_ui_tests(check: &mut RunningCheck, tests_path: &Path) { @@ -137,6 +188,24 @@ fn recursively_check_ui_tests<'issues>( remaining_issue_names } +fn collect_ui_tests_subdirs(path: &Path) -> BTreeSet { + let ui = path.join("ui"); + let entries = std::fs::read_dir(ui.as_path()).unwrap(); + + entries + .filter_map(|entry| entry.ok()) + .map(|entry| entry.path()) + .filter(|path| path.is_dir()) + .map(|dir_path| { + let dir_path = dir_path.strip_prefix(path).unwrap(); + format!( + "tests/{}", + dir_path.to_string_lossy().replace(std::path::MAIN_SEPARATOR_STR, "/") + ) + }) + .collect() +} + fn check_unexpected_extension(check: &mut RunningCheck, file_path: &Path, ext: &str) { const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/rustdoc-gui/headings.goml b/tests/rustdoc-gui/headings.goml index 94d80a3e3df5f..391234b78ebd3 100644 --- a/tests/rustdoc-gui/headings.goml +++ b/tests/rustdoc-gui/headings.goml @@ -221,14 +221,14 @@ call-function: ( define-function: ( "check-since-color", - [theme], + [theme, color], block { call-function: ("switch-theme", {"theme": |theme|}) - assert-css: (".since", {"color": "#808080"}, ALL) + assert-css: (".since", {"color": |color|}, ALL) }, ) go-to: "file://" + |DOC_PATH| + "/staged_api/struct.Foo.html" -call-function: ("check-since-color", {"theme": "ayu"}) -call-function: ("check-since-color", {"theme": "dark"}) -call-function: ("check-since-color", {"theme": "light"}) +call-function: ("check-since-color", {"theme": "ayu", "color": "#808080"}) +call-function: ("check-since-color", {"theme": "dark", "color": "#d0d0d0"}) +call-function: ("check-since-color", {"theme": "light", "color": "#808080"}) diff --git a/tests/rustdoc-gui/setting-hide-deprecated.goml b/tests/rustdoc-gui/setting-hide-deprecated.goml index 6dc5a6bff175d..0fefe00f9457b 100644 --- a/tests/rustdoc-gui/setting-hide-deprecated.goml +++ b/tests/rustdoc-gui/setting-hide-deprecated.goml @@ -69,7 +69,7 @@ wait-for-css: ("details" + |deprecated_class|, {"display": "block"}, ALL) // And now we check with the search results. call-function: ("perform-search", {"query": "deprecated::depr"}) -// There should at least 7 results. +// There should be at least 7 results. store-count: ("#results ul.search-results.active > a", nb_search_results) assert: |nb_search_results| >= 7 // There should be at least 5 deprecated items. @@ -77,6 +77,12 @@ store-count: ("#results ul.search-results.active > a" + |deprecated_class|, nb_d assert: |nb_search_results| >= 5 // Deprecated items should all be displayed. assert-css: ("#results ul.search-results.active > a" + |deprecated_class|, {"display": "grid"}, ALL) +// The "X deprecated items hidden by setting" element should not be displayed. +assert-text: ( + "#results ul.search-results.active .deprecated-count", + "5 deprecated items hidden by setting", +) +assert-css: ("#results ul.search-results.active .deprecated-count", {"display": "none"}) // We enable the "hide deprecated items" setting. call-function: ("open-settings-menu", {}) click: "#hide-deprecated-items" @@ -86,11 +92,16 @@ wait-for-css: ( {"display": "none"}, ALL, ) +// The "X deprecated items hidden by setting" element should be displayed. +assert-css: ("#results ul.search-results.active .deprecated-count", {"display": "block"}) // Finally we check that the future deprecated item doesn't have the deprecated class in the search -// and therefore isn't impact by the setting. -call-function: ("perform-search", {"query": "deprecated::future_deprecated"}) +// and therefore isn't impacted by the setting. +call-function: ("perform-search", {"query": '"future_deprecated_fn"'}) assert-text: ( "#results ul.search-results.active > a:not(" + |deprecated_class| + ") .path", " lib2::deprecated::NonDeprecatedStruct::future_deprecated_fn", ) +// The "X deprecated items hidden by setting" element should now be empty, and therefore not displayed. +assert-text: ("#results ul.search-results.active .deprecated-count", "") +assert-css: ("#results ul.search-results.active .deprecated-count", {"display": "none"}) diff --git a/tests/ui/README.md b/tests/ui/README.md index 4c91f313a7351..237cfb9c4f071 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -10,17 +10,23 @@ These tests deal with *Application Binary Interfaces* (ABI), mostly relating to Tests for unsupported ABIs can be made cross-platform by using the `extern "rust-invalid"` ABI, which is considered unsupported on every platform. +## `tests/ui/alloc-error` + +These tests exercise alloc error handling. + +See . + ## `tests/ui/allocator` These tests exercise `#![feature(allocator_api)]` and the `#[global_allocator]` attribute. See [Allocator traits and `std::heap` #32838](https://github.com/rust-lang/rust/issues/32838). -## `tests/ui/alloc-error` +## `tests/ui/annotate-moves` -These tests exercise alloc error handling. +These tests exercise the `annotate-moves` feature. -See . +See [`annotate-moves` | The Unstable book](https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/annotate-moves.html) ## `tests/ui/annotate-snippet` @@ -34,20 +40,26 @@ These tests exercise the [`annotate-snippets`]-based emitter implementation. These tests deal with anonymous parameters (no name, only type), a deprecated feature that becomes a hard error in Edition 2018. +## `tests/ui/any` + +These tests exercise the `try_as_dyn` feature. + +See [`core::any::try_as_dyn`](https://doc.rust-lang.org/nightly/core/any/fn.try_as_dyn.html) + ## `tests/ui/argfile`: External files providing command line arguments These tests exercise rustc reading command line arguments from an externally provided argfile (`@argsfile`). See [Implement `@argsfile` to read arguments from command line #63576](https://github.com/rust-lang/rust/issues/63576). -## `tests/ui/array-slice-vec`: Arrays, slices and vectors - -Exercises various aspects surrounding basic collection types `[]`, `&[]` and `Vec`. E.g. type-checking, out-of-bounds indices, attempted instructions which are allowed in other programming languages, and more. - ## `tests/ui/argument-suggestions`: Argument suggestions Calling a function with the wrong number of arguments causes a compilation failure, but the compiler is able to, in some cases, provide suggestions on how to fix the error, such as which arguments to add or delete. These tests exercise the quality of such diagnostics. +## `tests/ui/array-slice-vec`: Arrays, slices and vectors + +Exercises various aspects surrounding basic collection types `[]`, `&[]` and `Vec`. E.g. type-checking, out-of-bounds indices, attempted instructions which are allowed in other programming languages, and more. + ## `tests/ui/asm`: `asm!` macro These tests exercise the `asm!` macro, which is used for adding inline assembly. @@ -172,6 +184,10 @@ See [RFC 3729: Hierarchy of Sized traits](https://github.com/rust-lang/rfcs/pull Defining custom auto traits with the `auto` keyword belongs to `tests/ui/auto-traits/` instead. +## `tests/ui/c-variadic`: C Variadic Function + +Tests for FFI with C varargs (`va_list`). + ## `tests/ui/cast/`: Type Casting Tests for type casting using the `as` operator. Includes tests for valid/invalid casts between primitive types, trait objects, and custom types. For example, check that trying to cast `i32` into `bool` results in a helpful error message. @@ -190,16 +206,16 @@ Tests for the `--check-cfg` compiler mechanism for checking cfg configurations, See [Checking conditional configurations | The rustc book](https://doc.rust-lang.org/rustc/check-cfg.html). -## `tests/ui/closure_context/`: Closure type inference in context - -Tests for closure type inference with respect to surrounding scopes, mostly quality of diagnostics. - ## `tests/ui/closure-expected-type/`: Closure type inference Tests targeted at how we deduce the types of closure arguments. This process is a result of some heuristics which take into account the *expected type* we have alongside the *actual types* that we get from inputs. **FIXME**: Appears to have significant overlap with `tests/ui/closure_context` and `tests/ui/functions-closures/closure-expected-type`. Needs further investigation. +## `tests/ui/closure_context`: Closure type inference in context + +Tests for closure type inference with respect to surrounding scopes, mostly quality of diagnostics. + ## `tests/ui/closures/`: General Closure Tests Any closure-focused tests that does not fit in the other more specific closure subdirectories belong here. E.g. syntax, `move`, lifetimes. @@ -244,6 +260,14 @@ See: This directory only contains one highly specific test. Other coinduction tests can be found down the deeply located `tests/ui/traits/next-solver/cycles/coinduction/` subdirectory. +## `tests/ui/collections` + +These tests exercise the `collections` library. + +See [`std::collections`](https://doc.rust-lang.org/std/collections/index.html) + +**FIXME**: consider merge with `tests/ui/btreemap` and `tests/ui/hashmap` + ## `tests/ui/command/`: `std::process::Command` This directory is actually for the standard library [`std::process::Command`](https://doc.rust-lang.org/std/process/struct.Command.html) type, where some tests are too difficult or inconvenient to write as unit tests or integration tests within the standard library itself. @@ -285,10 +309,6 @@ See: - [Tracking Issue for complex generic constants: `feature(generic_const_exprs)` #76560](https://github.com/rust-lang/rust/issues/76560) - [Const generics | Reference](https://doc.rust-lang.org/reference/items/generics.html#const-generics) -## `tests/ui/const_prop/`: Constant Propagation - -Tests exercising `ConstProp` mir-opt pass (mostly regression tests). See . - ## `tests/ui/const-ptr/`: Constant Pointers Tests exercise const raw pointers. E.g. pointer arithmetic, casting and dereferencing, always with a `const`. @@ -299,6 +319,10 @@ See: - [`std::ptr`](https://doc.rust-lang.org/std/ptr/index.html) - [Pointer types | Reference](https://doc.rust-lang.org/reference/types/pointer.html) +## `tests/ui/const_prop`: Constant Propagation + +Tests exercising `ConstProp` mir-opt pass (mostly regression tests). See . + ## `tests/ui/consts/`: General Constant Evaluation Anything to do with constants, which does not fit in the previous two `const` categories, goes here. This does not always imply use of the `const` keyword - other values considered constant, such as defining an enum variant as `enum Foo { Variant = 5 }` also counts. @@ -340,10 +364,6 @@ Tests for `#[bench]`, `#[test_case]` attributes and the `custom_test_frameworks` See [Tracking issue for eRFC 2318, Custom test frameworks #50297](https://github.com/rust-lang/rust/issues/50297). -## `tests/ui/c-variadic/`: C Variadic Function - -Tests for FFI with C varargs (`va_list`). - ## `tests/ui/cycle-trait/`: Trait Cycle Detection Tests for detection and handling of cyclic trait dependencies. @@ -380,6 +400,18 @@ These tests use the unstable command line option `query-dep-graph` to examine th Tests for `#[deprecated]` attribute and `deprecated_in_future` internal lint. +## `tests/ui/deref` + +Tests for `Deref` and `DerefMut` traits. + +## `tests/ui/deref-patterns`: `#![feature(deref_patterns)]` and `#![feature(string_deref_patterns)]` + +Tests for `#![feature(deref_patterns)]` and `#![feature(string_deref_patterns)]`. See [Deref patterns | The Unstable book](https://doc.rust-lang.org/nightly/unstable-book/language-features/deref-patterns.html). + +**FIXME**: May have some overlap with `tests/ui/pattern/deref-patterns`. + +See [`std::ops::Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html) and [`std::ops::DerefMut`](https://doc.rust-lang.org/std/ops/trait.DerefMut.html) + ## `tests/ui/derived-errors/`: Derived Error Messages Tests for quality of diagnostics involving suppression of cascading errors in some cases to avoid overwhelming the user. @@ -406,6 +438,10 @@ These tests revolve around command-line flags which change the way error/warning **FIXME**: Check redundancy with `annotate-snippet`, which is another emitter. +## `tests/ui/diagnostic-width`: `--diagnostic-width` + +Everything to do with `--diagnostic-width`. + ## `tests/ui/diagnostic_namespace/` Exercises `#[diagnostic::*]` namespaced attributes. See [RFC 3368 Diagnostic attribute namespace](https://github.com/rust-lang/rfcs/blob/master/text/3368-diagnostic-attribute-namespace.md). @@ -414,10 +450,6 @@ Exercises `#[diagnostic::*]` namespaced attributes. See [RFC 3368 Diagnostic att This directory contains tests and infrastructure related to the diagnostics system, including support for translatable diagnostics -## `tests/ui/diagnostic-width/`: `--diagnostic-width` - -Everything to do with `--diagnostic-width`. - ## `tests/ui/did_you_mean/` Tests for miscellaneous suggestions. @@ -430,6 +462,10 @@ Exercises diagnostics for when a code block attempts to gain ownership of a non- Exercises diagnostics for disallowed struct destructuring. +## `tests/ui/dist` + +Tests that require distribution artifacts. + ## `tests/ui/dollar-crate/`: `$crate` used with the `use` keyword There are a few rules - which are checked in this directory - to follow when using `$crate` - it must be used in the start of a `use` line and is a reserved identifier. @@ -461,10 +497,6 @@ Tests for dynamically-sized types (DSTs). See [Dynamically Sized Types | Referen Tests about duplicated symbol names and associated errors, such as using the `#[export_name]` attribute to rename a function with the same name as another function. -## `tests/ui/dynamically-sized-types/`: Dynamically Sized Types - -**FIXME**: should be coalesced with `tests/ui/dst`. - ## `tests/ui/dyn-compatibility/`: Dyn-compatibility Tests for dyn-compatibility of traits. @@ -486,12 +518,20 @@ The `dyn` keyword is used to highlight that calls to methods on the associated T See [`dyn` keyword](https://doc.rust-lang.org/std/keyword.dyn.html). +## `tests/ui/dynamically-sized-types`: Dynamically Sized Types + +**FIXME**: should be coalesced with `tests/ui/dst`. + ## `tests/ui/editions/`: Rust edition-specific peculiarities These tests run in specific Rust editions, such as Rust 2015 or Rust 2018, and check errors and functionality related to specific now-deprecated idioms and features. **FIXME**: Maybe regroup `rust-2018`, `rust-2021` and `rust-2024` under this umbrella? +## `tests/ui/eii`: Externally Implementable Items + +Exercises `eii` keyword. + ## `tests/ui/empty/`: Various tests related to the concept of "empty" **FIXME**: These tests need better homes, this is not very informative. @@ -571,6 +611,10 @@ See: - [`ffi_const` | The Unstable book](https://doc.rust-lang.org/unstable-book/language-features/ffi-const.html) - [`ffi_pure` | The Unstable book](https://doc.rust-lang.org/beta/unstable-book/language-features/ffi-pure.html) +## `tests/ui/float` + +See: [Tracking Issue for `f16` and `f128` float types #116909](https://github.com/rust-lang/rust/issues/116909) + ## `tests/ui/fmt/` Exercises the `format!` macro. @@ -579,6 +623,16 @@ Exercises the `format!` macro. A broad category of tests on functions. +## `tests/ui/fn_traits` + +Tests for `#![feature(fn_traits)]`. See [`fn_traits` | The Unstable book](https://doc.rust-lang.org/nightly/unstable-book/library-features/fn-traits.html). + +## `tests/ui/for-loop-while` + +Anything to do with loops and `for`, `loop` and `while` keywords to express them. + +**FIXME**: After `ui/for` is merged into this, also carry over its SUMMARY text. + ## `tests/ui/force-inlining/`: `#[rustc_force_inline]` Tests for `#[rustc_force_inline]`, which will force a function to always be labelled as inline by the compiler (it will be inserted at the point of its call instead of being used as a normal function call.) If the compiler is unable to inline the function, an error will be reported. See . @@ -589,12 +643,6 @@ Tests for `extern "C"` and `extern "Rust`. **FIXME**: Check for potential overlap/merge with `ui/c-variadic` and/or `ui/extern`. -## `tests/ui/for-loop-while/` - -Anything to do with loops and `for`, `loop` and `while` keywords to express them. - -**FIXME**: After `ui/for` is merged into this, also carry over its SUMMARY text. - ## `tests/ui/frontmatter/` Tests for `#![feature(frontmatter)]`. See [Tracking Issue for `frontmatter` #136889](https://github.com/rust-lang/rust/issues/136889). @@ -603,12 +651,6 @@ Tests for `#![feature(frontmatter)]`. See [Tracking Issue for `frontmatter` #136 Tests for diagnostics when there may be identically named types that need further qualifications to disambiguate. -## `tests/ui/functional-struct-update/` - -Functional Struct Update is the name for the idiom by which one can write `..` at the end of a struct literal expression to fill in all remaining fields of the struct literal by using `` as the source for them. - -See [RFC 0736 Privacy-respecting Functional Struct Update](https://github.com/rust-lang/rfcs/blob/master/text/0736-privacy-respecting-fru.md). - ## `tests/ui/function-pointer/` Tests on function pointers, such as testing their compatibility with higher-ranked trait bounds. @@ -618,6 +660,12 @@ See: - [Function pointer types | Reference](https://doc.rust-lang.org/reference/types/function-pointer.html) - [Higher-ranked trait bounds | Nomicon](https://doc.rust-lang.org/nomicon/hrtb.html) +## `tests/ui/functional-struct-update/` + +Functional Struct Update is the name for the idiom by which one can write `..` at the end of a struct literal expression to fill in all remaining fields of the struct literal by using `` as the source for them. + +See [RFC 0736 Privacy-respecting Functional Struct Update](https://github.com/rust-lang/rfcs/blob/master/text/0736-privacy-respecting-fru.md). + ## `tests/ui/functions-closures/` Tests on closures. See [Closure expressions | Reference](https://doc.rust-lang.org/reference/expressions/closure-expr.html). @@ -653,6 +701,10 @@ See: - [Higher-ranked trait bounds | rustc-dev-guide](https://rustc-dev-guide.rust-lang.org/traits/hrtb.html) - [Higher-ranked trait bounds | Nomicon](https://doc.rust-lang.org/nomicon/hrtb.html) +## `tests/ui/higher-ranked-trait-bounds` + +**FIXME**: move to `tests/ui/higher-ranked/trait-bounds` + ## `tests/ui/hygiene/` This seems to have been originally intended for "hygienic macros" - macros which work in all contexts, independent of what surrounds them. However, this category has grown into a mish-mash of many tests that may belong in the other directories. @@ -669,14 +721,14 @@ This test category revolves around trait objects with `Sized` having illegal ope Tests on lifetime elision in impl function signatures. See [Lifetime elision | Nomicon](https://doc.rust-lang.org/nomicon/lifetime-elision.html). -## `tests/ui/implied-bounds/` - -See [Implied bounds | Reference](https://doc.rust-lang.org/reference/trait-bounds.html#implied-bounds). - ## `tests/ui/impl-trait/` Tests for trait impls. +## `tests/ui/implied-bounds/` + +See [Implied bounds | Reference](https://doc.rust-lang.org/reference/trait-bounds.html#implied-bounds). + ## `tests/ui/imports/` Tests for module system and imports. @@ -802,6 +854,12 @@ Broad directory on lifetimes, including proper specifiers, lifetimes not living These tests exercises numerical limits, such as `[[u8; 1518599999]; 1518600000]`. +## `tests/ui/link-native-libs/` + +Tests for `#[link(name = "", kind = "")]` and `-l` command line flag. + +See [Tracking Issue for linking modifiers for native libraries #81490](https://github.com/rust-lang/rust/issues/81490). + ## `tests/ui/linkage-attr/` Tests for the linkage attribute `#[linkage]` of `#![feature(linkage)]`. @@ -814,12 +872,6 @@ Tests on code which fails during the linking stage, or which contain arguments a See [Linkage | Reference](https://doc.rust-lang.org/reference/linkage.html). -## `tests/ui/link-native-libs/` - -Tests for `#[link(name = "", kind = "")]` and `-l` command line flag. - -See [Tracking Issue for linking modifiers for native libraries #81490](https://github.com/rust-lang/rust/issues/81490). - ## `tests/ui/lint/` Tests for the lint infrastructure, lint levels, lint reasons, etc. @@ -835,6 +887,10 @@ Tests exercising analysis for unused variables, unreachable statements, function **FIXME**: This seems unrelated to "liveness" as defined in the rustc compiler guide. Is this misleadingly named? https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/lifetime_parameters.html#liveness-and-universal-regions +## `tests/ui/loop-match` + +Tests for `loop` with `match` expressions. + ## `tests/ui/loops/` Tests on the `loop` construct. @@ -941,6 +997,10 @@ See [RFC 3550 New Range](https://github.com/rust-lang/rfcs/blob/master/text/3550 Tests for Non-lexical lifetimes. See [RFC 2094 NLL](https://rust-lang.github.io/rfcs/2094-nll.html). +## `tests/ui/no_std/` + +Tests for where the standard library is disabled through `#![no_std]`. + ## `tests/ui/non_modrs_mods/` Despite the size of the directory, this is a single test, spawning a sprawling `mod` dependency tree and checking its successful build. @@ -953,10 +1013,6 @@ A very similar principle as `non_modrs_mods`, but with an added inline `mod` sta **FIXME**: Consider merge with `tests/ui/modules/`, keeping the directory structure. -## `tests/ui/no_std/` - -Tests for where the standard library is disabled through `#![no_std]`. - ## `tests/ui/not-panic/` Tests checking various types, such as `&RefCell`, and whether they are not `UnwindSafe` as expected. @@ -981,6 +1037,15 @@ Contains a single test. Check that we reject the ancient Rust syntax `x <- y` an **FIXME**: Definitely should be rehomed, maybe to `tests/ui/deprecation/`. +## `tests/ui/offload` + +Exercises the offload feature. + +See: + +- [`std::offload` | rustc-dev-guide](https://rustc-dev-guide.rust-lang.org/offload/internals.html) +- [Tracking Issue for GPU-offload #131513](https://github.com/rust-lang/rust/issues/131513) + ## `tests/ui/offset-of/` Exercises the [`std::mem::offset_of` macro](https://doc.rust-lang.org/beta/std/mem/macro.offset_of.html). @@ -1039,6 +1104,16 @@ Broad category of tests surrounding patterns. See [Patterns | Reference](https:/ **FIXME**: Some overlap with `tests/ui/match/`. +## `tests/ui/pin` + +**FIXME**: Consider merging with `tests/ui/pin-macro`. + +## `tests/ui/pin-ergonomics` + +Exercises the `#![feature(pin_ergonomics)]` feature. + +See [Tracking issue for pin ergonomics #130494](https://github.com/rust-lang/rust/issues/130494) + ## `tests/ui/pin-macro/` See [`std::pin`](https://doc.rust-lang.org/std/pin/). @@ -1059,6 +1134,10 @@ Exercises the `-Z print-type-sizes` flag. Exercises on name privacy. E.g. the meaning of `pub`, `pub(crate)`, etc. +## `tests/ui/proc-macro/` + +Broad category of tests on proc-macros. See [Procedural Macros | Reference](https://doc.rust-lang.org/reference/procedural-macros.html). + ## `tests/ui/process/` Some standard library process tests which are hard to write within standard library crate tests. @@ -1067,10 +1146,6 @@ Some standard library process tests which are hard to write within standard libr Some standard library process termination tests which are hard to write within standard library crate tests. -## `tests/ui/proc-macro/` - -Broad category of tests on proc-macros. See [Procedural Macros | Reference](https://doc.rust-lang.org/reference/procedural-macros.html). - ## `tests/ui/ptr_ops/`: Using operations on a pointer Contains only 2 tests, related to a single issue, which was about an error caused by using addition on a pointer to `i8`. @@ -1103,6 +1178,12 @@ Reachability tests, primarily unreachable code and coercions into the never type **FIXME**: Check for overlap with `ui/liveness`. +## `tests/ui/reborrow` + +Exercises the `#![feature(reborrow)]` feature. + +See [Tracking Issue for Reborrow trait lang experiment #145612](https://github.com/rust-lang/rust/issues/145612) + ## `tests/ui/recursion/` Broad category of tests exercising recursions (compile test and run time), in functions, macros, `type` definitions, and more. @@ -1115,6 +1196,12 @@ Sets a recursion limit on recursive code. **FIXME**: Should be merged with `tests/ui/recursion/`. +## `tests/ui/reflection/` + +Exercises the `#![feature(type_info)]` feature. + +See [Tracking Issue for type_info #146922](https://github.com/rust-lang/rust/issues/146922) + ## `tests/ui/regions/` **FIXME**: Maybe merge with `ui/lifetimes`. @@ -1157,22 +1244,44 @@ Exercises `.rmeta` crate metadata and the `--emit=metadata` cli flag. Tests for runtime environment on which Rust programs are executed. E.g. Unix `SIGPIPE`. -## `tests/ui/rust-{2018,2021,2024}/` +## `tests/ui/rust-2018` + +Tests that exercise behaviors and features specific to the Rust 2018 edition. + +## `tests/ui/rust-2021` + +Tests that exercise behaviors and features specific to the Rust 2021 edition. -Tests that exercise behaviors and features that are specific to editions. +## `tests/ui/rust-2024` + +Tests that exercise behaviors and features specific to the Rust 2024 edition. ## `tests/ui/rustc-env` Tests on environmental variables that affect `rustc`. +## `tests/ui/rustc_public-ir-print` + +Some tests for pretty printing of rustc_public's IR. + ## `tests/ui/rustdoc` Hybrid tests that exercises `rustdoc`, and also some joint `rustdoc`/`rustc` interactions. +## `tests/ui/sanitize-attr` + +Tests for the `#![feature(sanitize)]` attribute. + +See [Sanitize | The Unstable Book](https://doc.rust-lang.org/unstable-book/language-features/sanitize.html). + ## `tests/ui/sanitizer/` Exercises sanitizer support. See [Sanitizer | The rustc book](https://doc.rust-lang.org/unstable-book/compiler-flags/sanitizer.html). +## `tests/ui/scalable-vectors` + +See [Tracking Issue for Scalable Vectors #145052](https://github.com/rust-lang/rust/issues/145052) + ## `tests/ui/self/`: `self` keyword Tests with erroneous ways of using `self`, such as using `this.x` syntax as seen in other languages, having it not be the first argument, or using it in a non-associated function (no `impl` or `trait`). It also contains correct uses of `self` which have previously been observed to cause ICEs. @@ -1211,6 +1320,12 @@ This is a test directory for the specific error case where a lifetime never gets While many tests here involve the `Sized` trait directly, some instead test, for example the slight variations between returning a zero-sized `Vec` and a `Vec` with one item, where one has no known type and the other does. +## `tests/ui/sized-hierarchy` + +Tests for `#![feature(sized_hierarchy)]` attribute. + +See [Tracking Issue for Sized Hierarchy #144404](https://github.com/rust-lang/rust/issues/144404) + ## `tests/ui/span/` An assorted collection of tests that involves specific diagnostic spans. @@ -1225,9 +1340,9 @@ See [Tracking issue for specialization (RFC 1210) #31844](https://github.com/rus Stability attributes used internally by the standard library: `#[stable()]` and `#[unstable()]`. -## `tests/ui/rustc_public-ir-print/` +## `tests/ui/stack-probes` -Some tests for pretty printing of rustc_public's IR. +**FIXME**: Contains a single test, should likely be rehomed to `tests/ui/abi`. ## `tests/ui/stack-protector/`: `-Z stack-protector` command line flag @@ -1359,6 +1474,10 @@ Tests surrounding [`std::mem::transmute`](https://doc.rust-lang.org/std/mem/fn.t Exercises compiler development support flag `-Z treat-err-as-bug`. +## `tests/ui/trimmed-paths/` + +Tests for the `#[doc(hidden)]` items. + ## `tests/ui/trivial-bounds/` `#![feature(trivial_bounds)]`. See [RFC 2056 Allow trivial where clause constraints](https://github.com/rust-lang/rfcs/blob/master/text/2056-allow-trivial-where-clause-constraints.md). @@ -1393,17 +1512,13 @@ Tests for `type` aliases in the context of `enum` variants, such as that applied `#![feature(type_alias_impl_trait)]`. See [Type Alias Impl Trait | The Unstable book](https://doc.rust-lang.org/nightly/unstable-book/language-features/type-alias-impl-trait.html). -## `tests/ui/typeck/` - -General collection of type checking related tests. - ## `tests/ui/type-inference/` General collection of type inference related tests. -## `tests/ui/typeof/` +## `tests/ui/typeck` -`typeof` keyword, reserved but unimplemented. +General collection of type checking related tests. ## `tests/ui/ufcs/` @@ -1483,7 +1598,11 @@ See: **FIXME**: Seems to also contain more generic tests that fit in `tests/ui/unsized/`. -## `tests/ui/unused-crate-deps/` +## `tests/ui/unstable-feature-bound` + +Tests for gating and diagnostics when unstable features are used. + +## `tests/ui/unused-crate-deps` Exercises the `unused_crate_dependencies` lint. diff --git a/tests/ui/async-await/async-closures/move-from-async-fn-bound.rs b/tests/ui/async-await/async-closures/move-from-async-fn-bound.rs new file mode 100644 index 0000000000000..fbd8aac2515b9 --- /dev/null +++ b/tests/ui/async-await/async-closures/move-from-async-fn-bound.rs @@ -0,0 +1,13 @@ +//@ edition:2021 +// Test that a by-ref `AsyncFn` closure gets an error when it tries to +// consume a value, with a helpful diagnostic pointing to the bound. + +fn call(_: F) where F: AsyncFn() {} + +fn main() { + let y = vec![format!("World")]; + call(async || { + //~^ ERROR cannot move out of `y`, a captured variable in an `AsyncFn` closure + y.into_iter(); + }); +} diff --git a/tests/ui/async-await/async-closures/move-from-async-fn-bound.stderr b/tests/ui/async-await/async-closures/move-from-async-fn-bound.stderr new file mode 100644 index 0000000000000..1a881db2a37d5 --- /dev/null +++ b/tests/ui/async-await/async-closures/move-from-async-fn-bound.stderr @@ -0,0 +1,30 @@ +error[E0507]: cannot move out of `y`, a captured variable in an `AsyncFn` closure + --> $DIR/move-from-async-fn-bound.rs:9:10 + | +LL | let y = vec![format!("World")]; + | - captured outer variable +LL | call(async || { + | ^^^^^^^^ + | | + | captured by this `AsyncFn` closure + | `y` is moved here +LL | +LL | y.into_iter(); + | - + | | + | variable moved due to use in coroutine + | move occurs because `y` has type `Vec`, which does not implement the `Copy` trait + | +help: `AsyncFn` and `AsyncFnMut` closures require captured values to be able to be consumed multiple times, but `AsyncFnOnce` closures may consume them only once + --> $DIR/move-from-async-fn-bound.rs:5:27 + | +LL | fn call(_: F) where F: AsyncFn() {} + | ^^^^^^^^^ +help: consider cloning the value if the performance cost is acceptable + | +LL | y.clone().into_iter(); + | ++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/lint/invalid_value-polymorphic.rs b/tests/ui/lint/invalid_value-polymorphic.rs index 6a31ac17d96ff..4ed8950d20faa 100644 --- a/tests/ui/lint/invalid_value-polymorphic.rs +++ b/tests/ui/lint/invalid_value-polymorphic.rs @@ -1,4 +1,4 @@ -//@ compile-flags: --crate-type=lib -Zmir-enable-passes=+InstSimplify +//@ compile-flags: --crate-type=lib -Zmir-enable-passes=+InstSimplify-before-inline //@ build-pass #![feature(core_intrinsics)] diff --git a/tests/ui/mir/enable_passes_validation.enum_not_in_pass_names.stderr b/tests/ui/mir/enable_passes_validation.enum_not_in_pass_names.stderr new file mode 100644 index 0000000000000..89229ebabe84c --- /dev/null +++ b/tests/ui/mir/enable_passes_validation.enum_not_in_pass_names.stderr @@ -0,0 +1,8 @@ +warning: MIR pass `SimplifyCfg` is unknown and will be ignored + +warning: MIR pass `SimplifyCfg` is unknown and will be ignored + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: 2 warnings emitted + diff --git a/tests/ui/mir/enable_passes_validation.rs b/tests/ui/mir/enable_passes_validation.rs index 99b1ba528b0cc..d3d22b49ac7f8 100644 --- a/tests/ui/mir/enable_passes_validation.rs +++ b/tests/ui/mir/enable_passes_validation.rs @@ -1,4 +1,5 @@ //@ revisions: empty unprefixed all_unknown all_known mixed +//@ revisions: enum_not_in_pass_names enum_in_pass_names //@[empty] compile-flags: -Zmir-enable-passes= @@ -13,6 +14,12 @@ //@[mixed] check-pass //@[mixed] compile-flags: -Zmir-enable-passes=+ThisPassDoesNotExist,+CheckAlignment +//@[enum_not_in_pass_names] check-pass +//@[enum_not_in_pass_names] compile-flags: -Zmir-enable-passes=+SimplifyCfg + +//@[enum_in_pass_names] check-pass +//@[enum_in_pass_names] compile-flags: -Zmir-enable-passes=+AddCallGuards + fn main() {} //[empty]~? ERROR incorrect value `` for unstable option `mir-enable-passes` @@ -23,3 +30,5 @@ fn main() {} //[all_unknown]~? WARN MIR pass `DoesNotExist` is unknown and will be ignored //[all_unknown]~? WARN MIR pass `ThisPass` is unknown and will be ignored //[all_unknown]~? WARN MIR pass `DoesNotExist` is unknown and will be ignored +//[enum_not_in_pass_names]~? WARN MIR pass `SimplifyCfg` is unknown and will be ignored +//[enum_not_in_pass_names]~? WARN MIR pass `SimplifyCfg` is unknown and will be ignored diff --git a/triagebot.toml b/triagebot.toml index 1572c4c8d0456..eb25d6e1b2015 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1182,11 +1182,11 @@ cc = ["@Muscraft"] [mentions."compiler/rustc_errors/src/translation.rs"] message = "`rustc_errors::translation` was changed" -cc = ["@davidtwco", "@TaKO8Ki"] +cc = ["@davidtwco", "@TaKO8Ki", "@JonathanBrouwer"] [mentions."compiler/rustc_macros/src/diagnostics"] message = "`rustc_macros::diagnostics` was changed" -cc = ["@davidtwco", "@TaKO8Ki"] +cc = ["@davidtwco", "@TaKO8Ki", "@JonathanBrouwer"] [mentions."compiler/rustc_public"] message = "This PR changes rustc_public" diff --git a/typos.toml b/typos.toml index 920234a9381bc..25083174cb8fb 100644 --- a/typos.toml +++ b/typos.toml @@ -1,3 +1,6 @@ +# Config for the `typos` crate, used by `./x test tidy --extra-checks=spellcheck`. +# See also: https://github.com/crate-ci/typos/blob/v1.28.2/docs/reference.md + [files] extend-exclude = [ # exclude git (sub)modules and generated content @@ -13,57 +16,65 @@ extend-exclude = [ ] [default.extend-words] -# Add exclusions here, lines should be like `x = "x"`, where `x` is excluded word. +# Allowlist for words that look like typos but are not, or aren't worth fixing +# right now. Entries should look like `mipsel = "mipsel"`. # -# Also see docs: https://github.com/crate-ci/typos/blob/v1.28.2/docs/reference.md -arange = "arange" +# tidy-alphabetical-start +arange = "arange" # short for A-range childs = "childs" clonable = "clonable" -Datas = "Datas" -filetimes = "filetimes" +filetimes = "filetimes" # short for "file times", not a typo for "lifetimes" leafs = "leafs" -makro = "makro" +makro = "makro" # deliberate misspelling to avoid `macro` keyword misformed = "misformed" moreso = "moreso" -optin = "optin" +numer = "numer" # short for numerator, not a typo for "number" +optin = "optin" # short for opt-in publically = "publically" -rplace = "rplace" -smove = "smove" +rplace = "rplace" # short for R-place splitted = "splitted" -taits = "taits" +taits = "taits" # lowercase for TAITs (type alias impl trait) targetting = "targetting" unparseable = "unparseable" unstability = "unstability" -unstalled = "unstalled" -numer = "numer" +unstalled = "unstalled" # short for un-stalled +# tidy-alphabetical-end -# this can be valid word, depends on dictionary edition -#matcheable = "matcheable" +# Denylist to forbid misspelled words that aren't detected by the built-in +# dictionary. Entries should look like `mipsel = ""` or `mipsel = "misspell"`; +# the non-empty form can be automatically fixed by `--bless`. +# +# tidy-alphabetical-start +definitinon = "definition" +# tidy-alphabetical-end [default.extend-identifiers] -# An entry goes here if the typo is part of some existing ident -# where you want to keep it, but don't want to allow -# such typos everywhere. +# Allowlist for specific identifiers that should be permitted even though they +# appear to contain typos that would be forbidden in other identifiers. +# +# For example, you might want to allow a specific constant like +# `DNS_ERROR_INVAILD_VIRTUALIZATION_INSTANCE_NAME`, but still want to forbid +# the typo `INVAILD` in other places. # -# I.e. you don't want (or can't) fix some constant name, like -# `DNS_ERROR_INVAILD_VIRTUALIZATION_INSTANCE_NAME` but actually -# want to see `INVAILD` typo fixed in other places. -debug_aranges = "debug_aranges" +# tidy-alphabetical-start DNS_ERROR_INVAILD_VIRTUALIZATION_INSTANCE_NAME = "DNS_ERROR_INVAILD_VIRTUALIZATION_INSTANCE_NAME" -EnzymeTypeTreeShiftIndiciesEq = "EnzymeTypeTreeShiftIndiciesEq" -EnzymeTypeTreeShiftIndiciesEqFn = "EnzymeTypeTreeShiftIndiciesEqFn" -shift_indicies_eq = "shift_indicies_eq" ERRNO_ACCES = "ERRNO_ACCES" ERROR_DS_FILTER_USES_CONTRUCTED_ATTRS = "ERROR_DS_FILTER_USES_CONTRUCTED_ATTRS" ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC = "ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC" ERROR_FILENAME_EXCED_RANGE = "ERROR_FILENAME_EXCED_RANGE" ERROR_MCA_OCCURED = "ERROR_MCA_OCCURED" ERROR_REQ_NOT_ACCEP = "ERROR_REQ_NOT_ACCEP" -Oppen = "Oppen" +EnzymeTypeTreeShiftIndiciesEq = "EnzymeTypeTreeShiftIndiciesEq" +EnzymeTypeTreeShiftIndiciesEqFn = "EnzymeTypeTreeShiftIndiciesEqFn" +Oppen = "Oppen" # Derek C. Oppen, author of "Pretty Printing" (1979) # typos treats this as two different camelcase words (`SETTIN` and `Gs`) # Tracked in: https://github.com/crate-ci/typos/issues/745 SETTINGs = "SETTINGs" -tolen = "tolen" +debug_aranges = "debug_aranges" # debug A-ranges +key_smove = "key_smove" # shifted move key, used by terminfo +shift_indicies_eq = "shift_indicies_eq" +tolen = "tolen" # length of "to" buffer, used by `sendto` in Windows sockets +# tidy-alphabetical-end [default] extend-ignore-words-re = [