From a79858c329baf2f17ec28b32061db7126099b59e Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Tue, 2 Dec 2025 12:04:58 +0100 Subject: [PATCH] reduce `unreachable-code` churn after `todo!()` --- compiler/rustc_hir_typeck/src/expr.rs | 9 +++++- compiler/rustc_middle/src/ty/context.rs | 15 +++++++++ library/core/src/macros/mod.rs | 5 ++- tests/ui/reachable/todo.rs | 41 +++++++++++++++++++++++++ tests/ui/reachable/todo.stderr | 16 ++++++++++ 5 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 tests/ui/reachable/todo.rs create mode 100644 tests/ui/reachable/todo.stderr diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 658f9857e5e10..b1dd24239e6f2 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -322,7 +322,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if self.try_structurally_resolve_type(expr.span, ty).is_never() && self.expr_guaranteed_to_constitute_read_for_never(expr) { - self.diverges.set(self.diverges.get() | Diverges::always(expr.span)); + let diverges = if self.tcx.is_expanded_by(expr.span, sym::todo_macro) { + // We don't warn for `todo!()` that diverges to avoid flooding the + // user with warnings while they are still working on their code. + Diverges::WarnedAlways + } else { + Diverges::always(expr.span) + }; + self.diverges.set(self.diverges.get() | diverges); } // Record the type, which applies it effects. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0cd36d5e971de..b439aa511274a 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2131,6 +2131,21 @@ impl<'tcx> TyCtxt<'tcx> { None => Err(VarError::NotPresent), } } + + /// Returns whether this context was expanded by the macro with the given name. + pub fn is_expanded_by(self, span: Span, mac: Symbol) -> bool { + let mut ctxt = span.ctxt(); + while !ctxt.is_root() { + let data = ctxt.outer_expn_data(); + if let Some(def_id) = data.macro_def_id + && self.is_diagnostic_item(mac, def_id) + { + return true; + } + ctxt = data.call_site.ctxt(); + } + false + } } impl<'tcx> TyCtxtAt<'tcx> { diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index f3386985bdf1b..7ee61f142e755 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -812,7 +812,10 @@ macro_rules! unimplemented { /// an intent of implementing the functionality later and the message is "not yet /// implemented", `unimplemented!` makes no such claims. Its message is "not implemented". /// -/// Also, some IDEs will mark `todo!`s. +/// Also, some IDEs will mark `todo!`s. Furthermore, the `unreachable_code` lint will +/// not warn on code that is unreachable because of a `todo!()` to reduce unhelpful +/// messages. The code will however still be marked as unreachable, which may have an +/// effect on type and lifetime checks. /// /// # Panics /// diff --git a/tests/ui/reachable/todo.rs b/tests/ui/reachable/todo.rs new file mode 100644 index 0000000000000..3c71471a2f13d --- /dev/null +++ b/tests/ui/reachable/todo.rs @@ -0,0 +1,41 @@ +//@ check-pass +//@ edition: 2018 + +#![allow(unused)] +#![warn(unreachable_code)] + +macro_rules! later { + () => { todo!() }; +} + +fn foo() { + todo!(); + let this_is_unreachable = 1; +} + +fn bar() { + panic!("This is really unreachable"); + let really_unreachable = true; + //~^ WARNING: unreachable +} + +fn baz() -> bool { + if true { + todo!(); + false + } else if todo!() { + true + } else { + later!(); + false + } +} + +fn main() { + foo(); + bar(); + if baz() { + todo!(); + } + let this_is_reachable = 1; +} diff --git a/tests/ui/reachable/todo.stderr b/tests/ui/reachable/todo.stderr new file mode 100644 index 0000000000000..bd9b4bec356e3 --- /dev/null +++ b/tests/ui/reachable/todo.stderr @@ -0,0 +1,16 @@ +warning: unreachable statement + --> $DIR/todo.rs:18:5 + | +LL | panic!("This is really unreachable"); + | ------------------------------------ any code following this expression is unreachable +LL | let really_unreachable = true; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable statement + | +note: the lint level is defined here + --> $DIR/todo.rs:5:9 + | +LL | #![warn(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted +