I'm the primary author of this style rule. I've been hoping this thread would converge, but perhaps it helps to weigh in with a few things.
In an ideal world, we would not have both DCHECK and CHECK -- we would have a single macro, which asserts to the reader that it is the author's opinion that some condition is an invariant precondition at that point (barring cosmic rays flipping bits between statements). The condition in question can be relied upon utterly, and the compiler can optimize away any code which would depend on it being violated. The compiler need not check that the condition holds, because we _know_ the condition holds. More important, the reader knows that the author wrote the code under the belief that that condition holds. And, assuming the author is correct, the reader can then simplify all callers and callees, transitively, by assuming that condition holds.
In this world, the assertion in question is critical documentation to the reader as to the author's state of mind when writing the code, and it greatly helps in later refactoring and cleanup, because it tells us what sorts of refactors should maintain validity of the code in question.
We would never let authors write code of the form:
if (i < 0) return;
if (i < 0) ...
...because the second conditional is nonsensical. At best, it's clutter. At worst, later refactoring could obscure the fact that it is nonsensical, resulting in people misunderstanding the preconditions of code they're reading, and beginning themselves to write complicated defense in their own code for conditions which can never occur. And in our ideal world, authors would treat this the same way:
INFALLIBLY_ASSERT(i >= 0);
if (i < 0) ...
Because the assertion is trustworthy, this has all the downsides mentioned above, and no upsides.
As soon as the assertion is not trustworthy, the benefits above fall apart. It is not safe for the compiler to optimize based on the assertion, because that could introduce cryptic bugs. It's not safe to refactor based on the assertion, because that could spread bugs across the codebase. The only remaining value of the assertion is if the code _does_ check whether it holds, and reports it back to us in some way, so that we can gather stats and make changes based on that.
When we wrote DCHECK, we intended it to have the first ("trustworthy") meaning, not the second. It meant that the author was certain the condition held and that we could safely optimize away checking that condition, or any consequent effects. The style guidance we have arose from this conception. We did still compile in such checks in developer mode, primarily so that while developers were in the midst of writing them they'd get notified about anything obviously silly they did, but we wanted them to be used as documentation of pre- and post-conditions, not as some sort of early-warning for surprising cases. If you weren't sure whether a DCHECK could fire, you needed to audit the code further until you were certain it could or certain it couldn't. Then either handle it without DCHECKing, or DCHECK without handling it. No middle ground.
CHECK was actually intended to be the defense-in-depth case. Much like trying to "handle" allocation failures due to OOM, "handling" the violation of believed-infallible preconditions just punts the problem to your callers and callees. It is better to crash immediately in such cases. CHECK was the concession we made to the reality that developers are not infallible. We reserved it for the case of security bugs primarily to avoid muddying the waters on whether or not DCHECKs were "trustworthy enough" (we didn't want people to believe CHECKs were "more trustworthy").
It has become clear over time that our existing DCHECKs are not as infallible as we'd like them to be, to the point where increasingly authors are suspicious of whether they can truly rely on them. We believe that we need wider testing, fixing, and enforcement of them, so that we can be sure they're holding in production. pbos@ has been leading this effort. Over time, you will likely see changes to both what assertion-like macros exist, as well as our style guidance on when to use them, so we can have more consistent testing of our assertions without adding too much binary size or runtime cost (as we believe will happen if we blindly convert ALL DCHECKs to CHECKs today).
In the meantime, I suggest you avoid "DCHECK + handler code". Be clear about the API design of your function: what are its preconditions and postconditions? Audit the callers and callees, and enforce the conditions you expect. Document them, both in comments and with DCHECKs, along with why it's important that your code have them. And handle (without DCHECKing) cases outside those.
PK