Tracing a lint's reasoning

Over the years I have learned an important lesson about lints: Whenever I encounter a warning that I don't think is true, I should step away for five minutes, stretch and make a fresh cup of tea, and then just read the code carefully. It is extremely rare that the lint warning is wrong.

Recently I encountered a lint warning for a piece of code whose outline looks like this:

loop {
  let did_proc = false;

  if some_condition_1 {
    did_proc = true;
    // .. other stuff ..
  }

  if some_condition_2 {
    did_proc = true;
    // .. other stuff ..
  }

  if some_condition_3 {
    did_proc = true;
    // .. other stuff ..
  }

  if !did_proc {
    break;
  }
}

It's telling me that the did_proc = true's are never read. The "other stuff" sections contain a bunch of continue and breaks. So what I'm thinking is that when the did_proc = true has been run, the compiler reasons that all branches lead to either a break or a continue. However, there's one path in each of these sections that has neither a break or continue. So I'm wondering if the compiler is able to deduce that this path can't happen.

As much as I love lints, this is one of the things that can become a little bit of a time-sink for me. Is there any way to see how the lint is "reasoning" (to get a hint about why it is triggering?). I have no idea how this would look, but I'm curious to know how people track down terse lint warnings whose cause isn't immediately obvious.


While writing this, I think I figured out why it's issuing that warning -- and if so it is indeed correct. But my question still stands -- because this isn't the first (or, I suspect, last) time this happened.

There is, unfortunately, no general mechanism for examining lints’ reasoning, nor for examining this one.

The “never read” warnings are, in my experience, highly accurate, and follow the same sort of control-flow-based reasoning as rustc’s dead_code lint and borrow checking. So, you can expect that, in fact, every path that leads to did_proc = true also leads to exiting the current loop iteration. Thus, either:

  • you can delete the if !did_proc { break }, or
  • you have a bug in your code where that part should be reachable but isn’t.

You may be able to narrow down the problem by inserting dummy statements into the code paths that should lead to neither breaking nor continuing. If that statement is flagged as dead_code then you know that path is unreachable when it should be reachable.

5 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.