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);