| // Copyright 2017-2020 The Verible Authors. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #ifndef VERIBLE_COMMON_UTIL_LOGGING_H_ | |
| #define VERIBLE_COMMON_UTIL_LOGGING_H_ | |
| #include <atomic> | |
| #include <cstdint> | |
| #include <limits> | |
| #include <memory> | |
| #include <sstream> | |
| #include <string> | |
| #include "absl/base/log_severity.h" | |
| #include "absl/base/optimization.h" | |
| #include "absl/strings/string_view.h" | |
| // Prevent this Windows.h #define from leaking out of our headers. | |
| #undef ERROR | |
| namespace verible { | |
| const int INFO = 0; // base_logging::INFO; | |
| const int WARNING = 1; // base_logging::WARNING; | |
| const int ERROR = 2; // base_logging::ERROR; | |
| const int FATAL = 3; // base_logging::FATAL; | |
| const int NUM_SEVERITIES = 4; // base_logging::NUM_SEVERITIES; | |
| namespace internal { | |
| class LogMessage : public std::basic_ostringstream<char> { | |
| public: | |
| LogMessage(const char* fname, int line, int severity); | |
| ~LogMessage() override; | |
| // Returns the minimum log level for VLOG statements. | |
| // E.g., if MinVLogLevel() is 2, then VLOG(2) statements will produce output, | |
| // but VLOG(3) will not. Defaults to 0. | |
| static int64_t MinVLogLevel(); | |
| // Returns whether VLOG level lvl is activated for the file fname. | |
| // | |
| // E.g. if the environment variable VERIBLE_CPP_VMODULE contains foo=3 and | |
| // fname is foo.cc and lvl is <= 3, this will return true. It will also return | |
| // true if the level is lower or equal to VERIBLE_CPP_MIN_VLOG_LEVEL (default | |
| // zero). | |
| // | |
| // It is expected that the result of this query will be cached in the VLOG-ing | |
| // call site to avoid repeated lookups. This routine performs a hash-map | |
| // access against the VLOG-ing specification provided by the env var. | |
| static bool VmoduleActivated(const char* fname, int level); | |
| protected: | |
| void GenerateLogMessage(); | |
| private: | |
| const char* fname_; | |
| int line_; | |
| int severity_; | |
| }; | |
| // Uses the lower operator & precedence to voidify a LogMessage reference, so | |
| // that the ternary VLOG() implementation is balanced, type wise. | |
| struct Voidifier { | |
| template <typename T> | |
| void operator&(const T&) const {} | |
| }; | |
| // LogMessageFatal ensures the process will exit in failure after | |
| // logging this message. | |
| class LogMessageFatal : public LogMessage { | |
| public: | |
| LogMessageFatal(const char* file, int line) ABSL_ATTRIBUTE_COLD; | |
| ABSL_ATTRIBUTE_NORETURN ~LogMessageFatal() override; | |
| }; | |
| // LogMessageNull supports the DVLOG macro by simply dropping any log messages. | |
| class LogMessageNull : public std::basic_ostringstream<char> { | |
| public: | |
| LogMessageNull() {} | |
| ~LogMessageNull() override {} | |
| }; | |
| #define _VERIBLE_LOG_INFO \ | |
| ::verible::internal::LogMessage(__FILE__, __LINE__, ::verible::INFO) | |
| #define _VERIBLE_LOG_WARNING \ | |
| ::verible::internal::LogMessage(__FILE__, __LINE__, ::verible::WARNING) | |
| #define _VERIBLE_LOG_ERROR \ | |
| ::verible::internal::LogMessage(__FILE__, __LINE__, ::verible::ERROR) | |
| #define _VERIBLE_LOG_FATAL \ | |
| ::verible::internal::LogMessageFatal(__FILE__, __LINE__) | |
| #define LOG(severity) _VERIBLE_LOG_##severity | |
| #define _VERIBLE_LOG_QFATAL _VERIBLE_LOG_FATAL | |
| // Otherwise, set VERIBLE_CPP_MIN_VLOG_LEVEL environment to update minimum log | |
| // level of VLOG, or VERIBLE_CPP_VMODULE to set the minimum log level for | |
| // individual translation units. | |
| #define VLOG_IS_ON(lvl) \ | |
| (([](int level, const char* fname) { \ | |
| static const bool vmodule_activated = \ | |
| ::verible::internal::LogMessage::VmoduleActivated(fname, level); \ | |
| return vmodule_activated; \ | |
| })(lvl, __FILE__)) | |
| #define VLOG(level) \ | |
| ABSL_PREDICT_TRUE(!VLOG_IS_ON(level)) \ | |
| ? (void)0 \ | |
| : ::verible::internal::Voidifier() & \ | |
| ::verible::internal::LogMessage(__FILE__, __LINE__, verible::INFO) | |
| // `DVLOG` behaves like `VLOG` in debug mode (i.e. `#ifndef NDEBUG`). | |
| // Otherwise, it compiles away and does nothing. | |
| #ifndef NDEBUG | |
| #define DVLOG VLOG | |
| #else | |
| #define DVLOG(verbose_level) \ | |
| while (false && (verbose_level) > 0) ::verible::internal::LogMessageNull() | |
| #endif | |
| class LogEveryNState { | |
| public: | |
| bool ShouldLog(int n); | |
| uint32_t counter() { return counter_.load(std::memory_order_relaxed); } | |
| private: | |
| std::atomic<uint32_t> counter_{0}; | |
| }; | |
| class LogFirstNState { | |
| public: | |
| bool ShouldLog(int n); | |
| uint32_t counter() { return counter_.load(std::memory_order_relaxed); } | |
| private: | |
| std::atomic<uint32_t> counter_{0}; | |
| }; | |
| class LogEveryPow2State { | |
| public: | |
| bool ShouldLog(int ignored); | |
| uint32_t counter() { return counter_.load(std::memory_order_relaxed); } | |
| private: | |
| std::atomic<uint32_t> counter_{0}; | |
| }; | |
| class LogEveryNSecState { | |
| public: | |
| bool ShouldLog(double seconds); | |
| uint32_t counter() { return counter_.load(std::memory_order_relaxed); } | |
| private: | |
| std::atomic<uint32_t> counter_{0}; | |
| // Cycle count according to CycleClock that we should next log at. | |
| std::atomic<int64_t> next_log_time_cycles_{0}; | |
| }; | |
| // This macro has a lot going on! | |
| // | |
| // * A local static (`logging_internal_stateful_condition_state`) is | |
| // declared in a scope such that each `LOG_EVERY_N` (etc.) line has its own | |
| // state. | |
| // * `COUNTER`, the third variable, is used to support `<< COUNTER`. It is not | |
| // mangled, so shadowing can be a problem, albeit more of a | |
| // shoot-yourself-in-the-foot one. Don't name your variables `COUNTER`. | |
| // * A single for loop can declare state and also test | |
| // `condition && state.ShouldLog()`, but there's no way to constrain it to run | |
| // only once (or not at all) without declaring another variable. The outer | |
| // for-loop declares this variable (`do_log`). | |
| // * Using for loops instead of if statements means there's no risk of an | |
| // ambiguous dangling else statement. | |
| #define LOGGING_INTERNAL_STATEFUL_CONDITION(kind, condition, arg) \ | |
| for (bool logging_internal_stateful_condition_do_log(condition); \ | |
| logging_internal_stateful_condition_do_log; \ | |
| logging_internal_stateful_condition_do_log = false) \ | |
| for (static ::verible::internal::Log##kind##State \ | |
| logging_internal_stateful_condition_state; \ | |
| logging_internal_stateful_condition_do_log && \ | |
| logging_internal_stateful_condition_state.ShouldLog(arg); \ | |
| logging_internal_stateful_condition_do_log = false) \ | |
| for (const uint32_t COUNTER ABSL_ATTRIBUTE_UNUSED = \ | |
| logging_internal_stateful_condition_state.counter(); \ | |
| logging_internal_stateful_condition_do_log; \ | |
| logging_internal_stateful_condition_do_log = false) | |
| // An instance of `LOG_EVERY_N` increments a hidden zero-initialized counter | |
| // every time execution passes through it and logs the specified message when | |
| // the counter's value is a multiple of `n`, doing nothing otherwise. Each | |
| // instance has its own counter. The counter's value can be logged by streaming | |
| // the symbol `COUNTER`. `LOG_EVERY_N` is thread-safe. | |
| // Example: | |
| // | |
| // for (const auto& user : all_users) { | |
| // LOG_EVERY_N(INFO, 1000) << "Processing user #" << COUNTER; | |
| // ProcessUser(user); | |
| // } | |
| #define LOG_EVERY_N(severity, n) \ | |
| LOGGING_INTERNAL_STATEFUL_CONDITION(EveryN, true, n) \ | |
| LOG(severity) | |
| // `LOG_FIRST_N` behaves like `LOG_EVERY_N` except that the specified message is | |
| // logged when the counter's value is less than `n`. `LOG_FIRST_N` is | |
| // thread-safe. | |
| #define LOG_FIRST_N(severity, n) \ | |
| LOGGING_INTERNAL_STATEFUL_CONDITION(FirstN, true, n) \ | |
| LOG(severity) | |
| // `LOG_EVERY_POW_2` behaves like `LOG_EVERY_N` except that the specified | |
| // message is logged when the counter's value is a power of 2. | |
| // `LOG_EVERY_POW_2` is thread-safe. | |
| #define LOG_EVERY_POW_2(severity) \ | |
| LOGGING_INTERNAL_STATEFUL_CONDITION(EveryPow2, true, 0) \ | |
| LOG(severity) | |
| // An instance of `LOG_EVERY_N_SEC` uses a hidden state variable to log the | |
| // specified message at most once every `n_seconds`. A hidden counter of | |
| // executions (whether a message is logged or not) is also maintained and can be | |
| // logged by streaming the symbol `COUNTER`. `LOG_EVERY_N_SEC` is thread-safe. | |
| // Example: | |
| // | |
| // LOG_EVERY_N_SEC(INFO, 2.5) << "Got " << COUNTER << " cookies so far"; | |
| #define LOG_EVERY_N_SEC(severity, n_seconds) \ | |
| LOGGING_INTERNAL_STATEFUL_CONDITION(EveryNSec, true, n_seconds) \ | |
| LOG(severity) | |
| // CHECK dies with a fatal error if condition is not true. It is *not* | |
| // controlled by NDEBUG, so the check will be executed regardless of | |
| // compilation mode. Therefore, it is safe to do things like: | |
| // CHECK(fp->Write(x) == 4) | |
| #define CHECK(condition) \ | |
| if (ABSL_PREDICT_FALSE(!(condition))) \ | |
| _VERIBLE_LOG_FATAL << "Check failed: " #condition " " | |
| // Function is overloaded for integral types to allow static const | |
| // integrals declared in classes and not defined to be used as arguments to | |
| // CHECK* macros. It's not encouraged though. | |
| template <typename T> | |
| inline const T& GetReferenceableValue(const T& t) { | |
| return t; | |
| } | |
| inline char GetReferenceableValue(char t) { return t; } | |
| inline unsigned char GetReferenceableValue(unsigned char t) { return t; } | |
| inline signed char GetReferenceableValue(signed char t) { return t; } | |
| inline int16_t GetReferenceableValue(int16_t t) { return t; } | |
| inline uint16_t GetReferenceableValue(uint16_t t) { return t; } | |
| inline int GetReferenceableValue(int t) { return t; } | |
| inline unsigned int GetReferenceableValue(unsigned int t) { return t; } | |
| inline int64_t GetReferenceableValue(int64_t t) { return t; } | |
| inline uint64_t GetReferenceableValue(uint64_t t) { return t; } | |
| // This formats a value for a failing CHECK_XX statement. Ordinarily, | |
| // it uses the definition for operator<<, with a few special cases below. | |
| template <typename T> | |
| inline void MakeCheckOpValueString(std::ostream* os, const T& v) { | |
| (*os) << v; | |
| } | |
| // Overrides for char types provide readable values for unprintable | |
| // characters. | |
| template <> | |
| void MakeCheckOpValueString(std::ostream* os, const char& v); | |
| template <> | |
| void MakeCheckOpValueString(std::ostream* os, const signed char& v); | |
| template <> | |
| void MakeCheckOpValueString(std::ostream* os, const unsigned char& v); | |
| // We need an explicit specialization for std::nullptr_t. | |
| template <> | |
| void MakeCheckOpValueString(std::ostream* os, const std::nullptr_t& p); | |
| // A container for a string pointer which can be evaluated to a bool - | |
| // true iff the pointer is non-NULL. | |
| struct CheckOpString { | |
| CheckOpString(std::string* str) : str_(str) {} | |
| // No destructor: if str_ is non-NULL, we're about to LOG(FATAL), | |
| // so there's no point in cleaning up str_. | |
| operator bool() const { return ABSL_PREDICT_FALSE(str_ != NULL); } | |
| std::string* str_; | |
| }; | |
| // Build the error message string. Specify no inlining for code size. | |
| template <typename T1, typename T2> | |
| std::string* MakeCheckOpString(const T1& v1, const T2& v2, | |
| const char* exprtext) ABSL_ATTRIBUTE_NOINLINE; | |
| // A helper class for formatting "expr (V1 vs. V2)" in a CHECK_XX | |
| // statement. See MakeCheckOpString for sample usage. Other | |
| // approaches were considered: use of a template method (e.g., | |
| // base::BuildCheckOpString(exprtext, base::Print<T1>, &v1, | |
| // base::Print<T2>, &v2), however this approach has complications | |
| // related to volatile arguments and function-pointer arguments). | |
| class CheckOpMessageBuilder { | |
| public: | |
| // Inserts "exprtext" and " (" to the stream. | |
| explicit CheckOpMessageBuilder(const char* exprtext); | |
| // Deletes "stream_". | |
| ~CheckOpMessageBuilder(); | |
| // For inserting the first variable. | |
| std::ostream* ForVar1() { return stream_; } | |
| // For inserting the second variable (adds an intermediate " vs. "). | |
| std::ostream* ForVar2(); | |
| // Get the result (inserts the closing ")"). | |
| std::string* NewString(); | |
| private: | |
| std::ostringstream* stream_; | |
| }; | |
| template <typename T1, typename T2> | |
| std::string* MakeCheckOpString(const T1& v1, const T2& v2, | |
| const char* exprtext) { | |
| CheckOpMessageBuilder comb(exprtext); | |
| MakeCheckOpValueString(comb.ForVar1(), v1); | |
| MakeCheckOpValueString(comb.ForVar2(), v2); | |
| return comb.NewString(); | |
| } | |
| // Helper functions for CHECK_OP macro. | |
| // The (int, int) specialization works around the issue that the compiler | |
| // will not instantiate the template version of the function on values of | |
| // unnamed enum type - see comment below. | |
| // The (size_t, int) and (int, size_t) specialization are to handle unsigned | |
| // comparison errors while still being thorough with the comparison. | |
| #define VERIBLE_DEFINE_CHECK_OP_IMPL(name, op) \ | |
| template <typename T1, typename T2> \ | |
| inline std::string* name##Impl(const T1& v1, const T2& v2, \ | |
| const char* exprtext) { \ | |
| if (ABSL_PREDICT_TRUE(v1 op v2)) \ | |
| return NULL; \ | |
| else \ | |
| return ::verible::internal::MakeCheckOpString(v1, v2, exprtext); \ | |
| } \ | |
| inline std::string* name##Impl(int v1, int v2, const char* exprtext) { \ | |
| return name##Impl<int, int>(v1, v2, exprtext); \ | |
| } \ | |
| inline std::string* name##Impl(const size_t v1, const int v2, \ | |
| const char* exprtext) { \ | |
| if (ABSL_PREDICT_FALSE(v2 < 0)) { \ | |
| return ::verible::internal::MakeCheckOpString(v1, v2, exprtext); \ | |
| } \ | |
| return name##Impl<size_t, size_t>(v1, v2, exprtext); \ | |
| } \ | |
| inline std::string* name##Impl(const int v1, const size_t v2, \ | |
| const char* exprtext) { \ | |
| const size_t max_compare = std::numeric_limits<int>::max(); \ | |
| if (ABSL_PREDICT_FALSE(v2 >= max_compare)) { \ | |
| return ::verible::internal::MakeCheckOpString(v1, v2, exprtext); \ | |
| } \ | |
| const size_t uval = (size_t)((unsigned)v2); \ | |
| return name##Impl<size_t, size_t>(v1, uval, exprtext); \ | |
| } | |
| // We use the full name Check_EQ, Check_NE, etc. in case the file including | |
| // base/logging.h provides its own #defines for the simpler names EQ, NE, etc. | |
| // This happens if, for example, those are used as token names in a | |
| // yacc grammar. | |
| VERIBLE_DEFINE_CHECK_OP_IMPL(Check_EQ, | |
| ==) // Compilation error with CHECK_EQ(NULL, x)? | |
| VERIBLE_DEFINE_CHECK_OP_IMPL(Check_NE, !=) // Use CHECK(x == NULL) instead. | |
| VERIBLE_DEFINE_CHECK_OP_IMPL(Check_LE, <=) | |
| VERIBLE_DEFINE_CHECK_OP_IMPL(Check_LT, <) | |
| VERIBLE_DEFINE_CHECK_OP_IMPL(Check_GE, >=) | |
| VERIBLE_DEFINE_CHECK_OP_IMPL(Check_GT, >) | |
| #undef VERIBLE_DEFINE_CHECK_OP_IMPL | |
| // In optimized mode, use CheckOpString to hint to compiler that | |
| // the while condition is unlikely. | |
| #define CHECK_OP_LOG(name, op, val1, val2) \ | |
| while (::verible::internal::CheckOpString _result = \ | |
| ::verible::internal::name##Impl( \ | |
| ::verible::internal::GetReferenceableValue(val1), \ | |
| ::verible::internal::GetReferenceableValue(val2), \ | |
| #val1 " " #op " " #val2)) \ | |
| ::verible::internal::LogMessageFatal(__FILE__, __LINE__) << *(_result.str_) | |
| #define CHECK_OP(name, op, val1, val2) CHECK_OP_LOG(name, op, val1, val2) | |
| // CHECK_EQ/NE/... | |
| #define CHECK_EQ(val1, val2) CHECK_OP(Check_EQ, ==, val1, val2) | |
| #define CHECK_NE(val1, val2) CHECK_OP(Check_NE, !=, val1, val2) | |
| #define CHECK_LE(val1, val2) CHECK_OP(Check_LE, <=, val1, val2) | |
| #define CHECK_LT(val1, val2) CHECK_OP(Check_LT, <, val1, val2) | |
| #define CHECK_GE(val1, val2) CHECK_OP(Check_GE, >=, val1, val2) | |
| #define CHECK_GT(val1, val2) CHECK_OP(Check_GT, >, val1, val2) | |
| #define CHECK_NOTNULL(val) \ | |
| ::verible::internal::CheckNotNull(__FILE__, __LINE__, \ | |
| "'" #val "' Must be non NULL", (val)) | |
| #ifndef NDEBUG | |
| // DCHECK_EQ/NE/... | |
| #define DCHECK(condition) CHECK(condition) | |
| #define DCHECK_EQ(val1, val2) CHECK_EQ(val1, val2) | |
| #define DCHECK_NE(val1, val2) CHECK_NE(val1, val2) | |
| #define DCHECK_LE(val1, val2) CHECK_LE(val1, val2) | |
| #define DCHECK_LT(val1, val2) CHECK_LT(val1, val2) | |
| #define DCHECK_GE(val1, val2) CHECK_GE(val1, val2) | |
| #define DCHECK_GT(val1, val2) CHECK_GT(val1, val2) | |
| #else | |
| #define DCHECK(condition) \ | |
| while (false && (condition)) LOG(FATAL) | |
| // NDEBUG is defined, so DCHECK_EQ(x, y) and so on do nothing. | |
| // However, we still want the compiler to parse x and y, because | |
| // we don't want to lose potentially useful errors and warnings. | |
| // _DCHECK_NOP is a helper, and should not be used outside of this file. | |
| #define _VERIBLE_DCHECK_NOP(x, y) \ | |
| while (false && ((void)(x), (void)(y), 0)) LOG(FATAL) | |
| #define DCHECK_EQ(x, y) _VERIBLE_DCHECK_NOP(x, y) | |
| #define DCHECK_NE(x, y) _VERIBLE_DCHECK_NOP(x, y) | |
| #define DCHECK_LE(x, y) _VERIBLE_DCHECK_NOP(x, y) | |
| #define DCHECK_LT(x, y) _VERIBLE_DCHECK_NOP(x, y) | |
| #define DCHECK_GE(x, y) _VERIBLE_DCHECK_NOP(x, y) | |
| #define DCHECK_GT(x, y) _VERIBLE_DCHECK_NOP(x, y) | |
| #endif | |
| // These are for when you don't want a CHECK failure to print a verbose | |
| // stack trace. The implementation of CHECK* in this file already doesn't. | |
| #define QCHECK(condition) CHECK(condition) | |
| #define QCHECK_EQ(x, y) CHECK_EQ(x, y) | |
| #define QCHECK_NE(x, y) CHECK_NE(x, y) | |
| #define QCHECK_LE(x, y) CHECK_LE(x, y) | |
| #define QCHECK_LT(x, y) CHECK_LT(x, y) | |
| #define QCHECK_GE(x, y) CHECK_GE(x, y) | |
| #define QCHECK_GT(x, y) CHECK_GT(x, y) | |
| template <typename T> | |
| T&& CheckNotNull(const char* file, int line, const char* exprtext, T&& t) { | |
| if (t == nullptr) { | |
| LogMessageFatal(file, line) << std::string(exprtext); | |
| } | |
| return std::forward<T>(t); | |
| } | |
| int64_t MinLogLevelFromEnv(); | |
| int64_t MinVLogLevelFromEnv(); | |
| } // namespace internal | |
| // LogSink support adapted from //base/logging.h | |
| // | |
| // `LogSink` is an interface which can be extended to intercept and process | |
| // all log messages. LogSink implementations must be thread-safe. A single | |
| // instance will be called from whichever thread is performing a logging | |
| // operation. | |
| class VeribleLogEntry { | |
| static absl::LogSeverity AsAbslLogSeverity(int severity) { | |
| return static_cast<absl::LogSeverity>(severity); | |
| } | |
| public: | |
| explicit VeribleLogEntry(int severity, absl::string_view log_line) | |
| : severity_(AsAbslLogSeverity(severity)), log_line_(log_line) {} | |
| absl::LogSeverity log_severity() const { return severity_; } | |
| std::string ToString() const { return std::string(log_line_); } | |
| private: | |
| const absl::LogSeverity severity_; | |
| const absl::string_view log_line_; | |
| }; | |
| class VeribleLogSink { | |
| public: | |
| virtual ~VeribleLogSink() = default; | |
| // `Send` is called synchronously during the log statement. The logging | |
| // module guarantees not to call `Send` concurrently on the same log sink. | |
| // Implementations should be careful not to call`LOG` or `CHECK` or take | |
| // any locks that might be held by the `LOG` caller, to avoid deadlock. | |
| // | |
| // `e` is guaranteed to remain valid until the subsequent call to | |
| // `WaitTillSent` completes, so implementations may store a pointer to or | |
| // copy of `e` (e.g. in a thread local variable) for use in `WaitTillSent`. | |
| virtual void Send(const VeribleLogEntry& entry) = 0; | |
| // `WaitTillSent` blocks the calling thread (the thread that generated a log | |
| // message) until the sink has finished processing the log message. | |
| // `WaitTillSent` is called once per log message, following the call to | |
| // `Send`. This may be useful when log messages are buffered or processed | |
| // asynchronously by an expensive log sink. | |
| // The default implementation returns immediately. Like `Send`, | |
| // implementations should be careful not to call `LOG` or `CHECK or take any | |
| // locks that might be held by the `LOG` caller, to avoid deadlock. | |
| virtual void WaitTillSent() {} | |
| }; | |
| // Add or remove a `LogSink` as a consumer of logging data. Thread-safe. | |
| void VeribleAddLogSink(VeribleLogSink* sink); | |
| void VeribleRemoveLogSink(VeribleLogSink* sink); | |
| // Helper for `ABSL_DIE_IF_NULL`. | |
| template <typename T> | |
| ABSL_MUST_USE_RESULT T DieIfNull(const char* file, int line, | |
| const char* exprtext, T&& t) { | |
| CHECK(t != nullptr) << exprtext; | |
| return std::forward<T>(t); | |
| } | |
| #ifndef ABSL_DIE_IF_NULL | |
| #define ABSL_DIE_IF_NULL(val) \ | |
| ::verible::DieIfNull(__FILE__, __LINE__, #val, (val)) | |
| #endif | |
| } // namespace verible | |
| #endif // VERIBLE_COMMON_UTIL_LOGGING_H_ |