Skip to content

Commit 2eadbc8

Browse files
committed
[libc++] Rework the whole availability markup implementation
Currently, vendor-specific availability markup is enabled by default. This means that even when building against trunk libc++, the headers will by default prevent you from using some features that were not released in the dylib on your target platform. This is a source of frustration since people building libc++ from sources are usually not trying to use some vendor's released dylib. For that reason, I've been thinking for a long time that availability annotations should be off by default, which is the primary change that this commit enables. In addition, it reworks the implementation to make it easier for new vendors to add availability annotations for their platform, and it refreshes the documentation to reflect the current state of the codebase. Finally, a CMake configuration option is added to control whether availability annotations should be turned on for the flavor of libc++ being created. The intent is for vendors like Apple to turn it on, and for the upstream libc++ to leave it off (the default). Differential Revision: https://reviews.llvm.org/D90843
1 parent afe9264 commit 2eadbc8

29 files changed

+261
-196
lines changed

libcxx/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,13 @@ option(LIBCXX_ENABLE_LOCALIZATION
121121
the C locale API (e.g. embedded). When localization is not supported,
122122
several parts of the library will be disabled: <iostream>, <regex>, <locale>
123123
will be completely unusable, and other parts may be only partly available." ON)
124+
option(LIBCXX_ENABLE_VENDOR_AVAILABILITY_ANNOTATIONS
125+
"Whether to turn on vendor availability annotations on declarations that depend
126+
on definitions in a shared library. By default, we assume that we're not building
127+
libc++ for any specific vendor, and we disable those annotations. Vendors wishing
128+
to provide compile-time errors when using features unavailable on some version of
129+
the shared library they shipped should turn this on and see `include/__availability`
130+
for more details." OFF)
124131
option(LIBCXX_TEST_GDB_PRETTY_PRINTERS "Test gdb pretty printers." OFF)
125132
set(LIBCXX_TEST_CONFIG "${CMAKE_CURRENT_SOURCE_DIR}/test/configs/legacy.cfg.in" CACHE STRING
126133
"The Lit testing configuration to use when running the tests.")
@@ -844,6 +851,7 @@ config_define_if(LIBCXX_NO_VCRUNTIME _LIBCPP_NO_VCRUNTIME)
844851
config_define_if(LIBCXX_ENABLE_PARALLEL_ALGORITHMS _LIBCPP_HAS_PARALLEL_ALGORITHMS)
845852
config_define_if_not(LIBCXX_ENABLE_RANDOM_DEVICE _LIBCPP_HAS_NO_RANDOM_DEVICE)
846853
config_define_if_not(LIBCXX_ENABLE_LOCALIZATION _LIBCPP_HAS_NO_LOCALIZATION)
854+
config_define_if_not(LIBCXX_ENABLE_VENDOR_AVAILABILITY_ANNOTATIONS _LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS)
847855

848856
if (LIBCXX_ABI_DEFINES)
849857
set(abi_defines)

libcxx/cmake/caches/Apple.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ set(LIBCXX_TYPEINFO_COMPARISON_IMPLEMENTATION "1" CACHE STRING "")
1111
set(LIBCXX_CXX_ABI libcxxabi CACHE STRING "")
1212
set(LIBCXX_HIDE_FROM_ABI_PER_TU_BY_DEFAULT ON CACHE BOOL "")
1313
set(LIBCXX_ENABLE_DEBUG_MODE_SUPPORT OFF CACHE BOOL "")
14+
set(LIBCXX_ENABLE_VENDOR_AVAILABILITY_ANNOTATIONS ON CACHE BOOL "")
1415

1516
set(LIBCXXABI_ENABLE_PIC OFF CACHE BOOL "")
1617
set(LIBCXXABI_ENABLE_ASSERTIONS OFF CACHE BOOL "")

libcxx/docs/DesignDocs/AvailabilityMarkup.rst

Lines changed: 0 additions & 96 deletions
This file was deleted.

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
set(files
2+
__availability
23
__bit_reference
34
__bsd_locale_defaults.h
45
__bsd_locale_fallbacks.h

libcxx/include/__availability

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
// -*- C++ -*-
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef _LIBCPP___AVAILABILITY
11+
#define _LIBCPP___AVAILABILITY
12+
13+
#include <__config>
14+
15+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
16+
# pragma GCC system_header
17+
#endif
18+
19+
// Libc++ is shipped by various vendors. In particular, it is used as a system
20+
// library on macOS, iOS and other Apple platforms. In order for users to be
21+
// able to compile a binary that is intended to be deployed to an older version
22+
// of a platform, Clang provides availability attributes [1]. These attributes
23+
// can be placed on declarations and are used to describe the life cycle of a
24+
// symbol in the library.
25+
//
26+
// The main goal is to ensure a compile-time error if a symbol that hasn't been
27+
// introduced in a previously released library is used in a program that targets
28+
// that previously released library. Normally, this would be a load-time error
29+
// when one tries to launch the program against the older library.
30+
//
31+
// For example, the filesystem library was introduced in the dylib in macOS 10.15.
32+
// If a user compiles on a macOS 10.15 host but targets macOS 10.13 with their
33+
// program, the compiler would normally not complain (because the required
34+
// declarations are in the headers), but the dynamic loader would fail to find
35+
// the symbols when actually trying to launch the program on macOS 10.13. To
36+
// turn this into a compile-time issue instead, declarations are annotated with
37+
// when they were introduced, and the compiler can produce a diagnostic if the
38+
// program references something that isn't available on the deployment target.
39+
//
40+
// This mechanism is general in nature, and any vendor can add their markup to
41+
// the library (see below). Whenever a new feature is added that requires support
42+
// in the shared library, a macro should be added below to mark this feature
43+
// as unavailable. When vendors decide to ship the feature as part of their
44+
// shared library, they can update the markup appropriately.
45+
//
46+
// Note that this mechanism is disabled by default in the "upstream" libc++.
47+
// Availability annotations are only meaningful when shipping libc++ inside
48+
// a platform (i.e. as a system library), and so vendors that want them should
49+
// turn those annotations on at CMake configuration time.
50+
//
51+
// [1]: https://clang.llvm.org/docs/AttributeReference.html#availability
52+
53+
54+
// For backwards compatibility, allow users to define _LIBCPP_DISABLE_AVAILABILITY
55+
// for a while.
56+
#if defined(_LIBCPP_DISABLE_AVAILABILITY)
57+
# if !defined(_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS)
58+
# define _LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS
59+
# endif
60+
#endif
61+
62+
// Availability markup is disabled when building the library, or when the compiler
63+
// doesn't support the proper attributes.
64+
#if defined(_LIBCPP_BUILDING_LIBRARY) || \
65+
defined(_LIBCXXABI_BUILDING_LIBRARY) || \
66+
!__has_feature(attribute_availability_with_strict) || \
67+
!__has_feature(attribute_availability_in_templates) || \
68+
!__has_extension(pragma_clang_attribute_external_declaration)
69+
# if !defined(_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS)
70+
# define _LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS
71+
# endif
72+
#endif
73+
74+
#if defined(_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS)
75+
76+
// This controls the availability of std::shared_mutex and std::shared_timed_mutex,
77+
// which were added to the dylib later.
78+
# define _LIBCPP_AVAILABILITY_SHARED_MUTEX
79+
80+
// These macros control the availability of std::bad_optional_access and
81+
// other exception types. These were put in the shared library to prevent
82+
// code bloat from every user program defining the vtable for these exception
83+
// types.
84+
# define _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS
85+
# define _LIBCPP_AVAILABILITY_BAD_VARIANT_ACCESS
86+
# define _LIBCPP_AVAILABILITY_BAD_ANY_CAST
87+
88+
// This controls the availability of std::uncaught_exceptions().
89+
# define _LIBCPP_AVAILABILITY_UNCAUGHT_EXCEPTIONS
90+
91+
// This controls the availability of the sized version of ::operator delete,
92+
// which was added to the dylib later.
93+
# define _LIBCPP_AVAILABILITY_SIZED_NEW_DELETE
94+
95+
// This controls the availability of the std::future_error exception.
96+
# define _LIBCPP_AVAILABILITY_FUTURE_ERROR
97+
98+
// This controls the availability of std::type_info's vtable.
99+
// I can't imagine how using std::type_info can work at all if
100+
// this isn't supported.
101+
# define _LIBCPP_AVAILABILITY_TYPEINFO_VTABLE
102+
103+
// This controls the availability of std::locale::category members
104+
// (e.g. std::locale::collate), which are defined in the dylib.
105+
# define _LIBCPP_AVAILABILITY_LOCALE_CATEGORY
106+
107+
// This controls the availability of atomic operations on std::shared_ptr
108+
// (e.g. `std::atomic_store(std::shared_ptr)`), which require a shared
109+
// lock table located in the dylib.
110+
# define _LIBCPP_AVAILABILITY_ATOMIC_SHARED_PTR
111+
112+
// These macros control the availability of all parts of <filesystem> that
113+
// depend on something in the dylib.
114+
# define _LIBCPP_AVAILABILITY_FILESYSTEM
115+
# define _LIBCPP_AVAILABILITY_FILESYSTEM_PUSH
116+
# define _LIBCPP_AVAILABILITY_FILESYSTEM_POP
117+
118+
// This controls the availability of std::to_chars.
119+
# define _LIBCPP_AVAILABILITY_TO_CHARS
120+
121+
// This controls the availability of the C++20 synchronization library,
122+
// which requires shared library support for various operations
123+
// (see libcxx/src/atomic.cpp).
124+
# define _LIBCPP_AVAILABILITY_SYNC
125+
126+
#elif defined(__APPLE__)
127+
128+
# define _LIBCPP_AVAILABILITY_SHARED_MUTEX \
129+
__attribute__((availability(macosx,strict,introduced=10.12))) \
130+
__attribute__((availability(ios,strict,introduced=10.0))) \
131+
__attribute__((availability(tvos,strict,introduced=10.0))) \
132+
__attribute__((availability(watchos,strict,introduced=3.0)))
133+
# define _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS \
134+
__attribute__((availability(macosx,strict,introduced=10.13))) \
135+
__attribute__((availability(ios,strict,introduced=11.0))) \
136+
__attribute__((availability(tvos,strict,introduced=11.0))) \
137+
__attribute__((availability(watchos,strict,introduced=4.0)))
138+
# define _LIBCPP_AVAILABILITY_BAD_VARIANT_ACCESS \
139+
_LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS
140+
# define _LIBCPP_AVAILABILITY_BAD_ANY_CAST \
141+
_LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS
142+
# define _LIBCPP_AVAILABILITY_UNCAUGHT_EXCEPTIONS \
143+
__attribute__((availability(macosx,strict,introduced=10.12))) \
144+
__attribute__((availability(ios,strict,introduced=10.0))) \
145+
__attribute__((availability(tvos,strict,introduced=10.0))) \
146+
__attribute__((availability(watchos,strict,introduced=3.0)))
147+
# define _LIBCPP_AVAILABILITY_SIZED_NEW_DELETE \
148+
__attribute__((availability(macosx,strict,introduced=10.12))) \
149+
__attribute__((availability(ios,strict,introduced=10.0))) \
150+
__attribute__((availability(tvos,strict,introduced=10.0))) \
151+
__attribute__((availability(watchos,strict,introduced=3.0)))
152+
# define _LIBCPP_AVAILABILITY_FUTURE_ERROR \
153+
__attribute__((availability(ios,strict,introduced=6.0)))
154+
# define _LIBCPP_AVAILABILITY_TYPEINFO_VTABLE \
155+
__attribute__((availability(macosx,strict,introduced=10.9))) \
156+
__attribute__((availability(ios,strict,introduced=7.0)))
157+
# define _LIBCPP_AVAILABILITY_LOCALE_CATEGORY \
158+
__attribute__((availability(macosx,strict,introduced=10.9))) \
159+
__attribute__((availability(ios,strict,introduced=7.0)))
160+
# define _LIBCPP_AVAILABILITY_ATOMIC_SHARED_PTR \
161+
__attribute__((availability(macosx,strict,introduced=10.9))) \
162+
__attribute__((availability(ios,strict,introduced=7.0)))
163+
# define _LIBCPP_AVAILABILITY_FILESYSTEM \
164+
__attribute__((availability(macosx,strict,introduced=10.15))) \
165+
__attribute__((availability(ios,strict,introduced=13.0))) \
166+
__attribute__((availability(tvos,strict,introduced=13.0))) \
167+
__attribute__((availability(watchos,strict,introduced=6.0)))
168+
# define _LIBCPP_AVAILABILITY_FILESYSTEM_PUSH \
169+
_Pragma("clang attribute push(__attribute__((availability(macosx,strict,introduced=10.15))), apply_to=any(function,record))") \
170+
_Pragma("clang attribute push(__attribute__((availability(ios,strict,introduced=13.0))), apply_to=any(function,record))") \
171+
_Pragma("clang attribute push(__attribute__((availability(tvos,strict,introduced=13.0))), apply_to=any(function,record))") \
172+
_Pragma("clang attribute push(__attribute__((availability(watchos,strict,introduced=6.0))), apply_to=any(function,record))")
173+
# define _LIBCPP_AVAILABILITY_FILESYSTEM_POP \
174+
_Pragma("clang attribute pop") \
175+
_Pragma("clang attribute pop") \
176+
_Pragma("clang attribute pop") \
177+
_Pragma("clang attribute pop")
178+
# define _LIBCPP_AVAILABILITY_TO_CHARS \
179+
_LIBCPP_AVAILABILITY_FILESYSTEM
180+
# define _LIBCPP_AVAILABILITY_SYNC \
181+
__attribute__((unavailable))
182+
183+
#else
184+
185+
// ...New vendors can add availability markup here...
186+
187+
# error "It looks like you're trying to enable vendor availability markup, but you haven't defined the corresponding macros yet!"
188+
189+
#endif
190+
191+
// Define availability attributes that depend on _LIBCPP_NO_EXCEPTIONS.
192+
// Those are defined in terms of the availability attributes above, and
193+
// should not be vendor-specific.
194+
#if defined(_LIBCPP_NO_EXCEPTIONS)
195+
# define _LIBCPP_AVAILABILITY_FUTURE
196+
# define _LIBCPP_AVAILABILITY_THROW_BAD_ANY_CAST
197+
# define _LIBCPP_AVAILABILITY_THROW_BAD_OPTIONAL_ACCESS
198+
# define _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
199+
#else
200+
# define _LIBCPP_AVAILABILITY_FUTURE _LIBCPP_AVAILABILITY_FUTURE_ERROR
201+
# define _LIBCPP_AVAILABILITY_THROW_BAD_ANY_CAST _LIBCPP_AVAILABILITY_BAD_ANY_CAST
202+
# define _LIBCPP_AVAILABILITY_THROW_BAD_OPTIONAL_ACCESS _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS
203+
# define _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS _LIBCPP_AVAILABILITY_BAD_VARIANT_ACCESS
204+
#endif
205+
206+
#endif // _LIBCPP___AVAILABILITY

0 commit comments

Comments
 (0)