Skip to content

Commit 80b8982

Browse files
committed
Auto merge of #151809 - Zalathar:rollup-YOo3wjw, r=Zalathar
Rollup of 12 pull requests Successful merges: - #150474 (Tidy: detect ui tests subdirectory changes so `tests/ui/README.md` stays in sync) - #150572 (Improve move error diagnostic for `AsyncFn` closures) - #151596 (Fix -Zmir-enable-passes to detect unregistered enum names in declare_passes macro) - #151802 (Make `QueryDispatcher::Qcx` an associated type) - #149110 (Implement `cast_slice` for raw pointer types) - #151559 ([rustdoc] Add a marker to tell users that there are hidden (deprecated) items in the search results) - #151665 (Fix contrast ratio for `Since` element in rustdoc dark theme) - #151785 (Stabilize feature(push_mut)) - #151798 (Update `askama` to `0.15.3`) - #151800 (Subscribe myself to translation diagnostics) - #151804 (Document, sort, and tweak spellcheck entries in `typos.toml`) - #151805 (Fix grammar in `env::current_exe()#Security`)
2 parents ba284f4 + e397c50 commit 80b8982

File tree

33 files changed

+778
-305
lines changed

33 files changed

+778
-305
lines changed

Cargo.lock

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
184184

185185
[[package]]
186186
name = "askama"
187-
version = "0.15.2"
187+
version = "0.15.3"
188188
source = "registry+https://github.com/rust-lang/crates.io-index"
189-
checksum = "03341eae1125472b0672fbf35cc9aa7b74cd8e0c3d02f02c28a04678f12aaa7a"
189+
checksum = "10a800c6f7c005e5bcb76ff0b9e61c9e54ad379ce4e83a88ed14ff487a73776d"
190190
dependencies = [
191191
"askama_macros",
192192
"itoa",
@@ -197,9 +197,9 @@ dependencies = [
197197

198198
[[package]]
199199
name = "askama_derive"
200-
version = "0.15.2"
200+
version = "0.15.3"
201201
source = "registry+https://github.com/rust-lang/crates.io-index"
202-
checksum = "461bd78f3da90b5e44eee4272cfb1c4832aa3dcdb6c370aedd3eb253d2b9e3ca"
202+
checksum = "0cb7657165bac49b5c533850e7cd67c1c60059aefc31088f89aa431c8a90d5d9"
203203
dependencies = [
204204
"askama_parser",
205205
"basic-toml",
@@ -214,18 +214,18 @@ dependencies = [
214214

215215
[[package]]
216216
name = "askama_macros"
217-
version = "0.15.2"
217+
version = "0.15.3"
218218
source = "registry+https://github.com/rust-lang/crates.io-index"
219-
checksum = "ba49fb22ee3074574b8510abd9495d4f0bb9b8f87e8e45ee31e2cee508f7a8e5"
219+
checksum = "e55eacd3e54d32483cd10d0a881a0f28a40f3a763704ac9b8693edc39d7321c7"
220220
dependencies = [
221221
"askama_derive",
222222
]
223223

224224
[[package]]
225225
name = "askama_parser"
226-
version = "0.15.2"
226+
version = "0.15.3"
227227
source = "registry+https://github.com/rust-lang/crates.io-index"
228-
checksum = "7e33eb7484958aaa1f27e9adb556f5d557331cd891bdbb33781bc1f9550b6f6e"
228+
checksum = "20c3df8886ab5acdcd76eee93b3e2df1ef734251438b5b942b5fea22c50d2a0f"
229229
dependencies = [
230230
"rustc-hash 2.1.1",
231231
"serde",

compiler/rustc_borrowck/src/diagnostics/move_errors.rs

Lines changed: 135 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use rustc_abi::FieldIdx;
12
use rustc_data_structures::fx::FxHashSet;
23
use rustc_errors::{Applicability, Diag};
34
use rustc_hir::intravisit::Visitor;
@@ -7,7 +8,7 @@ use rustc_middle::mir::*;
78
use rustc_middle::ty::{self, Ty, TyCtxt};
89
use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex};
910
use rustc_span::def_id::DefId;
10-
use rustc_span::{BytePos, DUMMY_SP, ExpnKind, MacroKind, Span};
11+
use rustc_span::{BytePos, ExpnKind, MacroKind, Span};
1112
use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
1213
use rustc_trait_selection::infer::InferCtxtExt;
1314
use tracing::debug;
@@ -472,49 +473,30 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
472473
if def_id.as_local() == Some(self.mir_def_id())
473474
&& let Some(upvar_field) = upvar_field =>
474475
{
475-
let closure_kind_ty = closure_args.as_closure().kind_ty();
476-
let closure_kind = match closure_kind_ty.to_opt_closure_kind() {
477-
Some(kind @ (ty::ClosureKind::Fn | ty::ClosureKind::FnMut)) => kind,
478-
Some(ty::ClosureKind::FnOnce) => {
479-
bug!("closure kind does not match first argument type")
480-
}
481-
None => bug!("closure kind not inferred by borrowck"),
482-
};
483-
let capture_description =
484-
format!("captured variable in an `{closure_kind}` closure");
485-
486-
let upvar = &self.upvars[upvar_field.index()];
487-
let upvar_hir_id = upvar.get_root_variable();
488-
let upvar_name = upvar.to_string(tcx);
489-
let upvar_span = tcx.hir_span(upvar_hir_id);
490-
491-
let place_name = self.describe_any_place(move_place.as_ref());
492-
493-
let place_description =
494-
if self.is_upvar_field_projection(move_place.as_ref()).is_some() {
495-
format!("{place_name}, a {capture_description}")
496-
} else {
497-
format!("{place_name}, as `{upvar_name}` is a {capture_description}")
498-
};
499-
500-
debug!(
501-
"report: closure_kind_ty={:?} closure_kind={:?} place_description={:?}",
502-
closure_kind_ty, closure_kind, place_description,
503-
);
504-
505-
let closure_span = tcx.def_span(def_id);
506-
507-
self.cannot_move_out_of(span, &place_description)
508-
.with_span_label(upvar_span, "captured outer variable")
509-
.with_span_label(
510-
closure_span,
511-
format!("captured by this `{closure_kind}` closure"),
512-
)
513-
.with_span_help(
514-
self.get_closure_bound_clause_span(*def_id),
515-
"`Fn` and `FnMut` closures require captured values to be able to be \
516-
consumed multiple times, but `FnOnce` closures may consume them only once",
517-
)
476+
self.report_closure_move_error(
477+
span,
478+
move_place,
479+
*def_id,
480+
closure_args.as_closure().kind_ty(),
481+
upvar_field,
482+
ty::Asyncness::No,
483+
)
484+
}
485+
ty::CoroutineClosure(def_id, closure_args)
486+
if def_id.as_local() == Some(self.mir_def_id())
487+
&& let Some(upvar_field) = upvar_field
488+
&& self
489+
.get_closure_bound_clause_span(*def_id, ty::Asyncness::Yes)
490+
.is_some() =>
491+
{
492+
self.report_closure_move_error(
493+
span,
494+
move_place,
495+
*def_id,
496+
closure_args.as_coroutine_closure().kind_ty(),
497+
upvar_field,
498+
ty::Asyncness::Yes,
499+
)
518500
}
519501
_ => {
520502
let source = self.borrowed_content_source(deref_base);
@@ -563,45 +545,134 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
563545
err
564546
}
565547

566-
fn get_closure_bound_clause_span(&self, def_id: DefId) -> Span {
548+
fn report_closure_move_error(
549+
&self,
550+
span: Span,
551+
move_place: Place<'tcx>,
552+
def_id: DefId,
553+
closure_kind_ty: Ty<'tcx>,
554+
upvar_field: FieldIdx,
555+
asyncness: ty::Asyncness,
556+
) -> Diag<'infcx> {
557+
let tcx = self.infcx.tcx;
558+
559+
let closure_kind = match closure_kind_ty.to_opt_closure_kind() {
560+
Some(kind @ (ty::ClosureKind::Fn | ty::ClosureKind::FnMut)) => kind,
561+
Some(ty::ClosureKind::FnOnce) => {
562+
bug!("closure kind does not match first argument type")
563+
}
564+
None => bug!("closure kind not inferred by borrowck"),
565+
};
566+
567+
let async_prefix = if asyncness.is_async() { "Async" } else { "" };
568+
let capture_description =
569+
format!("captured variable in an `{async_prefix}{closure_kind}` closure");
570+
571+
let upvar = &self.upvars[upvar_field.index()];
572+
let upvar_hir_id = upvar.get_root_variable();
573+
let upvar_name = upvar.to_string(tcx);
574+
let upvar_span = tcx.hir_span(upvar_hir_id);
575+
576+
let place_name = self.describe_any_place(move_place.as_ref());
577+
578+
let place_description = if self.is_upvar_field_projection(move_place.as_ref()).is_some() {
579+
format!("{place_name}, a {capture_description}")
580+
} else {
581+
format!("{place_name}, as `{upvar_name}` is a {capture_description}")
582+
};
583+
584+
debug!(?closure_kind_ty, ?closure_kind, ?place_description);
585+
586+
let closure_span = tcx.def_span(def_id);
587+
588+
let help_msg = format!(
589+
"`{async_prefix}Fn` and `{async_prefix}FnMut` closures require captured values to \
590+
be able to be consumed multiple times, but `{async_prefix}FnOnce` closures may \
591+
consume them only once"
592+
);
593+
594+
let mut err = self
595+
.cannot_move_out_of(span, &place_description)
596+
.with_span_label(upvar_span, "captured outer variable")
597+
.with_span_label(
598+
closure_span,
599+
format!("captured by this `{async_prefix}{closure_kind}` closure"),
600+
);
601+
602+
if let Some(bound_span) = self.get_closure_bound_clause_span(def_id, asyncness) {
603+
err.span_help(bound_span, help_msg);
604+
} else if !asyncness.is_async() {
605+
// For sync closures, always emit the help message even without a span.
606+
// For async closures, we only enter this branch if we found a valid span
607+
// (due to the match guard), so no fallback is needed.
608+
err.help(help_msg);
609+
}
610+
611+
err
612+
}
613+
614+
fn get_closure_bound_clause_span(
615+
&self,
616+
def_id: DefId,
617+
asyncness: ty::Asyncness,
618+
) -> Option<Span> {
567619
let tcx = self.infcx.tcx;
568620
let typeck_result = tcx.typeck(self.mir_def_id());
569621
// Check whether the closure is an argument to a call, if so,
570622
// get the instantiated where-bounds of that call.
571623
let closure_hir_id = tcx.local_def_id_to_hir_id(def_id.expect_local());
572-
let hir::Node::Expr(parent) = tcx.parent_hir_node(closure_hir_id) else { return DUMMY_SP };
624+
let hir::Node::Expr(parent) = tcx.parent_hir_node(closure_hir_id) else { return None };
573625

574626
let predicates = match parent.kind {
575627
hir::ExprKind::Call(callee, _) => {
576-
let Some(ty) = typeck_result.node_type_opt(callee.hir_id) else { return DUMMY_SP };
577-
let ty::FnDef(fn_def_id, args) = ty.kind() else { return DUMMY_SP };
628+
let ty = typeck_result.node_type_opt(callee.hir_id)?;
629+
let ty::FnDef(fn_def_id, args) = ty.kind() else { return None };
578630
tcx.predicates_of(fn_def_id).instantiate(tcx, args)
579631
}
580632
hir::ExprKind::MethodCall(..) => {
581-
let Some((_, method)) = typeck_result.type_dependent_def(parent.hir_id) else {
582-
return DUMMY_SP;
583-
};
633+
let (_, method) = typeck_result.type_dependent_def(parent.hir_id)?;
584634
let args = typeck_result.node_args(parent.hir_id);
585635
tcx.predicates_of(method).instantiate(tcx, args)
586636
}
587-
_ => return DUMMY_SP,
637+
_ => return None,
588638
};
589639

590-
// Check whether one of the where-bounds requires the closure to impl `Fn[Mut]`.
640+
// Check whether one of the where-bounds requires the closure to impl `Fn[Mut]`
641+
// or `AsyncFn[Mut]`.
591642
for (pred, span) in predicates.predicates.iter().zip(predicates.spans.iter()) {
592-
if let Some(clause) = pred.as_trait_clause()
593-
&& let ty::Closure(clause_closure_def_id, _) = clause.self_ty().skip_binder().kind()
594-
&& *clause_closure_def_id == def_id
595-
&& (tcx.lang_items().fn_mut_trait() == Some(clause.def_id())
596-
|| tcx.lang_items().fn_trait() == Some(clause.def_id()))
597-
{
598-
// Found `<TyOfCapturingClosure as FnMut>`
599-
// We point at the `Fn()` or `FnMut()` bound that coerced the closure, which
600-
// could be changed to `FnOnce()` to avoid the move error.
601-
return *span;
643+
let dominated_by_fn_trait = self
644+
.closure_clause_kind(*pred, def_id, asyncness)
645+
.is_some_and(|kind| matches!(kind, ty::ClosureKind::Fn | ty::ClosureKind::FnMut));
646+
if dominated_by_fn_trait {
647+
// Found `<TyOfCapturingClosure as FnMut>` or
648+
// `<TyOfCapturingClosure as AsyncFnMut>`.
649+
// We point at the bound that coerced the closure, which could be changed
650+
// to `FnOnce()` or `AsyncFnOnce()` to avoid the move error.
651+
return Some(*span);
602652
}
603653
}
604-
DUMMY_SP
654+
None
655+
}
656+
657+
/// If `pred` is a trait clause binding the closure `def_id` to `Fn`/`FnMut`/`FnOnce`
658+
/// (or their async equivalents based on `asyncness`), returns the corresponding
659+
/// `ClosureKind`. Otherwise returns `None`.
660+
fn closure_clause_kind(
661+
&self,
662+
pred: ty::Clause<'tcx>,
663+
def_id: DefId,
664+
asyncness: ty::Asyncness,
665+
) -> Option<ty::ClosureKind> {
666+
let tcx = self.infcx.tcx;
667+
let clause = pred.as_trait_clause()?;
668+
let kind = match asyncness {
669+
ty::Asyncness::Yes => tcx.async_fn_trait_kind_from_def_id(clause.def_id()),
670+
ty::Asyncness::No => tcx.fn_trait_kind_from_def_id(clause.def_id()),
671+
}?;
672+
match clause.self_ty().skip_binder().kind() {
673+
ty::Closure(id, _) | ty::CoroutineClosure(id, _) if *id == def_id => Some(kind),
674+
_ => None,
675+
}
605676
}
606677

607678
fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span: Span) {

compiler/rustc_mir_transform/src/lib.rs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -91,20 +91,32 @@ macro_rules! declare_passes {
9191
)+
9292
)*
9393

94-
static PASS_NAMES: LazyLock<FxIndexSet<&str>> = LazyLock::new(|| [
94+
static PASS_NAMES: LazyLock<FxIndexSet<&str>> = LazyLock::new(|| {
95+
let mut set = FxIndexSet::default();
9596
// Fake marker pass
96-
"PreCodegen",
97+
set.insert("PreCodegen");
9798
$(
9899
$(
99-
stringify!($pass_name),
100-
$(
101-
$(
102-
$mod_name::$pass_name::$ident.name(),
103-
)*
104-
)?
100+
set.extend(pass_names!($mod_name : $pass_name $( { $($ident),* } )? ));
105101
)+
106102
)*
107-
].into_iter().collect());
103+
set
104+
});
105+
};
106+
}
107+
108+
macro_rules! pass_names {
109+
// pass groups: only pass names inside are considered pass_names
110+
($mod_name:ident : $pass_group:ident { $($pass_name:ident),* $(,)? }) => {
111+
[
112+
$(
113+
$mod_name::$pass_group::$pass_name.name(),
114+
)*
115+
]
116+
};
117+
// lone pass names: stringify the struct or enum name
118+
($mod_name:ident : $pass_name:ident) => {
119+
[stringify!($pass_name)]
108120
};
109121
}
110122

compiler/rustc_query_impl/src/lib.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,11 @@ impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDA
6767

6868
// This is `impl QueryDispatcher for SemiDynamicQueryDispatcher`.
6969
impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDABLE: bool>
70-
QueryDispatcher<QueryCtxt<'tcx>>
71-
for SemiDynamicQueryDispatcher<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE>
70+
QueryDispatcher for SemiDynamicQueryDispatcher<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE>
7271
where
7372
for<'a> C::Key: HashStable<StableHashingContext<'a>>,
7473
{
74+
type Qcx = QueryCtxt<'tcx>;
7575
type Key = C::Key;
7676
type Value = C::Value;
7777
type Cache = C;
@@ -104,10 +104,7 @@ where
104104
}
105105

106106
#[inline(always)]
107-
fn query_cache<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a Self::Cache
108-
where
109-
'tcx: 'a,
110-
{
107+
fn query_cache<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a Self::Cache {
111108
// Safety:
112109
// This is just manually doing the subfield referencing through pointer math.
113110
unsafe {
@@ -215,15 +212,13 @@ where
215212
/// on the type `rustc_query_impl::query_impl::$name::QueryType`.
216213
trait QueryDispatcherUnerased<'tcx> {
217214
type UnerasedValue;
218-
type Dispatcher: QueryDispatcher<QueryCtxt<'tcx>>;
215+
type Dispatcher: QueryDispatcher<Qcx = QueryCtxt<'tcx>>;
219216

220217
const NAME: &'static &'static str;
221218

222219
fn query_dispatcher(tcx: TyCtxt<'tcx>) -> Self::Dispatcher;
223220

224-
fn restore_val(
225-
value: <Self::Dispatcher as QueryDispatcher<QueryCtxt<'tcx>>>::Value,
226-
) -> Self::UnerasedValue;
221+
fn restore_val(value: <Self::Dispatcher as QueryDispatcher>::Value) -> Self::UnerasedValue;
227222
}
228223

229224
pub fn query_system<'a>(

0 commit comments

Comments
 (0)