Skip to content

Fix check of typename C::value_type where C is an int #218

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

filipsajdak
Copy link
Contributor

4693e52 introduce a check std::is_convertible_v<X, typename C::value_type> that failed when C is an int.

The issue was discovered when trying to compile the following code:

main: () -> int = {
    x := 'a';
    u := x as int;

    std::cout << "u = '(u)$'" << std::endl;
}

cppfront succeeds but the cpp1 compiler fails with the error:

In file included from ../tests/bug_value_type_check.cpp:2:
include/cpp2util.h:883:92: error: type 'int' cannot be used prior to '::' because it has no members
    if constexpr( requires{ typename C::value_type; } && std::is_convertible_v<X, typename C::value_type> ) {
                                                                                           ^
include/cpp2util.h:1474:52: note: in instantiation of function template specialization 'cpp2::as<int, char>' requested here
    else if constexpr( std::is_same_v< CPP2_TYPEOF(as<C>(CPP2_FORWARD(x))), nonesuch_ > ) {
                                                   ^
../tests/bug_value_type_check.cpp2:3:19: note: in instantiation of function template specialization 'cpp2::as_<int, char &>' requested here
    auto u {cpp2::as_<int>(x)}; 
                  ^
1 error generated.

This change corrects this error and makes the code compile and run successfully.

prenaux added a commit to prenaux/cppfront that referenced this pull request Jan 11, 2023
prenaux added a commit to prenaux/cppfront that referenced this pull request Jan 11, 2023
@@ -880,7 +880,7 @@ auto as( X const& x ) -> auto
// Experiment: Recognize the nested `::value_type` pattern for some dynamic library types
// like std::optional, and try to prevent accidental narrowing conversions even when
// those types themselves don't defend against them
if constexpr( requires{ typename C::value_type; } && std::is_convertible_v<X, typename C::value_type> ) {
if constexpr( requires{ typename C::value_type; } && requires { std::is_convertible_v<X, typename C::value_type>; } ) {
Copy link
Owner

Choose a reason for hiding this comment

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

Thanks! I do see the need for that requires.

But doesn't it also still need the original && std::is_convertible_c<X, typename C::value_type> test itself?

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 have some doubts about it. When I am adding it

    if constexpr( requires{ typename C::value_type; } && requires { std::is_convertible_v<X, typename C::value_type>; } && std::is_convertible_v<X, typename C::value_type> ) {

it fails again:

In file included from ../tests/bug_value_type_check.cpp:2:
include/cpp2util.h:883:158: error: type 'int' cannot be used prior to '::' because it has no members
    if constexpr( requires{ typename C::value_type; } && requires { std::is_convertible_v<X, typename C::value_type>; } && std::is_convertible_v<X, typename C::value_type> ) {
                                                                                                                                                             ^
include/cpp2util.h:1474:52: note: in instantiation of function template specialization 'cpp2::as<int, char>' requested here
    else if constexpr( std::is_same_v< CPP2_TYPEOF(as<C>(CPP2_FORWARD(x))), nonesuch_ > ) {
                                                   ^
../tests/bug_value_type_check.cpp2:3:19: note: in instantiation of function template specialization 'cpp2::as_<int, char &>' requested here
    auto u {cpp2::as_<int>(x)}; 
                  ^
1 error generated.

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 have run all the regression tests with proposed change and they pass.

Copy link
Contributor

Choose a reason for hiding this comment

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

You need to have a single requires-expression with multiple requirements, so

requires{
  typename C::value_type;
  requires std::is_convertible_v<X, typename C::value_type>;
}

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 looks like it is working well as in the next line there is another use of C::value_type that is not causing trouble:

        if constexpr( is_narrowing_v<typename C::value_type, X>) {

So, the proposed change is passing the right C types through.

Copy link
Contributor

Choose a reason for hiding this comment

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

You need to have a single requires-expression with multiple _requirement_s, so

requires{
  typename C::value_type;
  requires std::is_convertible_v<X, typename C::value_type>;
}

In fact, the first requirement is redundant, so requires { requires std::is_convertible_v<X, typename C::value_type>; } should suffice. See https://compiler-explorer.com/z/cYoETj4K3.

#include <type_traits>
struct X {
  using value_type = int;
  operator int();
};
template<class T> constexpr bool f() {
  return requires { requires std::is_convertible_v<T, typename T::value_type>; };
}
static_assert(not f<int>());
static_assert(f<X>());

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That is true. Pushing this version.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks @JohelEGP !

Copy link
Owner

Choose a reason for hiding this comment

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

Thanks @JohelEGP and @filipsajdak for debugging this incantation!

@filipsajdak filipsajdak force-pushed the fsajdak-fix-c-value_type-check-on-int branch from c9929a6 to 8c93270 Compare January 12, 2023 00:29
@filipsajdak
Copy link
Contributor Author

@hsutter , I have just pushed the version proposed by @JohelEGP

@hsutter hsutter merged commit 8a67027 into hsutter:main Jan 12, 2023
@filipsajdak filipsajdak deleted the fsajdak-fix-c-value_type-check-on-int branch January 12, 2023 21:19
Azmah-Bad pushed a commit to Azmah-Bad/cppfront that referenced this pull request Feb 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants