Skip to content
8 changes: 2 additions & 6 deletions llvm/include/llvm/Support/Casting.h
Original file line number Diff line number Diff line change
Expand Up @@ -589,10 +589,6 @@ template <typename To, typename From>
// ValueIsPresent
//===----------------------------------------------------------------------===//

template <typename T>
constexpr bool IsNullable =
std::is_pointer_v<T> || std::is_constructible_v<T, std::nullptr_t>;

/// ValueIsPresent provides a way to check if a value is, well, present. For
/// pointers, this is the equivalent of checking against nullptr, for Optionals
/// this is the equivalent of checking hasValue(). It also provides a method for
Expand All @@ -614,9 +610,9 @@ template <typename T> struct ValueIsPresent<std::optional<T>> {
static inline decltype(auto) unwrapValue(std::optional<T> &t) { return *t; }
};

// If something is "nullable" then we just cast it to bool to see if it exists.
// Specialization for types convertible to bool.
template <typename T>
struct ValueIsPresent<T, std::enable_if_t<IsNullable<T>>> {
struct ValueIsPresent<T, std::enable_if_t<std::is_constructible_v<bool, T>>> {
Copy link
Member

Choose a reason for hiding this comment

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

Should we keep the check that T can be constructed with nullptr? There are types that can be cast to bool but are not pointer-like.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought about it, but figured that checking whether the type is convertible to bool exactly answers the question "does an object have a value". This may not be desired for non-class types (e.g. int) but those shouldn't really be used in this context.

Copy link
Member

Choose a reason for hiding this comment

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

But this enable_if guards both isPresent and unwrapValue -- don't we need extra care for the latter?

Copy link
Member

Choose a reason for hiding this comment

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

Anyway, I'm going to approve this as-is, use your judgement here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But this enable_if guards both isPresent and unwrapValue -- don't we need extra care for the latter?

Maybe, although constructibility from nullptr_t doesn't guarantee that the default implementation of unwrapValue would fit.

As I noted in the other comment, I think it would be best if we provided explicit specializations for each type like we do with simplify_type, for example. Possibly provide a generic one for T *, too. I would't commit myself to implementing this though, I've already shown my expertise in metaprogramming.

using UnwrappedType = T;
static inline bool isPresent(const T &t) { return static_cast<bool>(t); }
Copy link
Contributor

Choose a reason for hiding this comment

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

If we're going down this route, it would probably make sense to also change the enable_if to check std::is_convertible<T, bool> instead?

I think you could also drop the separate std::optional specialization because it also has operator bool.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If we're going down this route, it would probably make sense to also change the enable_if to check std::is_convertible<T, bool> instead?

I think it will make much more sense, will try.

I think you could also drop the separate std::optional specialization because it also has operator bool.

They are not quite the same, the specialization for std::optional derefernces the argument of unwrapValue().
This can probably be guarded by constexpr if, but personally I find the separate specialization clearer.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It appears is_convertible only handles implicit conversions, i.e. it returns false for types with explicit operator bool(). I used is_constructible with swapped arguments instead.

static inline decltype(auto) unwrapValue(T &t) { return t; }
Expand Down
Loading