Skip to content

Commit 5b39ef8

Browse files
committed
add temporary lints for crater run(s), detecting proposed change in muse use behavior
1 parent 3ab6b23 commit 5b39ef8

File tree

1 file changed

+94
-8
lines changed

1 file changed

+94
-8
lines changed

compiler/rustc_lint/src/unused.rs

Lines changed: 94 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,20 @@ declare_lint! {
5353
report_in_external_macro
5454
}
5555

56+
declare_lint! {
57+
pub UNMUSTUSE_IN_ALWAYS_OK,
58+
Warn,
59+
"",
60+
report_in_external_macro
61+
}
62+
63+
declare_lint! {
64+
pub MUSTUSE_IN_ALWAYS_OK,
65+
Warn,
66+
"",
67+
report_in_external_macro
68+
}
69+
5670
declare_lint! {
5771
/// The `unused_results` lint checks for the unused result of an
5872
/// expression in a statement.
@@ -92,7 +106,7 @@ declare_lint! {
92106
"unused result of an expression in a statement"
93107
}
94108

95-
declare_lint_pass!(UnusedResults => [UNUSED_MUST_USE, UNUSED_RESULTS]);
109+
declare_lint_pass!(UnusedResults => [UNUSED_MUST_USE, UNUSED_RESULTS, UNMUSTUSE_IN_ALWAYS_OK, MUSTUSE_IN_ALWAYS_OK]);
96110

97111
impl<'tcx> LateLintPass<'tcx> for UnusedResults {
98112
fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
@@ -136,7 +150,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
136150

137151
let ty = cx.typeck_results().expr_ty(expr);
138152

139-
let must_use_result = is_ty_must_use(cx, ty, expr, expr.span);
153+
let must_use_result = is_ty_must_use(cx, ty, expr, expr.span, false);
140154
let type_lint_emitted_or_suppressed = match must_use_result {
141155
Some(path) => {
142156
emit_must_use_untranslated(cx, &path, "", "", 1, false, expr_is_from_block);
@@ -209,6 +223,12 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
209223
cx.emit_span_lint(UNUSED_RESULTS, s.span, UnusedResult { ty });
210224
}
211225
}
226+
227+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
228+
let ty = cx.typeck_results().expr_ty(expr);
229+
230+
_ = is_ty_must_use(cx, ty, expr, expr.span, true);
231+
}
212232
}
213233

214234
fn check_fn_must_use(cx: &LateContext<'_>, expr: &hir::Expr<'_>, expr_is_from_block: bool) -> bool {
@@ -259,12 +279,33 @@ enum MustUsePath {
259279
Coroutine(Span),
260280
}
261281

282+
fn is_suppressed(p: &MustUsePath) -> bool {
283+
match p {
284+
MustUsePath::Suppressed => true,
285+
286+
MustUsePath::Def(..) | MustUsePath::Closure(..) | MustUsePath::Coroutine(..) => false,
287+
288+
MustUsePath::Boxed(must_use_path)
289+
| MustUsePath::Pinned(must_use_path)
290+
| MustUsePath::Opaque(must_use_path)
291+
| MustUsePath::Array(must_use_path, _)
292+
| MustUsePath::TraitObject(must_use_path)
293+
| MustUsePath::Result(must_use_path)
294+
| MustUsePath::ControlFlow(must_use_path) => is_suppressed(must_use_path),
295+
296+
MustUsePath::TupleElement(items) => {
297+
items.iter().all(|(_, must_use_path)| is_suppressed(must_use_path))
298+
}
299+
}
300+
}
301+
262302
#[instrument(skip(cx, expr), level = "debug", ret)]
263303
fn is_ty_must_use<'tcx>(
264304
cx: &LateContext<'tcx>,
265305
ty: Ty<'tcx>,
266306
expr: &hir::Expr<'_>,
267307
span: Span,
308+
tmp_lint: bool,
268309
) -> Option<MustUsePath> {
269310
if ty.is_unit() {
270311
return Some(MustUsePath::Suppressed);
@@ -276,11 +317,12 @@ fn is_ty_must_use<'tcx>(
276317
match *ty.kind() {
277318
_ if is_uninhabited(ty) => Some(MustUsePath::Suppressed),
278319
ty::Adt(..) if let Some(boxed) = ty.boxed_ty() => {
279-
is_ty_must_use(cx, boxed, expr, span).map(|inner| MustUsePath::Boxed(Box::new(inner)))
320+
is_ty_must_use(cx, boxed, expr, span, tmp_lint)
321+
.map(|inner| MustUsePath::Boxed(Box::new(inner)))
280322
}
281323
ty::Adt(def, args) if cx.tcx.is_lang_item(def.did(), LangItem::Pin) => {
282324
let pinned_ty = args.type_at(0);
283-
is_ty_must_use(cx, pinned_ty, expr, span)
325+
is_ty_must_use(cx, pinned_ty, expr, span, tmp_lint)
284326
.map(|inner| MustUsePath::Pinned(Box::new(inner)))
285327
}
286328
// Consider `Result<T, Uninhabited>` (e.g. `Result<(), !>`) equivalent to `T`.
@@ -289,15 +331,59 @@ fn is_ty_must_use<'tcx>(
289331
&& is_uninhabited(args.type_at(1)) =>
290332
{
291333
let ok_ty = args.type_at(0);
292-
is_ty_must_use(cx, ok_ty, expr, span).map(Box::new).map(MustUsePath::Result)
334+
let res = is_ty_must_use(cx, ok_ty, expr, span, tmp_lint)
335+
.map(Box::new)
336+
.map(MustUsePath::Result);
337+
338+
if tmp_lint
339+
&& !matches!(ok_ty.kind(), ty::Param(_))
340+
&& res.as_ref().is_none_or(is_suppressed)
341+
{
342+
cx.span_lint(UNMUSTUSE_IN_ALWAYS_OK, span, |d| {
343+
d.primary_message(format!("this type will no longer be must used: {ty}"));
344+
});
345+
}
346+
347+
if tmp_lint
348+
&& !matches!(ok_ty.kind(), ty::Param(_))
349+
&& res.as_ref().is_some_and(|x| !is_suppressed(x))
350+
{
351+
cx.span_lint(MUSTUSE_IN_ALWAYS_OK, span, |d| {
352+
d.primary_message(format!("this type continue be must used: {ty}"));
353+
});
354+
}
355+
356+
res
293357
}
294358
// Consider `ControlFlow<Uninhabited, T>` (e.g. `ControlFlow<!, ()>`) equivalent to `T`.
295359
ty::Adt(def, args)
296360
if cx.tcx.is_diagnostic_item(sym::ControlFlow, def.did())
297361
&& is_uninhabited(args.type_at(0)) =>
298362
{
299363
let continue_ty = args.type_at(1);
300-
is_ty_must_use(cx, continue_ty, expr, span).map(Box::new).map(MustUsePath::ControlFlow)
364+
let res = is_ty_must_use(cx, continue_ty, expr, span, tmp_lint)
365+
.map(Box::new)
366+
.map(MustUsePath::ControlFlow);
367+
368+
if tmp_lint
369+
&& !matches!(continue_ty.kind(), ty::Param(_))
370+
&& res.as_ref().is_none_or(is_suppressed)
371+
{
372+
cx.span_lint(UNMUSTUSE_IN_ALWAYS_OK, span, |d| {
373+
d.primary_message(format!("this type will no longer be must used: {ty}"));
374+
});
375+
}
376+
377+
if tmp_lint
378+
&& !matches!(continue_ty.kind(), ty::Param(_))
379+
&& res.as_ref().is_some_and(|x| !is_suppressed(x))
380+
{
381+
cx.span_lint(MUSTUSE_IN_ALWAYS_OK, span, |d| {
382+
d.primary_message(format!("this type continue be must used: {ty}"));
383+
});
384+
}
385+
386+
res
301387
}
302388
ty::Adt(def, _) => is_def_must_use(cx, def.did(), span),
303389
ty::Alias(ty::Opaque | ty::Projection, ty::AliasTy { def_id: def, .. }) => {
@@ -343,7 +429,7 @@ fn is_ty_must_use<'tcx>(
343429
.zip(elem_exprs)
344430
.enumerate()
345431
.filter_map(|(i, (ty, expr))| {
346-
is_ty_must_use(cx, ty, expr, expr.span).map(|path| (i, path))
432+
is_ty_must_use(cx, ty, expr, expr.span, tmp_lint).map(|path| (i, path))
347433
})
348434
.collect::<Vec<_>>();
349435

@@ -357,7 +443,7 @@ fn is_ty_must_use<'tcx>(
357443
// If the array is empty we don't lint, to avoid false positives
358444
Some(0) | None => None,
359445
// If the array is definitely non-empty, we can do `#[must_use]` checking.
360-
Some(len) => is_ty_must_use(cx, ty, expr, span)
446+
Some(len) => is_ty_must_use(cx, ty, expr, span, tmp_lint)
361447
.map(|inner| MustUsePath::Array(Box::new(inner), len)),
362448
},
363449
ty::Closure(..) | ty::CoroutineClosure(..) => Some(MustUsePath::Closure(span)),

0 commit comments

Comments
 (0)