[cfe-dev] __has_feature coverage

Richard Smith richard at metafoo.co.uk
Mon May 5 17:05:05 PDT 2014


On Mon, May 5, 2014 at 4:59 PM, Marshall Clow <mclow.lists at gmail.com> wrote:

>
> On May 5, 2014, at 1:09 PM, Richard Smith <richard at metafoo.co.uk> wrote:
>
> On Fri, May 2, 2014 at 1:00 AM, Alp Toker <alp at nuanti.com> wrote:
>
>>
>> On 02/05/2014 07:35, Richard Smith wrote:
>>
>> On Thu, May 1, 2014 at 10:36 PM, Alp Toker <alp at nuanti.com <mailto:
>>> alp at nuanti.com>> wrote:
>>>
>>>
>>>     On 02/05/2014 05:34, Richard Smith wrote:
>>>
>>>         IIRC there were concerns that __has_feature might not be the
>>>         right place to be surfacing these traits.
>>>
>>>
>>>     Right, I took some notes back when I was looking into this and my
>>>     findings were:
>>>
>>>     __has_feature() is intended for standardised language features and
>>>     it's prominently user-facing so not really appropriate for trait
>>>     primitives whether or not they're feature-complete. Once an
>>>     alternative is found we should phase those out.
>>>
>>>     __has_extension() also suffers from being user-facing, but perhaps
>>>     less so.
>>>
>>>     __has_builtin() would let us automatically list all built-in trait
>>>     primitives and I did some work to support that but it wasn't clear
>>>     what value this adds so I've put that aside.
>>>
>>>     Observation: There's no need to list "compatibility-only" or
>>>     poorly defined trait primitives in any detection macro because
>>>     they only exist for compatibility with MSVC and GCC which use
>>>     without checking, with the possible exception of Embarcadero(?).
>>>
>>>     As you see this is a bit of a tangle. As a way forward the viable
>>>     options to provide a feature test for _quality_ type trait
>>>     primitives could be one of:
>>>
>>>     a) A new __has_primitive()
>>>     b) Shoehorning into __has_extension() but naming the features more
>>>     clearly as primitives: e.g.
>>>     __has_extension(primitive_is_constructible)
>>>
>>>
>>> Another option is recommending people use __is_identifier, which already
>>> works for this purpose (because we treat these tokens as keywords), but I'd
>>> be against that one since we can't mark a trait as unavailable when it's in
>>> a not-fully-working state.
>>>
>>> One advantage of sticking with __has_feature or __has_extension is that
>>> we don't immediately gain a legacy deprecated interface to support and be
>>> unhappy about =) Here's what our documentation says:
>>>
>>> "For type trait __X, __has_extension(X) indicates the presence of the
>>> type trait primitive in the compiler."
>>>
>>> We could stick with that, using the is_ prefix as our indicator that the
>>> extension is a type trait (and adding these and any further type traits
>>> only to __has_extension and not to __has_feature).
>>>
>>
>> Yes, I think __has_extension() is the way to go.
>>
>> I wonder however if the feature names need a clearer prefix given that
>> the C++ standard library is considered part of the implementation.
>>
>> The existing names makes it sound to users as though this makes sense:
>>
>> #if __has_feature(is_constructible) || __has_extension(is_constructible)
>>   std::is_constructible<T>::value
>> #else
>>   ...
>> #endif
>
>
> I don't feel particularly uncomfortable about this. If users are using
> __has_feature without reading the documentation (maybe because they're
> cargo-culting something?), I think we're justified in saying they're doing
> it wrong. I'd prefer to keep the names the same (but to only document the
> __has_extension checks going forward).
>
> Marshall: libc++ has a lot of __has_feature checks. Is there a good reason
> you're not using __has_extension that you know of? (__has_extension always
> returns true for a superset of the cases where __has_feature does.)
>
>
> Probably historical reasons; but I was under the impression that
> __has_feature was the shiny, cross-compiler way to tell if a compiler had
> implemented some feature.  [ People use libc++ on other compilers than
> clang ]
>

__has_feature is not cross-compiler, it's a Clang extension just like
__has_extension. The shiny cross-compiler way is the SG10 __cpp_* macros
(but it's murky whether they should map to __has_feature or
__has_extension, and they're not widely supported yet, and they don't yet
cover all the things you want to test, so they're probably not exactly what
you want here.)

A quick search turned up no uses of __has_extension in libc++
>
> [ Apologies for belaboring the obvious, but ..]
> For libc++ to use a compiler intrinsic, I have to know if it’s available -
> so I need a test, and
> I’d like a method that works for different compilers.
>

If that's the case, then your current __has_feature checks are not doing
what you want.


> — Marshall
>
>
>
>
>         Some of the traits don't work in general (and support just
>>>         enough to get through the MS headers); I don't recall exactly
>>>         which ones, though, and I think it was more than just
>>>         __is_*_destructible. Alp, do you recall? (Maybe it was the
>>>         __is_nothrow_* ones?)
>>>
>>>
>>>     Many of the _is_ ones are sketchy. I cooked up some tests to
>>>     compare them against GCC and while compatibility was good, overall
>>>     usefulness wasn't clear and some of the results were sketchy. I'll
>>>     see if I can dig this up but the results may be lost (wish we had
>>>     a wiki to throw stuff like this).
>>>
>>>     Meanwhile our tests for the trait primitives have inconsistent
>>>     coverage and fixing them would be a lot of work. Fortunately the
>>>     libc++ test suite has great coverage and it might be possible to
>>>     reuse that work..
>>>
>>>     Marshall, do you think a strategically placed static_assert()
>>>     could be added somewhere in your type trait tests to compare
>>>     answers from the clang builtin type trait primitives against your
>>>     quality library implementations?
>>>
>>>
>>>
>>>         Do we advertise support for the __has_* ones? We should stop
>>>         doing that if we do -- they're fundamentally broken and pretty
>>>         much useless (they exist to support libstdc++ and give wrong
>>>         answers in some cases for GCC compatibility). Eventually I
>>>         would ilke to make them synonyms for the correct traits, but
>>>         I'm concerned that people might be relying on the GCC bugs
>>>         that we emulate for them.
>>>
>>>
>>>     My understanding of the Embarcadero usage is that they _DO_ use
>>>     the feature detection macros. If this is indeed the case (they
>>>     should comment, do we have a contact?) then removing them from
>>>     __has_feature() is tantamount to removing them completely. I'm not
>>>     at all opposed to that but it should be done after we get the
>>>     facts from the original authors.
>>>
>>>
>>> I'm not sure whether we're talking about the same traits. Just to make
>>> sure, I mean __has_trivial_* and __has_nothrow_* (which GCC added a few
>>> years ago based on the then-C++0x type traits proposal, which got reworked
>>> substantially before C++11).
>>>
>>
>> Oh right. The __has ones have issues like PR16627 and ignoring members
>> with default arguments. For the __is ones, there are various quirks and
>> FIXMEs in SemaExprCXX.cpp which need going through. The newly added
>> primitives not marked incomplete are good for general usage though. We
>> should probably only expose feature checks for the non-quirky ones going on
>> a case by case basis.
>>
>> Alp.
>>
>>
>>> I don't have any particular views on the __is_lvalue_expr,
>>> __is_rvalue_expr, __is_same, __is_convertible, __array_* Embarcadero traits
>>> (except that the names array_rank and array_extent are icky :-) ).
>>>
>>>     Alp.
>>>
>>>
>>>
>>>
>>>
>>>         On Thu, May 1, 2014 at 7:48 AM, Marshall Clow
>>>         <mclow.lists at gmail.com <mailto:mclow.lists at gmail.com>
>>>         <mailto:mclow.lists at gmail.com <mailto:mclow.lists at gmail.com>>>
>>>
>>>         wrote:
>>>
>>>             Recently, reading
>>>         llvm/tools/clang/docs/LanguageExtensions.rst, I
>>>             saw a list of type_trait primitives
>>>             supported by clang.
>>>
>>>             One of them caught my eye: __is_nothrow_constructible  —
>>> that
>>>             could be handy for use in libc++.
>>>
>>>             So I ran a quick test:
>>>
>>>                     __is_nothrow_constructible(int)
>>>             and it returned true.
>>>
>>>             Then I tried:
>>>                     __has_feature(is_nothrow_constructible)
>>>             and it returned false.
>>>
>>>             Well, that’s not useful to me; I need to be able to tell
>>>         when I
>>>             can use that feature.
>>>             So I whipped up a program to test all of the type_traits
>>>         listed in
>>>             that file (attached),
>>>             and to see if I can check (using __has_feature) whether or
>>> not
>>>             they are implemented.
>>>
>>>             Turns out that __has_feature returns false for the
>>>         following type
>>>             traits:
>>>
>>>                     __has_feature(is_interface_class) = 0
>>>                     __has_feature(is_destructible) = 0
>>>                     __has_feature(is_nothrow_destructible) = 0
>>>                     __has_feature(is_nothrow_assignable) = 0
>>>                     __has_feature(is_nothrow_constructible) = 0
>>>
>>>             __is_interface_class is a MS extension; so that’s fine.
>>>             __is_destructible and __is_nothrow_destructible are
>>>         described as
>>>             “partially implemented”, and attempts to use them fail.
>>>
>>>             On the other hand:
>>>                     __is_nothrow_constructible(int) returns 1
>>>                     __is_nothrow_assignable(int&, int) returns 1
>>>
>>>             So these two seem to work (for at least one case)
>>>             It seems to me that we should have feature tests for these
>>>         type
>>>             traits if we expect people to use them
>>>
>>>             So, I’d like to see
>>>                     __has_feature(is_nothrow_constructible)
>>>             and     __has_feature(is_nothrow_assignable)
>>>
>>>             return 1
>>>
>>>
>>>             — Marshall
>>>
>>>
>>>
>>>
>>>     --     http://www.nuanti.com
>>>     the browser experts
>>>
>>>
>>>
>> --
>> http://www.nuanti.com
>> the browser experts
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20140505/9bbec038/attachment.html>


More information about the cfe-dev mailing list