[libcxx-commits] [libcxx] [libcxxabi] [libc++] Introduce the notion of a minimum header version (PR #166074)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Tue Nov 18 06:28:20 PST 2025


https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/166074

>From b7433a55b4bae0d72c8f022ae700395a85951af9 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Sun, 2 Nov 2025 16:34:51 +0100
Subject: [PATCH] [libc++] Introduce the notion of a minimum header version

---
 libcxx/CMakeLists.txt                         |  4 ++
 libcxx/docs/ABIGuarantees.rst                 | 17 ---------
 libcxx/include/__config                       | 10 -----
 libcxx/include/__configuration/abi.h          | 14 -------
 libcxx/include/__configuration/availability.h |  7 ++++
 libcxx/include/__ostream/basic_ostream.h      | 16 ++++----
 libcxx/include/istream                        | 22 +++++------
 libcxx/include/streambuf                      | 38 +++++++++----------
 libcxx/include/valarray                       |  4 +-
 libcxx/src/any.cpp                            |  4 ++
 libcxx/src/charconv.cpp                       |  4 +-
 libcxx/src/condition_variable_destructor.cpp  |  2 +-
 libcxx/src/error_category.cpp                 |  4 +-
 libcxx/src/memory.cpp                         |  3 +-
 libcxx/src/mutex_destructor.cpp               |  2 +-
 libcxx/src/optional.cpp                       |  4 ++
 libcxx/src/string.cpp                         | 15 +++-----
 libcxx/src/valarray.cpp                       |  3 +-
 libcxx/src/vector.cpp                         |  4 +-
 libcxxabi/CMakeLists.txt                      |  4 ++
 20 files changed, 81 insertions(+), 100 deletions(-)

diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt
index a119850cd808e..070e55e85d3f9 100644
--- a/libcxx/CMakeLists.txt
+++ b/libcxx/CMakeLists.txt
@@ -205,6 +205,9 @@ set(LIBCXX_ABI_NAMESPACE "__${LIBCXX_ABI_VERSION}" CACHE STRING "The inline ABI
 if (NOT LIBCXX_ABI_NAMESPACE MATCHES "__.*")
   message(FATAL_ERROR "LIBCXX_ABI_NAMESPACE must be a reserved identifier, got '${LIBCXX_ABI_NAMESPACE}'.")
 endif()
+set(LIBCXX_AVAILABILITY_MINIMUM_HEADER_VERSION "1" CACHE STRING
+  "Minimum version of the libc++ headers that are allowed to be used by binaries linked against the libc++ library. This
+   version must correspond to the major version of an LLVM release.")
 option(LIBCXX_ABI_FORCE_ITANIUM "Ignore auto-detection and force use of the Itanium ABI.")
 option(LIBCXX_ABI_FORCE_MICROSOFT "Ignore auto-detection and force use of the Microsoft ABI.")
 
@@ -523,6 +526,7 @@ function(cxx_add_basic_build_flags target)
   # Let the library headers know they are currently being used to build the
   # library.
   target_compile_definitions(${target} PRIVATE -D_LIBCPP_BUILDING_LIBRARY)
+  target_compile_definitions(${target} PRIVATE -D_LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION=${LIBCXX_AVAILABILITY_MINIMUM_HEADER_VERSION})
 
   # Make sure the library can be build without transitive includes. This makes
   # it easier to upgrade the library to a newer language standard without build
diff --git a/libcxx/docs/ABIGuarantees.rst b/libcxx/docs/ABIGuarantees.rst
index 4d4674c7756a4..fc3cf8b7dd0a3 100644
--- a/libcxx/docs/ABIGuarantees.rst
+++ b/libcxx/docs/ABIGuarantees.rst
@@ -114,23 +114,6 @@ hand, backwards compatibility is generally guaranteed.
 
 There are multiple ABI flags that change the symbols exported from the built library:
 
-``_LIBCPP_ABI_DO_NOT_EXPORT_BASIC_STRING_COMMON``
--------------------------------------------------
-This removes ``__basic_string_common<true>::__throw_length_error()`` and
-``__basic_string_common<true>::__throw_out_of_range()``. These symbols have been used by ``basic_string`` in the past,
-but are not referenced from the headers anymore.
-
-``_LIBCPP_ABI_DO_NOT_EXPORT_VECTOR_BASE_COMMON``
-------------------------------------------------
-This removes ``__vector_base_common<true>::__throw_length_error()`` and
-``__vector_base_common<true>::__throw_out_of_range()``. These symbols have been used by ``vector`` in the past, but are
-not referenced from the headers anymore.
-
-``_LIBCPP_ABI_DO_NOT_EXPORT_TO_CHARS_BASE_10``
-----------------------------------------------
-This removes ``__itoa::__u32toa()`` and ``__iota::__u64toa``. These symbols have been used by ``to_chars`` in the past,
-but are not referenced from the headers anymore.
-
 ``_LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION``
 -------------------------------------------------------
 This replaces the symbols that are exported for ``basic_string`` to avoid exporting functions which are likely to be
diff --git a/libcxx/include/__config b/libcxx/include/__config
index d079bf8b500b6..48917aae8726c 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -360,16 +360,6 @@ typedef __char32_t char32_t;
 #  endif
 #  define _LIBCPP_HIDE_FROM_ABI_VIRTUAL _LIBCPP_HIDDEN _LIBCPP_EXCLUDE_FROM_EXPLICIT_INSTANTIATION
 
-#  ifdef _LIBCPP_BUILDING_LIBRARY
-#    if _LIBCPP_ABI_VERSION > 1
-#      define _LIBCPP_HIDE_FROM_ABI_AFTER_V1 _LIBCPP_HIDE_FROM_ABI
-#    else
-#      define _LIBCPP_HIDE_FROM_ABI_AFTER_V1
-#    endif
-#  else
-#    define _LIBCPP_HIDE_FROM_ABI_AFTER_V1 _LIBCPP_HIDE_FROM_ABI
-#  endif
-
 // Clang modules take a significant compile time hit when pushing and popping diagnostics.
 // Since all the headers are marked as system headers unless _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER is defined, we can
 // simply disable this pushing and popping when _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER isn't defined.
diff --git a/libcxx/include/__configuration/abi.h b/libcxx/include/__configuration/abi.h
index 38b85c6ac70de..f088fd92f29c0 100644
--- a/libcxx/include/__configuration/abi.h
+++ b/libcxx/include/__configuration/abi.h
@@ -63,9 +63,6 @@
 
 // These flags are documented in ABIGuarantees.rst
 #  define _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT
-#  define _LIBCPP_ABI_DO_NOT_EXPORT_BASIC_STRING_COMMON
-#  define _LIBCPP_ABI_DO_NOT_EXPORT_VECTOR_BASE_COMMON
-#  define _LIBCPP_ABI_DO_NOT_EXPORT_TO_CHARS_BASE_10
 #  define _LIBCPP_ABI_ENABLE_SHARED_PTR_TRIVIAL_ABI
 #  define _LIBCPP_ABI_ENABLE_UNIQUE_PTR_TRIVIAL_ABI
 #  define _LIBCPP_ABI_FIX_CITYHASH_IMPLEMENTATION
@@ -85,17 +82,6 @@
 #  define _LIBCPP_ABI_VARIANT_INDEX_TYPE_OPTIMIZATION
 
 #elif _LIBCPP_ABI_VERSION == 1
-#  if !(defined(_LIBCPP_OBJECT_FORMAT_COFF) || defined(_LIBCPP_OBJECT_FORMAT_XCOFF))
-// Enable compiling copies of now inline methods into the dylib to support
-// applications compiled against older libraries. This is unnecessary with
-// COFF dllexport semantics, since dllexport forces a non-inline definition
-// of inline functions to be emitted anyway. Our own non-inline copy would
-// conflict with the dllexport-emitted copy, so we disable it. For XCOFF,
-// the linker will take issue with the symbols in the shared object if the
-// weak inline methods get visibility (such as from -fvisibility-inlines-hidden),
-// so disable it.
-#    define _LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS
-#  endif
 // Feature macros for disabling pre ABI v1 features. All of these options
 // are deprecated.
 #  if defined(__FreeBSD__)
diff --git a/libcxx/include/__configuration/availability.h b/libcxx/include/__configuration/availability.h
index 5433df872fa39..d0e42a897122f 100644
--- a/libcxx/include/__configuration/availability.h
+++ b/libcxx/include/__configuration/availability.h
@@ -326,4 +326,11 @@
 #  define _LIBCPP_AVAILABILITY_INIT_PRIMARY_EXCEPTION
 #endif
 
+// Only define a bunch of symbols in the dylib if we target LLVM 7 headers or older
+#  if defined(_LIBCPP_BUILDING_LIBRARY) && _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 8
+#    define _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8
+#  else
+#    define _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 _LIBCPP_HIDE_FROM_ABI
+#  endif
+
 #endif // _LIBCPP___CONFIGURATION_AVAILABILITY_H
diff --git a/libcxx/include/__ostream/basic_ostream.h b/libcxx/include/__ostream/basic_ostream.h
index effeef491f341..ac8bb1a3159f9 100644
--- a/libcxx/include/__ostream/basic_ostream.h
+++ b/libcxx/include/__ostream/basic_ostream.h
@@ -53,7 +53,7 @@ class basic_ostream : virtual public basic_ios<_CharT, _Traits> {
   typedef typename traits_type::off_type off_type;
 
   // 27.7.2.2 Constructor/destructor:
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 explicit basic_ostream(basic_streambuf<char_type, traits_type>* __sb) {
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 explicit basic_ostream(basic_streambuf<char_type, traits_type>* __sb) {
     this->init(__sb);
   }
   ~basic_ostream() override;
@@ -67,7 +67,7 @@ class basic_ostream : virtual public basic_ios<_CharT, _Traits> {
   // 27.7.2.3 Assign/swap
   inline _LIBCPP_HIDE_FROM_ABI basic_ostream& operator=(basic_ostream&& __rhs);
 
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void swap(basic_ostream& __rhs) {
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 void swap(basic_ostream& __rhs) {
     basic_ios<char_type, traits_type>::swap(__rhs);
   }
 
@@ -76,17 +76,17 @@ class basic_ostream : virtual public basic_ios<_CharT, _Traits> {
   class sentry;
 
   // 27.7.2.6 Formatted output:
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_ostream& operator<<(basic_ostream& (*__pf)(basic_ostream&)) {
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_ostream& operator<<(basic_ostream& (*__pf)(basic_ostream&)) {
     return __pf(*this);
   }
 
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_ostream&
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_ostream&
   operator<<(basic_ios<char_type, traits_type>& (*__pf)(basic_ios<char_type, traits_type>&)) {
     __pf(*this);
     return *this;
   }
 
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_ostream& operator<<(ios_base& (*__pf)(ios_base&)) {
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_ostream& operator<<(ios_base& (*__pf)(ios_base&)) {
     __pf(*this);
     return *this;
   }
@@ -174,9 +174,9 @@ class basic_ostream : virtual public basic_ios<_CharT, _Traits> {
   basic_ostream& flush();
 
   // 27.7.2.5 seeks:
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 pos_type tellp();
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_ostream& seekp(pos_type __pos);
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_ostream& seekp(off_type __off, ios_base::seekdir __dir);
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 pos_type tellp();
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_ostream& seekp(pos_type __pos);
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_ostream& seekp(off_type __off, ios_base::seekdir __dir);
 
 protected:
   _LIBCPP_HIDE_FROM_ABI basic_ostream() {} // extension, intentially does not initialize
diff --git a/libcxx/include/istream b/libcxx/include/istream
index 7f15521f91a8a..4fc4c6b133552 100644
--- a/libcxx/include/istream
+++ b/libcxx/include/istream
@@ -209,7 +209,7 @@ public:
   typedef typename traits_type::off_type off_type;
 
   // 27.7.1.1.1 Constructor/destructor:
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 explicit basic_istream(basic_streambuf<char_type, traits_type>* __sb)
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 explicit basic_istream(basic_streambuf<char_type, traits_type>* __sb)
       : __gc_(0) {
     this->init(__sb);
   }
@@ -221,7 +221,7 @@ protected:
   // 27.7.1.1.2 Assign/swap:
   inline _LIBCPP_HIDE_FROM_ABI basic_istream& operator=(basic_istream&& __rhs);
 
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void swap(basic_istream& __rhs) {
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 void swap(basic_istream& __rhs) {
     std::swap(__gc_, __rhs.__gc_);
     basic_ios<char_type, traits_type>::swap(__rhs);
   }
@@ -234,17 +234,17 @@ public:
   class sentry;
 
   // 27.7.1.2 Formatted input:
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_istream& operator>>(basic_istream& (*__pf)(basic_istream&)) {
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_istream& operator>>(basic_istream& (*__pf)(basic_istream&)) {
     return __pf(*this);
   }
 
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_istream&
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_istream&
   operator>>(basic_ios<char_type, traits_type>& (*__pf)(basic_ios<char_type, traits_type>&)) {
     __pf(*this);
     return *this;
   }
 
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_istream& operator>>(ios_base& (*__pf)(ios_base&)) {
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_istream& operator>>(ios_base& (*__pf)(ios_base&)) {
     __pf(*this);
     return *this;
   }
@@ -268,26 +268,26 @@ public:
   _LIBCPP_HIDE_FROM_ABI streamsize gcount() const { return __gc_; }
   int_type get();
 
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_istream& get(char_type& __c) {
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_istream& get(char_type& __c) {
     int_type __ch = get();
     if (__ch != traits_type::eof())
       __c = traits_type::to_char_type(__ch);
     return *this;
   }
 
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_istream& get(char_type* __s, streamsize __n) {
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_istream& get(char_type* __s, streamsize __n) {
     return get(__s, __n, this->widen('\n'));
   }
 
   basic_istream& get(char_type* __s, streamsize __n, char_type __dlm);
 
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_istream& get(basic_streambuf<char_type, traits_type>& __sb) {
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_istream& get(basic_streambuf<char_type, traits_type>& __sb) {
     return get(__sb, this->widen('\n'));
   }
 
   basic_istream& get(basic_streambuf<char_type, traits_type>& __sb, char_type __dlm);
 
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_istream& getline(char_type* __s, streamsize __n) {
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_istream& getline(char_type* __s, streamsize __n) {
     return getline(__s, __n, this->widen('\n'));
   }
 
@@ -1184,7 +1184,7 @@ public:
   typedef typename traits_type::off_type off_type;
 
   // constructor/destructor
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 explicit basic_iostream(basic_streambuf<char_type, traits_type>* __sb)
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 explicit basic_iostream(basic_streambuf<char_type, traits_type>* __sb)
       : basic_istream<_CharT, _Traits>(__sb) {}
 
   ~basic_iostream() override;
@@ -1195,7 +1195,7 @@ protected:
   // assign/swap
   inline _LIBCPP_HIDE_FROM_ABI basic_iostream& operator=(basic_iostream&& __rhs);
 
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void swap(basic_iostream& __rhs) {
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 void swap(basic_iostream& __rhs) {
     basic_istream<char_type, traits_type>::swap(__rhs);
   }
 };
diff --git a/libcxx/include/streambuf b/libcxx/include/streambuf
index 7dc4e31cc2324..964dab2b8959d 100644
--- a/libcxx/include/streambuf
+++ b/libcxx/include/streambuf
@@ -150,35 +150,35 @@ public:
   virtual ~basic_streambuf() {}
 
   // 27.6.2.2.1 locales:
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 locale pubimbue(const locale& __loc) {
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 locale pubimbue(const locale& __loc) {
     imbue(__loc);
     locale __r = __loc_;
     __loc_     = __loc;
     return __r;
   }
 
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 locale getloc() const { return __loc_; }
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 locale getloc() const { return __loc_; }
 
   // 27.6.2.2.2 buffer and positioning:
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_streambuf* pubsetbuf(char_type* __s, streamsize __n) {
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_streambuf* pubsetbuf(char_type* __s, streamsize __n) {
     return setbuf(__s, __n);
   }
 
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 pos_type
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 pos_type
   pubseekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __which = ios_base::in | ios_base::out) {
     return seekoff(__off, __way, __which);
   }
 
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 pos_type
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 pos_type
   pubseekpos(pos_type __sp, ios_base::openmode __which = ios_base::in | ios_base::out) {
     return seekpos(__sp, __which);
   }
 
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int pubsync() { return sync(); }
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 int pubsync() { return sync(); }
 
   // Get and put areas:
   // 27.6.2.2.3 Get area:
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 streamsize in_avail() {
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 streamsize in_avail() {
     __check_invariants();
     auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); });
 
@@ -187,7 +187,7 @@ public:
     return showmanyc();
   }
 
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type snextc() {
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 int_type snextc() {
     __check_invariants();
     auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); });
 
@@ -196,7 +196,7 @@ public:
     return sgetc();
   }
 
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sbumpc() {
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 int_type sbumpc() {
     __check_invariants();
     auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); });
 
@@ -207,7 +207,7 @@ public:
     return __c;
   }
 
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sgetc() {
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 int_type sgetc() {
     __check_invariants();
     auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); });
 
@@ -216,10 +216,10 @@ public:
     return traits_type::to_int_type(*gptr());
   }
 
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 streamsize sgetn(char_type* __s, streamsize __n) { return xsgetn(__s, __n); }
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 streamsize sgetn(char_type* __s, streamsize __n) { return xsgetn(__s, __n); }
 
   // 27.6.2.2.4 Putback:
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sputbackc(char_type __c) {
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 int_type sputbackc(char_type __c) {
     __check_invariants();
     auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); });
 
@@ -229,7 +229,7 @@ public:
     return traits_type::to_int_type(*gptr());
   }
 
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sungetc() {
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 int_type sungetc() {
     __check_invariants();
     auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); });
 
@@ -240,7 +240,7 @@ public:
   }
 
   // 27.6.2.2.5 Put area:
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sputc(char_type __c) {
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 int_type sputc(char_type __c) {
     __check_invariants();
     auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); });
 
@@ -251,7 +251,7 @@ public:
     return traits_type::to_int_type(__c);
   }
 
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 streamsize sputn(const char_type* __s, streamsize __n) {
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 streamsize sputn(const char_type* __s, streamsize __n) {
     return xsputn(__s, __n);
   }
 
@@ -292,12 +292,12 @@ protected:
   _LIBCPP_HIDE_FROM_ABI char_type* gptr() const { return __ninp_; }
   _LIBCPP_HIDE_FROM_ABI char_type* egptr() const { return __einp_; }
 
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void gbump(int __n) { __ninp_ += __n; }
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 void gbump(int __n) { __ninp_ += __n; }
 
   // gbump takes an int, so it might not be able to represent the offset we want to add.
   _LIBCPP_HIDE_FROM_ABI void __gbump_ptrdiff(ptrdiff_t __n) { __ninp_ += __n; }
 
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void setg(char_type* __gbeg, char_type* __gnext, char_type* __gend) {
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 void setg(char_type* __gbeg, char_type* __gnext, char_type* __gend) {
     _LIBCPP_ASSERT_VALID_INPUT_RANGE(std::__is_valid_range(__gbeg, __gnext), "[gbeg, gnext) must be a valid range");
     _LIBCPP_ASSERT_VALID_INPUT_RANGE(std::__is_valid_range(__gbeg, __gend), "[gbeg, gend) must be a valid range");
     _LIBCPP_ASSERT_VALID_INPUT_RANGE(std::__is_valid_range(__gnext, __gend), "[gnext, gend) must be a valid range");
@@ -311,11 +311,11 @@ protected:
   _LIBCPP_HIDE_FROM_ABI char_type* pptr() const { return __nout_; }
   _LIBCPP_HIDE_FROM_ABI char_type* epptr() const { return __eout_; }
 
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void pbump(int __n) { __nout_ += __n; }
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 void pbump(int __n) { __nout_ += __n; }
 
   _LIBCPP_HIDE_FROM_ABI void __pbump(streamsize __n) { __nout_ += __n; }
 
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void setp(char_type* __pbeg, char_type* __pend) {
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 void setp(char_type* __pbeg, char_type* __pend) {
     _LIBCPP_ASSERT_VALID_INPUT_RANGE(std::__is_valid_range(__pbeg, __pend), "[pbeg, pend) must be a valid range");
     __bout_ = __nout_ = __pbeg;
     __eout_           = __pend;
diff --git a/libcxx/include/valarray b/libcxx/include/valarray
index 215811d5ba475..a97b930eac4a7 100644
--- a/libcxx/include/valarray
+++ b/libcxx/include/valarray
@@ -793,7 +793,7 @@ private:
 public:
   // construct/destroy:
   _LIBCPP_HIDE_FROM_ABI valarray() : __begin_(nullptr), __end_(nullptr) {}
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 explicit valarray(size_t __n);
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 explicit valarray(size_t __n);
   _LIBCPP_HIDE_FROM_ABI valarray(const value_type& __x, size_t __n);
   valarray(const value_type* __p, size_t __n);
   valarray(const valarray& __v);
@@ -805,7 +805,7 @@ public:
   valarray(const gslice_array<value_type>& __ga);
   valarray(const mask_array<value_type>& __ma);
   valarray(const indirect_array<value_type>& __ia);
-  inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 ~valarray();
+  inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 ~valarray();
 
   // assignment:
   valarray& operator=(const valarray& __v);
diff --git a/libcxx/src/any.cpp b/libcxx/src/any.cpp
index f3fc715d517f2..47058f55d8248 100644
--- a/libcxx/src/any.cpp
+++ b/libcxx/src/any.cpp
@@ -14,6 +14,8 @@ const char* bad_any_cast::what() const noexcept { return "bad any cast"; }
 
 #include <__config>
 
+#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 7
+
 //  Preserve std::experimental::any_bad_cast for ABI compatibility
 //  Even though it no longer exists in a header file
 _LIBCPP_BEGIN_NAMESPACE_LFTS
@@ -25,4 +27,6 @@ class _LIBCPP_EXPORTED_FROM_ABI bad_any_cast : public bad_cast {
 
 const char* bad_any_cast::what() const noexcept { return "bad any cast"; }
 
+#endif
+
 _LIBCPP_END_NAMESPACE_LFTS
diff --git a/libcxx/src/charconv.cpp b/libcxx/src/charconv.cpp
index 5e8cb7d97703b..5438910a7e751 100644
--- a/libcxx/src/charconv.cpp
+++ b/libcxx/src/charconv.cpp
@@ -14,7 +14,7 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-#ifndef _LIBCPP_ABI_DO_NOT_EXPORT_TO_CHARS_BASE_10
+#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 15
 
 namespace __itoa {
 
@@ -24,7 +24,7 @@ _LIBCPP_EXPORTED_FROM_ABI char* __u64toa(uint64_t value, char* buffer) noexcept
 
 } // namespace __itoa
 
-#endif // _LIBCPP_ABI_DO_NOT_EXPORT_TO_CHARS_BASE_10
+#endif // _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 15
 
 // The original version of floating-point to_chars was written by Microsoft and
 // contributed with the following license.
diff --git a/libcxx/src/condition_variable_destructor.cpp b/libcxx/src/condition_variable_destructor.cpp
index f6ffe33685990..fc4b4a601d964 100644
--- a/libcxx/src/condition_variable_destructor.cpp
+++ b/libcxx/src/condition_variable_destructor.cpp
@@ -14,7 +14,7 @@
 #include <__config>
 #include <__thread/support.h>
 
-#if _LIBCPP_ABI_VERSION == 1 || !_LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION
+#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 9 || !_LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION
 #  define NEEDS_CONDVAR_DESTRUCTOR
 #endif
 
diff --git a/libcxx/src/error_category.cpp b/libcxx/src/error_category.cpp
index 8ae460fb5f1f4..9c0ca6a04a523 100644
--- a/libcxx/src/error_category.cpp
+++ b/libcxx/src/error_category.cpp
@@ -8,7 +8,9 @@
 
 #include <__config>
 
-#ifdef _LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS
+// This has technically been removed in LLVM 3.4
+#if !defined(_LIBCPP_OBJECT_FORMAT_COFF) && !defined(_LIBCPP_OBJECT_FORMAT_XCOFF) &&                                   \
+    _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 4
 #  define _LIBCPP_ERROR_CATEGORY_DEFINE_LEGACY_INLINE_FUNCTIONS
 #endif
 
diff --git a/libcxx/src/memory.cpp b/libcxx/src/memory.cpp
index 9be40cb9c1285..e8631d0ad7e25 100644
--- a/libcxx/src/memory.cpp
+++ b/libcxx/src/memory.cpp
@@ -7,7 +7,8 @@
 //===----------------------------------------------------------------------===//
 
 #include <__config>
-#ifdef _LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS
+#if !defined(_LIBCPP_OBJECT_FORMAT_COFF) && !defined(_LIBCPP_OBJECT_FORMAT_XCOFF) &&                                   \
+    _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 5
 #  define _LIBCPP_SHARED_PTR_DEFINE_LEGACY_INLINE_FUNCTIONS
 #endif
 
diff --git a/libcxx/src/mutex_destructor.cpp b/libcxx/src/mutex_destructor.cpp
index 9f991721f083f..4c63ea0da74da 100644
--- a/libcxx/src/mutex_destructor.cpp
+++ b/libcxx/src/mutex_destructor.cpp
@@ -19,7 +19,7 @@
 #include <__config>
 #include <__thread/support.h>
 
-#if _LIBCPP_ABI_VERSION == 1 || !_LIBCPP_HAS_TRIVIAL_MUTEX_DESTRUCTION
+#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 9 || !_LIBCPP_HAS_TRIVIAL_MUTEX_DESTRUCTION
 #  define NEEDS_MUTEX_DESTRUCTOR
 #endif
 
diff --git a/libcxx/src/optional.cpp b/libcxx/src/optional.cpp
index faabe66cfcfc8..3b92580565bfc 100644
--- a/libcxx/src/optional.cpp
+++ b/libcxx/src/optional.cpp
@@ -19,6 +19,8 @@ const char* bad_optional_access::what() const noexcept { return "bad_optional_ac
 
 #include <__config>
 
+#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 7
+
 //  Preserve std::experimental::bad_optional_access for ABI compatibility
 //  Even though it no longer exists in a header file
 _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL
@@ -34,3 +36,5 @@ class _LIBCPP_EXPORTED_FROM_ABI bad_optional_access : public std::logic_error {
 bad_optional_access::~bad_optional_access() noexcept = default;
 
 _LIBCPP_END_NAMESPACE_EXPERIMENTAL
+
+#endif // _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 7
diff --git a/libcxx/src/string.cpp b/libcxx/src/string.cpp
index 5028fc88fe46d..178ef710f0bcf 100644
--- a/libcxx/src/string.cpp
+++ b/libcxx/src/string.cpp
@@ -20,7 +20,7 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-#ifndef _LIBCPP_ABI_DO_NOT_EXPORT_BASIC_STRING_COMMON
+#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 14
 
 template <bool>
 struct __basic_string_common;
@@ -35,12 +35,12 @@ struct __basic_string_common<true> {
 void __basic_string_common<true>::__throw_length_error() const { std::__throw_length_error("basic_string"); }
 void __basic_string_common<true>::__throw_out_of_range() const { std::__throw_out_of_range("basic_string"); }
 
-#endif // _LIBCPP_ABI_DO_NOT_EXPORT_BASIC_STRING_COMMON
+#endif // _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 14
 
 // Define legacy ABI functions
 // ---------------------------
 
-#ifndef _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION
+#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 21
 
 // This initializes the string with [__s, __s + __sz), but capacity() == __reserve. Assumes that __reserve >= __sz.
 template <class _CharT, class _Traits, class _Allocator>
@@ -53,15 +53,12 @@ void basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s, si
   __annotate_new(__sz);
 }
 
-#  define STRING_LEGACY_API(CharT)                                                                                     \
-    template _LIBCPP_EXPORTED_FROM_ABI void basic_string<CharT>::__init(const value_type*, size_type, size_type)
-
-STRING_LEGACY_API(char);
+template _LIBCPP_EXPORTED_FROM_ABI void basic_string<char>::__init(const value_type*, size_type, size_type);
 #  if _LIBCPP_HAS_WIDE_CHARACTERS
-STRING_LEGACY_API(wchar_t);
+template _LIBCPP_EXPORTED_FROM_ABI void basic_string<wchar_t>::__init(const value_type*, size_type, size_type);
 #  endif
 
-#endif // _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION
+#endif // _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 21
 
 #define _LIBCPP_EXTERN_TEMPLATE_DEFINE(...) template _LIBCPP_EXPORTED_FROM_ABI __VA_ARGS__;
 #ifdef _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION
diff --git a/libcxx/src/valarray.cpp b/libcxx/src/valarray.cpp
index 6ef1f1cafc0e5..3d3a9ac30ebd0 100644
--- a/libcxx/src/valarray.cpp
+++ b/libcxx/src/valarray.cpp
@@ -10,8 +10,7 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-// These two symbols are part of the v1 ABI but not part of the >=v2 ABI.
-#if _LIBCPP_ABI_VERSION == 1
+#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 9
 template _LIBCPP_EXPORTED_FROM_ABI valarray<size_t>::valarray(size_t);
 template _LIBCPP_EXPORTED_FROM_ABI valarray<size_t>::~valarray();
 #endif
diff --git a/libcxx/src/vector.cpp b/libcxx/src/vector.cpp
index 3f3a906d6421f..77a028a48077d 100644
--- a/libcxx/src/vector.cpp
+++ b/libcxx/src/vector.cpp
@@ -10,7 +10,7 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-#ifndef _LIBCPP_ABI_DO_NOT_EXPORT_VECTOR_BASE_COMMON
+#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 15
 
 template <bool>
 struct __vector_base_common;
@@ -25,6 +25,6 @@ void __vector_base_common<true>::__throw_length_error() const { std::__throw_len
 
 void __vector_base_common<true>::__throw_out_of_range() const { std::__throw_out_of_range("vector"); }
 
-#endif // _LIBCPP_ABI_DO_NOT_EXPORT_VECTOR_BASE_COMMON
+#endif // _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 15
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxxabi/CMakeLists.txt b/libcxxabi/CMakeLists.txt
index 3dabd87b9c587..e9e2a3f374541 100644
--- a/libcxxabi/CMakeLists.txt
+++ b/libcxxabi/CMakeLists.txt
@@ -64,6 +64,9 @@ option(LIBCXXABI_HAS_WIN32_THREAD_API "Ignore auto-detection and force use of wi
 option(LIBCXXABI_HAS_EXTERNAL_THREAD_API
   "Build libc++abi with an externalized threading API.
   This option may only be set to ON when LIBCXXABI_ENABLE_THREADS=ON." OFF)
+set(LIBCXXABI_AVAILABILITY_MINIMUM_HEADER_VERSION "1" CACHE STRING
+  "Minimum version of the libc++ headers that are allowed to be used by binaries linked against the libc++ library. This
+   version must correspond to the major version of an LLVM release.")
 option(LIBCXXABI_ENABLE_FORGIVING_DYNAMIC_CAST
 "Make dynamic_cast more forgiving when type_info's mistakenly have hidden \
 visibility, and thus multiple type_infos can exist for a single type. \
@@ -321,6 +324,7 @@ add_definitions(-D_LIBCXXABI_BUILDING_LIBRARY)
 # libcxxabi needs to, for various reasons, include the libcpp headers as if
 # it is being built as part of libcxx.
 add_definitions(-D_LIBCPP_BUILDING_LIBRARY)
+add_definitions(-D_LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION=${LIBCXXABI_AVAILABILITY_MINIMUM_HEADER_VERSION})
 
 # Get feature flags.
 add_compile_flags_if_supported(-fstrict-aliasing)



More information about the libcxx-commits mailing list