Auto merge of #151809 - Zalathar:rollup-YOo3wjw, r=Zalathar

Rollup of 12 pull requests

Successful merges:

 - rust-lang/rust#150474 (Tidy: detect ui tests subdirectory changes so `tests/ui/README.md` stays in sync)
 - rust-lang/rust#150572 (Improve move error diagnostic for `AsyncFn` closures)
 - rust-lang/rust#151596 (Fix -Zmir-enable-passes to detect unregistered enum names in declare_passes macro)
 - rust-lang/rust#151802 (Make `QueryDispatcher::Qcx` an associated type)
 - rust-lang/rust#149110 (Implement `cast_slice` for raw pointer types)
 - rust-lang/rust#151559 ([rustdoc] Add a marker to tell users that there are hidden (deprecated) items in the search results)
 - rust-lang/rust#151665 (Fix contrast ratio for `Since` element in rustdoc dark theme)
 - rust-lang/rust#151785 (Stabilize feature(push_mut))
 - rust-lang/rust#151798 (Update `askama` to `0.15.3`)
 - rust-lang/rust#151800 (Subscribe myself to translation diagnostics)
 - rust-lang/rust#151804 (Document, sort, and tweak spellcheck entries in `typos.toml`)
 - rust-lang/rust#151805 (Fix grammar in `env::current_exe()#Security`)
This commit is contained in:
bors 2026-01-29 08:41:01 +00:00
commit 80b898258d
33 changed files with 778 additions and 305 deletions

View file

@ -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",

View file

@ -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<Span> {
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 `<TyOfCapturingClosure as FnMut>`
// 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 `<TyOfCapturingClosure as FnMut>` or
// `<TyOfCapturingClosure as AsyncFnMut>`.
// 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<ty::ClosureKind> {
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) {

View file

@ -91,20 +91,32 @@ macro_rules! declare_passes {
)+
)*
static PASS_NAMES: LazyLock<FxIndexSet<&str>> = LazyLock::new(|| [
static PASS_NAMES: LazyLock<FxIndexSet<&str>> = 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)]
};
}

View file

@ -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<QueryCtxt<'tcx>>
for SemiDynamicQueryDispatcher<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE>
QueryDispatcher for SemiDynamicQueryDispatcher<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE>
where
for<'a> C::Key: HashStable<StableHashingContext<'a>>,
{
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<QueryCtxt<'tcx>>;
type Dispatcher: QueryDispatcher<Qcx = QueryCtxt<'tcx>>;
const NAME: &'static &'static str;
fn query_dispatcher(tcx: TyCtxt<'tcx>) -> Self::Dispatcher;
fn restore_val(
value: <Self::Dispatcher as QueryDispatcher<QueryCtxt<'tcx>>>::Value,
) -> Self::UnerasedValue;
fn restore_val(value: <Self::Dispatcher as QueryDispatcher>::Value) -> Self::UnerasedValue;
}
pub fn query_system<'a>(

View file

@ -414,7 +414,7 @@ pub(crate) fn encode_query_results<'a, 'tcx, Q>(
}
pub(crate) fn query_key_hash_verify<'tcx>(
query: impl QueryDispatcher<QueryCtxt<'tcx>>,
query: impl QueryDispatcher<Qcx = QueryCtxt<'tcx>>,
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<QueryCtxt<'tcx>>,
Q: QueryDispatcher<Qcx = QueryCtxt<'tcx>>,
{
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<QueryCtxt<'tcx>>,
Q: QueryDispatcher<Qcx = QueryCtxt<'tcx>>,
{
// 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 =
<Q::Dispatcher as QueryDispatcher<QueryCtxt<'tcx>>>::Key::fingerprint_style();
let fingerprint_style = <Q::Dispatcher as QueryDispatcher>::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: <Self::Dispatcher as QueryDispatcher<QueryCtxt<'tcx>>>::Value) -> Self::UnerasedValue {
fn restore_val(value: <Self::Dispatcher as QueryDispatcher>::Value) -> Self::UnerasedValue {
restore::<queries::$name::Value<'tcx>>(value)
}
}

View file

@ -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<V> = Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>;
/// Unambiguous shorthand for `<This::Qcx as HasDepContext>::DepContext`.
#[expect(type_alias_bounds)]
type DepContextOf<This: QueryDispatcher> =
<<This as QueryDispatcher>::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<V> = Option<fn(&mut StableHashingContext<'_>, &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<Qcx: QueryContext>: 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<Qcx::DepContext> + Eq + Hash + Copy + Debug;
type Key: DepNodeParams<DepContextOf<Self>> + Eq + Hash + Copy + Debug;
type Value: Copy;
type Cache: QueryCache<Key = Self::Key, Value = Self::Value>;
@ -33,36 +41,40 @@ pub trait QueryDispatcher<Qcx: QueryContext>: 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<Self::Key, Qcx::QueryInfo>
where
Qcx: 'a;
fn query_state<'a>(
self,
tcx: Self::Qcx,
) -> &'a QueryState<Self::Key, <Self::Qcx as QueryContext>::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<Self>, 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<Self>, 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<Self::Value>;
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<Self>,
cycle_error: &CycleError<QueryStackFrameExtra>,
guar: ErrorGuaranteed,
) -> Self::Value;
@ -77,7 +89,7 @@ pub trait QueryDispatcher<Qcx: QueryContext>: Copy {
fn hash_result(self) -> HashResult<Self::Value>;
// 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<Self>, key: &Self::Key) -> DepNode {
DepNode::construct(tcx, self.dep_kind(), key)
}
}

View file

@ -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<Q, Qcx>(query: Q, qcx: Qcx, cycle_error: CycleError) -> Q::Value
fn mk_cycle<Q>(query: Q, qcx: Q::Qcx, cycle_error: CycleError) -> Q::Value
where
Q: QueryDispatcher<Qcx>,
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<Q, Qcx>(
fn handle_cycle_error<Q>(
query: Q,
qcx: Qcx,
qcx: Q::Qcx,
cycle_error: &CycleError,
error: Diag<'_>,
) -> Q::Value
where
Q: QueryDispatcher<Qcx>,
Qcx: QueryContext,
Q: QueryDispatcher,
{
match query.cycle_error_handling() {
CycleErrorHandling::Error => {
@ -272,15 +272,14 @@ where
#[cold]
#[inline(never)]
fn cycle_error<Q, Qcx>(
fn cycle_error<Q>(
query: Q,
qcx: Qcx,
qcx: Q::Qcx,
try_execute: QueryJobId,
span: Span,
) -> (Q::Value, Option<DepNodeIndex>)
where
Q: QueryDispatcher<Qcx>,
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<Q, Qcx>(
fn wait_for_query<Q>(
query: Q,
qcx: Qcx,
qcx: Q::Qcx,
span: Span,
key: Q::Key,
latch: QueryLatch<Qcx::QueryInfo>,
latch: QueryLatch<<Q::Qcx as QueryContext>::QueryInfo>,
current: Option<QueryJobId>,
) -> (Q::Value, Option<DepNodeIndex>)
where
Q: QueryDispatcher<Qcx>,
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<Q, Qcx, const INCR: bool>(
fn try_execute_query<Q, const INCR: bool>(
query: Q,
qcx: Qcx,
qcx: Q::Qcx,
span: Span,
key: Q::Key,
dep_node: Option<DepNode>,
) -> (Q::Value, Option<DepNodeIndex>)
where
Q: QueryDispatcher<Qcx>,
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::<Q, INCR>(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<Q, Qcx, const INCR: bool>(
fn execute_job<Q, const INCR: bool>(
query: Q,
qcx: Qcx,
state: &QueryState<Q::Key, Qcx::QueryInfo>,
qcx: Q::Qcx,
state: &QueryState<Q::Key, <Q::Qcx as QueryContext>::QueryInfo>,
key: Q::Key,
key_hash: u64,
id: QueryJobId,
dep_node: Option<DepNode>,
) -> (Q::Value, Option<DepNodeIndex>)
where
Q: QueryDispatcher<Qcx>,
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<Q, Qcx>(
fn execute_job_non_incr<Q>(
query: Q,
qcx: Qcx,
qcx: Q::Qcx,
key: Q::Key,
job_id: QueryJobId,
) -> (Q::Value, DepNodeIndex)
where
Q: QueryDispatcher<Qcx>,
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<Q, Qcx>(
fn execute_job_incr<Q>(
query: Q,
qcx: Qcx,
dep_graph_data: &DepGraphData<Qcx::Deps>,
qcx: Q::Qcx,
dep_graph_data: &DepGraphData<<Q::Qcx as HasDepContext>::Deps>,
key: Q::Key,
mut dep_node_opt: Option<DepNode>,
job_id: QueryJobId,
) -> (Q::Value, DepNodeIndex)
where
Q: QueryDispatcher<Qcx>,
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<Q, Qcx>(
fn try_load_from_disk_and_cache_in_memory<Q>(
query: Q,
dep_graph_data: &DepGraphData<Qcx::Deps>,
qcx: Qcx,
dep_graph_data: &DepGraphData<<Q::Qcx as HasDepContext>::Deps>,
qcx: Q::Qcx,
key: &Q::Key,
dep_node: &DepNode,
) -> Option<(Q::Value, DepNodeIndex)>
where
Q: QueryDispatcher<Qcx>,
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<Tcx>(
///
/// Note: The optimization is only available during incr. comp.
#[inline(never)]
fn ensure_must_run<Q, Qcx>(
fn ensure_must_run<Q>(
query: Q,
qcx: Qcx,
qcx: Q::Qcx,
key: &Q::Key,
check_cache: bool,
) -> (bool, Option<DepNode>)
where
Q: QueryDispatcher<Qcx>,
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<Q, Qcx>(query: Q, qcx: Qcx, span: Span, key: Q::Key) -> Q::Value
pub fn get_query_non_incr<Q>(query: Q, qcx: Q::Qcx, span: Span, key: Q::Key) -> Q::Value
where
Q: QueryDispatcher<Qcx>,
Qcx: QueryContext,
Q: QueryDispatcher,
{
debug_assert!(!qcx.dep_context().dep_graph().is_fully_enabled());
ensure_sufficient_stack(|| try_execute_query::<Q, Qcx, false>(query, qcx, span, key, None).0)
ensure_sufficient_stack(|| try_execute_query::<Q, false>(query, qcx, span, key, None).0)
}
#[inline(always)]
pub fn get_query_incr<Q, Qcx>(
pub fn get_query_incr<Q>(
query: Q,
qcx: Qcx,
qcx: Q::Qcx,
span: Span,
key: Q::Key,
mode: QueryMode,
) -> Option<Q::Value>
where
Q: QueryDispatcher<Qcx>,
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::<Q, true>(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<Q, Qcx>(query: Q, qcx: Qcx, key: Q::Key, dep_node: DepNode)
pub fn force_query<Q>(query: Q, qcx: Q::Qcx, key: Q::Key, dep_node: DepNode)
where
Q: QueryDispatcher<Qcx>,
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::<Q, true>(query, qcx, DUMMY_SP, key, Some(dep_node))
});
}

View file

@ -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>,

View file

@ -854,7 +854,6 @@ impl<T, A: Allocator> LinkedList<T, A> {
/// # Examples
///
/// ```
/// #![feature(push_mut)]
/// use std::collections::LinkedList;
///
/// let mut dl = LinkedList::from([1, 2, 3]);
@ -863,7 +862,7 @@ impl<T, A: Allocator> LinkedList<T, A> {
/// *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<T, A: Allocator> LinkedList<T, A> {
/// # Examples
///
/// ```
/// #![feature(push_mut)]
/// use std::collections::LinkedList;
///
/// let mut dl = LinkedList::from([1, 2, 3]);
@ -935,7 +933,7 @@ impl<T, A: Allocator> LinkedList<T, A> {
/// *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 =

View file

@ -2168,7 +2168,6 @@ impl<T, A: Allocator> VecDeque<T, A> {
/// # Examples
///
/// ```
/// #![feature(push_mut)]
/// use std::collections::VecDeque;
///
/// let mut d = VecDeque::from([1, 2, 3]);
@ -2176,7 +2175,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
/// *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<T, A: Allocator> VecDeque<T, A> {
/// # Examples
///
/// ```
/// #![feature(push_mut)]
/// use std::collections::VecDeque;
///
/// let mut d = VecDeque::from([1, 2, 3]);
@ -2220,7 +2218,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
/// *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<T, A: Allocator> VecDeque<T, A> {
/// # Examples
///
/// ```
/// #![feature(push_mut)]
/// use std::collections::VecDeque;
///
/// let mut vec_deque = VecDeque::from([1, 2, 3]);
@ -2428,7 +2425,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
/// *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");

View file

@ -1003,9 +1003,6 @@ const impl<T, A: [const] Allocator + [const] Destruct> Vec<T, A> {
/// # 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<T, A: [const] Allocator + [const] Destruct> Vec<T, A> {
/// 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<T, A: Allocator> Vec<T, A> {
/// # 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<T, A: Allocator> Vec<T, A> {
/// 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<T, A: Allocator> Vec<T, A> {
/// 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);

View file

@ -1386,6 +1386,43 @@ impl<T> *const T {
pub const fn cast_uninit(self) -> *const MaybeUninit<T> {
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::<u8>().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<T> *const MaybeUninit<T> {
/// Casts from a maybe-uninitialized type to its initialized version.

View file

@ -1655,6 +1655,51 @@ impl<T> *mut T {
pub const fn cast_uninit(self) -> *mut MaybeUninit<T> {
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::<u8>().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<T> *mut MaybeUninit<T> {
/// Casts from a maybe-uninitialized type to its initialized version.

View file

@ -1377,6 +1377,35 @@ impl<T> NonNull<T> {
pub const fn cast_uninit(self) -> NonNull<MaybeUninit<T>> {
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<T> NonNull<MaybeUninit<T>> {
/// Casts from a maybe-uninitialized type to its initialized version.

View file

@ -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.

View file

@ -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"

View file

@ -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"

View file

@ -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%);

View file

@ -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%);

View file

@ -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<string|null>[]} */
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 {

View file

@ -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"

View file

@ -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);

View file

@ -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 <https://github.com/rust-lang/rust/issues/150399>
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"^##.*?`(?<dir>[^`]+)`").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<String> {
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

View file

@ -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"})

View file

@ -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"})

View file

@ -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 <https://doc.rust-lang.org/std/alloc/fn.handle_alloc_error.html>.
## `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 <https://doc.rust-lang.org/std/alloc/fn.handle_alloc_error.html>.
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 <https://blog.rust-lang.org/inside-rust/2019/12/02/const-prop-on-by-default/>.
## `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 <https://blog.rust-lang.org/inside-rust/2019/12/02/const-prop-on-by-default/>.
## `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 <https://github.com/rust-lang/rust/pull/134082>.
@ -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 `..<expr>` at the end of a struct literal expression to fill in all remaining fields of the struct literal by using `<expr>` 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 `..<expr>` at the end of a struct literal expression to fill in all remaining fields of the struct literal by using `<expr>` 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<i32>`, 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 that are specific to editions.
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/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.

View file

@ -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>(_: 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();
});
}

View file

@ -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<String>`, 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>(_: 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`.

View file

@ -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)]

View file

@ -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

View file

@ -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

View file

@ -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"

View file

@ -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.
#
# 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"
# 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.
#
# 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 = [