-
Notifications
You must be signed in to change notification settings - Fork 15.1k
Description
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.