Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libc++][NFC] Refactor _LIBCPP_AVAILABILITY_HAS_* macros to always be defined #71002

Merged
merged 1 commit into from
Nov 24, 2023

Conversation

philnik777
Copy link
Contributor

This makes the conditionals quite a bit simpler to understand, since it
avoids double negatives and makes sure we have <__availability>
included. For vendors which use availability macros, it also enforces
that they check when specific features are introduced and define the
macro for their platform appropriately.

@philnik777 philnik777 requested a review from a team as a code owner November 1, 2023 23:40
@philnik777 philnik777 added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Nov 1, 2023
@llvmbot
Copy link
Member

llvmbot commented Nov 1, 2023

@llvm/pr-subscribers-libcxx

Author: None (philnik777)

Changes

This makes the conditionals quite a bit simpler to understand, since it
avoids double negatives and makes sure we have <__availability>
included. For vendors which use availability macros, it also enforces
that they check when specific features are introduced and define the
macro for their platform appropriately.


Patch is 47.45 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/71002.diff

9 Files Affected:

  • (modified) libcxx/include/__availability (+94-86)
  • (modified) libcxx/include/__verbose_abort (+4-3)
  • (modified) libcxx/include/version (+5-5)
  • (modified) libcxx/test/std/language.support/support.limits/support.limits.general/atomic.version.compile.pass.cpp (+6-6)
  • (modified) libcxx/test/std/language.support/support.limits/support.limits.general/barrier.version.compile.pass.cpp (+6-6)
  • (modified) libcxx/test/std/language.support/support.limits/support.limits.general/filesystem.version.compile.pass.cpp (+8-8)
  • (modified) libcxx/test/std/language.support/support.limits/support.limits.general/memory_resource.version.compile.pass.cpp (+14-14)
  • (modified) libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp (+34-34)
  • (modified) libcxx/utils/generate_feature_test_macro_components.py (+10-10)
diff --git a/libcxx/include/__availability b/libcxx/include/__availability
index 99a16c968de3c60..5c71b904ae1a4ea 100644
--- a/libcxx/include/__availability
+++ b/libcxx/include/__availability
@@ -87,57 +87,57 @@
 
 #if defined(_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS)
 
-    // These macros control the availability of std::bad_optional_access and
-    // other exception types. These were put in the shared library to prevent
-    // code bloat from every user program defining the vtable for these exception
-    // types.
-    //
-    // Note that when exceptions are disabled, the methods that normally throw
-    // these exceptions can be used even on older deployment targets, but those
-    // methods will abort instead of throwing.
-// #   define _LIBCPP_AVAILABILITY_HAS_NO_BAD_OPTIONAL_ACCESS
-#   define _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS
-
-// #   define _LIBCPP_AVAILABILITY_HAS_NO_BAD_VARIANT_ACCESS
-#   define _LIBCPP_AVAILABILITY_BAD_VARIANT_ACCESS
-
-// #   define _LIBCPP_AVAILABILITY_HAS_NO_BAD_ANY_CAST
-#   define _LIBCPP_AVAILABILITY_BAD_ANY_CAST
-
-    // These macros control the availability of all parts of <filesystem> that
-    // depend on something in the dylib.
-// #   define _LIBCPP_AVAILABILITY_HAS_NO_FILESYSTEM_LIBRARY
-#   define _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY
-#   define _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_PUSH
-#   define _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_POP
-
-    // This controls the availability of floating-point std::to_chars functions.
-    // These overloads were added later than the integer overloads.
-// #   define _LIBCPP_AVAILABILITY_HAS_NO_TO_CHARS_FLOATING_POINT
-#   define _LIBCPP_AVAILABILITY_TO_CHARS_FLOATING_POINT
-
-    // This controls the availability of the C++20 synchronization library,
-    // which requires shared library support for various operations
-    // (see libcxx/src/atomic.cpp). This includes <barier>, <latch>,
-    // <semaphore>, and notification functions on std::atomic.
-// #   define _LIBCPP_AVAILABILITY_HAS_NO_SYNC
-#   define _LIBCPP_AVAILABILITY_SYNC
-
-    // This controls whether the library claims to provide a default verbose
-    // termination function, and consequently whether the headers will try
-    // to use it when the mechanism isn't overriden at compile-time.
-// #   define _LIBCPP_AVAILABILITY_HAS_NO_VERBOSE_ABORT
-#   define _LIBCPP_AVAILABILITY_VERBOSE_ABORT
-
-    // This controls the availability of the C++17 std::pmr library,
-    // which is implemented in large part in the built library.
-// #   define _LIBCPP_AVAILABILITY_HAS_NO_PMR
-#   define _LIBCPP_AVAILABILITY_PMR
-
-    // This controls the availability of the C++20 time zone database.
-    // The parser code is built in the library.
-// #   define _LIBCPP_AVAILABILITY_HAS_NO_TZDB
-#   define _LIBCPP_AVAILABILITY_TZDB
+// These macros control the availability of std::bad_optional_access and
+// other exception types. These were put in the shared library to prevent
+// code bloat from every user program defining the vtable for these exception
+// types.
+//
+// Note that when exceptions are disabled, the methods that normally throw
+// these exceptions can be used even on older deployment targets, but those
+// methods will abort instead of throwing.
+#  define _LIBCPP_AVAILABILITY_HAS_BAD_OPTIONAL_ACCESS 1
+#  define _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS
+
+#  define _LIBCPP_AVAILABILITY_HAS_BAD_VARIANT_ACCESS 1
+#  define _LIBCPP_AVAILABILITY_BAD_VARIANT_ACCESS
+
+#  define _LIBCPP_AVAILABILITY_HAS_BAD_ANY_CAST 1
+#  define _LIBCPP_AVAILABILITY_BAD_ANY_CAST
+
+// These macros control the availability of all parts of <filesystem> that
+// depend on something in the dylib.
+#  define _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_LIBRARY 1
+#  define _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY
+#  define _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_PUSH
+#  define _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_POP
+
+// This controls the availability of floating-point std::to_chars functions.
+// These overloads were added later than the integer overloads.
+#  define _LIBCPP_AVAILABILITY_HAS_TO_CHARS_FLOATING_POINT 1
+#  define _LIBCPP_AVAILABILITY_TO_CHARS_FLOATING_POINT
+
+// This controls the availability of the C++20 synchronization library,
+// which requires shared library support for various operations
+// (see libcxx/src/atomic.cpp). This includes <barier>, <latch>,
+// <semaphore>, and notification functions on std::atomic.
+#  define _LIBCPP_AVAILABILITY_HAS_NO_SYNC
+#  define _LIBCPP_AVAILABILITY_SYNC
+
+// This controls whether the library claims to provide a default verbose
+// termination function, and consequently whether the headers will try
+// to use it when the mechanism isn't overriden at compile-time.
+#  define _LIBCPP_AVAILABILITY_HAS_VERBOSE_ABORT 1
+#  define _LIBCPP_AVAILABILITY_VERBOSE_ABORT
+
+// This controls the availability of the C++17 std::pmr library,
+// which is implemented in large part in the built library.
+#  define _LIBCPP_AVAILABILITY_HAS_PMR 1
+#  define _LIBCPP_AVAILABILITY_PMR
+
+// This controls the availability of the C++20 time zone database.
+// The parser code is built in the library.
+#  define _LIBCPP_AVAILABILITY_HAS_TZDB 1
+#  define _LIBCPP_AVAILABILITY_TZDB
 
 // Enable additional explicit instantiations of iostreams components. This
 // reduces the number of weak definitions generated in programs that use
@@ -146,28 +146,30 @@
 // TODO: Enable additional explicit instantiations on GCC once it supports exclude_from_explicit_instantiation,
 //       or once libc++ doesn't use the attribute anymore.
 // TODO: Enable them on Windows once https://llvm.org/PR41018 has been fixed.
-#if defined(_LIBCPP_COMPILER_GCC) || defined(_WIN32)
-#  define _LIBCPP_AVAILABILITY_HAS_NO_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1
-#endif
+#  define _LIBCPP_AVAILABILITY_HAS_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1                                       \
+    !defined(_LIBCPP_COMPILER_GCC) && !defined(_WIN32)
 
 #elif defined(__APPLE__)
 
-#  if (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 50000)
-#    define _LIBCPP_AVAILABILITY_HAS_NO_BAD_OPTIONAL_ACCESS
-#    define _LIBCPP_AVAILABILITY_HAS_NO_BAD_VARIANT_ACCESS
-#    define _LIBCPP_AVAILABILITY_HAS_NO_BAD_ANY_CAST
-#  endif
+#  define _LIBCPP_AVAILABILITY_HAS_BAD_OPTIONAL_ACCESS                                                                 \
+    (!defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) || __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ >= 50000)
+
+#  define _LIBCPP_AVAILABILITY_HAS_BAD_VARIANT_ACCESS _LIBCPP_AVAILABILITY_HAS_BAD_OPTIONAL_ACCESS
+#  define _LIBCPP_AVAILABILITY_HAS_BAD_ANY_CAST _LIBCPP_AVAILABILITY_HAS_BAD_OPTIONAL_ACCESS
+
 #  define _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS __attribute__((availability(watchos,strict,introduced=5.0)))
 #  define _LIBCPP_AVAILABILITY_BAD_VARIANT_ACCESS _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS
 #  define _LIBCPP_AVAILABILITY_BAD_ANY_CAST _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS
 
-    // <filesystem>
-#   if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101500) ||    \
-        (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 130000) || \
-        (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 130000) ||         \
-        (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 60000)
-#       define _LIBCPP_AVAILABILITY_HAS_NO_FILESYSTEM_LIBRARY
-#   endif
+// <filesystem>
+#  if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101500) ||   \
+      (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 130000) || \
+      (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 130000) ||         \
+      (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 60000)
+#    define _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_LIBRARY 0
+#  else
+#    define _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_LIBRARY 1
+#  endif
 #   define _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY                              \
         __attribute__((availability(macos,strict,introduced=10.15)))            \
         __attribute__((availability(ios,strict,introduced=13.0)))               \
@@ -184,13 +186,15 @@
         _Pragma("clang attribute pop")                                          \
         _Pragma("clang attribute pop")
 
-    // std::to_chars(floating-point)
-#   if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 130300) ||    \
-        (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 160300) || \
-        (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 160300) ||         \
-        (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 90300)
-#       define _LIBCPP_AVAILABILITY_HAS_NO_TO_CHARS_FLOATING_POINT
-#   endif
+// std::to_chars(floating-point)
+#  if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 130300) ||   \
+      (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 160300) || \
+      (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 160300) ||         \
+      (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 90300)
+#    define _LIBCPP_AVAILABILITY_HAS_TO_CHARS_FLOATING_POINT 0
+#  else
+#    define _LIBCPP_AVAILABILITY_HAS_TO_CHARS_FLOATING_POINT 1
+#  endif
 #   define _LIBCPP_AVAILABILITY_TO_CHARS_FLOATING_POINT                         \
         __attribute__((availability(macos,strict,introduced=13.3)))             \
         __attribute__((availability(ios,strict,introduced=16.3)))               \
@@ -210,20 +214,22 @@
         __attribute__((availability(tvos,strict,introduced=14.0)))              \
         __attribute__((availability(watchos,strict,introduced=7.0)))
 
-    // __libcpp_verbose_abort
-#   if 1 // TODO: Update once this is released
-#       define _LIBCPP_AVAILABILITY_HAS_NO_VERBOSE_ABORT
-#   endif
+// __libcpp_verbose_abort
+// TODO: Update once this is released
+#  define _LIBCPP_AVAILABILITY_HAS_VERBOSE_ABORT 0
+
 #   define _LIBCPP_AVAILABILITY_VERBOSE_ABORT                                   \
         __attribute__((unavailable))
 
-    // std::pmr
-#   if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 140000) ||    \
-        (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 170000) || \
-        (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 170000) ||         \
-        (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 100000)
-#       define _LIBCPP_AVAILABILITY_HAS_NO_PMR
-#   endif
+// std::pmr
+#  if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 140000) ||   \
+      (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 170000) || \
+      (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 170000) ||         \
+      (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 100000)
+#    define _LIBCPP_AVAILABILITY_HAS_PMR 0
+#  else
+#    define _LIBCPP_AVAILABILITY_HAS_PMR 1
+#  endif
 // TODO: Enable std::pmr markup once https://github.com/llvm/llvm-project/issues/40340 has been fixed
 //       Until then, it is possible for folks to try to use `std::pmr` when back-deploying to targets that don't support
 //       it and it'll be a load-time error, but we don't have a good alternative because the library won't compile if we
@@ -238,14 +244,16 @@
 #    define _LIBCPP_AVAILABILITY_PMR
 #  endif
 
-#  define _LIBCPP_AVAILABILITY_HAS_NO_TZDB
+#  define _LIBCPP_AVAILABILITY_HAS_TZDB 0
 #  define _LIBCPP_AVAILABILITY_TZDB __attribute__((unavailable))
 
 #  if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 120000)   || \
       (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 150000) || \
       (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 150000)         || \
       (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 80000)
-#    define _LIBCPP_AVAILABILITY_HAS_NO_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1
+#    define _LIBCPP_AVAILABILITY_HAS_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1 0
+#  else
+#    define _LIBCPP_AVAILABILITY_HAS_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1 1
 #  endif
 #else
 
diff --git a/libcxx/include/__verbose_abort b/libcxx/include/__verbose_abort
index a38284b711f3628..accd596b088601c 100644
--- a/libcxx/include/__verbose_abort
+++ b/libcxx/include/__verbose_abort
@@ -40,12 +40,13 @@ void __libcpp_verbose_abort(const char *__format, ...);
 
 // Support _LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED until LLVM 18, but tell people
 // to move to customizing _LIBCPP_VERBOSE_ABORT instead.
-#  if defined(_LIBCPP_AVAILABILITY_HAS_NO_VERBOSE_ABORT) && defined(_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED)
-#    undef _LIBCPP_AVAILABILITY_HAS_NO_VERBOSE_ABORT
+#  if !_LIBCPP_AVAILABILITY_HAS_VERBOSE_ABORT && defined(_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED)
+#    undef _LIBCPP_AVAILABILITY_HAS_VERBOSE_ABORT
+#    define _LIBCPP_AVAILABILITY_HAS_VERBOSE_ABORT 1
 #    warning _LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED is deprecated, please customize _LIBCPP_VERBOSE_ABORT instead
 #  endif
 
-#  if defined(_LIBCPP_AVAILABILITY_HAS_NO_VERBOSE_ABORT)
+#  if !_LIBCPP_AVAILABILITY_HAS_VERBOSE_ABORT
 // The decltype is there to suppress -Wunused warnings in this configuration.
 void __use(const char*, ...);
 #    define _LIBCPP_VERBOSE_ABORT(...) (decltype(::std::__use(__VA_ARGS__))(), __builtin_abort())
diff --git a/libcxx/include/version b/libcxx/include/version
index 3c8e1a132e87f85..9d96ef25cbf67c2 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -273,7 +273,7 @@ __cpp_lib_within_lifetime                               202306L <type_traits>
 # define __cpp_lib_clamp                                201603L
 # define __cpp_lib_enable_shared_from_this              201603L
 // # define __cpp_lib_execution                            201603L
-# if !defined(_LIBCPP_AVAILABILITY_HAS_NO_FILESYSTEM_LIBRARY)
+# if _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_LIBRARY
 #   define __cpp_lib_filesystem                         201703L
 # endif
 # define __cpp_lib_gcd_lcm                              201606L
@@ -292,7 +292,7 @@ __cpp_lib_within_lifetime                               202306L <type_traits>
 # define __cpp_lib_make_from_tuple                      201606L
 # define __cpp_lib_map_try_emplace                      201411L
 // # define __cpp_lib_math_special_functions               201603L
-# if !defined(_LIBCPP_AVAILABILITY_HAS_NO_PMR)
+# if _LIBCPP_AVAILABILITY_HAS_PMR
 #   define __cpp_lib_memory_resource                    201603L
 # endif
 # define __cpp_lib_node_extract                         201606L
@@ -329,10 +329,10 @@ __cpp_lib_within_lifetime                               202306L <type_traits>
 // # define __cpp_lib_atomic_ref                           201806L
 // # define __cpp_lib_atomic_shared_ptr                    201711L
 # define __cpp_lib_atomic_value_initialization          201911L
-# if !defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)
+# if _LIBCPP_AVAILABILITY_HAS_SYNC
 #   define __cpp_lib_atomic_wait                        201907L
 # endif
-# if !defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)
+# if !defined(_LIBCPP_HAS_NO_THREADS) && _LIBCPP_AVAILABILITY_HAS_SYNC
 #   define __cpp_lib_barrier                            201907L
 # endif
 # define __cpp_lib_bind_front                           201907L
@@ -381,7 +381,7 @@ __cpp_lib_within_lifetime                               202306L <type_traits>
 # define __cpp_lib_list_remove_return_type              201806L
 # define __cpp_lib_math_constants                       201907L
 # define __cpp_lib_move_iterator_concept                202207L
-# if !defined(_LIBCPP_AVAILABILITY_HAS_NO_PMR)
+# if _LIBCPP_AVAILABILITY_HAS_PMR
 #   define __cpp_lib_polymorphic_allocator              201902L
 # endif
 # define __cpp_lib_ranges                               202207L
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/atomic.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/atomic.version.compile.pass.cpp
index ebb7efb5eb593ac..ded743716f33c1d 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/atomic.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/atomic.version.compile.pass.cpp
@@ -216,7 +216,7 @@
 #   error "__cpp_lib_atomic_value_initialization should have the value 201911L in c++20"
 # endif
 
-# if !defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)
+# if !defined(_LIBCPP_AVAILABILITY_HAS_SYNC) || _LIBCPP_AVAILABILITY_HAS_SYNC
 #   ifndef __cpp_lib_atomic_wait
 #     error "__cpp_lib_atomic_wait should be defined in c++20"
 #   endif
@@ -225,7 +225,7 @@
 #   endif
 # else
 #   ifdef __cpp_lib_atomic_wait
-#     error "__cpp_lib_atomic_wait should not be defined when the requirement '!defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)' is not met!"
+#     error "__cpp_lib_atomic_wait should not be defined when the requirement '!defined(_LIBCPP_AVAILABILITY_HAS_SYNC) || _LIBCPP_AVAILABILITY_HAS_SYNC' is not met!"
 #   endif
 # endif
 
@@ -311,7 +311,7 @@
 #   error "__cpp_lib_atomic_value_initialization should have the value 201911L in c++23"
 # endif
 
-# if !defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)
+# if !defined(_LIBCPP_AVAILABILITY_HAS_SYNC) || _LIBCPP_AVAILABILITY_HAS_SYNC
 #   ifndef __cpp_lib_atomic_wait
 #     error "__cpp_lib_atomic_wait should be defined in c++23"
 #   endif
@@ -320,7 +320,7 @@
 #   endif
 # else
 #   ifdef __cpp_lib_atomic_wait
-#     error "__cpp_lib_atomic_wait should not be defined when the requirement '!defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)' is not met!"
+#     error "__cpp_lib_atomic_wait should not be defined when the requirement '!defined(_LIBCPP_AVAILABILITY_HAS_SYNC) || _LIBCPP_AVAILABILITY_HAS_SYNC' is not met!"
 #   endif
 # endif
 
@@ -406,7 +406,7 @@
 #   error "__cpp_lib_atomic_value_initialization should have the value 201911L in c++26"
 # endif
 
-# if !defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)
+# if !defined(_LIBCPP_AVAILABILITY_HAS_SYNC) || _LIBCPP_AVAILABILITY_HAS_SYNC
 #   ifndef __cpp_lib_atomic_wait
 #     error "__cpp_lib_atomic_wait should be defined in c++26"
 #   endif
@@ -415,7 +415,7 @@
 #   endif
 # else
 #   ifdef __cpp_lib_atomic_wait
-#     error "__cpp_lib_atomic_wait should not be defined when the requirement '!defined(_LIBCPP_AVAILABILITY_HAS_NO_SYNC)' is not met!"
+#     error "__cpp_lib_atomic_wait should not be defined when the requirement '!defined(_LIBCPP_AVAILABILITY_HAS_SYNC) || _LIBCPP_AVAILABILITY_HAS_SYNC' is not met!"
 #   endif
 # endif
 
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/barrier.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/barrier.version.compile.pass.cpp
index 33e8a3c23a9e5b0..9aa0fe38d7f862d 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/barrier.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/barrier.version.comp...
[truncated]

Copy link
Member

@ldionne ldionne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This LGTM, it makes it harder to misuse these macros.

libcxx/include/__availability Outdated Show resolved Hide resolved
libcxx/utils/generate_feature_test_macro_components.py Outdated Show resolved Hide resolved
@philnik777 philnik777 force-pushed the refactor_availability branch 2 times, most recently from 8128ec3 to 60d7c68 Compare November 19, 2023 12:31
Copy link

github-actions bot commented Nov 19, 2023

✅ With the latest revision this PR passed the Python code formatter.

@philnik777 philnik777 force-pushed the refactor_availability branch 3 times, most recently from b8e49a4 to 474dd0d Compare November 24, 2023 17:11
Copy link

github-actions bot commented Nov 24, 2023

✅ With the latest revision this PR passed the C/C++ code formatter.

defined

This makes the conditionals quite a bit simpler to understand, since it
avoids double negatives and makes sure we have <__availability>
included. For vendors which use availability macros, it also enforces
that they check when specific features are introduced and define the
macro for their platform appropriately.
@philnik777 philnik777 force-pushed the refactor_availability branch from 474dd0d to 3c27b3c Compare November 24, 2023 22:45
@philnik777 philnik777 merged commit 12563ea into llvm:main Nov 24, 2023
@philnik777 philnik777 deleted the refactor_availability branch November 24, 2023 22:45
Guzhu-AMD pushed a commit to GPUOpen-Drivers/llvm-project that referenced this pull request Nov 30, 2023
Local branch amd-gfx fe4b214 Merged main:b86420c614b5 into amd-gfx:72cb88f43ff0
Remote branch main 12563ea [libc++][NFC] Refactor _LIBCPP_AVAILABILITY_HAS_* macros to always be defined (llvm#71002)
StephanTLavavej added a commit that referenced this pull request Dec 3, 2023
Found while running libc++'s test suite with MSVC's STL.

This is a followup to @philnik777's recent #71002 (thank you!) which
provided the existing examples of `__cpp_lib_barrier` and
`__cpp_lib_polymorphic_allocator`:

https://github.com/llvm/llvm-project/blob/66a3e4fafb6eae19764f8a192ca3a116c0554211/libcxx/utils/generate_feature_test_macro_components.py#L199-L203

https://github.com/llvm/llvm-project/blob/66a3e4fafb6eae19764f8a192ca3a116c0554211/libcxx/utils/generate_feature_test_macro_components.py#L866-L870

Applying that new pattern to the feature-test macros here gets their
corresponding tests passing for us.

:robot: Only `generate_feature_test_macro_components.py` was manually
updated; the other files were regenerated.
@wang-bin
Copy link

wang-bin commented Jan 29, 2024

how to disable _LIBCPP_AVAILABILITY_HAS_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1? I use the latest llvm toolchain on ubuntu to cross build linux programs, and expect they can run on OSes with old system libc++ version. in llvm-17 the produced binaries are compatible with old libc++ because _LIBCPP_ABI_ENABLE_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1 is not defined by default, but in llvm-18 _LIBCPP_AVAILABILITY_HAS_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1 is always 1 and breaks abi

@philnik777
Copy link
Contributor Author

how to disable _LIBCPP_AVAILABILITY_HAS_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1? I use the latest llvm toolchain on ubuntu to cross build linux programs, and expect they can run on OSes with old system libc++ version. in llvm-17 the produced binaries are compatible with old libc++ because _LIBCPP_ABI_ENABLE_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1 is not defined by default, but in llvm-18 _LIBCPP_AVAILABILITY_HAS_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1 is always 1 and breaks abi

AFAIK Ubuntu doesn't support back-porting. This has to be managed by the library vendor.

@wang-bin
Copy link

It's not about back-porting, it's an abi break in libc++18. when building user code with libc++17, _LIBCPP_ABI_ENABLE_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1 is not defined unless targeting _LIBCPP_ABI_VERSION >= 2, but libc++18 doesn't check _LIBCPP_ABI_VERSION, and there is no way to disable extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_ifstream<char>. The break comes from https://reviews.llvm.org/D154796

@philnik777
Copy link
Contributor Author

It's not about back-porting, it's an abi break in libc++18. when building user code with libc++17, _LIBCPP_ABI_ENABLE_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1 is not defined unless targeting _LIBCPP_ABI_VERSION >= 2, but libc++18 doesn't check _LIBCPP_ABI_VERSION, and there is no way to disable extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_ifstream<char>. The break comes from https://reviews.llvm.org/D154796

It's not an ABI break. Programs compiled against older libc++ version still work just fine with the dylib from libc++18. Programs compiled against a newer version of libc++ assume that symbols are available that aren't in older dylibs, which makes it a matter of availability (i.e. back-porting), not ABI.

@wang-bin
Copy link

another issue is __libcpp_verbose_abort, in libc++17 we can add -D_LIBCPP_AVAILABILITY_HAS_NO_VERBOSE_ABORT=1 to be compatible with libc++<=16 runtime, but in libc++18 _LIBCPP_AVAILABILITY_HAS_VERBOSE_ABORT is always 1, the solution becomes ugly -D_LIBCPP_VERBOSE_ABORT\(...\)=__builtin_abort\(\).

@wang-bin
Copy link

wang-bin commented Jan 29, 2024

It's not about back-porting, it's an abi break in libc++18. when building user code with libc++17, _LIBCPP_ABI_ENABLE_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1 is not defined unless targeting _LIBCPP_ABI_VERSION >= 2, but libc++18 doesn't check _LIBCPP_ABI_VERSION, and there is no way to disable extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_ifstream<char>. The break comes from https://reviews.llvm.org/D154796

It's not an ABI break. Programs compiled against older libc++ version still work just fine with the dylib from libc++18. Programs compiled against a newer version of libc++ assume that symbols are available that aren't in older dylibs, which makes it a matter of availability (i.e. back-porting), not ABI.

So how can I build with the libc++ and run on old systems(for example ubuntu 20.04)? distribute apps with the latest libc++? AFAIK these changes don't break apple OSes, it's better to provide an option to not break linux too.

@wang-bin
Copy link

wang-bin commented Jan 29, 2024

This will be a problem on android. If I build my library with a new ndk(libc++18 or later), library users may use an old ndk version(for example ndk23 LTS, llvm-12), then they will get link error, because these symbols don't exist in libc++ < 13. @DanAlbert what do you think?

@philnik777
Copy link
Contributor Author

It's not about back-porting, it's an abi break in libc++18. when building user code with libc++17, _LIBCPP_ABI_ENABLE_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1 is not defined unless targeting _LIBCPP_ABI_VERSION >= 2, but libc++18 doesn't check _LIBCPP_ABI_VERSION, and there is no way to disable extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_ifstream<char>. The break comes from https://reviews.llvm.org/D154796

It's not an ABI break. Programs compiled against older libc++ version still work just fine with the dylib from libc++18. Programs compiled against a newer version of libc++ assume that symbols are available that aren't in older dylibs, which makes it a matter of availability (i.e. back-porting), not ABI.

So how can I build with the libc++ and run on old systems? distribute apps with the latest libc++? AFAIK these changes don't break apple OSes, it's better to provide an option to not break linux too.

Distributing your own dylib is always an option, but may not be desirable. The way to make it work properly is to do the same thing as Apple does: Provide availability information. This has to be maintained of course, but it's the only way for us to know when to provide certain functionality. You'd basically have to

  • add a flag like -mubuntu-version-min to clang which adds a __UBUNTU_VERSION__ macro
  • extend [[clang::availability]] to accept ubuntu as a platform and uses the flag to check whether something is available
  • extend __availability with the corresponding availability requirements for ubuntu.

I'm pretty sure the only thing that has to be updated is the information in __availability. Anything else should be fine just sitting around.

@philnik777
Copy link
Contributor Author

Also, could you open an issue, so we don't continue to pollute this PR with unrelated posts?

@DanAlbert
Copy link
Member

I don't understand what Android problem you see? Android apps do distribute their own dylib. If the problem is that you distribute something that's too old for your dependencies, don't do that?

@wang-bin
Copy link

I don't understand what Android problem you see? Android apps do distribute their own dylib. If the problem is that you distribute something that's too old for your dependencies, don't do that?

What about 3rdparty SDKs? I opened an issue #79933

@aheejin
Copy link
Member

aheejin commented Mar 28, 2024

WebAssembly's emscripten toolchain (https://github.com/emscripten-core/emscripten) has been using _LIBCPP_AVAILABILITY_HAS_NO_VERBOSE_ABORT not to pay for the increased code size of __libcpp_verbose_abort so far. After this change, that macro does not exist. We don't provide our own vendor annotation, and defining _LIBCPP_AVAILABILITY_HAS_VERBOSE_ABORT as 0 is overridden by this line:

# define _LIBCPP_AVAILABILITY_HAS_VERBOSE_ABORT 1

I read the discussions in this PR; what I'm asking is not about backporting. I just would like to disable the verbose abort in the current version. I read about needing to create our own availability markup like Apple:

#elif defined(__APPLE__)

But to do that it looks we have to copy the whole list of macros here

// These macros control the availability of std::bad_optional_access and
// other exception types. These were put in the shared library to prevent
// code bloat from every user program defining the vtable for these exception
// types.
//
// Note that when exceptions are disabled, the methods that normally throw
// these exceptions can be used even on older deployment targets, but those
// methods will abort instead of throwing.
# define _LIBCPP_AVAILABILITY_HAS_BAD_OPTIONAL_ACCESS 1
# define _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS
# define _LIBCPP_AVAILABILITY_HAS_BAD_VARIANT_ACCESS 1
# define _LIBCPP_AVAILABILITY_BAD_VARIANT_ACCESS
# define _LIBCPP_AVAILABILITY_HAS_BAD_ANY_CAST 1
# define _LIBCPP_AVAILABILITY_BAD_ANY_CAST
// These macros control the availability of all parts of <filesystem> that
// depend on something in the dylib.
# define _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_LIBRARY 1
# define _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY
# define _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_PUSH
# define _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_POP
// This controls the availability of the C++20 synchronization library,
// which requires shared library support for various operations
// (see libcxx/src/atomic.cpp). This includes <barier>, <latch>,
// <semaphore>, and notification functions on std::atomic.
# define _LIBCPP_AVAILABILITY_HAS_SYNC 1
# define _LIBCPP_AVAILABILITY_SYNC
// Enable additional explicit instantiations of iostreams components. This
// reduces the number of weak definitions generated in programs that use
// iostreams by providing a single strong definition in the shared library.
//
// TODO: Enable additional explicit instantiations on GCC once it supports exclude_from_explicit_instantiation,
// or once libc++ doesn't use the attribute anymore.
// TODO: Enable them on Windows once https://llvm.org/PR41018 has been fixed.
# if !defined(_LIBCPP_COMPILER_GCC) && !defined(_WIN32)
# define _LIBCPP_AVAILABILITY_HAS_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1 1
# else
# define _LIBCPP_AVAILABILITY_HAS_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1 0
# endif
// This controls the availability of floating-point std::to_chars functions.
// These overloads were added later than the integer overloads.
# define _LIBCPP_AVAILABILITY_HAS_TO_CHARS_FLOATING_POINT 1
# define _LIBCPP_AVAILABILITY_TO_CHARS_FLOATING_POINT
// This controls whether the library claims to provide a default verbose
// termination function, and consequently whether the headers will try
// to use it when the mechanism isn't overriden at compile-time.
# define _LIBCPP_AVAILABILITY_HAS_VERBOSE_ABORT 1
# define _LIBCPP_AVAILABILITY_VERBOSE_ABORT
// This controls the availability of the C++17 std::pmr library,
// which is implemented in large part in the built library.
# define _LIBCPP_AVAILABILITY_HAS_PMR 1
# define _LIBCPP_AVAILABILITY_PMR
// These macros controls the availability of __cxa_init_primary_exception
// in the built library, which std::make_exception_ptr might use
// (see libcxx/include/__exception/exception_ptr.h).
# define _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION 1
# define _LIBCPP_AVAILABILITY_INIT_PRIMARY_EXCEPTION
// This controls the availability of C++23 <print>, which
// has a dependency on the built library (it needs access to
// the underlying buffer types of std::cout, std::cerr, and std::clog.
# define _LIBCPP_AVAILABILITY_HAS_PRINT 1
# define _LIBCPP_AVAILABILITY_PRINT
// This controls the availability of the C++20 time zone database.
// The parser code is built in the library.
# define _LIBCPP_AVAILABILITY_HAS_TZDB 1
# define _LIBCPP_AVAILABILITY_TZDB

and copy them to our section in order to just change the one line (_LIBCPP_AVAILABILITY_HAS_VERBOSE_ABORT). Is this the recommended (or the only possible) way of changing one setting?

@ldionne
Copy link
Member

ldionne commented Mar 28, 2024

In your case, since you don't care about back-deployment you should likely not define these macros. However, I also think you shouldn't be disabling __libcpp_verbose_abort(): we don't use it to handle assertions in release mode anyway (we moved to __builtin_trap()) so you shouldn't be disabling it artificially.

@aheejin
Copy link
Member

aheejin commented Mar 28, 2024

How does the release mode choose __builtin_trap() over __libcpp_verbose_abort()? Does it do that via CMake? (I can't find the string VERBOSE_ABORT in CMakeLists.txt though)

Not sure it's relevant, but Emscripten doesn't use CMake and we use our custom build infrastructure. If we know how CMake does it we can probably mimic it.

@ldionne
Copy link
Member

ldionne commented Mar 28, 2024

@aheejin
Copy link
Member

aheejin commented Mar 28, 2024

I see, but there are plenty of places that directly calls _LIBCPP_VERBOSE_ABORT macro, which does not seem to be controllable by a setting after this PR. Any advice on how to choose __builtin_abort() call over __libcpp_verbose_abort() here?

# if !_LIBCPP_AVAILABILITY_HAS_VERBOSE_ABORT
// The decltype is there to suppress -Wunused warnings in this configuration.
void __use(const char*, ...);
# define _LIBCPP_VERBOSE_ABORT(...) (decltype(::std::__use(__VA_ARGS__))(), __builtin_abort())
# else
# define _LIBCPP_VERBOSE_ABORT(...) ::std::__libcpp_verbose_abort(__VA_ARGS__)
# endif

@ldionne
Copy link
Member

ldionne commented Mar 28, 2024

You mentioned you wanted to disable it for code size reasons. Presumably you only care strongly about code size in release mode, where we already do the right thing. So I would argue there's nothing special for you to do, just use the default configuration of the library and call it a day.

And if that doesn't work, please open an issue explaining why the default configuration of the library isn't sufficient for your use case so we can have a dedicated space to investigate and discuss it.

@aheejin
Copy link
Member

aheejin commented Mar 28, 2024

What I was trying to say is, gating _LIBCPP_ASSERTION_HANDLER on debug/release mode is not sufficient to prevent code size increase in the relase mode. There are dozens of places in libc++ that directly call _LIBCPP_VERBOSE_ABORT, like these:

_LIBCPP_NORETURN inline _LIBCPP_HIDE_FROM_ABI void __throw_logic_error(const char* __msg) {
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
throw logic_error(__msg);
#else
_LIBCPP_VERBOSE_ABORT("logic_error was thrown in -fno-exceptions mode with message \"%s\"", __msg);
#endif
}
_LIBCPP_NORETURN inline _LIBCPP_HIDE_FROM_ABI void __throw_domain_error(const char* __msg) {
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
throw domain_error(__msg);
#else
_LIBCPP_VERBOSE_ABORT("domain_error was thrown in -fno-exceptions mode with message \"%s\"", __msg);
#endif
}
_LIBCPP_NORETURN inline _LIBCPP_HIDE_FROM_ABI void __throw_invalid_argument(const char* __msg) {
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
throw invalid_argument(__msg);
#else
_LIBCPP_VERBOSE_ABORT("invalid_argument was thrown in -fno-exceptions mode with message \"%s\"", __msg);
#endif
}
_LIBCPP_NORETURN inline _LIBCPP_HIDE_FROM_ABI void __throw_length_error(const char* __msg) {
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
throw length_error(__msg);
#else
_LIBCPP_VERBOSE_ABORT("length_error was thrown in -fno-exceptions mode with message \"%s\"", __msg);
#endif
}
_LIBCPP_NORETURN inline _LIBCPP_HIDE_FROM_ABI void __throw_out_of_range(const char* __msg) {
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
throw out_of_range(__msg);
#else
_LIBCPP_VERBOSE_ABORT("out_of_range was thrown in -fno-exceptions mode with message \"%s\"", __msg);
#endif
}
_LIBCPP_NORETURN inline _LIBCPP_HIDE_FROM_ABI void __throw_range_error(const char* __msg) {
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
throw range_error(__msg);
#else
_LIBCPP_VERBOSE_ABORT("range_error was thrown in -fno-exceptions mode with message \"%s\"", __msg);
#endif
}
_LIBCPP_NORETURN inline _LIBCPP_HIDE_FROM_ABI void __throw_overflow_error(const char* __msg) {
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
throw overflow_error(__msg);
#else
_LIBCPP_VERBOSE_ABORT("overflow_error was thrown in -fno-exceptions mode with message \"%s\"", __msg);
#endif
}
_LIBCPP_NORETURN inline _LIBCPP_HIDE_FROM_ABI void __throw_underflow_error(const char* __msg) {
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
throw underflow_error(__msg);
#else
_LIBCPP_VERBOSE_ABORT("underflow_error was thrown in -fno-exceptions mode with message \"%s\"", __msg);
#endif
}

or this:
_LIBCPP_VERBOSE_ABORT("bad_alloc was thrown in -fno-exceptions mode");

which has nothing to do with _LIBCPP_ASSERTION_HANDLER.

I can file an issue but I wanted to check first this was really an issue, meaning, if there was a solution and I wasn't aware of it. And this after PR, it looks controlling a specific single setting becomes very difficult in general. What Apple did was copy-pasting the whole set of section in __availability into their #elif defined(__APPLE__) and modifying the ones they wanted to. If we have many settings we want to modify that would be fine, but having to copy-paste dozens of settings to modify a single setting seems excessive, if that's the only way to do it.

@ldionne
Copy link
Member

ldionne commented Mar 28, 2024

What I was trying to say is, gating _LIBCPP_ASSERTION_HANDLER on debug/release mode is not sufficient to prevent code size increase in the relase mode. There are dozens of places in libc++ that directly call _LIBCPP_VERBOSE_ABORT, like these:

[...]

or this:
[...]

which has nothing to do with _LIBCPP_ASSERTION_HANDLER.
What Apple did was copy-pasting the whole set of section into their #elif defined(__APPLE__) and modified the ones they wanted to. If we have many settings we want to modify that would be fine, but having to copy-paste dozens of settings to modify a single setting seems excessive, if that's the only way to do it.

Basically, this mechanism is intended to be used for back-deployment purposes, not to optimize code size or enable/disable individual features based on preferences. That's why that mechanism is not optimized for setting just one or two of these macros. That's a mismatch between the way the header intends to be used and the way you are trying to use it.

Could you please provide more detail (in a separate issue) about the problematic code size you're seeing? I am kinda skeptical that calling an extern function in a few __throw_foo functions is really something that moves the needle, but I am happy to investigate in case it is.

@aheejin
Copy link
Member

aheejin commented Mar 28, 2024

First, thanks for your replies!

I can open a separate issue, but I don't think the code size was the point. (And I agree in general that code size increase doesn't matter, but it can be an issue for some embedded systems or Wasm because the larger the code size is it takes more time to transmit over the internet. But again, it's not the point here.)

My question was, is there a way to toggle individual setting in any way, for whatever reason?

Basically, this mechanism is intended to be used for back-deployment purposes, not to optimize code size or enable/disable individual features based on preferences. That's why that mechanism is not optimized for setting just one or two of these macros. That's a mismatch between the way the header intends to be used and the way you are trying to use it.

OK, now I understand that messing with __availability to toggle individual settings is not the way it's intended to be used. Then what's the recommended way of changing a single (or a couple) setting in libcxx now?

@aheejin
Copy link
Member

aheejin commented Mar 28, 2024

I posted a new issue: #87012
But this basically contains the same question I posted here.

aheejin added a commit to aheejin/emscripten that referenced this pull request Mar 29, 2024
In emscripten-core#20707 we decided to disable `__libcpp_verbose_abort` not to incur
the code size increase that brings (it brings in `vfprintf` and its
family). We disabled it in adding
`#define _LIBCPP_AVAILABILITY_HAS_NO_VERBOSE_ABORT` in `__config_site`.

That `_NO_` macros are gone in LLVM 18.1.2, so I changed it to
`#define _LIBCPP_AVAILABILITY_HAS_VERBOSE_ABORT 0`
emscripten-core@2bd7c67
But apparently, when including `__availability`, that setting is
overridden by this line:
https://github.com/llvm/llvm-project/blob/38f5596feda3276a8aa64fc14e074334017088ca/libcxx/include/__availability#L138
because we don't define our own vendor availability annotations
https://github.com/emscripten-core/emscripten/blob/193b2bff980529dbf5d067f01761ed8a6e41189f/system/lib/libcxx/include/__config_site#L4

I asked about this in
llvm/llvm-project#87012 and
llvm/llvm-project#71002 (comment)
(and more comments below)
but didn't get an actionable answer yet.

This disables `__libcpp_verbose_abort` in the code directly for now,
hopefully temporarily.
aheejin added a commit to emscripten-core/emscripten that referenced this pull request Apr 3, 2024
This updates libcxx and libcxxabi to LLVM 18.1.2. Due to
llvm/llvm-project#65534 we need to update both
at the same time.

Things to note:

- Disable hardening mode:
  LLVM 18.1.2 adds support for "Hardening Modes" to libcxx
  (https://libcxx.llvm.org/Hardening.html). There are four modes: none,
  fast, extensive and debug. Different hardening modes make different
  trade-offs between the amount of checking and runtime performance. We
  for now disable it (i.e., set it to 'none') so that we don't have any
  effects on the performance. We can consider enabling it when we ever
  get to enable the debug version of libcxx.

- Disable C++20 time zone support:
  LLVM 18.1.2 adds C++20 time zone support
  (https://libcxx.llvm.org/DesignDocs/TimeZone.html) to libcxx, which
  requires access IANA Time Zone Database. Currently it seems it only
  supports Linux:
  https://github.com/llvm/llvm-project/blob/26a1d6601d727a96f4301d0d8647b5a42760ae0c/libcxx/src/tz.cpp#L45-L49
  So this excludes the two source files from build (which is done via
  `CMakeLists.txt` in the upstream LLVM) and sets
  `_LIBCPP_HAS_NO_TIME_ZONE_DATABASE` macro in `__config_site`. In
  future maybe we can consider implementing this in JS.

- `__cxa_init_primary_exception` support:
  llvm/llvm-project#65534 introduces
  `__cxa_init_primary_exception` and uses this in libcxx. Like several
  other methods like the below in `cxa_exception.cpp`,
  https://github.com/emscripten-core/emscripten/blob/fbdd9249e939660cb0d20f00d6bc1897c2f3905e/system/lib/libcxxabi/src/cxa_exception.cpp#L264-L269
  this new function takes a pointer to a destructor, and in Wasm
  destructor returns a `this` pointer, which requires `ifdef
  __USING_WASM_EXCEPTION__` on its signature. And that it is also used
  in libcxx means we need to guard some code in libcxx with `ifdef
  __USING_WASM_EXCEPTION__` for the signature difference, and we need to
  build libcxx with `-D__USING_WASM_EXCEPTIONS__` when Wasm EH is used.
  Also we add Emscripte EH's counterpart in
  `cxa_exception_emscripten.cpp` too.

- This version fixes long-running misbehaviors of `operator new`
  llvm/llvm-project#69498 seems to fix some
  long-running misbhaviors of `operator new`, which in emscripten we
  tried to fix in #11079 and #20154. So while resolving the conflicts, I
  effectively reverted #11079 and #20154 in
  `libcxx/src/stdlib_new_delete.cpp` and `libcxx/src/new.cpp`.

- Add default `__assertion_handler` to `libcxx/include`:
  llvm/llvm-project#77883 adds a way for vendors
  to override how we handle assertions. If a vendor doesn't want to
  override it, CMake will copy the provided [default template assertion
  handler
  file](https://github.com/llvm/llvm-project/blob/26a1d6601d727a96f4301d0d8647b5a42760ae0c/libcxx/vendor/llvm/default_assertion_handler.in)
  to libcxx's generated include dir, which defaults to
  `SYSROOT/include/c++/v1`:
  https://github.com/llvm/llvm-project/blob/26a1d6601d727a96f4301d0d8647b5a42760ae0c/libcxx/CMakeLists.txt#L72-L73
  https://github.com/llvm/llvm-project/blob/26a1d6601d727a96f4301d0d8647b5a42760ae0c/libcxx/CMakeLists.txt#L439
  https://github.com/llvm/llvm-project/blob/26a1d6601d727a96f4301d0d8647b5a42760ae0c/libcxx/include/CMakeLists.txt#L1024
  We don't use CMake, so this renames the provided
  `vendor/llvm/default_assertion_handler.in` to `__assert_handler` in
  our `libcxx/include` directory, which will be copied to
  `SYSROOT/include/c++/v1`.

- Disable `__libcpp_verbose_abort directly` in code:
  In #20707 we decided to disable `__libcpp_verbose_abort` not to incur
  the code size increase that brings (it brings in `vfprintf` and its
  family). We disabled it in adding
  `#define _LIBCPP_AVAILABILITY_HAS_NO_VERBOSE_ABORT` in
  `__config_site`. But that `_NO_` macros are gone in LLVM 18.1.2, and
  changing it to `#define _LIBCPP_AVAILABILITY_HAS_VERBOSE_ABORT 0` does
  not work because it is overridden by this line, unless we provide our
  own vendor annotations:
  https://github.com/llvm/llvm-project/blob/38f5596feda3276a8aa64fc14e074334017088ca/libcxx/include/__availability#L138
  I asked about this in
  llvm/llvm-project#87012 and
  llvm/llvm-project#71002 (comment)
  (and more comments below)
  but didn't get an actionable answer yet. So this disables
  `__libcpp_verbose_abort` in the code directly for now, hopefully
  temporarily.

Each fix is described in its own commit, except for the fixes required
to resolve conflicts when merging our changes, which I wasn't able to
commit separately.

Fixes #21603.
impact-maker pushed a commit to impact-maker/emscripten that referenced this pull request Apr 11, 2024
This updates libcxx and libcxxabi to LLVM 18.1.2. Due to
llvm/llvm-project#65534 we need to update both
at the same time.

Things to note:

- Disable hardening mode:
  LLVM 18.1.2 adds support for "Hardening Modes" to libcxx
  (https://libcxx.llvm.org/Hardening.html). There are four modes: none,
  fast, extensive and debug. Different hardening modes make different
  trade-offs between the amount of checking and runtime performance. We
  for now disable it (i.e., set it to 'none') so that we don't have any
  effects on the performance. We can consider enabling it when we ever
  get to enable the debug version of libcxx.

- Disable C++20 time zone support:
  LLVM 18.1.2 adds C++20 time zone support
  (https://libcxx.llvm.org/DesignDocs/TimeZone.html) to libcxx, which
  requires access IANA Time Zone Database. Currently it seems it only
  supports Linux:
  https://github.com/llvm/llvm-project/blob/26a1d6601d727a96f4301d0d8647b5a42760ae0c/libcxx/src/tz.cpp#L45-L49
  So this excludes the two source files from build (which is done via
  `CMakeLists.txt` in the upstream LLVM) and sets
  `_LIBCPP_HAS_NO_TIME_ZONE_DATABASE` macro in `__config_site`. In
  future maybe we can consider implementing this in JS.

- `__cxa_init_primary_exception` support:
  llvm/llvm-project#65534 introduces
  `__cxa_init_primary_exception` and uses this in libcxx. Like several
  other methods like the below in `cxa_exception.cpp`,
  https://github.com/emscripten-core/emscripten/blob/fbdd9249e939660cb0d20f00d6bc1897c2f3905e/system/lib/libcxxabi/src/cxa_exception.cpp#L264-L269
  this new function takes a pointer to a destructor, and in Wasm
  destructor returns a `this` pointer, which requires `ifdef
  __USING_WASM_EXCEPTION__` on its signature. And that it is also used
  in libcxx means we need to guard some code in libcxx with `ifdef
  __USING_WASM_EXCEPTION__` for the signature difference, and we need to
  build libcxx with `-D__USING_WASM_EXCEPTIONS__` when Wasm EH is used.
  Also we add Emscripte EH's counterpart in
  `cxa_exception_emscripten.cpp` too.

- This version fixes long-running misbehaviors of `operator new`
  llvm/llvm-project#69498 seems to fix some
  long-running misbhaviors of `operator new`, which in emscripten we
  tried to fix in emscripten-core#11079 and emscripten-core#20154. So while resolving the conflicts, I
  effectively reverted emscripten-core#11079 and emscripten-core#20154 in
  `libcxx/src/stdlib_new_delete.cpp` and `libcxx/src/new.cpp`.

- Add default `__assertion_handler` to `libcxx/include`:
  llvm/llvm-project#77883 adds a way for vendors
  to override how we handle assertions. If a vendor doesn't want to
  override it, CMake will copy the provided [default template assertion
  handler
  file](https://github.com/llvm/llvm-project/blob/26a1d6601d727a96f4301d0d8647b5a42760ae0c/libcxx/vendor/llvm/default_assertion_handler.in)
  to libcxx's generated include dir, which defaults to
  `SYSROOT/include/c++/v1`:
  https://github.com/llvm/llvm-project/blob/26a1d6601d727a96f4301d0d8647b5a42760ae0c/libcxx/CMakeLists.txt#L72-L73
  https://github.com/llvm/llvm-project/blob/26a1d6601d727a96f4301d0d8647b5a42760ae0c/libcxx/CMakeLists.txt#L439
  https://github.com/llvm/llvm-project/blob/26a1d6601d727a96f4301d0d8647b5a42760ae0c/libcxx/include/CMakeLists.txt#L1024
  We don't use CMake, so this renames the provided
  `vendor/llvm/default_assertion_handler.in` to `__assert_handler` in
  our `libcxx/include` directory, which will be copied to
  `SYSROOT/include/c++/v1`.

- Disable `__libcpp_verbose_abort directly` in code:
  In emscripten-core#20707 we decided to disable `__libcpp_verbose_abort` not to incur
  the code size increase that brings (it brings in `vfprintf` and its
  family). We disabled it in adding
  `#define _LIBCPP_AVAILABILITY_HAS_NO_VERBOSE_ABORT` in
  `__config_site`. But that `_NO_` macros are gone in LLVM 18.1.2, and
  changing it to `#define _LIBCPP_AVAILABILITY_HAS_VERBOSE_ABORT 0` does
  not work because it is overridden by this line, unless we provide our
  own vendor annotations:
  https://github.com/llvm/llvm-project/blob/38f5596feda3276a8aa64fc14e074334017088ca/libcxx/include/__availability#L138
  I asked about this in
  llvm/llvm-project#87012 and
  llvm/llvm-project#71002 (comment)
  (and more comments below)
  but didn't get an actionable answer yet. So this disables
  `__libcpp_verbose_abort` in the code directly for now, hopefully
  temporarily.

Each fix is described in its own commit, except for the fixes required
to resolve conflicts when merging our changes, which I wasn't able to
commit separately.

Fixes emscripten-core#21603.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants