Type trait primitives and feature detection

Hello Marshall, Howard,

As promised I've had a look at what it'd take to get consistent feature detection support for the type trait primitives.

Like I mentioned at the end of last year, there are years of detritus and while we don't know why some of these traits are even here, but we can certainly do better to document and enable their detection in user code.

My first observation is that __has_feature() is intended to indicate mature support for broad language standards. As such, it was the wrong place to list type trait primitives in the first place because:

1) __has_feature(is_trivially_constructible) suggests that the complete feature is available, whereas in fact clang is just exposing an internal primitive that the standard C++ library may choose to use or ignore. Indeed, as in the case of Microsoft or Embarcadero type traits, libc++ may choose not to provide the feature directly or implement it a different way, so it's wrong for __has_feature() to make this claim to user code.

2) The __has_feature() list is manually maintained and indicates mature support for complete standards and major features. History has shown that the list won't be kept up to date for anything other than core C++ features, mainly because it's hard to track.

On the other hand, there's __has_builtin() which is currently used to list support for builtin functions. This list _is_ kept up to date dynamically based on the exact builtin functions currently enabled.

Unfortunately this list never included type trait primitives because they're handled slightly differently internally (and aren't redeclarable, for example). But in reality, they're just two forms of function-like builtins so they'd do well to share the same feature detection. Some GNU builtins functions like __builtin_types_compatible_p() are even implemented directly as type trait primitives today in clang.

My proposal is to expose automatic feature discovery for type trait primitives by plugging into the __has_builtin() system. This means there will no longer be a custom list to maintain and you'll always know what's supported by the clang version parsing your code.

With this proposal, we'd freeze the current (very incomplete) list of type trait primitives in __has_feature() and set it on a long path to deprecation, never adding to it by hand.

For compatibility, you'd define a support macro along the following lines to always get an accurate impression of builtin type trait primitive support:

#define _libcpp_has_trait(x) (__has_builtin(x) || __has_feature(x))

Does this sound like it'll make life easier for libc++? If so, I'll put up the patch shortly!

Regards,
Alp.

Alp,

Thanks much for your work in this area.

I believe Marshall's r199184 addresses the naming conflict.

Howard

Hello Marshall, Howard,

As promised I've had a look at what it'd take to get consistent feature detection support for the type trait primitives.

Like I mentioned at the end of last year, there are years of detritus and while we don't know why some of these traits are even here, but we can certainly do better to document and enable their detection in user code.

My first observation is that __has_feature() is intended to indicate mature support for broad language standards. As such, it was the wrong place to list type trait primitives in the first place because:

1) __has_feature(is_trivially_constructible) suggests that the complete feature is available, whereas in fact clang is just exposing an internal primitive that the standard C++ library may choose to use or ignore. Indeed, as in the case of Microsoft or Embarcadero type traits, libc++ may choose not to provide the feature directly or implement it a different way, so it's wrong for __has_feature() to make this claim to user code.

2) The __has_feature() list is manually maintained and indicates mature support for complete standards and major features. History has shown that the list won't be kept up to date for anything other than core C++ features, mainly because it's hard to track.

On the other hand, there's __has_builtin() which is currently used to list support for builtin functions. This list _is_ kept up to date dynamically based on the exact builtin functions currently enabled.

Unfortunately this list never included type trait primitives because they're handled slightly differently internally (and aren't redeclarable, for example). But in reality, they're just two forms of function-like builtins so they'd do well to share the same feature detection. Some GNU builtins functions like __builtin_types_compatible_p() are even implemented directly as type trait primitives today in clang.

My proposal is to expose automatic feature discovery for type trait primitives by plugging into the __has_builtin() system. This means there will no longer be a custom list to maintain and you'll always know what's supported by the clang version parsing your code.

With this proposal, we'd freeze the current (very incomplete) list of type trait primitives in __has_feature() and set it on a long path to deprecation, never adding to it by hand.

For compatibility, you'd define a support macro along the following lines to always get an accurate impression of builtin type trait primitive support:

#define _libcpp_has_trait(x) (__has_builtin(x) || __has_feature(x))

Does this sound like it'll make life easier for libc++? If so, I'll put up the patch shortly!

Alp,

Thanks much for your work in this area.

I believe Marshall's r199184 addresses the naming conflict.

Brilliant! Thanks for taking that route, it was the cleanest solution.

It'll still be useful to get the type trait primitive feature checks and documentation up to speed at some point, so keeping this thread open.

Cheers
Alp.

Hello Marshall, Howard,

As promised I've had a look at what it'd take to get consistent feature
detection support for the type trait primitives.

Like I mentioned at the end of last year, there are years of detritus and
while we don't know why some of these traits are even here, but we can
certainly do better to document and enable their detection in user code.

My first observation is that __has_feature() is intended to indicate
mature support for broad language standards. As such, it was the wrong
place to list type trait primitives in the first place because:

1) __has_feature(is_trivially_constructible) suggests that the complete
feature is available, whereas in fact clang is just exposing an internal
primitive that the standard C++ library may choose to use or ignore.
Indeed, as in the case of Microsoft or Embarcadero type traits, libc++ may
choose not to provide the feature directly or implement it a different way,
so it's wrong for __has_feature() to make this claim to user code.

2) The __has_feature() list is manually maintained and indicates mature
support for complete standards and major features. History has shown that
the list won't be kept up to date for anything other than core C++
features, mainly because it's hard to track.

On the other hand, there's __has_builtin() which is currently used to list
support for builtin functions. This list _is_ kept up to date dynamically
based on the exact builtin functions currently enabled.

Unfortunately this list never included type trait primitives because
they're handled slightly differently internally (and aren't redeclarable,
for example). But in reality, they're just two forms of function-like
builtins so they'd do well to share the same feature detection. Some GNU
builtins functions like __builtin_types_compatible_p() are even implemented
directly as type trait primitives today in clang.

My proposal is to expose automatic feature discovery for type trait
primitives by plugging into the __has_builtin() system. This means there
will no longer be a custom list to maintain and you'll always know what's
supported by the clang version parsing your code.

With this proposal, we'd freeze the current (very incomplete) list of type
trait primitives in __has_feature() and set it on a long path to
deprecation, never adding to it by hand.

For compatibility, you'd define a support macro along the following lines
to always get an accurate impression of builtin type trait primitive
support:

#define _libcpp_has_trait(x) (__has_builtin(x) || __has_feature(x))

Does this sound like it'll make life easier for libc++? If so, I'll put up
the patch shortly!

No comment on the libc++ point of view, but from Clang's perspective,
exposing these through __has_builtin rather than __has_feature, and
generating the checks automatically (and removing the documentation, but
not the implementation, of the __has_feature checks), seems like the right
thing to me. Thanks!