This is an archive of the discontinued LLVM Phabricator instance.

[libcxx] Support UDTs convertible to arithmetic types in <cmath>
AbandonedPublic

Authored by K-ballo on Oct 23 2014, 2:24 PM.

Details

Summary

This patch enables generic <cmath> overloads for types unambiguously convertible to any arithmetic type. Addresses PR18218.

Only pow is implemented completely, with proper noexcept specifications and the conversion dance, taken from Howard's original patch. If it looks good I'll extend the implementation and test cases to all the other generic <cmath> overloads.

Diff Detail

Event Timeline

K-ballo updated this revision to Diff 15349.Oct 23 2014, 2:24 PM
K-ballo retitled this revision from to [libcxx] Support UDTs convertible to arithmetic types in <cmath>.
K-ballo updated this object.
K-ballo edited the test plan for this revision. (Show Details)
K-ballo added reviewers: mclow.lists, EricWF.
K-ballo added a subscriber: Unknown Object (MLST).
mclow.lists edited edge metadata.Oct 27 2014, 7:33 AM

The __promote and lazy_enable_if changes have already gone into libc++ (I believe) as part of another patch.

include/type_traits
1180

Is there a reason that these functions are no longer static members?

This patch reverts the incorporation of __lazy_enable_if, as this is a more general solution. It implements __numeric_type in a SFINAE-friendly fashion, which will flag ambiguously convertible UDTs (as well as other soft errors) as non-numeric types.

include/type_traits
1180

They are needed for the well-formed specialization of __numeric_type.

1246

This change to struct was not intended. Will revert to class.

EricWF edited edge metadata.Dec 8 2014, 8:17 PM

The problem I see with this patch is that the expression we use to check for convertibility in __numeric_type is often very different from the expression that actually performs the conversion. The expression that checks for convertibility is:

__numeric_test(declval<T>());

and the expression that actually converts T is:

static_cast<T>(t);

First, we are checking for implicit conversions and preforming explicit ones. This causes a hard compile error in the following code:

struct ImplicitExplicit
{
    operator float() { return 0.0; }
private:
  explicit operator double() { return 0.0; }
};

// Doesn't fire
static_assert(is_same<
    __numeric_type<ImplicitExplicit>::type,float
 >::value, "");

ImplicitExplicit value;
// Fails to compile.
double d = static_cast<double>(value);

// Example in cmath:
std::isless(value, (float)0.0); // Compiles
std::isless(value, (double)0.0); // Doesn't compile.

Second, we are checking for conversions with rvalue references and preforming conversions with lvalue references. This causes a compile error in the following code:

struct RValueConvertible
{
    operator double() && { return 0.0; }
};

// Doesn't fire.
static_assert(__numeric_type<RValueConvertible>::value, "");

// Example of error in cmath
RValueConvertible value;
std::isnan(value); // Doesn't compile.

Third we copy/move the actual types into the cmath functions before preforming the conversion, but we probably shouldn't do this. The following code will not compile for this reason

struct NonCopyable
{
   NonCopyable() {}
   operator int() { return 1; }
private:
  NonCopyable(NonCopyable const &);
};

static_assert(__numeric_type<NonCopyable>::value, ""); // Doesn't fire

NonCopyable value;
std::isnan(value);

I'm not sure these problems should hold this patch up, but I would like to see some discussion on it before moving forward.
I think your implementation of std::pow solves each of these problems with a substantial increase in code complexity, but I think with some work a cleaner solution could be reached.
However it seems that every cmath function will have to perfect forward in order to solve all of the problems :(

include/cmath
944–949

Why does pow have the noexcept clause on it anyway?

include/type_traits
1204–1208

My personal preference would be to use a dummy type instead of void for this.

K-ballo updated this revision to Diff 18451.Jan 20 2015, 12:37 PM
K-ballo edited edge metadata.

Addressed review comments. Keep in mind that only pow is implemented completely, once we get that one right I'll update the others to follow.

K-ballo abandoned this revision.Jan 14 2018, 1:44 PM