Skip to content

-Wunreachable-code triggers undesirable warnings when log-streaming into a sometimes-disabled logging macro #111092

@pbos

Description

@pbos

In Chromium / abseil we have some logging macros that are sometimes compiled as no-ops. This sort of boils to a more complicated version of this (which I wanted to simplify our implementation to):

#include <iostream>

#define LAZY_STREAM(stream, condition) \
  switch (0)                           \
  case 0:                              \
  default:                             \
    if (!(condition))                  \
      ;                                \
    else                               \
      (stream)

#define ENABLE_LOGGING 0
#define MAYBE_LOG() LAZY_STREAM(std::cout, ENABLE_LOGGING)

int main() {
  MAYBE_LOG();
  MAYBE_LOG() << "hello";  // error: code will never be executed [-Werror,-Wunreachable-code]
}

Here when ENABLE_LOGGING is false MAYBE_LOG() gets correctly compiled into nothing. MAYBE_LOG() << "hello"; however triggers dead-code warnings for the << "hello"; bit when logging is disabled at compile time.

https://godbolt.org/z/f9EPMordr

No idea what heuristic upgrades would make sense here. Special casing << makes sense to me, as may exonerating binary operators with a macro LHS (the dead-codiness comes from inside the macro). Unsure about whether MAYBE_LOG(), foo; should warn on dead foo or not.

chromium and absl currently spells this differently and gets away with streaming logs to dead code:

#define LAZY_STREAM(stream, condition)                                  \
  !(condition) ? (void) 0 : ::logging::LogMessageVoidify() & (stream)

This seems to be sufficient to confuse clang enough to not issue dead-code warnings to (stream) even though it's part of the compile-time-known dead branch of the ternary.

Changing our implementation of LAZY_STREAM to the former results in dead-code warnings ~everywhere in chromium. Ideally we shouldn't make it harder for the compiler to deduce that this is indeed dead code, but that it should be OK since it originates from a macro (or some other heuristic that lets us do this). crrev.com/c/5905021 has the try run that explodes everywhere.

Metadata

Metadata

Assignees

No one assigned

    Labels

    clang:diagnosticsNew/improved warning or error message in Clang, but not in clang-tidy or static analyzer

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions