Skip to content

Commit 110aecd

Browse files
committed
factor into struct, and comments
1 parent 2af1ebf commit 110aecd

File tree

8 files changed

+104
-92
lines changed

8 files changed

+104
-92
lines changed

compiler/rustc_lint_defs/src/builtin.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ declare_lint! {
315315
}
316316

317317
declare_lint! {
318-
/// The `must_not_suspend` lint guards against values that shouldn't be held across yield points
318+
/// The `must_not_suspend` lint guards against values that shouldn't be held across suspend points
319319
/// (`.await`)
320320
///
321321
/// ### Example
@@ -339,10 +339,10 @@ declare_lint! {
339339
/// ### Explanation
340340
///
341341
/// The `must_not_suspend` lint detects values that are marked with the `#[must_not_suspend]`
342-
/// attribute being held across yield points. A "yield" point is usually a `.await` in an async
342+
/// attribute being held across suspend points. A "suspend" point is usually a `.await` in an async
343343
/// function.
344344
///
345-
/// This attribute can be used to mark values that are semantically incorrect across yields
345+
/// This attribute can be used to mark values that are semantically incorrect across suspends
346346
/// (like certain types of timers), values that have async alternatives, and values that
347347
/// regularly cause problems with the `Send`-ness of async fn's returned futures (like
348348
/// `MutexGuard`'s)

compiler/rustc_typeck/src/check/generator_interior.rs

+52-68
Original file line numberDiff line numberDiff line change
@@ -126,12 +126,13 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
126126
self.fcx,
127127
ty,
128128
hir_id,
129-
expr,
130-
source_span,
131-
yield_data.span,
132-
"",
133-
"",
134-
1,
129+
SuspendCheckData {
130+
expr,
131+
source_span,
132+
yield_span: yield_data.span,
133+
plural_len: 1,
134+
..Default::default()
135+
},
135136
);
136137

137138
self.types.insert(ty::GeneratorInteriorTypeCause {
@@ -448,56 +449,43 @@ impl<'a, 'tcx> Visitor<'tcx> for ArmPatCollector<'a> {
448449
}
449450
}
450451

452+
#[derive(Default)]
453+
pub struct SuspendCheckData<'a, 'tcx> {
454+
expr: Option<&'tcx Expr<'tcx>>,
455+
source_span: Span,
456+
yield_span: Span,
457+
descr_pre: &'a str,
458+
descr_post: &'a str,
459+
plural_len: usize,
460+
}
461+
451462
// Returns whether it emitted a diagnostic or not
452463
// Note that this fn and the proceding one are based on the code
453464
// for creating must_use diagnostics
454465
pub fn check_must_not_suspend_ty<'tcx>(
455466
fcx: &FnCtxt<'_, 'tcx>,
456467
ty: Ty<'tcx>,
457468
hir_id: HirId,
458-
expr: Option<&'tcx Expr<'tcx>>,
459-
source_span: Span,
460-
yield_span: Span,
461-
descr_pre: &str,
462-
descr_post: &str,
463-
plural_len: usize,
469+
data: SuspendCheckData<'_, 'tcx>,
464470
) -> bool {
465471
if ty.is_unit()
466472
// FIXME: should this check `is_ty_uninhabited_from`. This query is not available in this stage
467473
// of typeck (before ReVar and RePlaceholder are removed), but may remove noise, like in
468474
// `must_use`
469475
// || fcx.tcx.is_ty_uninhabited_from(fcx.tcx.parent_module(hir_id).to_def_id(), ty, fcx.param_env)
470476
{
471-
return true;
477+
return false;
472478
}
473479

474-
let plural_suffix = pluralize!(plural_len);
480+
let plural_suffix = pluralize!(data.plural_len);
475481

476482
match *ty.kind() {
477483
ty::Adt(..) if ty.is_box() => {
478484
let boxed_ty = ty.boxed_ty();
479-
let descr_pre = &format!("{}boxed ", descr_pre);
480-
check_must_not_suspend_ty(
481-
fcx,
482-
boxed_ty,
483-
hir_id,
484-
expr,
485-
source_span,
486-
yield_span,
487-
descr_pre,
488-
descr_post,
489-
plural_len,
490-
)
485+
let descr_pre = &format!("{}boxed ", data.descr_pre);
486+
check_must_not_suspend_ty(fcx, boxed_ty, hir_id, SuspendCheckData { descr_pre, ..data })
491487
}
492-
ty::Adt(def, _) => check_must_not_suspend_def(
493-
fcx.tcx,
494-
def.did,
495-
hir_id,
496-
source_span,
497-
yield_span,
498-
descr_pre,
499-
descr_post,
500-
),
488+
ty::Adt(def, _) => check_must_not_suspend_def(fcx.tcx, def.did, hir_id, data),
501489
// FIXME: support adding the attribute to TAITs
502490
ty::Opaque(def, _) => {
503491
let mut has_emitted = false;
@@ -507,15 +495,12 @@ pub fn check_must_not_suspend_ty<'tcx>(
507495
predicate.kind().skip_binder()
508496
{
509497
let def_id = poly_trait_predicate.trait_ref.def_id;
510-
let descr_pre = &format!("{}implementer{} of ", descr_pre, plural_suffix,);
498+
let descr_pre = &format!("{}implementer{} of ", data.descr_pre, plural_suffix);
511499
if check_must_not_suspend_def(
512500
fcx.tcx,
513501
def_id,
514502
hir_id,
515-
source_span,
516-
yield_span,
517-
descr_pre,
518-
descr_post,
503+
SuspendCheckData { descr_pre, ..data },
519504
) {
520505
has_emitted = true;
521506
break;
@@ -529,15 +514,12 @@ pub fn check_must_not_suspend_ty<'tcx>(
529514
for predicate in binder.iter() {
530515
if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() {
531516
let def_id = trait_ref.def_id;
532-
let descr_post = &format!(" trait object{}{}", plural_suffix, descr_post,);
517+
let descr_post = &format!(" trait object{}{}", plural_suffix, data.descr_post);
533518
if check_must_not_suspend_def(
534519
fcx.tcx,
535520
def_id,
536521
hir_id,
537-
source_span,
538-
yield_span,
539-
descr_pre,
540-
descr_post,
522+
SuspendCheckData { descr_post, ..data },
541523
) {
542524
has_emitted = true;
543525
break;
@@ -548,35 +530,38 @@ pub fn check_must_not_suspend_ty<'tcx>(
548530
}
549531
ty::Tuple(ref tys) => {
550532
let mut has_emitted = false;
551-
let spans = if let Some(hir::ExprKind::Tup(comps)) = expr.map(|e| &e.kind) {
533+
let spans = if let Some(hir::ExprKind::Tup(comps)) = data.expr.map(|e| &e.kind) {
552534
debug_assert_eq!(comps.len(), tys.len());
553535
comps.iter().map(|e| e.span).collect()
554536
} else {
555537
vec![]
556538
};
557539
for (i, ty) in tys.iter().map(|k| k.expect_ty()).enumerate() {
558540
let descr_post = &format!(" in tuple element {}", i);
559-
let span = *spans.get(i).unwrap_or(&source_span);
541+
let span = *spans.get(i).unwrap_or(&data.source_span);
560542
if check_must_not_suspend_ty(
561-
fcx, ty, hir_id, expr, span, yield_span, descr_pre, descr_post, plural_len,
543+
fcx,
544+
ty,
545+
hir_id,
546+
SuspendCheckData { descr_post, source_span: span, ..data },
562547
) {
563548
has_emitted = true;
564549
}
565550
}
566551
has_emitted
567552
}
568553
ty::Array(ty, len) => {
569-
let descr_pre = &format!("{}array{} of ", descr_pre, plural_suffix,);
554+
let descr_pre = &format!("{}array{} of ", data.descr_pre, plural_suffix);
570555
check_must_not_suspend_ty(
571556
fcx,
572557
ty,
573558
hir_id,
574-
expr,
575-
source_span,
576-
yield_span,
577-
descr_pre,
578-
descr_post,
579-
len.try_eval_usize(fcx.tcx, fcx.param_env).unwrap_or(0) as usize + 1,
559+
SuspendCheckData {
560+
descr_pre,
561+
plural_len: len.try_eval_usize(fcx.tcx, fcx.param_env).unwrap_or(0) as usize
562+
+ 1,
563+
..data
564+
},
580565
)
581566
}
582567
_ => false,
@@ -587,39 +572,38 @@ fn check_must_not_suspend_def(
587572
tcx: TyCtxt<'_>,
588573
def_id: DefId,
589574
hir_id: HirId,
590-
source_span: Span,
591-
yield_span: Span,
592-
descr_pre_path: &str,
593-
descr_post_path: &str,
575+
data: SuspendCheckData<'_, '_>,
594576
) -> bool {
595577
for attr in tcx.get_attrs(def_id).iter() {
596578
if attr.has_name(sym::must_not_suspend) {
597579
tcx.struct_span_lint_hir(
598580
rustc_session::lint::builtin::MUST_NOT_SUSPEND,
599581
hir_id,
600-
source_span,
582+
data.source_span,
601583
|lint| {
602584
let msg = format!(
603-
"{}`{}`{} held across a yield point, but should not be",
604-
descr_pre_path,
585+
"{}`{}`{} held across a suspend point, but should not be",
586+
data.descr_pre,
605587
tcx.def_path_str(def_id),
606-
descr_post_path
588+
data.descr_post,
607589
);
608590
let mut err = lint.build(&msg);
609591

610592
// add span pointing to the offending yield/await
611-
err.span_label(yield_span, "the value is held across this yield point");
593+
err.span_label(data.yield_span, "the value is held across this suspend point");
612594

613595
// Add optional reason note
614596
if let Some(note) = attr.value_str() {
615-
err.span_note(source_span, &note.as_str());
597+
// FIXME(guswynn): consider formatting this better
598+
err.span_note(data.source_span, &note.as_str());
616599
}
617600

618601
// Add some quick suggestions on what to do
602+
// FIXME: can `drop` work as a suggestion here as well?
619603
err.span_help(
620-
source_span,
621-
"`drop` this value before the yield point, or use a block (`{ ... }`) \
622-
to shrink its scope",
604+
data.source_span,
605+
"consider using a block (`{ ... }`) \
606+
to shrink the value's scope, ending before the suspend point",
623607
);
624608

625609
err.emit();

src/test/ui/lint/must_not_suspend/boxed.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
error: boxed `Umm` held across a yield point, but should not be
1+
error: boxed `Umm` held across a suspend point, but should not be
22
--> $DIR/boxed.rs:20:9
33
|
44
LL | let _guard = bar();
55
| ^^^^^^
66
LL | other().await;
7-
| ------------- the value is held across this yield point
7+
| ------------- the value is held across this suspend point
88
|
99
note: the lint level is defined here
1010
--> $DIR/boxed.rs:3:9
@@ -16,7 +16,7 @@ note: You gotta use Umm's, ya know?
1616
|
1717
LL | let _guard = bar();
1818
| ^^^^^^
19-
help: `drop` this value before the yield point, or use a block (`{ ... }`) to shrink its scope
19+
help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
2020
--> $DIR/boxed.rs:20:9
2121
|
2222
LL | let _guard = bar();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// edition:2018
2+
// run-pass
3+
#![feature(must_not_suspend)]
4+
#![deny(must_not_suspend)]
5+
6+
#[must_not_suspend = "You gotta use Umm's, ya know?"]
7+
struct Umm {
8+
_i: i64
9+
}
10+
11+
12+
fn bar() -> Umm {
13+
Umm {
14+
_i: 1
15+
}
16+
}
17+
18+
async fn other() {}
19+
20+
pub async fn uhoh() {
21+
{
22+
let _guard = bar();
23+
}
24+
other().await;
25+
}
26+
27+
fn main() {
28+
}

src/test/ui/lint/must_not_suspend/ref.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
error: `Umm` held across a yield point, but should not be
1+
error: `Umm` held across a suspend point, but should not be
22
--> $DIR/ref.rs:18:26
33
|
44
LL | let guard = &mut self.u;
55
| ^^^^^^
66
...
77
LL | other().await;
8-
| ------------- the value is held across this yield point
8+
| ------------- the value is held across this suspend point
99
|
1010
note: the lint level is defined here
1111
--> $DIR/ref.rs:3:9
@@ -17,27 +17,27 @@ note: You gotta use Umm's, ya know?
1717
|
1818
LL | let guard = &mut self.u;
1919
| ^^^^^^
20-
help: `drop` this value before the yield point, or use a block (`{ ... }`) to shrink its scope
20+
help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
2121
--> $DIR/ref.rs:18:26
2222
|
2323
LL | let guard = &mut self.u;
2424
| ^^^^^^
2525

26-
error: `Umm` held across a yield point, but should not be
26+
error: `Umm` held across a suspend point, but should not be
2727
--> $DIR/ref.rs:18:26
2828
|
2929
LL | let guard = &mut self.u;
3030
| ^^^^^^
3131
...
3232
LL | other().await;
33-
| ------------- the value is held across this yield point
33+
| ------------- the value is held across this suspend point
3434
|
3535
note: You gotta use Umm's, ya know?
3636
--> $DIR/ref.rs:18:26
3737
|
3838
LL | let guard = &mut self.u;
3939
| ^^^^^^
40-
help: `drop` this value before the yield point, or use a block (`{ ... }`) to shrink its scope
40+
help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
4141
--> $DIR/ref.rs:18:26
4242
|
4343
LL | let guard = &mut self.u;

src/test/ui/lint/must_not_suspend/trait.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,33 @@
1-
error: implementer of `Wow` held across a yield point, but should not be
1+
error: implementer of `Wow` held across a suspend point, but should not be
22
--> $DIR/trait.rs:21:9
33
|
44
LL | let _guard1 = r#impl();
55
| ^^^^^^^
66
...
77
LL | other().await;
8-
| ------------- the value is held across this yield point
8+
| ------------- the value is held across this suspend point
99
|
1010
note: the lint level is defined here
1111
--> $DIR/trait.rs:3:9
1212
|
1313
LL | #![deny(must_not_suspend)]
1414
| ^^^^^^^^^^^^^^^^
15-
help: `drop` this value before the yield point, or use a block (`{ ... }`) to shrink its scope
15+
help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
1616
--> $DIR/trait.rs:21:9
1717
|
1818
LL | let _guard1 = r#impl();
1919
| ^^^^^^^
2020

21-
error: boxed `Wow` trait object held across a yield point, but should not be
21+
error: boxed `Wow` trait object held across a suspend point, but should not be
2222
--> $DIR/trait.rs:22:9
2323
|
2424
LL | let _guard2 = r#dyn();
2525
| ^^^^^^^
2626
LL |
2727
LL | other().await;
28-
| ------------- the value is held across this yield point
28+
| ------------- the value is held across this suspend point
2929
|
30-
help: `drop` this value before the yield point, or use a block (`{ ... }`) to shrink its scope
30+
help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
3131
--> $DIR/trait.rs:22:9
3232
|
3333
LL | let _guard2 = r#dyn();

0 commit comments

Comments
 (0)