Make ABSL_ATTRIBUTE_ALWAYS_INLINE and ABSL_ATTRIBUTE_NOINLINE work on MSVC The attribute works unconditionally on _MSC_VER >= 1937, and under /std:c++latest (post-C++17) on _MSC_VER >= 1927. PiperOrigin-RevId: 994626183 Change-Id: Ice38136caf1a4ba8ef98be73c19442a776b3efae
diff --git a/absl/base/attributes.h b/absl/base/attributes.h index d79109d..e432bb7 100644 --- a/absl/base/attributes.h +++ b/absl/base/attributes.h
@@ -99,10 +99,23 @@ // ABSL_ATTRIBUTE_NOINLINE // // Forces functions to either inline or not inline. Introduced in gcc 3.1. +// +// Note that guarantees are ultimately toolchain-dependent. For example, MSVC +// will not inline any function by default, meaning at least /Ob1 or a higher +// levels of optimization is necessary. #if ABSL_HAVE_ATTRIBUTE(always_inline) || \ (defined(__GNUC__) && !defined(__clang__)) #define ABSL_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline)) #define ABSL_HAVE_ATTRIBUTE_ALWAYS_INLINE 1 +#elif defined(_MSC_VER) && \ + (_MSC_VER >= 1937 || \ + (_MSC_VER >= 1927 && ABSL_INTERNAL_CPLUSPLUS_LANG > 201703L)) +#define ABSL_ATTRIBUTE_ALWAYS_INLINE \ + _Pragma("warning(push)") \ + _Pragma("warning(error: 4649)") /* error on misplaced attributes */ \ + [[msvc::forceinline]] /* */ \ + _Pragma("warning(pop)") +#define ABSL_HAVE_ATTRIBUTE_ALWAYS_INLINE 1 #else #define ABSL_ATTRIBUTE_ALWAYS_INLINE #endif @@ -110,6 +123,15 @@ #if ABSL_HAVE_ATTRIBUTE(noinline) || (defined(__GNUC__) && !defined(__clang__)) #define ABSL_ATTRIBUTE_NOINLINE __attribute__((noinline)) #define ABSL_HAVE_ATTRIBUTE_NOINLINE 1 +#elif defined(_MSC_VER) && \ + (_MSC_VER >= 1937 || \ + (_MSC_VER >= 1927 && ABSL_INTERNAL_CPLUSPLUS_LANG > 201703L)) +#define ABSL_ATTRIBUTE_NOINLINE \ + _Pragma("warning(push)") \ + _Pragma("warning(error: 4649)") /* error on misplaced attributes */ \ + [[msvc::noinline]] /* */ \ + _Pragma("warning(pop)") +#define ABSL_HAVE_ATTRIBUTE_NOINLINE 1 #else #define ABSL_ATTRIBUTE_NOINLINE #endif
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 2239854..7c01b9e 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h
@@ -3705,7 +3705,7 @@ // Casting directly from e.g. char* to slot_type* can cause compilation errors // on objective-C. This function converts to void* first, avoiding the issue. - static ABSL_ATTRIBUTE_ALWAYS_INLINE slot_type* to_slot(void* buf) { + ABSL_ATTRIBUTE_ALWAYS_INLINE static slot_type* to_slot(void* buf) { return static_cast<slot_type*>(buf); }
diff --git a/absl/debugging/stacktrace_test.cc b/absl/debugging/stacktrace_test.cc index 02950bc..3cdd999 100644 --- a/absl/debugging/stacktrace_test.cc +++ b/absl/debugging/stacktrace_test.cc
@@ -339,13 +339,13 @@ ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); } -ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS ABSL_ATTRIBUTE_NOINLINE void RaiseSignal() { +ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS void RaiseSignal() { g_return_address = __builtin_return_address(0); raise(SIGUSR1); ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); } -ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS ABSL_ATTRIBUTE_NOINLINE void +ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS void TestNestedSignal() { constexpr size_t kAltstackSize = 1 << 14; // Allocate altstack on regular stack to make sure it'll have a higher
diff --git a/absl/debugging/symbolize_elf.inc b/absl/debugging/symbolize_elf.inc index 3fdf2ff..07b1167 100644 --- a/absl/debugging/symbolize_elf.inc +++ b/absl/debugging/symbolize_elf.inc
@@ -292,8 +292,8 @@ memcpy(dst, s, len + 1); return dst; } - ObjFile *FindObjFile(const void *const start, - size_t size) ABSL_ATTRIBUTE_NOINLINE; + ABSL_ATTRIBUTE_NOINLINE ObjFile* FindObjFile(const void* const start, + size_t size); static bool RegisterObjFile(const char *filename, const void *const start_addr, const void *const end_addr, uint64_t offset, @@ -547,9 +547,9 @@ // and return true. Otherwise, return false. // To keep stack consumption low, we would like this function to not get // inlined. -static ABSL_ATTRIBUTE_NOINLINE bool GetSectionHeaderByType( - CachingFile *file, ElfW(Half) sh_num, const off_t sh_offset, - ElfW(Word) type, ElfW(Shdr) * out, char *tmp_buf, size_t tmp_buf_size) { +ABSL_ATTRIBUTE_NOINLINE static bool GetSectionHeaderByType( + CachingFile* file, ElfW(Half) sh_num, const off_t sh_offset, + ElfW(Word) type, ElfW(Shdr) * out, char* tmp_buf, size_t tmp_buf_size) { ElfW(Shdr) *buf = reinterpret_cast<ElfW(Shdr) *>(tmp_buf); const size_t buf_entries = tmp_buf_size / sizeof(buf[0]); const size_t buf_bytes = buf_entries * sizeof(buf[0]); @@ -758,10 +758,10 @@ // If the symbol is not found, SYMBOL_NOT_FOUND is returned; // To keep stack consumption low, we would like this function to not get // inlined. -static ABSL_ATTRIBUTE_NOINLINE FindSymbolResult FindSymbol( - const void *const pc, CachingFile *file, char *out, size_t out_size, +ABSL_ATTRIBUTE_NOINLINE static FindSymbolResult FindSymbol( + const void* const pc, CachingFile* file, char* out, size_t out_size, ptrdiff_t relocation, const ElfW(Shdr) * strtab, const ElfW(Shdr) * symtab, - const ElfW(Shdr) * opd, char *tmp_buf, size_t tmp_buf_size) { + const ElfW(Shdr) * opd, char* tmp_buf, size_t tmp_buf_size) { if (symtab == nullptr) { return SYMBOL_NOT_FOUND; } @@ -1092,10 +1092,10 @@ // Read /proc/self/maps and run "callback" for each mmapped file found. If // "callback" returns false, stop scanning and return true. Else continue // scanning /proc/self/maps. Return true if no parse error is found. -static ABSL_ATTRIBUTE_NOINLINE bool ReadAddrMap( - bool (*callback)(const char *filename, const void *const start_addr, - const void *const end_addr, uint64_t offset, void *arg), - void *arg, void *tmp_buf, size_t tmp_buf_size) { +ABSL_ATTRIBUTE_NOINLINE static bool ReadAddrMap( + bool (*callback)(const char* filename, const void* const start_addr, + const void* const end_addr, uint64_t offset, void* arg), + void* arg, void* tmp_buf, size_t tmp_buf_size) { // Use /proc/self/task/<pid>/maps instead of /proc/self/maps. The latter // requires kernel to stop all threads, and is significantly slower when there // are 1000s of threads. @@ -1300,8 +1300,8 @@ // where the input symbol is demangled in-place. // To keep stack consumption low, we would like this function to not // get inlined. -static ABSL_ATTRIBUTE_NOINLINE void DemangleInplace(char *out, size_t out_size, - char *tmp_buf, +ABSL_ATTRIBUTE_NOINLINE static void DemangleInplace(char* out, size_t out_size, + char* tmp_buf, size_t tmp_buf_size) { if (Demangle(out, tmp_buf, tmp_buf_size)) { // Demangling succeeded. Copy to out if the space allows.
diff --git a/absl/debugging/symbolize_test.cc b/absl/debugging/symbolize_test.cc index 05de541..8fcdb84 100644 --- a/absl/debugging/symbolize_test.cc +++ b/absl/debugging/symbolize_test.cc
@@ -166,7 +166,7 @@ defined(ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE) // Test with a return address. -void ABSL_ATTRIBUTE_NOINLINE TestWithReturnAddress() { +ABSL_ATTRIBUTE_NOINLINE static void TestWithReturnAddress() { #if defined(ABSL_HAVE_ATTRIBUTE_NOINLINE) void *return_address = __builtin_return_address(0); const char *symbol = TrySymbolize(return_address); @@ -575,7 +575,7 @@ return pc; } -void *ABSL_ATTRIBUTE_NOINLINE non_inline_func() { +ABSL_ATTRIBUTE_NOINLINE void* non_inline_func() { void *pc = nullptr; #if defined(__i386__) __asm__ __volatile__("call 1f;\n 1: pop %[PC]" : [PC] "=r"(pc)); @@ -585,7 +585,7 @@ return pc; } -void ABSL_ATTRIBUTE_NOINLINE TestWithPCInsideNonInlineFunction() { +ABSL_ATTRIBUTE_NOINLINE void TestWithPCInsideNonInlineFunction() { #if defined(ABSL_HAVE_ATTRIBUTE_NOINLINE) && \ (defined(__i386__) || defined(__x86_64__)) void *pc = non_inline_func(); @@ -596,7 +596,7 @@ #endif } -void ABSL_ATTRIBUTE_NOINLINE TestWithPCInsideInlineFunction() { +ABSL_ATTRIBUTE_NOINLINE void TestWithPCInsideInlineFunction() { #if defined(ABSL_HAVE_ATTRIBUTE_ALWAYS_INLINE) && \ (defined(__i386__) || defined(__x86_64__)) void *pc = inline_func(); // Must be inlined. @@ -640,7 +640,7 @@ return x * x * x; } -void ABSL_ATTRIBUTE_NOINLINE TestArmThumbOverlap() { +ABSL_ATTRIBUTE_NOINLINE void TestArmThumbOverlap() { #if defined(ABSL_HAVE_ATTRIBUTE_NOINLINE) const char *symbol = TrySymbolize((void *)&ArmThumbOverlapArm); ASSERT_NE(symbol, nullptr) << "TestArmThumbOverlap failed";
diff --git a/absl/functional/function_type_benchmark.cc b/absl/functional/function_type_benchmark.cc index e4ba3a5..cc8b817 100644 --- a/absl/functional/function_type_benchmark.cc +++ b/absl/functional/function_type_benchmark.cc
@@ -40,7 +40,7 @@ }; template <typename Function, typename... Args> -void ABSL_ATTRIBUTE_NOINLINE CallFunction(Function f, Args&&... args) { +ABSL_ATTRIBUTE_NOINLINE void CallFunction(Function f, Args&&... args) { f(std::forward<Args>(args)...); }
diff --git a/absl/hash/internal/hash.cc b/absl/hash/internal/hash.cc index 43cb561..df75c25 100644 --- a/absl/hash/internal/hash.cc +++ b/absl/hash/internal/hash.cc
@@ -235,21 +235,28 @@ // We combine state and data with _mm_add_epi64/_mm_sub_epi64 before applying // AES encryption to make hash function dependent on the order of the blocks. // See comments in LowLevelHash33To64 for more considerations. - auto mix_ab = [&state0, - &state1](const uint8_t* p) ABSL_ATTRIBUTE_ALWAYS_INLINE { - Vector128 a = Load128(p); - Vector128 b = Load128(p + 16); - state0 = MixA(a, state0); - state1 = MixB(b, state1); + struct MixerAB { + Vector128& state0; + Vector128& state1; + ABSL_ATTRIBUTE_ALWAYS_INLINE auto operator()(const uint8_t* p) const { + Vector128 a = Load128(p); + Vector128 b = Load128(p + 16); + state0 = MixA(a, state0); + state1 = MixB(b, state1); + } }; - auto mix_cd = [&state2, - &state3](const uint8_t* p) ABSL_ATTRIBUTE_ALWAYS_INLINE { - Vector128 c = Load128(p); - Vector128 d = Load128(p + 16); - state2 = MixC(c, state2); - state3 = MixD(d, state3); + MixerAB mix_ab = {state0, state1}; + struct MixerCD { + Vector128& state2; + Vector128& state3; + ABSL_ATTRIBUTE_ALWAYS_INLINE auto operator()(const uint8_t* p) const { + Vector128 c = Load128(p); + Vector128 d = Load128(p + 16); + state2 = MixC(c, state2); + state3 = MixD(d, state3); + } }; - + MixerCD mix_cd = {state2, state3}; do { PrefetchFutureDataToLocalCache(ptr); mix_ab(ptr);
diff --git a/absl/log/internal/check_op.h b/absl/log/internal/check_op.h index ce2c76f..69f0c3b 100644 --- a/absl/log/internal/check_op.h +++ b/absl/log/internal/check_op.h
@@ -425,8 +425,8 @@ // Build the error message string. Specify no inlining for code size. template <typename T1, typename T2> -ABSL_ATTRIBUTE_RETURNS_NONNULL const char* absl_nonnull MakeCheckOpString( - T1 v1, T2 v2, const char* absl_nonnull exprtext) ABSL_ATTRIBUTE_NOINLINE; +ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_RETURNS_NONNULL const char* absl_nonnull +MakeCheckOpString(T1 v1, T2 v2, const char* absl_nonnull exprtext); template <typename T1, typename T2> const char* absl_nonnull MakeCheckOpString(T1 v1, T2 v2,
diff --git a/absl/log/internal/log_message.cc b/absl/log/internal/log_message.cc index 4e5da95..e56ef25 100644 --- a/absl/log/internal/log_message.cc +++ b/absl/log/internal/log_message.cc
@@ -605,7 +605,8 @@ // `str_type`. Truncates `str` if necessary, but emits nothing and marks the // buffer full if even the field headers do not fit. template <LogMessage::StringType str_type> -void LogMessage::CopyToEncodedBuffer(absl::string_view str) { +ABSL_ATTRIBUTE_NOINLINE void LogMessage::CopyToEncodedBuffer( + absl::string_view str) { auto encoded_remaining_copy = data_->encoded_remaining(); constexpr uint8_t tag_value = str_type == StringType::kLiteral ? ValueTag::kStringLiteral @@ -632,7 +633,8 @@ template void LogMessage::CopyToEncodedBuffer< LogMessage::StringType::kNotLiteral>(absl::string_view str); template <LogMessage::StringType str_type> -void LogMessage::CopyToEncodedBuffer(char ch, size_t num) { +ABSL_ATTRIBUTE_NOINLINE void LogMessage::CopyToEncodedBuffer(char ch, + size_t num) { auto encoded_remaining_copy = data_->encoded_remaining(); constexpr uint8_t tag_value = str_type == StringType::kLiteral ? ValueTag::kStringLiteral @@ -660,7 +662,8 @@ LogMessage::StringType::kNotLiteral>(char ch, size_t num); template <LogMessage::StringType str_type> -void LogMessage::CopyToEncodedBuffer(std::wstring_view str) { +ABSL_ATTRIBUTE_NOINLINE void LogMessage::CopyToEncodedBuffer( + std::wstring_view str) { auto encoded_remaining_copy = data_->encoded_remaining(); constexpr uint8_t tag_value = str_type == StringType::kLiteral ? ValueTag::kStringLiteral @@ -698,7 +701,8 @@ absl::string_view str); template <LogMessage::StringType str_type> -void LogMessage::CopyToEncodedBufferWithStructuredProtoField( +ABSL_ATTRIBUTE_NOINLINE void +LogMessage::CopyToEncodedBufferWithStructuredProtoField( StructuredProtoField field, absl::string_view str) { auto encoded_remaining_copy = data_->encoded_remaining(); size_t encoded_field_size = BufferSizeForStructuredProtoField(field);
diff --git a/absl/log/internal/log_message.h b/absl/log/internal/log_message.h index 50a728a..cd12833 100644 --- a/absl/log/internal/log_message.h +++ b/absl/log/internal/log_message.h
@@ -209,14 +209,14 @@ // This prevents non-const `char[]` arrays from looking like literals. template <int SIZE> - LogMessage& operator<<(char (&buf)[SIZE]) ABSL_ATTRIBUTE_NOINLINE; + ABSL_ATTRIBUTE_NOINLINE LogMessage& operator<<(char (&buf)[SIZE]); // `wchar_t[SIZE]` is handled by `operator<< <const wchar_t*>`. // Types that support `AbslStringify()` are serialized that way. // Types that don't support `AbslStringify()` but do support streaming into a // `std::ostream&` are serialized that way. template <typename T> - LogMessage& operator<<(const T& v) ABSL_ATTRIBUTE_NOINLINE; + ABSL_ATTRIBUTE_NOINLINE LogMessage& operator<<(const T& v); // Dispatches the completed `absl::LogEntry` to applicable `absl::LogSink`s. void Flush(); @@ -271,18 +271,17 @@ kNotLiteral, }; template <StringType str_type> - void CopyToEncodedBuffer(absl::string_view str) ABSL_ATTRIBUTE_NOINLINE; + void CopyToEncodedBuffer(absl::string_view str); template <StringType str_type> - void CopyToEncodedBuffer(char ch, size_t num) ABSL_ATTRIBUTE_NOINLINE; + void CopyToEncodedBuffer(char ch, size_t num); template <StringType str_type> - void CopyToEncodedBuffer(std::wstring_view str) ABSL_ATTRIBUTE_NOINLINE; + void CopyToEncodedBuffer(std::wstring_view str); // Copies `field` to the encoded buffer, then appends `str` after it // (truncating `str` if necessary to fit). template <StringType str_type> void CopyToEncodedBufferWithStructuredProtoField(StructuredProtoField field, - absl::string_view str) - ABSL_ATTRIBUTE_NOINLINE; + absl::string_view str); // Returns `true` if the message is fatal or enabled debug-fatal. bool IsFatal() const;
diff --git a/absl/numeric/int128.cc b/absl/numeric/int128.cc index a58b772..54e2a8c 100644 --- a/absl/numeric/int128.cc +++ b/absl/numeric/int128.cc
@@ -42,7 +42,7 @@ // For example: // Given: 5 (decimal) == 101 (binary) // Returns: 2 -inline ABSL_ATTRIBUTE_ALWAYS_INLINE int Fls128(uint128 n) { +ABSL_ATTRIBUTE_ALWAYS_INLINE inline int Fls128(uint128 n) { if (uint64_t hi = Uint128High64(n)) { ABSL_ASSUME(hi != 0); return 127 - countl_zero(hi);
diff --git a/absl/status/statusor_benchmark.cc b/absl/status/statusor_benchmark.cc index ac353bb..0a9d29d 100644 --- a/absl/status/statusor_benchmark.cc +++ b/absl/status/statusor_benchmark.cc
@@ -360,12 +360,12 @@ // below for the variants. bool bm_cond = true; -bool SimpleIntInterface(int64_t* v) ABSL_ATTRIBUTE_NOINLINE; -bool SimpleIntInterfaceWithErrorMessage(int64_t* v, std::string* msg) - ABSL_ATTRIBUTE_NOINLINE; -absl::Status SimpleIntInterfaceWithErrorStatus(int64_t* v) - ABSL_ATTRIBUTE_NOINLINE; -absl::StatusOr<int64_t> SimpleIntStatusOrInterface() ABSL_ATTRIBUTE_NOINLINE; +ABSL_ATTRIBUTE_NOINLINE bool SimpleIntInterface(int64_t* v); +ABSL_ATTRIBUTE_NOINLINE bool SimpleIntInterfaceWithErrorMessage( + int64_t* v, std::string* msg); +ABSL_ATTRIBUTE_NOINLINE absl::Status SimpleIntInterfaceWithErrorStatus( + int64_t* v); +ABSL_ATTRIBUTE_NOINLINE absl::StatusOr<int64_t> SimpleIntStatusOrInterface(); // (a): Just a boolean return value with an out int64* parameter bool SimpleIntInterface(int64_t* v) {
diff --git a/absl/strings/internal/cordz_info.h b/absl/strings/internal/cordz_info.h index 04609cd..b3d88a8 100644 --- a/absl/strings/internal/cordz_info.h +++ b/absl/strings/internal/cordz_info.h
@@ -252,7 +252,7 @@ const int64_t sampling_stride_; }; -inline ABSL_ATTRIBUTE_ALWAYS_INLINE void CordzInfo::MaybeTrackCord( +ABSL_ATTRIBUTE_ALWAYS_INLINE inline void CordzInfo::MaybeTrackCord( InlineData& cord, MethodIdentifier method) { auto stride = cordz_should_profile(); if (ABSL_PREDICT_FALSE(stride > 0)) { @@ -260,14 +260,14 @@ } } -inline ABSL_ATTRIBUTE_ALWAYS_INLINE void CordzInfo::MaybeTrackCord( +ABSL_ATTRIBUTE_ALWAYS_INLINE inline void CordzInfo::MaybeTrackCord( InlineData& cord, const InlineData& src, MethodIdentifier method) { if (ABSL_PREDICT_FALSE(InlineData::is_either_profiled(cord, src))) { MaybeTrackCordImpl(cord, src, method); } } -inline ABSL_ATTRIBUTE_ALWAYS_INLINE void CordzInfo::MaybeUntrackCord( +ABSL_ATTRIBUTE_ALWAYS_INLINE inline void CordzInfo::MaybeUntrackCord( CordzInfo* info) { if (ABSL_PREDICT_FALSE(info)) { info->Untrack();
diff --git a/absl/strings/numbers.cc b/absl/strings/numbers.cc index 924c912..c574dee 100644 --- a/absl/strings/numbers.cc +++ b/absl/strings/numbers.cc
@@ -256,7 +256,7 @@ return buffer + 16; } -inline ABSL_ATTRIBUTE_ALWAYS_INLINE char* absl_nonnull EncodeFullU32( +ABSL_ATTRIBUTE_ALWAYS_INLINE inline char* absl_nonnull EncodeFullU32( uint32_t n, char* absl_nonnull out_str) { if (n < 10) { *out_str = static_cast<char>('0' + n); @@ -279,7 +279,7 @@ return out_str + sizeof(bottom); } -inline ABSL_ATTRIBUTE_ALWAYS_INLINE char* absl_nonnull EncodeFullU64( +ABSL_ATTRIBUTE_ALWAYS_INLINE inline char* absl_nonnull EncodeFullU64( uint64_t i, char* absl_nonnull buffer) { if (i <= std::numeric_limits<uint32_t>::max()) { return EncodeFullU32(static_cast<uint32_t>(i), buffer); @@ -304,7 +304,7 @@ return buffer + sizeof(mod_result); } -inline ABSL_ATTRIBUTE_ALWAYS_INLINE char* absl_nonnull EncodeFullU128( +ABSL_ATTRIBUTE_ALWAYS_INLINE inline char* absl_nonnull EncodeFullU128( uint128 i, char* absl_nonnull buffer) { if (absl::Uint128High64(i) == 0) { return EncodeFullU64(absl::Uint128Low64(i), buffer);