[cfe-dev] RFC: Adding availability attributes to the libc++ headers

Duncan P. N. Exon Smith via cfe-dev cfe-dev at lists.llvm.org
Mon Feb 8 22:14:12 PST 2016


> On 2016-Feb-08, at 22:12, Duncan P. N. Exon Smith <dexonsmith at apple.com> wrote:
> 
> Manman and I are working on adding availability attributes to the libc++
> headers to express to `clang` which dylib feautures are available on
> Apple platforms (and at what versions).
> 
> I'd love some feedback!  Please read on.
> 
> What are availability attributes?
> =================================
> 
> Availability attributes describe when API is available.  It's widely
> used on Apple platforms; I'm not sure how much use it has outside of
> that.  For example:
> 
>    int foo()
>       __attribute__((availability(macosx,introduced=10.9,
>                                   deprecated=10.10,obsoleted=10.11)))
>       __attribute__((availability(ios,introduced=8.0)))
>       __attribute__((availability(android,unavailable)));
> 
> This says that `foo()` was added to the dylib in Mac OS X 10.9,
> deprecated in 10.10, and obsoleted in 10.11; added to iOS in 8.0; and
> isn't available at all on Android.
> 
> Availability attributes can be attached to most (all?) declarations,
> including types, variables, and functions.
> 
> Since libc++ has a stable API, I only expect to use "introduced" and
> "unavailable" (and we're only working on macosx, ios, tvos and watchos).
> 
> What are the semantics when API isn't available?
> ================================================
> 
> There are two cases here.  The simple case is when API is straight-up
> "unavailable": the frontend gives a diagnostic when it is used by a
> function which is *not* marked unavailable.  For example:
> 
>    int __foo() __attribute__((unavailable));
>    inline int foo() __attribute__((unavailable)) {
>        return __foo(); // no diagnostic
>    }
>    int bar() { return foo(); } // error: foo() unavailable
>    int baz() { return __foo(); } // error: __foo() unavailable
> 
> What about deploying to old versions?
> -------------------------------------
> 
> The seecond case is when a deployment target has been set on the
> command-line, and it's *older* than when an API has been introduced.
> I'll start with an example:
> 
>    $ cat t.cpp
>    int foo() __attribute__((availability(macosx,introduced=10.10)));
>    int bar() { return foo(); }
>    $ clang t.cpp -mmacosx-version-min=10.9
> 
> The default semantics are: weak-link the symbol for foo().  The user is
> expected to check at runtime to see if it's available.  Continuing the
> example:
> 
>    return foo ? foo() : my_workaround_when_foo_is_missing();
> 
> This is not a good usage model for libc++ API.  We'd rather give a hard
> diagnostic in this case.  This requires a new attribute flag, "noweak":
> 
>    $ cat t.cpp
>    int foo() __attribute__((availability(macosx,noweak,introduced=10.10)));
>    int bar() { return foo(); } // error: 'foo' not available until OS X 10.10
>    $ clang t.cpp -mmacosx-version-min=10.9
> 
> Instead of weak-linking foo(), diagnose all uses of it.
> 
> What would this look like in the libc++ headers?
> ================================================
> 
> This only affects header code that depends on the dylib.  Most of libc++
> is header-only, and doesn't need any markup at all.
> 
> I've attached WIP-libcxx-availability.patch,

Sadly forgot the attachment.  Got it this time.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: WIP-libcxx-availability.patch
Type: application/octet-stream
Size: 13506 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20160208/a8312a89/attachment.obj>
-------------- next part --------------

> which handles all of
> <__locale>, and the not-yet-supported parts of <exception>,
> <experimental/optional>, <new>, and <shared_mutex>.  It *does not* use
> `noweak`, but adding -Werror=partial-availability will have a similar
> effect.
> 
>  - The code in __config is too strict.  As currently written, it would
>    prevent libc++ developers from testing new library code.  It needs a
>    macro to control whether to apply the availability markup.  I
>    haven't thought much about this; please let me know if there's an
>    obvious solution.
>  - There's currently a relevant bug in clang.  If an unavailable
>    templated function has a non-template-dependent parameter that is
>    also unavailable, clang incorrectly emits a diagnostic.  I sent a
>    [patch](http://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20160208/149470.html)
>    to cfe-commits.
>  - I'd welcome feedback on how I structed the macros.  In the WIP
>    patch I named macros based on functional groups, but there are other
>    options.
> 
> Rejected alternative: delay diagnostics until first ODR-use of caller
> =====================================================================
> 
> We looked at the possibility of delaying availability diagnostics until
> the caller's first ODR-use if the caller was a `inline`, `template`d, or
> `static` (anything that is only emitted when it's ODR-used).
> Effectively, this would let us decorate *only* the functions on the
> dylib boundary, and then clang would auto-magically propagate the
> attributes up through the headers.
> 
> However, cases like this seemed prohibitively expensive to diagnose:
> 
>    int foo();
>    int bar() { return foo(); } // error: 'foo' unavailable
> 
>    int __foo() __attribute__((unavailable)); // note: '__foo' explicitly unavailable
>    inline int foo() { return __foo(); } // note: 'foo' implicitly unavailable
> 
> Our goal was: diagnose that bar() cannot call foo() because it's
> unavailable; foo() is unavailable because it calls __foo().  The order
> of definitions makes this pretty awkward though.  In general, I think it
> would require keeping track of all ODR-users of every function call, so
> that on parsing the body of foo() we could diagnose its call in bar().
> 
> Explicitly marking foo() unavailable keeps the frontend simple, and it
> also gives a better experience to library users.  They don't care about
> the full ODR-use chain that leads to the dylib; they just need to know
> that the library feature isn't available.



More information about the cfe-dev mailing list