Skip to content

Commit 79335f1

Browse files
committed
Auto merge of rust-lang#107064 - GuillaumeGomez:rollup-pbgu6r3, r=GuillaumeGomez
Rollup of 5 pull requests Successful merges: - rust-lang#105977 (Transform async `ResumeTy` in generator transform) - rust-lang#106927 (make `CastError::NeedsDeref` create a `MachineApplicable` suggestion) - rust-lang#106931 (document + UI test `E0208` and make its output more user-friendly) - rust-lang#107027 (Remove extra removal from test path) - rust-lang#107037 (Fix Dominators::rank_partial_cmp to match documentation) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
2 parents 705a96d + dee88e0 commit 79335f1

File tree

33 files changed

+716
-100
lines changed

33 files changed

+716
-100
lines changed

compiler/rustc_data_structures/src/graph/dominators/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ impl<Node: Idx> Dominators<Node> {
299299
/// of two unrelated nodes will also be consistent, but otherwise the order has no
300300
/// meaning.) This method cannot be used to determine if either Node dominates the other.
301301
pub fn rank_partial_cmp(&self, lhs: Node, rhs: Node) -> Option<Ordering> {
302-
self.post_order_rank[lhs].partial_cmp(&self.post_order_rank[rhs])
302+
self.post_order_rank[rhs].partial_cmp(&self.post_order_rank[lhs])
303303
}
304304
}
305305

Original file line numberDiff line numberDiff line change
@@ -1 +1,46 @@
11
#### This error code is internal to the compiler and will not be emitted with normal Rust code.
2+
#### Note: this error code is no longer emitted by the compiler.
3+
4+
This error code shows the variance of a type's generic parameters.
5+
6+
Erroneous code example:
7+
8+
```compile_fail
9+
// NOTE: this feature is perma-unstable and should *only* be used for
10+
// testing purposes.
11+
#![feature(rustc_attrs)]
12+
13+
#[rustc_variance]
14+
struct Foo<'a, T> { // error: deliberate error to display type's variance
15+
t: &'a mut T,
16+
}
17+
```
18+
19+
which produces the following error:
20+
21+
```text
22+
error: [-, o]
23+
--> <anon>:4:1
24+
|
25+
4 | struct Foo<'a, T> {
26+
| ^^^^^^^^^^^^^^^^^
27+
```
28+
29+
*Note that while `#[rustc_variance]` still exists and is used within the*
30+
*compiler, it no longer is marked as `E0208` and instead has no error code.*
31+
32+
This error is deliberately triggered with the `#[rustc_variance]` attribute
33+
(`#![feature(rustc_attrs)]` must be enabled) and helps to show you the variance
34+
of the type's generic parameters. You can read more about variance and
35+
subtyping in [this section of the Rustnomicon]. For a more in depth look at
36+
variance (including a more complete list of common variances) see
37+
[this section of the Reference]. For information on how variance is implemented
38+
in the compiler, see [this section of `rustc-dev-guide`].
39+
40+
This error can be easily fixed by removing the `#[rustc_variance]` attribute,
41+
the compiler's suggestion to comment it out can be applied automatically with
42+
`rustfix`.
43+
44+
[this section of the Rustnomicon]: https://doc.rust-lang.org/nomicon/subtyping.html
45+
[this section of the Reference]: https://doc.rust-lang.org/reference/subtyping.html#variance
46+
[this section of `rustc-dev-guide`]: https://rustc-dev-guide.rust-lang.org/variance.html

compiler/rustc_hir/src/hir.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1787,6 +1787,14 @@ impl Expr<'_> {
17871787
expr
17881788
}
17891789

1790+
pub fn peel_borrows(&self) -> &Self {
1791+
let mut expr = self;
1792+
while let ExprKind::AddrOf(.., inner) = &expr.kind {
1793+
expr = inner;
1794+
}
1795+
expr
1796+
}
1797+
17901798
pub fn can_have_side_effects(&self) -> bool {
17911799
match self.peel_drop_temps().kind {
17921800
ExprKind::Path(_) | ExprKind::Lit(_) => false,

compiler/rustc_hir/src/lang_items.rs

+1
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ language_item_table! {
291291
IdentityFuture, sym::identity_future, identity_future_fn, Target::Fn, GenericRequirement::None;
292292
GetContext, sym::get_context, get_context_fn, Target::Fn, GenericRequirement::None;
293293

294+
Context, sym::Context, context, Target::Struct, GenericRequirement::None;
294295
FuturePoll, sym::poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
295296

296297
FromFrom, sym::from, from_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use rustc_errors::struct_span_err;
21
use rustc_middle::ty::TyCtxt;
32
use rustc_span::symbol::sym;
43

@@ -8,8 +7,8 @@ pub fn test_variance(tcx: TyCtxt<'_>) {
87
for id in tcx.hir().items() {
98
if tcx.has_attr(id.owner_id.to_def_id(), sym::rustc_variance) {
109
let variances_of = tcx.variances_of(id.owner_id);
11-
struct_span_err!(tcx.sess, tcx.def_span(id.owner_id), E0208, "{:?}", variances_of)
12-
.emit();
10+
11+
tcx.sess.struct_span_err(tcx.def_span(id.owner_id), format!("{variances_of:?}")).emit();
1312
}
1413
}
1514
}

compiler/rustc_hir_typeck/src/cast.rs

+21-17
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
use super::FnCtxt;
3232

3333
use crate::type_error_struct;
34+
use hir::ExprKind;
3435
use rustc_errors::{
3536
struct_span_err, Applicability, DelayDm, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
3637
};
@@ -151,7 +152,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
151152

152153
#[derive(Copy, Clone)]
153154
pub enum CastError {
154-
ErrorGuaranteed,
155+
ErrorGuaranteed(ErrorGuaranteed),
155156

156157
CastToBool,
157158
CastToChar,
@@ -176,8 +177,8 @@ pub enum CastError {
176177
}
177178

178179
impl From<ErrorGuaranteed> for CastError {
179-
fn from(_: ErrorGuaranteed) -> Self {
180-
CastError::ErrorGuaranteed
180+
fn from(err: ErrorGuaranteed) -> Self {
181+
CastError::ErrorGuaranteed(err)
181182
}
182183
}
183184

@@ -225,33 +226,36 @@ impl<'a, 'tcx> CastCheck<'tcx> {
225226

226227
fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
227228
match e {
228-
CastError::ErrorGuaranteed => {
229+
CastError::ErrorGuaranteed(_) => {
229230
// an error has already been reported
230231
}
231232
CastError::NeedDeref => {
232-
let error_span = self.span;
233233
let mut err = make_invalid_casting_error(
234234
fcx.tcx.sess,
235235
self.span,
236236
self.expr_ty,
237237
self.cast_ty,
238238
fcx,
239239
);
240-
let cast_ty = fcx.ty_to_string(self.cast_ty);
241-
err.span_label(
242-
error_span,
243-
format!("cannot cast `{}` as `{}`", fcx.ty_to_string(self.expr_ty), cast_ty),
244-
);
245-
if let Ok(snippet) = fcx.sess().source_map().span_to_snippet(self.expr_span) {
246-
err.span_suggestion(
247-
self.expr_span,
248-
"dereference the expression",
249-
format!("*{}", snippet),
250-
Applicability::MaybeIncorrect,
240+
241+
if matches!(self.expr.kind, ExprKind::AddrOf(..)) {
242+
// get just the borrow part of the expression
243+
let span = self.expr_span.with_hi(self.expr.peel_borrows().span.lo());
244+
err.span_suggestion_verbose(
245+
span,
246+
"remove the unneeded borrow",
247+
"",
248+
Applicability::MachineApplicable,
251249
);
252250
} else {
253-
err.span_help(self.expr_span, "dereference the expression with `*`");
251+
err.span_suggestion_verbose(
252+
self.expr_span.shrink_to_lo(),
253+
"dereference the expression",
254+
"*",
255+
Applicability::MachineApplicable,
256+
);
254257
}
258+
255259
err.emit();
256260
}
257261
CastError::NeedViaThinPtr | CastError::NeedViaPtr => {

compiler/rustc_middle/src/ty/context.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1952,6 +1952,15 @@ impl<'tcx> TyCtxt<'tcx> {
19521952
self.mk_ty(GeneratorWitness(types))
19531953
}
19541954

1955+
/// Creates a `&mut Context<'_>` [`Ty`] with erased lifetimes.
1956+
pub fn mk_task_context(self) -> Ty<'tcx> {
1957+
let context_did = self.require_lang_item(LangItem::Context, None);
1958+
let context_adt_ref = self.adt_def(context_did);
1959+
let context_substs = self.intern_substs(&[self.lifetimes.re_erased.into()]);
1960+
let context_ty = self.mk_adt(context_adt_ref, context_substs);
1961+
self.mk_mut_ref(self.lifetimes.re_erased, context_ty)
1962+
}
1963+
19551964
#[inline]
19561965
pub fn mk_ty_var(self, v: TyVid) -> Ty<'tcx> {
19571966
self.mk_ty_infer(TyVar(v))

compiler/rustc_mir_transform/src/coverage/spans.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -341,11 +341,11 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
341341
if a.is_in_same_bcb(b) {
342342
Some(Ordering::Equal)
343343
} else {
344-
// Sort equal spans by dominator relationship, in reverse order (so
345-
// dominators always come after the dominated equal spans). When later
346-
// comparing two spans in order, the first will either dominate the second,
347-
// or they will have no dominator relationship.
348-
self.basic_coverage_blocks.dominators().rank_partial_cmp(b.bcb, a.bcb)
344+
// Sort equal spans by dominator relationship (so dominators always come
345+
// before the dominated equal spans). When later comparing two spans in
346+
// order, the first will either dominate the second, or they will have no
347+
// dominator relationship.
348+
self.basic_coverage_blocks.dominators().rank_partial_cmp(a.bcb, b.bcb)
349349
}
350350
} else {
351351
// Sort hi() in reverse order so shorter spans are attempted after longer spans.

compiler/rustc_mir_transform/src/generator.rs

+111-7
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,104 @@ fn replace_local<'tcx>(
460460
new_local
461461
}
462462

463+
/// Transforms the `body` of the generator applying the following transforms:
464+
///
465+
/// - Eliminates all the `get_context` calls that async lowering created.
466+
/// - Replace all `Local` `ResumeTy` types with `&mut Context<'_>` (`context_mut_ref`).
467+
///
468+
/// The `Local`s that have their types replaced are:
469+
/// - The `resume` argument itself.
470+
/// - The argument to `get_context`.
471+
/// - The yielded value of a `yield`.
472+
///
473+
/// The `ResumeTy` hides a `&mut Context<'_>` behind an unsafe raw pointer, and the
474+
/// `get_context` function is being used to convert that back to a `&mut Context<'_>`.
475+
///
476+
/// Ideally the async lowering would not use the `ResumeTy`/`get_context` indirection,
477+
/// but rather directly use `&mut Context<'_>`, however that would currently
478+
/// lead to higher-kinded lifetime errors.
479+
/// See <https://github.com/rust-lang/rust/issues/105501>.
480+
///
481+
/// The async lowering step and the type / lifetime inference / checking are
482+
/// still using the `ResumeTy` indirection for the time being, and that indirection
483+
/// is removed here. After this transform, the generator body only knows about `&mut Context<'_>`.
484+
fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
485+
let context_mut_ref = tcx.mk_task_context();
486+
487+
// replace the type of the `resume` argument
488+
replace_resume_ty_local(tcx, body, Local::new(2), context_mut_ref);
489+
490+
let get_context_def_id = tcx.require_lang_item(LangItem::GetContext, None);
491+
492+
for bb in BasicBlock::new(0)..body.basic_blocks.next_index() {
493+
let bb_data = &body[bb];
494+
if bb_data.is_cleanup {
495+
continue;
496+
}
497+
498+
match &bb_data.terminator().kind {
499+
TerminatorKind::Call { func, .. } => {
500+
let func_ty = func.ty(body, tcx);
501+
if let ty::FnDef(def_id, _) = *func_ty.kind() {
502+
if def_id == get_context_def_id {
503+
let local = eliminate_get_context_call(&mut body[bb]);
504+
replace_resume_ty_local(tcx, body, local, context_mut_ref);
505+
}
506+
} else {
507+
continue;
508+
}
509+
}
510+
TerminatorKind::Yield { resume_arg, .. } => {
511+
replace_resume_ty_local(tcx, body, resume_arg.local, context_mut_ref);
512+
}
513+
_ => {}
514+
}
515+
}
516+
}
517+
518+
fn eliminate_get_context_call<'tcx>(bb_data: &mut BasicBlockData<'tcx>) -> Local {
519+
let terminator = bb_data.terminator.take().unwrap();
520+
if let TerminatorKind::Call { mut args, destination, target, .. } = terminator.kind {
521+
let arg = args.pop().unwrap();
522+
let local = arg.place().unwrap().local;
523+
524+
let arg = Rvalue::Use(arg);
525+
let assign = Statement {
526+
source_info: terminator.source_info,
527+
kind: StatementKind::Assign(Box::new((destination, arg))),
528+
};
529+
bb_data.statements.push(assign);
530+
bb_data.terminator = Some(Terminator {
531+
source_info: terminator.source_info,
532+
kind: TerminatorKind::Goto { target: target.unwrap() },
533+
});
534+
local
535+
} else {
536+
bug!();
537+
}
538+
}
539+
540+
#[cfg_attr(not(debug_assertions), allow(unused))]
541+
fn replace_resume_ty_local<'tcx>(
542+
tcx: TyCtxt<'tcx>,
543+
body: &mut Body<'tcx>,
544+
local: Local,
545+
context_mut_ref: Ty<'tcx>,
546+
) {
547+
let local_ty = std::mem::replace(&mut body.local_decls[local].ty, context_mut_ref);
548+
// We have to replace the `ResumeTy` that is used for type and borrow checking
549+
// with `&mut Context<'_>` in MIR.
550+
#[cfg(debug_assertions)]
551+
{
552+
if let ty::Adt(resume_ty_adt, _) = local_ty.kind() {
553+
let expected_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None));
554+
assert_eq!(*resume_ty_adt, expected_adt);
555+
} else {
556+
panic!("expected `ResumeTy`, found `{:?}`", local_ty);
557+
};
558+
}
559+
}
560+
463561
struct LivenessInfo {
464562
/// Which locals are live across any suspension point.
465563
saved_locals: GeneratorSavedLocals,
@@ -1283,13 +1381,13 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
12831381
}
12841382
};
12851383

1286-
let is_async_kind = body.generator_kind().unwrap() != GeneratorKind::Gen;
1384+
let is_async_kind = matches!(body.generator_kind(), Some(GeneratorKind::Async(_)));
12871385
let (state_adt_ref, state_substs) = if is_async_kind {
12881386
// Compute Poll<return_ty>
1289-
let state_did = tcx.require_lang_item(LangItem::Poll, None);
1290-
let state_adt_ref = tcx.adt_def(state_did);
1291-
let state_substs = tcx.intern_substs(&[body.return_ty().into()]);
1292-
(state_adt_ref, state_substs)
1387+
let poll_did = tcx.require_lang_item(LangItem::Poll, None);
1388+
let poll_adt_ref = tcx.adt_def(poll_did);
1389+
let poll_substs = tcx.intern_substs(&[body.return_ty().into()]);
1390+
(poll_adt_ref, poll_substs)
12931391
} else {
12941392
// Compute GeneratorState<yield_ty, return_ty>
12951393
let state_did = tcx.require_lang_item(LangItem::GeneratorState, None);
@@ -1303,13 +1401,19 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
13031401
// RETURN_PLACE then is a fresh unused local with type ret_ty.
13041402
let new_ret_local = replace_local(RETURN_PLACE, ret_ty, body, tcx);
13051403

1404+
// Replace all occurrences of `ResumeTy` with `&mut Context<'_>` within async bodies.
1405+
if is_async_kind {
1406+
transform_async_context(tcx, body);
1407+
}
1408+
13061409
// We also replace the resume argument and insert an `Assign`.
13071410
// This is needed because the resume argument `_2` might be live across a `yield`, in which
13081411
// case there is no `Assign` to it that the transform can turn into a store to the generator
13091412
// state. After the yield the slot in the generator state would then be uninitialized.
13101413
let resume_local = Local::new(2);
1311-
let new_resume_local =
1312-
replace_local(resume_local, body.local_decls[resume_local].ty, body, tcx);
1414+
let resume_ty =
1415+
if is_async_kind { tcx.mk_task_context() } else { body.local_decls[resume_local].ty };
1416+
let new_resume_local = replace_local(resume_local, resume_ty, body, tcx);
13131417

13141418
// When first entering the generator, move the resume argument into its new local.
13151419
let source_info = SourceInfo::outermost(body.span);

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ symbols! {
164164
Capture,
165165
Center,
166166
Clone,
167+
Context,
167168
Continue,
168169
Copy,
169170
Count,

0 commit comments

Comments
 (0)