This is an archive of the discontinued LLVM Phabricator instance.

Make underlying_type SFINAE-friendly
ClosedPublic

Authored by zoecarver on Mar 5 2019, 11:20 AM.

Details

Summary

I couldn't view the the document (P0340R3). But I think this implementation should work.

Diff Detail

Event Timeline

zoecarver created this revision.Mar 5 2019, 11:20 AM

Here's the whole wording (from P0340):

template <class T>
struct underlying_type;

If T is an enumeration type, the member typedef type names the underlying type of T (9.6 [dcl.enum]); otherwise, there is no member type.

Mandates: T shall be a is not an incomplete enumeration type. (9.6)

So you'll need a test of an incomplete enumeration type.

include/type_traits
4702–4703

I think I'd rather bury the boolean in an __impl class.

test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.pass.cpp
66

I prefer a failing test; so that we can look at the error message: no type named type in std::underlying_type<int> blah blah.

EricWF added a subscriber: EricWF.Mar 6 2019, 12:29 PM
EricWF added inline comments.
include/type_traits
4702–4703

+1. We shouldn't change the top-level declaration like this. It's technically an ABI break.

test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.pass.cpp
65

We're backporting this behavior and we can probably expect others to do so as well.

Therefore the tests should run for all dialects we offer this behavior.

66

Why not both? Passing tests are nice too.

zoecarver marked 5 inline comments as done.Mar 6 2019, 1:47 PM
zoecarver added inline comments.
include/type_traits
4702–4703

Will do.

test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.pass.cpp
66

The failing test error would be

no matching function for call to 'test_sfinae'

There would be a note:

candidate template ignored: substitution failure [with T = int]: no type named 'type' in 'std::__1::underlying_type<int>'

Is there any way to test for the note too?

I will add both.

zoecarver updated this revision to Diff 189583.Mar 6 2019, 1:49 PM
zoecarver marked an inline comment as done.

Add fail test, update pass test to work with any version, use __impl_....

EricWF requested changes to this revision.Mar 6 2019, 2:47 PM
EricWF added inline comments.
include/type_traits
4713

Nit. Space between underlying_type and :.

test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.fail.cpp
23

No need to get SFINAE involved here. Simply write:

int main() {
  using T = std::underlying_type<int>::type; // expected-error {{boom}}
}
test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.pass.cpp
30

I'm not sure what this test is actually testing. How about:

template <class T, class = typename std::underlying_type<T>::type>
std::true_type test_sfinae(int);
template <class T>
std::false_type test_sfinae(...);

int main() {
  static_assert(decltype(test_sfinae<int>(0))::value == false, "not an enum");
   static_assert(decltype(test_sfinae<E>(0))::value == true, "is an enum");

}
This revision now requires changes to proceed.Mar 6 2019, 2:47 PM
mclow.lists added inline comments.Mar 6 2019, 4:24 PM
test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.pass.cpp
30

Now that we have the failing test, do we need this test at all?

zoecarver marked 2 inline comments as done.Mar 6 2019, 5:10 PM
zoecarver added inline comments.
test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.fail.cpp
23

Yes, your right. That's what happens when you copy and paste.

test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.pass.cpp
30

I like that idea @EricWF.

Thinking more about how to structure these tests, I think the "fail" test is not super helpful (as is). What this should be testing for is whether passing underlying_type a non-enum type breaks the compiler. Given that it _shouldn't_ break the compiler, I think it is more helpful to make sure it passes than to try and make sure it fails in the "right" way. Let me know if you disagree though.

mclow.lists added inline comments.Mar 6 2019, 6:55 PM
test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.pass.cpp
30

I don't know what you mean by "breaks the compiler" here.

zoecarver marked 2 inline comments as done.Mar 6 2019, 7:03 PM
zoecarver added inline comments.
test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.pass.cpp
30

I mean before this patch, the below code could not compile. The compiler would error when it tried to interpret the underlying_type template:

template<class T>
std::enable_if_t<
std::is_same_v<std::underlying_type_t<T>, int>
> test_sfinae(T t);

void test_sfinae(int) { return; }

int main()
{
	test_sfinae(0); // Error while substituting deduced template arguments into function template 'test_sfinae' [with T = int]
}
mclow.lists added inline comments.Mar 6 2019, 7:06 PM
test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.pass.cpp
30

And you believe that the compiler was wrong to do so?
If so, have you filed a bug against clang?

You should probably have at least one (and probably several) simple tests that underlying_type<non enum type> is a valid type.

using Int = std::underlying_type<int>;
using Float = std::underlying_type<float>;

etc.

zoecarver marked an inline comment as done.Mar 6 2019, 7:17 PM
zoecarver added inline comments.
test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.pass.cpp
30

Sorry, to clarify, what I meant by "breaks the compiler" was that there was an error while compiling. I did not mean that clang was broken in any way or did anything wrong. I should have chosen my wording more carefully.

zoecarver updated this revision to Diff 189648.Mar 6 2019, 8:49 PM

Update tests (tentatively) & fix stylistic error.

EricWF accepted this revision.Mar 6 2019, 9:55 PM
This revision is now accepted and ready to land.Mar 6 2019, 9:55 PM
EricWF added inline comments.Mar 6 2019, 9:58 PM
test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.pass.cpp
37

This test runs in C++03 mode. Which is weird because it can use a lot of C++11 features; but constexpr isn't one of them.

In C++11 this is a great improvement over my messy test. But the mess is needed for C++03.

EricWF added inline comments.Mar 6 2019, 10:00 PM
test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.fail.cpp
9

Add // UNSUPPORTED: c++98, c++03 here to disable the test before 11.
The other test should be sufficient to cover C++03.

zoecarver marked an inline comment as done.Mar 7 2019, 8:59 AM
zoecarver added inline comments.
test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.pass.cpp
37

I thought about that but IIRC underlying_type wasn't added until 2011. I can update if needed though.

zoecarver updated this revision to Diff 189729.Mar 7 2019, 9:02 AM
zoecarver marked an inline comment as done.

Add UNSUPPORTED comment.

zoecarver updated this revision to Diff 189730.Mar 7 2019, 9:04 AM

Move comment to correct file.

jloser added a subscriber: jloser.Apr 5 2019, 7:06 PM
jloser added a comment.Apr 5 2019, 7:08 PM

We should mark P0340R3 as complete with this patch. This is done in libcxx/www/cxx2a_status.html.

zoecarver updated this revision to Diff 193997.Apr 5 2019, 7:24 PM

Update status.

Thanks @jloser. I always forget to do that :P

mclow.lists closed this revision.Jun 25 2019, 7:41 PM

I forgot about this patch, and went off and implemented this myself. Sorry about that.

Reviewed as D63574; committed as r364094.